diff --git a/lib/Target/ARM/ARMBaseInstrInfo.cpp b/lib/Target/ARM/ARMBaseInstrInfo.cpp index 057fd718fdb..aa452538a8a 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -1568,6 +1568,55 @@ ARMBaseInstrInfo::commuteInstruction(MachineInstr *MI, bool NewMI) const { return TargetInstrInfoImpl::commuteInstruction(MI, NewMI); } +/// Identify instructions that can be folded into a MOVCC instruction, and +/// return the corresponding opcode for the predicated pseudo-instruction. +unsigned llvm::canFoldARMInstrIntoMOVCC(unsigned Reg, + MachineInstr *&MI, + const MachineRegisterInfo &MRI) { + if (!TargetRegisterInfo::isVirtualRegister(Reg)) + return 0; + if (!MRI.hasOneNonDBGUse(Reg)) + return 0; + MI = MRI.getVRegDef(Reg); + if (!MI) + return 0; + // Check if MI has any non-dead defs or physreg uses. This also detects + // predicated instructions which will be reading CPSR. + for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + if (!MO.isReg()) + continue; + if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) + return 0; + if (MO.isDef() && !MO.isDead()) + return 0; + } + switch (MI->getOpcode()) { + default: return 0; + case ARM::ANDri: return ARM::ANDCCri; + case ARM::ANDrr: return ARM::ANDCCrr; + case ARM::ANDrsi: return ARM::ANDCCrsi; + case ARM::ANDrsr: return ARM::ANDCCrsr; + case ARM::t2ANDri: return ARM::t2ANDCCri; + case ARM::t2ANDrr: return ARM::t2ANDCCrr; + case ARM::t2ANDrs: return ARM::t2ANDCCrs; + case ARM::EORri: return ARM::EORCCri; + case ARM::EORrr: return ARM::EORCCrr; + case ARM::EORrsi: return ARM::EORCCrsi; + case ARM::EORrsr: return ARM::EORCCrsr; + case ARM::t2EORri: return ARM::t2EORCCri; + case ARM::t2EORrr: return ARM::t2EORCCrr; + case ARM::t2EORrs: return ARM::t2EORCCrs; + case ARM::ORRri: return ARM::ORRCCri; + case ARM::ORRrr: return ARM::ORRCCrr; + case ARM::ORRrsi: return ARM::ORRCCrsi; + case ARM::ORRrsr: return ARM::ORRCCrsr; + case ARM::t2ORRri: return ARM::t2ORRCCri; + case ARM::t2ORRrr: return ARM::t2ORRCCrr; + case ARM::t2ORRrs: return ARM::t2ORRCCrs; + } +} + /// Map pseudo instructions that imply an 'S' bit onto real opcodes. Whether the /// instruction is encoded with an 'S' bit is determined by the optional CPSR /// def operand. diff --git a/lib/Target/ARM/ARMBaseInstrInfo.h b/lib/Target/ARM/ARMBaseInstrInfo.h index 1a10a4ab1c5..7a69b868c07 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.h +++ b/lib/Target/ARM/ARMBaseInstrInfo.h @@ -352,6 +352,11 @@ ARMCC::CondCodes getInstrPredicate(const MachineInstr *MI, unsigned &PredReg); int getMatchingCondBranchOpcode(int Opc); +/// Determine if MI can be folded into an ARM MOVCC instruction, and return the +/// opcode of the SSA instruction representing the conditional MI. +unsigned canFoldARMInstrIntoMOVCC(unsigned Reg, + MachineInstr *&MI, + const MachineRegisterInfo &MRI); /// Map pseudo instructions that imply an 'S' bit onto real opcodes. Whether /// the instruction is encoded with an 'S' bit is determined by the optional diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 77181cfcac3..a0284e6e153 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -6762,6 +6762,54 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, return BB; } + case ARM::MOVCCr: + case ARM::t2MOVCCr: { + // MOVCCr instructions can fold one of its operands as a predicated + // instruction: + // + // %v1 = AND %v2, %v3 + // %v4 = MOVCCr %v5, %v1, CC + // + // Becomes: + // + // %v4 = ANDCCrr %v5, %v2, %v3, CC + // + const MachineRegisterInfo &MRI = MI->getParent()->getParent()->getRegInfo(); + MachineInstr *DefMI = 0; + unsigned Opc = canFoldARMInstrIntoMOVCC(MI->getOperand(2).getReg(), + DefMI, MRI); + bool Invert = !Opc; + if (!Opc) + Opc = canFoldARMInstrIntoMOVCC(MI->getOperand(1).getReg(), DefMI, MRI); + if (!Opc) + return BB; + + // Create a new predicated version of DefMI. + // Rfalse is the first use. + MachineInstrBuilder NewMI = BuildMI(*BB, MI, dl, TII->get(Opc), + MI->getOperand(0).getReg()) + .addOperand(MI->getOperand(Invert ? 2 : 1)); + + // Copy all the DefMI operands, excluding its (null) predicate. + const MCInstrDesc &DefDesc = DefMI->getDesc(); + for (unsigned i = 1, e = DefDesc.getNumOperands(); + i != e && !DefDesc.OpInfo[i].isPredicate(); ++i) + NewMI.addOperand(DefMI->getOperand(i)); + + unsigned CondCode = MI->getOperand(3).getImm(); + if (Invert) + NewMI.addImm(ARMCC::getOppositeCondition(ARMCC::CondCodes(CondCode))); + else + NewMI.addImm(CondCode); + NewMI.addOperand(MI->getOperand(4)); + + AddDefaultCC(NewMI); + + DefMI->eraseFromParent(); + MI->eraseFromParent(); + return BB; + } + case ARM::BCCi64: case ARM::BCCZi64: { // If there is an unconditional branch to the other successor, remove it. diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 76c897c7958..9da8f1c3e34 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -3939,7 +3939,7 @@ def BCCZi64 : PseudoInst<(outs), // a two-value operand where a dag node expects two operands. :( let neverHasSideEffects = 1 in { -let isCommutable = 1 in +let isCommutable = 1, usesCustomInserter = 1 in def MOVCCr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$false, GPR:$Rm, pred:$p), 4, IIC_iCMOVr, [/*(set GPR:$Rd, (ARMcmov GPR:$false, GPR:$Rm, imm:$cc, CCR:$ccr))*/]>, diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index d2d24c81e66..79dc509fd59 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -2938,7 +2938,7 @@ defm t2TEQ : T2I_cmp_irs<0b0100, "teq", // a two-value operand where a dag node expects two operands. :( let neverHasSideEffects = 1 in { -let isCommutable = 1 in +let isCommutable = 1, usesCustomInserter = 1 in def t2MOVCCr : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$false, rGPR:$Rm, pred:$p), 4, IIC_iCMOVr, diff --git a/test/CodeGen/ARM/select_xform.ll b/test/CodeGen/ARM/select_xform.ll index ca2e18a6394..d98d7a628e2 100644 --- a/test/CodeGen/ARM/select_xform.ll +++ b/test/CodeGen/ARM/select_xform.ll @@ -104,3 +104,63 @@ entry: ret i32 %tmp3 } +; Fold ORRri into movcc. +define i32 @t8(i32 %a, i32 %b) nounwind { +; ARM: t8: +; ARM: cmp r0, r1 +; ARM: orrge r0, r1, #1 + +; T2: t8: +; T2: cmp r0, r1 +; T2: orrge r0, r1, #1 + %x = or i32 %b, 1 + %cond = icmp slt i32 %a, %b + %tmp1 = select i1 %cond, i32 %a, i32 %x + ret i32 %tmp1 +} + +; Fold ANDrr into movcc. +define i32 @t9(i32 %a, i32 %b, i32 %c) nounwind { +; ARM: t9: +; ARM: cmp r0, r1 +; ARM: andge r0, r1, r2 + +; T2: t9: +; T2: cmp r0, r1 +; T2: andge.w r0, r1, r2 + %x = and i32 %b, %c + %cond = icmp slt i32 %a, %b + %tmp1 = select i1 %cond, i32 %a, i32 %x + ret i32 %tmp1 +} + +; Fold EORrs into movcc. +define i32 @t10(i32 %a, i32 %b, i32 %c, i32 %d) nounwind { +; ARM: t10: +; ARM: cmp r0, r1 +; ARM: eorge r0, r1, r2, lsl #7 + +; T2: t10: +; T2: cmp r0, r1 +; T2: eorge.w r0, r1, r2, lsl #7 + %s = shl i32 %c, 7 + %x = xor i32 %b, %s + %cond = icmp slt i32 %a, %b + %tmp1 = select i1 %cond, i32 %a, i32 %x + ret i32 %tmp1 +} + +; Fold ORRri into movcc, reversing the condition. +define i32 @t11(i32 %a, i32 %b) nounwind { +; ARM: t11: +; ARM: cmp r0, r1 +; ARM: orrlt r0, r1, #1 + +; T2: t11: +; T2: cmp r0, r1 +; T2: orrlt r0, r1, #1 + %x = or i32 %b, 1 + %cond = icmp slt i32 %a, %b + %tmp1 = select i1 %cond, i32 %x, i32 %a + ret i32 %tmp1 +} diff --git a/test/CodeGen/Thumb2/machine-licm.ll b/test/CodeGen/Thumb2/machine-licm.ll index 82857425a9d..01df3732325 100644 --- a/test/CodeGen/Thumb2/machine-licm.ll +++ b/test/CodeGen/Thumb2/machine-licm.ll @@ -95,7 +95,7 @@ bb.nph: bb: ; preds = %bb, %bb.nph ; CHECK: bb ; CHECK: eor.w -; CHECK: eor.w {{(r[0-9])|(lr)}}, {{(r[0-9])|(lr)}}, [[REGISTER]] +; CHECK: eorne.w {{(r[0-9])|(lr)}}, {{(r[0-9])|(lr)}}, [[REGISTER]] ; CHECK-NOT: eor ; CHECK: and %data_addr.013 = phi i8 [ %data, %bb.nph ], [ %8, %bb ] ; [#uses=2]