Fold predicable instructions into MOVCC / t2MOVCC.
authorJakob Stoklund Olesen <stoklund@2pi.dk>
Wed, 15 Aug 2012 22:16:39 +0000 (22:16 +0000)
committerJakob Stoklund Olesen <stoklund@2pi.dk>
Wed, 15 Aug 2012 22:16:39 +0000 (22:16 +0000)
The ARM select instructions are just predicated moves. If the select is
the only use of an operand, the instruction defining the operand can be
predicated instead, saving one instruction and decreasing register
pressure.

This implementation can turn AND/ORR/EOR instructions into their
corresponding ANDCC/ORRCC/EORCC variants. Ideally, we should be able to
predicate any instruction, but we don't yet support predicated
instructions in SSA form.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@161994 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMBaseInstrInfo.cpp
lib/Target/ARM/ARMBaseInstrInfo.h
lib/Target/ARM/ARMISelLowering.cpp
lib/Target/ARM/ARMInstrInfo.td
lib/Target/ARM/ARMInstrThumb2.td
test/CodeGen/ARM/select_xform.ll
test/CodeGen/Thumb2/machine-licm.ll

index 057fd718fdb5d06eb586007170811a6e6e39a6ed..aa452538a8a7dd51b3f8d973de58c5e8545f93a0 100644 (file)
@@ -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.
index 1a10a4ab1c5225cd06c2c842be744131dcd37172..7a69b868c075a37ff94d82c8fcbfdc640ed049f9 100644 (file)
@@ -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
index 77181cfcac39c61d5bd677c37460f3e255a321f6..a0284e6e153d177747601a8988c518411805839d 100644 (file)
@@ -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.
index 76c897c7958a133c9de1ad077f037590aad9639c..9da8f1c3e34ce18bfa432ccede348ee19b7edf05 100644 (file)
@@ -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))*/]>,
index d2d24c81e665e4836d079bac7383f4fdfdd3d176..79dc509fd59f2eec325b3a01d761eb5e2bc7b616 100644 (file)
@@ -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,
index ca2e18a63949561a6bd758059500133f0d4d1183..d98d7a628e29f0112230aecafd32cf8de97ee7f1 100644 (file)
@@ -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
+}
index 82857425a9d751955a53ab13d69e15566ac68900..01df37323252d711bfa2950186f38ce6e8f1f262 100644 (file)
@@ -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 ] ; <i8> [#uses=2]