shader: accept dword SETPC tables whose load reuses the selector

This commit is contained in:
Andre Michi
2026-10-20 04:21:45 +02:00
committed by nmzik
parent 12ca1599cf
commit 1a053f9e13
2 changed files with 18 additions and 13 deletions
@@ -470,8 +470,10 @@ bool ResolveSetpcDwordJumpTable(const Decoder::Program& program, uint32_t setpc_
if (!ResolveJumpTableEntryCount(program, load_index, load.src1, 2u, &entry_count)) {
return false;
}
// Code-table loads are not translated, so a selector that is also the load destination
// keeps its scaled index at the branch.
uint32_t selector_code = UINT32_MAX;
if (!ScalarOperandCode(load.src1, selector_code) || selector_code == offset_code ||
if (!ScalarOperandCode(load.src1, selector_code) ||
ScalarCodeWrittenInRange(program, load_index + 1u, setpc_index, selector_code)) {
return false;
}
+15 -12
View File
@@ -11740,7 +11740,7 @@ void TestNewShaderRecompilerSetpcJumpTable() {
Check((*jump)->terminator.cases.size() == 2,
"S_SETPC_B64 jump table did not retain selector mapping");
Check(
(result.ir_dump.find("SLoadDword") == std::string::npos),
(result.ir_dump.find("LoadAddressU32") == std::string::npos),
"S_SETPC_B64 jump table load was reflected as a raw scalar buffer load");
Check(SpirvContainsOpcode(result.spirv, 251),
"dispatcher SPIR-V lacks OpSwitch");
@@ -11801,7 +11801,9 @@ void TestNewShaderRecompilerPrunesUnreachableSetpcMetadata() {
"unreachable S_SETPC metadata suppressed a reachable scalar load component");
}
void TestNewShaderRecompilerSetpcDwordJumpTable() {
// offset_sgpr 106 aliases the vcc_lo selector, like PPSA34015's
// s_load_dword s17, s[22:23], s17.
void TestNewShaderRecompilerSetpcDwordJumpTable(uint32_t offset_sgpr) {
const uint32_t shader[] = {
EncodeSopp(0x02, 1), // skip one unreachable block
EncodeSMovB32(100, 129), // unreachable
@@ -11811,20 +11813,20 @@ void TestNewShaderRecompilerSetpcDwordJumpTable() {
EncodeSop2(0x00, 4, 4, 255), // s_add_u32 s4, s4, literal
0x00000034u,
EncodeSop2(0x04, 5, 5, 128), // s_addc_u32 s5, s5, 0
EncodeSmem0(0x00, 6, 2),
(106u << 25u) | 4u, // s_load_dword s6, s[4:5], vcc_lo offset:4
EncodeSopp(0x0c, 0), // s_waitcnt 0
EncodeSop2(0x01, 4, 4, 6), // s_sub_u32 s4, s4, s6
EncodeSop2(0x05, 5, 5, 128), // s_subb_u32 s5, s5, 0
EncodeSop1(0x20, 0, 4), // s_setpc_b64 s[4:5]
EncodeSMovB32(1, 129), // case 0
EncodeSmem0(0x00, offset_sgpr, 2),
(106u << 25u) | 4u, // s_load_dword offset, s[4:5], vcc_lo offset:4
EncodeSopp(0x0c, 0), // s_waitcnt 0
EncodeSop2(0x01, 4, 4, offset_sgpr), // s_sub_u32 s4, s4, offset
EncodeSop2(0x05, 5, 5, 128), // s_subb_u32 s5, s5, 0
EncodeSop1(0x20, 0, 4), // s_setpc_b64 s[4:5]
EncodeSMovB32(1, 129), // case 0
EncodeSopp(0x02, 1),
EncodeSMovB32(2, 129), // case 1
EncodeSopp(0x01, 0),
0u,
0x00000010u,
0x00000008u,
0x00000010u, // table at pc 0x44, targets relative backward from pc 0x40
0x00000010u, // table at pc 0x4c, targets relative backward from pc 0x48
};
auto options = MakeCompileOptions(ShaderType::Compute);
@@ -11850,7 +11852,7 @@ void TestNewShaderRecompilerSetpcDwordJumpTable() {
result.program.blocks,
[](const auto *block) { return block->start_pc == 0x04u; }),
"subtractive S_SETPC_B64 table targets or selector mapping changed");
Check((result.ir_dump.find("SLoadDword") == std::string::npos),
Check((result.ir_dump.find("LoadAddressU32") == std::string::npos),
"subtractive S_SETPC_B64 table load reached normal IR");
Check(SpirvContainsOpcode(result.spirv, 251),
"subtractive S_SETPC_B64 dispatcher lacks OpSwitch");
@@ -16764,7 +16766,8 @@ int main() {
TestEmbeddedVertexFormatSwizzle();
TestNewShaderRecompilerSetpcJumpTable();
TestNewShaderRecompilerPrunesUnreachableSetpcMetadata();
TestNewShaderRecompilerSetpcDwordJumpTable();
TestNewShaderRecompilerSetpcDwordJumpTable(6);
TestNewShaderRecompilerSetpcDwordJumpTable(106);
TestTypedEntryStateIsMinimal();
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
TestFinalSsaRejectsRegisterStatePseudos();