diff --git a/Common/ArmEmitter.cpp b/Common/ArmEmitter.cpp index 44b183c8ed..4acaecd4b4 100644 --- a/Common/ArmEmitter.cpp +++ b/Common/ArmEmitter.cpp @@ -163,11 +163,19 @@ void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate) } void ARMXEmitter::ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) +{ + if (!TryADDI2R(rd, rs, val)) { + MOVI2R(scratch, val); + ADD(rd, rs, scratch); + } +} + +bool ARMXEmitter::TryADDI2R(ARMReg rd, ARMReg rs, u32 val) { if (val == 0) { if (rd != rs) MOV(rd, rs); - return; + return true; } Operand2 op2; bool negated; @@ -176,6 +184,7 @@ void ARMXEmitter::ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) ADD(rd, rs, op2); else SUB(rd, rs, op2); + return true; } else { // Try 16-bit additions and subtractions - easy to test for. // Should also try other rotations... @@ -183,30 +192,41 @@ void ARMXEmitter::ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) // Decompose into two additions. ADD(rd, rs, Operand2((u8)(val >> 8), 12)); // rotation right by 12*2 == rotation left by 8 ADD(rd, rd, Operand2((u8)(val), 0)); + return true; } else if ((((u32)-(s32)val) & 0xFFFF0000) == 0) { val = (u32)-(s32)val; SUB(rd, rs, Operand2((u8)(val >> 8), 12)); SUB(rd, rd, Operand2((u8)(val), 0)); + return true; } else { - MOVI2R(scratch, val); - ADD(rd, rs, scratch); + return false; } } } void ARMXEmitter::ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) +{ + if (!TryANDI2R(rd, rs, val)) { + MOVI2R(scratch, val); + AND(rd, rs, scratch); + } +} + +bool ARMXEmitter::TryANDI2R(ARMReg rd, ARMReg rs, u32 val) { Operand2 op2; bool inverse; if (val == 0) { // Avoid the ALU, may improve pipeline. MOV(rd, 0); + return true; } else if (TryMakeOperand2_AllowInverse(val, op2, &inverse)) { if (!inverse) { AND(rd, rs, op2); } else { BIC(rd, rs, op2); } + return true; } else { int ops = 0; for (int i = 0; i < 32; i += 2) { @@ -221,31 +241,37 @@ void ARMXEmitter::ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) // The worst case is 4 (e.g. 0x55555555.) #ifdef HAVE_ARMV7 if (ops > 3) { - MOVI2R(scratch, val); - AND(rd, rs, scratch); - } else + return false; + } #endif - { - bool first = true; - for (int i = 0; i < 32; i += 2) { - u8 bits = RotR(val, i) & 0xFF; - if ((bits & 3) != 3) { - u8 rotation = i == 0 ? 0 : 16 - i / 2; - if (first) { - BIC(rd, rs, Operand2(~bits, rotation)); - first = false; - } else { - BIC(rd, rd, Operand2(~bits, rotation)); - } - // Well, we took care of these other bits while we were at it. - i += 8 - 2; + bool first = true; + for (int i = 0; i < 32; i += 2) { + u8 bits = RotR(val, i) & 0xFF; + if ((bits & 3) != 3) { + u8 rotation = i == 0 ? 0 : 16 - i / 2; + if (first) { + BIC(rd, rs, Operand2(~bits, rotation)); + first = false; + } else { + BIC(rd, rd, Operand2(~bits, rotation)); } + // Well, we took care of these other bits while we were at it. + i += 8 - 2; } } + return true; } } void ARMXEmitter::CMPI2R(ARMReg rs, u32 val, ARMReg scratch) +{ + if (!TryCMPI2R(rs, val)) { + MOVI2R(scratch, val); + CMP(rs, scratch); + } +} + +bool ARMXEmitter::TryCMPI2R(ARMReg rs, u32 val) { Operand2 op2; bool negated; @@ -254,24 +280,40 @@ void ARMXEmitter::CMPI2R(ARMReg rs, u32 val, ARMReg scratch) CMP(rs, op2); else CMN(rs, op2); + return true; } else { - MOVI2R(scratch, val); - CMP(rs, scratch); + return false; } } void ARMXEmitter::TSTI2R(ARMReg rs, u32 val, ARMReg scratch) { - Operand2 op2; - if (TryMakeOperand2(val, op2)) { - TST(rs, op2); - } else { + if (!TryTSTI2R(rs, val)) { MOVI2R(scratch, val); TST(rs, scratch); } } +bool ARMXEmitter::TryTSTI2R(ARMReg rs, u32 val) +{ + Operand2 op2; + if (TryMakeOperand2(val, op2)) { + TST(rs, op2); + return true; + } else { + return false; + } +} + void ARMXEmitter::ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) +{ + if (!TryORI2R(rd, rs, val)) { + MOVI2R(scratch, val); + ORR(rd, rs, scratch); + } +} + +bool ARMXEmitter::TryORI2R(ARMReg rd, ARMReg rs, u32 val) { Operand2 op2; if (val == 0) { @@ -279,8 +321,10 @@ void ARMXEmitter::ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) if (rd != rs) { MOV(rd, rs); } + return true; } else if (TryMakeOperand2(val, op2)) { ORR(rd, rs, op2); + return true; } else { int ops = 0; for (int i = 0; i < 32; i += 2) { @@ -295,30 +339,53 @@ void ARMXEmitter::ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) // The worst case is 4 (e.g. 0x55555555.) But MVN can make it 2. Not sure if better. bool inversed; if (TryMakeOperand2_AllowInverse(val, op2, &inversed) && ops >= 3) { - MVN(scratch, op2); - ORR(rd, rs, scratch); + return false; #ifdef HAVE_ARMV7 } else if (ops > 3) { - MOVI2R(scratch, val); - ORR(rd, rs, scratch); + return false; #endif - } else { - bool first = true; - for (int i = 0; i < 32; i += 2) { - u8 bits = RotR(val, i) & 0xFF; - if ((bits & 3) != 0) { - u8 rotation = i == 0 ? 0 : 16 - i / 2; - if (first) { - ORR(rd, rs, Operand2(bits, rotation)); - first = false; - } else { - ORR(rd, rd, Operand2(bits, rotation)); - } - // Well, we took care of these other bits while we were at it. - i += 8 - 2; + } + + bool first = true; + for (int i = 0; i < 32; i += 2) { + u8 bits = RotR(val, i) & 0xFF; + if ((bits & 3) != 0) { + u8 rotation = i == 0 ? 0 : 16 - i / 2; + if (first) { + ORR(rd, rs, Operand2(bits, rotation)); + first = false; + } else { + ORR(rd, rd, Operand2(bits, rotation)); } + // Well, we took care of these other bits while we were at it. + i += 8 - 2; } } + return true; + } +} + +void ARMXEmitter::EORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) +{ + if (!TryEORI2R(rd, rs, val)) { + MOVI2R(scratch, val); + EOR(rd, rs, scratch); + } +} + +bool ARMXEmitter::TryEORI2R(ARMReg rd, ARMReg rs, u32 val) +{ + Operand2 op2; + if (val == 0) { + if (rd != rs) { + MOV(rd, rs); + } + return true; + } else if (TryMakeOperand2(val, op2)) { + EOR(rd, rs, op2); + return true; + } else { + return false; } } diff --git a/Common/ArmEmitter.h b/Common/ArmEmitter.h index 4ea606ae24..9202d30cea 100644 --- a/Common/ArmEmitter.h +++ b/Common/ArmEmitter.h @@ -795,10 +795,17 @@ public: } void ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); + bool TryADDI2R(ARMReg rd, ARMReg rs, u32 val); void ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); + bool TryANDI2R(ARMReg rd, ARMReg rs, u32 val); void CMPI2R(ARMReg rs, u32 val, ARMReg scratch); + bool TryCMPI2R(ARMReg rs, u32 val); void TSTI2R(ARMReg rs, u32 val, ARMReg scratch); + bool TryTSTI2R(ARMReg rs, u32 val); void ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); + bool TryORI2R(ARMReg rd, ARMReg rs, u32 val); + void EORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); + bool TryEORI2R(ARMReg rd, ARMReg rs, u32 val); }; // class ARMXEmitter