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//===----------------------------------------------------------------------===//
23
24#define DEBUG_TYPE "gi-combiner"
25
26using namespace llvm;
27
29 BuildFnTy &MatchInfo) const {
32
33 Register Dst = Sext->getReg(0);
34 Register Src = Trunc->getSrcReg();
35
36 LLT DstTy = MRI.getType(Dst);
37 LLT SrcTy = MRI.getType(Src);
38
39 // Combines without nsw trunc.
40 if (!Trunc->getFlag(MachineInstr::NoSWrap)) {
41 // Do this for 8 bit values and up. We don't want to do it for e.g. G_TRUNC
42 // to i1.
43 unsigned TruncWidth = MRI.getType(Trunc->getReg(0)).getScalarSizeInBits();
44 if (TruncWidth < 8)
45 return false;
46
47 if (DstTy != SrcTy ||
49 {TargetOpcode::G_SEXT_INREG, {DstTy, SrcTy}, {}, {TruncWidth}}))
50 return false;
51
52 MatchInfo = [=](MachineIRBuilder &B) {
53 B.buildSExtInReg(Dst, Src, TruncWidth);
54 };
55 return true;
56 }
57
58 // Combines for nsw trunc.
59
60 if (DstTy == SrcTy) {
61 MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
62 return true;
63 }
64
65 if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() &&
66 isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) {
67 MatchInfo = [=](MachineIRBuilder &B) {
68 B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoSWrap);
69 };
70 return true;
71 }
72
73 if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() &&
74 isLegalOrBeforeLegalizer({TargetOpcode::G_SEXT, {DstTy, SrcTy}})) {
75 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
76 return true;
77 }
78
79 return false;
80}
81
83 BuildFnTy &MatchInfo) const {
86
87 Register Dst = Zext->getReg(0);
88 Register Src = Trunc->getSrcReg();
89
90 LLT DstTy = MRI.getType(Dst);
91 LLT SrcTy = MRI.getType(Src);
92
93 if (DstTy == SrcTy) {
94 MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
95 return true;
96 }
97
98 if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() &&
99 isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) {
100 MatchInfo = [=](MachineIRBuilder &B) {
101 B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoUWrap);
102 };
103 return true;
104 }
105
106 if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() &&
107 isLegalOrBeforeLegalizer({TargetOpcode::G_ZEXT, {DstTy, SrcTy}})) {
108 MatchInfo = [=](MachineIRBuilder &B) {
109 B.buildZExt(Dst, Src, MachineInstr::MIFlag::NonNeg);
110 };
111 return true;
112 }
113
114 return false;
115}
116
118 BuildFnTy &MatchInfo) const {
119 GZext *Zext = cast<GZext>(MRI.getVRegDef(MO.getReg()));
120
121 Register Dst = Zext->getReg(0);
122 Register Src = Zext->getSrcReg();
123
124 LLT DstTy = MRI.getType(Dst);
125 LLT SrcTy = MRI.getType(Src);
126 const auto &TLI = getTargetLowering();
127
128 // Convert zext nneg to sext if sext is the preferred form for the target.
129 if (isLegalOrBeforeLegalizer({TargetOpcode::G_SEXT, {DstTy, SrcTy}}) &&
130 TLI.isSExtCheaperThanZExt(getMVTForLLT(SrcTy), getMVTForLLT(DstTy))) {
131 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
132 return true;
133 }
134
135 return false;
136}
137
139 const MachineInstr &ExtMI,
140 BuildFnTy &MatchInfo) const {
141 const GTrunc *Trunc = cast<GTrunc>(&Root);
142 const GExtOp *Ext = cast<GExtOp>(&ExtMI);
143
144 if (!MRI.hasOneNonDBGUse(Ext->getReg(0)))
145 return false;
146
147 Register Dst = Trunc->getReg(0);
148 Register Src = Ext->getSrcReg();
149 LLT DstTy = MRI.getType(Dst);
150 LLT SrcTy = MRI.getType(Src);
151
152 if (SrcTy == DstTy) {
153 // The source and the destination are equally sized. We need to copy.
154 MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
155
156 return true;
157 }
158
159 if (SrcTy.getScalarSizeInBits() < DstTy.getScalarSizeInBits()) {
160 // If the source is smaller than the destination, we need to extend.
161
162 if (!isLegalOrBeforeLegalizer({Ext->getOpcode(), {DstTy, SrcTy}}))
163 return false;
164
165 MatchInfo = [=](MachineIRBuilder &B) {
166 B.buildInstr(Ext->getOpcode(), {Dst}, {Src});
167 };
168
169 return true;
170 }
171
172 if (SrcTy.getScalarSizeInBits() > DstTy.getScalarSizeInBits()) {
173 // If the source is larger than the destination, then we need to truncate.
174
175 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}}))
176 return false;
177
178 MatchInfo = [=](MachineIRBuilder &B) { B.buildTrunc(Dst, Src); };
179
180 return true;
181 }
182
183 return false;
184}
185
186bool CombinerHelper::isCastFree(unsigned Opcode, LLT ToTy, LLT FromTy) const {
187 const TargetLowering &TLI = getTargetLowering();
188 LLVMContext &Ctx = getContext();
189
190 switch (Opcode) {
191 case TargetOpcode::G_ANYEXT:
192 case TargetOpcode::G_ZEXT:
193 return TLI.isZExtFree(FromTy, ToTy, Ctx);
194 case TargetOpcode::G_TRUNC:
195 return TLI.isTruncateFree(FromTy, ToTy, Ctx);
196 default:
197 return false;
198 }
199}
200
202 const MachineInstr &SelectMI,
203 BuildFnTy &MatchInfo) const {
204 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
205 const GSelect *Select = cast<GSelect>(&SelectMI);
206
207 if (!MRI.hasOneNonDBGUse(Select->getReg(0)))
208 return false;
209
210 Register Dst = Cast->getReg(0);
211 LLT DstTy = MRI.getType(Dst);
212 LLT CondTy = MRI.getType(Select->getCondReg());
213 Register TrueReg = Select->getTrueReg();
214 Register FalseReg = Select->getFalseReg();
215 LLT SrcTy = MRI.getType(TrueReg);
216 Register Cond = Select->getCondReg();
217
218 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_SELECT, {DstTy, CondTy}}))
219 return false;
220
221 if (!isCastFree(Cast->getOpcode(), DstTy, SrcTy))
222 return false;
223
224 MatchInfo = [=](MachineIRBuilder &B) {
225 auto True = B.buildInstr(Cast->getOpcode(), {DstTy}, {TrueReg});
226 auto False = B.buildInstr(Cast->getOpcode(), {DstTy}, {FalseReg});
227 B.buildSelect(Dst, Cond, True, False);
228 };
229
230 return true;
231}
232
234 const MachineInstr &SecondMI,
235 BuildFnTy &MatchInfo) const {
236 const GExtOp *First = cast<GExtOp>(&FirstMI);
237 const GExtOp *Second = cast<GExtOp>(&SecondMI);
238
239 Register Dst = First->getReg(0);
240 Register Src = Second->getSrcReg();
241 LLT DstTy = MRI.getType(Dst);
242 LLT SrcTy = MRI.getType(Src);
243
244 if (!MRI.hasOneNonDBGUse(Second->getReg(0)))
245 return false;
246
247 // ext of ext -> later ext
248 if (First->getOpcode() == Second->getOpcode() &&
249 isLegalOrBeforeLegalizer({Second->getOpcode(), {DstTy, SrcTy}})) {
250 if (Second->getOpcode() == TargetOpcode::G_ZEXT) {
254 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
255 return true;
256 }
257 // not zext -> no flags
258 MatchInfo = [=](MachineIRBuilder &B) {
259 B.buildInstr(Second->getOpcode(), {Dst}, {Src});
260 };
261 return true;
262 }
263
264 // anyext of sext/zext -> sext/zext
265 // -> pick anyext as second ext, then ext of ext
266 if (First->getOpcode() == TargetOpcode::G_ANYEXT &&
267 isLegalOrBeforeLegalizer({Second->getOpcode(), {DstTy, SrcTy}})) {
268 if (Second->getOpcode() == TargetOpcode::G_ZEXT) {
272 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
273 return true;
274 }
275 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
276 return true;
277 }
278
279 // sext/zext of anyext -> sext/zext
280 // -> pick anyext as first ext, then ext of ext
281 if (Second->getOpcode() == TargetOpcode::G_ANYEXT &&
282 isLegalOrBeforeLegalizer({First->getOpcode(), {DstTy, SrcTy}})) {
283 if (First->getOpcode() == TargetOpcode::G_ZEXT) {
287 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
288 return true;
289 }
290 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
291 return true;
292 }
293
294 return false;
295}
296
298 const MachineInstr &BVMI,
299 BuildFnTy &MatchInfo) const {
300 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
301 const GBuildVector *BV = cast<GBuildVector>(&BVMI);
302
303 if (!MRI.hasOneNonDBGUse(BV->getReg(0)))
304 return false;
305
306 Register Dst = Cast->getReg(0);
307 // The type of the new build vector.
308 LLT DstTy = MRI.getType(Dst);
309 // The scalar or element type of the new build vector.
310 LLT ElemTy = DstTy.getScalarType();
311 // The scalar or element type of the old build vector.
312 LLT InputElemTy = MRI.getType(BV->getReg(0)).getElementType();
313
314 // Check legality of new build vector, the scalar casts, and profitability of
315 // the many casts.
317 {TargetOpcode::G_BUILD_VECTOR, {DstTy, ElemTy}}) ||
318 !isLegalOrBeforeLegalizer({Cast->getOpcode(), {ElemTy, InputElemTy}}) ||
319 !isCastFree(Cast->getOpcode(), ElemTy, InputElemTy))
320 return false;
321
322 MatchInfo = [=](MachineIRBuilder &B) {
324 unsigned Elements = BV->getNumSources();
325 for (unsigned I = 0; I < Elements; ++I) {
326 auto CastI =
327 B.buildInstr(Cast->getOpcode(), {ElemTy}, {BV->getSourceReg(I)});
328 Casts.push_back(CastI.getReg(0));
329 }
330
331 B.buildBuildVector(Dst, Casts);
332 };
333
334 return true;
335}
336
338 const MachineInstr &BinopMI,
339 BuildFnTy &MatchInfo) const {
340 const GTrunc *Trunc = cast<GTrunc>(&TruncMI);
341 const GBinOp *BinOp = cast<GBinOp>(&BinopMI);
342
343 if (!MRI.hasOneNonDBGUse(BinOp->getReg(0)))
344 return false;
345
346 Register Dst = Trunc->getReg(0);
347 LLT DstTy = MRI.getType(Dst);
348
349 // Is narrow binop legal?
350 if (!isLegalOrBeforeLegalizer({BinOp->getOpcode(), {DstTy}}))
351 return false;
352
353 MatchInfo = [=](MachineIRBuilder &B) {
354 auto LHS = B.buildTrunc(DstTy, BinOp->getLHSReg());
355 auto RHS = B.buildTrunc(DstTy, BinOp->getRHSReg());
356 B.buildInstr(BinOp->getOpcode(), {Dst}, {LHS, RHS});
357 };
358
359 return true;
360}
361
363 APInt &MatchInfo) const {
364 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
365
367
368 LLT DstTy = MRI.getType(Cast->getReg(0));
369
371 return false;
372
373 switch (Cast->getOpcode()) {
374 case TargetOpcode::G_TRUNC: {
375 MatchInfo = Input.trunc(DstTy.getScalarSizeInBits());
376 return true;
377 }
378 default:
379 return false;
380 }
381}
382
385 BuildFnTy &MatchInfo) const {
386 assert(Root.getOpcode() == TargetOpcode::G_SEXT_INREG &&
387 Other.getOpcode() == TargetOpcode::G_SEXT_INREG);
388
389 unsigned RootWidth = Root.getOperand(2).getImm();
390 unsigned OtherWidth = Other.getOperand(2).getImm();
391
392 Register Dst = Root.getOperand(0).getReg();
393 Register OtherDst = Other.getOperand(0).getReg();
394 Register Src = Other.getOperand(1).getReg();
395
396 if (RootWidth >= OtherWidth) {
397 // The root sext_inreg is entirely redundant because the other one
398 // is narrower.
399 if (!canReplaceReg(Dst, OtherDst, MRI))
400 return false;
401
402 MatchInfo = [=](MachineIRBuilder &B) {
403 Observer.changingAllUsesOfReg(MRI, Dst);
404 MRI.replaceRegWith(Dst, OtherDst);
405 Observer.finishedChangingAllUsesOfReg();
406 };
407 } else {
408 // RootWidth < OtherWidth, rewrite this G_SEXT_INREG with the source of the
409 // other G_SEXT_INREG.
410 MatchInfo = [=](MachineIRBuilder &B) {
411 B.buildSExtInReg(Dst, Src, RootWidth);
412 };
413 }
414
415 return true;
416}
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
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...
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