Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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/SmallVector.h" |
||
15 | #include "llvm/ADT/StringRef.h" |
||
16 | #include <cstdint> |
||
17 | #include <optional> |
||
18 | #include <set> |
||
19 | #include <string> |
||
20 | #include <unordered_map> |
||
21 | #include <vector> |
||
22 | |||
23 | namespace llvm { |
||
24 | class raw_ostream; |
||
25 | } // end namespace llvm |
||
26 | |||
27 | namespace clang { |
||
28 | namespace RISCV { |
||
29 | |||
30 | using VScaleVal = std::optional<unsigned>; |
||
31 | |||
32 | // Modifier for vector type. |
||
33 | enum class VectorTypeModifier : uint8_t { |
||
34 | NoModifier, |
||
35 | Widening2XVector, |
||
36 | Widening4XVector, |
||
37 | Widening8XVector, |
||
38 | MaskVector, |
||
39 | Log2EEW3, |
||
40 | Log2EEW4, |
||
41 | Log2EEW5, |
||
42 | Log2EEW6, |
||
43 | FixedSEW8, |
||
44 | FixedSEW16, |
||
45 | FixedSEW32, |
||
46 | FixedSEW64, |
||
47 | LFixedLog2LMULN3, |
||
48 | LFixedLog2LMULN2, |
||
49 | LFixedLog2LMULN1, |
||
50 | LFixedLog2LMUL0, |
||
51 | LFixedLog2LMUL1, |
||
52 | LFixedLog2LMUL2, |
||
53 | LFixedLog2LMUL3, |
||
54 | SFixedLog2LMULN3, |
||
55 | SFixedLog2LMULN2, |
||
56 | SFixedLog2LMULN1, |
||
57 | SFixedLog2LMUL0, |
||
58 | SFixedLog2LMUL1, |
||
59 | SFixedLog2LMUL2, |
||
60 | SFixedLog2LMUL3, |
||
61 | }; |
||
62 | |||
63 | // Similar to basic type but used to describe what's kind of type related to |
||
64 | // basic vector type, used to compute type info of arguments. |
||
65 | enum class BaseTypeModifier : uint8_t { |
||
66 | Invalid, |
||
67 | Scalar, |
||
68 | Vector, |
||
69 | Void, |
||
70 | SizeT, |
||
71 | Ptrdiff, |
||
72 | UnsignedLong, |
||
73 | SignedLong, |
||
74 | }; |
||
75 | |||
76 | // Modifier for type, used for both scalar and vector types. |
||
77 | enum class TypeModifier : uint8_t { |
||
78 | NoModifier = 0, |
||
79 | Pointer = 1 << 0, |
||
80 | Const = 1 << 1, |
||
81 | Immediate = 1 << 2, |
||
82 | UnsignedInteger = 1 << 3, |
||
83 | SignedInteger = 1 << 4, |
||
84 | Float = 1 << 5, |
||
85 | // LMUL1 should be kind of VectorTypeModifier, but that might come with |
||
86 | // Widening2XVector for widening reduction. |
||
87 | // However that might require VectorTypeModifier become bitmask rather than |
||
88 | // simple enum, so we decide keek LMUL1 in TypeModifier for code size |
||
89 | // optimization of clang binary size. |
||
90 | LMUL1 = 1 << 6, |
||
91 | MaxOffset = 6, |
||
92 | LLVM_MARK_AS_BITMASK_ENUM(LMUL1), |
||
93 | }; |
||
94 | |||
95 | class Policy { |
||
96 | public: |
||
97 | enum PolicyType { |
||
98 | Undisturbed, |
||
99 | Agnostic, |
||
100 | }; |
||
101 | |||
102 | private: |
||
103 | // The default assumption for an RVV instruction is TAMA, as an undisturbed |
||
104 | // policy generally will affect the performance of an out-of-order core. |
||
105 | const PolicyType TailPolicy = Agnostic; |
||
106 | const PolicyType MaskPolicy = Agnostic; |
||
107 | |||
108 | public: |
||
109 | Policy() = default; |
||
110 | Policy(PolicyType TailPolicy) : TailPolicy(TailPolicy) {} |
||
111 | Policy(PolicyType TailPolicy, PolicyType MaskPolicy) |
||
112 | : TailPolicy(TailPolicy), MaskPolicy(MaskPolicy) {} |
||
113 | |||
114 | bool isTAMAPolicy() const { |
||
115 | return TailPolicy == Agnostic && MaskPolicy == Agnostic; |
||
116 | } |
||
117 | |||
118 | bool isTAMUPolicy() const { |
||
119 | return TailPolicy == Agnostic && MaskPolicy == Undisturbed; |
||
120 | } |
||
121 | |||
122 | bool isTUMAPolicy() const { |
||
123 | return TailPolicy == Undisturbed && MaskPolicy == Agnostic; |
||
124 | } |
||
125 | |||
126 | bool isTUMUPolicy() const { |
||
127 | return TailPolicy == Undisturbed && MaskPolicy == Undisturbed; |
||
128 | } |
||
129 | |||
130 | bool isTAPolicy() const { return TailPolicy == Agnostic; } |
||
131 | |||
132 | bool isTUPolicy() const { return TailPolicy == Undisturbed; } |
||
133 | |||
134 | bool isMAPolicy() const { return MaskPolicy == Agnostic; } |
||
135 | |||
136 | bool isMUPolicy() const { return MaskPolicy == Undisturbed; } |
||
137 | |||
138 | bool operator==(const Policy &Other) const { |
||
139 | return TailPolicy == Other.TailPolicy && MaskPolicy == Other.MaskPolicy; |
||
140 | } |
||
141 | |||
142 | bool operator!=(const Policy &Other) const { return !(*this == Other); } |
||
143 | |||
144 | bool operator<(const Policy &Other) const { |
||
145 | // Just for maintain the old order for quick test. |
||
146 | if (MaskPolicy != Other.MaskPolicy) |
||
147 | return Other.MaskPolicy < MaskPolicy; |
||
148 | return TailPolicy < Other.TailPolicy; |
||
149 | } |
||
150 | }; |
||
151 | |||
152 | // PrototypeDescriptor is used to compute type info of arguments or return |
||
153 | // value. |
||
154 | struct PrototypeDescriptor { |
||
155 | constexpr PrototypeDescriptor() = default; |
||
156 | constexpr PrototypeDescriptor( |
||
157 | BaseTypeModifier PT, |
||
158 | VectorTypeModifier VTM = VectorTypeModifier::NoModifier, |
||
159 | TypeModifier TM = TypeModifier::NoModifier) |
||
160 | : PT(static_cast<uint8_t>(PT)), VTM(static_cast<uint8_t>(VTM)), |
||
161 | TM(static_cast<uint8_t>(TM)) {} |
||
162 | constexpr PrototypeDescriptor(uint8_t PT, uint8_t VTM, uint8_t TM) |
||
163 | : PT(PT), VTM(VTM), TM(TM) {} |
||
164 | |||
165 | uint8_t PT = static_cast<uint8_t>(BaseTypeModifier::Invalid); |
||
166 | uint8_t VTM = static_cast<uint8_t>(VectorTypeModifier::NoModifier); |
||
167 | uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier); |
||
168 | |||
169 | bool operator!=(const PrototypeDescriptor &PD) const { |
||
170 | return !(*this == PD); |
||
171 | } |
||
172 | bool operator==(const PrototypeDescriptor &PD) const { |
||
173 | return PD.PT == PT && PD.VTM == VTM && PD.TM == TM; |
||
174 | } |
||
175 | bool operator<(const PrototypeDescriptor &PD) const { |
||
176 | return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM); |
||
177 | } |
||
178 | static const PrototypeDescriptor Mask; |
||
179 | static const PrototypeDescriptor Vector; |
||
180 | static const PrototypeDescriptor VL; |
||
181 | static std::optional<PrototypeDescriptor> |
||
182 | parsePrototypeDescriptor(llvm::StringRef PrototypeStr); |
||
183 | }; |
||
184 | |||
185 | llvm::SmallVector<PrototypeDescriptor> |
||
186 | parsePrototypes(llvm::StringRef Prototypes); |
||
187 | |||
188 | // Basic type of vector type. |
||
189 | enum class BasicType : uint8_t { |
||
190 | Unknown = 0, |
||
191 | Int8 = 1 << 0, |
||
192 | Int16 = 1 << 1, |
||
193 | Int32 = 1 << 2, |
||
194 | Int64 = 1 << 3, |
||
195 | Float16 = 1 << 4, |
||
196 | Float32 = 1 << 5, |
||
197 | Float64 = 1 << 6, |
||
198 | MaxOffset = 6, |
||
199 | LLVM_MARK_AS_BITMASK_ENUM(Float64), |
||
200 | }; |
||
201 | |||
202 | // Type of vector type. |
||
203 | enum ScalarTypeKind : uint8_t { |
||
204 | Void, |
||
205 | Size_t, |
||
206 | Ptrdiff_t, |
||
207 | UnsignedLong, |
||
208 | SignedLong, |
||
209 | Boolean, |
||
210 | SignedInteger, |
||
211 | UnsignedInteger, |
||
212 | Float, |
||
213 | Invalid, |
||
214 | }; |
||
215 | |||
216 | // Exponential LMUL |
||
217 | struct LMULType { |
||
218 | int Log2LMUL; |
||
219 | LMULType(int Log2LMUL); |
||
220 | // Return the C/C++ string representation of LMUL |
||
221 | std::string str() const; |
||
222 | std::optional<unsigned> getScale(unsigned ElementBitwidth) const; |
||
223 | void MulLog2LMUL(int Log2LMUL); |
||
224 | }; |
||
225 | |||
226 | class RVVType; |
||
227 | using RVVTypePtr = RVVType *; |
||
228 | using RVVTypes = std::vector<RVVTypePtr>; |
||
229 | class RVVTypeCache; |
||
230 | |||
231 | // This class is compact representation of a valid and invalid RVVType. |
||
232 | class RVVType { |
||
233 | friend class RVVTypeCache; |
||
234 | |||
235 | BasicType BT; |
||
236 | ScalarTypeKind ScalarType = Invalid; |
||
237 | LMULType LMUL; |
||
238 | bool IsPointer = false; |
||
239 | // IsConstant indices are "int", but have the constant expression. |
||
240 | bool IsImmediate = false; |
||
241 | // Const qualifier for pointer to const object or object of const type. |
||
242 | bool IsConstant = false; |
||
243 | unsigned ElementBitwidth = 0; |
||
244 | VScaleVal Scale = 0; |
||
245 | bool Valid; |
||
246 | |||
247 | std::string BuiltinStr; |
||
248 | std::string ClangBuiltinStr; |
||
249 | std::string Str; |
||
250 | std::string ShortStr; |
||
251 | |||
252 | enum class FixedLMULType { LargerThan, SmallerThan }; |
||
253 | |||
254 | RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile); |
||
255 | |||
256 | public: |
||
257 | // Return the string representation of a type, which is an encoded string for |
||
258 | // passing to the BUILTIN() macro in Builtins.def. |
||
259 | const std::string &getBuiltinStr() const { return BuiltinStr; } |
||
260 | |||
261 | // Return the clang builtin type for RVV vector type which are used in the |
||
262 | // riscv_vector.h header file. |
||
263 | const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; } |
||
264 | |||
265 | // Return the C/C++ string representation of a type for use in the |
||
266 | // riscv_vector.h header file. |
||
267 | const std::string &getTypeStr() const { return Str; } |
||
268 | |||
269 | // Return the short name of a type for C/C++ name suffix. |
||
270 | const std::string &getShortStr() { |
||
271 | // Not all types are used in short name, so compute the short name by |
||
272 | // demanded. |
||
273 | if (ShortStr.empty()) |
||
274 | initShortStr(); |
||
275 | return ShortStr; |
||
276 | } |
||
277 | |||
278 | bool isValid() const { return Valid; } |
||
279 | bool isScalar() const { return Scale && *Scale == 0; } |
||
280 | bool isVector() const { return Scale && *Scale != 0; } |
||
281 | bool isVector(unsigned Width) const { |
||
282 | return isVector() && ElementBitwidth == Width; |
||
283 | } |
||
284 | bool isFloat() const { return ScalarType == ScalarTypeKind::Float; } |
||
285 | bool isSignedInteger() const { |
||
286 | return ScalarType == ScalarTypeKind::SignedInteger; |
||
287 | } |
||
288 | bool isFloatVector(unsigned Width) const { |
||
289 | return isVector() && isFloat() && ElementBitwidth == Width; |
||
290 | } |
||
291 | bool isFloat(unsigned Width) const { |
||
292 | return isFloat() && ElementBitwidth == Width; |
||
293 | } |
||
294 | bool isConstant() const { return IsConstant; } |
||
295 | bool isPointer() const { return IsPointer; } |
||
296 | unsigned getElementBitwidth() const { return ElementBitwidth; } |
||
297 | |||
298 | ScalarTypeKind getScalarType() const { return ScalarType; } |
||
299 | VScaleVal getScale() const { return Scale; } |
||
300 | |||
301 | private: |
||
302 | // Verify RVV vector type and set Valid. |
||
303 | bool verifyType() const; |
||
304 | |||
305 | // Creates a type based on basic types of TypeRange |
||
306 | void applyBasicType(); |
||
307 | |||
308 | // Applies a prototype modifier to the current type. The result maybe an |
||
309 | // invalid type. |
||
310 | void applyModifier(const PrototypeDescriptor &prototype); |
||
311 | |||
312 | void applyLog2EEW(unsigned Log2EEW); |
||
313 | void applyFixedSEW(unsigned NewSEW); |
||
314 | void applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type); |
||
315 | |||
316 | // Compute and record a string for legal type. |
||
317 | void initBuiltinStr(); |
||
318 | // Compute and record a builtin RVV vector type string. |
||
319 | void initClangBuiltinStr(); |
||
320 | // Compute and record a type string for used in the header. |
||
321 | void initTypeStr(); |
||
322 | // Compute and record a short name of a type for C/C++ name suffix. |
||
323 | void initShortStr(); |
||
324 | }; |
||
325 | |||
326 | // This class is used to manage RVVType, RVVType should only created by this |
||
327 | // class, also provided thread-safe cache capability. |
||
328 | class RVVTypeCache { |
||
329 | private: |
||
330 | std::unordered_map<uint64_t, RVVType> LegalTypes; |
||
331 | std::set<uint64_t> IllegalTypes; |
||
332 | |||
333 | public: |
||
334 | /// Compute output and input types by applying different config (basic type |
||
335 | /// and LMUL with type transformers). It also record result of type in legal |
||
336 | /// or illegal set to avoid compute the same config again. The result maybe |
||
337 | /// have illegal RVVType. |
||
338 | std::optional<RVVTypes> |
||
339 | computeTypes(BasicType BT, int Log2LMUL, unsigned NF, |
||
340 | llvm::ArrayRef<PrototypeDescriptor> Prototype); |
||
341 | std::optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, |
||
342 | PrototypeDescriptor Proto); |
||
343 | }; |
||
344 | |||
345 | enum PolicyScheme : uint8_t { |
||
346 | SchemeNone, |
||
347 | // Passthru operand is at first parameter in C builtin. |
||
348 | HasPassthruOperand, |
||
349 | HasPolicyOperand, |
||
350 | }; |
||
351 | |||
352 | // TODO refactor RVVIntrinsic class design after support all intrinsic |
||
353 | // combination. This represents an instantiation of an intrinsic with a |
||
354 | // particular type and prototype |
||
355 | class RVVIntrinsic { |
||
356 | |||
357 | private: |
||
358 | std::string BuiltinName; // Builtin name |
||
359 | std::string Name; // C intrinsic name. |
||
360 | std::string OverloadedName; |
||
361 | std::string IRName; |
||
362 | bool IsMasked; |
||
363 | bool HasMaskedOffOperand; |
||
364 | bool HasVL; |
||
365 | PolicyScheme Scheme; |
||
366 | bool SupportOverloading; |
||
367 | bool HasBuiltinAlias; |
||
368 | std::string ManualCodegen; |
||
369 | RVVTypePtr OutputType; // Builtin output type |
||
370 | RVVTypes InputTypes; // Builtin input types |
||
371 | // The types we use to obtain the specific LLVM intrinsic. They are index of |
||
372 | // InputTypes. -1 means the return type. |
||
373 | std::vector<int64_t> IntrinsicTypes; |
||
374 | unsigned NF = 1; |
||
375 | Policy PolicyAttrs; |
||
376 | |||
377 | public: |
||
378 | RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix, |
||
379 | llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix, |
||
380 | llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand, |
||
381 | bool HasVL, PolicyScheme Scheme, bool SupportOverloading, |
||
382 | bool HasBuiltinAlias, llvm::StringRef ManualCodegen, |
||
383 | const RVVTypes &Types, |
||
384 | const std::vector<int64_t> &IntrinsicTypes, |
||
385 | const std::vector<llvm::StringRef> &RequiredFeatures, |
||
386 | unsigned NF, Policy PolicyAttrs); |
||
387 | ~RVVIntrinsic() = default; |
||
388 | |||
389 | RVVTypePtr getOutputType() const { return OutputType; } |
||
390 | const RVVTypes &getInputTypes() const { return InputTypes; } |
||
391 | llvm::StringRef getBuiltinName() const { return BuiltinName; } |
||
392 | llvm::StringRef getName() const { return Name; } |
||
393 | llvm::StringRef getOverloadedName() const { return OverloadedName; } |
||
394 | bool hasMaskedOffOperand() const { return HasMaskedOffOperand; } |
||
395 | bool hasVL() const { return HasVL; } |
||
396 | bool hasPolicy() const { return Scheme != PolicyScheme::SchemeNone; } |
||
397 | bool hasPassthruOperand() const { |
||
398 | return Scheme == PolicyScheme::HasPassthruOperand; |
||
399 | } |
||
400 | bool hasPolicyOperand() const { |
||
401 | return Scheme == PolicyScheme::HasPolicyOperand; |
||
402 | } |
||
403 | bool supportOverloading() const { return SupportOverloading; } |
||
404 | bool hasBuiltinAlias() const { return HasBuiltinAlias; } |
||
405 | bool hasManualCodegen() const { return !ManualCodegen.empty(); } |
||
406 | bool isMasked() const { return IsMasked; } |
||
407 | llvm::StringRef getIRName() const { return IRName; } |
||
408 | llvm::StringRef getManualCodegen() const { return ManualCodegen; } |
||
409 | PolicyScheme getPolicyScheme() const { return Scheme; } |
||
410 | unsigned getNF() const { return NF; } |
||
411 | const std::vector<int64_t> &getIntrinsicTypes() const { |
||
412 | return IntrinsicTypes; |
||
413 | } |
||
414 | Policy getPolicyAttrs() const { |
||
415 | return PolicyAttrs; |
||
416 | } |
||
417 | unsigned getPolicyAttrsBits() const { |
||
418 | // CGBuiltin.cpp |
||
419 | // The 0th bit simulates the `vta` of RVV |
||
420 | // The 1st bit simulates the `vma` of RVV |
||
421 | // int PolicyAttrs = 0; |
||
422 | |||
423 | if (PolicyAttrs.isTUMAPolicy()) |
||
424 | return 2; |
||
425 | if (PolicyAttrs.isTAMAPolicy()) |
||
426 | return 3; |
||
427 | if (PolicyAttrs.isTUMUPolicy()) |
||
428 | return 0; |
||
429 | if (PolicyAttrs.isTAMUPolicy()) |
||
430 | return 1; |
||
431 | |||
432 | llvm_unreachable("unsupport policy"); |
||
433 | return 0; |
||
434 | } |
||
435 | |||
436 | // Return the type string for a BUILTIN() macro in Builtins.def. |
||
437 | std::string getBuiltinTypeStr() const; |
||
438 | |||
439 | static std::string |
||
440 | getSuffixStr(RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL, |
||
441 | llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors); |
||
442 | |||
443 | static llvm::SmallVector<PrototypeDescriptor> |
||
444 | computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype, |
||
445 | bool IsMasked, bool HasMaskedOffOperand, bool HasVL, |
||
446 | unsigned NF, PolicyScheme DefaultScheme, |
||
447 | Policy PolicyAttrs); |
||
448 | |||
449 | static llvm::SmallVector<Policy> getSupportedUnMaskedPolicies(); |
||
450 | static llvm::SmallVector<Policy> |
||
451 | getSupportedMaskedPolicies(bool HasTailPolicy, bool HasMaskPolicy); |
||
452 | |||
453 | static void updateNamesAndPolicy(bool IsMasked, bool HasPolicy, |
||
454 | std::string &Name, std::string &BuiltinName, |
||
455 | std::string &OverloadedName, |
||
456 | Policy &PolicyAttrs); |
||
457 | }; |
||
458 | |||
459 | // RVVRequire should be sync'ed with target features, but only |
||
460 | // required features used in riscv_vector.td. |
||
461 | enum RVVRequire : uint8_t { |
||
462 | RVV_REQ_None = 0, |
||
463 | RVV_REQ_RV64 = 1 << 0, |
||
464 | RVV_REQ_FullMultiply = 1 << 1, |
||
465 | |||
466 | LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_FullMultiply) |
||
467 | }; |
||
468 | |||
469 | // Raw RVV intrinsic info, used to expand later. |
||
470 | // This struct is highly compact for minimized code size. |
||
471 | struct RVVIntrinsicRecord { |
||
472 | // Intrinsic name, e.g. vadd_vv |
||
473 | const char *Name; |
||
474 | |||
475 | // Overloaded intrinsic name, could be empty if it can be computed from Name. |
||
476 | // e.g. vadd |
||
477 | const char *OverloadedName; |
||
478 | |||
479 | // Prototype for this intrinsic, index of RVVSignatureTable. |
||
480 | uint16_t PrototypeIndex; |
||
481 | |||
482 | // Suffix of intrinsic name, index of RVVSignatureTable. |
||
483 | uint16_t SuffixIndex; |
||
484 | |||
485 | // Suffix of overloaded intrinsic name, index of RVVSignatureTable. |
||
486 | uint16_t OverloadedSuffixIndex; |
||
487 | |||
488 | // Length of the prototype. |
||
489 | uint8_t PrototypeLength; |
||
490 | |||
491 | // Length of intrinsic name suffix. |
||
492 | uint8_t SuffixLength; |
||
493 | |||
494 | // Length of overloaded intrinsic suffix. |
||
495 | uint8_t OverloadedSuffixSize; |
||
496 | |||
497 | // Required target features for this intrinsic. |
||
498 | uint8_t RequiredExtensions; |
||
499 | |||
500 | // Supported type, mask of BasicType. |
||
501 | uint8_t TypeRangeMask; |
||
502 | |||
503 | // Supported LMUL. |
||
504 | uint8_t Log2LMULMask; |
||
505 | |||
506 | // Number of fields, greater than 1 if it's segment load/store. |
||
507 | uint8_t NF; |
||
508 | |||
509 | bool HasMasked : 1; |
||
510 | bool HasVL : 1; |
||
511 | bool HasMaskedOffOperand : 1; |
||
512 | bool HasTailPolicy : 1; |
||
513 | bool HasMaskPolicy : 1; |
||
514 | uint8_t UnMaskedPolicyScheme : 2; |
||
515 | uint8_t MaskedPolicyScheme : 2; |
||
516 | }; |
||
517 | |||
518 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
||
519 | const RVVIntrinsicRecord &RVVInstrRecord); |
||
520 | |||
521 | LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); |
||
522 | } // end namespace RISCV |
||
523 | |||
524 | } // end namespace clang |
||
525 | |||
526 | #endif // CLANG_SUPPORT_RISCVVINTRINSICUTILS_H |