From fa32940d1474631ed156c1a6fae4a3ffdd413317 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 21 Oct 2026 22:59:56 +0200 Subject: [PATCH] shader: drop BFM mask bits shifted past bit 31 instead of an out-of-range bit-field insert --- .../recompiler/frontend/translate/Integer.cpp | 5 ++-- tests/ShaderRecompilerComputeTests.cpp | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/graphics/shader/recompiler/frontend/translate/Integer.cpp b/src/graphics/shader/recompiler/frontend/translate/Integer.cpp index 7fe8967c6..0a69f9e4c 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Integer.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Integer.cpp @@ -380,9 +380,8 @@ void Translator::S_QUADMASK_B64(const Decoder::Instruction& inst) { void Translator::BFM_B32(const Decoder::Instruction& inst) { const auto count = ir.BitwiseAnd(ReadU32(inst.src0), IR::U32(IR::Value(31u))); const auto offset = ir.BitwiseAnd(ReadU32(inst.src1), IR::U32(IR::Value(31u))); - const auto result = ir.Emit(IR::ValueOpcode::BitFieldInsert, - {IR::Value(0u), IR::Value(0xffffffffu), offset, count}); - WriteOperand(DestinationOperand(inst), result); + // Mask bits shifted past bit 31 are dropped. + WriteOperand(DestinationOperand(inst), ir.ShiftLeftLogical(RightMask32(count), offset)); } IR::U32 Translator::RightMask32(IR::U32 count) { diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 97caf606a..0d4272408 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -25622,6 +25622,31 @@ TestCase VectorBfeI32SignExtendsField() { return test; } +TestCase VectorBfmDropsMaskBitsPastBit31() { + using O = ShaderOpcode; + + std::vector code; + for (u32 vgpr = 0; vgpr < 4; vgpr++) { + AppendVMovU32(&code, 30, vgpr * sizeof(u32)); + AppendBufferLoadDword(&code, vgpr, 30); + } + AppendVop3(&code, 0x363, 10, Vgpr(0), Vgpr(1)); + AppendVop3(&code, 0x363, 11, Vgpr(2), Vgpr(3)); + AppendStoreVgpr(&code, 10, 0); + AppendStoreVgpr(&code, 11, 1); + AppendEnd(&code); + + TestCase test; + test.name = "VectorBfmDropsMaskBitsPastBit31"; + test.code = std::move(code); + // Size and offset use bits [4:0]; mask bits shifted past bit 31 are dropped. + test.initial = {24, 16, 0x3fu, 0x21u}; + test.expected = {0xffff0000u, 0xfffffffeu}; + test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_BFM_B32, + O::BUFFER_STORE_DWORD, O::S_ENDPGM}; + return test; +} + TestCase VectorAlignByteUsesTwoBitByteOffset() { using O = ShaderOpcode; @@ -42981,6 +43006,7 @@ std::vector MakeCases() { AddCase(VectorVop3LshlrevB64Captured); AddCase(VectorVop3IntegerOps); AddCase(VectorBfeI32SignExtendsField); + AddCase(VectorBfmDropsMaskBitsPastBit31); AddCase(VectorAlignByteUsesTwoBitByteOffset); AddCase(VectorCarryAndBitCountOps); AddCase(ScalarVector64BitFloatInlineConstants);