diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index 61af2578bf..98a857955a 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -2055,6 +2055,28 @@ void ARM64XEmitter::MOVI2R(ARM64Reg Rd, u64 imm, bool optimize) } } +bool ARM64XEmitter::MOVI2R2(ARM64Reg Rd, u64 imm1, u64 imm2) +{ + // TODO: Also optimize for performance, not just for code size. + u8* start_pointer = GetWritableCodePtr(); + + MOVI2R(Rd, imm1); + int size1 = GetCodePtr() - start_pointer; + + SetCodePtrUnsafe(start_pointer); + + MOVI2R(Rd, imm2); + int size2 = GetCodePtr() - start_pointer; + + SetCodePtrUnsafe(start_pointer); + + bool element = size1 > size2; + + MOVI2R(Rd, element ? imm2 : imm1); + + return element; +} + void ARM64XEmitter::ABI_PushRegisters(BitSet32 registers) { int num_regs = registers.Count(); @@ -4140,13 +4162,25 @@ void ARM64XEmitter::ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { SUB(Rd, Rn, val, shift); } + else if ((imm >= 0x10000u || scratch == INVALID_REG) && imm < 0x1000000u) + { + ADD(Rd, Rn, imm & 0xFFF, false); + ADD(Rd, Rd, imm >> 12, true); + } + else if ((imm_neg >= 0x10000u || scratch == INVALID_REG) && imm_neg < 0x1000000u) + { + SUB(Rd, Rn, imm_neg & 0xFFF, false); + SUB(Rd, Rd, imm_neg >> 12, true); + } else { _assert_msg_(DYNA_REC, scratch != INVALID_REG, "ADDI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - ADD(Rd, Rn, scratch); + if (MOVI2R2(scratch, imm, imm_neg)) + SUB(Rd, Rn, scratch); + else + ADD(Rd, Rn, scratch); } } @@ -4168,8 +4202,10 @@ void ARM64XEmitter::ADDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) _assert_msg_(DYNA_REC, scratch != INVALID_REG, "ADDSI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - ADDS(Rd, Rn, scratch); + if (MOVI2R2(scratch, imm, imm_neg)) + SUBS(Rd, Rn, scratch); + else + ADDS(Rd, Rn, scratch); } } @@ -4186,13 +4222,25 @@ void ARM64XEmitter::SUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { ADD(Rd, Rn, val, shift); } + else if ((imm >= 0x10000u || scratch == INVALID_REG) && imm < 0x1000000u) + { + SUB(Rd, Rn, imm & 0xFFF, false); + SUB(Rd, Rd, imm >> 12, true); + } + else if ((imm_neg >= 0x10000u || scratch == INVALID_REG) && imm_neg < 0x1000000u) + { + ADD(Rd, Rn, imm_neg & 0xFFF, false); + ADD(Rd, Rd, imm_neg >> 12, true); + } else { _assert_msg_(DYNA_REC, scratch != INVALID_REG, "SUBI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - SUB(Rd, Rn, scratch); + if (MOVI2R2(scratch, imm, imm_neg)) + ADD(Rd, Rn, scratch); + else + SUB(Rd, Rn, scratch); } } @@ -4213,8 +4261,10 @@ void ARM64XEmitter::SUBSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { _assert_msg_(DYNA_REC, scratch != INVALID_REG, "ANDSI2R - failed to construct immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - SUBS(Rd, Rn, scratch); + if (MOVI2R2(scratch, imm, imm_neg)) + ADDS(Rd, Rn, scratch); + else + SUBS(Rd, Rn, scratch); } } diff --git a/Source/Core/Common/Arm64Emitter.h b/Source/Core/Common/Arm64Emitter.h index 3426fe2be2..a23d5a4349 100644 --- a/Source/Core/Common/Arm64Emitter.h +++ b/Source/Core/Common/Arm64Emitter.h @@ -835,6 +835,7 @@ public: // Wrapper around MOVZ+MOVK void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true); + bool MOVI2R2(ARM64Reg Rd, u64 imm1, u64 imm2); template void MOVP2R(ARM64Reg Rd, P* ptr) { diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index 4528f751c1..e439c7b4c8 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -492,29 +492,7 @@ void JitArm64::lmw(UGeckoInstruction inst) ARM64Reg XA = EncodeRegTo64(WA); if (a) { - bool add = inst.SIMM_16 >= 0; - u16 off = std::abs(inst.SIMM_16); - if (off < 4096) - { - if (add) - ADD(WA, gpr.R(a), off); - else - SUB(WA, gpr.R(a), off); - } - else - { - u16 remaining = off >> 12; - if (add) - { - ADD(WA, gpr.R(a), off & 0xFFF); - ADD(WA, WA, remaining, true); - } - else - { - SUB(WA, gpr.R(a), off & 0xFFF); - SUB(WA, WA, remaining, true); - } - } + ADDI2R(WA, gpr.R(a), inst.SIMM_16, WA); ADD(XA, XA, MEM_REG); } else @@ -579,29 +557,7 @@ void JitArm64::stmw(UGeckoInstruction inst) if (a) { - bool add = inst.SIMM_16 >= 0; - u16 off = std::abs(inst.SIMM_16); - if (off < 4096) - { - if (add) - ADD(WA, gpr.R(a), off); - else - SUB(WA, gpr.R(a), off); - } - else - { - u16 remaining = off >> 12; - if (add) - { - ADD(WA, gpr.R(a), off & 0xFFF); - ADD(WA, WA, remaining, true); - } - else - { - SUB(WA, gpr.R(a), off & 0xFFF); - SUB(WA, WA, remaining, true); - } - } + ADDI2R(WA, gpr.R(a), inst.SIMM_16, WA); ADD(XA, XA, MEM_REG); } else