clang 17.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 {
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.
65enum class BaseTypeModifier : uint8_t {
66 Invalid,
67 Scalar,
68 Vector,
69 Void,
70 SizeT,
71 Ptrdiff,
74};
75
76// Modifier for type, used for both scalar and vector types.
77enum 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,
93};
94
95class Policy {
96public:
100 };
101
102private:
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
108public:
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.
155 constexpr PrototypeDescriptor() = default;
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 }
181 static std::optional<PrototypeDescriptor>
182 parsePrototypeDescriptor(llvm::StringRef PrototypeStr);
183};
184
186parsePrototypes(llvm::StringRef Prototypes);
187
188// Basic type of vector type.
189enum 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,
200};
201
202// Type of vector type.
203enum ScalarTypeKind : uint8_t {
214};
215
216// Exponential LMUL
217struct LMULType {
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
226class RVVType;
228using RVVTypes = std::vector<RVVTypePtr>;
229class RVVTypeCache;
230
231// This class is compact representation of a valid and invalid RVVType.
232class 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
256public:
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
301private:
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.
329private:
330 std::unordered_map<uint64_t, RVVType> LegalTypes;
331 std::set<uint64_t> IllegalTypes;
332
333public:
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,
341 std::optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL,
342 PrototypeDescriptor Proto);
343};
344
345enum PolicyScheme : uint8_t {
347 // Passthru operand is at first parameter in C builtin.
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
356
357private:
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
377public:
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 }
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
445 bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
446 unsigned NF, PolicyScheme DefaultScheme,
447 Policy PolicyAttrs);
448
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.
461enum RVVRequire : uint8_t {
463 RVV_REQ_RV64 = 1 << 0,
465
467};
468
469// Raw RVV intrinsic info, used to expand later.
470// This struct is highly compact for minimized code size.
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.
481
482 // Suffix of intrinsic name, index of RVVSignatureTable.
483 uint16_t SuffixIndex;
484
485 // Suffix of overloaded intrinsic name, index of RVVSignatureTable.
487
488 // Length of the prototype.
490
491 // Length of intrinsic name suffix.
493
494 // Length of overloaded intrinsic suffix.
496
497 // Required target features for this intrinsic.
499
500 // Supported type, mask of BasicType.
502
503 // Supported LMUL.
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;
516};
517
518llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
519 const RVVIntrinsicRecord &RVVInstrRecord);
520
522} // end namespace RISCV
523
524} // end namespace clang
525
526#endif // CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
llvm::raw_ostream & OS
Definition: Logger.cpp:24
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
llvm::StringRef getOverloadedName() const
static std::string getSuffixStr(RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL, llvm::ArrayRef< PrototypeDescriptor > PrototypeDescriptors)
static void updateNamesAndPolicy(bool IsMasked, bool HasPolicy, std::string &Name, std::string &BuiltinName, std::string &OverloadedName, Policy &PolicyAttrs)
static llvm::SmallVector< PrototypeDescriptor > computeBuiltinTypes(llvm::ArrayRef< PrototypeDescriptor > Prototype, bool IsMasked, bool HasMaskedOffOperand, bool HasVL, unsigned NF, PolicyScheme DefaultScheme, Policy PolicyAttrs)
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:1566
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