xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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