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) {
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) {
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) {
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) {
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 const DataLayout &DL = getDataLayout();
168 LLVMContext &Ctx = getContext();
169
170 switch (Opcode) {
171 case TargetOpcode::G_ANYEXT:
172 case TargetOpcode::G_ZEXT:
173 return TLI.isZExtFree(FromTy, ToTy, DL, Ctx);
174 case TargetOpcode::G_TRUNC:
175 return TLI.isTruncateFree(FromTy, ToTy, DL, Ctx);
176 default:
177 return false;
178 }
179}
180
182 const MachineInstr &SelectMI,
183 BuildFnTy &MatchInfo) {
184 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
185 const GSelect *Select = cast<GSelect>(&SelectMI);
186
187 if (!MRI.hasOneNonDBGUse(Select->getReg(0)))
188 return false;
189
190 Register Dst = Cast->getReg(0);
191 LLT DstTy = MRI.getType(Dst);
192 LLT CondTy = MRI.getType(Select->getCondReg());
193 Register TrueReg = Select->getTrueReg();
194 Register FalseReg = Select->getFalseReg();
195 LLT SrcTy = MRI.getType(TrueReg);
196 Register Cond = Select->getCondReg();
197
198 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_SELECT, {DstTy, CondTy}}))
199 return false;
200
201 if (!isCastFree(Cast->getOpcode(), DstTy, SrcTy))
202 return false;
203
204 MatchInfo = [=](MachineIRBuilder &B) {
205 auto True = B.buildInstr(Cast->getOpcode(), {DstTy}, {TrueReg});
206 auto False = B.buildInstr(Cast->getOpcode(), {DstTy}, {FalseReg});
207 B.buildSelect(Dst, Cond, True, False);
208 };
209
210 return true;
211}
212
214 const MachineInstr &SecondMI,
215 BuildFnTy &MatchInfo) {
216 const GExtOp *First = cast<GExtOp>(&FirstMI);
217 const GExtOp *Second = cast<GExtOp>(&SecondMI);
218
219 Register Dst = First->getReg(0);
220 Register Src = Second->getSrcReg();
221 LLT DstTy = MRI.getType(Dst);
222 LLT SrcTy = MRI.getType(Src);
223
224 if (!MRI.hasOneNonDBGUse(Second->getReg(0)))
225 return false;
226
227 // ext of ext -> later ext
228 if (First->getOpcode() == Second->getOpcode() &&
229 isLegalOrBeforeLegalizer({Second->getOpcode(), {DstTy, SrcTy}})) {
230 if (Second->getOpcode() == TargetOpcode::G_ZEXT) {
234 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
235 return true;
236 }
237 // not zext -> no flags
238 MatchInfo = [=](MachineIRBuilder &B) {
239 B.buildInstr(Second->getOpcode(), {Dst}, {Src});
240 };
241 return true;
242 }
243
244 // anyext of sext/zext -> sext/zext
245 // -> pick anyext as second ext, then ext of ext
246 if (First->getOpcode() == TargetOpcode::G_ANYEXT &&
247 isLegalOrBeforeLegalizer({Second->getOpcode(), {DstTy, SrcTy}})) {
248 if (Second->getOpcode() == TargetOpcode::G_ZEXT) {
252 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
253 return true;
254 }
255 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
256 return true;
257 }
258
259 // sext/zext of anyext -> sext/zext
260 // -> pick anyext as first ext, then ext of ext
261 if (Second->getOpcode() == TargetOpcode::G_ANYEXT &&
262 isLegalOrBeforeLegalizer({First->getOpcode(), {DstTy, SrcTy}})) {
263 if (First->getOpcode() == TargetOpcode::G_ZEXT) {
267 MatchInfo = [=](MachineIRBuilder &B) { B.buildZExt(Dst, Src, Flag); };
268 return true;
269 }
270 MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); };
271 return true;
272 }
273
274 return false;
275}
276
278 const MachineInstr &BVMI,
279 BuildFnTy &MatchInfo) {
280 const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
281 const GBuildVector *BV = cast<GBuildVector>(&BVMI);
282
283 if (!MRI.hasOneNonDBGUse(BV->getReg(0)))
284 return false;
285
286 Register Dst = Cast->getReg(0);
287 // The type of the new build vector.
288 LLT DstTy = MRI.getType(Dst);
289 // The scalar or element type of the new build vector.
290 LLT ElemTy = DstTy.getScalarType();
291 // The scalar or element type of the old build vector.
292 LLT InputElemTy = MRI.getType(BV->getReg(0)).getElementType();
293
294 // Check legality of new build vector, the scalar casts, and profitability of
295 // the many casts.
297 {TargetOpcode::G_BUILD_VECTOR, {DstTy, ElemTy}}) ||
298 !isLegalOrBeforeLegalizer({Cast->getOpcode(), {ElemTy, InputElemTy}}) ||
299 !isCastFree(Cast->getOpcode(), ElemTy, InputElemTy))
300 return false;
301
302 MatchInfo = [=](MachineIRBuilder &B) {
304 unsigned Elements = BV->getNumSources();
305 for (unsigned I = 0; I < Elements; ++I) {
306 auto CastI =
307 B.buildInstr(Cast->getOpcode(), {ElemTy}, {BV->getSourceReg(I)});
308 Casts.push_back(CastI.getReg(0));
309 }
310
311 B.buildBuildVector(Dst, Casts);
312 };
313
314 return true;
315}
amdgpu AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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
bool matchSextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine sext of trunc.
const DataLayout & getDataLayout() const
const TargetLowering & getTargetLowering() const
LLVMContext & getContext() const
bool matchExtOfExt(const MachineInstr &FirstMI, const MachineInstr &SecondMI, BuildFnTy &MatchInfo)
bool matchCastOfSelect(const MachineInstr &Cast, const MachineInstr &SelectMI, BuildFnTy &MatchInfo)
MachineRegisterInfo & MRI
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchNonNegZext(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine zext nneg to sext.
bool matchZextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine zext of trunc.
bool matchTruncateOfExt(const MachineInstr &Root, const MachineInstr &ExtMI, BuildFnTy &MatchInfo)
Transform trunc ([asz]ext x) to x or ([asz]ext x) or (trunc x).
bool matchCastOfBuildVector(const MachineInstr &CastMI, const MachineInstr &BVMI, BuildFnTy &MatchInfo)
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:63
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:267
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
Definition: LowLevelType.h:290
constexpr LLT getScalarType() const
Definition: LowLevelType.h:208
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:569
bool getFlag(MIFlag Flag) const
Return whether an MI flag is set.
Definition: MachineInstr.h:396
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:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
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:486
std::function< void(MachineIRBuilder &)> BuildFnTy
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.