mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-23 04:16:57 +02:00
Structure early returns with shared loop continuations
This commit is contained in:
@@ -1206,13 +1206,12 @@ uint32_t FindSelectionMerge(const Graph& graph, const BasicBlock& block) {
|
|||||||
return false_target;
|
return false_target;
|
||||||
}
|
}
|
||||||
// A return can leave a selection without reaching its merge. Keep the
|
// A return can leave a selection without reaching its merge. Keep the
|
||||||
// continuing arm as the merge instead of joining live state with a return.
|
// continuing arm as the merge. Shared continuations receive a dedicated
|
||||||
if (graph.Dominates(block.id, false_target) &&
|
// gateway in SplitSharedMergeBlock before structured control is emitted.
|
||||||
HasLinearPathToTerminal(graph, true_target)) {
|
if (HasLinearPathToTerminal(graph, true_target)) {
|
||||||
return false_target;
|
return false_target;
|
||||||
}
|
}
|
||||||
if (graph.Dominates(block.id, true_target) &&
|
if (HasLinearPathToTerminal(graph, false_target)) {
|
||||||
HasLinearPathToTerminal(graph, false_target)) {
|
|
||||||
return true_target;
|
return true_target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8762,6 +8762,54 @@ void TestNewShaderRecompilerCfgNestedEarlyExitSharedTerminal() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestNewShaderRecompilerCfgEarlyReturnSharedLoopContinuation() {
|
||||||
|
// PS d6fb5f22c689ceff: an outer EXEC skip and an inner SCC exit share the
|
||||||
|
// continuing arm, which contains another loop and reaches a different return.
|
||||||
|
const uint32_t shader[] = {
|
||||||
|
EncodeSopc(0x06, 0, 128),
|
||||||
|
EncodeSopp(0x04, 7), // outer -> shared loop or preceding work
|
||||||
|
EncodeSMovB32(2, 129),
|
||||||
|
EncodeSopc(0x06, 2, 128), // preceding work loop
|
||||||
|
EncodeSopp(0x04, 2), // loop -> early-return condition or body
|
||||||
|
EncodeSop2(0x01, 2, 2, 129),
|
||||||
|
EncodeSopp(0x02, -4),
|
||||||
|
EncodeSopc(0x06, 1, 128),
|
||||||
|
EncodeSopp(0x04, 5), // inner -> private return or shared loop
|
||||||
|
EncodeSopc(0x06, 3, 128), // shared loop header
|
||||||
|
EncodeSopp(0x04, 2), // loop -> normal return or body
|
||||||
|
EncodeSop2(0x01, 3, 3, 129),
|
||||||
|
EncodeSopp(0x02, -4), // body -> loop header
|
||||||
|
0xbf810000u, // normal return
|
||||||
|
EncodeSMovB32(4, 130), // private return epilogue
|
||||||
|
0xbf810000u,
|
||||||
|
};
|
||||||
|
|
||||||
|
ShaderRecompiler::Decoder::Program decoded;
|
||||||
|
ShaderRecompiler::Decoder::DecodeProgram(std::span{shader}, decoded);
|
||||||
|
auto graph = ShaderRecompiler::CFG::BuildGraph(decoded);
|
||||||
|
const auto original_coverage =
|
||||||
|
CfgInstructionCoverage(graph, decoded.instructions.size());
|
||||||
|
Check(ShaderRecompiler::CFG::Structurize(graph),
|
||||||
|
graph.unsupported_reason.c_str());
|
||||||
|
Check(CfgInstructionCoverage(graph, decoded.instructions.size()) ==
|
||||||
|
original_coverage &&
|
||||||
|
graph.natural_loops.size() == 2u,
|
||||||
|
"shared-continuation gateway changed semantic blocks or the loops");
|
||||||
|
Check(std::ranges::none_of(graph.blocks,
|
||||||
|
[](const auto &block) {
|
||||||
|
return block.terminator.goto_variable !=
|
||||||
|
UINT32_MAX;
|
||||||
|
}),
|
||||||
|
"private early return introduced unnecessary routing state");
|
||||||
|
|
||||||
|
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||||
|
auto result = RecompileForTest(shader, options);
|
||||||
|
Check(!result.program.dispatcher_fallback &&
|
||||||
|
SpirvInstructionOpcodeCount(result.spirv, 251) == 0u,
|
||||||
|
"early return with a shared loop continuation selected the dispatcher");
|
||||||
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
|
}
|
||||||
|
|
||||||
void TestNewShaderRecompilerCfgSharedTerminalEarlyExit() {
|
void TestNewShaderRecompilerCfgSharedTerminalEarlyExit() {
|
||||||
const uint32_t shader[] = {
|
const uint32_t shader[] = {
|
||||||
EncodeSopc(0x06, 0, 0), // outer early-exit condition
|
EncodeSopc(0x06, 0, 0), // outer early-exit condition
|
||||||
@@ -13491,6 +13539,7 @@ int main() {
|
|||||||
TestNewShaderRecompilerCfgSharedRegionBeforeEarlyBreakLoop();
|
TestNewShaderRecompilerCfgSharedRegionBeforeEarlyBreakLoop();
|
||||||
TestNewShaderRecompilerCfgOverlappingEarlyExitLadder();
|
TestNewShaderRecompilerCfgOverlappingEarlyExitLadder();
|
||||||
TestNewShaderRecompilerCfgNestedEarlyExitSharedTerminal();
|
TestNewShaderRecompilerCfgNestedEarlyExitSharedTerminal();
|
||||||
|
TestNewShaderRecompilerCfgEarlyReturnSharedLoopContinuation();
|
||||||
TestNewShaderRecompilerCfgSharedTerminalEarlyExit();
|
TestNewShaderRecompilerCfgSharedTerminalEarlyExit();
|
||||||
TestNewShaderRecompilerCfgPrunesUnreachableSelectionEntry();
|
TestNewShaderRecompilerCfgPrunesUnreachableSelectionEntry();
|
||||||
TestNewShaderRecompilerCfgFailedStructurizationPreservesGraph();
|
TestNewShaderRecompilerCfgFailedStructurizationPreservesGraph();
|
||||||
|
|||||||
Reference in New Issue
Block a user