diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index 93ad037c..3ba351bc 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -1073,6 +1073,14 @@ static void EmitPackedOperation(BlockOfCode* code, RegAlloc& reg_alloc, IR::Inst code->MOVD_xmm(R(result), xmm_scratch_a); } +void EmitX64::EmitPackedSaturatedAddU8(IR::Block& block, IR::Inst* inst) { + EmitPackedOperation(code, reg_alloc, inst, &XEmitter::PADDUSB); +} + +void EmitX64::EmitPackedSaturatedAddS8(IR::Block& block, IR::Inst* inst) { + EmitPackedOperation(code, reg_alloc, inst, &XEmitter::PADDSB); +} + void EmitX64::EmitPackedSaturatedSubU8(IR::Block& block, IR::Inst* inst) { EmitPackedOperation(code, reg_alloc, inst, &XEmitter::PSUBUSB); } diff --git a/src/frontend/disassembler/disassembler_arm.cpp b/src/frontend/disassembler/disassembler_arm.cpp index d01830c4..5ae74d9e 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -663,7 +663,9 @@ public: std::string arm_USUB16(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } // Parallel Add/Subtract (Saturating) instructions - std::string arm_QADD8(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } + std::string arm_QADD8(Cond cond, Reg n, Reg d, Reg m) { + return Common::StringFromFormat("qadd8%s %s, %s, %s", CondToString(cond), RegToString(d), RegToString(n), RegToString(m)); + } std::string arm_QADD16(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } std::string arm_QASX(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } std::string arm_QSAX(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } @@ -671,7 +673,9 @@ public: return Common::StringFromFormat("qsub8%s %s, %s, %s", CondToString(cond), RegToString(d), RegToString(n), RegToString(m)); } std::string arm_QSUB16(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } - std::string arm_UQADD8(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } + std::string arm_UQADD8(Cond cond, Reg n, Reg d, Reg m) { + return Common::StringFromFormat("uqadd8%s %s, %s, %s", CondToString(cond), RegToString(d), RegToString(n), RegToString(m)); + } std::string arm_UQADD16(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } std::string arm_UQASX(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } std::string arm_UQSAX(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 1ba79157..547d5159 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -282,6 +282,14 @@ IR::Value IREmitter::ByteReverseDual(const IR::Value& a) { return Inst(IR::Opcode::ByteReverseDual, {a}); } +IR::Value IREmitter::PackedSaturatedAddU8(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::PackedSaturatedAddU8, {a, b}); +} + +IR::Value IREmitter::PackedSaturatedAddS8(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::PackedSaturatedAddS8, {a, b}); +} + IR::Value IREmitter::PackedSaturatedSubU8(const IR::Value& a, const IR::Value& b) { return Inst(IR::Opcode::PackedSaturatedSubU8, {a, b}); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 85edfcfa..5d38e21f 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -98,6 +98,8 @@ public: IR::Value ByteReverseWord(const IR::Value& a); IR::Value ByteReverseHalf(const IR::Value& a); IR::Value ByteReverseDual(const IR::Value& a); + IR::Value PackedSaturatedAddU8(const IR::Value& a, const IR::Value& b); + IR::Value PackedSaturatedAddS8(const IR::Value& a, const IR::Value& b); IR::Value PackedSaturatedSubU8(const IR::Value& a, const IR::Value& b); IR::Value PackedSaturatedSubS8(const IR::Value& a, const IR::Value& b); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index 792cdf25..ebd34526 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -60,6 +60,8 @@ OPCODE(ZeroExtendByteToWord, T::U32, T::U8 OPCODE(ByteReverseWord, T::U32, T::U32 ) OPCODE(ByteReverseHalf, T::U16, T::U16 ) OPCODE(ByteReverseDual, T::U64, T::U64 ) +OPCODE(PackedSaturatedAddU8, T::U32, T::U32, T::U32 ) +OPCODE(PackedSaturatedAddS8, T::U32, T::U32, T::U32 ) OPCODE(PackedSaturatedSubU8, T::U32, T::U32, T::U32 ) OPCODE(PackedSaturatedSubS8, T::U32, T::U32, T::U32 ) diff --git a/src/frontend/translate/translate_arm/parallel.cpp b/src/frontend/translate/translate_arm/parallel.cpp index 8249a2a1..ca7226dd 100644 --- a/src/frontend/translate/translate_arm/parallel.cpp +++ b/src/frontend/translate/translate_arm/parallel.cpp @@ -61,7 +61,11 @@ bool ArmTranslatorVisitor::arm_USUB16(Cond cond, Reg n, Reg d, Reg m) { // Parallel Add/Subtract (Saturating) instructions bool ArmTranslatorVisitor::arm_QADD8(Cond cond, Reg n, Reg d, Reg m) { - return InterpretThisInstruction(); + if (ConditionPassed(cond)) { + auto result = ir.PackedSaturatedAddS8(ir.GetRegister(n), ir.GetRegister(m)); + ir.SetRegister(d, result); + } + return true; } bool ArmTranslatorVisitor::arm_QADD16(Cond cond, Reg n, Reg d, Reg m) { @@ -89,7 +93,11 @@ bool ArmTranslatorVisitor::arm_QSUB16(Cond cond, Reg n, Reg d, Reg m) { } bool ArmTranslatorVisitor::arm_UQADD8(Cond cond, Reg n, Reg d, Reg m) { - return InterpretThisInstruction(); + if (ConditionPassed(cond)) { + auto result = ir.PackedSaturatedAddU8(ir.GetRegister(n), ir.GetRegister(m)); + ir.SetRegister(d, result); + } + return true; } bool ArmTranslatorVisitor::arm_UQADD16(Cond cond, Reg n, Reg d, Reg m) { diff --git a/tests/arm/fuzz_arm.cpp b/tests/arm/fuzz_arm.cpp index d2866d01..337fb5b2 100644 --- a/tests/arm/fuzz_arm.cpp +++ b/tests/arm/fuzz_arm.cpp @@ -829,9 +829,11 @@ TEST_CASE("Fuzz ARM parallel instructions", "[JitX64]") { return Bits<0, 3>(instr) != 0b1111 && Bits<12, 15>(instr) != 0b1111 && Bits<16, 19>(instr) != 0b1111; }; - const std::array saturating_instructions = {{ + const std::array saturating_instructions = {{ InstructionGenerator("cccc01100110nnnndddd11111111mmmm", is_valid), // UQSUB8 InstructionGenerator("cccc01100010nnnndddd11111111mmmm", is_valid), // QSUB8 + InstructionGenerator("cccc01100010nnnndddd11111001mmmm", is_valid), // QADD8 + InstructionGenerator("cccc01100110nnnndddd11111001mmmm", is_valid), // UQADD8 }}; SECTION("Parallel Add/Subtract (Saturating)") {