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