mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
shader: route inner shared exits first
This commit is contained in:
@@ -1875,7 +1875,8 @@ bool RouteSharedSelectionArm(Graph& graph, uint32_t route_variable) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto block_count = static_cast<uint32_t>(graph.blocks.size());
|
const auto block_count = static_cast<uint32_t>(graph.blocks.size());
|
||||||
for (uint32_t block_id = 0; block_id < block_count; block_id++) {
|
// Route later/deeper candidates first so earlier shared arms remain structured.
|
||||||
|
for (uint32_t block_id = block_count; block_id-- > 0;) {
|
||||||
GotoRouteBlocks route;
|
GotoRouteBlocks route;
|
||||||
if (RouteOneSharedArm(graph, block_count, block_id, route_variable, route)) {
|
if (RouteOneSharedArm(graph, block_count, block_id, route_variable, route)) {
|
||||||
PlaceGotoRouteBlocks(graph, block_count, route);
|
PlaceGotoRouteBlocks(graph, block_count, route);
|
||||||
|
|||||||
@@ -7926,6 +7926,68 @@ void TestNewShaderRecompilerCfgNestedTailEarlyExit() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestNewShaderRecompilerCfgRoutesInnerSharedExitFirst() {
|
||||||
|
const uint32_t shader[] = {
|
||||||
|
EncodeSopc(0x06, 0, 0), // outer forward-skip condition
|
||||||
|
EncodeSopp(0x04, 4), // outer -> shared or nested condition
|
||||||
|
EncodeSopc(0x06, 1, 1), // nested forward-skip condition
|
||||||
|
EncodeSopp(0x04, 2), // nested -> shared or work
|
||||||
|
EncodeSMovB32(2, 129), // forward-skip work
|
||||||
|
EncodeSopp(0x02, 0), // work -> shared
|
||||||
|
EncodeSMovB32(3, 129), // shared work
|
||||||
|
EncodeSopc(0x06, 4, 4), // outer terminal condition
|
||||||
|
EncodeSopp(0x04, 3), // outer -> shared terminal or inner
|
||||||
|
EncodeSopc(0x06, 5, 5), // inner terminal condition
|
||||||
|
EncodeSopp(0x04, 1), // inner -> shared terminal or other terminal
|
||||||
|
0xbf810000u, // other terminal
|
||||||
|
0xbf810000u, // shared terminal
|
||||||
|
};
|
||||||
|
|
||||||
|
ShaderRecompiler::Decoder::Program decoded;
|
||||||
|
std::string error;
|
||||||
|
Check(ShaderRecompiler::Decoder::DecodeProgram(std::span{shader}, decoded,
|
||||||
|
&error),
|
||||||
|
error.c_str());
|
||||||
|
ShaderRecompiler::CFG::Graph graph;
|
||||||
|
Check(ShaderRecompiler::CFG::BuildGraph(decoded, graph, &error),
|
||||||
|
error.c_str());
|
||||||
|
const auto original_coverage =
|
||||||
|
CfgInstructionCoverage(graph, decoded.instructions.size());
|
||||||
|
Check(ShaderRecompiler::CFG::Structurize(graph, &error), error.c_str());
|
||||||
|
Check(CfgInstructionCoverage(graph, decoded.instructions.size()) ==
|
||||||
|
original_coverage,
|
||||||
|
"shared-exit route ordering changed semantic instruction coverage");
|
||||||
|
const auto route_selects =
|
||||||
|
std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||||
|
return block.terminator.condition ==
|
||||||
|
ShaderRecompiler::CFG::BranchCondition::GotoVariable;
|
||||||
|
});
|
||||||
|
const auto route_sets =
|
||||||
|
std::ranges::count_if(graph.blocks, [](const auto &block) {
|
||||||
|
return block.terminator.goto_value >= 0;
|
||||||
|
});
|
||||||
|
const bool has_early_route =
|
||||||
|
std::ranges::any_of(graph.blocks, [](const auto &block) {
|
||||||
|
return block.start_pc < 0x30u &&
|
||||||
|
(block.terminator.condition ==
|
||||||
|
ShaderRecompiler::CFG::BranchCondition::GotoVariable ||
|
||||||
|
block.terminator.goto_value >= 0);
|
||||||
|
});
|
||||||
|
Check(route_selects == 1u && route_sets == 3u && !has_early_route,
|
||||||
|
"shared exits were routed before the innermost blocking construct");
|
||||||
|
|
||||||
|
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||||
|
options.dump_ir = true;
|
||||||
|
ShaderRecompiler::CompileResult result;
|
||||||
|
Check(ShaderRecompiler::TryRecompile(shader, options, result, &error),
|
||||||
|
error.c_str());
|
||||||
|
Check(!result.program.dispatcher_fallback &&
|
||||||
|
Common::ContainsStr(result.ir_dump, "mode=structured") &&
|
||||||
|
SpirvInstructionOpcodeCount(result.spirv, 251) == 0u,
|
||||||
|
"inner-first shared-exit routing did not stay structured");
|
||||||
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
|
}
|
||||||
|
|
||||||
void TestNewShaderRecompilerCfgLoopSharedRegion() {
|
void TestNewShaderRecompilerCfgLoopSharedRegion() {
|
||||||
const uint32_t shader[] = {
|
const uint32_t shader[] = {
|
||||||
EncodeSopc(0x06, 0, 0), // loop condition
|
EncodeSopc(0x06, 0, 0), // loop condition
|
||||||
@@ -11954,6 +12016,7 @@ int main() {
|
|||||||
TestNewShaderRecompilerCfgNestedEarlyExitLoopForwarders();
|
TestNewShaderRecompilerCfgNestedEarlyExitLoopForwarders();
|
||||||
TestNewShaderRecompilerCfgExecSccSharedArm();
|
TestNewShaderRecompilerCfgExecSccSharedArm();
|
||||||
TestNewShaderRecompilerCfgNestedTailEarlyExit();
|
TestNewShaderRecompilerCfgNestedTailEarlyExit();
|
||||||
|
TestNewShaderRecompilerCfgRoutesInnerSharedExitFirst();
|
||||||
TestNewShaderRecompilerCfgLoopSharedRegion();
|
TestNewShaderRecompilerCfgLoopSharedRegion();
|
||||||
TestNewShaderRecompilerCfgOverlappingEarlyExitLadder();
|
TestNewShaderRecompilerCfgOverlappingEarlyExitLadder();
|
||||||
TestNewShaderRecompilerCfgNestedEarlyExitSharedTerminal();
|
TestNewShaderRecompilerCfgNestedEarlyExitSharedTerminal();
|
||||||
|
|||||||
Reference in New Issue
Block a user