From 86fe29c6d2127e1154fa13b8dbf62d23d5d02d7f Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Aug 2016 11:53:16 -0400 Subject: [PATCH] TranslateArm: Implement UQSUB8. --- src/backend_x64/emit_x64.cpp | 18 ++++++++++++++++++ src/frontend/disassembler/disassembler_arm.cpp | 4 +++- src/frontend/ir/ir_emitter.cpp | 4 ++++ src/frontend/ir/ir_emitter.h | 1 + src/frontend/ir/opcodes.inc | 1 + .../translate/translate_arm/parallel.cpp | 6 +++++- tests/arm/fuzz_arm.cpp | 17 +++++++++++++++++ 7 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index f4815176..a3b5ee5a 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -1055,6 +1055,24 @@ void EmitX64::EmitByteReverseDual(IR::Block&, IR::Inst* inst) { code->BSWAP(64, result); } +void EmitX64::EmitPackedSaturatedSubU8(IR::Block& block, IR::Inst* inst) { + IR::Value a = inst->GetArg(0); + IR::Value b = inst->GetArg(1); + + X64Reg result = reg_alloc.UseDefRegister(a, inst, any_gpr); + OpArg op_arg = reg_alloc.UseOpArg(b, any_gpr); + + X64Reg xmm_scratch_a = reg_alloc.ScratchRegister(any_xmm); + X64Reg xmm_scratch_b = reg_alloc.ScratchRegister(any_xmm); + + code->MOVD_xmm(xmm_scratch_a, R(result)); + code->MOVD_xmm(xmm_scratch_b, op_arg); + + code->PSUBUSB(xmm_scratch_a, R(xmm_scratch_b)); + + code->MOVD_xmm(R(result), xmm_scratch_a); +} + static void DenormalsAreZero32(BlockOfCode* code, X64Reg xmm_value, X64Reg gpr_scratch) { // We need to report back whether we've found a denormal on input. // SSE doesn't do this for us when SSE's DAZ is enabled. diff --git a/src/frontend/disassembler/disassembler_arm.cpp b/src/frontend/disassembler/disassembler_arm.cpp index 5750d2a5..17b9f28b 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -673,7 +673,9 @@ public: 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"; } - std::string arm_UQSUB8(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } + std::string arm_UQSUB8(Cond cond, Reg n, Reg d, Reg m) { + return Common::StringFromFormat("uqsub8%s %s, %s, %s", CondToString(cond), RegToString(d), RegToString(n), RegToString(m)); + } std::string arm_UQSUB16(Cond cond, Reg n, Reg d, Reg m) { return "ice"; } // Parallel Add/Subtract (Halving) instructions diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 26bb7703..8e6882b8 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -282,6 +282,10 @@ IR::Value IREmitter::ByteReverseDual(const IR::Value& a) { return Inst(IR::Opcode::ByteReverseDual, {a}); } +IR::Value IREmitter::PackedSaturatedSubU8(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::PackedSaturatedSubU8, {a, b}); +} + IR::Value IREmitter::TransferToFP32(const IR::Value& a) { return Inst(IR::Opcode::TransferToFP32, {a}); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 85ce1733..7519d614 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -98,6 +98,7 @@ public: IR::Value ByteReverseWord(const IR::Value& a); IR::Value ByteReverseHalf(const IR::Value& a); IR::Value ByteReverseDual(const IR::Value& a); + IR::Value PackedSaturatedSubU8(const IR::Value& a, const IR::Value& b); IR::Value TransferToFP32(const IR::Value& a); IR::Value TransferToFP64(const IR::Value& a); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index c4072883..c0a6b9e7 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -60,6 +60,7 @@ 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(PackedSaturatedSubU8, T::U32, T::U32, T::U32 ) // Floating-point OPCODE(TransferToFP32, T::F32, T::U32 ) diff --git a/src/frontend/translate/translate_arm/parallel.cpp b/src/frontend/translate/translate_arm/parallel.cpp index ac13702e..e6bf271f 100644 --- a/src/frontend/translate/translate_arm/parallel.cpp +++ b/src/frontend/translate/translate_arm/parallel.cpp @@ -101,7 +101,11 @@ bool ArmTranslatorVisitor::arm_UQSAX(Cond cond, Reg n, Reg d, Reg m) { } bool ArmTranslatorVisitor::arm_UQSUB8(Cond cond, Reg n, Reg d, Reg m) { - return InterpretThisInstruction(); + if (ConditionPassed(cond)) { + auto result = ir.PackedSaturatedSubU8(ir.GetRegister(n), ir.GetRegister(m)); + ir.SetRegister(d, result); + } + return true; } bool ArmTranslatorVisitor::arm_UQSUB16(Cond cond, Reg n, Reg d, Reg m) { diff --git a/tests/arm/fuzz_arm.cpp b/tests/arm/fuzz_arm.cpp index 3aa49e53..38dd6c72 100644 --- a/tests/arm/fuzz_arm.cpp +++ b/tests/arm/fuzz_arm.cpp @@ -822,3 +822,20 @@ TEST_CASE("Fuzz ARM multiply instructions", "[JitX64]") { }); } } + +TEST_CASE("Fuzz ARM parallel instructions", "[JitX64]") { + const auto is_valid = [](u32 instr) -> bool { + // R15 as Rd, Rn, or Rm is UNPREDICTABLE + return Bits<0, 3>(instr) != 0b1111 && Bits<12, 15>(instr) != 0b1111 && Bits<16, 19>(instr) != 0b1111; + }; + + const std::array saturating_instructions = {{ + InstructionGenerator("cccc01100110nnnndddd11111111mmmm", is_valid), // UQSUB8 + }}; + + SECTION("Parallel Add/Subtract (Saturating)") { + FuzzJitArm(1, 1, 10000, [&saturating_instructions]() -> u32 { + return saturating_instructions[RandInt(0, saturating_instructions.size() - 1)].Generate(); + }); + } +}