/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Support/RISCVVIntrinsicUtils.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- RISCVVIntrinsicUtils.h - RISC-V Vector Intrinsic Utils -*- 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 | | #ifndef CLANG_SUPPORT_RISCVVINTRINSICUTILS_H |
10 | | #define CLANG_SUPPORT_RISCVVINTRINSICUTILS_H |
11 | | |
12 | | #include "llvm/ADT/ArrayRef.h" |
13 | | #include "llvm/ADT/BitmaskEnum.h" |
14 | | #include "llvm/ADT/Optional.h" |
15 | | #include "llvm/ADT/SmallVector.h" |
16 | | #include "llvm/ADT/StringRef.h" |
17 | | #include <cstdint> |
18 | | #include <string> |
19 | | #include <vector> |
20 | | |
21 | | namespace clang { |
22 | | namespace RISCV { |
23 | | |
24 | | using VScaleVal = llvm::Optional<unsigned>; |
25 | | |
26 | | // Modifier for vector type. |
27 | | enum class VectorTypeModifier : uint8_t { |
28 | | NoModifier, |
29 | | Widening2XVector, |
30 | | Widening4XVector, |
31 | | Widening8XVector, |
32 | | MaskVector, |
33 | | Log2EEW3, |
34 | | Log2EEW4, |
35 | | Log2EEW5, |
36 | | Log2EEW6, |
37 | | FixedSEW8, |
38 | | FixedSEW16, |
39 | | FixedSEW32, |
40 | | FixedSEW64, |
41 | | LFixedLog2LMULN3, |
42 | | LFixedLog2LMULN2, |
43 | | LFixedLog2LMULN1, |
44 | | LFixedLog2LMUL0, |
45 | | LFixedLog2LMUL1, |
46 | | LFixedLog2LMUL2, |
47 | | LFixedLog2LMUL3, |
48 | | SFixedLog2LMULN3, |
49 | | SFixedLog2LMULN2, |
50 | | SFixedLog2LMULN1, |
51 | | SFixedLog2LMUL0, |
52 | | SFixedLog2LMUL1, |
53 | | SFixedLog2LMUL2, |
54 | | SFixedLog2LMUL3, |
55 | | }; |
56 | | |
57 | | // Similar to basic type but used to describe what's kind of type related to |
58 | | // basic vector type, used to compute type info of arguments. |
59 | | enum class BaseTypeModifier : uint8_t { |
60 | | Invalid, |
61 | | Scalar, |
62 | | Vector, |
63 | | Void, |
64 | | SizeT, |
65 | | Ptrdiff, |
66 | | UnsignedLong, |
67 | | SignedLong, |
68 | | }; |
69 | | |
70 | | // Modifier for type, used for both scalar and vector types. |
71 | | enum class TypeModifier : uint8_t { |
72 | | NoModifier = 0, |
73 | | Pointer = 1 << 0, |
74 | | Const = 1 << 1, |
75 | | Immediate = 1 << 2, |
76 | | UnsignedInteger = 1 << 3, |
77 | | SignedInteger = 1 << 4, |
78 | | Float = 1 << 5, |
79 | | // LMUL1 should be kind of VectorTypeModifier, but that might come with |
80 | | // Widening2XVector for widening reduction. |
81 | | // However that might require VectorTypeModifier become bitmask rather than |
82 | | // simple enum, so we decide keek LMUL1 in TypeModifier for code size |
83 | | // optimization of clang binary size. |
84 | | LMUL1 = 1 << 6, |
85 | | MaxOffset = 6, |
86 | | LLVM_MARK_AS_BITMASK_ENUM(LMUL1), |
87 | | }; |
88 | | |
89 | | // PrototypeDescriptor is used to compute type info of arguments or return |
90 | | // value. |
91 | | struct PrototypeDescriptor { |
92 | 0 | constexpr PrototypeDescriptor() = default; |
93 | | constexpr PrototypeDescriptor( |
94 | | BaseTypeModifier PT, |
95 | | VectorTypeModifier VTM = VectorTypeModifier::NoModifier, |
96 | | TypeModifier TM = TypeModifier::NoModifier) |
97 | | : PT(static_cast<uint8_t>(PT)), VTM(static_cast<uint8_t>(VTM)), |
98 | 0 | TM(static_cast<uint8_t>(TM)) {} |
99 | | constexpr PrototypeDescriptor(uint8_t PT, uint8_t VTM, uint8_t TM) |
100 | 0 | : PT(PT), VTM(VTM), TM(TM) {} |
101 | | |
102 | | uint8_t PT = static_cast<uint8_t>(BaseTypeModifier::Invalid); |
103 | | uint8_t VTM = static_cast<uint8_t>(VectorTypeModifier::NoModifier); |
104 | | uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier); |
105 | | |
106 | 0 | bool operator!=(const PrototypeDescriptor &PD) const { |
107 | 0 | return PD.PT != PT || PD.VTM != VTM || PD.TM != TM; |
108 | 0 | } |
109 | 0 | bool operator>(const PrototypeDescriptor &PD) const { |
110 | 0 | return !(PD.PT <= PT && PD.VTM <= VTM && PD.TM <= TM); |
111 | 0 | } |
112 | | |
113 | | static const PrototypeDescriptor Mask; |
114 | | static const PrototypeDescriptor Vector; |
115 | | static const PrototypeDescriptor VL; |
116 | | static llvm::Optional<PrototypeDescriptor> |
117 | | parsePrototypeDescriptor(llvm::StringRef PrototypeStr); |
118 | | }; |
119 | | |
120 | | llvm::SmallVector<PrototypeDescriptor> |
121 | | parsePrototypes(llvm::StringRef Prototypes); |
122 | | |
123 | | // Basic type of vector type. |
124 | | enum class BasicType : uint8_t { |
125 | | Unknown = 0, |
126 | | Int8 = 1 << 0, |
127 | | Int16 = 1 << 1, |
128 | | Int32 = 1 << 2, |
129 | | Int64 = 1 << 3, |
130 | | Float16 = 1 << 4, |
131 | | Float32 = 1 << 5, |
132 | | Float64 = 1 << 6, |
133 | | MaxOffset = 6, |
134 | | LLVM_MARK_AS_BITMASK_ENUM(Float64), |
135 | | }; |
136 | | |
137 | | // Type of vector type. |
138 | | enum ScalarTypeKind : uint8_t { |
139 | | Void, |
140 | | Size_t, |
141 | | Ptrdiff_t, |
142 | | UnsignedLong, |
143 | | SignedLong, |
144 | | Boolean, |
145 | | SignedInteger, |
146 | | UnsignedInteger, |
147 | | Float, |
148 | | Invalid, |
149 | | }; |
150 | | |
151 | | // Exponential LMUL |
152 | | struct LMULType { |
153 | | int Log2LMUL; |
154 | | LMULType(int Log2LMUL); |
155 | | // Return the C/C++ string representation of LMUL |
156 | | std::string str() const; |
157 | | llvm::Optional<unsigned> getScale(unsigned ElementBitwidth) const; |
158 | | void MulLog2LMUL(int Log2LMUL); |
159 | | }; |
160 | | |
161 | | class RVVType; |
162 | | using RVVTypePtr = RVVType *; |
163 | | using RVVTypes = std::vector<RVVTypePtr>; |
164 | | |
165 | | // This class is compact representation of a valid and invalid RVVType. |
166 | | class RVVType { |
167 | | BasicType BT; |
168 | | ScalarTypeKind ScalarType = Invalid; |
169 | | LMULType LMUL; |
170 | | bool IsPointer = false; |
171 | | // IsConstant indices are "int", but have the constant expression. |
172 | | bool IsImmediate = false; |
173 | | // Const qualifier for pointer to const object or object of const type. |
174 | | bool IsConstant = false; |
175 | | unsigned ElementBitwidth = 0; |
176 | | VScaleVal Scale = 0; |
177 | | bool Valid; |
178 | | |
179 | | std::string BuiltinStr; |
180 | | std::string ClangBuiltinStr; |
181 | | std::string Str; |
182 | | std::string ShortStr; |
183 | | |
184 | | enum class FixedLMULType { LargerThan, SmallerThan }; |
185 | | |
186 | | public: |
187 | 0 | RVVType() : BT(BasicType::Unknown), LMUL(0), Valid(false) {} |
188 | | RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile); |
189 | | |
190 | | // Return the string representation of a type, which is an encoded string for |
191 | | // passing to the BUILTIN() macro in Builtins.def. |
192 | 0 | const std::string &getBuiltinStr() const { return BuiltinStr; } |
193 | | |
194 | | // Return the clang builtin type for RVV vector type which are used in the |
195 | | // riscv_vector.h header file. |
196 | 0 | const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; } |
197 | | |
198 | | // Return the C/C++ string representation of a type for use in the |
199 | | // riscv_vector.h header file. |
200 | 0 | const std::string &getTypeStr() const { return Str; } |
201 | | |
202 | | // Return the short name of a type for C/C++ name suffix. |
203 | 0 | const std::string &getShortStr() { |
204 | | // Not all types are used in short name, so compute the short name by |
205 | | // demanded. |
206 | 0 | if (ShortStr.empty()) |
207 | 0 | initShortStr(); |
208 | 0 | return ShortStr; |
209 | 0 | } |
210 | | |
211 | 0 | bool isValid() const { return Valid; } |
212 | 0 | bool isScalar() const { return Scale && Scale.value() == 0; } |
213 | 0 | bool isVector() const { return Scale && Scale.value() != 0; } |
214 | 0 | bool isVector(unsigned Width) const { |
215 | 0 | return isVector() && ElementBitwidth == Width; |
216 | 0 | } |
217 | 0 | bool isFloat() const { return ScalarType == ScalarTypeKind::Float; } |
218 | 0 | bool isSignedInteger() const { |
219 | 0 | return ScalarType == ScalarTypeKind::SignedInteger; |
220 | 0 | } |
221 | 0 | bool isFloatVector(unsigned Width) const { |
222 | 0 | return isVector() && isFloat() && ElementBitwidth == Width; |
223 | 0 | } |
224 | 0 | bool isFloat(unsigned Width) const { |
225 | 0 | return isFloat() && ElementBitwidth == Width; |
226 | 0 | } |
227 | | |
228 | 0 | bool isPointer() const { return IsPointer; } |
229 | | |
230 | | private: |
231 | | // Verify RVV vector type and set Valid. |
232 | | bool verifyType() const; |
233 | | |
234 | | // Creates a type based on basic types of TypeRange |
235 | | void applyBasicType(); |
236 | | |
237 | | // Applies a prototype modifier to the current type. The result maybe an |
238 | | // invalid type. |
239 | | void applyModifier(const PrototypeDescriptor &prototype); |
240 | | |
241 | | void applyLog2EEW(unsigned Log2EEW); |
242 | | void applyFixedSEW(unsigned NewSEW); |
243 | | void applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type); |
244 | | |
245 | | // Compute and record a string for legal type. |
246 | | void initBuiltinStr(); |
247 | | // Compute and record a builtin RVV vector type string. |
248 | | void initClangBuiltinStr(); |
249 | | // Compute and record a type string for used in the header. |
250 | | void initTypeStr(); |
251 | | // Compute and record a short name of a type for C/C++ name suffix. |
252 | | void initShortStr(); |
253 | | |
254 | | public: |
255 | | /// Compute output and input types by applying different config (basic type |
256 | | /// and LMUL with type transformers). It also record result of type in legal |
257 | | /// or illegal set to avoid compute the same config again. The result maybe |
258 | | /// have illegal RVVType. |
259 | | static llvm::Optional<RVVTypes> |
260 | | computeTypes(BasicType BT, int Log2LMUL, unsigned NF, |
261 | | llvm::ArrayRef<PrototypeDescriptor> Prototype); |
262 | | static llvm::Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, |
263 | | PrototypeDescriptor Proto); |
264 | | }; |
265 | | |
266 | | using RISCVPredefinedMacroT = uint8_t; |
267 | | |
268 | | enum RISCVPredefinedMacro : RISCVPredefinedMacroT { |
269 | | Basic = 0, |
270 | | V = 1 << 1, |
271 | | Zvfh = 1 << 2, |
272 | | RV64 = 1 << 3, |
273 | | VectorMaxELen64 = 1 << 4, |
274 | | VectorMaxELenFp32 = 1 << 5, |
275 | | VectorMaxELenFp64 = 1 << 6, |
276 | | }; |
277 | | |
278 | | enum PolicyScheme : uint8_t { |
279 | | SchemeNone, |
280 | | HasPassthruOperand, |
281 | | HasPolicyOperand, |
282 | | }; |
283 | | |
284 | | // TODO refactor RVVIntrinsic class design after support all intrinsic |
285 | | // combination. This represents an instantiation of an intrinsic with a |
286 | | // particular type and prototype |
287 | | class RVVIntrinsic { |
288 | | |
289 | | private: |
290 | | std::string BuiltinName; // Builtin name |
291 | | std::string Name; // C intrinsic name. |
292 | | std::string OverloadedName; |
293 | | std::string IRName; |
294 | | bool IsMasked; |
295 | | bool HasVL; |
296 | | PolicyScheme Scheme; |
297 | | bool HasUnMaskedOverloaded; |
298 | | bool HasBuiltinAlias; |
299 | | std::string ManualCodegen; |
300 | | RVVTypePtr OutputType; // Builtin output type |
301 | | RVVTypes InputTypes; // Builtin input types |
302 | | // The types we use to obtain the specific LLVM intrinsic. They are index of |
303 | | // InputTypes. -1 means the return type. |
304 | | std::vector<int64_t> IntrinsicTypes; |
305 | | RISCVPredefinedMacroT RISCVPredefinedMacros = 0; |
306 | | unsigned NF = 1; |
307 | | |
308 | | public: |
309 | | RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix, |
310 | | llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix, |
311 | | llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand, |
312 | | bool HasVL, PolicyScheme Scheme, bool HasUnMaskedOverloaded, |
313 | | bool HasBuiltinAlias, llvm::StringRef ManualCodegen, |
314 | | const RVVTypes &Types, |
315 | | const std::vector<int64_t> &IntrinsicTypes, |
316 | | const std::vector<llvm::StringRef> &RequiredFeatures, |
317 | | unsigned NF); |
318 | 0 | ~RVVIntrinsic() = default; |
319 | | |
320 | 0 | RVVTypePtr getOutputType() const { return OutputType; } |
321 | 0 | const RVVTypes &getInputTypes() const { return InputTypes; } |
322 | 0 | llvm::StringRef getBuiltinName() const { return BuiltinName; } |
323 | 0 | llvm::StringRef getName() const { return Name; } |
324 | 0 | llvm::StringRef getOverloadedName() const { return OverloadedName; } |
325 | 0 | bool hasVL() const { return HasVL; } |
326 | 0 | bool hasPolicy() const { return Scheme != SchemeNone; } |
327 | 0 | bool hasPassthruOperand() const { return Scheme == HasPassthruOperand; } |
328 | 0 | bool hasPolicyOperand() const { return Scheme == HasPolicyOperand; } |
329 | 0 | bool hasUnMaskedOverloaded() const { return HasUnMaskedOverloaded; } |
330 | 0 | bool hasBuiltinAlias() const { return HasBuiltinAlias; } |
331 | 0 | bool hasManualCodegen() const { return !ManualCodegen.empty(); } |
332 | 0 | bool isMasked() const { return IsMasked; } |
333 | 0 | llvm::StringRef getIRName() const { return IRName; } |
334 | 0 | llvm::StringRef getManualCodegen() const { return ManualCodegen; } |
335 | 0 | PolicyScheme getPolicyScheme() const { return Scheme; } |
336 | 0 | RISCVPredefinedMacroT getRISCVPredefinedMacros() const { |
337 | 0 | return RISCVPredefinedMacros; |
338 | 0 | } |
339 | 0 | unsigned getNF() const { return NF; } |
340 | 0 | const std::vector<int64_t> &getIntrinsicTypes() const { |
341 | 0 | return IntrinsicTypes; |
342 | 0 | } |
343 | | |
344 | | // Return the type string for a BUILTIN() macro in Builtins.def. |
345 | | std::string getBuiltinTypeStr() const; |
346 | | |
347 | | static std::string |
348 | | getSuffixStr(BasicType Type, int Log2LMUL, |
349 | | llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors); |
350 | | }; |
351 | | |
352 | | } // end namespace RISCV |
353 | | |
354 | | } // end namespace clang |
355 | | |
356 | | #endif // CLANG_SUPPORT_RISCVVINTRINSICUTILS_H |