shader: fix wave32 VCC halves and scalar mask moves

Co-authored-by: Brandon Strong <brandostrong@gmail.com>
This commit is contained in:
nmzik
2026-09-07 06:04:40 +04:00
parent bf7ca29487
commit 6cc9e5de11
3 changed files with 56 additions and 5 deletions
@@ -240,10 +240,6 @@ void Translator::MOV_B32(const Decoder::Instruction& inst, bool apply_float_modi
}
void Translator::S_MOV_B64(const Decoder::Instruction& inst) {
if (IsExecOrVcc(inst.dst) || IsExecOrVcc(inst.src0)) {
WriteMask(inst.dst, ReadMask(inst.src0), true);
return;
}
const bool scalar_copy =
inst.dst.kind == Decoder::OperandKind::Sgpr && inst.src0.kind == Decoder::OperandKind::Sgpr;
IR::U1 source_mask;
@@ -631,7 +631,10 @@ IR::U1 Translator::ReadMask(const Decoder::Operand& operand) {
case Decoder::OperandKind::ExecLo:
case Decoder::OperandKind::ExecHi: return ir.GetExec();
case Decoder::OperandKind::VccLo:
case Decoder::OperandKind::VccHi: return ir.GetVcc();
case Decoder::OperandKind::VccHi:
return current_wave_size == 32u
? ThreadBit({ReadRawU32(operand), IR::U32(IR::Value(0u))})
: ir.GetVcc();
case Decoder::OperandKind::Scc: return ir.GetScc();
case Decoder::OperandKind::VccZ: return ir.LogicalNot(ir.GetVcc());
case Decoder::OperandKind::ExecZ: return ir.LogicalNot(ir.GetExec());
@@ -697,6 +700,10 @@ std::array<IR::U32, 2> Translator::WriteMask(const Decoder::Operand& operand, IR
}
case Decoder::OperandKind::VccLo:
case Decoder::OperandKind::VccHi: {
if (!write_64 && current_wave_size == 32u) {
WriteRawU32(operand, mask[0]);
return mask;
}
ir.SetVcc(value);
ir.SetVccLo(mask[0]);
ir.SetVccHi(mask[1]);
+48
View File
@@ -18191,6 +18191,52 @@ TestCase VectorVopcSdwaCmpxClassF32CapturedExecMask() {
return test;
}
TestCase Wave32VccMasksPreserveOtherHalf() {
using O = ShaderOpcode;
TestCase test;
test.name = "Wave32VccMasksPreserveOtherHalf";
auto &code = test.code;
AppendSMovLiteral(&code, 106, 0x12345678u);
AppendSMovLiteral(&code, 107, 0x2468ace0u);
AppendVMovU32(&code, 1, 20);
u32 offset = 0;
const auto check_masks = [&](u32 low, u32 high) {
AppendStoreSgprAtLaneDwordOffset(&code, 106, 0, offset);
AppendStoreSgprAtLaneDwordOffset(&code, 107, 0, offset + 4);
AppendVop3(&code, 0x101, 2, InlineU32(10), Vgpr(1), 107);
code.push_back(EncodeVop2(0x01, 3, InlineU32(10), 1));
AppendStoreVgprAtLaneDwordOffset(&code, 2, 0, offset + 8);
AppendStoreVgprAtLaneDwordOffset(&code, 3, 0, offset + 12);
test.expected.insert(test.expected.end(), 4, low);
test.expected.insert(test.expected.end(), 4, high);
for (u32 mask : {high, low}) {
for (u32 lane = 0; lane < 4; ++lane) {
test.expected.push_back((mask & (1u << lane)) != 0 ? 20u : 10u);
}
}
offset += 16;
};
// PPSA10737 keeps a table offset in VCC_LO while comparing into VCC_HI.
AppendVop3(&code, 0xc2, 107, InlineU32(1), Vgpr(0));
check_masks(0x12345678u, 2u);
AppendVop3(&code, 0xc2, 106, InlineU32(2), Vgpr(0));
check_masks(4u, 2u);
code.push_back(EncodeSop2(0x10, 106, 106, 107)); // s_or_b32
check_masks(6u, 2u);
code.push_back(EncodeSop1(0x04, 106, 193u)); // Explicit s_mov_b64 writes both.
check_masks(0xffffffffu, 0xffffffffu);
AppendEnd(&code);
test.opcodes = {O::S_MOV_B32, O::S_MOV_B64, O::S_OR_B32, O::V_MOV_B32,
O::V_CMP_EQ_U32, O::V_CNDMASK_B32, O::V_LSHLREV_B32,
O::V_ADD_NC_U32, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.compute_info.threads_num[0] = 4;
test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1;
test.compute_info.thread_ids_num = 1;
test.compute_info.wave_size = 32;
test.has_compute_info = true;
return test;
}
TestCase VectorCompareF16Ops() {
using O = ShaderOpcode;
@@ -23655,6 +23701,7 @@ std::vector<TestCase> MakeCases() {
AddCase(VectorCompareClassF32);
AddCase(VectorVopcSdwaCmpxClassF32CapturedExecMask);
AddCase(VectorCompareF16Ops);
AddCase(Wave32VccMasksPreserveOtherHalf);
AddCase(Vop2SdwaCndmaskSourceModifier);
AddCase(Vop2SdwaCndmaskCapturedByte3Source);
AddCase(Vop3CndmaskUsesSgprMaskLaneBits);
@@ -28024,6 +28071,7 @@ int main(int argc, char **argv) {
#endif
if (argc == 2 && std::strcmp(argv[1], "--wave64-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, Wave32VccMasksPreserveOtherHalf());
RunCase(&vulkan, DsBpermuteWave64UsesIndependentHalves());
RunCase(&vulkan, Wave64CrossHalfLaneAndLds());
RunCase(&vulkan, Wave64RawMasksAndScalarBranch());