diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index c50b8d30..610250bc 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -636,6 +636,24 @@ void EmitX64::EmitRotateRight(IR::Block& block, IR::Inst* inst) { } } +void EmitX64::EmitRotateRightExtended(IR::Block& block, IR::Inst* inst) { + auto carry_inst = FindUseWithOpcode(inst, IR::Opcode::GetCarryFromOp); + + X64Reg result = reg_alloc.UseDefRegister(inst->GetArg(0), inst, any_gpr); + X64Reg carry = carry_inst + ? reg_alloc.UseDefRegister(inst->GetArg(1), carry_inst, any_gpr) + : reg_alloc.UseRegister(inst->GetArg(1), any_gpr); + + code->BT(32, R(carry), Imm8(0)); + code->RCR(32, R(result), Imm8(1)); + + if (carry_inst) { + EraseInstruction(block, carry_inst); + reg_alloc.DecrementRemainingUses(inst); + code->SETcc(CC_C, R(carry)); + } +} + static X64Reg DoCarry(RegAlloc& reg_alloc, const IR::Value& carry_in, IR::Inst* carry_out) { if (carry_in.IsImmediate()) { return carry_out ? reg_alloc.DefRegister(carry_out, any_gpr) : INVALID_REG; diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 869b5335..d025d1d5 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -138,6 +138,12 @@ IREmitter::ResultAndCarry IREmitter::RotateRight(const IR::Value& value_in, cons return {result, carry_out}; } +IREmitter::ResultAndCarry IREmitter::RotateRightExtended(const IR::Value& value_in, const IR::Value& carry_in) { + auto result = Inst(IR::Opcode::RotateRightExtended, {value_in, carry_in}); + auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result}); + return {result, carry_out}; +} + IREmitter::ResultAndCarryAndOverflow IREmitter::AddWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& 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/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 165cc058..202c12f3 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -63,6 +63,7 @@ public: ResultAndCarry LogicalShiftRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in); ResultAndCarry ArithmeticShiftRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in); ResultAndCarry RotateRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in); + ResultAndCarry RotateRightExtended(const IR::Value& value_in, const IR::Value& carry_in); ResultAndCarryAndOverflow AddWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& carry_in); IR::Value Add(const IR::Value& a, const IR::Value& b); ResultAndCarryAndOverflow SubWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& carry_in); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index ad75a8e6..a1f2754c 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -29,6 +29,7 @@ OPCODE(LogicalShiftLeft, T::U32, T::U32, T::U8, 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(RotateRightExtended, T::U32, T::U32, 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 )