1 //===-- llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h -----*- C++ -*-//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
8 // This file contains some helper functions which try to cleanup artifacts
9 // such as G_TRUNCs/G_[ZSA]EXTENDS that were created during legalization to make
10 // the types match. This file also contains some combines of merges that happens
11 // at the end of the legalization.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/CodeGen/GlobalISel/Legalizer.h"
15 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
16 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
17 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
18 #include "llvm/CodeGen/GlobalISel/Utils.h"
19 #include "llvm/CodeGen/MachineRegisterInfo.h"
20 #include "llvm/Support/Debug.h"
22 #define DEBUG_TYPE "legalizer"
23 using namespace llvm::MIPatternMatch
;
26 class LegalizationArtifactCombiner
{
27 MachineIRBuilder
&Builder
;
28 MachineRegisterInfo
&MRI
;
29 const LegalizerInfo
&LI
;
32 LegalizationArtifactCombiner(MachineIRBuilder
&B
, MachineRegisterInfo
&MRI
,
33 const LegalizerInfo
&LI
)
34 : Builder(B
), MRI(MRI
), LI(LI
) {}
36 bool tryCombineAnyExt(MachineInstr
&MI
,
37 SmallVectorImpl
<MachineInstr
*> &DeadInsts
) {
38 if (MI
.getOpcode() != TargetOpcode::G_ANYEXT
)
42 unsigned DstReg
= MI
.getOperand(0).getReg();
43 unsigned SrcReg
= lookThroughCopyInstrs(MI
.getOperand(1).getReg());
45 // aext(trunc x) - > aext/copy/trunc x
47 if (mi_match(SrcReg
, MRI
, m_GTrunc(m_Reg(TruncSrc
)))) {
48 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI
;);
49 Builder
.buildAnyExtOrTrunc(DstReg
, TruncSrc
);
50 markInstAndDefDead(MI
, *MRI
.getVRegDef(SrcReg
), DeadInsts
);
54 // aext([asz]ext x) -> [asz]ext x
57 if (mi_match(SrcReg
, MRI
,
58 m_all_of(m_MInstr(ExtMI
), m_any_of(m_GAnyExt(m_Reg(ExtSrc
)),
59 m_GSExt(m_Reg(ExtSrc
)),
60 m_GZExt(m_Reg(ExtSrc
)))))) {
61 Builder
.buildInstr(ExtMI
->getOpcode(), {DstReg
}, {ExtSrc
});
62 markInstAndDefDead(MI
, *ExtMI
, DeadInsts
);
65 return tryFoldImplicitDef(MI
, DeadInsts
);
68 bool tryCombineZExt(MachineInstr
&MI
,
69 SmallVectorImpl
<MachineInstr
*> &DeadInsts
) {
71 if (MI
.getOpcode() != TargetOpcode::G_ZEXT
)
75 unsigned DstReg
= MI
.getOperand(0).getReg();
76 unsigned SrcReg
= lookThroughCopyInstrs(MI
.getOperand(1).getReg());
78 // zext(trunc x) - > and (aext/copy/trunc x), mask
80 if (mi_match(SrcReg
, MRI
, m_GTrunc(m_Reg(TruncSrc
)))) {
81 LLT DstTy
= MRI
.getType(DstReg
);
82 if (isInstUnsupported({TargetOpcode::G_AND
, {DstTy
}}) ||
83 isConstantUnsupported(DstTy
))
85 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI
;);
86 LLT SrcTy
= MRI
.getType(SrcReg
);
87 APInt Mask
= APInt::getAllOnesValue(SrcTy
.getScalarSizeInBits());
88 auto MIBMask
= Builder
.buildConstant(DstTy
, Mask
.getZExtValue());
89 Builder
.buildAnd(DstReg
, Builder
.buildAnyExtOrTrunc(DstTy
, TruncSrc
),
91 markInstAndDefDead(MI
, *MRI
.getVRegDef(SrcReg
), DeadInsts
);
94 return tryFoldImplicitDef(MI
, DeadInsts
);
97 bool tryCombineSExt(MachineInstr
&MI
,
98 SmallVectorImpl
<MachineInstr
*> &DeadInsts
) {
100 if (MI
.getOpcode() != TargetOpcode::G_SEXT
)
103 Builder
.setInstr(MI
);
104 unsigned DstReg
= MI
.getOperand(0).getReg();
105 unsigned SrcReg
= lookThroughCopyInstrs(MI
.getOperand(1).getReg());
107 // sext(trunc x) - > ashr (shl (aext/copy/trunc x), c), c
109 if (mi_match(SrcReg
, MRI
, m_GTrunc(m_Reg(TruncSrc
)))) {
110 LLT DstTy
= MRI
.getType(DstReg
);
111 // Guess on the RHS shift amount type, which should be re-legalized if
113 if (isInstUnsupported({TargetOpcode::G_SHL
, {DstTy
, DstTy
}}) ||
114 isInstUnsupported({TargetOpcode::G_ASHR
, {DstTy
, DstTy
}}) ||
115 isConstantUnsupported(DstTy
))
117 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI
;);
118 LLT SrcTy
= MRI
.getType(SrcReg
);
119 unsigned ShAmt
= DstTy
.getScalarSizeInBits() - SrcTy
.getScalarSizeInBits();
120 auto MIBShAmt
= Builder
.buildConstant(DstTy
, ShAmt
);
121 auto MIBShl
= Builder
.buildInstr(
122 TargetOpcode::G_SHL
, {DstTy
},
123 {Builder
.buildAnyExtOrTrunc(DstTy
, TruncSrc
), MIBShAmt
});
124 Builder
.buildInstr(TargetOpcode::G_ASHR
, {DstReg
}, {MIBShl
, MIBShAmt
});
125 markInstAndDefDead(MI
, *MRI
.getVRegDef(SrcReg
), DeadInsts
);
128 return tryFoldImplicitDef(MI
, DeadInsts
);
131 /// Try to fold G_[ASZ]EXT (G_IMPLICIT_DEF).
132 bool tryFoldImplicitDef(MachineInstr
&MI
,
133 SmallVectorImpl
<MachineInstr
*> &DeadInsts
) {
134 unsigned Opcode
= MI
.getOpcode();
135 if (Opcode
!= TargetOpcode::G_ANYEXT
&& Opcode
!= TargetOpcode::G_ZEXT
&&
136 Opcode
!= TargetOpcode::G_SEXT
)
139 if (MachineInstr
*DefMI
= getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF
,
140 MI
.getOperand(1).getReg(), MRI
)) {
141 Builder
.setInstr(MI
);
142 unsigned DstReg
= MI
.getOperand(0).getReg();
143 LLT DstTy
= MRI
.getType(DstReg
);
145 if (Opcode
== TargetOpcode::G_ANYEXT
) {
146 // G_ANYEXT (G_IMPLICIT_DEF) -> G_IMPLICIT_DEF
147 if (isInstUnsupported({TargetOpcode::G_IMPLICIT_DEF
, {DstTy
}}))
149 LLVM_DEBUG(dbgs() << ".. Combine G_ANYEXT(G_IMPLICIT_DEF): " << MI
;);
150 Builder
.buildInstr(TargetOpcode::G_IMPLICIT_DEF
, {DstReg
}, {});
152 // G_[SZ]EXT (G_IMPLICIT_DEF) -> G_CONSTANT 0 because the top
153 // bits will be 0 for G_ZEXT and 0/1 for the G_SEXT.
154 if (isConstantUnsupported(DstTy
))
156 LLVM_DEBUG(dbgs() << ".. Combine G_[SZ]EXT(G_IMPLICIT_DEF): " << MI
;);
157 Builder
.buildConstant(DstReg
, 0);
160 markInstAndDefDead(MI
, *DefMI
, DeadInsts
);
166 static unsigned getMergeOpcode(LLT OpTy
, LLT DestTy
) {
167 if (OpTy
.isVector() && DestTy
.isVector())
168 return TargetOpcode::G_CONCAT_VECTORS
;
170 if (OpTy
.isVector() && !DestTy
.isVector())
171 return TargetOpcode::G_BUILD_VECTOR
;
173 return TargetOpcode::G_MERGE_VALUES
;
176 bool tryCombineMerges(MachineInstr
&MI
,
177 SmallVectorImpl
<MachineInstr
*> &DeadInsts
) {
179 if (MI
.getOpcode() != TargetOpcode::G_UNMERGE_VALUES
)
182 unsigned NumDefs
= MI
.getNumOperands() - 1;
184 LLT OpTy
= MRI
.getType(MI
.getOperand(NumDefs
).getReg());
185 LLT DestTy
= MRI
.getType(MI
.getOperand(0).getReg());
187 unsigned MergingOpcode
= getMergeOpcode(OpTy
, DestTy
);
188 MachineInstr
*MergeI
=
189 getOpcodeDef(MergingOpcode
, MI
.getOperand(NumDefs
).getReg(), MRI
);
194 const unsigned NumMergeRegs
= MergeI
->getNumOperands() - 1;
196 if (NumMergeRegs
< NumDefs
) {
197 if (NumDefs
% NumMergeRegs
!= 0)
200 Builder
.setInstr(MI
);
201 // Transform to UNMERGEs, for example
202 // %1 = G_MERGE_VALUES %4, %5
203 // %9, %10, %11, %12 = G_UNMERGE_VALUES %1
205 // %9, %10 = G_UNMERGE_VALUES %4
206 // %11, %12 = G_UNMERGE_VALUES %5
208 const unsigned NewNumDefs
= NumDefs
/ NumMergeRegs
;
209 for (unsigned Idx
= 0; Idx
< NumMergeRegs
; ++Idx
) {
210 SmallVector
<unsigned, 2> DstRegs
;
211 for (unsigned j
= 0, DefIdx
= Idx
* NewNumDefs
; j
< NewNumDefs
;
213 DstRegs
.push_back(MI
.getOperand(DefIdx
).getReg());
215 Builder
.buildUnmerge(DstRegs
, MergeI
->getOperand(Idx
+ 1).getReg());
218 } else if (NumMergeRegs
> NumDefs
) {
219 if (NumMergeRegs
% NumDefs
!= 0)
222 Builder
.setInstr(MI
);
223 // Transform to MERGEs
224 // %6 = G_MERGE_VALUES %17, %18, %19, %20
225 // %7, %8 = G_UNMERGE_VALUES %6
227 // %7 = G_MERGE_VALUES %17, %18
228 // %8 = G_MERGE_VALUES %19, %20
230 const unsigned NumRegs
= NumMergeRegs
/ NumDefs
;
231 for (unsigned DefIdx
= 0; DefIdx
< NumDefs
; ++DefIdx
) {
232 SmallVector
<unsigned, 2> Regs
;
233 for (unsigned j
= 0, Idx
= NumRegs
* DefIdx
+ 1; j
< NumRegs
;
235 Regs
.push_back(MergeI
->getOperand(Idx
).getReg());
237 Builder
.buildMerge(MI
.getOperand(DefIdx
).getReg(), Regs
);
241 // FIXME: is a COPY appropriate if the types mismatch? We know both
242 // registers are allocatable by now.
243 if (MRI
.getType(MI
.getOperand(0).getReg()) !=
244 MRI
.getType(MergeI
->getOperand(1).getReg()))
247 for (unsigned Idx
= 0; Idx
< NumDefs
; ++Idx
)
248 MRI
.replaceRegWith(MI
.getOperand(Idx
).getReg(),
249 MergeI
->getOperand(Idx
+ 1).getReg());
252 markInstAndDefDead(MI
, *MergeI
, DeadInsts
);
256 static bool isMergeLikeOpcode(unsigned Opc
) {
258 case TargetOpcode::G_MERGE_VALUES
:
259 case TargetOpcode::G_BUILD_VECTOR
:
260 case TargetOpcode::G_CONCAT_VECTORS
:
267 bool tryCombineExtract(MachineInstr
&MI
,
268 SmallVectorImpl
<MachineInstr
*> &DeadInsts
) {
269 assert(MI
.getOpcode() == TargetOpcode::G_EXTRACT
);
271 // Try to use the source registers from a G_MERGE_VALUES
273 // %2 = G_MERGE_VALUES %0, %1
274 // %3 = G_EXTRACT %2, N
277 // for N < %2.getSizeInBits() / 2
278 // %3 = G_EXTRACT %0, N
280 // for N >= %2.getSizeInBits() / 2
281 // %3 = G_EXTRACT %1, (N - %0.getSizeInBits()
283 unsigned Src
= lookThroughCopyInstrs(MI
.getOperand(1).getReg());
284 MachineInstr
*MergeI
= MRI
.getVRegDef(Src
);
285 if (!MergeI
|| !isMergeLikeOpcode(MergeI
->getOpcode()))
288 LLT DstTy
= MRI
.getType(MI
.getOperand(0).getReg());
289 LLT SrcTy
= MRI
.getType(Src
);
291 // TODO: Do we need to check if the resulting extract is supported?
292 unsigned ExtractDstSize
= DstTy
.getSizeInBits();
293 unsigned Offset
= MI
.getOperand(2).getImm();
294 unsigned NumMergeSrcs
= MergeI
->getNumOperands() - 1;
295 unsigned MergeSrcSize
= SrcTy
.getSizeInBits() / NumMergeSrcs
;
296 unsigned MergeSrcIdx
= Offset
/ MergeSrcSize
;
298 // Compute the offset of the last bit the extract needs.
299 unsigned EndMergeSrcIdx
= (Offset
+ ExtractDstSize
- 1) / MergeSrcSize
;
301 // Can't handle the case where the extract spans multiple inputs.
302 if (MergeSrcIdx
!= EndMergeSrcIdx
)
305 // TODO: We could modify MI in place in most cases.
306 Builder
.setInstr(MI
);
307 Builder
.buildExtract(
308 MI
.getOperand(0).getReg(),
309 MergeI
->getOperand(MergeSrcIdx
+ 1).getReg(),
310 Offset
- MergeSrcIdx
* MergeSrcSize
);
311 markInstAndDefDead(MI
, *MergeI
, DeadInsts
);
315 /// Try to combine away MI.
316 /// Returns true if it combined away the MI.
317 /// Adds instructions that are dead as a result of the combine
318 /// into DeadInsts, which can include MI.
319 bool tryCombineInstruction(MachineInstr
&MI
,
320 SmallVectorImpl
<MachineInstr
*> &DeadInsts
) {
321 switch (MI
.getOpcode()) {
324 case TargetOpcode::G_ANYEXT
:
325 return tryCombineAnyExt(MI
, DeadInsts
);
326 case TargetOpcode::G_ZEXT
:
327 return tryCombineZExt(MI
, DeadInsts
);
328 case TargetOpcode::G_SEXT
:
329 return tryCombineSExt(MI
, DeadInsts
);
330 case TargetOpcode::G_UNMERGE_VALUES
:
331 return tryCombineMerges(MI
, DeadInsts
);
332 case TargetOpcode::G_EXTRACT
:
333 return tryCombineExtract(MI
, DeadInsts
);
334 case TargetOpcode::G_TRUNC
: {
335 bool Changed
= false;
336 for (auto &Use
: MRI
.use_instructions(MI
.getOperand(0).getReg()))
337 Changed
|= tryCombineInstruction(Use
, DeadInsts
);
345 static unsigned getArtifactSrcReg(const MachineInstr
&MI
) {
346 switch (MI
.getOpcode()) {
347 case TargetOpcode::COPY
:
348 case TargetOpcode::G_TRUNC
:
349 case TargetOpcode::G_ZEXT
:
350 case TargetOpcode::G_ANYEXT
:
351 case TargetOpcode::G_SEXT
:
352 case TargetOpcode::G_UNMERGE_VALUES
:
353 return MI
.getOperand(MI
.getNumOperands() - 1).getReg();
354 case TargetOpcode::G_EXTRACT
:
355 return MI
.getOperand(1).getReg();
357 llvm_unreachable("Not a legalization artifact happen");
361 /// Mark MI as dead. If a def of one of MI's operands, DefMI, would also be
362 /// dead due to MI being killed, then mark DefMI as dead too.
363 /// Some of the combines (extends(trunc)), try to walk through redundant
364 /// copies in between the extends and the truncs, and this attempts to collect
365 /// the in between copies if they're dead.
366 void markInstAndDefDead(MachineInstr
&MI
, MachineInstr
&DefMI
,
367 SmallVectorImpl
<MachineInstr
*> &DeadInsts
) {
368 DeadInsts
.push_back(&MI
);
370 // Collect all the copy instructions that are made dead, due to deleting
371 // this instruction. Collect all of them until the Trunc(DefMI).
373 // %1(s1) = G_TRUNC %0(s32)
374 // %2(s1) = COPY %1(s1)
375 // %3(s1) = COPY %2(s1)
376 // %4(s32) = G_ANYEXT %3(s1)
377 // In this case, we would have replaced %4 with a copy of %0,
378 // and as a result, %3, %2, %1 are dead.
379 MachineInstr
*PrevMI
= &MI
;
380 while (PrevMI
!= &DefMI
) {
381 unsigned PrevRegSrc
= getArtifactSrcReg(*PrevMI
);
383 MachineInstr
*TmpDef
= MRI
.getVRegDef(PrevRegSrc
);
384 if (MRI
.hasOneUse(PrevRegSrc
)) {
385 if (TmpDef
!= &DefMI
) {
386 assert(TmpDef
->getOpcode() == TargetOpcode::COPY
&&
387 "Expecting copy here");
388 DeadInsts
.push_back(TmpDef
);
394 if (PrevMI
== &DefMI
&& MRI
.hasOneUse(DefMI
.getOperand(0).getReg()))
395 DeadInsts
.push_back(&DefMI
);
398 /// Checks if the target legalizer info has specified anything about the
399 /// instruction, or if unsupported.
400 bool isInstUnsupported(const LegalityQuery
&Query
) const {
401 using namespace LegalizeActions
;
402 auto Step
= LI
.getAction(Query
);
403 return Step
.Action
== Unsupported
|| Step
.Action
== NotFound
;
406 bool isConstantUnsupported(LLT Ty
) const {
408 return isInstUnsupported({TargetOpcode::G_CONSTANT
, {Ty
}});
410 LLT EltTy
= Ty
.getElementType();
411 return isInstUnsupported({TargetOpcode::G_CONSTANT
, {EltTy
}}) ||
412 isInstUnsupported({TargetOpcode::G_BUILD_VECTOR
, {Ty
, EltTy
}});
415 /// Looks through copy instructions and returns the actual
417 unsigned lookThroughCopyInstrs(unsigned Reg
) {
419 while (mi_match(Reg
, MRI
, m_Copy(m_Reg(TmpReg
)))) {
420 if (MRI
.getType(TmpReg
).isValid())