1*0b57cec5SDimitry Andric //===-- lib/CodeGen/GlobalISel/GICombinerHelper.cpp -----------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/CombinerHelper.h" 9*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/Combiner.h" 10*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" 11*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 12*0b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h" 13*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 14*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 15*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric #define DEBUG_TYPE "gi-combiner" 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric using namespace llvm; 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric CombinerHelper::CombinerHelper(GISelChangeObserver &Observer, 22*0b57cec5SDimitry Andric MachineIRBuilder &B) 23*0b57cec5SDimitry Andric : Builder(B), MRI(Builder.getMF().getRegInfo()), Observer(Observer) {} 24*0b57cec5SDimitry Andric 25*0b57cec5SDimitry Andric void CombinerHelper::replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, 26*0b57cec5SDimitry Andric Register ToReg) const { 27*0b57cec5SDimitry Andric Observer.changingAllUsesOfReg(MRI, FromReg); 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric if (MRI.constrainRegAttrs(ToReg, FromReg)) 30*0b57cec5SDimitry Andric MRI.replaceRegWith(FromReg, ToReg); 31*0b57cec5SDimitry Andric else 32*0b57cec5SDimitry Andric Builder.buildCopy(ToReg, FromReg); 33*0b57cec5SDimitry Andric 34*0b57cec5SDimitry Andric Observer.finishedChangingAllUsesOfReg(); 35*0b57cec5SDimitry Andric } 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric void CombinerHelper::replaceRegOpWith(MachineRegisterInfo &MRI, 38*0b57cec5SDimitry Andric MachineOperand &FromRegOp, 39*0b57cec5SDimitry Andric Register ToReg) const { 40*0b57cec5SDimitry Andric assert(FromRegOp.getParent() && "Expected an operand in an MI"); 41*0b57cec5SDimitry Andric Observer.changingInstr(*FromRegOp.getParent()); 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric FromRegOp.setReg(ToReg); 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric Observer.changedInstr(*FromRegOp.getParent()); 46*0b57cec5SDimitry Andric } 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric bool CombinerHelper::tryCombineCopy(MachineInstr &MI) { 49*0b57cec5SDimitry Andric if (matchCombineCopy(MI)) { 50*0b57cec5SDimitry Andric applyCombineCopy(MI); 51*0b57cec5SDimitry Andric return true; 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric return false; 54*0b57cec5SDimitry Andric } 55*0b57cec5SDimitry Andric bool CombinerHelper::matchCombineCopy(MachineInstr &MI) { 56*0b57cec5SDimitry Andric if (MI.getOpcode() != TargetOpcode::COPY) 57*0b57cec5SDimitry Andric return false; 58*0b57cec5SDimitry Andric unsigned DstReg = MI.getOperand(0).getReg(); 59*0b57cec5SDimitry Andric unsigned SrcReg = MI.getOperand(1).getReg(); 60*0b57cec5SDimitry Andric LLT DstTy = MRI.getType(DstReg); 61*0b57cec5SDimitry Andric LLT SrcTy = MRI.getType(SrcReg); 62*0b57cec5SDimitry Andric // Simple Copy Propagation. 63*0b57cec5SDimitry Andric // a(sx) = COPY b(sx) -> Replace all uses of a with b. 64*0b57cec5SDimitry Andric if (DstTy.isValid() && SrcTy.isValid() && DstTy == SrcTy) 65*0b57cec5SDimitry Andric return true; 66*0b57cec5SDimitry Andric return false; 67*0b57cec5SDimitry Andric } 68*0b57cec5SDimitry Andric void CombinerHelper::applyCombineCopy(MachineInstr &MI) { 69*0b57cec5SDimitry Andric unsigned DstReg = MI.getOperand(0).getReg(); 70*0b57cec5SDimitry Andric unsigned SrcReg = MI.getOperand(1).getReg(); 71*0b57cec5SDimitry Andric MI.eraseFromParent(); 72*0b57cec5SDimitry Andric replaceRegWith(MRI, DstReg, SrcReg); 73*0b57cec5SDimitry Andric } 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric namespace { 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric /// Select a preference between two uses. CurrentUse is the current preference 78*0b57cec5SDimitry Andric /// while *ForCandidate is attributes of the candidate under consideration. 79*0b57cec5SDimitry Andric PreferredTuple ChoosePreferredUse(PreferredTuple &CurrentUse, 80*0b57cec5SDimitry Andric const LLT &TyForCandidate, 81*0b57cec5SDimitry Andric unsigned OpcodeForCandidate, 82*0b57cec5SDimitry Andric MachineInstr *MIForCandidate) { 83*0b57cec5SDimitry Andric if (!CurrentUse.Ty.isValid()) { 84*0b57cec5SDimitry Andric if (CurrentUse.ExtendOpcode == OpcodeForCandidate || 85*0b57cec5SDimitry Andric CurrentUse.ExtendOpcode == TargetOpcode::G_ANYEXT) 86*0b57cec5SDimitry Andric return {TyForCandidate, OpcodeForCandidate, MIForCandidate}; 87*0b57cec5SDimitry Andric return CurrentUse; 88*0b57cec5SDimitry Andric } 89*0b57cec5SDimitry Andric 90*0b57cec5SDimitry Andric // We permit the extend to hoist through basic blocks but this is only 91*0b57cec5SDimitry Andric // sensible if the target has extending loads. If you end up lowering back 92*0b57cec5SDimitry Andric // into a load and extend during the legalizer then the end result is 93*0b57cec5SDimitry Andric // hoisting the extend up to the load. 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric // Prefer defined extensions to undefined extensions as these are more 96*0b57cec5SDimitry Andric // likely to reduce the number of instructions. 97*0b57cec5SDimitry Andric if (OpcodeForCandidate == TargetOpcode::G_ANYEXT && 98*0b57cec5SDimitry Andric CurrentUse.ExtendOpcode != TargetOpcode::G_ANYEXT) 99*0b57cec5SDimitry Andric return CurrentUse; 100*0b57cec5SDimitry Andric else if (CurrentUse.ExtendOpcode == TargetOpcode::G_ANYEXT && 101*0b57cec5SDimitry Andric OpcodeForCandidate != TargetOpcode::G_ANYEXT) 102*0b57cec5SDimitry Andric return {TyForCandidate, OpcodeForCandidate, MIForCandidate}; 103*0b57cec5SDimitry Andric 104*0b57cec5SDimitry Andric // Prefer sign extensions to zero extensions as sign-extensions tend to be 105*0b57cec5SDimitry Andric // more expensive. 106*0b57cec5SDimitry Andric if (CurrentUse.Ty == TyForCandidate) { 107*0b57cec5SDimitry Andric if (CurrentUse.ExtendOpcode == TargetOpcode::G_SEXT && 108*0b57cec5SDimitry Andric OpcodeForCandidate == TargetOpcode::G_ZEXT) 109*0b57cec5SDimitry Andric return CurrentUse; 110*0b57cec5SDimitry Andric else if (CurrentUse.ExtendOpcode == TargetOpcode::G_ZEXT && 111*0b57cec5SDimitry Andric OpcodeForCandidate == TargetOpcode::G_SEXT) 112*0b57cec5SDimitry Andric return {TyForCandidate, OpcodeForCandidate, MIForCandidate}; 113*0b57cec5SDimitry Andric } 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric // This is potentially target specific. We've chosen the largest type 116*0b57cec5SDimitry Andric // because G_TRUNC is usually free. One potential catch with this is that 117*0b57cec5SDimitry Andric // some targets have a reduced number of larger registers than smaller 118*0b57cec5SDimitry Andric // registers and this choice potentially increases the live-range for the 119*0b57cec5SDimitry Andric // larger value. 120*0b57cec5SDimitry Andric if (TyForCandidate.getSizeInBits() > CurrentUse.Ty.getSizeInBits()) { 121*0b57cec5SDimitry Andric return {TyForCandidate, OpcodeForCandidate, MIForCandidate}; 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric return CurrentUse; 124*0b57cec5SDimitry Andric } 125*0b57cec5SDimitry Andric 126*0b57cec5SDimitry Andric /// Find a suitable place to insert some instructions and insert them. This 127*0b57cec5SDimitry Andric /// function accounts for special cases like inserting before a PHI node. 128*0b57cec5SDimitry Andric /// The current strategy for inserting before PHI's is to duplicate the 129*0b57cec5SDimitry Andric /// instructions for each predecessor. However, while that's ok for G_TRUNC 130*0b57cec5SDimitry Andric /// on most targets since it generally requires no code, other targets/cases may 131*0b57cec5SDimitry Andric /// want to try harder to find a dominating block. 132*0b57cec5SDimitry Andric static void InsertInsnsWithoutSideEffectsBeforeUse( 133*0b57cec5SDimitry Andric MachineIRBuilder &Builder, MachineInstr &DefMI, MachineOperand &UseMO, 134*0b57cec5SDimitry Andric std::function<void(MachineBasicBlock *, MachineBasicBlock::iterator, 135*0b57cec5SDimitry Andric MachineOperand &UseMO)> 136*0b57cec5SDimitry Andric Inserter) { 137*0b57cec5SDimitry Andric MachineInstr &UseMI = *UseMO.getParent(); 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric MachineBasicBlock *InsertBB = UseMI.getParent(); 140*0b57cec5SDimitry Andric 141*0b57cec5SDimitry Andric // If the use is a PHI then we want the predecessor block instead. 142*0b57cec5SDimitry Andric if (UseMI.isPHI()) { 143*0b57cec5SDimitry Andric MachineOperand *PredBB = std::next(&UseMO); 144*0b57cec5SDimitry Andric InsertBB = PredBB->getMBB(); 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric // If the block is the same block as the def then we want to insert just after 148*0b57cec5SDimitry Andric // the def instead of at the start of the block. 149*0b57cec5SDimitry Andric if (InsertBB == DefMI.getParent()) { 150*0b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPt = &DefMI; 151*0b57cec5SDimitry Andric Inserter(InsertBB, std::next(InsertPt), UseMO); 152*0b57cec5SDimitry Andric return; 153*0b57cec5SDimitry Andric } 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric // Otherwise we want the start of the BB 156*0b57cec5SDimitry Andric Inserter(InsertBB, InsertBB->getFirstNonPHI(), UseMO); 157*0b57cec5SDimitry Andric } 158*0b57cec5SDimitry Andric } // end anonymous namespace 159*0b57cec5SDimitry Andric 160*0b57cec5SDimitry Andric bool CombinerHelper::tryCombineExtendingLoads(MachineInstr &MI) { 161*0b57cec5SDimitry Andric PreferredTuple Preferred; 162*0b57cec5SDimitry Andric if (matchCombineExtendingLoads(MI, Preferred)) { 163*0b57cec5SDimitry Andric applyCombineExtendingLoads(MI, Preferred); 164*0b57cec5SDimitry Andric return true; 165*0b57cec5SDimitry Andric } 166*0b57cec5SDimitry Andric return false; 167*0b57cec5SDimitry Andric } 168*0b57cec5SDimitry Andric 169*0b57cec5SDimitry Andric bool CombinerHelper::matchCombineExtendingLoads(MachineInstr &MI, 170*0b57cec5SDimitry Andric PreferredTuple &Preferred) { 171*0b57cec5SDimitry Andric // We match the loads and follow the uses to the extend instead of matching 172*0b57cec5SDimitry Andric // the extends and following the def to the load. This is because the load 173*0b57cec5SDimitry Andric // must remain in the same position for correctness (unless we also add code 174*0b57cec5SDimitry Andric // to find a safe place to sink it) whereas the extend is freely movable. 175*0b57cec5SDimitry Andric // It also prevents us from duplicating the load for the volatile case or just 176*0b57cec5SDimitry Andric // for performance. 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric if (MI.getOpcode() != TargetOpcode::G_LOAD && 179*0b57cec5SDimitry Andric MI.getOpcode() != TargetOpcode::G_SEXTLOAD && 180*0b57cec5SDimitry Andric MI.getOpcode() != TargetOpcode::G_ZEXTLOAD) 181*0b57cec5SDimitry Andric return false; 182*0b57cec5SDimitry Andric 183*0b57cec5SDimitry Andric auto &LoadValue = MI.getOperand(0); 184*0b57cec5SDimitry Andric assert(LoadValue.isReg() && "Result wasn't a register?"); 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric LLT LoadValueTy = MRI.getType(LoadValue.getReg()); 187*0b57cec5SDimitry Andric if (!LoadValueTy.isScalar()) 188*0b57cec5SDimitry Andric return false; 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric // Most architectures are going to legalize <s8 loads into at least a 1 byte 191*0b57cec5SDimitry Andric // load, and the MMOs can only describe memory accesses in multiples of bytes. 192*0b57cec5SDimitry Andric // If we try to perform extload combining on those, we can end up with 193*0b57cec5SDimitry Andric // %a(s8) = extload %ptr (load 1 byte from %ptr) 194*0b57cec5SDimitry Andric // ... which is an illegal extload instruction. 195*0b57cec5SDimitry Andric if (LoadValueTy.getSizeInBits() < 8) 196*0b57cec5SDimitry Andric return false; 197*0b57cec5SDimitry Andric 198*0b57cec5SDimitry Andric // For non power-of-2 types, they will very likely be legalized into multiple 199*0b57cec5SDimitry Andric // loads. Don't bother trying to match them into extending loads. 200*0b57cec5SDimitry Andric if (!isPowerOf2_32(LoadValueTy.getSizeInBits())) 201*0b57cec5SDimitry Andric return false; 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric // Find the preferred type aside from the any-extends (unless it's the only 204*0b57cec5SDimitry Andric // one) and non-extending ops. We'll emit an extending load to that type and 205*0b57cec5SDimitry Andric // and emit a variant of (extend (trunc X)) for the others according to the 206*0b57cec5SDimitry Andric // relative type sizes. At the same time, pick an extend to use based on the 207*0b57cec5SDimitry Andric // extend involved in the chosen type. 208*0b57cec5SDimitry Andric unsigned PreferredOpcode = MI.getOpcode() == TargetOpcode::G_LOAD 209*0b57cec5SDimitry Andric ? TargetOpcode::G_ANYEXT 210*0b57cec5SDimitry Andric : MI.getOpcode() == TargetOpcode::G_SEXTLOAD 211*0b57cec5SDimitry Andric ? TargetOpcode::G_SEXT 212*0b57cec5SDimitry Andric : TargetOpcode::G_ZEXT; 213*0b57cec5SDimitry Andric Preferred = {LLT(), PreferredOpcode, nullptr}; 214*0b57cec5SDimitry Andric for (auto &UseMI : MRI.use_instructions(LoadValue.getReg())) { 215*0b57cec5SDimitry Andric if (UseMI.getOpcode() == TargetOpcode::G_SEXT || 216*0b57cec5SDimitry Andric UseMI.getOpcode() == TargetOpcode::G_ZEXT || 217*0b57cec5SDimitry Andric UseMI.getOpcode() == TargetOpcode::G_ANYEXT) { 218*0b57cec5SDimitry Andric Preferred = ChoosePreferredUse(Preferred, 219*0b57cec5SDimitry Andric MRI.getType(UseMI.getOperand(0).getReg()), 220*0b57cec5SDimitry Andric UseMI.getOpcode(), &UseMI); 221*0b57cec5SDimitry Andric } 222*0b57cec5SDimitry Andric } 223*0b57cec5SDimitry Andric 224*0b57cec5SDimitry Andric // There were no extends 225*0b57cec5SDimitry Andric if (!Preferred.MI) 226*0b57cec5SDimitry Andric return false; 227*0b57cec5SDimitry Andric // It should be impossible to chose an extend without selecting a different 228*0b57cec5SDimitry Andric // type since by definition the result of an extend is larger. 229*0b57cec5SDimitry Andric assert(Preferred.Ty != LoadValueTy && "Extending to same type?"); 230*0b57cec5SDimitry Andric 231*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Preferred use is: " << *Preferred.MI); 232*0b57cec5SDimitry Andric return true; 233*0b57cec5SDimitry Andric } 234*0b57cec5SDimitry Andric 235*0b57cec5SDimitry Andric void CombinerHelper::applyCombineExtendingLoads(MachineInstr &MI, 236*0b57cec5SDimitry Andric PreferredTuple &Preferred) { 237*0b57cec5SDimitry Andric // Rewrite the load to the chosen extending load. 238*0b57cec5SDimitry Andric Register ChosenDstReg = Preferred.MI->getOperand(0).getReg(); 239*0b57cec5SDimitry Andric 240*0b57cec5SDimitry Andric // Inserter to insert a truncate back to the original type at a given point 241*0b57cec5SDimitry Andric // with some basic CSE to limit truncate duplication to one per BB. 242*0b57cec5SDimitry Andric DenseMap<MachineBasicBlock *, MachineInstr *> EmittedInsns; 243*0b57cec5SDimitry Andric auto InsertTruncAt = [&](MachineBasicBlock *InsertIntoBB, 244*0b57cec5SDimitry Andric MachineBasicBlock::iterator InsertBefore, 245*0b57cec5SDimitry Andric MachineOperand &UseMO) { 246*0b57cec5SDimitry Andric MachineInstr *PreviouslyEmitted = EmittedInsns.lookup(InsertIntoBB); 247*0b57cec5SDimitry Andric if (PreviouslyEmitted) { 248*0b57cec5SDimitry Andric Observer.changingInstr(*UseMO.getParent()); 249*0b57cec5SDimitry Andric UseMO.setReg(PreviouslyEmitted->getOperand(0).getReg()); 250*0b57cec5SDimitry Andric Observer.changedInstr(*UseMO.getParent()); 251*0b57cec5SDimitry Andric return; 252*0b57cec5SDimitry Andric } 253*0b57cec5SDimitry Andric 254*0b57cec5SDimitry Andric Builder.setInsertPt(*InsertIntoBB, InsertBefore); 255*0b57cec5SDimitry Andric Register NewDstReg = MRI.cloneVirtualRegister(MI.getOperand(0).getReg()); 256*0b57cec5SDimitry Andric MachineInstr *NewMI = Builder.buildTrunc(NewDstReg, ChosenDstReg); 257*0b57cec5SDimitry Andric EmittedInsns[InsertIntoBB] = NewMI; 258*0b57cec5SDimitry Andric replaceRegOpWith(MRI, UseMO, NewDstReg); 259*0b57cec5SDimitry Andric }; 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric Observer.changingInstr(MI); 262*0b57cec5SDimitry Andric MI.setDesc( 263*0b57cec5SDimitry Andric Builder.getTII().get(Preferred.ExtendOpcode == TargetOpcode::G_SEXT 264*0b57cec5SDimitry Andric ? TargetOpcode::G_SEXTLOAD 265*0b57cec5SDimitry Andric : Preferred.ExtendOpcode == TargetOpcode::G_ZEXT 266*0b57cec5SDimitry Andric ? TargetOpcode::G_ZEXTLOAD 267*0b57cec5SDimitry Andric : TargetOpcode::G_LOAD)); 268*0b57cec5SDimitry Andric 269*0b57cec5SDimitry Andric // Rewrite all the uses to fix up the types. 270*0b57cec5SDimitry Andric auto &LoadValue = MI.getOperand(0); 271*0b57cec5SDimitry Andric SmallVector<MachineOperand *, 4> Uses; 272*0b57cec5SDimitry Andric for (auto &UseMO : MRI.use_operands(LoadValue.getReg())) 273*0b57cec5SDimitry Andric Uses.push_back(&UseMO); 274*0b57cec5SDimitry Andric 275*0b57cec5SDimitry Andric for (auto *UseMO : Uses) { 276*0b57cec5SDimitry Andric MachineInstr *UseMI = UseMO->getParent(); 277*0b57cec5SDimitry Andric 278*0b57cec5SDimitry Andric // If the extend is compatible with the preferred extend then we should fix 279*0b57cec5SDimitry Andric // up the type and extend so that it uses the preferred use. 280*0b57cec5SDimitry Andric if (UseMI->getOpcode() == Preferred.ExtendOpcode || 281*0b57cec5SDimitry Andric UseMI->getOpcode() == TargetOpcode::G_ANYEXT) { 282*0b57cec5SDimitry Andric unsigned UseDstReg = UseMI->getOperand(0).getReg(); 283*0b57cec5SDimitry Andric MachineOperand &UseSrcMO = UseMI->getOperand(1); 284*0b57cec5SDimitry Andric const LLT &UseDstTy = MRI.getType(UseDstReg); 285*0b57cec5SDimitry Andric if (UseDstReg != ChosenDstReg) { 286*0b57cec5SDimitry Andric if (Preferred.Ty == UseDstTy) { 287*0b57cec5SDimitry Andric // If the use has the same type as the preferred use, then merge 288*0b57cec5SDimitry Andric // the vregs and erase the extend. For example: 289*0b57cec5SDimitry Andric // %1:_(s8) = G_LOAD ... 290*0b57cec5SDimitry Andric // %2:_(s32) = G_SEXT %1(s8) 291*0b57cec5SDimitry Andric // %3:_(s32) = G_ANYEXT %1(s8) 292*0b57cec5SDimitry Andric // ... = ... %3(s32) 293*0b57cec5SDimitry Andric // rewrites to: 294*0b57cec5SDimitry Andric // %2:_(s32) = G_SEXTLOAD ... 295*0b57cec5SDimitry Andric // ... = ... %2(s32) 296*0b57cec5SDimitry Andric replaceRegWith(MRI, UseDstReg, ChosenDstReg); 297*0b57cec5SDimitry Andric Observer.erasingInstr(*UseMO->getParent()); 298*0b57cec5SDimitry Andric UseMO->getParent()->eraseFromParent(); 299*0b57cec5SDimitry Andric } else if (Preferred.Ty.getSizeInBits() < UseDstTy.getSizeInBits()) { 300*0b57cec5SDimitry Andric // If the preferred size is smaller, then keep the extend but extend 301*0b57cec5SDimitry Andric // from the result of the extending load. For example: 302*0b57cec5SDimitry Andric // %1:_(s8) = G_LOAD ... 303*0b57cec5SDimitry Andric // %2:_(s32) = G_SEXT %1(s8) 304*0b57cec5SDimitry Andric // %3:_(s64) = G_ANYEXT %1(s8) 305*0b57cec5SDimitry Andric // ... = ... %3(s64) 306*0b57cec5SDimitry Andric /// rewrites to: 307*0b57cec5SDimitry Andric // %2:_(s32) = G_SEXTLOAD ... 308*0b57cec5SDimitry Andric // %3:_(s64) = G_ANYEXT %2:_(s32) 309*0b57cec5SDimitry Andric // ... = ... %3(s64) 310*0b57cec5SDimitry Andric replaceRegOpWith(MRI, UseSrcMO, ChosenDstReg); 311*0b57cec5SDimitry Andric } else { 312*0b57cec5SDimitry Andric // If the preferred size is large, then insert a truncate. For 313*0b57cec5SDimitry Andric // example: 314*0b57cec5SDimitry Andric // %1:_(s8) = G_LOAD ... 315*0b57cec5SDimitry Andric // %2:_(s64) = G_SEXT %1(s8) 316*0b57cec5SDimitry Andric // %3:_(s32) = G_ZEXT %1(s8) 317*0b57cec5SDimitry Andric // ... = ... %3(s32) 318*0b57cec5SDimitry Andric /// rewrites to: 319*0b57cec5SDimitry Andric // %2:_(s64) = G_SEXTLOAD ... 320*0b57cec5SDimitry Andric // %4:_(s8) = G_TRUNC %2:_(s32) 321*0b57cec5SDimitry Andric // %3:_(s64) = G_ZEXT %2:_(s8) 322*0b57cec5SDimitry Andric // ... = ... %3(s64) 323*0b57cec5SDimitry Andric InsertInsnsWithoutSideEffectsBeforeUse(Builder, MI, *UseMO, 324*0b57cec5SDimitry Andric InsertTruncAt); 325*0b57cec5SDimitry Andric } 326*0b57cec5SDimitry Andric continue; 327*0b57cec5SDimitry Andric } 328*0b57cec5SDimitry Andric // The use is (one of) the uses of the preferred use we chose earlier. 329*0b57cec5SDimitry Andric // We're going to update the load to def this value later so just erase 330*0b57cec5SDimitry Andric // the old extend. 331*0b57cec5SDimitry Andric Observer.erasingInstr(*UseMO->getParent()); 332*0b57cec5SDimitry Andric UseMO->getParent()->eraseFromParent(); 333*0b57cec5SDimitry Andric continue; 334*0b57cec5SDimitry Andric } 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric // The use isn't an extend. Truncate back to the type we originally loaded. 337*0b57cec5SDimitry Andric // This is free on many targets. 338*0b57cec5SDimitry Andric InsertInsnsWithoutSideEffectsBeforeUse(Builder, MI, *UseMO, InsertTruncAt); 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric MI.getOperand(0).setReg(ChosenDstReg); 342*0b57cec5SDimitry Andric Observer.changedInstr(MI); 343*0b57cec5SDimitry Andric } 344*0b57cec5SDimitry Andric 345*0b57cec5SDimitry Andric bool CombinerHelper::matchCombineBr(MachineInstr &MI) { 346*0b57cec5SDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_BR && "Expected a G_BR"); 347*0b57cec5SDimitry Andric // Try to match the following: 348*0b57cec5SDimitry Andric // bb1: 349*0b57cec5SDimitry Andric // %c(s32) = G_ICMP pred, %a, %b 350*0b57cec5SDimitry Andric // %c1(s1) = G_TRUNC %c(s32) 351*0b57cec5SDimitry Andric // G_BRCOND %c1, %bb2 352*0b57cec5SDimitry Andric // G_BR %bb3 353*0b57cec5SDimitry Andric // bb2: 354*0b57cec5SDimitry Andric // ... 355*0b57cec5SDimitry Andric // bb3: 356*0b57cec5SDimitry Andric 357*0b57cec5SDimitry Andric // The above pattern does not have a fall through to the successor bb2, always 358*0b57cec5SDimitry Andric // resulting in a branch no matter which path is taken. Here we try to find 359*0b57cec5SDimitry Andric // and replace that pattern with conditional branch to bb3 and otherwise 360*0b57cec5SDimitry Andric // fallthrough to bb2. 361*0b57cec5SDimitry Andric 362*0b57cec5SDimitry Andric MachineBasicBlock *MBB = MI.getParent(); 363*0b57cec5SDimitry Andric MachineBasicBlock::iterator BrIt(MI); 364*0b57cec5SDimitry Andric if (BrIt == MBB->begin()) 365*0b57cec5SDimitry Andric return false; 366*0b57cec5SDimitry Andric assert(std::next(BrIt) == MBB->end() && "expected G_BR to be a terminator"); 367*0b57cec5SDimitry Andric 368*0b57cec5SDimitry Andric MachineInstr *BrCond = &*std::prev(BrIt); 369*0b57cec5SDimitry Andric if (BrCond->getOpcode() != TargetOpcode::G_BRCOND) 370*0b57cec5SDimitry Andric return false; 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric // Check that the next block is the conditional branch target. 373*0b57cec5SDimitry Andric if (!MBB->isLayoutSuccessor(BrCond->getOperand(1).getMBB())) 374*0b57cec5SDimitry Andric return false; 375*0b57cec5SDimitry Andric 376*0b57cec5SDimitry Andric MachineInstr *CmpMI = MRI.getVRegDef(BrCond->getOperand(0).getReg()); 377*0b57cec5SDimitry Andric if (!CmpMI || CmpMI->getOpcode() != TargetOpcode::G_ICMP || 378*0b57cec5SDimitry Andric !MRI.hasOneUse(CmpMI->getOperand(0).getReg())) 379*0b57cec5SDimitry Andric return false; 380*0b57cec5SDimitry Andric return true; 381*0b57cec5SDimitry Andric } 382*0b57cec5SDimitry Andric 383*0b57cec5SDimitry Andric bool CombinerHelper::tryCombineBr(MachineInstr &MI) { 384*0b57cec5SDimitry Andric if (!matchCombineBr(MI)) 385*0b57cec5SDimitry Andric return false; 386*0b57cec5SDimitry Andric MachineBasicBlock *BrTarget = MI.getOperand(0).getMBB(); 387*0b57cec5SDimitry Andric MachineBasicBlock::iterator BrIt(MI); 388*0b57cec5SDimitry Andric MachineInstr *BrCond = &*std::prev(BrIt); 389*0b57cec5SDimitry Andric MachineInstr *CmpMI = MRI.getVRegDef(BrCond->getOperand(0).getReg()); 390*0b57cec5SDimitry Andric 391*0b57cec5SDimitry Andric CmpInst::Predicate InversePred = CmpInst::getInversePredicate( 392*0b57cec5SDimitry Andric (CmpInst::Predicate)CmpMI->getOperand(1).getPredicate()); 393*0b57cec5SDimitry Andric 394*0b57cec5SDimitry Andric // Invert the G_ICMP condition. 395*0b57cec5SDimitry Andric Observer.changingInstr(*CmpMI); 396*0b57cec5SDimitry Andric CmpMI->getOperand(1).setPredicate(InversePred); 397*0b57cec5SDimitry Andric Observer.changedInstr(*CmpMI); 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric // Change the conditional branch target. 400*0b57cec5SDimitry Andric Observer.changingInstr(*BrCond); 401*0b57cec5SDimitry Andric BrCond->getOperand(1).setMBB(BrTarget); 402*0b57cec5SDimitry Andric Observer.changedInstr(*BrCond); 403*0b57cec5SDimitry Andric MI.eraseFromParent(); 404*0b57cec5SDimitry Andric return true; 405*0b57cec5SDimitry Andric } 406*0b57cec5SDimitry Andric 407*0b57cec5SDimitry Andric bool CombinerHelper::tryCombine(MachineInstr &MI) { 408*0b57cec5SDimitry Andric if (tryCombineCopy(MI)) 409*0b57cec5SDimitry Andric return true; 410*0b57cec5SDimitry Andric return tryCombineExtendingLoads(MI); 411*0b57cec5SDimitry Andric } 412