From ca2cc2c4ba4006e9dffe5c9d6b38b1eebec2216c Mon Sep 17 00:00:00 2001 From: Merry Date: Tue, 30 Jan 2024 22:59:41 +0000 Subject: [PATCH] emit_x64_data_processing: Emit lea where possible in EmitAdd and EmitSub --- .../backend/x64/emit_x64_data_processing.cpp | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/dynarmic/backend/x64/emit_x64_data_processing.cpp b/src/dynarmic/backend/x64/emit_x64_data_processing.cpp index 396d3118..e271317b 100644 --- a/src/dynarmic/backend/x64/emit_x64_data_processing.cpp +++ b/src/dynarmic/backend/x64/emit_x64_data_processing.cpp @@ -924,13 +924,32 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto& carry_in = args[2]; + // Consider using LEA. + if (!carry_inst && !overflow_inst && !nzcv_inst && carry_in.IsImmediate() && !carry_in.GetImmediateU1()) { + if (args[1].IsImmediate() && args[1].FitsInImmediateS32()) { + const Xbyak::Reg op1 = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize); + const Xbyak::Reg result = ctx.reg_alloc.ScratchGpr().changeBit(bitsize); + + code.lea(result, code.ptr[op1 + args[1].GetImmediateS32()]); + + ctx.reg_alloc.DefineValue(inst, result); + } else { + const Xbyak::Reg op1 = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize); + const Xbyak::Reg op2 = ctx.reg_alloc.UseGpr(args[1]).changeBit(bitsize); + const Xbyak::Reg result = ctx.reg_alloc.ScratchGpr().changeBit(bitsize); + + code.lea(result, code.ptr[op1 + op2]); + + ctx.reg_alloc.DefineValue(inst, result); + } + return; + } + 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::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. - if (args[1].IsImmediate() && args[1].GetType() == IR::Type::U32) { const u32 op_arg = args[1].GetImmediateU32(); if (carry_in.IsImmediate()) { @@ -994,12 +1013,22 @@ static void EmitSub(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit auto& carry_in = args[2]; const bool is_cmp = inst->UseCount() == size_t(!!carry_inst + !!overflow_inst + !!nzcv_inst) && carry_in.IsImmediate() && carry_in.GetImmediateU1(); + // Consider using LEA. + if (!carry_inst && !overflow_inst && !nzcv_inst && carry_in.IsImmediate() && carry_in.GetImmediateU1() && args[1].IsImmediate() && args[1].FitsInImmediateS32()) { + const Xbyak::Reg op1 = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize); + const Xbyak::Reg result = ctx.reg_alloc.ScratchGpr().changeBit(bitsize); + + code.lea(result, code.ptr[op1 - args[1].GetImmediateS32()]); + + ctx.reg_alloc.DefineValue(inst, result); + return; + } + const Xbyak::Reg64 nzcv = DoNZCV(code, ctx.reg_alloc, nzcv_inst); 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. // Note that x64 CF is inverse of what the ARM carry flag is here. bool invert_output_carry = true;