mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 11:26:56 +02:00
shader: let structurization own rollback on failure
This commit is contained in:
@@ -552,19 +552,10 @@ TranslateResult TranslateProgram(std::span<const uint32_t> code, const CompileOp
|
|||||||
if (cfg.irreducible) {
|
if (cfg.irreducible) {
|
||||||
LogDispatcherFallback(options, cfg, "build");
|
LogDispatcherFallback(options, cfg, "build");
|
||||||
} else {
|
} else {
|
||||||
const auto unstructured_cfg = cfg;
|
|
||||||
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG Structurize\n",
|
LOGF("%s phase begin: stage=%s hash=0x%016" PRIx64 " CFG Structurize\n",
|
||||||
GetDumpLabel(options), StageName(options.stage), options.shader_hash);
|
GetDumpLabel(options), StageName(options.stage), options.shader_hash);
|
||||||
if (!CFG::Structurize(cfg)) {
|
if (!CFG::Structurize(cfg)) {
|
||||||
const auto failure_kind = cfg.failure_kind;
|
|
||||||
const auto failure_block = cfg.failure_block;
|
|
||||||
LogDispatcherFallback(options, cfg, "structurize");
|
LogDispatcherFallback(options, cfg, "structurize");
|
||||||
auto failure_reason = std::move(cfg.unsupported_reason);
|
|
||||||
cfg = unstructured_cfg;
|
|
||||||
cfg.unsupported = true;
|
|
||||||
cfg.failure_kind = failure_kind;
|
|
||||||
cfg.failure_block = failure_block;
|
|
||||||
cfg.unsupported_reason = std::move(failure_reason);
|
|
||||||
} else {
|
} else {
|
||||||
LOGF("%s structured CFG success: blocks=%" PRIu64 "\n", GetDumpLabel(options),
|
LOGF("%s structured CFG success: blocks=%" PRIu64 "\n", GetDumpLabel(options),
|
||||||
static_cast<uint64_t>(cfg.blocks.size()));
|
static_cast<uint64_t>(cfg.blocks.size()));
|
||||||
|
|||||||
@@ -2193,27 +2193,38 @@ bool StructurizeImpl(Graph& graph) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool Structurize(Graph& graph) {
|
bool Structurize(Graph& graph) {
|
||||||
Graph original = graph;
|
Graph structured = graph;
|
||||||
if (StructurizeImpl(graph)) {
|
if (StructurizeImpl(structured)) {
|
||||||
|
graph = std::move(structured);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph failed_graph = std::move(graph);
|
const auto failure_kind = structured.failure_kind;
|
||||||
graph = std::move(original);
|
// Structurization inserts and renumbers blocks. Recover source identity for a
|
||||||
|
// semantic block; a synthetic block has no corresponding original diagnostic ID.
|
||||||
|
const auto* failed = structured.FindBlock(structured.failure_block);
|
||||||
|
const auto original = std::ranges::find_if(graph.blocks, [&](const BasicBlock& block) {
|
||||||
|
return failed != nullptr && failed->inst_begin != failed->inst_end &&
|
||||||
|
block.inst_begin == failed->inst_begin && block.inst_end == failed->inst_end &&
|
||||||
|
block.start_pc == failed->start_pc && block.end_pc == failed->end_pc;
|
||||||
|
});
|
||||||
|
const auto failure_block = original != graph.blocks.end() ? original->id : UINT32_MAX;
|
||||||
|
auto failure_reason = std::move(structured.unsupported_reason);
|
||||||
|
Graph routed = graph;
|
||||||
const auto route_budget = static_cast<uint32_t>(graph.blocks.size());
|
const auto route_budget = static_cast<uint32_t>(graph.blocks.size());
|
||||||
// Apply one route at a time and retry. Eagerly routing every matching diamond can
|
// Apply one route at a time and retry. Eagerly routing every matching diamond can
|
||||||
// rewrite unrelated selections that were already structurally valid.
|
// rewrite unrelated selections that were already structurally valid.
|
||||||
for (uint32_t route_variable = 0; route_variable < route_budget; route_variable++) {
|
for (uint32_t route_variable = 0; route_variable < route_budget; route_variable++) {
|
||||||
if (!RouteSharedSelectionArm(graph, route_variable)) {
|
if (!RouteSharedSelectionArm(routed, route_variable)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Graph routed = graph;
|
structured = routed;
|
||||||
if (StructurizeImpl(routed)) {
|
if (StructurizeImpl(structured)) {
|
||||||
graph = std::move(routed);
|
graph = std::move(structured);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
graph = std::move(failed_graph);
|
SetFailure(graph, failure_kind, failure_block, failure_reason);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ struct Graph {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Graph BuildGraph(const Decoder::Program& program);
|
Graph BuildGraph(const Decoder::Program& program);
|
||||||
|
// Commits structured control flow on success; preserves the original graph with
|
||||||
|
// failure diagnostics on failure. failure_block is an original block ID or UINT32_MAX.
|
||||||
bool Structurize(Graph& graph);
|
bool Structurize(Graph& graph);
|
||||||
std::string BranchConditionToString(BranchCondition condition);
|
std::string BranchConditionToString(BranchCondition condition);
|
||||||
std::string FailureKindToString(FailureKind kind);
|
std::string FailureKindToString(FailureKind kind);
|
||||||
|
|||||||
@@ -8624,6 +8624,45 @@ void TestNewShaderRecompilerCfgPrunesUnreachableSelectionEntry() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestNewShaderRecompilerCfgFailedStructurizationPreservesGraph() {
|
||||||
|
using namespace ShaderRecompiler;
|
||||||
|
const uint32_t shader[] = {
|
||||||
|
EncodeSMovB32(0, 129),
|
||||||
|
EncodeSopp(0x02, 0xfffeu), // semantic loop header, no exit/merge
|
||||||
|
0xbf810000u, // unreachable decoder terminator
|
||||||
|
};
|
||||||
|
Decoder::Program decoded;
|
||||||
|
Decoder::DecodeProgram(std::span{shader}, decoded);
|
||||||
|
auto graph = CFG::BuildGraph(decoded);
|
||||||
|
const auto original = graph;
|
||||||
|
Check(graph.natural_loops.size() == 1u && !graph.irreducible,
|
||||||
|
"failed structurization fixture must have one reducible loop");
|
||||||
|
Check(!CFG::Structurize(graph) && graph.unsupported &&
|
||||||
|
graph.failure_kind == CFG::FailureKind::StructuredControlFlow &&
|
||||||
|
!graph.unsupported_reason.empty(),
|
||||||
|
"loop without a merge did not retain its structurization failure");
|
||||||
|
Check(graph.failure_block == UINT32_MAX,
|
||||||
|
"failed structurization exposed a discarded synthetic block ID");
|
||||||
|
Check(CfgInstructionCoverage(graph, decoded.instructions.size()) ==
|
||||||
|
CfgInstructionCoverage(original, decoded.instructions.size()),
|
||||||
|
"failed structurization changed instruction coverage");
|
||||||
|
auto topology = graph;
|
||||||
|
topology.unsupported = original.unsupported;
|
||||||
|
topology.failure_kind = original.failure_kind;
|
||||||
|
topology.failure_block = original.failure_block;
|
||||||
|
topology.unsupported_reason = original.unsupported_reason;
|
||||||
|
Check(CFG::GraphToString(topology) == CFG::GraphToString(original),
|
||||||
|
"failed structurization changed CFG topology or analyses");
|
||||||
|
|
||||||
|
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||||
|
auto result = RecompileForTest(shader, options);
|
||||||
|
Check(result.program.dispatcher_fallback &&
|
||||||
|
result.program.cfg_failure_kind == graph.failure_kind &&
|
||||||
|
result.program.fallback_reason == graph.unsupported_reason,
|
||||||
|
"compiler did not consume CFG failure diagnostics directly");
|
||||||
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
|
}
|
||||||
|
|
||||||
void TestNewShaderRecompilerCfgIrreducibleDispatcher() {
|
void TestNewShaderRecompilerCfgIrreducibleDispatcher() {
|
||||||
const uint32_t shader[] = {
|
const uint32_t shader[] = {
|
||||||
EncodeSopp(0x05, 2), // entry -> B, fallthrough A
|
EncodeSopp(0x05, 2), // entry -> B, fallthrough A
|
||||||
@@ -13047,6 +13086,7 @@ int main() {
|
|||||||
TestNewShaderRecompilerCfgNestedEarlyExitSharedTerminal();
|
TestNewShaderRecompilerCfgNestedEarlyExitSharedTerminal();
|
||||||
TestNewShaderRecompilerCfgSharedTerminalEarlyExit();
|
TestNewShaderRecompilerCfgSharedTerminalEarlyExit();
|
||||||
TestNewShaderRecompilerCfgPrunesUnreachableSelectionEntry();
|
TestNewShaderRecompilerCfgPrunesUnreachableSelectionEntry();
|
||||||
|
TestNewShaderRecompilerCfgFailedStructurizationPreservesGraph();
|
||||||
TestNewShaderRecompilerCfgIrreducibleDispatcher();
|
TestNewShaderRecompilerCfgIrreducibleDispatcher();
|
||||||
TestNewShaderRecompilerDispatcherSpillsU32x3();
|
TestNewShaderRecompilerDispatcherSpillsU32x3();
|
||||||
TestNewShaderRecompilerPlanningOnlyLoads();
|
TestNewShaderRecompilerPlanningOnlyLoads();
|
||||||
|
|||||||
Reference in New Issue
Block a user