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