xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/VE/VECustomDAG.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 
isPackedVectorType(EVT SomeVT)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 
splitVectorType(MVT VT)2881ad6265SDimitry Andric MVT splitVectorType(MVT VT) {
2981ad6265SDimitry Andric   if (!VT.isVector())
3081ad6265SDimitry Andric     return VT;
3181ad6265SDimitry Andric   return MVT::getVectorVT(VT.getVectorElementType(), StandardVectorWidth);
3281ad6265SDimitry Andric }
3381ad6265SDimitry Andric 
getLegalVectorType(Packing P,MVT ElemVT)3481ad6265SDimitry Andric MVT getLegalVectorType(Packing P, MVT ElemVT) {
3581ad6265SDimitry Andric   return MVT::getVectorVT(ElemVT, P == Packing::Normal ? StandardVectorWidth
3681ad6265SDimitry Andric                                                        : PackedVectorWidth);
3781ad6265SDimitry Andric }
3881ad6265SDimitry Andric 
getTypePacking(EVT VT)3981ad6265SDimitry Andric Packing getTypePacking(EVT VT) {
4081ad6265SDimitry Andric   assert(VT.isVector());
4181ad6265SDimitry Andric   return isPackedVectorType(VT) ? Packing::Dense : Packing::Normal;
4281ad6265SDimitry Andric }
4381ad6265SDimitry Andric 
isMaskType(EVT SomeVT)4481ad6265SDimitry Andric bool isMaskType(EVT SomeVT) {
4581ad6265SDimitry Andric   if (!SomeVT.isVector())
4681ad6265SDimitry Andric     return false;
4781ad6265SDimitry Andric   return SomeVT.getVectorElementType() == MVT::i1;
4881ad6265SDimitry Andric }
4981ad6265SDimitry Andric 
isMaskArithmetic(SDValue Op)5081ad6265SDimitry Andric bool isMaskArithmetic(SDValue Op) {
5181ad6265SDimitry Andric   switch (Op.getOpcode()) {
5281ad6265SDimitry Andric   default:
5381ad6265SDimitry Andric     return false;
5481ad6265SDimitry Andric   case ISD::AND:
5581ad6265SDimitry Andric   case ISD::XOR:
5681ad6265SDimitry Andric   case ISD::OR:
5781ad6265SDimitry Andric     return isMaskType(Op.getValueType());
5881ad6265SDimitry Andric   }
5981ad6265SDimitry Andric }
6081ad6265SDimitry Andric 
6104eeddc0SDimitry Andric /// \returns the VVP_* SDNode opcode corresponsing to \p OC.
getVVPOpcode(unsigned Opcode)62*bdd1243dSDimitry Andric std::optional<unsigned> getVVPOpcode(unsigned Opcode) {
6304eeddc0SDimitry Andric   switch (Opcode) {
6481ad6265SDimitry Andric   case ISD::MLOAD:
6581ad6265SDimitry Andric     return VEISD::VVP_LOAD;
6681ad6265SDimitry Andric   case ISD::MSTORE:
6781ad6265SDimitry 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"
7681ad6265SDimitry Andric   // TODO: Map those in VVPNodes.def too
7781ad6265SDimitry Andric   case ISD::EXPERIMENTAL_VP_STRIDED_LOAD:
7881ad6265SDimitry Andric     return VEISD::VVP_LOAD;
7981ad6265SDimitry Andric   case ISD::EXPERIMENTAL_VP_STRIDED_STORE:
8081ad6265SDimitry Andric     return VEISD::VVP_STORE;
8104eeddc0SDimitry Andric   }
82*bdd1243dSDimitry Andric   return std::nullopt;
8304eeddc0SDimitry Andric }
8404eeddc0SDimitry Andric 
maySafelyIgnoreMask(SDValue Op)8581ad6265SDimitry Andric bool maySafelyIgnoreMask(SDValue Op) {
8681ad6265SDimitry Andric   auto VVPOpc = getVVPOpcode(Op->getOpcode());
8781ad6265SDimitry Andric   auto Opc = VVPOpc.value_or(Op->getOpcode());
8881ad6265SDimitry Andric 
8981ad6265SDimitry Andric   switch (Opc) {
9081ad6265SDimitry Andric   case VEISD::VVP_SDIV:
9181ad6265SDimitry Andric   case VEISD::VVP_UDIV:
9281ad6265SDimitry Andric   case VEISD::VVP_FDIV:
9381ad6265SDimitry Andric   case VEISD::VVP_SELECT:
9481ad6265SDimitry Andric     return false;
9581ad6265SDimitry Andric 
9681ad6265SDimitry Andric   default:
9781ad6265SDimitry Andric     return true;
9881ad6265SDimitry Andric   }
9981ad6265SDimitry Andric }
10081ad6265SDimitry Andric 
supportsPackedMode(unsigned Opcode,EVT IdiomVT)10181ad6265SDimitry Andric bool supportsPackedMode(unsigned Opcode, EVT IdiomVT) {
10281ad6265SDimitry Andric   bool IsPackedOp = isPackedVectorType(IdiomVT);
10381ad6265SDimitry Andric   bool IsMaskOp = isMaskType(IdiomVT);
10481ad6265SDimitry Andric   switch (Opcode) {
10581ad6265SDimitry Andric   default:
10681ad6265SDimitry Andric     return false;
10781ad6265SDimitry Andric 
10881ad6265SDimitry Andric   case VEISD::VEC_BROADCAST:
10981ad6265SDimitry Andric     return true;
11081ad6265SDimitry Andric #define REGISTER_PACKED(VVP_NAME) case VEISD::VVP_NAME:
11181ad6265SDimitry Andric #include "VVPNodes.def"
11281ad6265SDimitry Andric     return IsPackedOp && !IsMaskOp;
11381ad6265SDimitry Andric   }
11481ad6265SDimitry Andric }
11581ad6265SDimitry Andric 
isPackingSupportOpcode(unsigned Opc)11681ad6265SDimitry Andric bool isPackingSupportOpcode(unsigned Opc) {
11781ad6265SDimitry Andric   switch (Opc) {
11881ad6265SDimitry Andric   case VEISD::VEC_PACK:
11981ad6265SDimitry Andric   case VEISD::VEC_UNPACK_LO:
12081ad6265SDimitry Andric   case VEISD::VEC_UNPACK_HI:
12181ad6265SDimitry Andric     return true;
12281ad6265SDimitry Andric   }
12381ad6265SDimitry Andric   return false;
12481ad6265SDimitry Andric }
12581ad6265SDimitry Andric 
isVVPOrVEC(unsigned Opcode)12681ad6265SDimitry Andric bool isVVPOrVEC(unsigned Opcode) {
12781ad6265SDimitry Andric   switch (Opcode) {
12881ad6265SDimitry Andric   case VEISD::VEC_BROADCAST:
12981ad6265SDimitry Andric #define ADD_VVP_OP(VVPNAME, ...) case VEISD::VVPNAME:
13081ad6265SDimitry Andric #include "VVPNodes.def"
13181ad6265SDimitry Andric     return true;
13281ad6265SDimitry Andric   }
13381ad6265SDimitry Andric   return false;
13481ad6265SDimitry Andric }
13581ad6265SDimitry Andric 
isVVPUnaryOp(unsigned VVPOpcode)13681ad6265SDimitry Andric bool isVVPUnaryOp(unsigned VVPOpcode) {
13781ad6265SDimitry Andric   switch (VVPOpcode) {
13881ad6265SDimitry Andric #define ADD_UNARY_VVP_OP(VVPNAME, ...)                                         \
13981ad6265SDimitry Andric   case VEISD::VVPNAME:                                                         \
14081ad6265SDimitry Andric     return true;
14181ad6265SDimitry Andric #include "VVPNodes.def"
14281ad6265SDimitry Andric   }
14381ad6265SDimitry Andric   return false;
14481ad6265SDimitry Andric }
14581ad6265SDimitry Andric 
isVVPBinaryOp(unsigned VVPOpcode)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 
isVVPReductionOp(unsigned Opcode)15681ad6265SDimitry Andric bool isVVPReductionOp(unsigned Opcode) {
15781ad6265SDimitry Andric   switch (Opcode) {
15881ad6265SDimitry Andric #define ADD_REDUCE_VVP_OP(VVP_NAME, SDNAME) case VEISD::VVP_NAME:
15981ad6265SDimitry Andric #include "VVPNodes.def"
16081ad6265SDimitry Andric     return true;
16181ad6265SDimitry Andric   }
16281ad6265SDimitry Andric   return false;
16381ad6265SDimitry Andric }
16481ad6265SDimitry Andric 
16581ad6265SDimitry Andric // Return the AVL operand position for this VVP or VEC Op.
getAVLPos(unsigned Opc)166*bdd1243dSDimitry Andric std::optional<int> getAVLPos(unsigned Opc) {
16781ad6265SDimitry Andric   // This is only available for VP SDNodes
16881ad6265SDimitry Andric   auto PosOpt = ISD::getVPExplicitVectorLengthIdx(Opc);
16981ad6265SDimitry Andric   if (PosOpt)
17081ad6265SDimitry Andric     return *PosOpt;
17181ad6265SDimitry Andric 
17281ad6265SDimitry Andric   // VVP Opcodes.
17381ad6265SDimitry Andric   if (isVVPBinaryOp(Opc))
17481ad6265SDimitry Andric     return 3;
17581ad6265SDimitry Andric 
17681ad6265SDimitry Andric   // VM Opcodes.
17781ad6265SDimitry Andric   switch (Opc) {
17881ad6265SDimitry Andric   case VEISD::VEC_BROADCAST:
17981ad6265SDimitry Andric     return 1;
18081ad6265SDimitry Andric   case VEISD::VVP_SELECT:
18181ad6265SDimitry Andric     return 3;
18281ad6265SDimitry Andric   case VEISD::VVP_LOAD:
18381ad6265SDimitry Andric     return 4;
18481ad6265SDimitry Andric   case VEISD::VVP_STORE:
18581ad6265SDimitry Andric     return 5;
18681ad6265SDimitry Andric   }
18781ad6265SDimitry Andric 
188*bdd1243dSDimitry Andric   return std::nullopt;
18981ad6265SDimitry Andric }
19081ad6265SDimitry Andric 
getMaskPos(unsigned Opc)191*bdd1243dSDimitry Andric std::optional<int> getMaskPos(unsigned Opc) {
19281ad6265SDimitry Andric   // This is only available for VP SDNodes
19381ad6265SDimitry Andric   auto PosOpt = ISD::getVPMaskIdx(Opc);
19481ad6265SDimitry Andric   if (PosOpt)
19581ad6265SDimitry Andric     return *PosOpt;
19681ad6265SDimitry Andric 
19781ad6265SDimitry Andric   // VVP Opcodes.
19881ad6265SDimitry Andric   if (isVVPBinaryOp(Opc))
19981ad6265SDimitry Andric     return 2;
20081ad6265SDimitry Andric 
20181ad6265SDimitry Andric   // Other opcodes.
20281ad6265SDimitry Andric   switch (Opc) {
20381ad6265SDimitry Andric   case ISD::MSTORE:
20481ad6265SDimitry Andric     return 4;
20581ad6265SDimitry Andric   case ISD::MLOAD:
20681ad6265SDimitry Andric     return 3;
20781ad6265SDimitry Andric   case VEISD::VVP_SELECT:
20881ad6265SDimitry Andric     return 2;
20981ad6265SDimitry Andric   }
21081ad6265SDimitry Andric 
211*bdd1243dSDimitry Andric   return std::nullopt;
21281ad6265SDimitry Andric }
21381ad6265SDimitry Andric 
isLegalAVL(SDValue AVL)21481ad6265SDimitry Andric bool isLegalAVL(SDValue AVL) { return AVL->getOpcode() == VEISD::LEGALAVL; }
21581ad6265SDimitry Andric 
21681ad6265SDimitry Andric /// Node Properties {
21781ad6265SDimitry Andric 
getNodeChain(SDValue Op)21881ad6265SDimitry Andric SDValue getNodeChain(SDValue Op) {
21981ad6265SDimitry Andric   if (MemSDNode *MemN = dyn_cast<MemSDNode>(Op.getNode()))
22081ad6265SDimitry Andric     return MemN->getChain();
22181ad6265SDimitry Andric 
22281ad6265SDimitry Andric   switch (Op->getOpcode()) {
22381ad6265SDimitry Andric   case VEISD::VVP_LOAD:
22481ad6265SDimitry Andric   case VEISD::VVP_STORE:
22581ad6265SDimitry Andric     return Op->getOperand(0);
22681ad6265SDimitry Andric   }
22781ad6265SDimitry Andric   return SDValue();
22881ad6265SDimitry Andric }
22981ad6265SDimitry Andric 
getMemoryPtr(SDValue Op)23081ad6265SDimitry Andric SDValue getMemoryPtr(SDValue Op) {
23181ad6265SDimitry Andric   if (auto *MemN = dyn_cast<MemSDNode>(Op.getNode()))
23281ad6265SDimitry Andric     return MemN->getBasePtr();
23381ad6265SDimitry Andric 
23481ad6265SDimitry Andric   switch (Op->getOpcode()) {
23581ad6265SDimitry Andric   case VEISD::VVP_LOAD:
23681ad6265SDimitry Andric     return Op->getOperand(1);
23781ad6265SDimitry Andric   case VEISD::VVP_STORE:
23881ad6265SDimitry Andric     return Op->getOperand(2);
23981ad6265SDimitry Andric   }
24081ad6265SDimitry Andric   return SDValue();
24181ad6265SDimitry Andric }
24281ad6265SDimitry Andric 
getIdiomaticVectorType(SDNode * Op)243*bdd1243dSDimitry Andric std::optional<EVT> getIdiomaticVectorType(SDNode *Op) {
24481ad6265SDimitry Andric   unsigned OC = Op->getOpcode();
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric   // For memory ops -> the transfered data type
24781ad6265SDimitry Andric   if (auto MemN = dyn_cast<MemSDNode>(Op))
24881ad6265SDimitry Andric     return MemN->getMemoryVT();
24981ad6265SDimitry Andric 
25081ad6265SDimitry Andric   switch (OC) {
25181ad6265SDimitry Andric   // Standard ISD.
25281ad6265SDimitry Andric   case ISD::SELECT: // not aliased with VVP_SELECT
25381ad6265SDimitry Andric   case ISD::CONCAT_VECTORS:
25481ad6265SDimitry Andric   case ISD::EXTRACT_SUBVECTOR:
25581ad6265SDimitry Andric   case ISD::VECTOR_SHUFFLE:
25681ad6265SDimitry Andric   case ISD::BUILD_VECTOR:
25781ad6265SDimitry Andric   case ISD::SCALAR_TO_VECTOR:
25881ad6265SDimitry Andric     return Op->getValueType(0);
25981ad6265SDimitry Andric   }
26081ad6265SDimitry Andric 
26181ad6265SDimitry Andric   // Translate to VVP where possible.
26281ad6265SDimitry Andric   unsigned OriginalOC = OC;
26381ad6265SDimitry Andric   if (auto VVPOpc = getVVPOpcode(OC))
26481ad6265SDimitry Andric     OC = *VVPOpc;
26581ad6265SDimitry Andric 
26681ad6265SDimitry Andric   if (isVVPReductionOp(OC))
26781ad6265SDimitry Andric     return Op->getOperand(hasReductionStartParam(OriginalOC) ? 1 : 0)
26881ad6265SDimitry Andric         .getValueType();
26981ad6265SDimitry Andric 
27081ad6265SDimitry Andric   switch (OC) {
27181ad6265SDimitry Andric   default:
27281ad6265SDimitry Andric   case VEISD::VVP_SETCC:
27381ad6265SDimitry Andric     return Op->getOperand(0).getValueType();
27481ad6265SDimitry Andric 
27581ad6265SDimitry Andric   case VEISD::VVP_SELECT:
27681ad6265SDimitry Andric #define ADD_BINARY_VVP_OP(VVP_NAME, ...) case VEISD::VVP_NAME:
27781ad6265SDimitry Andric #include "VVPNodes.def"
27881ad6265SDimitry Andric     return Op->getValueType(0);
27981ad6265SDimitry Andric 
28081ad6265SDimitry Andric   case VEISD::VVP_LOAD:
28181ad6265SDimitry Andric     return Op->getValueType(0);
28281ad6265SDimitry Andric 
28381ad6265SDimitry Andric   case VEISD::VVP_STORE:
28481ad6265SDimitry Andric     return Op->getOperand(1)->getValueType(0);
28581ad6265SDimitry Andric 
28681ad6265SDimitry Andric   // VEC
28781ad6265SDimitry Andric   case VEISD::VEC_BROADCAST:
28881ad6265SDimitry Andric     return Op->getValueType(0);
28981ad6265SDimitry Andric   }
29081ad6265SDimitry Andric }
29181ad6265SDimitry Andric 
getLoadStoreStride(SDValue Op,VECustomDAG & CDAG)29281ad6265SDimitry Andric SDValue getLoadStoreStride(SDValue Op, VECustomDAG &CDAG) {
29381ad6265SDimitry Andric   switch (Op->getOpcode()) {
29481ad6265SDimitry Andric   case VEISD::VVP_STORE:
29581ad6265SDimitry Andric     return Op->getOperand(3);
29681ad6265SDimitry Andric   case VEISD::VVP_LOAD:
29781ad6265SDimitry Andric     return Op->getOperand(2);
29881ad6265SDimitry Andric   }
29981ad6265SDimitry Andric 
30081ad6265SDimitry Andric   if (auto *StoreN = dyn_cast<VPStridedStoreSDNode>(Op.getNode()))
30181ad6265SDimitry Andric     return StoreN->getStride();
30281ad6265SDimitry Andric   if (auto *StoreN = dyn_cast<VPStridedLoadSDNode>(Op.getNode()))
30381ad6265SDimitry Andric     return StoreN->getStride();
30481ad6265SDimitry Andric 
30581ad6265SDimitry Andric   if (isa<MemSDNode>(Op.getNode())) {
30681ad6265SDimitry Andric     // Regular MLOAD/MSTORE/LOAD/STORE
30781ad6265SDimitry Andric     // No stride argument -> use the contiguous element size as stride.
30881ad6265SDimitry Andric     uint64_t ElemStride = getIdiomaticVectorType(Op.getNode())
30981ad6265SDimitry Andric                               ->getVectorElementType()
31081ad6265SDimitry Andric                               .getStoreSize();
31181ad6265SDimitry Andric     return CDAG.getConstant(ElemStride, MVT::i64);
31281ad6265SDimitry Andric   }
31381ad6265SDimitry Andric   return SDValue();
31481ad6265SDimitry Andric }
31581ad6265SDimitry Andric 
getGatherScatterIndex(SDValue Op)31681ad6265SDimitry Andric SDValue getGatherScatterIndex(SDValue Op) {
31781ad6265SDimitry Andric   if (auto *N = dyn_cast<MaskedGatherScatterSDNode>(Op.getNode()))
31881ad6265SDimitry Andric     return N->getIndex();
31981ad6265SDimitry Andric   if (auto *N = dyn_cast<VPGatherScatterSDNode>(Op.getNode()))
32081ad6265SDimitry Andric     return N->getIndex();
32181ad6265SDimitry Andric   return SDValue();
32281ad6265SDimitry Andric }
32381ad6265SDimitry Andric 
getGatherScatterScale(SDValue Op)32481ad6265SDimitry Andric SDValue getGatherScatterScale(SDValue Op) {
32581ad6265SDimitry Andric   if (auto *N = dyn_cast<MaskedGatherScatterSDNode>(Op.getNode()))
32681ad6265SDimitry Andric     return N->getScale();
32781ad6265SDimitry Andric   if (auto *N = dyn_cast<VPGatherScatterSDNode>(Op.getNode()))
32881ad6265SDimitry Andric     return N->getScale();
32981ad6265SDimitry Andric   return SDValue();
33081ad6265SDimitry Andric }
33181ad6265SDimitry Andric 
getStoredValue(SDValue Op)33281ad6265SDimitry Andric SDValue getStoredValue(SDValue Op) {
33381ad6265SDimitry Andric   switch (Op->getOpcode()) {
33481ad6265SDimitry Andric   case ISD::EXPERIMENTAL_VP_STRIDED_STORE:
33581ad6265SDimitry Andric   case VEISD::VVP_STORE:
33681ad6265SDimitry Andric     return Op->getOperand(1);
33781ad6265SDimitry Andric   }
33881ad6265SDimitry Andric   if (auto *StoreN = dyn_cast<StoreSDNode>(Op.getNode()))
33981ad6265SDimitry Andric     return StoreN->getValue();
34081ad6265SDimitry Andric   if (auto *StoreN = dyn_cast<MaskedStoreSDNode>(Op.getNode()))
34181ad6265SDimitry Andric     return StoreN->getValue();
34281ad6265SDimitry Andric   if (auto *StoreN = dyn_cast<VPStridedStoreSDNode>(Op.getNode()))
34381ad6265SDimitry Andric     return StoreN->getValue();
34481ad6265SDimitry Andric   if (auto *StoreN = dyn_cast<VPStoreSDNode>(Op.getNode()))
34581ad6265SDimitry Andric     return StoreN->getValue();
34681ad6265SDimitry Andric   if (auto *StoreN = dyn_cast<MaskedScatterSDNode>(Op.getNode()))
34781ad6265SDimitry Andric     return StoreN->getValue();
34881ad6265SDimitry Andric   if (auto *StoreN = dyn_cast<VPScatterSDNode>(Op.getNode()))
34981ad6265SDimitry Andric     return StoreN->getValue();
35081ad6265SDimitry Andric   return SDValue();
35181ad6265SDimitry Andric }
35281ad6265SDimitry Andric 
getNodePassthru(SDValue Op)35381ad6265SDimitry Andric SDValue getNodePassthru(SDValue Op) {
35481ad6265SDimitry Andric   if (auto *N = dyn_cast<MaskedLoadSDNode>(Op.getNode()))
35581ad6265SDimitry Andric     return N->getPassThru();
35681ad6265SDimitry Andric   if (auto *N = dyn_cast<MaskedGatherSDNode>(Op.getNode()))
35781ad6265SDimitry Andric     return N->getPassThru();
35881ad6265SDimitry Andric 
35981ad6265SDimitry Andric   return SDValue();
36081ad6265SDimitry Andric }
36181ad6265SDimitry Andric 
hasReductionStartParam(unsigned OPC)36281ad6265SDimitry Andric bool hasReductionStartParam(unsigned OPC) {
36381ad6265SDimitry Andric   // TODO: Ordered reduction opcodes.
36481ad6265SDimitry Andric   if (ISD::isVPReduction(OPC))
36581ad6265SDimitry Andric     return true;
36681ad6265SDimitry Andric   return false;
36781ad6265SDimitry Andric }
36881ad6265SDimitry Andric 
getScalarReductionOpcode(unsigned VVPOC,bool IsMask)36981ad6265SDimitry Andric unsigned getScalarReductionOpcode(unsigned VVPOC, bool IsMask) {
37081ad6265SDimitry Andric   assert(!IsMask && "Mask reduction isel");
37181ad6265SDimitry Andric 
37281ad6265SDimitry Andric   switch (VVPOC) {
37381ad6265SDimitry Andric #define HANDLE_VVP_REDUCE_TO_SCALAR(VVP_RED_ISD, REDUCE_ISD)                   \
37481ad6265SDimitry Andric   case VEISD::VVP_RED_ISD:                                                     \
37581ad6265SDimitry Andric     return ISD::REDUCE_ISD;
37681ad6265SDimitry Andric #include "VVPNodes.def"
37781ad6265SDimitry Andric   default:
37881ad6265SDimitry Andric     break;
37981ad6265SDimitry Andric   }
38081ad6265SDimitry Andric   llvm_unreachable("Cannot not scalarize this reduction Opcode!");
38181ad6265SDimitry Andric }
38281ad6265SDimitry Andric 
38381ad6265SDimitry Andric /// } Node Properties
38481ad6265SDimitry Andric 
getNodeAVL(SDValue Op)38581ad6265SDimitry Andric SDValue getNodeAVL(SDValue Op) {
38681ad6265SDimitry Andric   auto PosOpt = getAVLPos(Op->getOpcode());
38781ad6265SDimitry Andric   return PosOpt ? Op->getOperand(*PosOpt) : SDValue();
38881ad6265SDimitry Andric }
38981ad6265SDimitry Andric 
getNodeMask(SDValue Op)39081ad6265SDimitry Andric SDValue getNodeMask(SDValue Op) {
39181ad6265SDimitry Andric   auto PosOpt = getMaskPos(Op->getOpcode());
39281ad6265SDimitry Andric   return PosOpt ? Op->getOperand(*PosOpt) : SDValue();
39381ad6265SDimitry Andric }
39481ad6265SDimitry Andric 
getAnnotatedNodeAVL(SDValue Op)39581ad6265SDimitry Andric std::pair<SDValue, bool> getAnnotatedNodeAVL(SDValue Op) {
39681ad6265SDimitry Andric   SDValue AVL = getNodeAVL(Op);
39781ad6265SDimitry Andric   if (!AVL)
39881ad6265SDimitry Andric     return {SDValue(), true};
39981ad6265SDimitry Andric   if (isLegalAVL(AVL))
40081ad6265SDimitry Andric     return {AVL->getOperand(0), true};
40181ad6265SDimitry Andric   return {AVL, false};
40281ad6265SDimitry Andric }
40381ad6265SDimitry Andric 
getConstant(uint64_t Val,EVT VT,bool IsTarget,bool IsOpaque) const40404eeddc0SDimitry 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 
getConstantMask(Packing Packing,bool AllTrue) const40981ad6265SDimitry Andric SDValue VECustomDAG::getConstantMask(Packing Packing, bool AllTrue) const {
41081ad6265SDimitry Andric   auto MaskVT = getLegalVectorType(Packing, MVT::i1);
41181ad6265SDimitry Andric 
41281ad6265SDimitry Andric   // VEISelDAGtoDAG will replace this pattern with the constant-true VM.
41381ad6265SDimitry Andric   auto TrueVal = DAG.getConstant(-1, DL, MVT::i32);
41481ad6265SDimitry Andric   auto AVL = getConstant(MaskVT.getVectorNumElements(), MVT::i32);
41581ad6265SDimitry Andric   auto Res = getNode(VEISD::VEC_BROADCAST, MaskVT, {TrueVal, AVL});
41681ad6265SDimitry Andric   if (AllTrue)
41781ad6265SDimitry Andric     return Res;
41881ad6265SDimitry Andric 
41981ad6265SDimitry Andric   return DAG.getNOT(DL, Res, Res.getValueType());
42081ad6265SDimitry Andric }
42181ad6265SDimitry Andric 
getMaskBroadcast(EVT ResultVT,SDValue Scalar,SDValue AVL) const42281ad6265SDimitry Andric SDValue VECustomDAG::getMaskBroadcast(EVT ResultVT, SDValue Scalar,
42381ad6265SDimitry Andric                                       SDValue AVL) const {
42481ad6265SDimitry Andric   // Constant mask splat.
42581ad6265SDimitry Andric   if (auto BcConst = dyn_cast<ConstantSDNode>(Scalar))
42681ad6265SDimitry Andric     return getConstantMask(getTypePacking(ResultVT),
42781ad6265SDimitry Andric                            BcConst->getSExtValue() != 0);
42881ad6265SDimitry Andric 
42981ad6265SDimitry Andric   // Expand the broadcast to a vector comparison.
43081ad6265SDimitry Andric   auto ScalarBoolVT = Scalar.getSimpleValueType();
43181ad6265SDimitry Andric   assert(ScalarBoolVT == MVT::i32);
43281ad6265SDimitry Andric 
43381ad6265SDimitry Andric   // Cast to i32 ty.
43481ad6265SDimitry Andric   SDValue CmpElem = DAG.getSExtOrTrunc(Scalar, DL, MVT::i32);
43581ad6265SDimitry Andric   unsigned ElemCount = ResultVT.getVectorNumElements();
43681ad6265SDimitry Andric   MVT CmpVecTy = MVT::getVectorVT(ScalarBoolVT, ElemCount);
43781ad6265SDimitry Andric 
43881ad6265SDimitry Andric   // Broadcast to vector.
43981ad6265SDimitry Andric   SDValue BCVec =
44081ad6265SDimitry Andric       DAG.getNode(VEISD::VEC_BROADCAST, DL, CmpVecTy, {CmpElem, AVL});
44181ad6265SDimitry Andric   SDValue ZeroVec =
44281ad6265SDimitry Andric       getBroadcast(CmpVecTy, {DAG.getConstant(0, DL, ScalarBoolVT)}, AVL);
44381ad6265SDimitry Andric 
44481ad6265SDimitry Andric   MVT BoolVecTy = MVT::getVectorVT(MVT::i1, ElemCount);
44581ad6265SDimitry Andric 
44681ad6265SDimitry Andric   // Broadcast(Data) != Broadcast(0)
44781ad6265SDimitry Andric   // TODO: Use a VVP operation for this.
44881ad6265SDimitry Andric   return DAG.getSetCC(DL, BoolVecTy, BCVec, ZeroVec, ISD::CondCode::SETNE);
44981ad6265SDimitry Andric }
45081ad6265SDimitry Andric 
getBroadcast(EVT ResultVT,SDValue Scalar,SDValue AVL) const45104eeddc0SDimitry Andric SDValue VECustomDAG::getBroadcast(EVT ResultVT, SDValue Scalar,
45204eeddc0SDimitry Andric                                   SDValue AVL) const {
45304eeddc0SDimitry Andric   assert(ResultVT.isVector());
45404eeddc0SDimitry Andric   auto ScaVT = Scalar.getValueType();
45581ad6265SDimitry Andric 
45681ad6265SDimitry Andric   if (isMaskType(ResultVT))
45781ad6265SDimitry 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 
annotateLegalAVL(SDValue AVL) const47481ad6265SDimitry Andric SDValue VECustomDAG::annotateLegalAVL(SDValue AVL) const {
47581ad6265SDimitry Andric   if (isLegalAVL(AVL))
47681ad6265SDimitry Andric     return AVL;
47781ad6265SDimitry Andric   return getNode(VEISD::LEGALAVL, AVL.getValueType(), AVL);
47881ad6265SDimitry Andric }
47981ad6265SDimitry Andric 
getUnpack(EVT DestVT,SDValue Vec,PackElem Part,SDValue AVL) const48081ad6265SDimitry Andric SDValue VECustomDAG::getUnpack(EVT DestVT, SDValue Vec, PackElem Part,
48181ad6265SDimitry Andric                                SDValue AVL) const {
48281ad6265SDimitry Andric   assert(getAnnotatedNodeAVL(AVL).second && "Expected a pack-legalized AVL");
48381ad6265SDimitry Andric 
48481ad6265SDimitry Andric   // TODO: Peek through VEC_PACK and VEC_BROADCAST(REPL_<sth> ..) operands.
48581ad6265SDimitry Andric   unsigned OC =
48681ad6265SDimitry Andric       (Part == PackElem::Lo) ? VEISD::VEC_UNPACK_LO : VEISD::VEC_UNPACK_HI;
48781ad6265SDimitry Andric   return DAG.getNode(OC, DL, DestVT, Vec, AVL);
48881ad6265SDimitry Andric }
48981ad6265SDimitry Andric 
getPack(EVT DestVT,SDValue LoVec,SDValue HiVec,SDValue AVL) const49081ad6265SDimitry Andric SDValue VECustomDAG::getPack(EVT DestVT, SDValue LoVec, SDValue HiVec,
49181ad6265SDimitry Andric                              SDValue AVL) const {
49281ad6265SDimitry Andric   assert(getAnnotatedNodeAVL(AVL).second && "Expected a pack-legalized AVL");
49381ad6265SDimitry Andric 
49481ad6265SDimitry Andric   // TODO: Peek through VEC_UNPACK_LO|HI operands.
49581ad6265SDimitry Andric   return DAG.getNode(VEISD::VEC_PACK, DL, DestVT, LoVec, HiVec, AVL);
49681ad6265SDimitry Andric }
49781ad6265SDimitry Andric 
getTargetSplitMask(SDValue RawMask,SDValue RawAVL,PackElem Part) const49881ad6265SDimitry Andric VETargetMasks VECustomDAG::getTargetSplitMask(SDValue RawMask, SDValue RawAVL,
49981ad6265SDimitry Andric                                               PackElem Part) const {
50081ad6265SDimitry Andric   // Adjust AVL for this part
50181ad6265SDimitry Andric   SDValue NewAVL;
50281ad6265SDimitry Andric   SDValue OneV = getConstant(1, MVT::i32);
50381ad6265SDimitry Andric   if (Part == PackElem::Hi)
50481ad6265SDimitry Andric     NewAVL = getNode(ISD::ADD, MVT::i32, {RawAVL, OneV});
50581ad6265SDimitry Andric   else
50681ad6265SDimitry Andric     NewAVL = RawAVL;
50781ad6265SDimitry Andric   NewAVL = getNode(ISD::SRL, MVT::i32, {NewAVL, OneV});
50881ad6265SDimitry Andric 
50981ad6265SDimitry Andric   NewAVL = annotateLegalAVL(NewAVL);
51081ad6265SDimitry Andric 
51181ad6265SDimitry Andric   // Legalize Mask (unpack or all-true)
51281ad6265SDimitry Andric   SDValue NewMask;
51381ad6265SDimitry Andric   if (!RawMask)
51481ad6265SDimitry Andric     NewMask = getConstantMask(Packing::Normal, true);
51581ad6265SDimitry Andric   else
51681ad6265SDimitry Andric     NewMask = getUnpack(MVT::v256i1, RawMask, Part, NewAVL);
51781ad6265SDimitry Andric 
51881ad6265SDimitry Andric   return VETargetMasks(NewMask, NewAVL);
51981ad6265SDimitry Andric }
52081ad6265SDimitry Andric 
getSplitPtrOffset(SDValue Ptr,SDValue ByteStride,PackElem Part) const52181ad6265SDimitry Andric SDValue VECustomDAG::getSplitPtrOffset(SDValue Ptr, SDValue ByteStride,
52281ad6265SDimitry Andric                                        PackElem Part) const {
52381ad6265SDimitry Andric   // High starts at base ptr but has more significant bits in the 64bit vector
52481ad6265SDimitry Andric   // element.
52581ad6265SDimitry Andric   if (Part == PackElem::Hi)
52681ad6265SDimitry Andric     return Ptr;
52781ad6265SDimitry Andric   return getNode(ISD::ADD, MVT::i64, {Ptr, ByteStride});
52881ad6265SDimitry Andric }
52981ad6265SDimitry Andric 
getSplitPtrStride(SDValue PackStride) const53081ad6265SDimitry Andric SDValue VECustomDAG::getSplitPtrStride(SDValue PackStride) const {
53181ad6265SDimitry Andric   if (auto ConstBytes = dyn_cast<ConstantSDNode>(PackStride))
53281ad6265SDimitry Andric     return getConstant(2 * ConstBytes->getSExtValue(), MVT::i64);
53381ad6265SDimitry Andric   return getNode(ISD::SHL, MVT::i64, {PackStride, getConstant(1, MVT::i32)});
53481ad6265SDimitry Andric }
53581ad6265SDimitry Andric 
getGatherScatterAddress(SDValue BasePtr,SDValue Scale,SDValue Index,SDValue Mask,SDValue AVL) const53681ad6265SDimitry Andric SDValue VECustomDAG::getGatherScatterAddress(SDValue BasePtr, SDValue Scale,
53781ad6265SDimitry Andric                                              SDValue Index, SDValue Mask,
53881ad6265SDimitry Andric                                              SDValue AVL) const {
53981ad6265SDimitry Andric   EVT IndexVT = Index.getValueType();
54081ad6265SDimitry Andric 
54181ad6265SDimitry Andric   // Apply scale.
54281ad6265SDimitry Andric   SDValue ScaledIndex;
54381ad6265SDimitry Andric   if (!Scale || isOneConstant(Scale))
54481ad6265SDimitry Andric     ScaledIndex = Index;
54581ad6265SDimitry Andric   else {
54681ad6265SDimitry Andric     SDValue ScaleBroadcast = getBroadcast(IndexVT, Scale, AVL);
54781ad6265SDimitry Andric     ScaledIndex =
54881ad6265SDimitry Andric         getNode(VEISD::VVP_MUL, IndexVT, {Index, ScaleBroadcast, Mask, AVL});
54981ad6265SDimitry Andric   }
55081ad6265SDimitry Andric 
55181ad6265SDimitry Andric   // Add basePtr.
55281ad6265SDimitry Andric   if (isNullConstant(BasePtr))
55381ad6265SDimitry Andric     return ScaledIndex;
55481ad6265SDimitry Andric 
55581ad6265SDimitry Andric   // re-constitute pointer vector (basePtr + index * scale)
55681ad6265SDimitry Andric   SDValue BaseBroadcast = getBroadcast(IndexVT, BasePtr, AVL);
55781ad6265SDimitry Andric   auto ResPtr =
55881ad6265SDimitry Andric       getNode(VEISD::VVP_ADD, IndexVT, {BaseBroadcast, ScaledIndex, Mask, AVL});
55981ad6265SDimitry Andric   return ResPtr;
56081ad6265SDimitry Andric }
56181ad6265SDimitry Andric 
getLegalReductionOpVVP(unsigned VVPOpcode,EVT ResVT,SDValue StartV,SDValue VectorV,SDValue Mask,SDValue AVL,SDNodeFlags Flags) const56281ad6265SDimitry Andric SDValue VECustomDAG::getLegalReductionOpVVP(unsigned VVPOpcode, EVT ResVT,
56381ad6265SDimitry Andric                                             SDValue StartV, SDValue VectorV,
56481ad6265SDimitry Andric                                             SDValue Mask, SDValue AVL,
56581ad6265SDimitry Andric                                             SDNodeFlags Flags) const {
56681ad6265SDimitry Andric 
56781ad6265SDimitry Andric   // Optionally attach the start param with a scalar op (where it is
56881ad6265SDimitry Andric   // unsupported).
56981ad6265SDimitry Andric   bool scalarizeStartParam = StartV && !hasReductionStartParam(VVPOpcode);
57081ad6265SDimitry Andric   bool IsMaskReduction = isMaskType(VectorV.getValueType());
57181ad6265SDimitry Andric   assert(!IsMaskReduction && "TODO Implement");
57281ad6265SDimitry Andric   auto AttachStartValue = [&](SDValue ReductionResV) {
57381ad6265SDimitry Andric     if (!scalarizeStartParam)
57481ad6265SDimitry Andric       return ReductionResV;
57581ad6265SDimitry Andric     auto ScalarOC = getScalarReductionOpcode(VVPOpcode, IsMaskReduction);
57681ad6265SDimitry Andric     return getNode(ScalarOC, ResVT, {StartV, ReductionResV});
57781ad6265SDimitry Andric   };
57881ad6265SDimitry Andric 
57981ad6265SDimitry Andric   // Fixup: Always Use sequential 'fmul' reduction.
58081ad6265SDimitry Andric   if (!scalarizeStartParam && StartV) {
58181ad6265SDimitry Andric     assert(hasReductionStartParam(VVPOpcode));
58281ad6265SDimitry Andric     return AttachStartValue(
58381ad6265SDimitry Andric         getNode(VVPOpcode, ResVT, {StartV, VectorV, Mask, AVL}, Flags));
58481ad6265SDimitry Andric   } else
58581ad6265SDimitry Andric     return AttachStartValue(
58681ad6265SDimitry Andric         getNode(VVPOpcode, ResVT, {VectorV, Mask, AVL}, Flags));
58781ad6265SDimitry Andric }
58881ad6265SDimitry Andric 
58904eeddc0SDimitry Andric } // namespace llvm
590