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 2181ad6265SDimitry 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 3881ad6265SDimitry 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(); 44*bdd1243dSDimitry 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 12381ad6265SDimitry 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); 17281ad6265SDimitry Andric return CDAG.getNode(VEISD::VVP_STORE, Op.getNode()->getVTList(), 17381ad6265SDimitry Andric {Chain, Data, BasePtr, StrideV, Mask, AVL}); 17481ad6265SDimitry Andric } 17581ad6265SDimitry Andric 17681ad6265SDimitry Andric SDValue VETargetLowering::splitPackedLoadStore(SDValue Op, 17781ad6265SDimitry Andric VECustomDAG &CDAG) const { 17881ad6265SDimitry Andric auto VVPOC = *getVVPOpcode(Op.getOpcode()); 17981ad6265SDimitry Andric assert((VVPOC == VEISD::VVP_LOAD) || (VVPOC == VEISD::VVP_STORE)); 18081ad6265SDimitry Andric 18181ad6265SDimitry Andric MVT DataVT = getIdiomaticVectorType(Op.getNode())->getSimpleVT(); 18281ad6265SDimitry Andric assert(getTypePacking(DataVT) == Packing::Dense && 18381ad6265SDimitry Andric "Can only split packed load/store"); 18481ad6265SDimitry Andric MVT SplitDataVT = splitVectorType(DataVT); 18581ad6265SDimitry Andric 18681ad6265SDimitry Andric assert(!getNodePassthru(Op) && 18781ad6265SDimitry Andric "Should have been folded in lowering to VVP layer"); 18881ad6265SDimitry Andric 18981ad6265SDimitry Andric // Analyze the operation 19081ad6265SDimitry Andric SDValue PackedMask = getNodeMask(Op); 19181ad6265SDimitry Andric SDValue PackedAVL = getAnnotatedNodeAVL(Op).first; 19281ad6265SDimitry Andric SDValue PackPtr = getMemoryPtr(Op); 19381ad6265SDimitry Andric SDValue PackData = getStoredValue(Op); 19481ad6265SDimitry Andric SDValue PackStride = getLoadStoreStride(Op, CDAG); 19581ad6265SDimitry Andric 19681ad6265SDimitry Andric unsigned ChainResIdx = PackData ? 0 : 1; 19781ad6265SDimitry Andric 19881ad6265SDimitry Andric SDValue PartOps[2]; 19981ad6265SDimitry Andric 20081ad6265SDimitry Andric SDValue UpperPartAVL; // we will use this for packing things back together 20181ad6265SDimitry Andric for (PackElem Part : {PackElem::Hi, PackElem::Lo}) { 20281ad6265SDimitry Andric // VP ops already have an explicit mask and AVL. When expanding from non-VP 20381ad6265SDimitry Andric // attach those additional inputs here. 20481ad6265SDimitry Andric auto SplitTM = CDAG.getTargetSplitMask(PackedMask, PackedAVL, Part); 20581ad6265SDimitry Andric 20681ad6265SDimitry Andric // Keep track of the (higher) lvl. 20781ad6265SDimitry Andric if (Part == PackElem::Hi) 20881ad6265SDimitry Andric UpperPartAVL = SplitTM.AVL; 20981ad6265SDimitry Andric 21081ad6265SDimitry Andric // Attach non-predicating value operands 21181ad6265SDimitry Andric SmallVector<SDValue, 4> OpVec; 21281ad6265SDimitry Andric 21381ad6265SDimitry Andric // Chain 21481ad6265SDimitry Andric OpVec.push_back(getNodeChain(Op)); 21581ad6265SDimitry Andric 21681ad6265SDimitry Andric // Data 21781ad6265SDimitry Andric if (PackData) { 21881ad6265SDimitry Andric SDValue PartData = 21981ad6265SDimitry Andric CDAG.getUnpack(SplitDataVT, PackData, Part, SplitTM.AVL); 22081ad6265SDimitry Andric OpVec.push_back(PartData); 22181ad6265SDimitry Andric } 22281ad6265SDimitry Andric 22381ad6265SDimitry Andric // Ptr & Stride 22481ad6265SDimitry Andric // Push (ptr + ElemBytes * <Part>, 2 * ElemBytes) 22581ad6265SDimitry Andric // Stride info 22681ad6265SDimitry Andric // EVT DataVT = LegalizeVectorType(getMemoryDataVT(Op), Op, DAG, Mode); 22781ad6265SDimitry Andric OpVec.push_back(CDAG.getSplitPtrOffset(PackPtr, PackStride, Part)); 22881ad6265SDimitry Andric OpVec.push_back(CDAG.getSplitPtrStride(PackStride)); 22981ad6265SDimitry Andric 23081ad6265SDimitry Andric // Add predicating args and generate part node 23181ad6265SDimitry Andric OpVec.push_back(SplitTM.Mask); 23281ad6265SDimitry Andric OpVec.push_back(SplitTM.AVL); 23381ad6265SDimitry Andric 23481ad6265SDimitry Andric if (PackData) { 23581ad6265SDimitry Andric // Store 23681ad6265SDimitry Andric PartOps[(int)Part] = CDAG.getNode(VVPOC, MVT::Other, OpVec); 23781ad6265SDimitry Andric } else { 23881ad6265SDimitry Andric // Load 23981ad6265SDimitry Andric PartOps[(int)Part] = 24081ad6265SDimitry Andric CDAG.getNode(VVPOC, {SplitDataVT, MVT::Other}, OpVec); 24181ad6265SDimitry Andric } 24281ad6265SDimitry Andric } 24381ad6265SDimitry Andric 24481ad6265SDimitry Andric // Merge the chains 24581ad6265SDimitry Andric SDValue LowChain = SDValue(PartOps[(int)PackElem::Lo].getNode(), ChainResIdx); 24681ad6265SDimitry Andric SDValue HiChain = SDValue(PartOps[(int)PackElem::Hi].getNode(), ChainResIdx); 24781ad6265SDimitry Andric SDValue FusedChains = 24881ad6265SDimitry Andric CDAG.getNode(ISD::TokenFactor, MVT::Other, {LowChain, HiChain}); 24981ad6265SDimitry Andric 25081ad6265SDimitry Andric // Chain only [store] 25181ad6265SDimitry Andric if (PackData) 25281ad6265SDimitry Andric return FusedChains; 25381ad6265SDimitry Andric 25481ad6265SDimitry Andric // Re-pack into full packed vector result 25581ad6265SDimitry Andric MVT PackedVT = 25681ad6265SDimitry Andric getLegalVectorType(Packing::Dense, DataVT.getVectorElementType()); 25781ad6265SDimitry Andric SDValue PackedVals = CDAG.getPack(PackedVT, PartOps[(int)PackElem::Lo], 25881ad6265SDimitry Andric PartOps[(int)PackElem::Hi], UpperPartAVL); 25981ad6265SDimitry Andric 26081ad6265SDimitry Andric return CDAG.getMergeValues({PackedVals, FusedChains}); 26181ad6265SDimitry Andric } 26281ad6265SDimitry Andric 26381ad6265SDimitry Andric SDValue VETargetLowering::lowerVVP_GATHER_SCATTER(SDValue Op, 26481ad6265SDimitry Andric VECustomDAG &CDAG) const { 26581ad6265SDimitry Andric EVT DataVT = *getIdiomaticVectorType(Op.getNode()); 26681ad6265SDimitry Andric auto Packing = getTypePacking(DataVT); 26781ad6265SDimitry Andric MVT LegalDataVT = 26881ad6265SDimitry Andric getLegalVectorType(Packing, DataVT.getVectorElementType().getSimpleVT()); 26981ad6265SDimitry Andric 27081ad6265SDimitry Andric SDValue AVL = getAnnotatedNodeAVL(Op).first; 27181ad6265SDimitry Andric SDValue Index = getGatherScatterIndex(Op); 27281ad6265SDimitry Andric SDValue BasePtr = getMemoryPtr(Op); 27381ad6265SDimitry Andric SDValue Mask = getNodeMask(Op); 27481ad6265SDimitry Andric SDValue Chain = getNodeChain(Op); 27581ad6265SDimitry Andric SDValue Scale = getGatherScatterScale(Op); 27681ad6265SDimitry Andric SDValue PassThru = getNodePassthru(Op); 27781ad6265SDimitry Andric SDValue StoredValue = getStoredValue(Op); 27881ad6265SDimitry Andric if (PassThru && PassThru->isUndef()) 27981ad6265SDimitry Andric PassThru = SDValue(); 28081ad6265SDimitry Andric 28181ad6265SDimitry Andric bool IsScatter = (bool)StoredValue; 28281ad6265SDimitry Andric 28381ad6265SDimitry Andric // TODO: Infer lower AVL from mask. 28481ad6265SDimitry Andric if (!AVL) 28581ad6265SDimitry Andric AVL = CDAG.getConstant(DataVT.getVectorNumElements(), MVT::i32); 28681ad6265SDimitry Andric 28781ad6265SDimitry Andric // Default to the all-true mask. 28881ad6265SDimitry Andric if (!Mask) 28981ad6265SDimitry Andric Mask = CDAG.getConstantMask(Packing, true); 29081ad6265SDimitry Andric 29181ad6265SDimitry Andric SDValue AddressVec = 29281ad6265SDimitry Andric CDAG.getGatherScatterAddress(BasePtr, Scale, Index, Mask, AVL); 29381ad6265SDimitry Andric if (IsScatter) 29481ad6265SDimitry Andric return CDAG.getNode(VEISD::VVP_SCATTER, MVT::Other, 29581ad6265SDimitry Andric {Chain, StoredValue, AddressVec, Mask, AVL}); 29681ad6265SDimitry Andric 29781ad6265SDimitry Andric // Gather. 29881ad6265SDimitry Andric SDValue NewLoadV = CDAG.getNode(VEISD::VVP_GATHER, {LegalDataVT, MVT::Other}, 29981ad6265SDimitry Andric {Chain, AddressVec, Mask, AVL}); 30081ad6265SDimitry Andric 30181ad6265SDimitry Andric if (!PassThru) 30281ad6265SDimitry Andric return NewLoadV; 30381ad6265SDimitry Andric 30481ad6265SDimitry Andric // TODO: Use vvp_select 30581ad6265SDimitry Andric SDValue DataV = CDAG.getNode(VEISD::VVP_SELECT, LegalDataVT, 30681ad6265SDimitry Andric {NewLoadV, PassThru, Mask, AVL}); 30781ad6265SDimitry Andric SDValue NewLoadChainV = SDValue(NewLoadV.getNode(), 1); 30881ad6265SDimitry Andric return CDAG.getMergeValues({DataV, NewLoadChainV}); 30981ad6265SDimitry Andric } 31081ad6265SDimitry Andric 31181ad6265SDimitry Andric SDValue VETargetLowering::legalizeInternalLoadStoreOp(SDValue Op, 31281ad6265SDimitry Andric VECustomDAG &CDAG) const { 31381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "::legalizeInternalLoadStoreOp\n";); 31481ad6265SDimitry Andric MVT DataVT = getIdiomaticVectorType(Op.getNode())->getSimpleVT(); 31581ad6265SDimitry Andric 31681ad6265SDimitry Andric // TODO: Recognize packable load,store. 31781ad6265SDimitry Andric if (isPackedVectorType(DataVT)) 31881ad6265SDimitry Andric return splitPackedLoadStore(Op, CDAG); 31981ad6265SDimitry Andric 32081ad6265SDimitry Andric return legalizePackedAVL(Op, CDAG); 32181ad6265SDimitry Andric } 32281ad6265SDimitry Andric 32381ad6265SDimitry Andric SDValue VETargetLowering::legalizeInternalVectorOp(SDValue Op, 32481ad6265SDimitry Andric SelectionDAG &DAG) const { 32581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "::legalizeInternalVectorOp\n";); 32681ad6265SDimitry Andric VECustomDAG CDAG(DAG, Op); 32781ad6265SDimitry Andric 32881ad6265SDimitry Andric // Dispatch to specialized legalization functions. 32981ad6265SDimitry Andric switch (Op->getOpcode()) { 33081ad6265SDimitry Andric case VEISD::VVP_LOAD: 33181ad6265SDimitry Andric case VEISD::VVP_STORE: 33281ad6265SDimitry Andric return legalizeInternalLoadStoreOp(Op, CDAG); 33381ad6265SDimitry Andric } 33481ad6265SDimitry Andric 33581ad6265SDimitry Andric EVT IdiomVT = Op.getValueType(); 33681ad6265SDimitry Andric if (isPackedVectorType(IdiomVT) && 33781ad6265SDimitry Andric !supportsPackedMode(Op.getOpcode(), IdiomVT)) 33881ad6265SDimitry Andric return splitVectorOp(Op, CDAG); 33981ad6265SDimitry Andric 34081ad6265SDimitry Andric // TODO: Implement odd/even splitting. 34181ad6265SDimitry Andric return legalizePackedAVL(Op, CDAG); 34281ad6265SDimitry Andric } 34381ad6265SDimitry Andric 34481ad6265SDimitry Andric SDValue VETargetLowering::splitVectorOp(SDValue Op, VECustomDAG &CDAG) const { 34581ad6265SDimitry Andric MVT ResVT = splitVectorType(Op.getValue(0).getSimpleValueType()); 34681ad6265SDimitry Andric 34781ad6265SDimitry Andric auto AVLPos = getAVLPos(Op->getOpcode()); 34881ad6265SDimitry Andric auto MaskPos = getMaskPos(Op->getOpcode()); 34981ad6265SDimitry Andric 35081ad6265SDimitry Andric SDValue PackedMask = getNodeMask(Op); 35181ad6265SDimitry Andric auto AVLPair = getAnnotatedNodeAVL(Op); 35281ad6265SDimitry Andric SDValue PackedAVL = AVLPair.first; 35381ad6265SDimitry Andric assert(!AVLPair.second && "Expecting non pack-legalized oepration"); 35481ad6265SDimitry Andric 35581ad6265SDimitry Andric // request the parts 35681ad6265SDimitry Andric SDValue PartOps[2]; 35781ad6265SDimitry Andric 35881ad6265SDimitry Andric SDValue UpperPartAVL; // we will use this for packing things back together 35981ad6265SDimitry Andric for (PackElem Part : {PackElem::Hi, PackElem::Lo}) { 36081ad6265SDimitry Andric // VP ops already have an explicit mask and AVL. When expanding from non-VP 36181ad6265SDimitry Andric // attach those additional inputs here. 36281ad6265SDimitry Andric auto SplitTM = CDAG.getTargetSplitMask(PackedMask, PackedAVL, Part); 36381ad6265SDimitry Andric 36481ad6265SDimitry Andric if (Part == PackElem::Hi) 36581ad6265SDimitry Andric UpperPartAVL = SplitTM.AVL; 36681ad6265SDimitry Andric 36781ad6265SDimitry Andric // Attach non-predicating value operands 36881ad6265SDimitry Andric SmallVector<SDValue, 4> OpVec; 36981ad6265SDimitry Andric for (unsigned i = 0; i < Op.getNumOperands(); ++i) { 37081ad6265SDimitry Andric if (AVLPos && ((int)i) == *AVLPos) 37181ad6265SDimitry Andric continue; 37281ad6265SDimitry Andric if (MaskPos && ((int)i) == *MaskPos) 37381ad6265SDimitry Andric continue; 37481ad6265SDimitry Andric 37581ad6265SDimitry Andric // Value operand 37681ad6265SDimitry Andric auto PackedOperand = Op.getOperand(i); 37781ad6265SDimitry Andric auto UnpackedOpVT = splitVectorType(PackedOperand.getSimpleValueType()); 37881ad6265SDimitry Andric SDValue PartV = 37981ad6265SDimitry Andric CDAG.getUnpack(UnpackedOpVT, PackedOperand, Part, SplitTM.AVL); 38081ad6265SDimitry Andric OpVec.push_back(PartV); 38181ad6265SDimitry Andric } 38281ad6265SDimitry Andric 38381ad6265SDimitry Andric // Add predicating args and generate part node. 38481ad6265SDimitry Andric OpVec.push_back(SplitTM.Mask); 38581ad6265SDimitry Andric OpVec.push_back(SplitTM.AVL); 38681ad6265SDimitry Andric // Emit legal VVP nodes. 38781ad6265SDimitry Andric PartOps[(int)Part] = 38881ad6265SDimitry Andric CDAG.getNode(Op.getOpcode(), ResVT, OpVec, Op->getFlags()); 38981ad6265SDimitry Andric } 39081ad6265SDimitry Andric 39181ad6265SDimitry Andric // Re-package vectors. 39281ad6265SDimitry Andric return CDAG.getPack(Op.getValueType(), PartOps[(int)PackElem::Lo], 39381ad6265SDimitry Andric PartOps[(int)PackElem::Hi], UpperPartAVL); 39481ad6265SDimitry Andric } 39581ad6265SDimitry Andric 39681ad6265SDimitry Andric SDValue VETargetLowering::legalizePackedAVL(SDValue Op, 39781ad6265SDimitry Andric VECustomDAG &CDAG) const { 39881ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "::legalizePackedAVL\n";); 39981ad6265SDimitry Andric // Only required for VEC and VVP ops. 40081ad6265SDimitry Andric if (!isVVPOrVEC(Op->getOpcode())) 40181ad6265SDimitry Andric return Op; 40281ad6265SDimitry Andric 40381ad6265SDimitry Andric // Operation already has a legal AVL. 40481ad6265SDimitry Andric auto AVL = getNodeAVL(Op); 40581ad6265SDimitry Andric if (isLegalAVL(AVL)) 40681ad6265SDimitry Andric return Op; 40781ad6265SDimitry Andric 40881ad6265SDimitry Andric // Half and round up EVL for 32bit element types. 40981ad6265SDimitry Andric SDValue LegalAVL = AVL; 41081ad6265SDimitry Andric MVT IdiomVT = getIdiomaticVectorType(Op.getNode())->getSimpleVT(); 41181ad6265SDimitry Andric if (isPackedVectorType(IdiomVT)) { 41281ad6265SDimitry Andric assert(maySafelyIgnoreMask(Op) && 41381ad6265SDimitry Andric "TODO Shift predication from EVL into Mask"); 41481ad6265SDimitry Andric 41581ad6265SDimitry Andric if (auto *ConstAVL = dyn_cast<ConstantSDNode>(AVL)) { 41681ad6265SDimitry Andric LegalAVL = CDAG.getConstant((ConstAVL->getZExtValue() + 1) / 2, MVT::i32); 41781ad6265SDimitry Andric } else { 41881ad6265SDimitry Andric auto ConstOne = CDAG.getConstant(1, MVT::i32); 41981ad6265SDimitry Andric auto PlusOne = CDAG.getNode(ISD::ADD, MVT::i32, {AVL, ConstOne}); 42081ad6265SDimitry Andric LegalAVL = CDAG.getNode(ISD::SRL, MVT::i32, {PlusOne, ConstOne}); 42181ad6265SDimitry Andric } 42281ad6265SDimitry Andric } 42381ad6265SDimitry Andric 42481ad6265SDimitry Andric SDValue AnnotatedLegalAVL = CDAG.annotateLegalAVL(LegalAVL); 42581ad6265SDimitry Andric 42681ad6265SDimitry Andric // Copy the operand list. 42781ad6265SDimitry Andric int NumOp = Op->getNumOperands(); 42881ad6265SDimitry Andric auto AVLPos = getAVLPos(Op->getOpcode()); 42981ad6265SDimitry Andric std::vector<SDValue> FixedOperands; 43081ad6265SDimitry Andric for (int i = 0; i < NumOp; ++i) { 43181ad6265SDimitry Andric if (AVLPos && (i == *AVLPos)) { 43281ad6265SDimitry Andric FixedOperands.push_back(AnnotatedLegalAVL); 43381ad6265SDimitry Andric continue; 43481ad6265SDimitry Andric } 43581ad6265SDimitry Andric FixedOperands.push_back(Op->getOperand(i)); 43681ad6265SDimitry Andric } 43781ad6265SDimitry Andric 43881ad6265SDimitry Andric // Clone the operation with fixed operands. 43981ad6265SDimitry Andric auto Flags = Op->getFlags(); 44081ad6265SDimitry Andric SDValue NewN = 44181ad6265SDimitry Andric CDAG.getNode(Op->getOpcode(), Op->getVTList(), FixedOperands, Flags); 44281ad6265SDimitry Andric return NewN; 44381ad6265SDimitry Andric } 444