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