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