LLVM 20.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 {
30 GSext *Sext = cast<GSext>(getDefIgnoringCopies(MO.getReg(), MRI));
31 GTrunc *Trunc = cast<GTrunc>(getDefIgnoringCopies(Sext->getSrcReg(), MRI));
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 if (DstTy == SrcTy) {
40 MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
41 return true;
42 }
43
44 if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() &&
45 isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) {
46 MatchInfo = [=](MachineIRBuilder &B) {
47 B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoSWrap);
48 };
49 return true;
50 }
51
52 if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() &&
53 isLegalOrBeforeLegalizer({TargetOpcode::G_SEXT, {DstTy, SrcTy}})) {
54 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
55 return true;
56 }
57
58 return false;
59}
60
62 BuildFnTy &MatchInfo) const {
63 GZext *Zext = cast<GZext>(getDefIgnoringCopies(MO.getReg(), MRI));
64 GTrunc *Trunc = cast<GTrunc>(getDefIgnoringCopies(Zext->getSrcReg(), MRI));
65
66 Register Dst = Zext->getReg(0);
67 Register Src = Trunc->getSrcReg();
68
69 LLT DstTy = MRI.getType(Dst);
70 LLT SrcTy = MRI.getType(Src);
71
72 if (DstTy == SrcTy) {
73 MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
74 return true;
75 }
76
77 if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() &&
78 isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) {
79 MatchInfo = [=](MachineIRBuilder &B) {
80 B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoUWrap);
81 };
82 return true;
83 }
84
85 if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() &&
86 isLegalOrBeforeLegalizer({TargetOpcode::G_ZEXT, {DstTy, SrcTy}})) {
87 MatchInfo = [=](MachineIRBuilder &B) {
88 B.buildZExt(Dst, Src, MachineInstr::MIFlag::NonNeg);
89 };
90 return true;
91 }
92
93 return false;
94}
95
97 BuildFnTy &MatchInfo) const {
98 GZext *Zext = cast<GZext>(MRI.getVRegDef(MO.getReg()));
99
100 Register Dst = Zext->getReg(0);
101 Register Src = Zext->getSrcReg();
102
103 LLT DstTy = MRI.getType(Dst);
104 LLT SrcTy = MRI.getType(Src);
105 const auto &TLI = getTargetLowering();
106
107 // Convert zext nneg to sext if sext is the preferred form for the target.
108 if (isLegalOrBeforeLegalizer({TargetOpcode::G_SEXT, {DstTy, SrcTy}}) &&
109 TLI.isSExtCheaperThanZExt(getMVTForLLT(SrcTy), getMVTForLLT(DstTy))) {
110 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
111 return true;
112 }
113
114 return false;
115}
116
118 const MachineInstr &ExtMI,
119 BuildFnTy &MatchInfo) const {
120 const GTrunc *Trunc = cast<GTrunc>(&Root);
121 const GExtOp *Ext = cast<GExtOp>(&ExtMI);
122
123 if (!MRI.hasOneNonDBGUse(Ext->getReg(0)))
124 return false;
125
126 Register Dst = Trunc->getReg(0);
127 Register Src = Ext->getSrcReg();
128 LLT DstTy = MRI.getType(Dst);
129 LLT SrcTy = MRI.getType(Src);
130
131 if (SrcTy == DstTy) {
132 // The source and the destination are equally sized. We need to copy.
133 MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
134
135 return true;
136 }
137
138 if (SrcTy.getScalarSizeInBits() < DstTy.getScalarSizeInBits()) {
139 // If the source is smaller than the destination, we need to extend.
140
141 if (!isLegalOrBeforeLegalizer({Ext->getOpcode(), {DstTy, SrcTy}}))
142 return false;
143
144 MatchInfo = [=](MachineIRBuilder &B) {
145 B.buildInstr(Ext->getOpcode(), {Dst}, {Src});
146 };
147
148 return true;
149 }
150
151 if (SrcTy.getScalarSizeInBits() > DstTy.getScalarSizeInBits()) {
152 // If the source is larger than the destination, then we need to truncate.
153
154 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}}))
155 return false;
156
157 MatchInfo = [=](MachineIRBuilder &B) { B.buildTrunc(Dst, Src); };
158
159 return true;
160 }
161
162 return false;
163}
164
165bool CombinerHelper::isCastFree(unsigned Opcode, LLT ToTy, LLT FromTy) const {
166 const TargetLowering &TLI = getTargetLowering();
167 LLVMContext &Ctx = getContext();
168
169 switch (Opcode) {
170 case TargetOpcode::G_ANYEXT:
171 case TargetOpcode::G_ZEXT:
172 return TLI.isZExtFree(FromTy, ToTy, Ctx);
173 case TargetOpcode::G_TRUNC:
174 return TLI.isTruncateFree(FromTy, ToTy, Ctx);
175 default:
176 return false;
177 }
178}
179
181 const MachineInstr &SelectMI,
182 BuildFnTy &MatchInfo) const {
183 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
184 const GSelect *Select = cast<GSelect>(&SelectMI);
185
186 if (!MRI.hasOneNonDBGUse(Select->getReg(0)))
187 return false;
188
189 Register Dst = Cast->getReg(0);
190 LLT DstTy = MRI.getType(Dst);
191 LLT CondTy = MRI.getType(Select->getCondReg());
192 Register TrueReg = Select->getTrueReg();
193 Register FalseReg = Select->getFalseReg();
194 LLT SrcTy = MRI.getType(TrueReg);
195 Register Cond = Select->getCondReg();
196
197 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_SELECT, {DstTy, CondTy}}))
198 return false;
199
200 if (!isCastFree(Cast->getOpcode(), DstTy, SrcTy))
201 return false;
202
203 MatchInfo = [=](MachineIRBuilder &B) {
204 auto True = B.buildInstr(Cast->getOpcode(), {DstTy}, {TrueReg});
205 auto False = B.buildInstr(Cast->getOpcode(), {DstTy}, {FalseReg});
206 B.buildSelect(Dst, Cond, True, False);
207 };
208
209 return true;
210}
211
213 const MachineInstr &SecondMI,
214 BuildFnTy &MatchInfo) const {
215 const GExtOp *First = cast<GExtOp>(&FirstMI);
216 const GExtOp *Second = cast<GExtOp>(&SecondMI);
217
218 Register Dst = First->getReg(0);
219 Register Src = Second->getSrcReg();
220 LLT DstTy = MRI.getType(Dst);
221 LLT SrcTy = MRI.getType(Src);
222
223 if (!MRI.hasOneNonDBGUse(Second->getReg(0)))
224 return false;
225
226 // ext of ext -> later ext
227 if (First->getOpcode() == Second->getOpcode() &&
228 isLegalOrBeforeLegalizer({Second->getOpcode(), {DstTy, SrcTy}})) {
229 if (Second->getOpcode() == TargetOpcode::G_ZEXT) {
233 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
234 return true;
235 }
236 // not zext -> no flags
237 MatchInfo = [=](MachineIRBuilder &B) {
238 B.buildInstr(Second->getOpcode(), {Dst}, {Src});
239 };
240 return true;
241 }
242
243 // anyext of sext/zext -> sext/zext
244 // -> pick anyext as second ext, then ext of ext
245 if (First->getOpcode() == TargetOpcode::G_ANYEXT &&
246 isLegalOrBeforeLegalizer({Second->getOpcode(), {DstTy, SrcTy}})) {
247 if (Second->getOpcode() == TargetOpcode::G_ZEXT) {
251 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
252 return true;
253 }
254 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
255 return true;
256 }
257
258 // sext/zext of anyext -> sext/zext
259 // -> pick anyext as first ext, then ext of ext
260 if (Second->getOpcode() == TargetOpcode::G_ANYEXT &&
261 isLegalOrBeforeLegalizer({First->getOpcode(), {DstTy, SrcTy}})) {
262 if (First->getOpcode() == TargetOpcode::G_ZEXT) {
266 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
267 return true;
268 }
269 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
270 return true;
271 }
272
273 return false;
274}
275
277 const MachineInstr &BVMI,
278 BuildFnTy &MatchInfo) const {
279 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
280 const GBuildVector *BV = cast<GBuildVector>(&BVMI);
281
282 if (!MRI.hasOneNonDBGUse(BV->getReg(0)))
283 return false;
284
285 Register Dst = Cast->getReg(0);
286 // The type of the new build vector.
287 LLT DstTy = MRI.getType(Dst);
288 // The scalar or element type of the new build vector.
289 LLT ElemTy = DstTy.getScalarType();
290 // The scalar or element type of the old build vector.
291 LLT InputElemTy = MRI.getType(BV->getReg(0)).getElementType();
292
293 // Check legality of new build vector, the scalar casts, and profitability of
294 // the many casts.
296 {TargetOpcode::G_BUILD_VECTOR, {DstTy, ElemTy}}) ||
297 !isLegalOrBeforeLegalizer({Cast->getOpcode(), {ElemTy, InputElemTy}}) ||
298 !isCastFree(Cast->getOpcode(), ElemTy, InputElemTy))
299 return false;
300
301 MatchInfo = [=](MachineIRBuilder &B) {
303 unsigned Elements = BV->getNumSources();
304 for (unsigned I = 0; I < Elements; ++I) {
305 auto CastI =
306 B.buildInstr(Cast->getOpcode(), {ElemTy}, {BV->getSourceReg(I)});
307 Casts.push_back(CastI.getReg(0));
308 }
309
310 B.buildBuildVector(Dst, Casts);
311 };
312
313 return true;
314}
315
317 const MachineInstr &BinopMI,
318 BuildFnTy &MatchInfo) const {
319 const GTrunc *Trunc = cast<GTrunc>(&TruncMI);
320 const GBinOp *BinOp = cast<GBinOp>(&BinopMI);
321
322 if (!MRI.hasOneNonDBGUse(BinOp->getReg(0)))
323 return false;
324
325 Register Dst = Trunc->getReg(0);
326 LLT DstTy = MRI.getType(Dst);
327
328 // Is narrow binop legal?
329 if (!isLegalOrBeforeLegalizer({BinOp->getOpcode(), {DstTy}}))
330 return false;
331
332 MatchInfo = [=](MachineIRBuilder &B) {
333 auto LHS = B.buildTrunc(DstTy, BinOp->getLHSReg());
334 auto RHS = B.buildTrunc(DstTy, BinOp->getRHSReg());
335 B.buildInstr(BinOp->getOpcode(), {Dst}, {LHS, RHS});
336 };
337
338 return true;
339}
340
342 APInt &MatchInfo) const {
343 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
344
345 APInt Input = getIConstantFromReg(Cast->getSrcReg(), MRI);
346
347 LLT DstTy = MRI.getType(Cast->getReg(0));
348
350 return false;
351
352 switch (Cast->getOpcode()) {
353 case TargetOpcode::G_TRUNC: {
354 MatchInfo = Input.trunc(DstTy.getScalarSizeInBits());
355 return true;
356 }
357 default:
358 return false;
359 }
360}
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:58
This file declares the MachineIRBuilder class.
const SmallVectorImpl< MachineOperand > & Cond
Value * RHS
Value * LHS
Class for arbitrary precision integers.
Definition: APInt.h:78
APInt trunc(unsigned width) const
Truncate to new width.
Definition: APInt.cpp:910
bool matchZextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine zext of trunc.
bool matchNonNegZext(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine zext nneg to sext.
const TargetLowering & getTargetLowering() const
bool matchSextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine sext of trunc.
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).
bool matchExtOfExt(const MachineInstr &FirstMI, const MachineInstr &SecondMI, BuildFnTy &MatchInfo) const
LLVMContext & getContext() const
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
MachineRegisterInfo & MRI
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchNarrowBinop(const MachineInstr &TruncMI, const MachineInstr &BinopMI, BuildFnTy &MatchInfo) const
trunc (binop X, C) --> binop (trunc X, trunc C).
bool matchCastOfBuildVector(const MachineInstr &CastMI, const MachineInstr &BVMI, BuildFnTy &MatchInfo) const
bool matchCastOfInteger(const MachineInstr &CastMI, APInt &MatchInfo) const
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.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
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
Definition: LowLevelType.h:264
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
Definition: LowLevelType.h:277
constexpr LLT getScalarType() const
Definition: LowLevelType.h:205
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
Helper class to build MachineInstr.
Representation of each machine instruction.
Definition: MachineInstr.h:69
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:575
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
Definition: MachineInstr.h:397
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
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.
Definition: AddressRanges.h:18
MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
Definition: Utils.cpp:471
std::function< void(MachineIRBuilder &)> BuildFnTy
const APInt & getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI)
VReg is defined by a G_CONSTANT, return the corresponding value.
Definition: Utils.cpp:290
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.