| 1 | //===------------ VECustomDAG.h - VE Custom DAG Nodes -----------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file defines the helper functions that VE uses to lower LLVM code into a |
| 10 | // selection DAG. For example, hiding SDLoc, and easy to use SDNodeFlags. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef LLVM_LIB_TARGET_VE_VECUSTOMDAG_H |
| 15 | #define LLVM_LIB_TARGET_VE_VECUSTOMDAG_H |
| 16 | |
| 17 | #include "VE.h" |
| 18 | #include "VEISelLowering.h" |
| 19 | #include "llvm/CodeGen/SelectionDAG.h" |
| 20 | #include "llvm/CodeGen/TargetLowering.h" |
| 21 | |
| 22 | namespace llvm { |
| 23 | |
| 24 | std::optional<unsigned> getVVPOpcode(unsigned Opcode); |
| 25 | |
| 26 | bool isVVPUnaryOp(unsigned Opcode); |
| 27 | bool isVVPBinaryOp(unsigned Opcode); |
| 28 | bool isVVPReductionOp(unsigned Opcode); |
| 29 | |
| 30 | MVT splitVectorType(MVT VT); |
| 31 | |
| 32 | bool isPackedVectorType(EVT SomeVT); |
| 33 | |
| 34 | bool isMaskType(EVT SomeVT); |
| 35 | |
| 36 | bool isMaskArithmetic(SDValue Op); |
| 37 | |
| 38 | bool isVVPOrVEC(unsigned); |
| 39 | |
| 40 | bool supportsPackedMode(unsigned Opcode, EVT IdiomVT); |
| 41 | |
| 42 | bool isPackingSupportOpcode(unsigned Opc); |
| 43 | |
| 44 | bool maySafelyIgnoreMask(SDValue Op); |
| 45 | |
| 46 | /// The VE backend uses a two-staged process to lower and legalize vector |
| 47 | /// instructions: |
| 48 | // |
| 49 | /// 1. VP and standard vector SDNodes are lowered to SDNodes of the VVP_* layer. |
| 50 | // |
| 51 | // All VVP nodes have a mask and an Active Vector Length (AVL) parameter. |
| 52 | // The AVL parameters refers to the element position in the vector the VVP |
| 53 | // node operates on. |
| 54 | // |
| 55 | // |
| 56 | // 2. The VVP SDNodes are legalized. The AVL in a legal VVP node refers to |
| 57 | // chunks of 64bit. We track this by wrapping the AVL in a LEGALAVL node. |
| 58 | // |
| 59 | // The AVL mechanism in the VE architecture always refers to chunks of |
| 60 | // 64bit, regardless of the actual element type vector instructions are |
| 61 | // operating on. For vector types v256.32 or v256.64 nothing needs to be |
| 62 | // legalized since each element occupies a 64bit chunk - there is no |
| 63 | // difference between counting 64bit chunks or element positions. However, |
| 64 | // all vector types with > 256 elements store more than one logical element |
| 65 | // per 64bit chunk and need to be transformed. |
| 66 | // However legalization is performed, the resulting legal VVP SDNodes will |
| 67 | // have a LEGALAVL node as their AVL operand. The LEGALAVL nodes wraps |
| 68 | // around an AVL that refers to 64 bit chunks just as the architecture |
| 69 | // demands - that is, the wrapped AVL is the correct setting for the VL |
| 70 | // register for this VVP operation to get the desired behavior. |
| 71 | // |
| 72 | /// AVL Functions { |
| 73 | // The AVL operand position of this node. |
| 74 | std::optional<int> getAVLPos(unsigned); |
| 75 | |
| 76 | // Whether this is a LEGALAVL node. |
| 77 | bool isLegalAVL(SDValue AVL); |
| 78 | |
| 79 | // The AVL operand of this node. |
| 80 | SDValue getNodeAVL(SDValue); |
| 81 | |
| 82 | // Mask position of this node. |
| 83 | std::optional<int> getMaskPos(unsigned); |
| 84 | |
| 85 | SDValue getNodeMask(SDValue); |
| 86 | |
| 87 | // Return the AVL operand of this node. If it is a LEGALAVL node, unwrap it. |
| 88 | // Return with the boolean whether unwrapping happened. |
| 89 | std::pair<SDValue, bool> getAnnotatedNodeAVL(SDValue); |
| 90 | |
| 91 | /// } AVL Functions |
| 92 | |
| 93 | /// Node Properties { |
| 94 | |
| 95 | std::optional<EVT> getIdiomaticVectorType(SDNode *Op); |
| 96 | |
| 97 | SDValue getLoadStoreStride(SDValue Op, VECustomDAG &CDAG); |
| 98 | |
| 99 | SDValue getMemoryPtr(SDValue Op); |
| 100 | |
| 101 | SDValue getNodeChain(SDValue Op); |
| 102 | |
| 103 | SDValue getStoredValue(SDValue Op); |
| 104 | |
| 105 | SDValue getNodePassthru(SDValue Op); |
| 106 | |
| 107 | SDValue getGatherScatterIndex(SDValue Op); |
| 108 | |
| 109 | SDValue getGatherScatterScale(SDValue Op); |
| 110 | |
| 111 | unsigned getScalarReductionOpcode(unsigned VVPOC, bool IsMask); |
| 112 | |
| 113 | // Whether this VP_REDUCE_*/ VECREDUCE_*/VVP_REDUCE_* SDNode has a start |
| 114 | // parameter. |
| 115 | bool hasReductionStartParam(unsigned VVPOC); |
| 116 | |
| 117 | /// } Node Properties |
| 118 | |
| 119 | enum class Packing { |
| 120 | Normal = 0, // 256 element standard mode. |
| 121 | Dense = 1 // 512 element packed mode. |
| 122 | }; |
| 123 | |
| 124 | // Get the vector or mask register type for this packing and element type. |
| 125 | MVT getLegalVectorType(Packing P, MVT ElemVT); |
| 126 | |
| 127 | // Whether this type belongs to a packed mask or vector register. |
| 128 | Packing getTypePacking(EVT); |
| 129 | |
| 130 | enum class PackElem : int8_t { |
| 131 | Lo = 0, // Integer (63, 32] |
| 132 | Hi = 1 // Float (32, 0] |
| 133 | }; |
| 134 | |
| 135 | struct VETargetMasks { |
| 136 | SDValue Mask; |
| 137 | SDValue AVL; |
| 138 | VETargetMasks(SDValue Mask = SDValue(), SDValue AVL = SDValue()) |
| 139 | : Mask(Mask), AVL(AVL) {} |
| 140 | }; |
| 141 | |
| 142 | class VECustomDAG { |
| 143 | SelectionDAG &DAG; |
| 144 | SDLoc DL; |
| 145 | |
| 146 | public: |
| 147 | SelectionDAG *getDAG() const { return &DAG; } |
| 148 | |
| 149 | VECustomDAG(SelectionDAG &DAG, SDLoc DL) : DAG(DAG), DL(DL) {} |
| 150 | |
| 151 | VECustomDAG(SelectionDAG &DAG, SDValue WhereOp) : DAG(DAG), DL(WhereOp) {} |
| 152 | |
| 153 | VECustomDAG(SelectionDAG &DAG, const SDNode *WhereN) : DAG(DAG), DL(WhereN) {} |
| 154 | |
| 155 | /// getNode { |
| 156 | SDValue getNode(unsigned OC, SDVTList VTL, ArrayRef<SDValue> OpV, |
| 157 | std::optional<SDNodeFlags> Flags = std::nullopt) const { |
| 158 | auto N = DAG.getNode(Opcode: OC, DL, VTList: VTL, Ops: OpV); |
| 159 | if (Flags) |
| 160 | N->setFlags(*Flags); |
| 161 | return N; |
| 162 | } |
| 163 | |
| 164 | SDValue getNode(unsigned OC, ArrayRef<EVT> ResVT, ArrayRef<SDValue> OpV, |
| 165 | std::optional<SDNodeFlags> Flags = std::nullopt) const { |
| 166 | auto N = DAG.getNode(Opcode: OC, DL, ResultTys: ResVT, Ops: OpV); |
| 167 | if (Flags) |
| 168 | N->setFlags(*Flags); |
| 169 | return N; |
| 170 | } |
| 171 | |
| 172 | SDValue getNode(unsigned OC, EVT ResVT, ArrayRef<SDValue> OpV, |
| 173 | std::optional<SDNodeFlags> Flags = std::nullopt) const { |
| 174 | auto N = DAG.getNode(Opcode: OC, DL, VT: ResVT, Ops: OpV); |
| 175 | if (Flags) |
| 176 | N->setFlags(*Flags); |
| 177 | return N; |
| 178 | } |
| 179 | |
| 180 | SDValue getUNDEF(EVT VT) const { return DAG.getUNDEF(VT); } |
| 181 | /// } getNode |
| 182 | |
| 183 | /// Legalizing getNode { |
| 184 | SDValue getLegalReductionOpVVP(unsigned VVPOpcode, EVT ResVT, SDValue StartV, |
| 185 | SDValue VectorV, SDValue Mask, SDValue AVL, |
| 186 | SDNodeFlags Flags) const; |
| 187 | /// } Legalizing getNode |
| 188 | |
| 189 | /// Packing { |
| 190 | SDValue getUnpack(EVT DestVT, SDValue Vec, PackElem Part, SDValue AVL) const; |
| 191 | SDValue getPack(EVT DestVT, SDValue LoVec, SDValue HiVec, SDValue AVL) const; |
| 192 | /// } Packing |
| 193 | |
| 194 | SDValue getMergeValues(ArrayRef<SDValue> Values) const { |
| 195 | return DAG.getMergeValues(Ops: Values, dl: DL); |
| 196 | } |
| 197 | |
| 198 | SDValue getConstant(uint64_t Val, EVT VT, bool IsTarget = false, |
| 199 | bool IsOpaque = false) const; |
| 200 | |
| 201 | SDValue getConstantMask(Packing Packing, bool AllTrue) const; |
| 202 | SDValue getMaskBroadcast(EVT ResultVT, SDValue Scalar, SDValue AVL) const; |
| 203 | SDValue getBroadcast(EVT ResultVT, SDValue Scalar, SDValue AVL) const; |
| 204 | |
| 205 | // Wrap AVL in a LEGALAVL node (unless it is one already). |
| 206 | SDValue annotateLegalAVL(SDValue AVL) const; |
| 207 | VETargetMasks getTargetSplitMask(SDValue RawMask, SDValue RawAVL, |
| 208 | PackElem Part) const; |
| 209 | |
| 210 | // Splitting support |
| 211 | SDValue getSplitPtrOffset(SDValue Ptr, SDValue ByteStride, |
| 212 | PackElem Part) const; |
| 213 | SDValue getSplitPtrStride(SDValue PackStride) const; |
| 214 | SDValue getGatherScatterAddress(SDValue BasePtr, SDValue Scale, SDValue Index, |
| 215 | SDValue Mask, SDValue AVL) const; |
| 216 | EVT getVectorVT(EVT ElemVT, unsigned NumElems) const { |
| 217 | return EVT::getVectorVT(Context&: *DAG.getContext(), VT: ElemVT, NumElements: NumElems); |
| 218 | } |
| 219 | }; |
| 220 | |
| 221 | } // namespace llvm |
| 222 | |
| 223 | #endif // LLVM_LIB_TARGET_VE_VECUSTOMDAG_H |
| 224 | |