xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/VE/VVPISelLowering.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
181ad6265SDimitry Andric //===-- VVPISelLowering.cpp - VE DAG Lowering Implementation --------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file implements the lowering and legalization of vector instructions to
1081ad6265SDimitry Andric // VVP_*layer SDNodes.
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include "VECustomDAG.h"
1581ad6265SDimitry Andric #include "VEISelLowering.h"
1681ad6265SDimitry Andric 
1781ad6265SDimitry Andric using namespace llvm;
1881ad6265SDimitry Andric 
1981ad6265SDimitry Andric #define DEBUG_TYPE "ve-lower"
2081ad6265SDimitry Andric 
splitMaskArithmetic(SDValue Op,SelectionDAG & DAG) const2181ad6265SDimitry Andric SDValue VETargetLowering::splitMaskArithmetic(SDValue Op,
2281ad6265SDimitry Andric                                               SelectionDAG &DAG) const {
2381ad6265SDimitry Andric   VECustomDAG CDAG(DAG, Op);
2481ad6265SDimitry Andric   SDValue AVL =
2581ad6265SDimitry Andric       CDAG.getConstant(Op.getValueType().getVectorNumElements(), MVT::i32);
2681ad6265SDimitry Andric   SDValue A = Op->getOperand(0);
2781ad6265SDimitry Andric   SDValue B = Op->getOperand(1);
2881ad6265SDimitry Andric   SDValue LoA = CDAG.getUnpack(MVT::v256i1, A, PackElem::Lo, AVL);
2981ad6265SDimitry Andric   SDValue HiA = CDAG.getUnpack(MVT::v256i1, A, PackElem::Hi, AVL);
3081ad6265SDimitry Andric   SDValue LoB = CDAG.getUnpack(MVT::v256i1, B, PackElem::Lo, AVL);
3181ad6265SDimitry Andric   SDValue HiB = CDAG.getUnpack(MVT::v256i1, B, PackElem::Hi, AVL);
3281ad6265SDimitry Andric   unsigned Opc = Op.getOpcode();
3381ad6265SDimitry Andric   auto LoRes = CDAG.getNode(Opc, MVT::v256i1, {LoA, LoB});
3481ad6265SDimitry Andric   auto HiRes = CDAG.getNode(Opc, MVT::v256i1, {HiA, HiB});
3581ad6265SDimitry Andric   return CDAG.getPack(MVT::v512i1, LoRes, HiRes, AVL);
3681ad6265SDimitry Andric }
3781ad6265SDimitry Andric 
lowerToVVP(SDValue Op,SelectionDAG & DAG) const3881ad6265SDimitry Andric SDValue VETargetLowering::lowerToVVP(SDValue Op, SelectionDAG &DAG) const {
3981ad6265SDimitry Andric   // Can we represent this as a VVP node.
4081ad6265SDimitry Andric   const unsigned Opcode = Op->getOpcode();
4181ad6265SDimitry Andric   auto VVPOpcodeOpt = getVVPOpcode(Opcode);
4281ad6265SDimitry Andric   if (!VVPOpcodeOpt)
4381ad6265SDimitry Andric     return SDValue();
44bdd1243dSDimitry Andric   unsigned VVPOpcode = *VVPOpcodeOpt;
4581ad6265SDimitry Andric   const bool FromVP = ISD::isVPOpcode(Opcode);
4681ad6265SDimitry Andric 
4781ad6265SDimitry Andric   // The representative and legalized vector type of this operation.
4881ad6265SDimitry Andric   VECustomDAG CDAG(DAG, Op);
4981ad6265SDimitry Andric   // Dispatch to complex lowering functions.
5081ad6265SDimitry Andric   switch (VVPOpcode) {
5181ad6265SDimitry Andric   case VEISD::VVP_LOAD:
5281ad6265SDimitry Andric   case VEISD::VVP_STORE:
5381ad6265SDimitry Andric     return lowerVVP_LOAD_STORE(Op, CDAG);
5481ad6265SDimitry Andric   case VEISD::VVP_GATHER:
5581ad6265SDimitry Andric   case VEISD::VVP_SCATTER:
5681ad6265SDimitry Andric     return lowerVVP_GATHER_SCATTER(Op, CDAG);
5781ad6265SDimitry Andric   }
5881ad6265SDimitry Andric 
5981ad6265SDimitry Andric   EVT OpVecVT = *getIdiomaticVectorType(Op.getNode());
6081ad6265SDimitry Andric   EVT LegalVecVT = getTypeToTransformTo(*DAG.getContext(), OpVecVT);
6181ad6265SDimitry Andric   auto Packing = getTypePacking(LegalVecVT.getSimpleVT());
6281ad6265SDimitry Andric 
6381ad6265SDimitry Andric   SDValue AVL;
6481ad6265SDimitry Andric   SDValue Mask;
6581ad6265SDimitry Andric 
6681ad6265SDimitry Andric   if (FromVP) {
6781ad6265SDimitry Andric     // All upstream VP SDNodes always have a mask and avl.
6881ad6265SDimitry Andric     auto MaskIdx = ISD::getVPMaskIdx(Opcode);
6981ad6265SDimitry Andric     auto AVLIdx = ISD::getVPExplicitVectorLengthIdx(Opcode);
7081ad6265SDimitry Andric     if (MaskIdx)
7181ad6265SDimitry Andric       Mask = Op->getOperand(*MaskIdx);
7281ad6265SDimitry Andric     if (AVLIdx)
7381ad6265SDimitry Andric       AVL = Op->getOperand(*AVLIdx);
7481ad6265SDimitry Andric   }
7581ad6265SDimitry Andric 
7681ad6265SDimitry Andric   // Materialize default mask and avl.
7781ad6265SDimitry Andric   if (!AVL)
7881ad6265SDimitry Andric     AVL = CDAG.getConstant(OpVecVT.getVectorNumElements(), MVT::i32);
7981ad6265SDimitry Andric   if (!Mask)
8081ad6265SDimitry Andric     Mask = CDAG.getConstantMask(Packing, true);
8181ad6265SDimitry Andric 
8281ad6265SDimitry Andric   assert(LegalVecVT.isSimple());
8381ad6265SDimitry Andric   if (isVVPUnaryOp(VVPOpcode))
8481ad6265SDimitry Andric     return CDAG.getNode(VVPOpcode, LegalVecVT, {Op->getOperand(0), Mask, AVL});
8581ad6265SDimitry Andric   if (isVVPBinaryOp(VVPOpcode))
8681ad6265SDimitry Andric     return CDAG.getNode(VVPOpcode, LegalVecVT,
8781ad6265SDimitry Andric                         {Op->getOperand(0), Op->getOperand(1), Mask, AVL});
8881ad6265SDimitry Andric   if (isVVPReductionOp(VVPOpcode)) {
8981ad6265SDimitry Andric     auto SrcHasStart = hasReductionStartParam(Op->getOpcode());
9081ad6265SDimitry Andric     SDValue StartV = SrcHasStart ? Op->getOperand(0) : SDValue();
9181ad6265SDimitry Andric     SDValue VectorV = Op->getOperand(SrcHasStart ? 1 : 0);
9281ad6265SDimitry Andric     return CDAG.getLegalReductionOpVVP(VVPOpcode, Op.getValueType(), StartV,
9381ad6265SDimitry Andric                                        VectorV, Mask, AVL, Op->getFlags());
9481ad6265SDimitry Andric   }
9581ad6265SDimitry Andric 
9681ad6265SDimitry Andric   switch (VVPOpcode) {
9781ad6265SDimitry Andric   default:
9881ad6265SDimitry Andric     llvm_unreachable("lowerToVVP called for unexpected SDNode.");
9981ad6265SDimitry Andric   case VEISD::VVP_FFMA: {
10081ad6265SDimitry Andric     // VE has a swizzled operand order in FMA (compared to LLVM IR and
10181ad6265SDimitry Andric     // SDNodes).
10281ad6265SDimitry Andric     auto X = Op->getOperand(2);
10381ad6265SDimitry Andric     auto Y = Op->getOperand(0);
10481ad6265SDimitry Andric     auto Z = Op->getOperand(1);
10581ad6265SDimitry Andric     return CDAG.getNode(VVPOpcode, LegalVecVT, {X, Y, Z, Mask, AVL});
10681ad6265SDimitry Andric   }
10781ad6265SDimitry Andric   case VEISD::VVP_SELECT: {
10881ad6265SDimitry Andric     auto Mask = Op->getOperand(0);
10981ad6265SDimitry Andric     auto OnTrue = Op->getOperand(1);
11081ad6265SDimitry Andric     auto OnFalse = Op->getOperand(2);
11181ad6265SDimitry Andric     return CDAG.getNode(VVPOpcode, LegalVecVT, {OnTrue, OnFalse, Mask, AVL});
11281ad6265SDimitry Andric   }
11381ad6265SDimitry Andric   case VEISD::VVP_SETCC: {
11481ad6265SDimitry Andric     EVT LegalResVT = getTypeToTransformTo(*DAG.getContext(), Op.getValueType());
11581ad6265SDimitry Andric     auto LHS = Op->getOperand(0);
11681ad6265SDimitry Andric     auto RHS = Op->getOperand(1);
11781ad6265SDimitry Andric     auto Pred = Op->getOperand(2);
11881ad6265SDimitry Andric     return CDAG.getNode(VVPOpcode, LegalResVT, {LHS, RHS, Pred, Mask, AVL});
11981ad6265SDimitry Andric   }
12081ad6265SDimitry Andric   }
12181ad6265SDimitry Andric }
12281ad6265SDimitry Andric 
lowerVVP_LOAD_STORE(SDValue Op,VECustomDAG & CDAG) const12381ad6265SDimitry Andric SDValue VETargetLowering::lowerVVP_LOAD_STORE(SDValue Op,
12481ad6265SDimitry Andric                                               VECustomDAG &CDAG) const {
12581ad6265SDimitry Andric   auto VVPOpc = *getVVPOpcode(Op->getOpcode());
12681ad6265SDimitry Andric   const bool IsLoad = (VVPOpc == VEISD::VVP_LOAD);
12781ad6265SDimitry Andric 
12881ad6265SDimitry Andric   // Shares.
12981ad6265SDimitry Andric   SDValue BasePtr = getMemoryPtr(Op);
13081ad6265SDimitry Andric   SDValue Mask = getNodeMask(Op);
13181ad6265SDimitry Andric   SDValue Chain = getNodeChain(Op);
13281ad6265SDimitry Andric   SDValue AVL = getNodeAVL(Op);
13381ad6265SDimitry Andric   // Store specific.
13481ad6265SDimitry Andric   SDValue Data = getStoredValue(Op);
13581ad6265SDimitry Andric   // Load specific.
13681ad6265SDimitry Andric   SDValue PassThru = getNodePassthru(Op);
13781ad6265SDimitry Andric 
13881ad6265SDimitry Andric   SDValue StrideV = getLoadStoreStride(Op, CDAG);
13981ad6265SDimitry Andric 
14081ad6265SDimitry Andric   auto DataVT = *getIdiomaticVectorType(Op.getNode());
14181ad6265SDimitry Andric   auto Packing = getTypePacking(DataVT);
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric   // TODO: Infer lower AVL from mask.
14481ad6265SDimitry Andric   if (!AVL)
14581ad6265SDimitry Andric     AVL = CDAG.getConstant(DataVT.getVectorNumElements(), MVT::i32);
14681ad6265SDimitry Andric 
14781ad6265SDimitry Andric   // Default to the all-true mask.
14881ad6265SDimitry Andric   if (!Mask)
14981ad6265SDimitry Andric     Mask = CDAG.getConstantMask(Packing, true);
15081ad6265SDimitry Andric 
15181ad6265SDimitry Andric   if (IsLoad) {
15281ad6265SDimitry Andric     MVT LegalDataVT = getLegalVectorType(
15381ad6265SDimitry Andric         Packing, DataVT.getVectorElementType().getSimpleVT());
15481ad6265SDimitry Andric 
15581ad6265SDimitry Andric     auto NewLoadV = CDAG.getNode(VEISD::VVP_LOAD, {LegalDataVT, MVT::Other},
15681ad6265SDimitry Andric                                  {Chain, BasePtr, StrideV, Mask, AVL});
15781ad6265SDimitry Andric 
15881ad6265SDimitry Andric     if (!PassThru || PassThru->isUndef())
15981ad6265SDimitry Andric       return NewLoadV;
16081ad6265SDimitry Andric 
16181ad6265SDimitry Andric     // Convert passthru to an explicit select node.
16281ad6265SDimitry Andric     SDValue DataV = CDAG.getNode(VEISD::VVP_SELECT, DataVT,
16381ad6265SDimitry Andric                                  {NewLoadV, PassThru, Mask, AVL});
16481ad6265SDimitry Andric     SDValue NewLoadChainV = SDValue(NewLoadV.getNode(), 1);
16581ad6265SDimitry Andric 
16681ad6265SDimitry Andric     // Merge them back into one node.
16781ad6265SDimitry Andric     return CDAG.getMergeValues({DataV, NewLoadChainV});
16881ad6265SDimitry Andric   }
16981ad6265SDimitry Andric 
17081ad6265SDimitry Andric   // VVP_STORE
17181ad6265SDimitry Andric   assert(VVPOpc == VEISD::VVP_STORE);
172*5f757f3fSDimitry Andric   if (getTypeAction(*CDAG.getDAG()->getContext(), Data.getValueType()) !=
173*5f757f3fSDimitry Andric       TargetLowering::TypeLegal)
174*5f757f3fSDimitry Andric     // Doesn't lower store instruction if an operand is not lowered yet.
175*5f757f3fSDimitry Andric     // If it isn't, return SDValue().  In this way, LLVM will try to lower
176*5f757f3fSDimitry Andric     // store instruction again after lowering all operands.
177*5f757f3fSDimitry Andric     return SDValue();
17881ad6265SDimitry Andric   return CDAG.getNode(VEISD::VVP_STORE, Op.getNode()->getVTList(),
17981ad6265SDimitry Andric                       {Chain, Data, BasePtr, StrideV, Mask, AVL});
18081ad6265SDimitry Andric }
18181ad6265SDimitry Andric 
splitPackedLoadStore(SDValue Op,VECustomDAG & CDAG) const18281ad6265SDimitry Andric SDValue VETargetLowering::splitPackedLoadStore(SDValue Op,
18381ad6265SDimitry Andric                                                VECustomDAG &CDAG) const {
18481ad6265SDimitry Andric   auto VVPOC = *getVVPOpcode(Op.getOpcode());
18581ad6265SDimitry Andric   assert((VVPOC == VEISD::VVP_LOAD) || (VVPOC == VEISD::VVP_STORE));
18681ad6265SDimitry Andric 
18781ad6265SDimitry Andric   MVT DataVT = getIdiomaticVectorType(Op.getNode())->getSimpleVT();
18881ad6265SDimitry Andric   assert(getTypePacking(DataVT) == Packing::Dense &&
18981ad6265SDimitry Andric          "Can only split packed load/store");
19081ad6265SDimitry Andric   MVT SplitDataVT = splitVectorType(DataVT);
19181ad6265SDimitry Andric 
19281ad6265SDimitry Andric   assert(!getNodePassthru(Op) &&
19381ad6265SDimitry Andric          "Should have been folded in lowering to VVP layer");
19481ad6265SDimitry Andric 
19581ad6265SDimitry Andric   // Analyze the operation
19681ad6265SDimitry Andric   SDValue PackedMask = getNodeMask(Op);
19781ad6265SDimitry Andric   SDValue PackedAVL = getAnnotatedNodeAVL(Op).first;
19881ad6265SDimitry Andric   SDValue PackPtr = getMemoryPtr(Op);
19981ad6265SDimitry Andric   SDValue PackData = getStoredValue(Op);
20081ad6265SDimitry Andric   SDValue PackStride = getLoadStoreStride(Op, CDAG);
20181ad6265SDimitry Andric 
20281ad6265SDimitry Andric   unsigned ChainResIdx = PackData ? 0 : 1;
20381ad6265SDimitry Andric 
20481ad6265SDimitry Andric   SDValue PartOps[2];
20581ad6265SDimitry Andric 
20681ad6265SDimitry Andric   SDValue UpperPartAVL; // we will use this for packing things back together
20781ad6265SDimitry Andric   for (PackElem Part : {PackElem::Hi, PackElem::Lo}) {
20881ad6265SDimitry Andric     // VP ops already have an explicit mask and AVL. When expanding from non-VP
20981ad6265SDimitry Andric     // attach those additional inputs here.
21081ad6265SDimitry Andric     auto SplitTM = CDAG.getTargetSplitMask(PackedMask, PackedAVL, Part);
21181ad6265SDimitry Andric 
21281ad6265SDimitry Andric     // Keep track of the (higher) lvl.
21381ad6265SDimitry Andric     if (Part == PackElem::Hi)
21481ad6265SDimitry Andric       UpperPartAVL = SplitTM.AVL;
21581ad6265SDimitry Andric 
21681ad6265SDimitry Andric     // Attach non-predicating value operands
21781ad6265SDimitry Andric     SmallVector<SDValue, 4> OpVec;
21881ad6265SDimitry Andric 
21981ad6265SDimitry Andric     // Chain
22081ad6265SDimitry Andric     OpVec.push_back(getNodeChain(Op));
22181ad6265SDimitry Andric 
22281ad6265SDimitry Andric     // Data
22381ad6265SDimitry Andric     if (PackData) {
22481ad6265SDimitry Andric       SDValue PartData =
22581ad6265SDimitry Andric           CDAG.getUnpack(SplitDataVT, PackData, Part, SplitTM.AVL);
22681ad6265SDimitry Andric       OpVec.push_back(PartData);
22781ad6265SDimitry Andric     }
22881ad6265SDimitry Andric 
22981ad6265SDimitry Andric     // Ptr & Stride
23081ad6265SDimitry Andric     // Push (ptr + ElemBytes * <Part>, 2 * ElemBytes)
23181ad6265SDimitry Andric     // Stride info
23281ad6265SDimitry Andric     // EVT DataVT = LegalizeVectorType(getMemoryDataVT(Op), Op, DAG, Mode);
23381ad6265SDimitry Andric     OpVec.push_back(CDAG.getSplitPtrOffset(PackPtr, PackStride, Part));
23481ad6265SDimitry Andric     OpVec.push_back(CDAG.getSplitPtrStride(PackStride));
23581ad6265SDimitry Andric 
23681ad6265SDimitry Andric     // Add predicating args and generate part node
23781ad6265SDimitry Andric     OpVec.push_back(SplitTM.Mask);
23881ad6265SDimitry Andric     OpVec.push_back(SplitTM.AVL);
23981ad6265SDimitry Andric 
24081ad6265SDimitry Andric     if (PackData) {
24181ad6265SDimitry Andric       // Store
24281ad6265SDimitry Andric       PartOps[(int)Part] = CDAG.getNode(VVPOC, MVT::Other, OpVec);
24381ad6265SDimitry Andric     } else {
24481ad6265SDimitry Andric       // Load
24581ad6265SDimitry Andric       PartOps[(int)Part] =
24681ad6265SDimitry Andric           CDAG.getNode(VVPOC, {SplitDataVT, MVT::Other}, OpVec);
24781ad6265SDimitry Andric     }
24881ad6265SDimitry Andric   }
24981ad6265SDimitry Andric 
25081ad6265SDimitry Andric   // Merge the chains
25181ad6265SDimitry Andric   SDValue LowChain = SDValue(PartOps[(int)PackElem::Lo].getNode(), ChainResIdx);
25281ad6265SDimitry Andric   SDValue HiChain = SDValue(PartOps[(int)PackElem::Hi].getNode(), ChainResIdx);
25381ad6265SDimitry Andric   SDValue FusedChains =
25481ad6265SDimitry Andric       CDAG.getNode(ISD::TokenFactor, MVT::Other, {LowChain, HiChain});
25581ad6265SDimitry Andric 
25681ad6265SDimitry Andric   // Chain only [store]
25781ad6265SDimitry Andric   if (PackData)
25881ad6265SDimitry Andric     return FusedChains;
25981ad6265SDimitry Andric 
26081ad6265SDimitry Andric   // Re-pack into full packed vector result
26181ad6265SDimitry Andric   MVT PackedVT =
26281ad6265SDimitry Andric       getLegalVectorType(Packing::Dense, DataVT.getVectorElementType());
26381ad6265SDimitry Andric   SDValue PackedVals = CDAG.getPack(PackedVT, PartOps[(int)PackElem::Lo],
26481ad6265SDimitry Andric                                     PartOps[(int)PackElem::Hi], UpperPartAVL);
26581ad6265SDimitry Andric 
26681ad6265SDimitry Andric   return CDAG.getMergeValues({PackedVals, FusedChains});
26781ad6265SDimitry Andric }
26881ad6265SDimitry Andric 
lowerVVP_GATHER_SCATTER(SDValue Op,VECustomDAG & CDAG) const26981ad6265SDimitry Andric SDValue VETargetLowering::lowerVVP_GATHER_SCATTER(SDValue Op,
27081ad6265SDimitry Andric                                                   VECustomDAG &CDAG) const {
27181ad6265SDimitry Andric   EVT DataVT = *getIdiomaticVectorType(Op.getNode());
27281ad6265SDimitry Andric   auto Packing = getTypePacking(DataVT);
27381ad6265SDimitry Andric   MVT LegalDataVT =
27481ad6265SDimitry Andric       getLegalVectorType(Packing, DataVT.getVectorElementType().getSimpleVT());
27581ad6265SDimitry Andric 
27681ad6265SDimitry Andric   SDValue AVL = getAnnotatedNodeAVL(Op).first;
27781ad6265SDimitry Andric   SDValue Index = getGatherScatterIndex(Op);
27881ad6265SDimitry Andric   SDValue BasePtr = getMemoryPtr(Op);
27981ad6265SDimitry Andric   SDValue Mask = getNodeMask(Op);
28081ad6265SDimitry Andric   SDValue Chain = getNodeChain(Op);
28181ad6265SDimitry Andric   SDValue Scale = getGatherScatterScale(Op);
28281ad6265SDimitry Andric   SDValue PassThru = getNodePassthru(Op);
28381ad6265SDimitry Andric   SDValue StoredValue = getStoredValue(Op);
28481ad6265SDimitry Andric   if (PassThru && PassThru->isUndef())
28581ad6265SDimitry Andric     PassThru = SDValue();
28681ad6265SDimitry Andric 
28781ad6265SDimitry Andric   bool IsScatter = (bool)StoredValue;
28881ad6265SDimitry Andric 
28981ad6265SDimitry Andric   // TODO: Infer lower AVL from mask.
29081ad6265SDimitry Andric   if (!AVL)
29181ad6265SDimitry Andric     AVL = CDAG.getConstant(DataVT.getVectorNumElements(), MVT::i32);
29281ad6265SDimitry Andric 
29381ad6265SDimitry Andric   // Default to the all-true mask.
29481ad6265SDimitry Andric   if (!Mask)
29581ad6265SDimitry Andric     Mask = CDAG.getConstantMask(Packing, true);
29681ad6265SDimitry Andric 
29781ad6265SDimitry Andric   SDValue AddressVec =
29881ad6265SDimitry Andric       CDAG.getGatherScatterAddress(BasePtr, Scale, Index, Mask, AVL);
29981ad6265SDimitry Andric   if (IsScatter)
30081ad6265SDimitry Andric     return CDAG.getNode(VEISD::VVP_SCATTER, MVT::Other,
30181ad6265SDimitry Andric                         {Chain, StoredValue, AddressVec, Mask, AVL});
30281ad6265SDimitry Andric 
30381ad6265SDimitry Andric   // Gather.
30481ad6265SDimitry Andric   SDValue NewLoadV = CDAG.getNode(VEISD::VVP_GATHER, {LegalDataVT, MVT::Other},
30581ad6265SDimitry Andric                                   {Chain, AddressVec, Mask, AVL});
30681ad6265SDimitry Andric 
30781ad6265SDimitry Andric   if (!PassThru)
30881ad6265SDimitry Andric     return NewLoadV;
30981ad6265SDimitry Andric 
31081ad6265SDimitry Andric   // TODO: Use vvp_select
31181ad6265SDimitry Andric   SDValue DataV = CDAG.getNode(VEISD::VVP_SELECT, LegalDataVT,
31281ad6265SDimitry Andric                                {NewLoadV, PassThru, Mask, AVL});
31381ad6265SDimitry Andric   SDValue NewLoadChainV = SDValue(NewLoadV.getNode(), 1);
31481ad6265SDimitry Andric   return CDAG.getMergeValues({DataV, NewLoadChainV});
31581ad6265SDimitry Andric }
31681ad6265SDimitry Andric 
legalizeInternalLoadStoreOp(SDValue Op,VECustomDAG & CDAG) const31781ad6265SDimitry Andric SDValue VETargetLowering::legalizeInternalLoadStoreOp(SDValue Op,
31881ad6265SDimitry Andric                                                       VECustomDAG &CDAG) const {
31981ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "::legalizeInternalLoadStoreOp\n";);
32081ad6265SDimitry Andric   MVT DataVT = getIdiomaticVectorType(Op.getNode())->getSimpleVT();
32181ad6265SDimitry Andric 
32281ad6265SDimitry Andric   // TODO: Recognize packable load,store.
32381ad6265SDimitry Andric   if (isPackedVectorType(DataVT))
32481ad6265SDimitry Andric     return splitPackedLoadStore(Op, CDAG);
32581ad6265SDimitry Andric 
32681ad6265SDimitry Andric   return legalizePackedAVL(Op, CDAG);
32781ad6265SDimitry Andric }
32881ad6265SDimitry Andric 
legalizeInternalVectorOp(SDValue Op,SelectionDAG & DAG) const32981ad6265SDimitry Andric SDValue VETargetLowering::legalizeInternalVectorOp(SDValue Op,
33081ad6265SDimitry Andric                                                    SelectionDAG &DAG) const {
33181ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "::legalizeInternalVectorOp\n";);
33281ad6265SDimitry Andric   VECustomDAG CDAG(DAG, Op);
33381ad6265SDimitry Andric 
33481ad6265SDimitry Andric   // Dispatch to specialized legalization functions.
33581ad6265SDimitry Andric   switch (Op->getOpcode()) {
33681ad6265SDimitry Andric   case VEISD::VVP_LOAD:
33781ad6265SDimitry Andric   case VEISD::VVP_STORE:
33881ad6265SDimitry Andric     return legalizeInternalLoadStoreOp(Op, CDAG);
33981ad6265SDimitry Andric   }
34081ad6265SDimitry Andric 
34181ad6265SDimitry Andric   EVT IdiomVT = Op.getValueType();
34281ad6265SDimitry Andric   if (isPackedVectorType(IdiomVT) &&
34381ad6265SDimitry Andric       !supportsPackedMode(Op.getOpcode(), IdiomVT))
34481ad6265SDimitry Andric     return splitVectorOp(Op, CDAG);
34581ad6265SDimitry Andric 
34681ad6265SDimitry Andric   // TODO: Implement odd/even splitting.
34781ad6265SDimitry Andric   return legalizePackedAVL(Op, CDAG);
34881ad6265SDimitry Andric }
34981ad6265SDimitry Andric 
splitVectorOp(SDValue Op,VECustomDAG & CDAG) const35081ad6265SDimitry Andric SDValue VETargetLowering::splitVectorOp(SDValue Op, VECustomDAG &CDAG) const {
35181ad6265SDimitry Andric   MVT ResVT = splitVectorType(Op.getValue(0).getSimpleValueType());
35281ad6265SDimitry Andric 
35381ad6265SDimitry Andric   auto AVLPos = getAVLPos(Op->getOpcode());
35481ad6265SDimitry Andric   auto MaskPos = getMaskPos(Op->getOpcode());
35581ad6265SDimitry Andric 
35681ad6265SDimitry Andric   SDValue PackedMask = getNodeMask(Op);
35781ad6265SDimitry Andric   auto AVLPair = getAnnotatedNodeAVL(Op);
35881ad6265SDimitry Andric   SDValue PackedAVL = AVLPair.first;
35981ad6265SDimitry Andric   assert(!AVLPair.second && "Expecting non pack-legalized oepration");
36081ad6265SDimitry Andric 
36181ad6265SDimitry Andric   // request the parts
36281ad6265SDimitry Andric   SDValue PartOps[2];
36381ad6265SDimitry Andric 
36481ad6265SDimitry Andric   SDValue UpperPartAVL; // we will use this for packing things back together
36581ad6265SDimitry Andric   for (PackElem Part : {PackElem::Hi, PackElem::Lo}) {
36681ad6265SDimitry Andric     // VP ops already have an explicit mask and AVL. When expanding from non-VP
36781ad6265SDimitry Andric     // attach those additional inputs here.
36881ad6265SDimitry Andric     auto SplitTM = CDAG.getTargetSplitMask(PackedMask, PackedAVL, Part);
36981ad6265SDimitry Andric 
37081ad6265SDimitry Andric     if (Part == PackElem::Hi)
37181ad6265SDimitry Andric       UpperPartAVL = SplitTM.AVL;
37281ad6265SDimitry Andric 
37381ad6265SDimitry Andric     // Attach non-predicating value operands
37481ad6265SDimitry Andric     SmallVector<SDValue, 4> OpVec;
37581ad6265SDimitry Andric     for (unsigned i = 0; i < Op.getNumOperands(); ++i) {
37681ad6265SDimitry Andric       if (AVLPos && ((int)i) == *AVLPos)
37781ad6265SDimitry Andric         continue;
37881ad6265SDimitry Andric       if (MaskPos && ((int)i) == *MaskPos)
37981ad6265SDimitry Andric         continue;
38081ad6265SDimitry Andric 
38181ad6265SDimitry Andric       // Value operand
38281ad6265SDimitry Andric       auto PackedOperand = Op.getOperand(i);
38381ad6265SDimitry Andric       auto UnpackedOpVT = splitVectorType(PackedOperand.getSimpleValueType());
38481ad6265SDimitry Andric       SDValue PartV =
38581ad6265SDimitry Andric           CDAG.getUnpack(UnpackedOpVT, PackedOperand, Part, SplitTM.AVL);
38681ad6265SDimitry Andric       OpVec.push_back(PartV);
38781ad6265SDimitry Andric     }
38881ad6265SDimitry Andric 
38981ad6265SDimitry Andric     // Add predicating args and generate part node.
39081ad6265SDimitry Andric     OpVec.push_back(SplitTM.Mask);
39181ad6265SDimitry Andric     OpVec.push_back(SplitTM.AVL);
39281ad6265SDimitry Andric     // Emit legal VVP nodes.
39381ad6265SDimitry Andric     PartOps[(int)Part] =
39481ad6265SDimitry Andric         CDAG.getNode(Op.getOpcode(), ResVT, OpVec, Op->getFlags());
39581ad6265SDimitry Andric   }
39681ad6265SDimitry Andric 
39781ad6265SDimitry Andric   // Re-package vectors.
39881ad6265SDimitry Andric   return CDAG.getPack(Op.getValueType(), PartOps[(int)PackElem::Lo],
39981ad6265SDimitry Andric                       PartOps[(int)PackElem::Hi], UpperPartAVL);
40081ad6265SDimitry Andric }
40181ad6265SDimitry Andric 
legalizePackedAVL(SDValue Op,VECustomDAG & CDAG) const40281ad6265SDimitry Andric SDValue VETargetLowering::legalizePackedAVL(SDValue Op,
40381ad6265SDimitry Andric                                             VECustomDAG &CDAG) const {
40481ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "::legalizePackedAVL\n";);
40581ad6265SDimitry Andric   // Only required for VEC and VVP ops.
40681ad6265SDimitry Andric   if (!isVVPOrVEC(Op->getOpcode()))
40781ad6265SDimitry Andric     return Op;
40881ad6265SDimitry Andric 
40981ad6265SDimitry Andric   // Operation already has a legal AVL.
41081ad6265SDimitry Andric   auto AVL = getNodeAVL(Op);
41181ad6265SDimitry Andric   if (isLegalAVL(AVL))
41281ad6265SDimitry Andric     return Op;
41381ad6265SDimitry Andric 
41481ad6265SDimitry Andric   // Half and round up EVL for 32bit element types.
41581ad6265SDimitry Andric   SDValue LegalAVL = AVL;
41681ad6265SDimitry Andric   MVT IdiomVT = getIdiomaticVectorType(Op.getNode())->getSimpleVT();
41781ad6265SDimitry Andric   if (isPackedVectorType(IdiomVT)) {
41881ad6265SDimitry Andric     assert(maySafelyIgnoreMask(Op) &&
41981ad6265SDimitry Andric            "TODO Shift predication from EVL into Mask");
42081ad6265SDimitry Andric 
42181ad6265SDimitry Andric     if (auto *ConstAVL = dyn_cast<ConstantSDNode>(AVL)) {
42281ad6265SDimitry Andric       LegalAVL = CDAG.getConstant((ConstAVL->getZExtValue() + 1) / 2, MVT::i32);
42381ad6265SDimitry Andric     } else {
42481ad6265SDimitry Andric       auto ConstOne = CDAG.getConstant(1, MVT::i32);
42581ad6265SDimitry Andric       auto PlusOne = CDAG.getNode(ISD::ADD, MVT::i32, {AVL, ConstOne});
42681ad6265SDimitry Andric       LegalAVL = CDAG.getNode(ISD::SRL, MVT::i32, {PlusOne, ConstOne});
42781ad6265SDimitry Andric     }
42881ad6265SDimitry Andric   }
42981ad6265SDimitry Andric 
43081ad6265SDimitry Andric   SDValue AnnotatedLegalAVL = CDAG.annotateLegalAVL(LegalAVL);
43181ad6265SDimitry Andric 
43281ad6265SDimitry Andric   // Copy the operand list.
43381ad6265SDimitry Andric   int NumOp = Op->getNumOperands();
43481ad6265SDimitry Andric   auto AVLPos = getAVLPos(Op->getOpcode());
43581ad6265SDimitry Andric   std::vector<SDValue> FixedOperands;
43681ad6265SDimitry Andric   for (int i = 0; i < NumOp; ++i) {
43781ad6265SDimitry Andric     if (AVLPos && (i == *AVLPos)) {
43881ad6265SDimitry Andric       FixedOperands.push_back(AnnotatedLegalAVL);
43981ad6265SDimitry Andric       continue;
44081ad6265SDimitry Andric     }
44181ad6265SDimitry Andric     FixedOperands.push_back(Op->getOperand(i));
44281ad6265SDimitry Andric   }
44381ad6265SDimitry Andric 
44481ad6265SDimitry Andric   // Clone the operation with fixed operands.
44581ad6265SDimitry Andric   auto Flags = Op->getFlags();
44681ad6265SDimitry Andric   SDValue NewN =
44781ad6265SDimitry Andric       CDAG.getNode(Op->getOpcode(), Op->getVTList(), FixedOperands, Flags);
44881ad6265SDimitry Andric   return NewN;
44981ad6265SDimitry Andric }
450