From 8e68e6fdd94ce0591b6ca5df6acffb4e0ab37359 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Aug 2016 13:42:16 -0400 Subject: [PATCH] TranslateArm: Implement QADD16/QSUB16/UQADD16/UQSUB16. --- src/backend_x64/emit_x64.cpp | 16 +++++++++++++ .../disassembler/disassembler_arm.cpp | 16 +++++++++---- src/frontend/ir/ir_emitter.cpp | 16 +++++++++++++ src/frontend/ir/ir_emitter.h | 4 ++++ src/frontend/ir/opcodes.inc | 4 ++++ .../translate/translate_arm/parallel.cpp | 24 +++++++++++++++---- tests/arm/fuzz_arm.cpp | 10 +++++--- 7 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index 3ba351bc..4d3f5cde 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -1089,6 +1089,22 @@ void EmitX64::EmitPackedSaturatedSubS8(IR::Block& block, IR::Inst* inst) { EmitPackedOperation(code, reg_alloc, inst, &XEmitter::PSUBSB); } +void EmitX64::EmitPackedSaturatedAddU16(IR::Block& block, IR::Inst* inst) { + EmitPackedOperation(code, reg_alloc, inst, &XEmitter::PADDUSW); +} + +void EmitX64::EmitPackedSaturatedAddS16(IR::Block& block, IR::Inst* inst) { + EmitPackedOperation(code, reg_alloc, inst, &XEmitter::PADDSW); +} + +void EmitX64::EmitPackedSaturatedSubU16(IR::Block& block, IR::Inst* inst) { + EmitPackedOperation(code, reg_alloc, inst, &XEmitter::PSUBUSW); +} + +void EmitX64::EmitPackedSaturatedSubS16(IR::Block& block, IR::Inst* inst) { + EmitPackedOperation(code, reg_alloc, inst, &XEmitter::PSUBSW); +} + 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 5ae74d9e..6e6963b5 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -666,23 +666,31 @@ public: 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_QADD16(Cond cond, Reg n, Reg d, Reg m) { + return Common::StringFromFormat("qadd16%s %s, %s, %s", CondToString(cond), RegToString(d), RegToString(n), RegToString(m)); + } 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"; } std::string arm_QSUB8(Cond cond, Reg n, Reg d, Reg m) { 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_QSUB16(Cond cond, Reg n, Reg d, Reg m) { + return Common::StringFromFormat("qsub16%s %s, %s, %s", CondToString(cond), RegToString(d), RegToString(n), RegToString(m)); + } 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_UQADD16(Cond cond, Reg n, Reg d, Reg m) { + return Common::StringFromFormat("uqadd16%s %s, %s, %s", CondToString(cond), RegToString(d), RegToString(n), RegToString(m)); + } 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 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"; } + std::string arm_UQSUB16(Cond cond, Reg n, Reg d, Reg m) { + return Common::StringFromFormat("uqsub16%s %s, %s, %s", CondToString(cond), RegToString(d), RegToString(n), RegToString(m)); + } // Parallel Add/Subtract (Halving) instructions std::string arm_SHADD8(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 547d5159..b59d65e5 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -298,6 +298,22 @@ IR::Value IREmitter::PackedSaturatedSubS8(const IR::Value& a, const IR::Value& b return Inst(IR::Opcode::PackedSaturatedSubS8, {a, b}); } +IR::Value IREmitter::PackedSaturatedAddU16(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::PackedSaturatedAddU16, {a, b}); +} + +IR::Value IREmitter::PackedSaturatedAddS16(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::PackedSaturatedAddS16, {a, b}); +} + +IR::Value IREmitter::PackedSaturatedSubU16(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::PackedSaturatedSubU16, {a, b}); +} + +IR::Value IREmitter::PackedSaturatedSubS16(const IR::Value& a, const IR::Value& b) { + return Inst(IR::Opcode::PackedSaturatedSubS16, {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 5d38e21f..89372087 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -102,6 +102,10 @@ public: 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); + IR::Value PackedSaturatedAddU16(const IR::Value& a, const IR::Value& b); + IR::Value PackedSaturatedAddS16(const IR::Value& a, const IR::Value& b); + IR::Value PackedSaturatedSubU16(const IR::Value& a, const IR::Value& b); + IR::Value PackedSaturatedSubS16(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 ebd34526..6aac8ad2 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -64,6 +64,10 @@ 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 ) +OPCODE(PackedSaturatedAddU16, T::U32, T::U32, T::U32 ) +OPCODE(PackedSaturatedAddS16, T::U32, T::U32, T::U32 ) +OPCODE(PackedSaturatedSubU16, T::U32, T::U32, T::U32 ) +OPCODE(PackedSaturatedSubS16, 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 ca7226dd..c32ee592 100644 --- a/src/frontend/translate/translate_arm/parallel.cpp +++ b/src/frontend/translate/translate_arm/parallel.cpp @@ -69,7 +69,11 @@ bool ArmTranslatorVisitor::arm_QADD8(Cond cond, Reg n, Reg d, Reg m) { } bool ArmTranslatorVisitor::arm_QADD16(Cond cond, Reg n, Reg d, Reg m) { - return InterpretThisInstruction(); + if (ConditionPassed(cond)) { + auto result = ir.PackedSaturatedAddS16(ir.GetRegister(n), ir.GetRegister(m)); + ir.SetRegister(d, result); + } + return true; } bool ArmTranslatorVisitor::arm_QASX(Cond cond, Reg n, Reg d, Reg m) { @@ -89,7 +93,11 @@ bool ArmTranslatorVisitor::arm_QSUB8(Cond cond, Reg n, Reg d, Reg m) { } bool ArmTranslatorVisitor::arm_QSUB16(Cond cond, Reg n, Reg d, Reg m) { - return InterpretThisInstruction(); + if (ConditionPassed(cond)) { + auto result = ir.PackedSaturatedSubS16(ir.GetRegister(n), ir.GetRegister(m)); + ir.SetRegister(d, result); + } + return true; } bool ArmTranslatorVisitor::arm_UQADD8(Cond cond, Reg n, Reg d, Reg m) { @@ -101,7 +109,11 @@ bool ArmTranslatorVisitor::arm_UQADD8(Cond cond, Reg n, Reg d, Reg m) { } bool ArmTranslatorVisitor::arm_UQADD16(Cond cond, Reg n, Reg d, Reg m) { - return InterpretThisInstruction(); + if (ConditionPassed(cond)) { + auto result = ir.PackedSaturatedAddU16(ir.GetRegister(n), ir.GetRegister(m)); + ir.SetRegister(d, result); + } + return true; } bool ArmTranslatorVisitor::arm_UQASX(Cond cond, Reg n, Reg d, Reg m) { @@ -121,7 +133,11 @@ bool ArmTranslatorVisitor::arm_UQSUB8(Cond cond, Reg n, Reg d, Reg m) { } bool ArmTranslatorVisitor::arm_UQSUB16(Cond cond, Reg n, Reg d, Reg m) { - return InterpretThisInstruction(); + if (ConditionPassed(cond)) { + auto result = ir.PackedSaturatedSubU16(ir.GetRegister(n), ir.GetRegister(m)); + ir.SetRegister(d, result); + } + return true; } diff --git a/tests/arm/fuzz_arm.cpp b/tests/arm/fuzz_arm.cpp index 337fb5b2..7c67d957 100644 --- a/tests/arm/fuzz_arm.cpp +++ b/tests/arm/fuzz_arm.cpp @@ -829,11 +829,15 @@ 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 = {{ - InstructionGenerator("cccc01100110nnnndddd11111111mmmm", is_valid), // UQSUB8 - InstructionGenerator("cccc01100010nnnndddd11111111mmmm", is_valid), // QSUB8 + const std::array saturating_instructions = {{ InstructionGenerator("cccc01100010nnnndddd11111001mmmm", is_valid), // QADD8 + InstructionGenerator("cccc01100010nnnndddd11111111mmmm", is_valid), // QSUB8 InstructionGenerator("cccc01100110nnnndddd11111001mmmm", is_valid), // UQADD8 + InstructionGenerator("cccc01100110nnnndddd11111111mmmm", is_valid), // UQSUB8 + InstructionGenerator("cccc01100010nnnndddd11110001mmmm", is_valid), // QADD16 + InstructionGenerator("cccc01100010nnnndddd11110111mmmm", is_valid), // QSUB16 + InstructionGenerator("cccc01100110nnnndddd11110001mmmm", is_valid), // UQADD16 + InstructionGenerator("cccc01100110nnnndddd11110111mmmm", is_valid), // UQSUB16 }}; SECTION("Parallel Add/Subtract (Saturating)") {