From d9ae3ed64c69aaadd03f61d658ff157283a932c1 Mon Sep 17 00:00:00 2001 From: nmzik Date: Sat, 29 Aug 2026 14:03:57 +0400 Subject: [PATCH] shader: V_FFBH_I32 --- .../frontend/decode/ShaderDecoder.h | 1 + .../frontend/decode/VectorAluOps.cpp | 2 ++ .../recompiler/frontend/translate/Integer.cpp | 11 ++++--- .../frontend/translate/Translator.h | 2 +- .../recompiler/frontend/translate/Vector.cpp | 3 +- tests/ShaderRecompilerComputeTests.cpp | 32 +++++++++++++++++++ tests/shaderCfgTests.cpp | 12 +++++++ 7 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h index a2b346a56..03bb8c06b 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h @@ -185,6 +185,7 @@ enum class Opcode { V_BFREV_B32, V_FFBH_U32, V_FFBL_B32, + V_FFBH_I32, V_ADD_F32, V_SUB_F32, V_SUBREV_F32, diff --git a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp index 1e6c8663c..c2a26bc44 100644 --- a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp @@ -119,6 +119,7 @@ constexpr OpcodeMap VOP1_OPCODE_LIST[] = { {0x38u, Opcode::V_BFREV_B32}, {0x39u, Opcode::V_FFBH_U32}, {0x3au, Opcode::V_FFBL_B32}, + {0x3bu, Opcode::V_FFBH_I32}, {0x3fu, Opcode::V_FREXP_EXP_I32_F32}, {0x40u, Opcode::V_FREXP_MANT_F32}, {0x42u, Opcode::V_MOVRELD_B32}, @@ -169,6 +170,7 @@ constexpr OpcodeMap VOP3_ENCODED_VOP1_OPCODE_LIST[] = { {0x38u, Opcode::V_BFREV_B32}, {0x39u, Opcode::V_FFBH_U32}, {0x3au, Opcode::V_FFBL_B32}, + {0x3bu, Opcode::V_FFBH_I32}, {0x3fu, Opcode::V_FREXP_EXP_I32_F32}, {0x40u, Opcode::V_FREXP_MANT_F32}, {0x42u, Opcode::V_MOVRELD_B32}, diff --git a/src/graphics/shader/recompiler/frontend/translate/Integer.cpp b/src/graphics/shader/recompiler/frontend/translate/Integer.cpp index 2fa32851d..39dc0b6b3 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Integer.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Integer.cpp @@ -224,11 +224,14 @@ bool Translator::S_FF1_I32_B64(const Decoder::Instruction& inst) { return true; } -bool Translator::V_FFBH_U32(const Decoder::Instruction& inst) { - const auto source = ReadU32(inst.src0); - const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {source})); +bool Translator::V_FFBH_32(const Decoder::Instruction& inst, bool sign) { + const auto source = ReadU32(inst.src0); + const auto value = sign ? ir.BitwiseXor( + source, ir.ShiftRightArithmetic(source, IR::U32(IR::Value(31u)))) + : source; + const auto msb = IR::U32(ir.Emit(IR::ValueOpcode::FindUMsb32, {value})); const auto position = ir.ISub(IR::U32(IR::Value(31u)), msb); - const auto result = ir.Select(ir.INotEqual(source, IR::U32(IR::Value(0u))), position, + const auto result = ir.Select(ir.INotEqual(value, IR::U32(IR::Value(0u))), position, IR::U32(IR::Value(0xffffffffu))); WriteOperand(DestinationOperand(inst), result); return true; diff --git a/src/graphics/shader/recompiler/frontend/translate/Translator.h b/src/graphics/shader/recompiler/frontend/translate/Translator.h index 89c74e832..e59360c57 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Translator.h +++ b/src/graphics/shader/recompiler/frontend/translate/Translator.h @@ -182,7 +182,7 @@ private: bool V_OR3_B32(const Decoder::Instruction& inst); bool V_XOR3_B32(const Decoder::Instruction& inst); bool S_FF1_I32_B64(const Decoder::Instruction& inst); - bool V_FFBH_U32(const Decoder::Instruction& inst); + bool V_FFBH_32(const Decoder::Instruction& inst, bool sign); bool S_FLBIT_I32_B64(const Decoder::Instruction& inst); bool Integer24(const Decoder::Instruction& inst, bool sign, bool addend); bool V_MAD_U64_U32(const Decoder::Instruction& inst); diff --git a/src/graphics/shader/recompiler/frontend/translate/Vector.cpp b/src/graphics/shader/recompiler/frontend/translate/Vector.cpp index a3b8b721e..376677b84 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Vector.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Vector.cpp @@ -491,7 +491,8 @@ bool Translator::EmitVector(const Decoder::Instruction& inst, std::string* error case O::V_AND_OR_B32: return V_AND_OR_B32(inst); case O::V_OR3_B32: return V_OR3_B32(inst); case O::V_XOR3_B32: return V_XOR3_B32(inst); - case O::V_FFBH_U32: return V_FFBH_U32(inst); + case O::V_FFBH_U32: return V_FFBH_32(inst, false); + case O::V_FFBH_I32: return V_FFBH_32(inst, true); case O::V_MAD_I32_I24: return Integer24(inst, true, true); case O::V_MAD_U32_U24: return Integer24(inst, false, true); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index bdedc6d06..406d5a253 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -13356,6 +13356,37 @@ TestCase VectorIntegerOps() { O::S_ENDPGM}}; } +TestCase VectorFfbhI32NativeAndVop3OnGpu() { + using O = ShaderOpcode; + + constexpr std::array inputs = {0x00000000u, 0x40000000u, 0x80000000u, + 0x0fffffffu, 0xffff0000u, 0xfffffffeu, + 0xffffffffu, 0x80000000u}; + std::vector code; + for (u32 i = 0; i < inputs.size() - 1u; i++) { + AppendVMovU32(&code, 30, i * 4u); + AppendBufferLoadDword(&code, 14, 30); + code.push_back(0x7e1c770eu); // v_ffbh_i32 v14, v14 + AppendStoreVgpr(&code, 14, i); + } + AppendVMovU32(&code, 30, (inputs.size() - 1u) * 4u); + AppendBufferLoadDword(&code, 14, 30); + AppendVop3(&code, 0x1bbu, 15, Vgpr(14), 0); + AppendStoreVgpr(&code, 15, inputs.size() - 1u); + AppendEnd(&code); + + TestCase test; + test.name = "VectorFfbhI32NativeAndVop3OnGpu"; + test.code = std::move(code); + test.initial.assign(inputs.begin(), inputs.end()); + test.expected = {0xffffffffu, 1u, 1u, 4u, 16u, 31u, 0xffffffffu, 1u}; + test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_FFBH_I32, + O::BUFFER_STORE_DWORD, O::S_ENDPGM}; + test.decoded_counts = {{"V_FFBH_I32 v14, v14", inputs.size() - 1u}, + {"V_FFBH_I32 v15, v14", 1u}}; + return test; +} + TestCase Vop1SdwaFfblCapturedHighWordSource() { using O = ShaderOpcode; @@ -20492,6 +20523,7 @@ std::vector MakeCases() { AddCase(VectorMoves); AddCase(VectorVop3MoveAppliesFloatSourceModifiers); AddCase(VectorIntegerOps); + AddCase(VectorFfbhI32NativeAndVop3OnGpu); AddCase(Vop1SdwaFfblCapturedHighWordSource); AddCase(Vop1SdwaNotCapturedByte0Source); AddCase(Vop2SdwaSubNcExactByte2Destination); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index cbc144384..5237b101d 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -4019,6 +4019,18 @@ void TestNewShaderDecoderArchitecture() { cmp_eq_u64.src1.kind == OperandKind::VccLo, "decoder rejected the captured VOP3 V_CMP_EQ_U64 instruction"); + const uint32_t ffbh_i32_code[] = {0x7e1c770eu}; + Instruction ffbh_i32; + Check(DecodeInstruction(ffbh_i32_code, 0u, ffbh_i32, &error), + error.c_str()); + Check(ffbh_i32.family == Family::VOP1 && + ffbh_i32.opcode == Opcode::V_FFBH_I32 && + ffbh_i32.dst.kind == OperandKind::Vgpr && ffbh_i32.dst.reg == 14u && + ffbh_i32.src_count == 1u && + ffbh_i32.src0.kind == OperandKind::Vgpr && + ffbh_i32.src0.reg == 14u, + "decoder rejected the captured VOP1 V_FFBH_I32 instruction"); + const uint32_t literal_code[] = {EncodeVop1(0x01, 2, 255u), 0x12345678u}; Instruction literal; Check(DecodeInstruction(literal_code, 0u, literal, &error), error.c_str());