diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp index dfc09da173..4198a17c2c 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp @@ -911,15 +911,15 @@ static Xbyak::Reg8 DoCarry(RegAlloc& reg_alloc, Argument& carry_in, IR::Inst* ca // AL contains flags (after LAHF + SETO sequence) static Xbyak::Reg64 DoNZCV(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* nzcv_out) { - if (!nzcv_out) { - return Xbyak::Reg64{-1}; + if (nzcv_out) { + const Xbyak::Reg64 nzcv = reg_alloc.ScratchGpr(HostLoc::RAX); + code.xor_(nzcv.cvt32(), nzcv.cvt32()); + return nzcv; } - const Xbyak::Reg64 nzcv = reg_alloc.ScratchGpr(HostLoc::RAX); - code.xor_(nzcv.cvt32(), nzcv.cvt32()); - return nzcv; + return Xbyak::Reg64{-1}; } -static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bitsize) { +static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, size_t bitsize) { const auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp); const auto overflow_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp); const auto nzcv_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetNZCVFromOp); @@ -930,19 +930,13 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit // 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()]); - + const Xbyak::Reg result = ctx.reg_alloc.UseScratchGpr(args[0]).changeBit(bitsize); + code.lea(result, code.ptr[result + 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 result = ctx.reg_alloc.UseScratchGpr(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]); - + code.lea(result, code.ptr[result + op2]); ctx.reg_alloc.DefineValue(inst, result); } return; @@ -957,8 +951,14 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit const u32 op_arg = args[1].GetImmediateU32(); if (carry_in.IsImmediate()) { if (carry_in.GetImmediateU1()) { - code.stc(); - code.adc(result, op_arg); + // In range for a valid LEA materialisation + auto const in_range = s32(op_arg) >= -0x7ffffffe && s32(op_arg) <= 0x7ffffffe; + if (in_range && (carry_inst || nzcv_inst || overflow_inst)) { + code.stc(); + code.adc(result, op_arg); + } else { + code.lea(result, code.ptr[result + op_arg + 1]); + } } else { code.add(result, op_arg); }