Index: llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp =================================================================== --- llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -5501,6 +5501,8 @@ return ForCodesize ? 4 : 1; if (ARM_AM::isSOImmTwoPartVal(Val)) // two instrs return ForCodesize ? 8 : 2; + if (ARM_AM::isSOImmTwoPartValNeg(Val)) // two instrs + return ForCodesize ? 8 : 2; } if (Subtarget->useMovt()) // MOVW + MOVT return ForCodesize ? 8 : 2; Index: llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp =================================================================== --- llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp +++ llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp @@ -873,16 +873,27 @@ // FIXME Windows CE supports older ARM CPUs assert(!STI->isTargetWindows() && "Windows on ARM requires ARMv7+"); - // Expand into a movi + orr. - LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MOVi), DstReg); - HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::ORRri)) - .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)) - .addReg(DstReg); - assert (MO.isImm() && "MOVi32imm w/ non-immediate source operand!"); unsigned ImmVal = (unsigned)MO.getImm(); - unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal); - unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal); + unsigned SOImmValV1 = 0, SOImmValV2 = 0; + + if (ARM_AM::isSOImmTwoPartVal(ImmVal)) { // Expand into a movi + orr. + LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MOVi), DstReg); + HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::ORRri)) + .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstReg); + SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal); + SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal); + } else { // Expand into a mvn + sub. + LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MVNi), DstReg); + HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::SUBri)) + .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstReg); + SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(-ImmVal); + SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(-ImmVal); + SOImmValV1 = ~(-SOImmValV1); + } + unsigned MIFlags = MI.getFlags(); LO16 = LO16.addImm(SOImmValV1); HI16 = HI16.addImm(SOImmValV2); Index: llvm/lib/Target/ARM/ARMInstrInfo.td =================================================================== --- llvm/lib/Target/ARM/ARMInstrInfo.td +++ llvm/lib/Target/ARM/ARMInstrInfo.td @@ -812,7 +812,9 @@ def arm_i32imm : IntImmLeafuseMovt()) return true; - return ARM_AM::isSOImmTwoPartVal(Imm.getZExtValue()); + if (ARM_AM::isSOImmTwoPartVal(Imm.getZExtValue())) + return true; + return ARM_AM::isSOImmTwoPartValNeg(Imm.getZExtValue()); }]>; /// imm0_1 predicate - Immediate in the range [0,1]. Index: llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h =================================================================== --- llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h +++ llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h @@ -205,6 +205,20 @@ return V; } + /// isSOImmTwoPartValNeg - Return true if the specified value can be obtained + /// by two SOImmVal, that -V = First + Second. + /// "R+V" can be optimized to (sub (sub R, First), Second). + /// "R=V" can be optimized to (sub (mvn R, ~(-First)), Second). + inline bool isSOImmTwoPartValNeg(unsigned V) { + unsigned First; + if (!isSOImmTwoPartVal(-V)) + return false; + // Return false if ~(-First) is not a SoImmval. + First = getSOImmTwoPartFirst(-V); + First = ~(-First); + return !(rotr32(~255U, getSOImmValRotate(First)) & First); + } + /// getThumbImmValShift - Try to handle Imm with a 8-bit immediate followed /// by a left shift. Returns the shift amount to use. inline unsigned getThumbImmValShift(unsigned Imm) { Index: llvm/test/CodeGen/ARM/select-imm.ll =================================================================== --- llvm/test/CodeGen/ARM/select-imm.ll +++ llvm/test/CodeGen/ARM/select-imm.ll @@ -85,7 +85,8 @@ define i32 @t4(i32 %a, i32 %b, i32 %x) nounwind { entry: ; ARM-LABEL: t4: -; ARM: ldr +; ARM: mvn [[R0:r[0-9]+]], #170 +; ARM: sub [[R0:r[0-9]+]], [[R0:r[0-9]+]], #11141120 ; ARM: mov{{lt|ge}} ; ARMT2-LABEL: t4: