From d47b0524ce4fe692bcc2bd770a8fac0c347120b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Mon, 27 Apr 2026 22:35:37 +0200 Subject: [PATCH] V_ADD3_U32 and V_OR3_B32 (#4326) --- .../frontend/translate/translate.h | 2 + .../frontend/translate/vector_alu.cpp | 22 +++++ tests/gcn/test_gcn_instructions.cpp | 83 +++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index 11622f8a3..f4ef54a4d 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -275,6 +275,8 @@ public: void V_MUL_LO_U32(const GcnInst& inst); void V_MUL_HI_U32(bool is_signed, const GcnInst& inst); void V_MAD_U64_U32(const GcnInst& inst); + void V_ADD3_U32(const GcnInst& inst); + void V_OR3_B32(const GcnInst& inst); // Vector interpolation // VINTRP diff --git a/src/shader_recompiler/frontend/translate/vector_alu.cpp b/src/shader_recompiler/frontend/translate/vector_alu.cpp index 17cccf90b..c35a534aa 100644 --- a/src/shader_recompiler/frontend/translate/vector_alu.cpp +++ b/src/shader_recompiler/frontend/translate/vector_alu.cpp @@ -456,6 +456,10 @@ void Translator::EmitVectorAlu(const GcnInst& inst) { return V_MUL_HI_U32(true, inst); case Opcode::V_MAD_U64_U32: return V_MAD_U64_U32(inst); + case Opcode::V_ADD3_U32: + return V_ADD3_U32(inst); + case Opcode::V_OR3_B32: + return V_OR3_B32(inst); case Opcode::V_NOP: return; default: @@ -1548,6 +1552,24 @@ void Translator::V_MAD_U64_U32(const GcnInst& inst) { ir.SetVcc(did_overflow); } +void Translator::V_ADD3_U32(const GcnInst& inst) { + const auto src0 = GetSrc(inst.src[0]); + const auto src1 = GetSrc(inst.src[1]); + const auto src2 = GetSrc(inst.src[2]); + + SetDst(inst.dst[0], ir.IAdd(src0, ir.IAdd(src1, src2))); +} + +void Translator::V_OR3_B32(const GcnInst& inst) { + const auto src0 = GetSrc(inst.src[0]); + const auto src1 = GetSrc(inst.src[1]); + const auto src2 = GetSrc(inst.src[2]); + + const auto result = ir.BitwiseOr(ir.BitwiseOr(src0, src1), src2); + + SetDst(inst.dst[0], result); +} + IR::U32 Translator::GetCarryIn(const GcnInst& inst) { IR::U1 carry; if (inst.src_count == 3) { // VOP3 diff --git a/tests/gcn/test_gcn_instructions.cpp b/tests/gcn/test_gcn_instructions.cpp index e39f36a99..76659f1d6 100644 --- a/tests/gcn/test_gcn_instructions.cpp +++ b/tests/gcn/test_gcn_instructions.cpp @@ -161,3 +161,86 @@ TEST_F(GcnTest, min_nan) { EXPECT_TRUE(result.has_value()); EXPECT_EQ(*result, 0); } + +TEST_F(GcnTest, add3_u32_1) { + auto runner = gcn_test::Runner::instance().value(); + + auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_ADD3_U32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).Get()); + auto result = runner->run(spirv, std::array{0, 1, 2}); + + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(*result, 3); +} + +TEST_F(GcnTest, add3_u32_2) { + auto runner = gcn_test::Runner::instance().value(); + auto big = 2000000000; + + auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_ADD3_U32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).Get()); + auto result = runner->run(spirv, std::array{big, big, big}); + + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(*result, 0x65A0BC00); +} + +TEST_F(GcnTest, add3_u32_3) { + auto runner = gcn_test::Runner::instance().value(); + auto big = 2000000000; + + auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_ADD3_U32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetClamp(true).Get()); + auto result = runner->run(spirv, std::array{big, big, big}); + + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(*result, 0x65A0BC00); +} + +TEST_F(GcnTest, add3_u32_4) { + auto runner = gcn_test::Runner::instance().value(); + + auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_ADD3_U32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetNeg({1,0,0}).Get()); + auto result = runner->run(spirv, std::array{0, 1, 2}); + + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(*result, 0x80000003); +} + +TEST_F(GcnTest, or3_u32_1) { + auto runner = gcn_test::Runner::instance().value(); + + auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_OR3_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).Get()); + auto result = runner->run(spirv, std::array{0xF0F0F0F0, 0x07070707, 0x11111111}); + + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(*result, 0xF7F7F7F7); +} + +TEST_F(GcnTest, or3_u32_2) { + auto runner = gcn_test::Runner::instance().value(); + + auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_OR3_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).Get()); + auto result = runner->run(spirv, std::array{0x07070707, 0x11111111, 0x40404040}); + + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(*result, 0x57575757); +} + +TEST_F(GcnTest, or3_u32_3) { + auto runner = gcn_test::Runner::instance().value(); + auto big = 2000000000; + + auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_OR3_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetClamp(true).Get()); + auto result = runner->run(spirv, std::array{0x07070707, 0x11111111, 0x40404040}); + + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(*result, 0x57575757); +} + +TEST_F(GcnTest, or3_u32_4) { + auto runner = gcn_test::Runner::instance().value(); + + auto spirv = TranslateToSpirv(VOP3A(OpcodeVOP3::V_OR3_B32, VOperand8::V0, SOperand9::V0, SOperand9::V1, SOperand9::V2).SetNeg({0,0,1}).Get()); + auto result = runner->run(spirv, std::array{0x07070707, 0x11111111, 0x40404040}); + + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(*result, 0xD7575757); +}