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