LLVM 24.0.0git
CombinerHelperCasts.cpp
Go to the documentation of this file.
1//===- CombinerHelperCasts.cpp---------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements CombinerHelper for G_ANYEXT, G_SEXT, G_TRUNC, and
10// G_ZEXT
11//
12//===----------------------------------------------------------------------===//
24
25#define DEBUG_TYPE "gi-combiner"
26
27using namespace llvm;
28using namespace MIPatternMatch;
29
31 BuildFnTy &MatchInfo) const {
34
35 Register Dst = Sext->getReg(0);
36 Register Src = Trunc->getSrcReg();
37
38 LLT DstTy = MRI.getType(Dst);
39 LLT SrcTy = MRI.getType(Src);
40
41 // Combines without nsw trunc.
42 if (!Trunc->getFlag(MachineInstr::NoSWrap)) {
43 // Do this for 8 bit values and up. We don't want to do it for e.g. G_TRUNC
44 // to i1.
45 unsigned TruncWidth = MRI.getType(Trunc->getReg(0)).getScalarSizeInBits();
46 if (TruncWidth < 8)
47 return false;
48
49 if (DstTy != SrcTy ||
51 {TargetOpcode::G_SEXT_INREG, {DstTy, SrcTy}, {}, {TruncWidth}}))
52 return false;
53
54 MatchInfo = [=](MachineIRBuilder &B) {
55 B.buildSExtInReg(Dst, Src, TruncWidth);
56 };
57 return true;
58 }
59
60 // Combines for nsw trunc.
61
62 if (DstTy == SrcTy) {
63 MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
64 return true;
65 }
66
67 if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() &&
68 isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) {
69 MatchInfo = [=](MachineIRBuilder &B) {
70 B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoSWrap);
71 };
72 return true;
73 }
74
75 if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() &&
76 isLegalOrBeforeLegalizer({TargetOpcode::G_SEXT, {DstTy, SrcTy}})) {
77 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
78 return true;
79 }
80
81 return false;
82}
83
85 BuildFnTy &MatchInfo) const {
88
89 Register Dst = Zext->getReg(0);
90 Register Src = Trunc->getSrcReg();
91
92 LLT DstTy = MRI.getType(Dst);
93 LLT SrcTy = MRI.getType(Src);
94
95 if (DstTy == SrcTy) {
96 MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
97 return true;
98 }
99
100 if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() &&
101 isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) {
102 MatchInfo = [=](MachineIRBuilder &B) {
103 B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoUWrap);
104 };
105 return true;
106 }
107
108 if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() &&
109 isLegalOrBeforeLegalizer({TargetOpcode::G_ZEXT, {DstTy, SrcTy}})) {
110 MatchInfo = [=](MachineIRBuilder &B) {
111 B.buildZExt(Dst, Src, MachineInstr::MIFlag::NonNeg);
112 };
113 return true;
114 }
115
116 return false;
117}
118
120 BuildFnTy &MatchInfo) const {
121 Register Dst = MO.getReg();
122 Register Src;
123 if (!mi_match(Dst, MRI, m_GZExt(m_Reg(Src))))
124 return false;
125
126 LLT DstTy = MRI.getType(Dst);
127 LLT SrcTy = MRI.getType(Src);
128 const auto &TLI = getTargetLowering();
129
130 // Convert zext nneg to sext if sext is the preferred form for the target.
131 if (isLegalOrBeforeLegalizer({TargetOpcode::G_SEXT, {DstTy, SrcTy}}) &&
132 TLI.isSExtCheaperThanZExt(getMVTForLLT(SrcTy), getMVTForLLT(DstTy))) {
133 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
134 return true;
135 }
136
137 return false;
138}
139
141 const MachineInstr &ExtMI,
142 BuildFnTy &MatchInfo) const {
143 const GTrunc *Trunc = cast<GTrunc>(&Root);
144 const GExtOp *Ext = cast<GExtOp>(&ExtMI);
145
146 if (!MRI.hasOneNonDBGUse(Ext->getReg(0)))
147 return false;
148
149 Register Dst = Trunc->getReg(0);
150 Register Src = Ext->getSrcReg();
151 LLT DstTy = MRI.getType(Dst);
152 LLT SrcTy = MRI.getType(Src);
153
154 if (SrcTy == DstTy) {
155 // The source and the destination are equally sized. We need to copy.
156 MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
157
158 return true;
159 }
160
161 if (SrcTy.getScalarSizeInBits() < DstTy.getScalarSizeInBits()) {
162 // If the source is smaller than the destination, we need to extend.
163
164 if (!isLegalOrBeforeLegalizer({Ext->getOpcode(), {DstTy, SrcTy}}))
165 return false;
166
167 MatchInfo = [=](MachineIRBuilder &B) {
168 B.buildInstr(Ext->getOpcode(), {Dst}, {Src});
169 };
170
171 return true;
172 }
173
174 if (SrcTy.getScalarSizeInBits() > DstTy.getScalarSizeInBits()) {
175 // If the source is larger than the destination, then we need to truncate.
176
177 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}}))
178 return false;
179
180 MatchInfo = [=](MachineIRBuilder &B) { B.buildTrunc(Dst, Src); };
181
182 return true;
183 }
184
185 return false;
186}
187
188bool CombinerHelper::isCastFree(unsigned Opcode, LLT ToTy, LLT FromTy) const {
189 const TargetLowering &TLI = getTargetLowering();
190 LLVMContext &Ctx = getContext();
191
192 switch (Opcode) {
193 case TargetOpcode::G_ANYEXT:
194 case TargetOpcode::G_ZEXT:
195 return TLI.isZExtFree(FromTy, ToTy, Ctx);
196 case TargetOpcode::G_TRUNC:
197 return TLI.isTruncateFree(FromTy, ToTy, Ctx);
198 default:
199 return false;
200 }
201}
202
204 const MachineInstr &SelectMI,
205 BuildFnTy &MatchInfo) const {
206 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
207 const GSelect *Select = cast<GSelect>(&SelectMI);
208
209 if (!MRI.hasOneNonDBGUse(Select->getReg(0)))
210 return false;
211
212 Register Dst = Cast->getReg(0);
213 LLT DstTy = MRI.getType(Dst);
214 LLT CondTy = MRI.getType(Select->getCondReg());
215 Register TrueReg = Select->getTrueReg();
216 Register FalseReg = Select->getFalseReg();
217 LLT SrcTy = MRI.getType(TrueReg);
218 Register Cond = Select->getCondReg();
219
220 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_SELECT, {DstTy, CondTy}}))
221 return false;
222
223 if (!isCastFree(Cast->getOpcode(), DstTy, SrcTy))
224 return false;
225
226 MatchInfo = [=](MachineIRBuilder &B) {
227 auto True = B.buildInstr(Cast->getOpcode(), {DstTy}, {TrueReg});
228 auto False = B.buildInstr(Cast->getOpcode(), {DstTy}, {FalseReg});
229 B.buildSelect(Dst, Cond, True, False);
230 };
231
232 return true;
233}
234
236 const MachineInstr &SecondMI,
237 BuildFnTy &MatchInfo) const {
238 const GExtOp *First = cast<GExtOp>(&FirstMI);
239 const GExtOp *Second = cast<GExtOp>(&SecondMI);
240
241 Register Dst = First->getReg(0);
242 Register Src = Second->getSrcReg();
243 LLT DstTy = MRI.getType(Dst);
244 LLT SrcTy = MRI.getType(Src);
245
246 if (!MRI.hasOneNonDBGUse(Second->getReg(0)))
247 return false;
248
249 // ext of ext -> later ext
250 if (First->getOpcode() == Second->getOpcode() &&
251 isLegalOrBeforeLegalizer({Second->getOpcode(), {DstTy, SrcTy}})) {
252 if (Second->getOpcode() == TargetOpcode::G_ZEXT) {
256 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
257 return true;
258 }
259 // not zext -> no flags
260 MatchInfo = [=](MachineIRBuilder &B) {
261 B.buildInstr(Second->getOpcode(), {Dst}, {Src});
262 };
263 return true;
264 }
265
266 // anyext of sext/zext -> sext/zext
267 // -> pick anyext as second ext, then ext of ext
268 if (First->getOpcode() == TargetOpcode::G_ANYEXT &&
269 isLegalOrBeforeLegalizer({Second->getOpcode(), {DstTy, SrcTy}})) {
270 if (Second->getOpcode() == TargetOpcode::G_ZEXT) {
274 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
275 return true;
276 }
277 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
278 return true;
279 }
280
281 // sext/zext of anyext -> sext/zext
282 // -> pick anyext as first ext, then ext of ext
283 if (Second->getOpcode() == TargetOpcode::G_ANYEXT &&
284 isLegalOrBeforeLegalizer({First->getOpcode(), {DstTy, SrcTy}})) {
285 if (First->getOpcode() == TargetOpcode::G_ZEXT) {
289 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
290 return true;
291 }
292 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
293 return true;
294 }
295
296 return false;
297}
298
300 const MachineInstr &BVMI,
301 BuildFnTy &MatchInfo) const {
302 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
303 const GBuildVector *BV = cast<GBuildVector>(&BVMI);
304
305 if (!MRI.hasOneNonDBGUse(BV->getReg(0)))
306 return false;
307
308 Register Dst = Cast->getReg(0);
309 // The type of the new build vector.
310 LLT DstTy = MRI.getType(Dst);
311 // The scalar or element type of the new build vector.
312 LLT ElemTy = DstTy.getScalarType();
313 // The scalar or element type of the old build vector.
314 LLT InputElemTy = MRI.getType(BV->getReg(0)).getElementType();
315
316 // Check legality of new build vector, the scalar casts, and profitability of
317 // the many casts.
319 {TargetOpcode::G_BUILD_VECTOR, {DstTy, ElemTy}}) ||
320 !isLegalOrBeforeLegalizer({Cast->getOpcode(), {ElemTy, InputElemTy}}) ||
321 !isCastFree(Cast->getOpcode(), ElemTy, InputElemTy))
322 return false;
323
324 MatchInfo = [=](MachineIRBuilder &B) {
326 unsigned Elements = BV->getNumSources();
327 for (unsigned I = 0; I < Elements; ++I) {
328 auto CastI =
329 B.buildInstr(Cast->getOpcode(), {ElemTy}, {BV->getSourceReg(I)});
330 Casts.push_back(CastI.getReg(0));
331 }
332
333 B.buildBuildVector(Dst, Casts);
334 };
335
336 return true;
337}
338
340 const MachineInstr &BinopMI,
341 BuildFnTy &MatchInfo) const {
342 const GTrunc *Trunc = cast<GTrunc>(&TruncMI);
343 const GBinOp *BinOp = cast<GBinOp>(&BinopMI);
344
345 if (!MRI.hasOneNonDBGUse(BinOp->getReg(0)))
346 return false;
347
348 Register Dst = Trunc->getReg(0);
349 LLT DstTy = MRI.getType(Dst);
350
351 // Is narrow binop legal?
352 if (!isLegalOrBeforeLegalizer({BinOp->getOpcode(), {DstTy}}))
353 return false;
354
355 MatchInfo = [=](MachineIRBuilder &B) {
356 auto LHS = B.buildTrunc(DstTy, BinOp->getLHSReg());
357 auto RHS = B.buildTrunc(DstTy, BinOp->getRHSReg());
358 B.buildInstr(BinOp->getOpcode(), {Dst}, {LHS, RHS});
359 };
360
361 return true;
362}
363
365 APInt &MatchInfo) const {
366 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
367
369
370 LLT DstTy = MRI.getType(Cast->getReg(0));
371
373 return false;
374
375 switch (Cast->getOpcode()) {
376 case TargetOpcode::G_TRUNC: {
377 MatchInfo = Input.trunc(DstTy.getScalarSizeInBits());
378 return true;
379 }
380 default:
381 return false;
382 }
383}
384
387 BuildFnTy &MatchInfo) const {
388 assert(Root.getOpcode() == TargetOpcode::G_SEXT_INREG &&
389 Other.getOpcode() == TargetOpcode::G_SEXT_INREG);
390
391 unsigned RootWidth = Root.getOperand(2).getImm();
392 unsigned OtherWidth = Other.getOperand(2).getImm();
393
394 Register Dst = Root.getOperand(0).getReg();
395 Register OtherDst = Other.getOperand(0).getReg();
396 Register Src = Other.getOperand(1).getReg();
397
398 if (RootWidth >= OtherWidth) {
399 // The root sext_inreg is entirely redundant because the other one
400 // is narrower.
401 if (!canReplaceReg(Dst, OtherDst, MRI))
402 return false;
403
404 MatchInfo = [=](MachineIRBuilder &B) {
405 Observer.changingAllUsesOfReg(MRI, Dst);
406 MRI.replaceRegWith(Dst, OtherDst);
407 Observer.finishedChangingAllUsesOfReg();
408 };
409 } else {
410 // RootWidth < OtherWidth, rewrite this G_SEXT_INREG with the source of the
411 // other G_SEXT_INREG.
412 MatchInfo = [=](MachineIRBuilder &B) {
413 B.buildSExtInReg(Dst, Src, RootWidth);
414 };
415 }
416
417 return true;
418}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This contains common combine transformations that may be used in a combine pass,or by the target else...
Interface for Targets to specify which operations they can successfully select and how the others sho...
Implement a low-level type suitable for MachineInstr level instruction selection.
#define I(x, y, z)
Definition MD5.cpp:57
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
const SmallVectorImpl< MachineOperand > & Cond
The Input class is used to parse a yaml document into in-memory structs and vectors.
Class for arbitrary precision integers.
Definition APInt.h:78
LLVM_ABI bool matchZextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine zext of trunc.
LLVM_ABI bool matchNonNegZext(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine zext nneg to sext.
LLVM_ABI const TargetLowering & getTargetLowering() const
LLVM_ABI bool matchSextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine sext of trunc.
LLVM_ABI bool matchTruncateOfExt(const MachineInstr &Root, const MachineInstr &ExtMI, BuildFnTy &MatchInfo) const
Transform trunc ([asz]ext x) to x or ([asz]ext x) or (trunc x).
LLVM_ABI bool matchExtOfExt(const MachineInstr &FirstMI, const MachineInstr &SecondMI, BuildFnTy &MatchInfo) const
LLVM_ABI LLVMContext & getContext() const
LLVM_ABI bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
MachineRegisterInfo & MRI
LLVM_ABI bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
LLVM_ABI bool matchNarrowBinop(const MachineInstr &TruncMI, const MachineInstr &BinopMI, BuildFnTy &MatchInfo) const
trunc (binop X, C) --> binop (trunc X, trunc C).
GISelChangeObserver & Observer
LLVM_ABI bool matchRedundantSextInReg(MachineInstr &Root, MachineInstr &Other, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchCastOfBuildVector(const MachineInstr &CastMI, const MachineInstr &BVMI, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchCastOfInteger(const MachineInstr &CastMI, APInt &MatchInfo) const
LLVM_ABI bool matchCastOfSelect(const MachineInstr &Cast, const MachineInstr &SelectMI, BuildFnTy &MatchInfo) const
Represents a binary operation, i.e, x = y op z.
Register getLHSReg() const
Register getRHSReg() const
Represents a G_BUILD_VECTOR.
Register getSrcReg() const
Represents an integer-like extending operation.
Represents an integer-like extending or truncating operation.
unsigned getNumSources() const
Returns the number of source registers.
Represents a G_SELECT.
Represents a sext.
Represents a trunc.
Represents a zext.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
constexpr unsigned getScalarSizeInBits() const
LLT getScalarType() const
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
Helper class to build MachineInstr.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
int64_t getImm() const
Register getReg() const
getReg - Returns the register number.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
virtual bool isZExtFree(Type *FromTy, Type *ToTy) const
Return true if any actual instruction that defines a value of type FromTy implicitly zero-extends the...
virtual bool isTruncateFree(Type *FromTy, Type *ToTy) const
Return true if it's free to truncate a value of type FromTy to type ToTy.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
operand_type_match m_Reg()
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
This is an optimization pass for GlobalISel generic memory operations.
std::function< void(MachineIRBuilder &)> BuildFnTy
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
Definition Utils.cpp:497
LLVM_ABI const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
Definition Utils.cpp:308
LLVM_ABI bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI)
Check if DstReg can be replaced with SrcReg depending on the register constraints.
Definition Utils.cpp:203
@ Other
Any other memory.
Definition ModRef.h:68
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559