LLVM 19.0.0git
CombinerHelperVectorOps.cpp
Go to the documentation of this file.
1//===- CombinerHelperVectorOps.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_EXTRACT_VECTOR_ELT.
10//
11//===----------------------------------------------------------------------===//
25#include <optional>
26
27#define DEBUG_TYPE "gi-combiner"
28
29using namespace llvm;
30using namespace MIPatternMatch;
31
33 BuildFnTy &MatchInfo) {
34 GExtractVectorElement *Extract = cast<GExtractVectorElement>(&MI);
35
36 Register Dst = Extract->getReg(0);
37 Register Vector = Extract->getVectorReg();
38 Register Index = Extract->getIndexReg();
39 LLT DstTy = MRI.getType(Dst);
40 LLT VectorTy = MRI.getType(Vector);
41
42 // The vector register can be def'd by various ops that have vector as its
43 // type. They can all be used for constant folding, scalarizing,
44 // canonicalization, or combining based on symmetry.
45 //
46 // vector like ops
47 // * build vector
48 // * build vector trunc
49 // * shuffle vector
50 // * splat vector
51 // * concat vectors
52 // * insert/extract vector element
53 // * insert/extract subvector
54 // * vector loads
55 // * scalable vector loads
56 //
57 // compute like ops
58 // * binary ops
59 // * unary ops
60 // * exts and truncs
61 // * casts
62 // * fneg
63 // * select
64 // * phis
65 // * cmps
66 // * freeze
67 // * bitcast
68 // * undef
69
70 // We try to get the value of the Index register.
71 std::optional<ValueAndVReg> MaybeIndex =
73 std::optional<APInt> IndexC = std::nullopt;
74
75 if (MaybeIndex)
76 IndexC = MaybeIndex->Value;
77
78 // Fold extractVectorElement(Vector, TOOLARGE) -> undef
79 if (IndexC && VectorTy.isFixedVector() &&
80 IndexC->uge(VectorTy.getNumElements()) &&
81 isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) {
82 // For fixed-length vectors, it's invalid to extract out-of-range elements.
83 MatchInfo = [=](MachineIRBuilder &B) { B.buildUndef(Dst); };
84 return true;
85 }
86
87 return false;
88}
89
91 const MachineOperand &MO, BuildFnTy &MatchInfo) {
93 GExtractVectorElement *Extract = cast<GExtractVectorElement>(Root);
94
95 //
96 // %idx1:_(s64) = G_CONSTANT i64 1
97 // %idx2:_(s64) = G_CONSTANT i64 2
98 // %insert:_(<2 x s32>) = G_INSERT_VECTOR_ELT_ELT %bv(<2 x s32>),
99 // %value(s32), %idx2(s64) %extract:_(s32) = G_EXTRACT_VECTOR_ELT %insert(<2
100 // x s32>), %idx1(s64)
101 //
102 // -->
103 //
104 // %insert:_(<2 x s32>) = G_INSERT_VECTOR_ELT_ELT %bv(<2 x s32>),
105 // %value(s32), %idx2(s64) %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x
106 // s32>), %idx1(s64)
107 //
108 //
109
110 Register Index = Extract->getIndexReg();
111
112 // We try to get the value of the Index register.
113 std::optional<ValueAndVReg> MaybeIndex =
115 std::optional<APInt> IndexC = std::nullopt;
116
117 if (!MaybeIndex)
118 return false;
119 else
120 IndexC = MaybeIndex->Value;
121
122 Register Vector = Extract->getVectorReg();
123
124 GInsertVectorElement *Insert =
125 getOpcodeDef<GInsertVectorElement>(Vector, MRI);
126 if (!Insert)
127 return false;
128
129 Register Dst = Extract->getReg(0);
130
131 std::optional<ValueAndVReg> MaybeInsertIndex =
132 getIConstantVRegValWithLookThrough(Insert->getIndexReg(), MRI);
133
134 if (MaybeInsertIndex && MaybeInsertIndex->Value != *IndexC) {
135 // There is no one-use check. We have to keep the insert. When both Index
136 // registers are constants and not equal, we can look into the Vector
137 // register of the insert.
138 MatchInfo = [=](MachineIRBuilder &B) {
139 B.buildExtractVectorElement(Dst, Insert->getVectorReg(), Index);
140 };
141 return true;
142 }
143
144 return false;
145}
146
148 const MachineOperand &MO, BuildFnTy &MatchInfo) {
150 GExtractVectorElement *Extract = cast<GExtractVectorElement>(Root);
151
152 Register Vector = Extract->getVectorReg();
153
154 //
155 // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
156 // %freeze:_(<2 x s32>) = G_FREEZE %bv(<2 x s32>)
157 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
158 //
159 // -->
160 //
161 // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
162 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
163 // %freeze:_(s32) = G_FREEZE %extract(s32)
164 //
165 //
166
167 // For G_FREEZE, the input and the output types are identical. Moving the
168 // freeze from the Vector into the front of the extract preserves the freeze
169 // semantics. The result is still freeze'd. Furthermore, the Vector register
170 // becomes easier to analyze. A build vector could have been hidden behind the
171 // freeze.
172
173 // We expect a freeze on the Vector register.
174 GFreeze *Freeze = getOpcodeDef<GFreeze>(Vector, MRI);
175 if (!Freeze)
176 return false;
177
178 Register Dst = Extract->getReg(0);
179 LLT DstTy = MRI.getType(Dst);
180
181 // We first have to check for one-use and legality of the freeze.
182 // The type of the extractVectorElement did not change.
183 if (!MRI.hasOneNonDBGUse(Freeze->getReg(0)) ||
184 !isLegalOrBeforeLegalizer({TargetOpcode::G_FREEZE, {DstTy}}))
185 return false;
186
187 Register Index = Extract->getIndexReg();
188
189 // We move the freeze from the Vector register in front of the
190 // extractVectorElement.
191 MatchInfo = [=](MachineIRBuilder &B) {
192 auto Extract =
193 B.buildExtractVectorElement(DstTy, Freeze->getSourceReg(), Index);
194 B.buildFreeze(Dst, Extract);
195 };
196
197 return true;
198}
199
201 const MachineOperand &MO, BuildFnTy &MatchInfo) {
203 GExtractVectorElement *Extract = cast<GExtractVectorElement>(Root);
204
205 //
206 // %zero:_(s64) = G_CONSTANT i64 0
207 // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
208 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %zero(s64)
209 //
210 // -->
211 //
212 // %extract:_(32) = COPY %arg1(s32)
213 //
214 //
215 //
216 // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
217 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
218 //
219 // -->
220 //
221 // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
222 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
223 //
224
225 Register Vector = Extract->getVectorReg();
226
227 // We expect a buildVector on the Vector register.
228 GBuildVector *Build = getOpcodeDef<GBuildVector>(Vector, MRI);
229 if (!Build)
230 return false;
231
232 LLT VectorTy = MRI.getType(Vector);
233
234 // There is a one-use check. There are more combines on build vectors.
235 EVT Ty(getMVTForLLT(VectorTy));
236 if (!MRI.hasOneNonDBGUse(Build->getReg(0)) ||
237 !getTargetLowering().aggressivelyPreferBuildVectorSources(Ty))
238 return false;
239
240 Register Index = Extract->getIndexReg();
241
242 // If the Index is constant, then we can extract the element from the given
243 // offset.
244 std::optional<ValueAndVReg> MaybeIndex =
246 if (!MaybeIndex)
247 return false;
248
249 // We now know that there is a buildVector def'd on the Vector register and
250 // the index is const. The combine will succeed.
251
252 Register Dst = Extract->getReg(0);
253
254 MatchInfo = [=](MachineIRBuilder &B) {
255 B.buildCopy(Dst, Build->getSourceReg(MaybeIndex->Value.getZExtValue()));
256 };
257
258 return true;
259}
260
262 const MachineOperand &MO, BuildFnTy &MatchInfo) {
264 GExtractVectorElement *Extract = cast<GExtractVectorElement>(Root);
265
266 //
267 // %zero:_(s64) = G_CONSTANT i64 0
268 // %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64)
269 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %zero(s64)
270 //
271 // -->
272 //
273 // %extract:_(32) = G_TRUNC %arg1(s64)
274 //
275 //
276 //
277 // %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64)
278 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
279 //
280 // -->
281 //
282 // %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64)
283 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
284 //
285
286 Register Vector = Extract->getVectorReg();
287
288 // We expect a buildVectorTrunc on the Vector register.
289 GBuildVectorTrunc *Build = getOpcodeDef<GBuildVectorTrunc>(Vector, MRI);
290 if (!Build)
291 return false;
292
293 LLT VectorTy = MRI.getType(Vector);
294
295 // There is a one-use check. There are more combines on build vectors.
296 EVT Ty(getMVTForLLT(VectorTy));
297 if (!MRI.hasOneNonDBGUse(Build->getReg(0)) ||
298 !getTargetLowering().aggressivelyPreferBuildVectorSources(Ty))
299 return false;
300
301 Register Index = Extract->getIndexReg();
302
303 // If the Index is constant, then we can extract the element from the given
304 // offset.
305 std::optional<ValueAndVReg> MaybeIndex =
307 if (!MaybeIndex)
308 return false;
309
310 // We now know that there is a buildVectorTrunc def'd on the Vector register
311 // and the index is const. The combine will succeed.
312
313 Register Dst = Extract->getReg(0);
314 LLT DstTy = MRI.getType(Dst);
315 LLT SrcTy = MRI.getType(Build->getSourceReg(0));
316
317 // For buildVectorTrunc, the inputs are truncated.
318 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}}))
319 return false;
320
321 MatchInfo = [=](MachineIRBuilder &B) {
322 B.buildTrunc(Dst, Build->getSourceReg(MaybeIndex->Value.getZExtValue()));
323 };
324
325 return true;
326}
327
329 BuildFnTy &MatchInfo) {
330 GInsertVectorElement *Insert = cast<GInsertVectorElement>(&MI);
331
332 Register Dst = Insert->getReg(0);
333 LLT DstTy = MRI.getType(Dst);
334 Register Index = Insert->getIndexReg();
335
336 if (!DstTy.isFixedVector())
337 return false;
338
339 std::optional<ValueAndVReg> MaybeIndex =
341
342 if (MaybeIndex && MaybeIndex->Value.uge(DstTy.getNumElements()) &&
343 isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) {
344 MatchInfo = [=](MachineIRBuilder &B) { B.buildUndef(Dst); };
345 return true;
346 }
347
348 return false;
349}
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...
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
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.
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
This file describes how to lower LLVM code to machine code.
bool matchExtractVectorElementWithFreeze(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine extract vector element with freeze on the vector register.
bool matchExtractVectorElementWithDifferentIndices(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine extract vector element with a insert vector element on the vector register and different indi...
bool matchExtractVectorElementWithBuildVectorTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine extract vector element with a build vector trunc on the vector register.
const TargetLowering & getTargetLowering() const
bool matchInsertVectorElementOOB(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine insert vector element OOB.
MachineRegisterInfo & MRI
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
bool matchExtractVectorElementWithBuildVector(const MachineOperand &MO, BuildFnTy &MatchInfo)
Combine extract vector element with a build vector on the vector register.
bool matchExtractVectorElement(MachineInstr &MI, BuildFnTy &MatchInfo)
Combine extract vector element.
Represents a G_BUILD_VECTOR_TRUNC.
Represents a G_BUILD_VECTOR.
Represents an extract vector element.
Represents a freeze.
Register getSourceReg() const
Represents an insert vector element.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
Definition: LowLevelType.h:159
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
Definition: LowLevelType.h:178
Helper class to build MachineInstr.
Representation of each machine instruction.
Definition: MachineInstr.h:69
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.
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
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:467
std::function< void(MachineIRBuilder &)> BuildFnTy
std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition: Utils.cpp:415
Extended Value Type.
Definition: ValueTypes.h:34