LLVM 24.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// G_INSERT_VECTOR_ELT, and G_VSCALE
11//
12//===----------------------------------------------------------------------===//
26#include <optional>
27
28#define DEBUG_TYPE "gi-combiner"
29
30using namespace llvm;
31using namespace MIPatternMatch;
32
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 return true;
83
84 return false;
85}
86
88 const MachineOperand &MO, BuildFnTy &MatchInfo) const {
91
92 //
93 // %idx1:_(s64) = G_CONSTANT i64 1
94 // %idx2:_(s64) = G_CONSTANT i64 2
95 // %insert:_(<2 x s32>) = G_INSERT_VECTOR_ELT_ELT %bv(<2 x s32>),
96 // %value(s32), %idx2(s64) %extract:_(s32) = G_EXTRACT_VECTOR_ELT %insert(<2
97 // x s32>), %idx1(s64)
98 //
99 // -->
100 //
101 // %insert:_(<2 x s32>) = G_INSERT_VECTOR_ELT_ELT %bv(<2 x s32>),
102 // %value(s32), %idx2(s64) %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x
103 // s32>), %idx1(s64)
104 //
105 //
106
107 Register Index = Extract->getIndexReg();
108
109 // We try to get the value of the Index register.
110 std::optional<ValueAndVReg> MaybeIndex =
112 std::optional<APInt> IndexC = std::nullopt;
113
114 if (!MaybeIndex)
115 return false;
116 else
117 IndexC = MaybeIndex->Value;
118
119 Register Vector = Extract->getVectorReg();
120
121 GInsertVectorElement *Insert =
123 if (!Insert)
124 return false;
125
126 Register Dst = Extract->getReg(0);
127
128 std::optional<ValueAndVReg> MaybeInsertIndex =
129 getIConstantVRegValWithLookThrough(Insert->getIndexReg(), MRI);
130
131 if (MaybeInsertIndex && MaybeInsertIndex->Value != *IndexC) {
132 // There is no one-use check. We have to keep the insert. When both Index
133 // registers are constants and not equal, we can look into the Vector
134 // register of the insert.
135 MatchInfo = [=](MachineIRBuilder &B) {
136 B.buildExtractVectorElement(Dst, Insert->getVectorReg(), Index);
137 };
138 return true;
139 }
140
141 return false;
142}
143
145 const MachineInstr &MI, const MachineInstr &MI2,
146 BuildFnTy &MatchInfo) const {
148 const GBuildVector *Build = cast<GBuildVector>(&MI2);
149
150 //
151 // %zero:_(s64) = G_CONSTANT i64 0
152 // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
153 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %zero(s64)
154 //
155 // -->
156 //
157 // %extract:_(32) = COPY %arg1(s32)
158 //
159 //
160
161 Register Vector = Extract->getVectorReg();
162 LLT VectorTy = MRI.getType(Vector);
163
164 // There is a one-use check. There are more combines on build vectors.
165 EVT Ty(getMVTForLLT(VectorTy));
166 if (!MRI.hasOneNonDBGUse(Build->getReg(0)) ||
167 !getTargetLowering().aggressivelyPreferBuildVectorSources(Ty))
168 return false;
169
170 APInt Index = getIConstantFromReg(Extract->getIndexReg(), MRI);
171
172 // An out-of-bounds constant index extracts undef; it is handled by
173 // extract_vec_elt_out_of_bounds. Bail out here so we never read past the
174 // G_BUILD_VECTOR's sources.
175 if (Index.uge(Build->getNumSources()))
176 return false;
177
178 // We now know that there is a buildVector def'd on the Vector register and
179 // the index is const. The combine will succeed.
180
181 Register Dst = Extract->getReg(0);
182
183 MatchInfo = [=](MachineIRBuilder &B) {
184 B.buildCopy(Dst, Build->getSourceReg(Index.getZExtValue()));
185 };
186
187 return true;
188}
189
191 const MachineOperand &MO, BuildFnTy &MatchInfo) const {
194
195 //
196 // %zero:_(s64) = G_CONSTANT i64 0
197 // %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64)
198 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %zero(s64)
199 //
200 // -->
201 //
202 // %extract:_(32) = G_TRUNC %arg1(s64)
203 //
204 //
205 //
206 // %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64)
207 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
208 //
209 // -->
210 //
211 // %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64)
212 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
213 //
214
215 Register Vector = Extract->getVectorReg();
216
217 // We expect a buildVectorTrunc on the Vector register.
219 if (!Build)
220 return false;
221
222 LLT VectorTy = MRI.getType(Vector);
223
224 // There is a one-use check. There are more combines on build vectors.
225 EVT Ty(getMVTForLLT(VectorTy));
226 if (!MRI.hasOneNonDBGUse(Build->getReg(0)) ||
227 !getTargetLowering().aggressivelyPreferBuildVectorSources(Ty))
228 return false;
229
230 Register Index = Extract->getIndexReg();
231
232 // If the Index is constant, then we can extract the element from the given
233 // offset.
234 std::optional<ValueAndVReg> MaybeIndex =
236 if (!MaybeIndex)
237 return false;
238
239 // An out-of-bounds constant index extracts undef; it is handled by
240 // extract_vec_elt_out_of_bounds. Bail out so we never read past the
241 // G_BUILD_VECTOR_TRUNC's sources.
242 if (MaybeIndex->Value.uge(Build->getNumSources()))
243 return false;
244
245 // We now know that there is a buildVectorTrunc def'd on the Vector register
246 // and the index is const. The combine will succeed.
247
248 Register Dst = Extract->getReg(0);
249 LLT DstTy = MRI.getType(Dst);
250 LLT SrcTy = MRI.getType(Build->getSourceReg(0));
251
252 // For buildVectorTrunc, the inputs are truncated.
253 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}}))
254 return false;
255
256 MatchInfo = [=](MachineIRBuilder &B) {
257 B.buildTrunc(Dst, Build->getSourceReg(MaybeIndex->Value.getZExtValue()));
258 };
259
260 return true;
261}
262
264 const MachineInstr &MI, const MachineInstr &MI2,
265 BuildFnTy &MatchInfo) const {
267 const GShuffleVector *Shuffle = cast<GShuffleVector>(&MI2);
268
269 //
270 // %zero:_(s64) = G_CONSTANT i64 0
271 // %sv:_(<4 x s32>) = G_SHUFFLE_SHUFFLE %arg1(<4 x s32>), %arg2(<4 x s32>),
272 // shufflemask(0, 0, 0, 0)
273 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %sv(<4 x s32>), %zero(s64)
274 //
275 // -->
276 //
277 // %zero1:_(s64) = G_CONSTANT i64 0
278 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %arg1(<4 x s32>), %zero1(s64)
279 //
280 //
281 //
282 //
283 // %three:_(s64) = G_CONSTANT i64 3
284 // %sv:_(<4 x s32>) = G_SHUFFLE_SHUFFLE %arg1(<4 x s32>), %arg2(<4 x s32>),
285 // shufflemask(0, 0, 0, -1)
286 // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %sv(<4 x s32>), %three(s64)
287 //
288 // -->
289 //
290 // %extract:_(s32) = G_IMPLICIT_DEF
291 //
292 //
293
294 APInt Index = getIConstantFromReg(Extract->getIndexReg(), MRI);
295
296 ArrayRef<int> Mask = Shuffle->getMask();
297
298 unsigned Offset = Index.getZExtValue();
299 int SrcIdx = Mask[Offset];
300
301 LLT Src1Type = MRI.getType(Shuffle->getSrc1Reg());
302 // At the IR level a <1 x ty> shuffle vector is valid, but we want to extract
303 // from a vector.
304 assert(Src1Type.isVector() && "expected to extract from a vector");
305 unsigned LHSWidth = Src1Type.isVector() ? Src1Type.getNumElements() : 1;
306
307 // Note that there is no one use check.
308 Register Dst = Extract->getReg(0);
309 LLT DstTy = MRI.getType(Dst);
310
311 if (SrcIdx < 0 &&
312 isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) {
313 MatchInfo = [=](MachineIRBuilder &B) { B.buildUndef(Dst); };
314 return true;
315 }
316
317 // If the legality check failed, then we still have to abort.
318 if (SrcIdx < 0)
319 return false;
320
321 Register NewVector;
322
323 // We check in which vector and at what offset to look through.
324 if (SrcIdx < (int)LHSWidth) {
325 NewVector = Shuffle->getSrc1Reg();
326 // SrcIdx unchanged
327 } else { // SrcIdx >= LHSWidth
328 NewVector = Shuffle->getSrc2Reg();
329 SrcIdx -= LHSWidth;
330 }
331
332 LLT IdxTy = MRI.getType(Extract->getIndexReg());
333 LLT NewVectorTy = MRI.getType(NewVector);
334
335 // We check the legality of the look through.
337 {TargetOpcode::G_EXTRACT_VECTOR_ELT, {DstTy, NewVectorTy, IdxTy}}) ||
339 return false;
340
341 // We look through the shuffle vector.
342 MatchInfo = [=](MachineIRBuilder &B) {
343 auto Idx = B.buildConstant(IdxTy, SrcIdx);
344 B.buildExtractVectorElement(Dst, NewVector, Idx);
345 };
346
347 return true;
348}
349
352
353 Register Dst = Insert->getReg(0);
354 LLT DstTy = MRI.getType(Dst);
355 Register Index = Insert->getIndexReg();
356
357 if (!DstTy.isFixedVector())
358 return false;
359
360 std::optional<ValueAndVReg> MaybeIndex =
362
363 if (MaybeIndex && MaybeIndex->Value.uge(DstTy.getNumElements()) &&
364 isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}}))
365 return true;
366
367 return false;
368}
369
371 BuildFnTy &MatchInfo) const {
372 Register Dst = MO.getReg();
373 GVScale *LHSVScale, *RHSVScale;
374 if (!mi_match(Dst, MRI, m_GAdd(m_GVScale(LHSVScale), m_GVScale(RHSVScale))))
375 return false;
376
377 if (!MRI.hasOneNonDBGUse(LHSVScale->getReg(0)) ||
378 !MRI.hasOneNonDBGUse(RHSVScale->getReg(0)))
379 return false;
380
381 MatchInfo = [=](MachineIRBuilder &B) {
382 B.buildVScale(Dst, LHSVScale->getSrc() + RHSVScale->getSrc());
383 };
384
385 return true;
386}
387
389 BuildFnTy &MatchInfo) const {
390 Register Dst = MO.getReg();
391 GVScale *LHSVScale;
392 Register RHSReg;
393 if (!mi_match(Dst, MRI, m_GMul(m_GVScale(LHSVScale), m_Reg(RHSReg))))
394 return false;
395
396 std::optional<APInt> MaybeRHS = getIConstantVRegVal(RHSReg, MRI);
397 if (!MaybeRHS)
398 return false;
399
400 if (!MRI.hasOneNonDBGUse(LHSVScale->getReg(0)))
401 return false;
402
403 MatchInfo = [=](MachineIRBuilder &B) {
404 B.buildVScale(Dst, LHSVScale->getSrc() * *MaybeRHS);
405 };
406
407 return true;
408}
409
411 BuildFnTy &MatchInfo) const {
412 Register Dst = MO.getReg();
413 Register SubLHS;
414 GVScale *RHSVScale;
415 uint32_t Flags;
416 if (!mi_match(Dst, MRI,
417 m_GSub(m_Reg(SubLHS), m_GVScale(RHSVScale), m_MIFlags(Flags))))
418 return false;
419
420 LLT DstTy = MRI.getType(Dst);
421
422 if (!MRI.hasOneNonDBGUse(RHSVScale->getReg(0)) ||
423 !isLegalOrBeforeLegalizer({TargetOpcode::G_ADD, DstTy}))
424 return false;
425
426 MatchInfo = [=](MachineIRBuilder &B) {
427 auto VScale = B.buildVScale(DstTy, -RHSVScale->getSrc());
428 B.buildAdd(Dst, SubLHS, VScale, Flags);
429 };
430
431 return true;
432}
433
435 BuildFnTy &MatchInfo) const {
436 Register Dst = MO.getReg();
437 GVScale *LHSVScale;
438 Register ShiftReg;
439 if (!mi_match(Dst, MRI, m_GShl(m_GVScale(LHSVScale), m_Reg(ShiftReg))))
440 return false;
441
442 std::optional<APInt> MaybeRHS = getIConstantVRegVal(ShiftReg, MRI);
443 if (!MaybeRHS)
444 return false;
445
446 LLT DstTy = MRI.getType(Dst);
447
448 if (!MRI.hasOneNonDBGUse(LHSVScale->getReg(0)) ||
449 !isLegalOrBeforeLegalizer({TargetOpcode::G_VSCALE, DstTy}))
450 return false;
451
452 MatchInfo = [=](MachineIRBuilder &B) {
453 B.buildVScale(Dst, LHSVScale->getSrc().shl(*MaybeRHS));
454 };
455
456 return true;
457}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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.
Class for arbitrary precision integers.
Definition APInt.h:78
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:875
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
LLVM_ABI bool matchExtractVectorElementWithBuildVectorTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine extract vector element with a build vector trunc on the vector register.
LLVM_ABI const TargetLowering & getTargetLowering() const
LLVM_ABI bool matchExtractVectorElementWithDifferentIndices(const MachineOperand &MO, BuildFnTy &MatchInfo) const
Combine extract vector element with a insert vector element on the vector register and different indi...
LLVM_ABI bool matchMulOfVScale(const MachineOperand &MO, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchAddOfVScale(const MachineOperand &MO, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchShlOfVScale(const MachineOperand &MO, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchExtractVectorElementWithShuffleVector(const MachineInstr &MI, const MachineInstr &MI2, BuildFnTy &MatchInfo) const
Combine extract vector element with a shuffle vector on the vector register.
LLVM_ABI bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const
MachineRegisterInfo & MRI
LLVM_ABI bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
LLVM_ABI bool matchInsertVectorElementOOB(MachineInstr &MI) const
Combine insert vector element OOB.
LLVM_ABI bool matchSubOfVScale(const MachineOperand &MO, BuildFnTy &MatchInfo) const
LLVM_ABI bool matchExtractVectorElement(MachineInstr &MI) const
Combine extract vector element.
LLVM_ABI bool matchExtractVectorElementWithBuildVector(const MachineInstr &MI, const MachineInstr &MI2, BuildFnTy &MatchInfo) const
Combine extract vector element with a build vector on the vector register.
Represents a G_BUILD_VECTOR_TRUNC.
Represents a G_BUILD_VECTOR.
Represents an extract vector element.
Represents an insert vector element.
Register getSourceReg(unsigned I) const
Returns the I'th source register.
unsigned getNumSources() const
Returns the number of source registers.
Represents a G_SHUFFLE_VECTOR.
ArrayRef< int > getMask() const
Represents a vscale.
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.
constexpr bool isVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
Helper class to build MachineInstr.
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
operand_type_match m_Reg()
MIFlagsRef m_MIFlags(uint32_t &Flags)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
GInstrBind< GVScale > m_GVScale(GVScale *&Inst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_MUL, true > m_GMul(const LHS &L, const RHS &R)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
Definition Utils.cpp:656
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
Definition Utils.cpp:297
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
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI 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:436
Extended Value Type.
Definition ValueTypes.h:35