| //===-- VECustomDAG.h - VE Custom DAG Nodes ------------*- C++ -*-===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This file defines the interfaces that VE uses to lower LLVM code into a | 
 | // selection DAG. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "VECustomDAG.h" | 
 |  | 
 | #ifndef DEBUG_TYPE | 
 | #define DEBUG_TYPE "vecustomdag" | 
 | #endif | 
 |  | 
 | namespace llvm { | 
 |  | 
 | bool isPackedVectorType(EVT SomeVT) { | 
 |   if (!SomeVT.isVector()) | 
 |     return false; | 
 |   return SomeVT.getVectorNumElements() > StandardVectorWidth; | 
 | } | 
 |  | 
 | MVT splitVectorType(MVT VT) { | 
 |   if (!VT.isVector()) | 
 |     return VT; | 
 |   return MVT::getVectorVT(VT.getVectorElementType(), StandardVectorWidth); | 
 | } | 
 |  | 
 | MVT getLegalVectorType(Packing P, MVT ElemVT) { | 
 |   return MVT::getVectorVT(ElemVT, P == Packing::Normal ? StandardVectorWidth | 
 |                                                        : PackedVectorWidth); | 
 | } | 
 |  | 
 | Packing getTypePacking(EVT VT) { | 
 |   assert(VT.isVector()); | 
 |   return isPackedVectorType(VT) ? Packing::Dense : Packing::Normal; | 
 | } | 
 |  | 
 | bool isMaskType(EVT SomeVT) { | 
 |   if (!SomeVT.isVector()) | 
 |     return false; | 
 |   return SomeVT.getVectorElementType() == MVT::i1; | 
 | } | 
 |  | 
 | bool isMaskArithmetic(SDValue Op) { | 
 |   switch (Op.getOpcode()) { | 
 |   default: | 
 |     return false; | 
 |   case ISD::AND: | 
 |   case ISD::XOR: | 
 |   case ISD::OR: | 
 |     return isMaskType(Op.getValueType()); | 
 |   } | 
 | } | 
 |  | 
 | /// \returns the VVP_* SDNode opcode corresponsing to \p OC. | 
 | std::optional<unsigned> getVVPOpcode(unsigned Opcode) { | 
 |   switch (Opcode) { | 
 |   case ISD::MLOAD: | 
 |     return VEISD::VVP_LOAD; | 
 |   case ISD::MSTORE: | 
 |     return VEISD::VVP_STORE; | 
 | #define HANDLE_VP_TO_VVP(VPOPC, VVPNAME)                                       \ | 
 |   case ISD::VPOPC:                                                             \ | 
 |     return VEISD::VVPNAME; | 
 | #define ADD_VVP_OP(VVPNAME, SDNAME)                                            \ | 
 |   case VEISD::VVPNAME:                                                         \ | 
 |   case ISD::SDNAME:                                                            \ | 
 |     return VEISD::VVPNAME; | 
 | #include "VVPNodes.def" | 
 |   // TODO: Map those in VVPNodes.def too | 
 |   case ISD::EXPERIMENTAL_VP_STRIDED_LOAD: | 
 |     return VEISD::VVP_LOAD; | 
 |   case ISD::EXPERIMENTAL_VP_STRIDED_STORE: | 
 |     return VEISD::VVP_STORE; | 
 |   } | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | bool maySafelyIgnoreMask(SDValue Op) { | 
 |   auto VVPOpc = getVVPOpcode(Op->getOpcode()); | 
 |   auto Opc = VVPOpc.value_or(Op->getOpcode()); | 
 |  | 
 |   switch (Opc) { | 
 |   case VEISD::VVP_SDIV: | 
 |   case VEISD::VVP_UDIV: | 
 |   case VEISD::VVP_FDIV: | 
 |   case VEISD::VVP_SELECT: | 
 |     return false; | 
 |  | 
 |   default: | 
 |     return true; | 
 |   } | 
 | } | 
 |  | 
 | bool supportsPackedMode(unsigned Opcode, EVT IdiomVT) { | 
 |   bool IsPackedOp = isPackedVectorType(IdiomVT); | 
 |   bool IsMaskOp = isMaskType(IdiomVT); | 
 |   switch (Opcode) { | 
 |   default: | 
 |     return false; | 
 |  | 
 |   case VEISD::VEC_BROADCAST: | 
 |     return true; | 
 | #define REGISTER_PACKED(VVP_NAME) case VEISD::VVP_NAME: | 
 | #include "VVPNodes.def" | 
 |     return IsPackedOp && !IsMaskOp; | 
 |   } | 
 | } | 
 |  | 
 | bool isPackingSupportOpcode(unsigned Opc) { | 
 |   switch (Opc) { | 
 |   case VEISD::VEC_PACK: | 
 |   case VEISD::VEC_UNPACK_LO: | 
 |   case VEISD::VEC_UNPACK_HI: | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | bool isVVPOrVEC(unsigned Opcode) { | 
 |   switch (Opcode) { | 
 |   case VEISD::VEC_BROADCAST: | 
 | #define ADD_VVP_OP(VVPNAME, ...) case VEISD::VVPNAME: | 
 | #include "VVPNodes.def" | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | bool isVVPUnaryOp(unsigned VVPOpcode) { | 
 |   switch (VVPOpcode) { | 
 | #define ADD_UNARY_VVP_OP(VVPNAME, ...)                                         \ | 
 |   case VEISD::VVPNAME:                                                         \ | 
 |     return true; | 
 | #include "VVPNodes.def" | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | bool isVVPBinaryOp(unsigned VVPOpcode) { | 
 |   switch (VVPOpcode) { | 
 | #define ADD_BINARY_VVP_OP(VVPNAME, ...)                                        \ | 
 |   case VEISD::VVPNAME:                                                         \ | 
 |     return true; | 
 | #include "VVPNodes.def" | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | bool isVVPReductionOp(unsigned Opcode) { | 
 |   switch (Opcode) { | 
 | #define ADD_REDUCE_VVP_OP(VVP_NAME, SDNAME) case VEISD::VVP_NAME: | 
 | #include "VVPNodes.def" | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | // Return the AVL operand position for this VVP or VEC Op. | 
 | std::optional<int> getAVLPos(unsigned Opc) { | 
 |   // This is only available for VP SDNodes | 
 |   auto PosOpt = ISD::getVPExplicitVectorLengthIdx(Opc); | 
 |   if (PosOpt) | 
 |     return *PosOpt; | 
 |  | 
 |   // VVP Opcodes. | 
 |   if (isVVPBinaryOp(Opc)) | 
 |     return 3; | 
 |  | 
 |   // VM Opcodes. | 
 |   switch (Opc) { | 
 |   case VEISD::VEC_BROADCAST: | 
 |     return 1; | 
 |   case VEISD::VVP_SELECT: | 
 |     return 3; | 
 |   case VEISD::VVP_LOAD: | 
 |     return 4; | 
 |   case VEISD::VVP_STORE: | 
 |     return 5; | 
 |   } | 
 |  | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | std::optional<int> getMaskPos(unsigned Opc) { | 
 |   // This is only available for VP SDNodes | 
 |   auto PosOpt = ISD::getVPMaskIdx(Opc); | 
 |   if (PosOpt) | 
 |     return *PosOpt; | 
 |  | 
 |   // VVP Opcodes. | 
 |   if (isVVPBinaryOp(Opc)) | 
 |     return 2; | 
 |  | 
 |   // Other opcodes. | 
 |   switch (Opc) { | 
 |   case ISD::MSTORE: | 
 |     return 4; | 
 |   case ISD::MLOAD: | 
 |     return 3; | 
 |   case VEISD::VVP_SELECT: | 
 |     return 2; | 
 |   } | 
 |  | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | bool isLegalAVL(SDValue AVL) { return AVL->getOpcode() == VEISD::LEGALAVL; } | 
 |  | 
 | /// Node Properties { | 
 |  | 
 | SDValue getNodeChain(SDValue Op) { | 
 |   if (MemSDNode *MemN = dyn_cast<MemSDNode>(Op.getNode())) | 
 |     return MemN->getChain(); | 
 |  | 
 |   switch (Op->getOpcode()) { | 
 |   case VEISD::VVP_LOAD: | 
 |   case VEISD::VVP_STORE: | 
 |     return Op->getOperand(0); | 
 |   } | 
 |   return SDValue(); | 
 | } | 
 |  | 
 | SDValue getMemoryPtr(SDValue Op) { | 
 |   if (auto *MemN = dyn_cast<MemSDNode>(Op.getNode())) | 
 |     return MemN->getBasePtr(); | 
 |  | 
 |   switch (Op->getOpcode()) { | 
 |   case VEISD::VVP_LOAD: | 
 |     return Op->getOperand(1); | 
 |   case VEISD::VVP_STORE: | 
 |     return Op->getOperand(2); | 
 |   } | 
 |   return SDValue(); | 
 | } | 
 |  | 
 | std::optional<EVT> getIdiomaticVectorType(SDNode *Op) { | 
 |   unsigned OC = Op->getOpcode(); | 
 |  | 
 |   // For memory ops -> the transfered data type | 
 |   if (auto MemN = dyn_cast<MemSDNode>(Op)) | 
 |     return MemN->getMemoryVT(); | 
 |  | 
 |   switch (OC) { | 
 |   // Standard ISD. | 
 |   case ISD::SELECT: // not aliased with VVP_SELECT | 
 |   case ISD::CONCAT_VECTORS: | 
 |   case ISD::EXTRACT_SUBVECTOR: | 
 |   case ISD::VECTOR_SHUFFLE: | 
 |   case ISD::BUILD_VECTOR: | 
 |   case ISD::SCALAR_TO_VECTOR: | 
 |     return Op->getValueType(0); | 
 |   } | 
 |  | 
 |   // Translate to VVP where possible. | 
 |   unsigned OriginalOC = OC; | 
 |   if (auto VVPOpc = getVVPOpcode(OC)) | 
 |     OC = *VVPOpc; | 
 |  | 
 |   if (isVVPReductionOp(OC)) | 
 |     return Op->getOperand(hasReductionStartParam(OriginalOC) ? 1 : 0) | 
 |         .getValueType(); | 
 |  | 
 |   switch (OC) { | 
 |   default: | 
 |   case VEISD::VVP_SETCC: | 
 |     return Op->getOperand(0).getValueType(); | 
 |  | 
 |   case VEISD::VVP_SELECT: | 
 | #define ADD_BINARY_VVP_OP(VVP_NAME, ...) case VEISD::VVP_NAME: | 
 | #include "VVPNodes.def" | 
 |     return Op->getValueType(0); | 
 |  | 
 |   case VEISD::VVP_LOAD: | 
 |     return Op->getValueType(0); | 
 |  | 
 |   case VEISD::VVP_STORE: | 
 |     return Op->getOperand(1)->getValueType(0); | 
 |  | 
 |   // VEC | 
 |   case VEISD::VEC_BROADCAST: | 
 |     return Op->getValueType(0); | 
 |   } | 
 | } | 
 |  | 
 | SDValue getLoadStoreStride(SDValue Op, VECustomDAG &CDAG) { | 
 |   switch (Op->getOpcode()) { | 
 |   case VEISD::VVP_STORE: | 
 |     return Op->getOperand(3); | 
 |   case VEISD::VVP_LOAD: | 
 |     return Op->getOperand(2); | 
 |   } | 
 |  | 
 |   if (auto *StoreN = dyn_cast<VPStridedStoreSDNode>(Op.getNode())) | 
 |     return StoreN->getStride(); | 
 |   if (auto *StoreN = dyn_cast<VPStridedLoadSDNode>(Op.getNode())) | 
 |     return StoreN->getStride(); | 
 |  | 
 |   if (isa<MemSDNode>(Op.getNode())) { | 
 |     // Regular MLOAD/MSTORE/LOAD/STORE | 
 |     // No stride argument -> use the contiguous element size as stride. | 
 |     uint64_t ElemStride = getIdiomaticVectorType(Op.getNode()) | 
 |                               ->getVectorElementType() | 
 |                               .getStoreSize(); | 
 |     return CDAG.getConstant(ElemStride, MVT::i64); | 
 |   } | 
 |   return SDValue(); | 
 | } | 
 |  | 
 | SDValue getGatherScatterIndex(SDValue Op) { | 
 |   if (auto *N = dyn_cast<MaskedGatherScatterSDNode>(Op.getNode())) | 
 |     return N->getIndex(); | 
 |   if (auto *N = dyn_cast<VPGatherScatterSDNode>(Op.getNode())) | 
 |     return N->getIndex(); | 
 |   return SDValue(); | 
 | } | 
 |  | 
 | SDValue getGatherScatterScale(SDValue Op) { | 
 |   if (auto *N = dyn_cast<MaskedGatherScatterSDNode>(Op.getNode())) | 
 |     return N->getScale(); | 
 |   if (auto *N = dyn_cast<VPGatherScatterSDNode>(Op.getNode())) | 
 |     return N->getScale(); | 
 |   return SDValue(); | 
 | } | 
 |  | 
 | SDValue getStoredValue(SDValue Op) { | 
 |   switch (Op->getOpcode()) { | 
 |   case ISD::EXPERIMENTAL_VP_STRIDED_STORE: | 
 |   case VEISD::VVP_STORE: | 
 |     return Op->getOperand(1); | 
 |   } | 
 |   if (auto *StoreN = dyn_cast<StoreSDNode>(Op.getNode())) | 
 |     return StoreN->getValue(); | 
 |   if (auto *StoreN = dyn_cast<MaskedStoreSDNode>(Op.getNode())) | 
 |     return StoreN->getValue(); | 
 |   if (auto *StoreN = dyn_cast<VPStridedStoreSDNode>(Op.getNode())) | 
 |     return StoreN->getValue(); | 
 |   if (auto *StoreN = dyn_cast<VPStoreSDNode>(Op.getNode())) | 
 |     return StoreN->getValue(); | 
 |   if (auto *StoreN = dyn_cast<MaskedScatterSDNode>(Op.getNode())) | 
 |     return StoreN->getValue(); | 
 |   if (auto *StoreN = dyn_cast<VPScatterSDNode>(Op.getNode())) | 
 |     return StoreN->getValue(); | 
 |   return SDValue(); | 
 | } | 
 |  | 
 | SDValue getNodePassthru(SDValue Op) { | 
 |   if (auto *N = dyn_cast<MaskedLoadSDNode>(Op.getNode())) | 
 |     return N->getPassThru(); | 
 |   if (auto *N = dyn_cast<MaskedGatherSDNode>(Op.getNode())) | 
 |     return N->getPassThru(); | 
 |  | 
 |   return SDValue(); | 
 | } | 
 |  | 
 | bool hasReductionStartParam(unsigned OPC) { | 
 |   // TODO: Ordered reduction opcodes. | 
 |   if (ISD::isVPReduction(OPC)) | 
 |     return true; | 
 |   return false; | 
 | } | 
 |  | 
 | unsigned getScalarReductionOpcode(unsigned VVPOC, bool IsMask) { | 
 |   assert(!IsMask && "Mask reduction isel"); | 
 |  | 
 |   switch (VVPOC) { | 
 | #define HANDLE_VVP_REDUCE_TO_SCALAR(VVP_RED_ISD, REDUCE_ISD)                   \ | 
 |   case VEISD::VVP_RED_ISD:                                                     \ | 
 |     return ISD::REDUCE_ISD; | 
 | #include "VVPNodes.def" | 
 |   default: | 
 |     break; | 
 |   } | 
 |   llvm_unreachable("Cannot not scalarize this reduction Opcode!"); | 
 | } | 
 |  | 
 | /// } Node Properties | 
 |  | 
 | SDValue getNodeAVL(SDValue Op) { | 
 |   auto PosOpt = getAVLPos(Op->getOpcode()); | 
 |   return PosOpt ? Op->getOperand(*PosOpt) : SDValue(); | 
 | } | 
 |  | 
 | SDValue getNodeMask(SDValue Op) { | 
 |   auto PosOpt = getMaskPos(Op->getOpcode()); | 
 |   return PosOpt ? Op->getOperand(*PosOpt) : SDValue(); | 
 | } | 
 |  | 
 | std::pair<SDValue, bool> getAnnotatedNodeAVL(SDValue Op) { | 
 |   SDValue AVL = getNodeAVL(Op); | 
 |   if (!AVL) | 
 |     return {SDValue(), true}; | 
 |   if (isLegalAVL(AVL)) | 
 |     return {AVL->getOperand(0), true}; | 
 |   return {AVL, false}; | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getConstant(uint64_t Val, EVT VT, bool IsTarget, | 
 |                                  bool IsOpaque) const { | 
 |   return DAG.getConstant(Val, DL, VT, IsTarget, IsOpaque); | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getConstantMask(Packing Packing, bool AllTrue) const { | 
 |   auto MaskVT = getLegalVectorType(Packing, MVT::i1); | 
 |  | 
 |   // VEISelDAGtoDAG will replace this pattern with the constant-true VM. | 
 |   auto TrueVal = DAG.getAllOnesConstant(DL, MVT::i32); | 
 |   auto AVL = getConstant(MaskVT.getVectorNumElements(), MVT::i32); | 
 |   auto Res = getNode(VEISD::VEC_BROADCAST, MaskVT, {TrueVal, AVL}); | 
 |   if (AllTrue) | 
 |     return Res; | 
 |  | 
 |   return DAG.getNOT(DL, Res, Res.getValueType()); | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getMaskBroadcast(EVT ResultVT, SDValue Scalar, | 
 |                                       SDValue AVL) const { | 
 |   // Constant mask splat. | 
 |   if (auto BcConst = dyn_cast<ConstantSDNode>(Scalar)) | 
 |     return getConstantMask(getTypePacking(ResultVT), | 
 |                            BcConst->getSExtValue() != 0); | 
 |  | 
 |   // Expand the broadcast to a vector comparison. | 
 |   auto ScalarBoolVT = Scalar.getSimpleValueType(); | 
 |   assert(ScalarBoolVT == MVT::i32); | 
 |  | 
 |   // Cast to i32 ty. | 
 |   SDValue CmpElem = DAG.getSExtOrTrunc(Scalar, DL, MVT::i32); | 
 |   unsigned ElemCount = ResultVT.getVectorNumElements(); | 
 |   MVT CmpVecTy = MVT::getVectorVT(ScalarBoolVT, ElemCount); | 
 |  | 
 |   // Broadcast to vector. | 
 |   SDValue BCVec = | 
 |       DAG.getNode(VEISD::VEC_BROADCAST, DL, CmpVecTy, {CmpElem, AVL}); | 
 |   SDValue ZeroVec = | 
 |       getBroadcast(CmpVecTy, {DAG.getConstant(0, DL, ScalarBoolVT)}, AVL); | 
 |  | 
 |   MVT BoolVecTy = MVT::getVectorVT(MVT::i1, ElemCount); | 
 |  | 
 |   // Broadcast(Data) != Broadcast(0) | 
 |   // TODO: Use a VVP operation for this. | 
 |   return DAG.getSetCC(DL, BoolVecTy, BCVec, ZeroVec, ISD::CondCode::SETNE); | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getBroadcast(EVT ResultVT, SDValue Scalar, | 
 |                                   SDValue AVL) const { | 
 |   assert(ResultVT.isVector()); | 
 |   auto ScaVT = Scalar.getValueType(); | 
 |  | 
 |   if (isMaskType(ResultVT)) | 
 |     return getMaskBroadcast(ResultVT, Scalar, AVL); | 
 |  | 
 |   if (isPackedVectorType(ResultVT)) { | 
 |     // v512x packed mode broadcast | 
 |     // Replicate the scalar reg (f32 or i32) onto the opposing half of the full | 
 |     // scalar register. If it's an I64 type, assume that this has already | 
 |     // happened. | 
 |     if (ScaVT == MVT::f32) { | 
 |       Scalar = getNode(VEISD::REPL_F32, MVT::i64, Scalar); | 
 |     } else if (ScaVT == MVT::i32) { | 
 |       Scalar = getNode(VEISD::REPL_I32, MVT::i64, Scalar); | 
 |     } | 
 |   } | 
 |  | 
 |   return getNode(VEISD::VEC_BROADCAST, ResultVT, {Scalar, AVL}); | 
 | } | 
 |  | 
 | SDValue VECustomDAG::annotateLegalAVL(SDValue AVL) const { | 
 |   if (isLegalAVL(AVL)) | 
 |     return AVL; | 
 |   return getNode(VEISD::LEGALAVL, AVL.getValueType(), AVL); | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getUnpack(EVT DestVT, SDValue Vec, PackElem Part, | 
 |                                SDValue AVL) const { | 
 |   assert(getAnnotatedNodeAVL(AVL).second && "Expected a pack-legalized AVL"); | 
 |  | 
 |   // TODO: Peek through VEC_PACK and VEC_BROADCAST(REPL_<sth> ..) operands. | 
 |   unsigned OC = | 
 |       (Part == PackElem::Lo) ? VEISD::VEC_UNPACK_LO : VEISD::VEC_UNPACK_HI; | 
 |   return DAG.getNode(OC, DL, DestVT, Vec, AVL); | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getPack(EVT DestVT, SDValue LoVec, SDValue HiVec, | 
 |                              SDValue AVL) const { | 
 |   assert(getAnnotatedNodeAVL(AVL).second && "Expected a pack-legalized AVL"); | 
 |  | 
 |   // TODO: Peek through VEC_UNPACK_LO|HI operands. | 
 |   return DAG.getNode(VEISD::VEC_PACK, DL, DestVT, LoVec, HiVec, AVL); | 
 | } | 
 |  | 
 | VETargetMasks VECustomDAG::getTargetSplitMask(SDValue RawMask, SDValue RawAVL, | 
 |                                               PackElem Part) const { | 
 |   // Adjust AVL for this part | 
 |   SDValue NewAVL; | 
 |   SDValue OneV = getConstant(1, MVT::i32); | 
 |   if (Part == PackElem::Hi) | 
 |     NewAVL = getNode(ISD::ADD, MVT::i32, {RawAVL, OneV}); | 
 |   else | 
 |     NewAVL = RawAVL; | 
 |   NewAVL = getNode(ISD::SRL, MVT::i32, {NewAVL, OneV}); | 
 |  | 
 |   NewAVL = annotateLegalAVL(NewAVL); | 
 |  | 
 |   // Legalize Mask (unpack or all-true) | 
 |   SDValue NewMask; | 
 |   if (!RawMask) | 
 |     NewMask = getConstantMask(Packing::Normal, true); | 
 |   else | 
 |     NewMask = getUnpack(MVT::v256i1, RawMask, Part, NewAVL); | 
 |  | 
 |   return VETargetMasks(NewMask, NewAVL); | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getSplitPtrOffset(SDValue Ptr, SDValue ByteStride, | 
 |                                        PackElem Part) const { | 
 |   // High starts at base ptr but has more significant bits in the 64bit vector | 
 |   // element. | 
 |   if (Part == PackElem::Hi) | 
 |     return Ptr; | 
 |   return getNode(ISD::ADD, MVT::i64, {Ptr, ByteStride}); | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getSplitPtrStride(SDValue PackStride) const { | 
 |   if (auto ConstBytes = dyn_cast<ConstantSDNode>(PackStride)) | 
 |     return getConstant(2 * ConstBytes->getSExtValue(), MVT::i64); | 
 |   return getNode(ISD::SHL, MVT::i64, {PackStride, getConstant(1, MVT::i32)}); | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getGatherScatterAddress(SDValue BasePtr, SDValue Scale, | 
 |                                              SDValue Index, SDValue Mask, | 
 |                                              SDValue AVL) const { | 
 |   EVT IndexVT = Index.getValueType(); | 
 |  | 
 |   // Apply scale. | 
 |   SDValue ScaledIndex; | 
 |   if (!Scale || isOneConstant(Scale)) | 
 |     ScaledIndex = Index; | 
 |   else { | 
 |     SDValue ScaleBroadcast = getBroadcast(IndexVT, Scale, AVL); | 
 |     ScaledIndex = | 
 |         getNode(VEISD::VVP_MUL, IndexVT, {Index, ScaleBroadcast, Mask, AVL}); | 
 |   } | 
 |  | 
 |   // Add basePtr. | 
 |   if (isNullConstant(BasePtr)) | 
 |     return ScaledIndex; | 
 |  | 
 |   // re-constitute pointer vector (basePtr + index * scale) | 
 |   SDValue BaseBroadcast = getBroadcast(IndexVT, BasePtr, AVL); | 
 |   auto ResPtr = | 
 |       getNode(VEISD::VVP_ADD, IndexVT, {BaseBroadcast, ScaledIndex, Mask, AVL}); | 
 |   return ResPtr; | 
 | } | 
 |  | 
 | SDValue VECustomDAG::getLegalReductionOpVVP(unsigned VVPOpcode, EVT ResVT, | 
 |                                             SDValue StartV, SDValue VectorV, | 
 |                                             SDValue Mask, SDValue AVL, | 
 |                                             SDNodeFlags Flags) const { | 
 |  | 
 |   // Optionally attach the start param with a scalar op (where it is | 
 |   // unsupported). | 
 |   bool scalarizeStartParam = StartV && !hasReductionStartParam(VVPOpcode); | 
 |   bool IsMaskReduction = isMaskType(VectorV.getValueType()); | 
 |   assert(!IsMaskReduction && "TODO Implement"); | 
 |   auto AttachStartValue = [&](SDValue ReductionResV) { | 
 |     if (!scalarizeStartParam) | 
 |       return ReductionResV; | 
 |     auto ScalarOC = getScalarReductionOpcode(VVPOpcode, IsMaskReduction); | 
 |     return getNode(ScalarOC, ResVT, {StartV, ReductionResV}); | 
 |   }; | 
 |  | 
 |   // Fixup: Always Use sequential 'fmul' reduction. | 
 |   if (!scalarizeStartParam && StartV) { | 
 |     assert(hasReductionStartParam(VVPOpcode)); | 
 |     return AttachStartValue( | 
 |         getNode(VVPOpcode, ResVT, {StartV, VectorV, Mask, AVL}, Flags)); | 
 |   } else | 
 |     return AttachStartValue( | 
 |         getNode(VVPOpcode, ResVT, {VectorV, Mask, AVL}, Flags)); | 
 | } | 
 |  | 
 | } // namespace llvm |