xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/VE/VECustomDAG.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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