Shader decompiler: Fix control flow analysis bugs

This commit is contained in:
wheremyfoodat 2024-08-25 18:38:22 +03:00
parent 5432a5a0d8
commit e925a91e40

View file

@ -18,7 +18,7 @@ void ControlFlow::analyze(const PICAShader& shader, u32 entrypoint) {
analysisFailed = false; analysisFailed = false;
const Function* function = addFunction(shader, entrypoint, PICAShader::maxInstructionCount); const Function* function = addFunction(shader, entrypoint, PICAShader::maxInstructionCount);
if (function == nullptr) { if (function == nullptr || function->exitMode != ExitMode::AlwaysEnd) {
analysisFailed = true; analysisFailed = true;
} }
} }
@ -83,6 +83,7 @@ ExitMode ControlFlow::analyzeFunction(const PICAShader& shader, u32 start, u32 e
it->second = exitParallel(branchTakenExit, branchNotTakenExit); it->second = exitParallel(branchTakenExit, branchNotTakenExit);
return it->second; return it->second;
} }
case ShaderOpcodes::IFU: case ShaderOpcodes::IFU:
case ShaderOpcodes::IFC: { case ShaderOpcodes::IFC: {
const u32 num = instruction & 0xff; const u32 num = instruction & 0xff;
@ -114,7 +115,7 @@ ExitMode ControlFlow::analyzeFunction(const PICAShader& shader, u32 start, u32 e
it->second = parallel; it->second = parallel;
return it->second; return it->second;
} else { } else {
ExitMode afterConditional = analyzeFunction(shader, pc + 1, end, labels); ExitMode afterConditional = analyzeFunction(shader, dest + num, end, labels);
ExitMode conditionalExitMode = exitSeries(parallel, afterConditional); ExitMode conditionalExitMode = exitSeries(parallel, afterConditional);
it->second = conditionalExitMode; it->second = conditionalExitMode;
return it->second; return it->second;
@ -139,7 +140,7 @@ ExitMode ControlFlow::analyzeFunction(const PICAShader& shader, u32 start, u32 e
// Exit mode of the remainder of this function, after we return from the callee // Exit mode of the remainder of this function, after we return from the callee
const ExitMode postCallExitMode = analyzeFunction(shader, pc + 1, end, labels); const ExitMode postCallExitMode = analyzeFunction(shader, pc + 1, end, labels);
const ExitMode exitMode = exitSeries(postCallExitMode, calledFunction->exitMode); const ExitMode exitMode = exitSeries(calledFunction->exitMode, postCallExitMode);
it->second = exitMode; it->second = exitMode;
return exitMode; return exitMode;
@ -179,7 +180,7 @@ ExitMode ControlFlow::analyzeFunction(const PICAShader& shader, u32 start, u32 e
} }
const ExitMode afterLoop = analyzeFunction(shader, dest + 1, end, labels); const ExitMode afterLoop = analyzeFunction(shader, dest + 1, end, labels);
const ExitMode exitMode = exitSeries(afterLoop, loopFunction->exitMode); const ExitMode exitMode = exitSeries(loopFunction->exitMode, afterLoop);
it->second = exitMode; it->second = exitMode;
return it->second; return it->second;
} }
@ -190,7 +191,8 @@ ExitMode ControlFlow::analyzeFunction(const PICAShader& shader, u32 start, u32 e
} }
// A function without control flow instructions will always reach its "return point" and return // A function without control flow instructions will always reach its "return point" and return
return ExitMode::AlwaysReturn; it->second = ExitMode::AlwaysReturn;
return it->second;
} }
std::pair<u32, bool> ShaderDecompiler::compileRange(const AddressRange& range) { std::pair<u32, bool> ShaderDecompiler::compileRange(const AddressRange& range) {