shader: zero-extend unsigned SOPK comparisons

This commit is contained in:
nmzik
2026-09-05 10:38:29 +04:00
parent dea80f34ca
commit 51afce3a97
2 changed files with 47 additions and 1 deletions
@@ -188,7 +188,9 @@ void DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
const uint32_t word = code[word_index];
const uint32_t opcode = (word >> 23u) & 0x1fu;
const uint32_t sdst = (word >> 16u) & 0x7fu;
const auto imm = static_cast<int16_t>(word & 0xffffu);
const auto imm = opcode >= 0x09u && opcode <= 0x0eu
? static_cast<int32_t>(word & 0xffffu)
: static_cast<int32_t>(static_cast<int16_t>(word & 0xffffu));
inst.pc = pc;
inst.word = word;
+44
View File
@@ -1670,6 +1670,49 @@ void TestNewShaderRecompilerSopkWaitcntMarkers() {
CheckSpirvBinaryValidates(result.spirv);
}
void TestSopkCompareImmediateExtension() {
using namespace ShaderRecompiler;
for (uint32_t opcode = 0x03; opcode <= 0x0e; opcode++) {
for (uint32_t immediate : {0x8000u, 0xffffu}) {
const std::array shader = {
EncodeSopk(opcode, 2, static_cast<int16_t>(immediate)),
EncodeSopp(0x01),
};
Decoder::Program decoded;
Decoder::DecodeProgram(shader, decoded);
const auto &operand = decoded.instructions.front().src1;
const int32_t expected = opcode < 0x09
? (immediate == 0x8000u ? -32768 : -1)
: static_cast<int32_t>(immediate);
Check(operand.value == static_cast<uint32_t>(expected) &&
operand.signed_val == expected,
"SOPK compare immediate extension does not match its signedness");
}
}
// GTA3's LUT GS exports its UV parameter only when packed primitive count > 0.
for (uint32_t counts : {0x00000006u, 0x00020006u}) {
const std::array shader = {
EncodeSMovB32(2, 255), counts,
0xb582ffffu, // s_cmpk_gt_u32 s2, 0xffff
EncodeSopp(0x04, 2), // s_cbranch_scc0 past exp param0
0xf800020fu, 0x06060504u, // exp param0 v4, v5, v6, v6
EncodeSopp(0x01),
};
auto translated =
TranslateProgram(shader, MakeCompileOptions(ShaderType::Vertex));
const auto branch = std::ranges::find_if(
translated.program.block_info, [](const auto &block) {
return block.terminator.condition == CFG::BranchCondition::SccZero;
});
Check(branch != translated.program.block_info.end(),
"captured LUT parameter export branch was lost");
const auto condition = branch->condition.Resolve();
Check(condition.IsImmediate() && condition.U1() == (counts == 6u),
"captured LUT unsigned compare suppressed a live parameter export");
}
}
void TestNewShaderRecompilerRdna2ScalarOpcodes() {
const uint32_t shader[] = {
EncodeSMovB32(2, 135), // s2 = 7
@@ -11896,6 +11939,7 @@ int main() {
// ShaderRecompilerComputeTests; keep the distinct decoder contract checks
// here.
TestNewShaderDecoderArchitecture();
TestSopkCompareImmediateExtension();
TestNewShaderRecompilerCapturedVopcSdwaCmpxClass();
TestNewShaderRecompilerIrLookupMissFailsExplicitly();
TestNewShaderRecompilerRejectsDppOn64BitCompares();