104eeddc0SDimitry Andric //===-- VECustomDAG.h - VE Custom DAG Nodes ------------*- C++ -*-===// 204eeddc0SDimitry Andric // 304eeddc0SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 404eeddc0SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 504eeddc0SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 604eeddc0SDimitry Andric // 704eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 804eeddc0SDimitry Andric // 904eeddc0SDimitry Andric // This file defines the interfaces that VE uses to lower LLVM code into a 1004eeddc0SDimitry Andric // selection DAG. 1104eeddc0SDimitry Andric // 1204eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 1304eeddc0SDimitry Andric 1404eeddc0SDimitry Andric #include "VECustomDAG.h" 1504eeddc0SDimitry Andric 1604eeddc0SDimitry Andric #ifndef DEBUG_TYPE 1704eeddc0SDimitry Andric #define DEBUG_TYPE "vecustomdag" 1804eeddc0SDimitry Andric #endif 1904eeddc0SDimitry Andric 2004eeddc0SDimitry Andric namespace llvm { 2104eeddc0SDimitry Andric 2204eeddc0SDimitry Andric bool isPackedVectorType(EVT SomeVT) { 2304eeddc0SDimitry Andric if (!SomeVT.isVector()) 2404eeddc0SDimitry Andric return false; 2504eeddc0SDimitry Andric return SomeVT.getVectorNumElements() > StandardVectorWidth; 2604eeddc0SDimitry Andric } 2704eeddc0SDimitry Andric 28*81ad6265SDimitry Andric MVT splitVectorType(MVT VT) { 29*81ad6265SDimitry Andric if (!VT.isVector()) 30*81ad6265SDimitry Andric return VT; 31*81ad6265SDimitry Andric return MVT::getVectorVT(VT.getVectorElementType(), StandardVectorWidth); 32*81ad6265SDimitry Andric } 33*81ad6265SDimitry Andric 34*81ad6265SDimitry Andric MVT getLegalVectorType(Packing P, MVT ElemVT) { 35*81ad6265SDimitry Andric return MVT::getVectorVT(ElemVT, P == Packing::Normal ? StandardVectorWidth 36*81ad6265SDimitry Andric : PackedVectorWidth); 37*81ad6265SDimitry Andric } 38*81ad6265SDimitry Andric 39*81ad6265SDimitry Andric Packing getTypePacking(EVT VT) { 40*81ad6265SDimitry Andric assert(VT.isVector()); 41*81ad6265SDimitry Andric return isPackedVectorType(VT) ? Packing::Dense : Packing::Normal; 42*81ad6265SDimitry Andric } 43*81ad6265SDimitry Andric 44*81ad6265SDimitry Andric bool isMaskType(EVT SomeVT) { 45*81ad6265SDimitry Andric if (!SomeVT.isVector()) 46*81ad6265SDimitry Andric return false; 47*81ad6265SDimitry Andric return SomeVT.getVectorElementType() == MVT::i1; 48*81ad6265SDimitry Andric } 49*81ad6265SDimitry Andric 50*81ad6265SDimitry Andric bool isMaskArithmetic(SDValue Op) { 51*81ad6265SDimitry Andric switch (Op.getOpcode()) { 52*81ad6265SDimitry Andric default: 53*81ad6265SDimitry Andric return false; 54*81ad6265SDimitry Andric case ISD::AND: 55*81ad6265SDimitry Andric case ISD::XOR: 56*81ad6265SDimitry Andric case ISD::OR: 57*81ad6265SDimitry Andric return isMaskType(Op.getValueType()); 58*81ad6265SDimitry Andric } 59*81ad6265SDimitry Andric } 60*81ad6265SDimitry Andric 6104eeddc0SDimitry Andric /// \returns the VVP_* SDNode opcode corresponsing to \p OC. 6204eeddc0SDimitry Andric Optional<unsigned> getVVPOpcode(unsigned Opcode) { 6304eeddc0SDimitry Andric switch (Opcode) { 64*81ad6265SDimitry Andric case ISD::MLOAD: 65*81ad6265SDimitry Andric return VEISD::VVP_LOAD; 66*81ad6265SDimitry Andric case ISD::MSTORE: 67*81ad6265SDimitry Andric return VEISD::VVP_STORE; 6804eeddc0SDimitry Andric #define HANDLE_VP_TO_VVP(VPOPC, VVPNAME) \ 6904eeddc0SDimitry Andric case ISD::VPOPC: \ 7004eeddc0SDimitry Andric return VEISD::VVPNAME; 7104eeddc0SDimitry Andric #define ADD_VVP_OP(VVPNAME, SDNAME) \ 7204eeddc0SDimitry Andric case VEISD::VVPNAME: \ 7304eeddc0SDimitry Andric case ISD::SDNAME: \ 7404eeddc0SDimitry Andric return VEISD::VVPNAME; 7504eeddc0SDimitry Andric #include "VVPNodes.def" 76*81ad6265SDimitry Andric // TODO: Map those in VVPNodes.def too 77*81ad6265SDimitry Andric case ISD::EXPERIMENTAL_VP_STRIDED_LOAD: 78*81ad6265SDimitry Andric return VEISD::VVP_LOAD; 79*81ad6265SDimitry Andric case ISD::EXPERIMENTAL_VP_STRIDED_STORE: 80*81ad6265SDimitry Andric return VEISD::VVP_STORE; 8104eeddc0SDimitry Andric } 8204eeddc0SDimitry Andric return None; 8304eeddc0SDimitry Andric } 8404eeddc0SDimitry Andric 85*81ad6265SDimitry Andric bool maySafelyIgnoreMask(SDValue Op) { 86*81ad6265SDimitry Andric auto VVPOpc = getVVPOpcode(Op->getOpcode()); 87*81ad6265SDimitry Andric auto Opc = VVPOpc.value_or(Op->getOpcode()); 88*81ad6265SDimitry Andric 89*81ad6265SDimitry Andric switch (Opc) { 90*81ad6265SDimitry Andric case VEISD::VVP_SDIV: 91*81ad6265SDimitry Andric case VEISD::VVP_UDIV: 92*81ad6265SDimitry Andric case VEISD::VVP_FDIV: 93*81ad6265SDimitry Andric case VEISD::VVP_SELECT: 94*81ad6265SDimitry Andric return false; 95*81ad6265SDimitry Andric 96*81ad6265SDimitry Andric default: 97*81ad6265SDimitry Andric return true; 98*81ad6265SDimitry Andric } 99*81ad6265SDimitry Andric } 100*81ad6265SDimitry Andric 101*81ad6265SDimitry Andric bool supportsPackedMode(unsigned Opcode, EVT IdiomVT) { 102*81ad6265SDimitry Andric bool IsPackedOp = isPackedVectorType(IdiomVT); 103*81ad6265SDimitry Andric bool IsMaskOp = isMaskType(IdiomVT); 104*81ad6265SDimitry Andric switch (Opcode) { 105*81ad6265SDimitry Andric default: 106*81ad6265SDimitry Andric return false; 107*81ad6265SDimitry Andric 108*81ad6265SDimitry Andric case VEISD::VEC_BROADCAST: 109*81ad6265SDimitry Andric return true; 110*81ad6265SDimitry Andric #define REGISTER_PACKED(VVP_NAME) case VEISD::VVP_NAME: 111*81ad6265SDimitry Andric #include "VVPNodes.def" 112*81ad6265SDimitry Andric return IsPackedOp && !IsMaskOp; 113*81ad6265SDimitry Andric } 114*81ad6265SDimitry Andric } 115*81ad6265SDimitry Andric 116*81ad6265SDimitry Andric bool isPackingSupportOpcode(unsigned Opc) { 117*81ad6265SDimitry Andric switch (Opc) { 118*81ad6265SDimitry Andric case VEISD::VEC_PACK: 119*81ad6265SDimitry Andric case VEISD::VEC_UNPACK_LO: 120*81ad6265SDimitry Andric case VEISD::VEC_UNPACK_HI: 121*81ad6265SDimitry Andric return true; 122*81ad6265SDimitry Andric } 123*81ad6265SDimitry Andric return false; 124*81ad6265SDimitry Andric } 125*81ad6265SDimitry Andric 126*81ad6265SDimitry Andric bool isVVPOrVEC(unsigned Opcode) { 127*81ad6265SDimitry Andric switch (Opcode) { 128*81ad6265SDimitry Andric case VEISD::VEC_BROADCAST: 129*81ad6265SDimitry Andric #define ADD_VVP_OP(VVPNAME, ...) case VEISD::VVPNAME: 130*81ad6265SDimitry Andric #include "VVPNodes.def" 131*81ad6265SDimitry Andric return true; 132*81ad6265SDimitry Andric } 133*81ad6265SDimitry Andric return false; 134*81ad6265SDimitry Andric } 135*81ad6265SDimitry Andric 136*81ad6265SDimitry Andric bool isVVPUnaryOp(unsigned VVPOpcode) { 137*81ad6265SDimitry Andric switch (VVPOpcode) { 138*81ad6265SDimitry Andric #define ADD_UNARY_VVP_OP(VVPNAME, ...) \ 139*81ad6265SDimitry Andric case VEISD::VVPNAME: \ 140*81ad6265SDimitry Andric return true; 141*81ad6265SDimitry Andric #include "VVPNodes.def" 142*81ad6265SDimitry Andric } 143*81ad6265SDimitry Andric return false; 144*81ad6265SDimitry Andric } 145*81ad6265SDimitry Andric 14604eeddc0SDimitry Andric bool isVVPBinaryOp(unsigned VVPOpcode) { 14704eeddc0SDimitry Andric switch (VVPOpcode) { 14804eeddc0SDimitry Andric #define ADD_BINARY_VVP_OP(VVPNAME, ...) \ 14904eeddc0SDimitry Andric case VEISD::VVPNAME: \ 15004eeddc0SDimitry Andric return true; 15104eeddc0SDimitry Andric #include "VVPNodes.def" 15204eeddc0SDimitry Andric } 15304eeddc0SDimitry Andric return false; 15404eeddc0SDimitry Andric } 15504eeddc0SDimitry Andric 156*81ad6265SDimitry Andric bool isVVPReductionOp(unsigned Opcode) { 157*81ad6265SDimitry Andric switch (Opcode) { 158*81ad6265SDimitry Andric #define ADD_REDUCE_VVP_OP(VVP_NAME, SDNAME) case VEISD::VVP_NAME: 159*81ad6265SDimitry Andric #include "VVPNodes.def" 160*81ad6265SDimitry Andric return true; 161*81ad6265SDimitry Andric } 162*81ad6265SDimitry Andric return false; 163*81ad6265SDimitry Andric } 164*81ad6265SDimitry Andric 165*81ad6265SDimitry Andric // Return the AVL operand position for this VVP or VEC Op. 166*81ad6265SDimitry Andric Optional<int> getAVLPos(unsigned Opc) { 167*81ad6265SDimitry Andric // This is only available for VP SDNodes 168*81ad6265SDimitry Andric auto PosOpt = ISD::getVPExplicitVectorLengthIdx(Opc); 169*81ad6265SDimitry Andric if (PosOpt) 170*81ad6265SDimitry Andric return *PosOpt; 171*81ad6265SDimitry Andric 172*81ad6265SDimitry Andric // VVP Opcodes. 173*81ad6265SDimitry Andric if (isVVPBinaryOp(Opc)) 174*81ad6265SDimitry Andric return 3; 175*81ad6265SDimitry Andric 176*81ad6265SDimitry Andric // VM Opcodes. 177*81ad6265SDimitry Andric switch (Opc) { 178*81ad6265SDimitry Andric case VEISD::VEC_BROADCAST: 179*81ad6265SDimitry Andric return 1; 180*81ad6265SDimitry Andric case VEISD::VVP_SELECT: 181*81ad6265SDimitry Andric return 3; 182*81ad6265SDimitry Andric case VEISD::VVP_LOAD: 183*81ad6265SDimitry Andric return 4; 184*81ad6265SDimitry Andric case VEISD::VVP_STORE: 185*81ad6265SDimitry Andric return 5; 186*81ad6265SDimitry Andric } 187*81ad6265SDimitry Andric 188*81ad6265SDimitry Andric return None; 189*81ad6265SDimitry Andric } 190*81ad6265SDimitry Andric 191*81ad6265SDimitry Andric Optional<int> getMaskPos(unsigned Opc) { 192*81ad6265SDimitry Andric // This is only available for VP SDNodes 193*81ad6265SDimitry Andric auto PosOpt = ISD::getVPMaskIdx(Opc); 194*81ad6265SDimitry Andric if (PosOpt) 195*81ad6265SDimitry Andric return *PosOpt; 196*81ad6265SDimitry Andric 197*81ad6265SDimitry Andric // VVP Opcodes. 198*81ad6265SDimitry Andric if (isVVPBinaryOp(Opc)) 199*81ad6265SDimitry Andric return 2; 200*81ad6265SDimitry Andric 201*81ad6265SDimitry Andric // Other opcodes. 202*81ad6265SDimitry Andric switch (Opc) { 203*81ad6265SDimitry Andric case ISD::MSTORE: 204*81ad6265SDimitry Andric return 4; 205*81ad6265SDimitry Andric case ISD::MLOAD: 206*81ad6265SDimitry Andric return 3; 207*81ad6265SDimitry Andric case VEISD::VVP_SELECT: 208*81ad6265SDimitry Andric return 2; 209*81ad6265SDimitry Andric } 210*81ad6265SDimitry Andric 211*81ad6265SDimitry Andric return None; 212*81ad6265SDimitry Andric } 213*81ad6265SDimitry Andric 214*81ad6265SDimitry Andric bool isLegalAVL(SDValue AVL) { return AVL->getOpcode() == VEISD::LEGALAVL; } 215*81ad6265SDimitry Andric 216*81ad6265SDimitry Andric /// Node Properties { 217*81ad6265SDimitry Andric 218*81ad6265SDimitry Andric SDValue getNodeChain(SDValue Op) { 219*81ad6265SDimitry Andric if (MemSDNode *MemN = dyn_cast<MemSDNode>(Op.getNode())) 220*81ad6265SDimitry Andric return MemN->getChain(); 221*81ad6265SDimitry Andric 222*81ad6265SDimitry Andric switch (Op->getOpcode()) { 223*81ad6265SDimitry Andric case VEISD::VVP_LOAD: 224*81ad6265SDimitry Andric case VEISD::VVP_STORE: 225*81ad6265SDimitry Andric return Op->getOperand(0); 226*81ad6265SDimitry Andric } 227*81ad6265SDimitry Andric return SDValue(); 228*81ad6265SDimitry Andric } 229*81ad6265SDimitry Andric 230*81ad6265SDimitry Andric SDValue getMemoryPtr(SDValue Op) { 231*81ad6265SDimitry Andric if (auto *MemN = dyn_cast<MemSDNode>(Op.getNode())) 232*81ad6265SDimitry Andric return MemN->getBasePtr(); 233*81ad6265SDimitry Andric 234*81ad6265SDimitry Andric switch (Op->getOpcode()) { 235*81ad6265SDimitry Andric case VEISD::VVP_LOAD: 236*81ad6265SDimitry Andric return Op->getOperand(1); 237*81ad6265SDimitry Andric case VEISD::VVP_STORE: 238*81ad6265SDimitry Andric return Op->getOperand(2); 239*81ad6265SDimitry Andric } 240*81ad6265SDimitry Andric return SDValue(); 241*81ad6265SDimitry Andric } 242*81ad6265SDimitry Andric 243*81ad6265SDimitry Andric Optional<EVT> getIdiomaticVectorType(SDNode *Op) { 244*81ad6265SDimitry Andric unsigned OC = Op->getOpcode(); 245*81ad6265SDimitry Andric 246*81ad6265SDimitry Andric // For memory ops -> the transfered data type 247*81ad6265SDimitry Andric if (auto MemN = dyn_cast<MemSDNode>(Op)) 248*81ad6265SDimitry Andric return MemN->getMemoryVT(); 249*81ad6265SDimitry Andric 250*81ad6265SDimitry Andric switch (OC) { 251*81ad6265SDimitry Andric // Standard ISD. 252*81ad6265SDimitry Andric case ISD::SELECT: // not aliased with VVP_SELECT 253*81ad6265SDimitry Andric case ISD::CONCAT_VECTORS: 254*81ad6265SDimitry Andric case ISD::EXTRACT_SUBVECTOR: 255*81ad6265SDimitry Andric case ISD::VECTOR_SHUFFLE: 256*81ad6265SDimitry Andric case ISD::BUILD_VECTOR: 257*81ad6265SDimitry Andric case ISD::SCALAR_TO_VECTOR: 258*81ad6265SDimitry Andric return Op->getValueType(0); 259*81ad6265SDimitry Andric } 260*81ad6265SDimitry Andric 261*81ad6265SDimitry Andric // Translate to VVP where possible. 262*81ad6265SDimitry Andric unsigned OriginalOC = OC; 263*81ad6265SDimitry Andric if (auto VVPOpc = getVVPOpcode(OC)) 264*81ad6265SDimitry Andric OC = *VVPOpc; 265*81ad6265SDimitry Andric 266*81ad6265SDimitry Andric if (isVVPReductionOp(OC)) 267*81ad6265SDimitry Andric return Op->getOperand(hasReductionStartParam(OriginalOC) ? 1 : 0) 268*81ad6265SDimitry Andric .getValueType(); 269*81ad6265SDimitry Andric 270*81ad6265SDimitry Andric switch (OC) { 271*81ad6265SDimitry Andric default: 272*81ad6265SDimitry Andric case VEISD::VVP_SETCC: 273*81ad6265SDimitry Andric return Op->getOperand(0).getValueType(); 274*81ad6265SDimitry Andric 275*81ad6265SDimitry Andric case VEISD::VVP_SELECT: 276*81ad6265SDimitry Andric #define ADD_BINARY_VVP_OP(VVP_NAME, ...) case VEISD::VVP_NAME: 277*81ad6265SDimitry Andric #include "VVPNodes.def" 278*81ad6265SDimitry Andric return Op->getValueType(0); 279*81ad6265SDimitry Andric 280*81ad6265SDimitry Andric case VEISD::VVP_LOAD: 281*81ad6265SDimitry Andric return Op->getValueType(0); 282*81ad6265SDimitry Andric 283*81ad6265SDimitry Andric case VEISD::VVP_STORE: 284*81ad6265SDimitry Andric return Op->getOperand(1)->getValueType(0); 285*81ad6265SDimitry Andric 286*81ad6265SDimitry Andric // VEC 287*81ad6265SDimitry Andric case VEISD::VEC_BROADCAST: 288*81ad6265SDimitry Andric return Op->getValueType(0); 289*81ad6265SDimitry Andric } 290*81ad6265SDimitry Andric } 291*81ad6265SDimitry Andric 292*81ad6265SDimitry Andric SDValue getLoadStoreStride(SDValue Op, VECustomDAG &CDAG) { 293*81ad6265SDimitry Andric switch (Op->getOpcode()) { 294*81ad6265SDimitry Andric case VEISD::VVP_STORE: 295*81ad6265SDimitry Andric return Op->getOperand(3); 296*81ad6265SDimitry Andric case VEISD::VVP_LOAD: 297*81ad6265SDimitry Andric return Op->getOperand(2); 298*81ad6265SDimitry Andric } 299*81ad6265SDimitry Andric 300*81ad6265SDimitry Andric if (auto *StoreN = dyn_cast<VPStridedStoreSDNode>(Op.getNode())) 301*81ad6265SDimitry Andric return StoreN->getStride(); 302*81ad6265SDimitry Andric if (auto *StoreN = dyn_cast<VPStridedLoadSDNode>(Op.getNode())) 303*81ad6265SDimitry Andric return StoreN->getStride(); 304*81ad6265SDimitry Andric 305*81ad6265SDimitry Andric if (isa<MemSDNode>(Op.getNode())) { 306*81ad6265SDimitry Andric // Regular MLOAD/MSTORE/LOAD/STORE 307*81ad6265SDimitry Andric // No stride argument -> use the contiguous element size as stride. 308*81ad6265SDimitry Andric uint64_t ElemStride = getIdiomaticVectorType(Op.getNode()) 309*81ad6265SDimitry Andric ->getVectorElementType() 310*81ad6265SDimitry Andric .getStoreSize(); 311*81ad6265SDimitry Andric return CDAG.getConstant(ElemStride, MVT::i64); 312*81ad6265SDimitry Andric } 313*81ad6265SDimitry Andric return SDValue(); 314*81ad6265SDimitry Andric } 315*81ad6265SDimitry Andric 316*81ad6265SDimitry Andric SDValue getGatherScatterIndex(SDValue Op) { 317*81ad6265SDimitry Andric if (auto *N = dyn_cast<MaskedGatherScatterSDNode>(Op.getNode())) 318*81ad6265SDimitry Andric return N->getIndex(); 319*81ad6265SDimitry Andric if (auto *N = dyn_cast<VPGatherScatterSDNode>(Op.getNode())) 320*81ad6265SDimitry Andric return N->getIndex(); 321*81ad6265SDimitry Andric return SDValue(); 322*81ad6265SDimitry Andric } 323*81ad6265SDimitry Andric 324*81ad6265SDimitry Andric SDValue getGatherScatterScale(SDValue Op) { 325*81ad6265SDimitry Andric if (auto *N = dyn_cast<MaskedGatherScatterSDNode>(Op.getNode())) 326*81ad6265SDimitry Andric return N->getScale(); 327*81ad6265SDimitry Andric if (auto *N = dyn_cast<VPGatherScatterSDNode>(Op.getNode())) 328*81ad6265SDimitry Andric return N->getScale(); 329*81ad6265SDimitry Andric return SDValue(); 330*81ad6265SDimitry Andric } 331*81ad6265SDimitry Andric 332*81ad6265SDimitry Andric SDValue getStoredValue(SDValue Op) { 333*81ad6265SDimitry Andric switch (Op->getOpcode()) { 334*81ad6265SDimitry Andric case ISD::EXPERIMENTAL_VP_STRIDED_STORE: 335*81ad6265SDimitry Andric case VEISD::VVP_STORE: 336*81ad6265SDimitry Andric return Op->getOperand(1); 337*81ad6265SDimitry Andric } 338*81ad6265SDimitry Andric if (auto *StoreN = dyn_cast<StoreSDNode>(Op.getNode())) 339*81ad6265SDimitry Andric return StoreN->getValue(); 340*81ad6265SDimitry Andric if (auto *StoreN = dyn_cast<MaskedStoreSDNode>(Op.getNode())) 341*81ad6265SDimitry Andric return StoreN->getValue(); 342*81ad6265SDimitry Andric if (auto *StoreN = dyn_cast<VPStridedStoreSDNode>(Op.getNode())) 343*81ad6265SDimitry Andric return StoreN->getValue(); 344*81ad6265SDimitry Andric if (auto *StoreN = dyn_cast<VPStoreSDNode>(Op.getNode())) 345*81ad6265SDimitry Andric return StoreN->getValue(); 346*81ad6265SDimitry Andric if (auto *StoreN = dyn_cast<MaskedScatterSDNode>(Op.getNode())) 347*81ad6265SDimitry Andric return StoreN->getValue(); 348*81ad6265SDimitry Andric if (auto *StoreN = dyn_cast<VPScatterSDNode>(Op.getNode())) 349*81ad6265SDimitry Andric return StoreN->getValue(); 350*81ad6265SDimitry Andric return SDValue(); 351*81ad6265SDimitry Andric } 352*81ad6265SDimitry Andric 353*81ad6265SDimitry Andric SDValue getNodePassthru(SDValue Op) { 354*81ad6265SDimitry Andric if (auto *N = dyn_cast<MaskedLoadSDNode>(Op.getNode())) 355*81ad6265SDimitry Andric return N->getPassThru(); 356*81ad6265SDimitry Andric if (auto *N = dyn_cast<MaskedGatherSDNode>(Op.getNode())) 357*81ad6265SDimitry Andric return N->getPassThru(); 358*81ad6265SDimitry Andric 359*81ad6265SDimitry Andric return SDValue(); 360*81ad6265SDimitry Andric } 361*81ad6265SDimitry Andric 362*81ad6265SDimitry Andric bool hasReductionStartParam(unsigned OPC) { 363*81ad6265SDimitry Andric // TODO: Ordered reduction opcodes. 364*81ad6265SDimitry Andric if (ISD::isVPReduction(OPC)) 365*81ad6265SDimitry Andric return true; 366*81ad6265SDimitry Andric return false; 367*81ad6265SDimitry Andric } 368*81ad6265SDimitry Andric 369*81ad6265SDimitry Andric unsigned getScalarReductionOpcode(unsigned VVPOC, bool IsMask) { 370*81ad6265SDimitry Andric assert(!IsMask && "Mask reduction isel"); 371*81ad6265SDimitry Andric 372*81ad6265SDimitry Andric switch (VVPOC) { 373*81ad6265SDimitry Andric #define HANDLE_VVP_REDUCE_TO_SCALAR(VVP_RED_ISD, REDUCE_ISD) \ 374*81ad6265SDimitry Andric case VEISD::VVP_RED_ISD: \ 375*81ad6265SDimitry Andric return ISD::REDUCE_ISD; 376*81ad6265SDimitry Andric #include "VVPNodes.def" 377*81ad6265SDimitry Andric default: 378*81ad6265SDimitry Andric break; 379*81ad6265SDimitry Andric } 380*81ad6265SDimitry Andric llvm_unreachable("Cannot not scalarize this reduction Opcode!"); 381*81ad6265SDimitry Andric } 382*81ad6265SDimitry Andric 383*81ad6265SDimitry Andric /// } Node Properties 384*81ad6265SDimitry Andric 385*81ad6265SDimitry Andric SDValue getNodeAVL(SDValue Op) { 386*81ad6265SDimitry Andric auto PosOpt = getAVLPos(Op->getOpcode()); 387*81ad6265SDimitry Andric return PosOpt ? Op->getOperand(*PosOpt) : SDValue(); 388*81ad6265SDimitry Andric } 389*81ad6265SDimitry Andric 390*81ad6265SDimitry Andric SDValue getNodeMask(SDValue Op) { 391*81ad6265SDimitry Andric auto PosOpt = getMaskPos(Op->getOpcode()); 392*81ad6265SDimitry Andric return PosOpt ? Op->getOperand(*PosOpt) : SDValue(); 393*81ad6265SDimitry Andric } 394*81ad6265SDimitry Andric 395*81ad6265SDimitry Andric std::pair<SDValue, bool> getAnnotatedNodeAVL(SDValue Op) { 396*81ad6265SDimitry Andric SDValue AVL = getNodeAVL(Op); 397*81ad6265SDimitry Andric if (!AVL) 398*81ad6265SDimitry Andric return {SDValue(), true}; 399*81ad6265SDimitry Andric if (isLegalAVL(AVL)) 400*81ad6265SDimitry Andric return {AVL->getOperand(0), true}; 401*81ad6265SDimitry Andric return {AVL, false}; 402*81ad6265SDimitry Andric } 403*81ad6265SDimitry Andric 40404eeddc0SDimitry Andric SDValue VECustomDAG::getConstant(uint64_t Val, EVT VT, bool IsTarget, 40504eeddc0SDimitry Andric bool IsOpaque) const { 40604eeddc0SDimitry Andric return DAG.getConstant(Val, DL, VT, IsTarget, IsOpaque); 40704eeddc0SDimitry Andric } 40804eeddc0SDimitry Andric 409*81ad6265SDimitry Andric SDValue VECustomDAG::getConstantMask(Packing Packing, bool AllTrue) const { 410*81ad6265SDimitry Andric auto MaskVT = getLegalVectorType(Packing, MVT::i1); 411*81ad6265SDimitry Andric 412*81ad6265SDimitry Andric // VEISelDAGtoDAG will replace this pattern with the constant-true VM. 413*81ad6265SDimitry Andric auto TrueVal = DAG.getConstant(-1, DL, MVT::i32); 414*81ad6265SDimitry Andric auto AVL = getConstant(MaskVT.getVectorNumElements(), MVT::i32); 415*81ad6265SDimitry Andric auto Res = getNode(VEISD::VEC_BROADCAST, MaskVT, {TrueVal, AVL}); 416*81ad6265SDimitry Andric if (AllTrue) 417*81ad6265SDimitry Andric return Res; 418*81ad6265SDimitry Andric 419*81ad6265SDimitry Andric return DAG.getNOT(DL, Res, Res.getValueType()); 420*81ad6265SDimitry Andric } 421*81ad6265SDimitry Andric 422*81ad6265SDimitry Andric SDValue VECustomDAG::getMaskBroadcast(EVT ResultVT, SDValue Scalar, 423*81ad6265SDimitry Andric SDValue AVL) const { 424*81ad6265SDimitry Andric // Constant mask splat. 425*81ad6265SDimitry Andric if (auto BcConst = dyn_cast<ConstantSDNode>(Scalar)) 426*81ad6265SDimitry Andric return getConstantMask(getTypePacking(ResultVT), 427*81ad6265SDimitry Andric BcConst->getSExtValue() != 0); 428*81ad6265SDimitry Andric 429*81ad6265SDimitry Andric // Expand the broadcast to a vector comparison. 430*81ad6265SDimitry Andric auto ScalarBoolVT = Scalar.getSimpleValueType(); 431*81ad6265SDimitry Andric assert(ScalarBoolVT == MVT::i32); 432*81ad6265SDimitry Andric 433*81ad6265SDimitry Andric // Cast to i32 ty. 434*81ad6265SDimitry Andric SDValue CmpElem = DAG.getSExtOrTrunc(Scalar, DL, MVT::i32); 435*81ad6265SDimitry Andric unsigned ElemCount = ResultVT.getVectorNumElements(); 436*81ad6265SDimitry Andric MVT CmpVecTy = MVT::getVectorVT(ScalarBoolVT, ElemCount); 437*81ad6265SDimitry Andric 438*81ad6265SDimitry Andric // Broadcast to vector. 439*81ad6265SDimitry Andric SDValue BCVec = 440*81ad6265SDimitry Andric DAG.getNode(VEISD::VEC_BROADCAST, DL, CmpVecTy, {CmpElem, AVL}); 441*81ad6265SDimitry Andric SDValue ZeroVec = 442*81ad6265SDimitry Andric getBroadcast(CmpVecTy, {DAG.getConstant(0, DL, ScalarBoolVT)}, AVL); 443*81ad6265SDimitry Andric 444*81ad6265SDimitry Andric MVT BoolVecTy = MVT::getVectorVT(MVT::i1, ElemCount); 445*81ad6265SDimitry Andric 446*81ad6265SDimitry Andric // Broadcast(Data) != Broadcast(0) 447*81ad6265SDimitry Andric // TODO: Use a VVP operation for this. 448*81ad6265SDimitry Andric return DAG.getSetCC(DL, BoolVecTy, BCVec, ZeroVec, ISD::CondCode::SETNE); 449*81ad6265SDimitry Andric } 450*81ad6265SDimitry Andric 45104eeddc0SDimitry Andric SDValue VECustomDAG::getBroadcast(EVT ResultVT, SDValue Scalar, 45204eeddc0SDimitry Andric SDValue AVL) const { 45304eeddc0SDimitry Andric assert(ResultVT.isVector()); 45404eeddc0SDimitry Andric auto ScaVT = Scalar.getValueType(); 455*81ad6265SDimitry Andric 456*81ad6265SDimitry Andric if (isMaskType(ResultVT)) 457*81ad6265SDimitry Andric return getMaskBroadcast(ResultVT, Scalar, AVL); 45804eeddc0SDimitry Andric 45904eeddc0SDimitry Andric if (isPackedVectorType(ResultVT)) { 46004eeddc0SDimitry Andric // v512x packed mode broadcast 46104eeddc0SDimitry Andric // Replicate the scalar reg (f32 or i32) onto the opposing half of the full 46204eeddc0SDimitry Andric // scalar register. If it's an I64 type, assume that this has already 46304eeddc0SDimitry Andric // happened. 46404eeddc0SDimitry Andric if (ScaVT == MVT::f32) { 46504eeddc0SDimitry Andric Scalar = getNode(VEISD::REPL_F32, MVT::i64, Scalar); 46604eeddc0SDimitry Andric } else if (ScaVT == MVT::i32) { 46704eeddc0SDimitry Andric Scalar = getNode(VEISD::REPL_I32, MVT::i64, Scalar); 46804eeddc0SDimitry Andric } 46904eeddc0SDimitry Andric } 47004eeddc0SDimitry Andric 47104eeddc0SDimitry Andric return getNode(VEISD::VEC_BROADCAST, ResultVT, {Scalar, AVL}); 47204eeddc0SDimitry Andric } 47304eeddc0SDimitry Andric 474*81ad6265SDimitry Andric SDValue VECustomDAG::annotateLegalAVL(SDValue AVL) const { 475*81ad6265SDimitry Andric if (isLegalAVL(AVL)) 476*81ad6265SDimitry Andric return AVL; 477*81ad6265SDimitry Andric return getNode(VEISD::LEGALAVL, AVL.getValueType(), AVL); 478*81ad6265SDimitry Andric } 479*81ad6265SDimitry Andric 480*81ad6265SDimitry Andric SDValue VECustomDAG::getUnpack(EVT DestVT, SDValue Vec, PackElem Part, 481*81ad6265SDimitry Andric SDValue AVL) const { 482*81ad6265SDimitry Andric assert(getAnnotatedNodeAVL(AVL).second && "Expected a pack-legalized AVL"); 483*81ad6265SDimitry Andric 484*81ad6265SDimitry Andric // TODO: Peek through VEC_PACK and VEC_BROADCAST(REPL_<sth> ..) operands. 485*81ad6265SDimitry Andric unsigned OC = 486*81ad6265SDimitry Andric (Part == PackElem::Lo) ? VEISD::VEC_UNPACK_LO : VEISD::VEC_UNPACK_HI; 487*81ad6265SDimitry Andric return DAG.getNode(OC, DL, DestVT, Vec, AVL); 488*81ad6265SDimitry Andric } 489*81ad6265SDimitry Andric 490*81ad6265SDimitry Andric SDValue VECustomDAG::getPack(EVT DestVT, SDValue LoVec, SDValue HiVec, 491*81ad6265SDimitry Andric SDValue AVL) const { 492*81ad6265SDimitry Andric assert(getAnnotatedNodeAVL(AVL).second && "Expected a pack-legalized AVL"); 493*81ad6265SDimitry Andric 494*81ad6265SDimitry Andric // TODO: Peek through VEC_UNPACK_LO|HI operands. 495*81ad6265SDimitry Andric return DAG.getNode(VEISD::VEC_PACK, DL, DestVT, LoVec, HiVec, AVL); 496*81ad6265SDimitry Andric } 497*81ad6265SDimitry Andric 498*81ad6265SDimitry Andric VETargetMasks VECustomDAG::getTargetSplitMask(SDValue RawMask, SDValue RawAVL, 499*81ad6265SDimitry Andric PackElem Part) const { 500*81ad6265SDimitry Andric // Adjust AVL for this part 501*81ad6265SDimitry Andric SDValue NewAVL; 502*81ad6265SDimitry Andric SDValue OneV = getConstant(1, MVT::i32); 503*81ad6265SDimitry Andric if (Part == PackElem::Hi) 504*81ad6265SDimitry Andric NewAVL = getNode(ISD::ADD, MVT::i32, {RawAVL, OneV}); 505*81ad6265SDimitry Andric else 506*81ad6265SDimitry Andric NewAVL = RawAVL; 507*81ad6265SDimitry Andric NewAVL = getNode(ISD::SRL, MVT::i32, {NewAVL, OneV}); 508*81ad6265SDimitry Andric 509*81ad6265SDimitry Andric NewAVL = annotateLegalAVL(NewAVL); 510*81ad6265SDimitry Andric 511*81ad6265SDimitry Andric // Legalize Mask (unpack or all-true) 512*81ad6265SDimitry Andric SDValue NewMask; 513*81ad6265SDimitry Andric if (!RawMask) 514*81ad6265SDimitry Andric NewMask = getConstantMask(Packing::Normal, true); 515*81ad6265SDimitry Andric else 516*81ad6265SDimitry Andric NewMask = getUnpack(MVT::v256i1, RawMask, Part, NewAVL); 517*81ad6265SDimitry Andric 518*81ad6265SDimitry Andric return VETargetMasks(NewMask, NewAVL); 519*81ad6265SDimitry Andric } 520*81ad6265SDimitry Andric 521*81ad6265SDimitry Andric SDValue VECustomDAG::getSplitPtrOffset(SDValue Ptr, SDValue ByteStride, 522*81ad6265SDimitry Andric PackElem Part) const { 523*81ad6265SDimitry Andric // High starts at base ptr but has more significant bits in the 64bit vector 524*81ad6265SDimitry Andric // element. 525*81ad6265SDimitry Andric if (Part == PackElem::Hi) 526*81ad6265SDimitry Andric return Ptr; 527*81ad6265SDimitry Andric return getNode(ISD::ADD, MVT::i64, {Ptr, ByteStride}); 528*81ad6265SDimitry Andric } 529*81ad6265SDimitry Andric 530*81ad6265SDimitry Andric SDValue VECustomDAG::getSplitPtrStride(SDValue PackStride) const { 531*81ad6265SDimitry Andric if (auto ConstBytes = dyn_cast<ConstantSDNode>(PackStride)) 532*81ad6265SDimitry Andric return getConstant(2 * ConstBytes->getSExtValue(), MVT::i64); 533*81ad6265SDimitry Andric return getNode(ISD::SHL, MVT::i64, {PackStride, getConstant(1, MVT::i32)}); 534*81ad6265SDimitry Andric } 535*81ad6265SDimitry Andric 536*81ad6265SDimitry Andric SDValue VECustomDAG::getGatherScatterAddress(SDValue BasePtr, SDValue Scale, 537*81ad6265SDimitry Andric SDValue Index, SDValue Mask, 538*81ad6265SDimitry Andric SDValue AVL) const { 539*81ad6265SDimitry Andric EVT IndexVT = Index.getValueType(); 540*81ad6265SDimitry Andric 541*81ad6265SDimitry Andric // Apply scale. 542*81ad6265SDimitry Andric SDValue ScaledIndex; 543*81ad6265SDimitry Andric if (!Scale || isOneConstant(Scale)) 544*81ad6265SDimitry Andric ScaledIndex = Index; 545*81ad6265SDimitry Andric else { 546*81ad6265SDimitry Andric SDValue ScaleBroadcast = getBroadcast(IndexVT, Scale, AVL); 547*81ad6265SDimitry Andric ScaledIndex = 548*81ad6265SDimitry Andric getNode(VEISD::VVP_MUL, IndexVT, {Index, ScaleBroadcast, Mask, AVL}); 549*81ad6265SDimitry Andric } 550*81ad6265SDimitry Andric 551*81ad6265SDimitry Andric // Add basePtr. 552*81ad6265SDimitry Andric if (isNullConstant(BasePtr)) 553*81ad6265SDimitry Andric return ScaledIndex; 554*81ad6265SDimitry Andric 555*81ad6265SDimitry Andric // re-constitute pointer vector (basePtr + index * scale) 556*81ad6265SDimitry Andric SDValue BaseBroadcast = getBroadcast(IndexVT, BasePtr, AVL); 557*81ad6265SDimitry Andric auto ResPtr = 558*81ad6265SDimitry Andric getNode(VEISD::VVP_ADD, IndexVT, {BaseBroadcast, ScaledIndex, Mask, AVL}); 559*81ad6265SDimitry Andric return ResPtr; 560*81ad6265SDimitry Andric } 561*81ad6265SDimitry Andric 562*81ad6265SDimitry Andric SDValue VECustomDAG::getLegalReductionOpVVP(unsigned VVPOpcode, EVT ResVT, 563*81ad6265SDimitry Andric SDValue StartV, SDValue VectorV, 564*81ad6265SDimitry Andric SDValue Mask, SDValue AVL, 565*81ad6265SDimitry Andric SDNodeFlags Flags) const { 566*81ad6265SDimitry Andric 567*81ad6265SDimitry Andric // Optionally attach the start param with a scalar op (where it is 568*81ad6265SDimitry Andric // unsupported). 569*81ad6265SDimitry Andric bool scalarizeStartParam = StartV && !hasReductionStartParam(VVPOpcode); 570*81ad6265SDimitry Andric bool IsMaskReduction = isMaskType(VectorV.getValueType()); 571*81ad6265SDimitry Andric assert(!IsMaskReduction && "TODO Implement"); 572*81ad6265SDimitry Andric auto AttachStartValue = [&](SDValue ReductionResV) { 573*81ad6265SDimitry Andric if (!scalarizeStartParam) 574*81ad6265SDimitry Andric return ReductionResV; 575*81ad6265SDimitry Andric auto ScalarOC = getScalarReductionOpcode(VVPOpcode, IsMaskReduction); 576*81ad6265SDimitry Andric return getNode(ScalarOC, ResVT, {StartV, ReductionResV}); 577*81ad6265SDimitry Andric }; 578*81ad6265SDimitry Andric 579*81ad6265SDimitry Andric // Fixup: Always Use sequential 'fmul' reduction. 580*81ad6265SDimitry Andric if (!scalarizeStartParam && StartV) { 581*81ad6265SDimitry Andric assert(hasReductionStartParam(VVPOpcode)); 582*81ad6265SDimitry Andric return AttachStartValue( 583*81ad6265SDimitry Andric getNode(VVPOpcode, ResVT, {StartV, VectorV, Mask, AVL}, Flags)); 584*81ad6265SDimitry Andric } else 585*81ad6265SDimitry Andric return AttachStartValue( 586*81ad6265SDimitry Andric getNode(VVPOpcode, ResVT, {VectorV, Mask, AVL}, Flags)); 587*81ad6265SDimitry Andric } 588*81ad6265SDimitry Andric 58904eeddc0SDimitry Andric } // namespace llvm 590