1 //== ---lib/CodeGen/GlobalISel/GICombinerHelper.cpp --------------------- == //
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 #include "llvm/CodeGen/GlobalISel/Combiner.h"
10 #include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
11 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
12 #include "llvm/CodeGen/GlobalISel/Utils.h"
13 #include "llvm/CodeGen/MachineInstr.h"
14 #include "llvm/CodeGen/MachineRegisterInfo.h"
15 #include "llvm/CodeGen/TargetInstrInfo.h"
17 #define DEBUG_TYPE "gi-combine"
21 CombinerHelper::CombinerHelper(CombinerChangeObserver
&Observer
,
23 : Builder(B
), MRI(Builder
.getMF().getRegInfo()), Observer(Observer
) {}
25 void CombinerHelper::eraseInstr(MachineInstr
&MI
) {
26 Observer
.erasedInstr(MI
);
28 void CombinerHelper::scheduleForVisit(MachineInstr
&MI
) {
29 Observer
.createdInstr(MI
);
32 bool CombinerHelper::tryCombineCopy(MachineInstr
&MI
) {
33 if (MI
.getOpcode() != TargetOpcode::COPY
)
35 unsigned DstReg
= MI
.getOperand(0).getReg();
36 unsigned SrcReg
= MI
.getOperand(1).getReg();
37 LLT DstTy
= MRI
.getType(DstReg
);
38 LLT SrcTy
= MRI
.getType(SrcReg
);
39 // Simple Copy Propagation.
40 // a(sx) = COPY b(sx) -> Replace all uses of a with b.
41 if (DstTy
.isValid() && SrcTy
.isValid() && DstTy
== SrcTy
) {
43 MRI
.replaceRegWith(DstReg
, SrcReg
);
50 struct PreferredTuple
{
51 LLT Ty
; // The result type of the extend.
52 unsigned ExtendOpcode
; // G_ANYEXT/G_SEXT/G_ZEXT
56 /// Select a preference between two uses. CurrentUse is the current preference
57 /// while *ForCandidate is attributes of the candidate under consideration.
58 PreferredTuple
ChoosePreferredUse(PreferredTuple
&CurrentUse
,
59 const LLT
&TyForCandidate
,
60 unsigned OpcodeForCandidate
,
61 MachineInstr
*MIForCandidate
) {
62 if (!CurrentUse
.Ty
.isValid()) {
63 if (CurrentUse
.ExtendOpcode
== OpcodeForCandidate
||
64 CurrentUse
.ExtendOpcode
== TargetOpcode::G_ANYEXT
)
65 return {TyForCandidate
, OpcodeForCandidate
, MIForCandidate
};
69 // We permit the extend to hoist through basic blocks but this is only
70 // sensible if the target has extending loads. If you end up lowering back
71 // into a load and extend during the legalizer then the end result is
72 // hoisting the extend up to the load.
74 // Prefer defined extensions to undefined extensions as these are more
75 // likely to reduce the number of instructions.
76 if (OpcodeForCandidate
== TargetOpcode::G_ANYEXT
&&
77 CurrentUse
.ExtendOpcode
!= TargetOpcode::G_ANYEXT
)
79 else if (CurrentUse
.ExtendOpcode
== TargetOpcode::G_ANYEXT
&&
80 OpcodeForCandidate
!= TargetOpcode::G_ANYEXT
)
81 return {TyForCandidate
, OpcodeForCandidate
, MIForCandidate
};
83 // Prefer sign extensions to zero extensions as sign-extensions tend to be
85 if (CurrentUse
.Ty
== TyForCandidate
) {
86 if (CurrentUse
.ExtendOpcode
== TargetOpcode::G_SEXT
&&
87 OpcodeForCandidate
== TargetOpcode::G_ZEXT
)
89 else if (CurrentUse
.ExtendOpcode
== TargetOpcode::G_ZEXT
&&
90 OpcodeForCandidate
== TargetOpcode::G_SEXT
)
91 return {TyForCandidate
, OpcodeForCandidate
, MIForCandidate
};
94 // This is potentially target specific. We've chosen the largest type
95 // because G_TRUNC is usually free. One potential catch with this is that
96 // some targets have a reduced number of larger registers than smaller
97 // registers and this choice potentially increases the live-range for the
99 if (TyForCandidate
.getSizeInBits() > CurrentUse
.Ty
.getSizeInBits()) {
100 return {TyForCandidate
, OpcodeForCandidate
, MIForCandidate
};
105 /// Find a suitable place to insert some instructions and insert them. This
106 /// function accounts for special cases like inserting before a PHI node.
107 /// The current strategy for inserting before PHI's is to duplicate the
108 /// instructions for each predecessor. However, while that's ok for G_TRUNC
109 /// on most targets since it generally requires no code, other targets/cases may
110 /// want to try harder to find a dominating block.
111 static void InsertInsnsWithoutSideEffectsBeforeUse(
112 MachineIRBuilder
&Builder
, MachineInstr
&DefMI
, MachineOperand
&UseMO
,
113 std::function
<void(MachineBasicBlock
*, MachineBasicBlock::iterator
)>
115 MachineInstr
&UseMI
= *UseMO
.getParent();
117 MachineBasicBlock
*InsertBB
= UseMI
.getParent();
119 // If the use is a PHI then we want the predecessor block instead.
121 MachineOperand
*PredBB
= std::next(&UseMO
);
122 InsertBB
= PredBB
->getMBB();
125 // If the block is the same block as the def then we want to insert just after
126 // the def instead of at the start of the block.
127 if (InsertBB
== DefMI
.getParent()) {
128 MachineBasicBlock::iterator InsertPt
= &DefMI
;
129 Inserter(InsertBB
, std::next(InsertPt
));
133 // Otherwise we want the start of the BB
134 Inserter(InsertBB
, InsertBB
->getFirstNonPHI());
136 } // end anonymous namespace
138 bool CombinerHelper::tryCombineExtendingLoads(MachineInstr
&MI
) {
139 struct InsertionPoint
{
140 MachineOperand
*UseMO
;
141 MachineBasicBlock
*InsertIntoBB
;
142 MachineBasicBlock::iterator InsertBefore
;
143 InsertionPoint(MachineOperand
*UseMO
, MachineBasicBlock
*InsertIntoBB
,
144 MachineBasicBlock::iterator InsertBefore
)
145 : UseMO(UseMO
), InsertIntoBB(InsertIntoBB
), InsertBefore(InsertBefore
) {
149 // We match the loads and follow the uses to the extend instead of matching
150 // the extends and following the def to the load. This is because the load
151 // must remain in the same position for correctness (unless we also add code
152 // to find a safe place to sink it) whereas the extend is freely movable.
153 // It also prevents us from duplicating the load for the volatile case or just
156 if (MI
.getOpcode() != TargetOpcode::G_LOAD
&&
157 MI
.getOpcode() != TargetOpcode::G_SEXTLOAD
&&
158 MI
.getOpcode() != TargetOpcode::G_ZEXTLOAD
)
161 auto &LoadValue
= MI
.getOperand(0);
162 assert(LoadValue
.isReg() && "Result wasn't a register?");
164 LLT LoadValueTy
= MRI
.getType(LoadValue
.getReg());
165 if (!LoadValueTy
.isScalar())
168 // Find the preferred type aside from the any-extends (unless it's the only
169 // one) and non-extending ops. We'll emit an extending load to that type and
170 // and emit a variant of (extend (trunc X)) for the others according to the
171 // relative type sizes. At the same time, pick an extend to use based on the
172 // extend involved in the chosen type.
173 unsigned PreferredOpcode
= MI
.getOpcode() == TargetOpcode::G_LOAD
174 ? TargetOpcode::G_ANYEXT
175 : MI
.getOpcode() == TargetOpcode::G_SEXTLOAD
176 ? TargetOpcode::G_SEXT
177 : TargetOpcode::G_ZEXT
;
178 PreferredTuple Preferred
= {LLT(), PreferredOpcode
, nullptr};
179 for (auto &UseMI
: MRI
.use_instructions(LoadValue
.getReg())) {
180 if (UseMI
.getOpcode() == TargetOpcode::G_SEXT
||
181 UseMI
.getOpcode() == TargetOpcode::G_ZEXT
||
182 UseMI
.getOpcode() == TargetOpcode::G_ANYEXT
) {
183 Preferred
= ChoosePreferredUse(Preferred
,
184 MRI
.getType(UseMI
.getOperand(0).getReg()),
185 UseMI
.getOpcode(), &UseMI
);
189 // There were no extends
192 // It should be impossible to chose an extend without selecting a different
193 // type since by definition the result of an extend is larger.
194 assert(Preferred
.Ty
!= LoadValueTy
&& "Extending to same type?");
196 // Rewrite the load to the chosen extending load.
197 unsigned ChosenDstReg
= Preferred
.MI
->getOperand(0).getReg();
199 Builder
.getTII().get(Preferred
.ExtendOpcode
== TargetOpcode::G_SEXT
200 ? TargetOpcode::G_SEXTLOAD
201 : Preferred
.ExtendOpcode
== TargetOpcode::G_ZEXT
202 ? TargetOpcode::G_ZEXTLOAD
203 : TargetOpcode::G_LOAD
));
205 // Rewrite all the uses to fix up the types.
206 SmallVector
<MachineInstr
*, 1> ScheduleForErase
;
207 SmallVector
<InsertionPoint
, 4> ScheduleForInsert
;
208 for (auto &UseMO
: MRI
.use_operands(LoadValue
.getReg())) {
209 MachineInstr
*UseMI
= UseMO
.getParent();
211 // If the extend is compatible with the preferred extend then we should fix
212 // up the type and extend so that it uses the preferred use.
213 if (UseMI
->getOpcode() == Preferred
.ExtendOpcode
||
214 UseMI
->getOpcode() == TargetOpcode::G_ANYEXT
) {
215 unsigned UseDstReg
= UseMI
->getOperand(0).getReg();
216 unsigned UseSrcReg
= UseMI
->getOperand(1).getReg();
217 const LLT
&UseDstTy
= MRI
.getType(UseDstReg
);
218 if (UseDstReg
!= ChosenDstReg
) {
219 if (Preferred
.Ty
== UseDstTy
) {
220 // If the use has the same type as the preferred use, then merge
221 // the vregs and erase the extend. For example:
222 // %1:_(s8) = G_LOAD ...
223 // %2:_(s32) = G_SEXT %1(s8)
224 // %3:_(s32) = G_ANYEXT %1(s8)
227 // %2:_(s32) = G_SEXTLOAD ...
229 MRI
.replaceRegWith(UseDstReg
, ChosenDstReg
);
230 ScheduleForErase
.push_back(UseMO
.getParent());
231 } else if (Preferred
.Ty
.getSizeInBits() < UseDstTy
.getSizeInBits()) {
232 // If the preferred size is smaller, then keep the extend but extend
233 // from the result of the extending load. For example:
234 // %1:_(s8) = G_LOAD ...
235 // %2:_(s32) = G_SEXT %1(s8)
236 // %3:_(s64) = G_ANYEXT %1(s8)
239 // %2:_(s32) = G_SEXTLOAD ...
240 // %3:_(s64) = G_ANYEXT %2:_(s32)
242 MRI
.replaceRegWith(UseSrcReg
, ChosenDstReg
);
244 // If the preferred size is large, then insert a truncate. For
246 // %1:_(s8) = G_LOAD ...
247 // %2:_(s64) = G_SEXT %1(s8)
248 // %3:_(s32) = G_ZEXT %1(s8)
251 // %2:_(s64) = G_SEXTLOAD ...
252 // %4:_(s8) = G_TRUNC %2:_(s32)
253 // %3:_(s64) = G_ZEXT %2:_(s8)
255 InsertInsnsWithoutSideEffectsBeforeUse(
257 [&](MachineBasicBlock
*InsertIntoBB
,
258 MachineBasicBlock::iterator InsertBefore
) {
259 ScheduleForInsert
.emplace_back(&UseMO
, InsertIntoBB
, InsertBefore
);
264 // The use is (one of) the uses of the preferred use we chose earlier.
265 // We're going to update the load to def this value later so just erase
267 ScheduleForErase
.push_back(UseMO
.getParent());
271 // The use isn't an extend. Truncate back to the type we originally loaded.
272 // This is free on many targets.
273 InsertInsnsWithoutSideEffectsBeforeUse(
275 [&](MachineBasicBlock
*InsertIntoBB
,
276 MachineBasicBlock::iterator InsertBefore
) {
277 ScheduleForInsert
.emplace_back(&UseMO
, InsertIntoBB
, InsertBefore
);
281 DenseMap
<MachineBasicBlock
*, MachineInstr
*> EmittedInsns
;
282 for (auto &InsertionInfo
: ScheduleForInsert
) {
283 MachineOperand
*UseMO
= InsertionInfo
.UseMO
;
284 MachineBasicBlock
*InsertIntoBB
= InsertionInfo
.InsertIntoBB
;
285 MachineBasicBlock::iterator InsertBefore
= InsertionInfo
.InsertBefore
;
287 MachineInstr
*PreviouslyEmitted
= EmittedInsns
.lookup(InsertIntoBB
);
288 if (PreviouslyEmitted
) {
289 UseMO
->setReg(PreviouslyEmitted
->getOperand(0).getReg());
293 Builder
.setInsertPt(*InsertIntoBB
, InsertBefore
);
294 unsigned NewDstReg
= MRI
.cloneVirtualRegister(MI
.getOperand(0).getReg());
295 MachineInstr
*NewMI
= Builder
.buildTrunc(NewDstReg
, ChosenDstReg
);
296 EmittedInsns
[InsertIntoBB
] = NewMI
;
297 UseMO
->setReg(NewDstReg
);
298 Observer
.createdInstr(*NewMI
);
300 for (auto &EraseMI
: ScheduleForErase
) {
301 EraseMI
->eraseFromParent();
302 Observer
.erasedInstr(*EraseMI
);
304 MI
.getOperand(0).setReg(ChosenDstReg
);
309 bool CombinerHelper::tryCombine(MachineInstr
&MI
) {
310 if (tryCombineCopy(MI
))
312 return tryCombineExtendingLoads(MI
);