xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- CombinerHelperVectorOps.cpp-----------------------------------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // This file implements CombinerHelper for G_EXTRACT_VECTOR_ELT,
10*0fca6ea1SDimitry Andric // G_INSERT_VECTOR_ELT, and G_VSCALE
11*0fca6ea1SDimitry Andric //
12*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
13*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
14*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
15*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
16*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
17*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
18*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
19*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h"
20*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LowLevelTypeUtils.h"
21*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
22*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
23*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
24*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
25*0fca6ea1SDimitry Andric #include "llvm/Support/Casting.h"
26*0fca6ea1SDimitry Andric #include <optional>
27*0fca6ea1SDimitry Andric 
28*0fca6ea1SDimitry Andric #define DEBUG_TYPE "gi-combiner"
29*0fca6ea1SDimitry Andric 
30*0fca6ea1SDimitry Andric using namespace llvm;
31*0fca6ea1SDimitry Andric using namespace MIPatternMatch;
32*0fca6ea1SDimitry Andric 
33*0fca6ea1SDimitry Andric bool CombinerHelper::matchExtractVectorElement(MachineInstr &MI,
34*0fca6ea1SDimitry Andric                                                BuildFnTy &MatchInfo) {
35*0fca6ea1SDimitry Andric   GExtractVectorElement *Extract = cast<GExtractVectorElement>(&MI);
36*0fca6ea1SDimitry Andric 
37*0fca6ea1SDimitry Andric   Register Dst = Extract->getReg(0);
38*0fca6ea1SDimitry Andric   Register Vector = Extract->getVectorReg();
39*0fca6ea1SDimitry Andric   Register Index = Extract->getIndexReg();
40*0fca6ea1SDimitry Andric   LLT DstTy = MRI.getType(Dst);
41*0fca6ea1SDimitry Andric   LLT VectorTy = MRI.getType(Vector);
42*0fca6ea1SDimitry Andric 
43*0fca6ea1SDimitry Andric   // The vector register can be def'd by various ops that have vector as its
44*0fca6ea1SDimitry Andric   // type. They can all be used for constant folding, scalarizing,
45*0fca6ea1SDimitry Andric   // canonicalization, or combining based on symmetry.
46*0fca6ea1SDimitry Andric   //
47*0fca6ea1SDimitry Andric   // vector like ops
48*0fca6ea1SDimitry Andric   // * build vector
49*0fca6ea1SDimitry Andric   // * build vector trunc
50*0fca6ea1SDimitry Andric   // * shuffle vector
51*0fca6ea1SDimitry Andric   // * splat vector
52*0fca6ea1SDimitry Andric   // * concat vectors
53*0fca6ea1SDimitry Andric   // * insert/extract vector element
54*0fca6ea1SDimitry Andric   // * insert/extract subvector
55*0fca6ea1SDimitry Andric   // * vector loads
56*0fca6ea1SDimitry Andric   // * scalable vector loads
57*0fca6ea1SDimitry Andric   //
58*0fca6ea1SDimitry Andric   // compute like ops
59*0fca6ea1SDimitry Andric   // * binary ops
60*0fca6ea1SDimitry Andric   // * unary ops
61*0fca6ea1SDimitry Andric   //  * exts and truncs
62*0fca6ea1SDimitry Andric   //  * casts
63*0fca6ea1SDimitry Andric   //  * fneg
64*0fca6ea1SDimitry Andric   // * select
65*0fca6ea1SDimitry Andric   // * phis
66*0fca6ea1SDimitry Andric   // * cmps
67*0fca6ea1SDimitry Andric   // * freeze
68*0fca6ea1SDimitry Andric   // * bitcast
69*0fca6ea1SDimitry Andric   // * undef
70*0fca6ea1SDimitry Andric 
71*0fca6ea1SDimitry Andric   // We try to get the value of the Index register.
72*0fca6ea1SDimitry Andric   std::optional<ValueAndVReg> MaybeIndex =
73*0fca6ea1SDimitry Andric       getIConstantVRegValWithLookThrough(Index, MRI);
74*0fca6ea1SDimitry Andric   std::optional<APInt> IndexC = std::nullopt;
75*0fca6ea1SDimitry Andric 
76*0fca6ea1SDimitry Andric   if (MaybeIndex)
77*0fca6ea1SDimitry Andric     IndexC = MaybeIndex->Value;
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric   // Fold extractVectorElement(Vector, TOOLARGE) -> undef
80*0fca6ea1SDimitry Andric   if (IndexC && VectorTy.isFixedVector() &&
81*0fca6ea1SDimitry Andric       IndexC->uge(VectorTy.getNumElements()) &&
82*0fca6ea1SDimitry Andric       isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) {
83*0fca6ea1SDimitry Andric     // For fixed-length vectors, it's invalid to extract out-of-range elements.
84*0fca6ea1SDimitry Andric     MatchInfo = [=](MachineIRBuilder &B) { B.buildUndef(Dst); };
85*0fca6ea1SDimitry Andric     return true;
86*0fca6ea1SDimitry Andric   }
87*0fca6ea1SDimitry Andric 
88*0fca6ea1SDimitry Andric   return false;
89*0fca6ea1SDimitry Andric }
90*0fca6ea1SDimitry Andric 
91*0fca6ea1SDimitry Andric bool CombinerHelper::matchExtractVectorElementWithDifferentIndices(
92*0fca6ea1SDimitry Andric     const MachineOperand &MO, BuildFnTy &MatchInfo) {
93*0fca6ea1SDimitry Andric   MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI);
94*0fca6ea1SDimitry Andric   GExtractVectorElement *Extract = cast<GExtractVectorElement>(Root);
95*0fca6ea1SDimitry Andric 
96*0fca6ea1SDimitry Andric   //
97*0fca6ea1SDimitry Andric   //  %idx1:_(s64) = G_CONSTANT i64 1
98*0fca6ea1SDimitry Andric   //  %idx2:_(s64) = G_CONSTANT i64 2
99*0fca6ea1SDimitry Andric   //  %insert:_(<2 x s32>) = G_INSERT_VECTOR_ELT_ELT %bv(<2 x s32>),
100*0fca6ea1SDimitry Andric   //  %value(s32), %idx2(s64) %extract:_(s32) = G_EXTRACT_VECTOR_ELT %insert(<2
101*0fca6ea1SDimitry Andric   //  x s32>), %idx1(s64)
102*0fca6ea1SDimitry Andric   //
103*0fca6ea1SDimitry Andric   //  -->
104*0fca6ea1SDimitry Andric   //
105*0fca6ea1SDimitry Andric   //  %insert:_(<2 x s32>) = G_INSERT_VECTOR_ELT_ELT %bv(<2 x s32>),
106*0fca6ea1SDimitry Andric   //  %value(s32), %idx2(s64) %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x
107*0fca6ea1SDimitry Andric   //  s32>), %idx1(s64)
108*0fca6ea1SDimitry Andric   //
109*0fca6ea1SDimitry Andric   //
110*0fca6ea1SDimitry Andric 
111*0fca6ea1SDimitry Andric   Register Index = Extract->getIndexReg();
112*0fca6ea1SDimitry Andric 
113*0fca6ea1SDimitry Andric   // We try to get the value of the Index register.
114*0fca6ea1SDimitry Andric   std::optional<ValueAndVReg> MaybeIndex =
115*0fca6ea1SDimitry Andric       getIConstantVRegValWithLookThrough(Index, MRI);
116*0fca6ea1SDimitry Andric   std::optional<APInt> IndexC = std::nullopt;
117*0fca6ea1SDimitry Andric 
118*0fca6ea1SDimitry Andric   if (!MaybeIndex)
119*0fca6ea1SDimitry Andric     return false;
120*0fca6ea1SDimitry Andric   else
121*0fca6ea1SDimitry Andric     IndexC = MaybeIndex->Value;
122*0fca6ea1SDimitry Andric 
123*0fca6ea1SDimitry Andric   Register Vector = Extract->getVectorReg();
124*0fca6ea1SDimitry Andric 
125*0fca6ea1SDimitry Andric   GInsertVectorElement *Insert =
126*0fca6ea1SDimitry Andric       getOpcodeDef<GInsertVectorElement>(Vector, MRI);
127*0fca6ea1SDimitry Andric   if (!Insert)
128*0fca6ea1SDimitry Andric     return false;
129*0fca6ea1SDimitry Andric 
130*0fca6ea1SDimitry Andric   Register Dst = Extract->getReg(0);
131*0fca6ea1SDimitry Andric 
132*0fca6ea1SDimitry Andric   std::optional<ValueAndVReg> MaybeInsertIndex =
133*0fca6ea1SDimitry Andric       getIConstantVRegValWithLookThrough(Insert->getIndexReg(), MRI);
134*0fca6ea1SDimitry Andric 
135*0fca6ea1SDimitry Andric   if (MaybeInsertIndex && MaybeInsertIndex->Value != *IndexC) {
136*0fca6ea1SDimitry Andric     // There is no one-use check. We have to keep the insert. When both Index
137*0fca6ea1SDimitry Andric     // registers are constants and not equal, we can look into the Vector
138*0fca6ea1SDimitry Andric     // register of the insert.
139*0fca6ea1SDimitry Andric     MatchInfo = [=](MachineIRBuilder &B) {
140*0fca6ea1SDimitry Andric       B.buildExtractVectorElement(Dst, Insert->getVectorReg(), Index);
141*0fca6ea1SDimitry Andric     };
142*0fca6ea1SDimitry Andric     return true;
143*0fca6ea1SDimitry Andric   }
144*0fca6ea1SDimitry Andric 
145*0fca6ea1SDimitry Andric   return false;
146*0fca6ea1SDimitry Andric }
147*0fca6ea1SDimitry Andric 
148*0fca6ea1SDimitry Andric bool CombinerHelper::matchExtractVectorElementWithBuildVector(
149*0fca6ea1SDimitry Andric     const MachineOperand &MO, BuildFnTy &MatchInfo) {
150*0fca6ea1SDimitry Andric   MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI);
151*0fca6ea1SDimitry Andric   GExtractVectorElement *Extract = cast<GExtractVectorElement>(Root);
152*0fca6ea1SDimitry Andric 
153*0fca6ea1SDimitry Andric   //
154*0fca6ea1SDimitry Andric   //  %zero:_(s64) = G_CONSTANT i64 0
155*0fca6ea1SDimitry Andric   //  %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
156*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %zero(s64)
157*0fca6ea1SDimitry Andric   //
158*0fca6ea1SDimitry Andric   //  -->
159*0fca6ea1SDimitry Andric   //
160*0fca6ea1SDimitry Andric   //  %extract:_(32) = COPY %arg1(s32)
161*0fca6ea1SDimitry Andric   //
162*0fca6ea1SDimitry Andric   //
163*0fca6ea1SDimitry Andric   //
164*0fca6ea1SDimitry Andric   //  %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
165*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
166*0fca6ea1SDimitry Andric   //
167*0fca6ea1SDimitry Andric   //  -->
168*0fca6ea1SDimitry Andric   //
169*0fca6ea1SDimitry Andric   //  %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
170*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
171*0fca6ea1SDimitry Andric   //
172*0fca6ea1SDimitry Andric 
173*0fca6ea1SDimitry Andric   Register Vector = Extract->getVectorReg();
174*0fca6ea1SDimitry Andric 
175*0fca6ea1SDimitry Andric   // We expect a buildVector on the Vector register.
176*0fca6ea1SDimitry Andric   GBuildVector *Build = getOpcodeDef<GBuildVector>(Vector, MRI);
177*0fca6ea1SDimitry Andric   if (!Build)
178*0fca6ea1SDimitry Andric     return false;
179*0fca6ea1SDimitry Andric 
180*0fca6ea1SDimitry Andric   LLT VectorTy = MRI.getType(Vector);
181*0fca6ea1SDimitry Andric 
182*0fca6ea1SDimitry Andric   // There is a one-use check. There are more combines on build vectors.
183*0fca6ea1SDimitry Andric   EVT Ty(getMVTForLLT(VectorTy));
184*0fca6ea1SDimitry Andric   if (!MRI.hasOneNonDBGUse(Build->getReg(0)) ||
185*0fca6ea1SDimitry Andric       !getTargetLowering().aggressivelyPreferBuildVectorSources(Ty))
186*0fca6ea1SDimitry Andric     return false;
187*0fca6ea1SDimitry Andric 
188*0fca6ea1SDimitry Andric   Register Index = Extract->getIndexReg();
189*0fca6ea1SDimitry Andric 
190*0fca6ea1SDimitry Andric   // If the Index is constant, then we can extract the element from the given
191*0fca6ea1SDimitry Andric   // offset.
192*0fca6ea1SDimitry Andric   std::optional<ValueAndVReg> MaybeIndex =
193*0fca6ea1SDimitry Andric       getIConstantVRegValWithLookThrough(Index, MRI);
194*0fca6ea1SDimitry Andric   if (!MaybeIndex)
195*0fca6ea1SDimitry Andric     return false;
196*0fca6ea1SDimitry Andric 
197*0fca6ea1SDimitry Andric   // We now know that there is a buildVector def'd on the Vector register and
198*0fca6ea1SDimitry Andric   // the index is const. The combine will succeed.
199*0fca6ea1SDimitry Andric 
200*0fca6ea1SDimitry Andric   Register Dst = Extract->getReg(0);
201*0fca6ea1SDimitry Andric 
202*0fca6ea1SDimitry Andric   MatchInfo = [=](MachineIRBuilder &B) {
203*0fca6ea1SDimitry Andric     B.buildCopy(Dst, Build->getSourceReg(MaybeIndex->Value.getZExtValue()));
204*0fca6ea1SDimitry Andric   };
205*0fca6ea1SDimitry Andric 
206*0fca6ea1SDimitry Andric   return true;
207*0fca6ea1SDimitry Andric }
208*0fca6ea1SDimitry Andric 
209*0fca6ea1SDimitry Andric bool CombinerHelper::matchExtractVectorElementWithBuildVectorTrunc(
210*0fca6ea1SDimitry Andric     const MachineOperand &MO, BuildFnTy &MatchInfo) {
211*0fca6ea1SDimitry Andric   MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI);
212*0fca6ea1SDimitry Andric   GExtractVectorElement *Extract = cast<GExtractVectorElement>(Root);
213*0fca6ea1SDimitry Andric 
214*0fca6ea1SDimitry Andric   //
215*0fca6ea1SDimitry Andric   //  %zero:_(s64) = G_CONSTANT i64 0
216*0fca6ea1SDimitry Andric   //  %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64)
217*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %zero(s64)
218*0fca6ea1SDimitry Andric   //
219*0fca6ea1SDimitry Andric   //  -->
220*0fca6ea1SDimitry Andric   //
221*0fca6ea1SDimitry Andric   //  %extract:_(32) = G_TRUNC %arg1(s64)
222*0fca6ea1SDimitry Andric   //
223*0fca6ea1SDimitry Andric   //
224*0fca6ea1SDimitry Andric   //
225*0fca6ea1SDimitry Andric   //  %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64)
226*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
227*0fca6ea1SDimitry Andric   //
228*0fca6ea1SDimitry Andric   //  -->
229*0fca6ea1SDimitry Andric   //
230*0fca6ea1SDimitry Andric   //  %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64)
231*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
232*0fca6ea1SDimitry Andric   //
233*0fca6ea1SDimitry Andric 
234*0fca6ea1SDimitry Andric   Register Vector = Extract->getVectorReg();
235*0fca6ea1SDimitry Andric 
236*0fca6ea1SDimitry Andric   // We expect a buildVectorTrunc on the Vector register.
237*0fca6ea1SDimitry Andric   GBuildVectorTrunc *Build = getOpcodeDef<GBuildVectorTrunc>(Vector, MRI);
238*0fca6ea1SDimitry Andric   if (!Build)
239*0fca6ea1SDimitry Andric     return false;
240*0fca6ea1SDimitry Andric 
241*0fca6ea1SDimitry Andric   LLT VectorTy = MRI.getType(Vector);
242*0fca6ea1SDimitry Andric 
243*0fca6ea1SDimitry Andric   // There is a one-use check. There are more combines on build vectors.
244*0fca6ea1SDimitry Andric   EVT Ty(getMVTForLLT(VectorTy));
245*0fca6ea1SDimitry Andric   if (!MRI.hasOneNonDBGUse(Build->getReg(0)) ||
246*0fca6ea1SDimitry Andric       !getTargetLowering().aggressivelyPreferBuildVectorSources(Ty))
247*0fca6ea1SDimitry Andric     return false;
248*0fca6ea1SDimitry Andric 
249*0fca6ea1SDimitry Andric   Register Index = Extract->getIndexReg();
250*0fca6ea1SDimitry Andric 
251*0fca6ea1SDimitry Andric   // If the Index is constant, then we can extract the element from the given
252*0fca6ea1SDimitry Andric   // offset.
253*0fca6ea1SDimitry Andric   std::optional<ValueAndVReg> MaybeIndex =
254*0fca6ea1SDimitry Andric       getIConstantVRegValWithLookThrough(Index, MRI);
255*0fca6ea1SDimitry Andric   if (!MaybeIndex)
256*0fca6ea1SDimitry Andric     return false;
257*0fca6ea1SDimitry Andric 
258*0fca6ea1SDimitry Andric   // We now know that there is a buildVectorTrunc def'd on the Vector register
259*0fca6ea1SDimitry Andric   // and the index is const. The combine will succeed.
260*0fca6ea1SDimitry Andric 
261*0fca6ea1SDimitry Andric   Register Dst = Extract->getReg(0);
262*0fca6ea1SDimitry Andric   LLT DstTy = MRI.getType(Dst);
263*0fca6ea1SDimitry Andric   LLT SrcTy = MRI.getType(Build->getSourceReg(0));
264*0fca6ea1SDimitry Andric 
265*0fca6ea1SDimitry Andric   // For buildVectorTrunc, the inputs are truncated.
266*0fca6ea1SDimitry Andric   if (!isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}}))
267*0fca6ea1SDimitry Andric     return false;
268*0fca6ea1SDimitry Andric 
269*0fca6ea1SDimitry Andric   MatchInfo = [=](MachineIRBuilder &B) {
270*0fca6ea1SDimitry Andric     B.buildTrunc(Dst, Build->getSourceReg(MaybeIndex->Value.getZExtValue()));
271*0fca6ea1SDimitry Andric   };
272*0fca6ea1SDimitry Andric 
273*0fca6ea1SDimitry Andric   return true;
274*0fca6ea1SDimitry Andric }
275*0fca6ea1SDimitry Andric 
276*0fca6ea1SDimitry Andric bool CombinerHelper::matchExtractVectorElementWithShuffleVector(
277*0fca6ea1SDimitry Andric     const MachineOperand &MO, BuildFnTy &MatchInfo) {
278*0fca6ea1SDimitry Andric   GExtractVectorElement *Extract =
279*0fca6ea1SDimitry Andric       cast<GExtractVectorElement>(getDefIgnoringCopies(MO.getReg(), MRI));
280*0fca6ea1SDimitry Andric 
281*0fca6ea1SDimitry Andric   //
282*0fca6ea1SDimitry Andric   //  %zero:_(s64) = G_CONSTANT i64 0
283*0fca6ea1SDimitry Andric   //  %sv:_(<4 x s32>) = G_SHUFFLE_SHUFFLE %arg1(<4 x s32>), %arg2(<4 x s32>),
284*0fca6ea1SDimitry Andric   //                     shufflemask(0, 0, 0, 0)
285*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %sv(<4 x s32>), %zero(s64)
286*0fca6ea1SDimitry Andric   //
287*0fca6ea1SDimitry Andric   //  -->
288*0fca6ea1SDimitry Andric   //
289*0fca6ea1SDimitry Andric   //  %zero1:_(s64) = G_CONSTANT i64 0
290*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %arg1(<4 x s32>), %zero1(s64)
291*0fca6ea1SDimitry Andric   //
292*0fca6ea1SDimitry Andric   //
293*0fca6ea1SDimitry Andric   //
294*0fca6ea1SDimitry Andric   //
295*0fca6ea1SDimitry Andric   //  %three:_(s64) = G_CONSTANT i64 3
296*0fca6ea1SDimitry Andric   //  %sv:_(<4 x s32>) = G_SHUFFLE_SHUFFLE %arg1(<4 x s32>), %arg2(<4 x s32>),
297*0fca6ea1SDimitry Andric   //                     shufflemask(0, 0, 0, -1)
298*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %sv(<4 x s32>), %three(s64)
299*0fca6ea1SDimitry Andric   //
300*0fca6ea1SDimitry Andric   //  -->
301*0fca6ea1SDimitry Andric   //
302*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_IMPLICIT_DEF
303*0fca6ea1SDimitry Andric   //
304*0fca6ea1SDimitry Andric   //
305*0fca6ea1SDimitry Andric   //
306*0fca6ea1SDimitry Andric   //
307*0fca6ea1SDimitry Andric   //
308*0fca6ea1SDimitry Andric   //  %sv:_(<4 x s32>) = G_SHUFFLE_SHUFFLE %arg1(<4 x s32>), %arg2(<4 x s32>),
309*0fca6ea1SDimitry Andric   //                     shufflemask(0, 0, 0, -1)
310*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %sv(<4 x s32>), %opaque(s64)
311*0fca6ea1SDimitry Andric   //
312*0fca6ea1SDimitry Andric   //  -->
313*0fca6ea1SDimitry Andric   //
314*0fca6ea1SDimitry Andric   //  %sv:_(<4 x s32>) = G_SHUFFLE_SHUFFLE %arg1(<4 x s32>), %arg2(<4 x s32>),
315*0fca6ea1SDimitry Andric   //                     shufflemask(0, 0, 0, -1)
316*0fca6ea1SDimitry Andric   //  %extract:_(s32) = G_EXTRACT_VECTOR_ELT %sv(<4 x s32>), %opaque(s64)
317*0fca6ea1SDimitry Andric   //
318*0fca6ea1SDimitry Andric 
319*0fca6ea1SDimitry Andric   // We try to get the value of the Index register.
320*0fca6ea1SDimitry Andric   std::optional<ValueAndVReg> MaybeIndex =
321*0fca6ea1SDimitry Andric       getIConstantVRegValWithLookThrough(Extract->getIndexReg(), MRI);
322*0fca6ea1SDimitry Andric   if (!MaybeIndex)
323*0fca6ea1SDimitry Andric     return false;
324*0fca6ea1SDimitry Andric 
325*0fca6ea1SDimitry Andric   GShuffleVector *Shuffle =
326*0fca6ea1SDimitry Andric       cast<GShuffleVector>(getDefIgnoringCopies(Extract->getVectorReg(), MRI));
327*0fca6ea1SDimitry Andric 
328*0fca6ea1SDimitry Andric   ArrayRef<int> Mask = Shuffle->getMask();
329*0fca6ea1SDimitry Andric 
330*0fca6ea1SDimitry Andric   unsigned Offset = MaybeIndex->Value.getZExtValue();
331*0fca6ea1SDimitry Andric   int SrcIdx = Mask[Offset];
332*0fca6ea1SDimitry Andric 
333*0fca6ea1SDimitry Andric   LLT Src1Type = MRI.getType(Shuffle->getSrc1Reg());
334*0fca6ea1SDimitry Andric   // At the IR level a <1 x ty> shuffle  vector is valid, but we want to extract
335*0fca6ea1SDimitry Andric   // from a vector.
336*0fca6ea1SDimitry Andric   assert(Src1Type.isVector() && "expected to extract from a vector");
337*0fca6ea1SDimitry Andric   unsigned LHSWidth = Src1Type.isVector() ? Src1Type.getNumElements() : 1;
338*0fca6ea1SDimitry Andric 
339*0fca6ea1SDimitry Andric   // Note that there is no one use check.
340*0fca6ea1SDimitry Andric   Register Dst = Extract->getReg(0);
341*0fca6ea1SDimitry Andric   LLT DstTy = MRI.getType(Dst);
342*0fca6ea1SDimitry Andric 
343*0fca6ea1SDimitry Andric   if (SrcIdx < 0 &&
344*0fca6ea1SDimitry Andric       isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) {
345*0fca6ea1SDimitry Andric     MatchInfo = [=](MachineIRBuilder &B) { B.buildUndef(Dst); };
346*0fca6ea1SDimitry Andric     return true;
347*0fca6ea1SDimitry Andric   }
348*0fca6ea1SDimitry Andric 
349*0fca6ea1SDimitry Andric   // If the legality check failed, then we still have to abort.
350*0fca6ea1SDimitry Andric   if (SrcIdx < 0)
351*0fca6ea1SDimitry Andric     return false;
352*0fca6ea1SDimitry Andric 
353*0fca6ea1SDimitry Andric   Register NewVector;
354*0fca6ea1SDimitry Andric 
355*0fca6ea1SDimitry Andric   // We check in which vector and at what offset to look through.
356*0fca6ea1SDimitry Andric   if (SrcIdx < (int)LHSWidth) {
357*0fca6ea1SDimitry Andric     NewVector = Shuffle->getSrc1Reg();
358*0fca6ea1SDimitry Andric     // SrcIdx unchanged
359*0fca6ea1SDimitry Andric   } else { // SrcIdx >= LHSWidth
360*0fca6ea1SDimitry Andric     NewVector = Shuffle->getSrc2Reg();
361*0fca6ea1SDimitry Andric     SrcIdx -= LHSWidth;
362*0fca6ea1SDimitry Andric   }
363*0fca6ea1SDimitry Andric 
364*0fca6ea1SDimitry Andric   LLT IdxTy = MRI.getType(Extract->getIndexReg());
365*0fca6ea1SDimitry Andric   LLT NewVectorTy = MRI.getType(NewVector);
366*0fca6ea1SDimitry Andric 
367*0fca6ea1SDimitry Andric   // We check the legality of the look through.
368*0fca6ea1SDimitry Andric   if (!isLegalOrBeforeLegalizer(
369*0fca6ea1SDimitry Andric           {TargetOpcode::G_EXTRACT_VECTOR_ELT, {DstTy, NewVectorTy, IdxTy}}) ||
370*0fca6ea1SDimitry Andric       !isConstantLegalOrBeforeLegalizer({IdxTy}))
371*0fca6ea1SDimitry Andric     return false;
372*0fca6ea1SDimitry Andric 
373*0fca6ea1SDimitry Andric   // We look through the shuffle vector.
374*0fca6ea1SDimitry Andric   MatchInfo = [=](MachineIRBuilder &B) {
375*0fca6ea1SDimitry Andric     auto Idx = B.buildConstant(IdxTy, SrcIdx);
376*0fca6ea1SDimitry Andric     B.buildExtractVectorElement(Dst, NewVector, Idx);
377*0fca6ea1SDimitry Andric   };
378*0fca6ea1SDimitry Andric 
379*0fca6ea1SDimitry Andric   return true;
380*0fca6ea1SDimitry Andric }
381*0fca6ea1SDimitry Andric 
382*0fca6ea1SDimitry Andric bool CombinerHelper::matchInsertVectorElementOOB(MachineInstr &MI,
383*0fca6ea1SDimitry Andric                                                  BuildFnTy &MatchInfo) {
384*0fca6ea1SDimitry Andric   GInsertVectorElement *Insert = cast<GInsertVectorElement>(&MI);
385*0fca6ea1SDimitry Andric 
386*0fca6ea1SDimitry Andric   Register Dst = Insert->getReg(0);
387*0fca6ea1SDimitry Andric   LLT DstTy = MRI.getType(Dst);
388*0fca6ea1SDimitry Andric   Register Index = Insert->getIndexReg();
389*0fca6ea1SDimitry Andric 
390*0fca6ea1SDimitry Andric   if (!DstTy.isFixedVector())
391*0fca6ea1SDimitry Andric     return false;
392*0fca6ea1SDimitry Andric 
393*0fca6ea1SDimitry Andric   std::optional<ValueAndVReg> MaybeIndex =
394*0fca6ea1SDimitry Andric       getIConstantVRegValWithLookThrough(Index, MRI);
395*0fca6ea1SDimitry Andric 
396*0fca6ea1SDimitry Andric   if (MaybeIndex && MaybeIndex->Value.uge(DstTy.getNumElements()) &&
397*0fca6ea1SDimitry Andric       isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) {
398*0fca6ea1SDimitry Andric     MatchInfo = [=](MachineIRBuilder &B) { B.buildUndef(Dst); };
399*0fca6ea1SDimitry Andric     return true;
400*0fca6ea1SDimitry Andric   }
401*0fca6ea1SDimitry Andric 
402*0fca6ea1SDimitry Andric   return false;
403*0fca6ea1SDimitry Andric }
404*0fca6ea1SDimitry Andric 
405*0fca6ea1SDimitry Andric bool CombinerHelper::matchAddOfVScale(const MachineOperand &MO,
406*0fca6ea1SDimitry Andric                                       BuildFnTy &MatchInfo) {
407*0fca6ea1SDimitry Andric   GAdd *Add = cast<GAdd>(MRI.getVRegDef(MO.getReg()));
408*0fca6ea1SDimitry Andric   GVScale *LHSVScale = cast<GVScale>(MRI.getVRegDef(Add->getLHSReg()));
409*0fca6ea1SDimitry Andric   GVScale *RHSVScale = cast<GVScale>(MRI.getVRegDef(Add->getRHSReg()));
410*0fca6ea1SDimitry Andric 
411*0fca6ea1SDimitry Andric   Register Dst = Add->getReg(0);
412*0fca6ea1SDimitry Andric 
413*0fca6ea1SDimitry Andric   if (!MRI.hasOneNonDBGUse(LHSVScale->getReg(0)) ||
414*0fca6ea1SDimitry Andric       !MRI.hasOneNonDBGUse(RHSVScale->getReg(0)))
415*0fca6ea1SDimitry Andric     return false;
416*0fca6ea1SDimitry Andric 
417*0fca6ea1SDimitry Andric   MatchInfo = [=](MachineIRBuilder &B) {
418*0fca6ea1SDimitry Andric     B.buildVScale(Dst, LHSVScale->getSrc() + RHSVScale->getSrc());
419*0fca6ea1SDimitry Andric   };
420*0fca6ea1SDimitry Andric 
421*0fca6ea1SDimitry Andric   return true;
422*0fca6ea1SDimitry Andric }
423*0fca6ea1SDimitry Andric 
424*0fca6ea1SDimitry Andric bool CombinerHelper::matchMulOfVScale(const MachineOperand &MO,
425*0fca6ea1SDimitry Andric                                       BuildFnTy &MatchInfo) {
426*0fca6ea1SDimitry Andric   GMul *Mul = cast<GMul>(MRI.getVRegDef(MO.getReg()));
427*0fca6ea1SDimitry Andric   GVScale *LHSVScale = cast<GVScale>(MRI.getVRegDef(Mul->getLHSReg()));
428*0fca6ea1SDimitry Andric 
429*0fca6ea1SDimitry Andric   std::optional<APInt> MaybeRHS = getIConstantVRegVal(Mul->getRHSReg(), MRI);
430*0fca6ea1SDimitry Andric   if (!MaybeRHS)
431*0fca6ea1SDimitry Andric     return false;
432*0fca6ea1SDimitry Andric 
433*0fca6ea1SDimitry Andric   Register Dst = MO.getReg();
434*0fca6ea1SDimitry Andric 
435*0fca6ea1SDimitry Andric   if (!MRI.hasOneNonDBGUse(LHSVScale->getReg(0)))
436*0fca6ea1SDimitry Andric     return false;
437*0fca6ea1SDimitry Andric 
438*0fca6ea1SDimitry Andric   MatchInfo = [=](MachineIRBuilder &B) {
439*0fca6ea1SDimitry Andric     B.buildVScale(Dst, LHSVScale->getSrc() * *MaybeRHS);
440*0fca6ea1SDimitry Andric   };
441*0fca6ea1SDimitry Andric 
442*0fca6ea1SDimitry Andric   return true;
443*0fca6ea1SDimitry Andric }
444*0fca6ea1SDimitry Andric 
445*0fca6ea1SDimitry Andric bool CombinerHelper::matchSubOfVScale(const MachineOperand &MO,
446*0fca6ea1SDimitry Andric                                       BuildFnTy &MatchInfo) {
447*0fca6ea1SDimitry Andric   GSub *Sub = cast<GSub>(MRI.getVRegDef(MO.getReg()));
448*0fca6ea1SDimitry Andric   GVScale *RHSVScale = cast<GVScale>(MRI.getVRegDef(Sub->getRHSReg()));
449*0fca6ea1SDimitry Andric 
450*0fca6ea1SDimitry Andric   Register Dst = MO.getReg();
451*0fca6ea1SDimitry Andric   LLT DstTy = MRI.getType(Dst);
452*0fca6ea1SDimitry Andric 
453*0fca6ea1SDimitry Andric   if (!MRI.hasOneNonDBGUse(RHSVScale->getReg(0)) ||
454*0fca6ea1SDimitry Andric       !isLegalOrBeforeLegalizer({TargetOpcode::G_ADD, DstTy}))
455*0fca6ea1SDimitry Andric     return false;
456*0fca6ea1SDimitry Andric 
457*0fca6ea1SDimitry Andric   MatchInfo = [=](MachineIRBuilder &B) {
458*0fca6ea1SDimitry Andric     auto VScale = B.buildVScale(DstTy, -RHSVScale->getSrc());
459*0fca6ea1SDimitry Andric     B.buildAdd(Dst, Sub->getLHSReg(), VScale, Sub->getFlags());
460*0fca6ea1SDimitry Andric   };
461*0fca6ea1SDimitry Andric 
462*0fca6ea1SDimitry Andric   return true;
463*0fca6ea1SDimitry Andric }
464*0fca6ea1SDimitry Andric 
465*0fca6ea1SDimitry Andric bool CombinerHelper::matchShlOfVScale(const MachineOperand &MO,
466*0fca6ea1SDimitry Andric                                       BuildFnTy &MatchInfo) {
467*0fca6ea1SDimitry Andric   GShl *Shl = cast<GShl>(MRI.getVRegDef(MO.getReg()));
468*0fca6ea1SDimitry Andric   GVScale *LHSVScale = cast<GVScale>(MRI.getVRegDef(Shl->getSrcReg()));
469*0fca6ea1SDimitry Andric 
470*0fca6ea1SDimitry Andric   std::optional<APInt> MaybeRHS = getIConstantVRegVal(Shl->getShiftReg(), MRI);
471*0fca6ea1SDimitry Andric   if (!MaybeRHS)
472*0fca6ea1SDimitry Andric     return false;
473*0fca6ea1SDimitry Andric 
474*0fca6ea1SDimitry Andric   Register Dst = MO.getReg();
475*0fca6ea1SDimitry Andric   LLT DstTy = MRI.getType(Dst);
476*0fca6ea1SDimitry Andric 
477*0fca6ea1SDimitry Andric   if (!MRI.hasOneNonDBGUse(LHSVScale->getReg(0)) ||
478*0fca6ea1SDimitry Andric       !isLegalOrBeforeLegalizer({TargetOpcode::G_VSCALE, DstTy}))
479*0fca6ea1SDimitry Andric     return false;
480*0fca6ea1SDimitry Andric 
481*0fca6ea1SDimitry Andric   MatchInfo = [=](MachineIRBuilder &B) {
482*0fca6ea1SDimitry Andric     B.buildVScale(Dst, LHSVScale->getSrc().shl(*MaybeRHS));
483*0fca6ea1SDimitry Andric   };
484*0fca6ea1SDimitry Andric 
485*0fca6ea1SDimitry Andric   return true;
486*0fca6ea1SDimitry Andric }
487