diff --git a/src/backend/x64/emit_x64_data_processing.cpp b/src/backend/x64/emit_x64_data_processing.cpp index 88201cbb..45bdc75c 100644 --- a/src/backend/x64/emit_x64_data_processing.cpp +++ b/src/backend/x64/emit_x64_data_processing.cpp @@ -1080,19 +1080,28 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto& carry_in = args[2]; + const bool is_cmp = inst->UseCount() == !!carry_inst + !!overflow_inst + !!nzcv_inst && carry_in.IsImmediate() && carry_in.GetImmediateU1(); const Xbyak::Reg64 nzcv = DoNZCV(code, ctx.reg_alloc, nzcv_inst); - const Xbyak::Reg result = ctx.reg_alloc.UseScratchGpr(args[0]).changeBit(bitsize); + const Xbyak::Reg result = (is_cmp ? ctx.reg_alloc.UseGpr(args[0]) : ctx.reg_alloc.UseScratchGpr(args[0])).changeBit(bitsize); const Xbyak::Reg8 carry = DoCarry(ctx.reg_alloc, carry_in, carry_inst); const Xbyak::Reg8 overflow = overflow_inst ? ctx.reg_alloc.ScratchGpr().cvt8() : Xbyak::Reg8{-1}; // TODO: Consider using LEA. - // TODO: Optimize CMP case. // Note that x64 CF is inverse of what the ARM carry flag is here. bool invert_output_carry = true; - if (args[1].IsImmediate() && args[1].GetType() == IR::Type::U32) { + if (is_cmp) { + if (args[1].IsImmediate() && args[1].GetType() == IR::Type::U32) { + const u32 op_arg = args[1].GetImmediateU32(); + code.cmp(result, op_arg); + } else { + OpArg op_arg = ctx.reg_alloc.UseOpArg(args[1]); + op_arg.setBit(bitsize); + code.cmp(result, *op_arg); + } + } else if (args[1].IsImmediate() && args[1].GetType() == IR::Type::U32) { const u32 op_arg = args[1].GetImmediateU32(); if (carry_in.IsImmediate()) { if (carry_in.GetImmediateU1()) { @@ -1146,8 +1155,9 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit ctx.reg_alloc.DefineValue(overflow_inst, overflow); ctx.EraseInstruction(overflow_inst); } - - ctx.reg_alloc.DefineValue(inst, result); + if (!is_cmp) { + ctx.reg_alloc.DefineValue(inst, result); + } } void EmitX64::EmitSub32(EmitContext& ctx, IR::Inst* inst) { diff --git a/src/frontend/A64/translate/impl/data_processing_conditional_compare.cpp b/src/frontend/A64/translate/impl/data_processing_conditional_compare.cpp index 837e2b52..591c3cf6 100644 --- a/src/frontend/A64/translate/impl/data_processing_conditional_compare.cpp +++ b/src/frontend/A64/translate/impl/data_processing_conditional_compare.cpp @@ -27,7 +27,7 @@ bool TranslatorVisitor::CCMP_reg(bool sf, Reg Rm, Cond cond, Reg Rn, Imm<4> nzcv const IR::U32U64 operand1 = X(datasize, Rn); const IR::U32U64 operand2 = X(datasize, Rm); - const IR::NZCV then_flags = ir.NZCVFrom(ir.AddWithCarry(operand1, ir.Not(operand2), ir.Imm1(1))); + const IR::NZCV then_flags = ir.NZCVFrom(ir.SubWithCarry(operand1, operand2, ir.Imm1(1))); const IR::NZCV else_flags = ir.NZCVFromPackedFlags(ir.Imm32(flags)); ir.SetNZCV(ir.ConditionalSelect(cond, then_flags, else_flags)); return true; @@ -53,7 +53,7 @@ bool TranslatorVisitor::CCMP_imm(bool sf, Imm<5> imm5, Cond cond, Reg Rn, Imm<4> const IR::U32U64 operand1 = X(datasize, Rn); const IR::U32U64 operand2 = I(datasize, imm5.ZeroExtend()); - const IR::NZCV then_flags = ir.NZCVFrom(ir.AddWithCarry(operand1, ir.Not(operand2), ir.Imm1(1))); + const IR::NZCV then_flags = ir.NZCVFrom(ir.SubWithCarry(operand1, operand2, ir.Imm1(1))); const IR::NZCV else_flags = ir.NZCVFromPackedFlags(ir.Imm32(flags)); ir.SetNZCV(ir.ConditionalSelect(cond, then_flags, else_flags)); return true;