From 8145b3388200328b1ff0724a0fcd0c2d8320ff69 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 10 Jul 2016 08:18:17 +0800 Subject: [PATCH] Implemented thumb1_ROR_reg --- src/backend_x64/emit_x64.cpp | 39 +++++++++++++++++++++++++++++ src/backend_x64/emit_x64.h | 1 + src/frontend/decoder/thumb1.h | 4 +-- src/frontend/disassembler_thumb.cpp | 4 +++ src/frontend/ir/opcodes.inc | 1 + src/frontend/ir_emitter.cpp | 6 +++++ src/frontend/ir_emitter.h | 1 + src/frontend/translate_thumb.cpp | 12 +++++++++ 8 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index d818d593..305dacce 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -407,6 +407,45 @@ void EmitX64::EmitArithmeticShiftRight(IR::Value* value_) { } } +void EmitX64::EmitRotateRight(IR::Value* value_) { + auto value = reinterpret_cast(value_); + auto carry_inst = FindUseWithOpcode(value, IR::Opcode::GetCarryFromOp); + + if (!carry_inst) { + X64Reg shift = reg_alloc.UseRegister(value->GetArg(1).get(), {HostLoc::RCX}); + X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value); + + // x64 ROR instruction does (shift & 0x1F) for us. + code->ROR(32, R(result), R(shift)); + } else { + inhibit_emission.insert(carry_inst); + + X64Reg shift = reg_alloc.UseRegister(value->GetArg(1).get(), {HostLoc::RCX}); + X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value); + X64Reg carry = reg_alloc.UseDefRegister(value->GetArg(2).get(), carry_inst); + + // TODO: Optimize + + // if (Rs & 0xFF == 0) goto end; + code->TEST(8, R(shift), R(shift)); + auto Rs_zero = code->J_CC(CC_Z); + + code->AND(32, R(shift), Imm8(0x1F)); + auto zero_1F = code->J_CC(CC_Z); + // if (Rs & 0x1F != 0) { + code->ROR(32, R(result), R(shift)); + code->SETcc(CC_C, R(carry)); + auto jmp_to_end = code->J(); + // } else { + code->SetJumpTarget(zero_1F); + code->BT(32, R(result), Imm8(31)); + code->SETcc(CC_C, R(carry)); + // } + code->SetJumpTarget(jmp_to_end); + code->SetJumpTarget(Rs_zero); + } +} + void EmitX64::EmitAddWithCarry(IR::Value* value_) { auto value = reinterpret_cast(value_); auto carry_inst = FindUseWithOpcode(value, IR::Opcode::GetCarryFromOp); diff --git a/src/backend_x64/emit_x64.h b/src/backend_x64/emit_x64.h index 92625aae..beeef22c 100644 --- a/src/backend_x64/emit_x64.h +++ b/src/backend_x64/emit_x64.h @@ -52,6 +52,7 @@ public: void EmitLogicalShiftLeft(IR::Value* value); void EmitLogicalShiftRight(IR::Value* value); void EmitArithmeticShiftRight(IR::Value* value); + void EmitRotateRight(IR::Value* value); void EmitAddWithCarry(IR::Value* value); void EmitSubWithCarry(IR::Value* value); void EmitAnd(IR::Value* value); diff --git a/src/frontend/decoder/thumb1.h b/src/frontend/decoder/thumb1.h index 70826371..6bb03ea5 100644 --- a/src/frontend/decoder/thumb1.h +++ b/src/frontend/decoder/thumb1.h @@ -56,7 +56,7 @@ private: }; template -static const std::array, 20> g_thumb1_instruction_table {{ +static const std::array, 21> g_thumb1_instruction_table {{ #define INST(fn, name, bitstring) detail::detail::GetMatcher(name, bitstring) @@ -81,7 +81,7 @@ static const std::array, 20> g_thumb1_instruction_table {{ { INST(&V::thumb1_ASR_reg, "ASR (reg)", "0100000100mmmddd") }, { INST(&V::thumb1_ADC_reg, "ADC (reg)", "0100000101mmmddd") }, { INST(&V::thumb1_SBC_reg, "SBC (reg)", "0100000110mmmddd") }, - //{ INST(&V::thumb1_RORS_rr, "RORS (rr)", "0100000111sssddd") }, + { INST(&V::thumb1_ROR_reg, "ROR (reg)", "0100000111sssddd") }, //{ INST(&V::thumb1_TST_rr, "TST (rr)", "0100001000mmmnnn") }, //{ INST(&V::thumb1_NEGS_rr, "NEGS (rr)", "0100001001mmmddd") }, //{ INST(&V::thumb1_CMP_rr, "CMP (rr)", "0100001010mmmnnn") }, diff --git a/src/frontend/disassembler_thumb.cpp b/src/frontend/disassembler_thumb.cpp index 33b22859..fa661737 100644 --- a/src/frontend/disassembler_thumb.cpp +++ b/src/frontend/disassembler_thumb.cpp @@ -174,6 +174,10 @@ public: return Common::StringFromFormat("sbcs %s, %s", RegStr(d_n), RegStr(m)); } + std::string thumb1_ROR_reg(Reg m, Reg d_n) { + return Common::StringFromFormat("rors %s, %s", RegStr(d_n), RegStr(m)); + } + std::string thumb1_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) { Reg d_n = d_n_hi ? (d_n_lo + 8) : d_n_lo; return Common::StringFromFormat("add %s, %s", RegStr(d_n), RegStr(m)); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index fa659eb5..1c67e942 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -29,6 +29,7 @@ OPCODE(IsZero, T::U1, T::U32 OPCODE(LogicalShiftLeft, T::U32, T::U32, T::U8, T::U1 ) OPCODE(LogicalShiftRight, T::U32, T::U32, T::U8, T::U1 ) OPCODE(ArithmeticShiftRight, T::U32, T::U32, T::U8, T::U1 ) +OPCODE(RotateRight, T::U32, T::U32, T::U8, T::U1 ) OPCODE(AddWithCarry, T::U32, T::U32, T::U32, T::U1 ) OPCODE(SubWithCarry, T::U32, T::U32, T::U32, T::U1 ) OPCODE(And, T::U32, T::U32, T::U32 ) diff --git a/src/frontend/ir_emitter.cpp b/src/frontend/ir_emitter.cpp index f78dce19..ac08cca1 100644 --- a/src/frontend/ir_emitter.cpp +++ b/src/frontend/ir_emitter.cpp @@ -99,6 +99,12 @@ IREmitter::ResultAndCarry IREmitter::ArithmeticShiftRight(IR::ValuePtr value_in, return {result, carry_out}; } +IREmitter::ResultAndCarry IREmitter::RotateRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in) { + auto result = Inst(IR::Opcode::RotateRight, {value_in, shift_amount, carry_in}); + auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result}); + return {result, carry_out}; +} + IREmitter::ResultAndCarryAndOverflow IREmitter::AddWithCarry(IR::ValuePtr a, IR::ValuePtr b, IR::ValuePtr carry_in) { auto result = Inst(IR::Opcode::AddWithCarry, {a, b, carry_in}); auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result}); diff --git a/src/frontend/ir_emitter.h b/src/frontend/ir_emitter.h index b550dc77..f713dcb2 100644 --- a/src/frontend/ir_emitter.h +++ b/src/frontend/ir_emitter.h @@ -55,6 +55,7 @@ public: ResultAndCarry LogicalShiftLeft(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in); ResultAndCarry LogicalShiftRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in); ResultAndCarry ArithmeticShiftRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in); + ResultAndCarry RotateRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in); ResultAndCarryAndOverflow AddWithCarry(IR::ValuePtr a, IR::ValuePtr b, IR::ValuePtr carry_in); ResultAndCarryAndOverflow SubWithCarry(IR::ValuePtr a, IR::ValuePtr b, IR::ValuePtr carry_in); IR::ValuePtr And(IR::ValuePtr a, IR::ValuePtr b); diff --git a/src/frontend/translate_thumb.cpp b/src/frontend/translate_thumb.cpp index 8d752d60..32fe45ef 100644 --- a/src/frontend/translate_thumb.cpp +++ b/src/frontend/translate_thumb.cpp @@ -239,6 +239,18 @@ struct TranslatorVisitor final { ir.SetVFlag(result.overflow); return true; } + bool thumb1_ROR_reg(Reg m, Reg d_n) { + Reg d = d_n, n = d_n; + // RORS , + auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m)); + auto cpsr_c = ir.GetCFlag(); + auto result = ir.RotateRight(ir.GetRegister(n), shift_n, cpsr_c); + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + return true; + } bool thumb1_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) { Reg d_n = d_n_hi ? (d_n_lo + 8) : d_n_lo;