clang 23.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.
77
78// Similar to basic type but used to describe what's kind of type related to
79// basic vector type, used to compute type info of arguments.
91
92// Modifier for type, used for both scalar and vector types.
93enum class TypeModifier : uint8_t {
95 Pointer = 1 << 0,
96 Const = 1 << 1,
97 Immediate = 1 << 2,
99 SignedInteger = 1 << 4,
100 Float = 1 << 5,
101 BFloat = 1 << 6,
102 // LMUL1 should be kind of VectorTypeModifier, but that might come with
103 // Widening2XVector for widening reduction.
104 // However that might require VectorTypeModifier become bitmask rather than
105 // simple enum, so we decide keek LMUL1 in TypeModifier for code size
106 // optimization of clang binary size.
107 LMUL1 = 1 << 7,
110};
111
112class Policy {
113public:
118
119private:
120 // The default assumption for an RVV instruction is TAMA, as an undisturbed
121 // policy generally will affect the performance of an out-of-order core.
122 const PolicyType TailPolicy = Agnostic;
123 const PolicyType MaskPolicy = Agnostic;
124
125public:
126 Policy() = default;
127 Policy(PolicyType TailPolicy) : TailPolicy(TailPolicy) {}
128 Policy(PolicyType TailPolicy, PolicyType MaskPolicy)
129 : TailPolicy(TailPolicy), MaskPolicy(MaskPolicy) {}
130
131 bool isTAMAPolicy() const {
132 return TailPolicy == Agnostic && MaskPolicy == Agnostic;
133 }
134
135 bool isTAMUPolicy() const {
136 return TailPolicy == Agnostic && MaskPolicy == Undisturbed;
137 }
138
139 bool isTUMAPolicy() const {
140 return TailPolicy == Undisturbed && MaskPolicy == Agnostic;
141 }
142
143 bool isTUMUPolicy() const {
144 return TailPolicy == Undisturbed && MaskPolicy == Undisturbed;
145 }
146
147 bool isTAPolicy() const { return TailPolicy == Agnostic; }
148
149 bool isTUPolicy() const { return TailPolicy == Undisturbed; }
150
151 bool isMAPolicy() const { return MaskPolicy == Agnostic; }
152
153 bool isMUPolicy() const { return MaskPolicy == Undisturbed; }
154
155 bool operator==(const Policy &Other) const {
156 return TailPolicy == Other.TailPolicy && MaskPolicy == Other.MaskPolicy;
157 }
158
159 bool operator!=(const Policy &Other) const { return !(*this == Other); }
160
161 bool operator<(const Policy &Other) const {
162 // Just for maintain the old order for quick test.
163 if (MaskPolicy != Other.MaskPolicy)
164 return Other.MaskPolicy < MaskPolicy;
165 return TailPolicy < Other.TailPolicy;
166 }
167};
168
169// PrototypeDescriptor is used to compute type info of arguments or return
170// value.
172 constexpr PrototypeDescriptor() = default;
178 constexpr PrototypeDescriptor(uint8_t PT, uint8_t VTM, uint8_t TM)
179 : PT(static_cast<BaseTypeModifier>(PT)),
180 VTM(static_cast<VectorTypeModifier>(VTM)),
181 TM(static_cast<TypeModifier>(TM)) {}
182
186
187 bool operator!=(const PrototypeDescriptor &PD) const {
188 return !(*this == PD);
189 }
190 bool operator==(const PrototypeDescriptor &PD) const {
191 return PD.PT == PT && PD.VTM == VTM && PD.TM == TM;
192 }
193 bool operator<(const PrototypeDescriptor &PD) const {
194 return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM);
195 }
199 static std::optional<PrototypeDescriptor>
200 parsePrototypeDescriptor(llvm::StringRef PrototypeStr);
201};
202
204parsePrototypes(llvm::StringRef Prototypes);
205
206// Basic type of vector type.
207enum class BasicType : uint16_t {
209 Int8 = 1 << 0,
210 Int16 = 1 << 1,
211 Int32 = 1 << 2,
212 Int64 = 1 << 3,
213 BFloat16 = 1 << 4,
214 Float16 = 1 << 5,
215 Float32 = 1 << 6,
216 Float64 = 1 << 7,
217 F8E4M3 = 1 << 8,
218 F8E5M2 = 1 << 9,
221};
222
223// Type of vector type.
240
241// Exponential LMUL
242struct LMULType {
244 LMULType(int Log2LMUL);
245 // Return the C/C++ string representation of LMUL
246 std::string str() const;
247 std::optional<unsigned> getScale(unsigned ElementBitwidth) const;
248 void MulLog2LMUL(int Log2LMUL);
249};
250
251class RVVType;
253using RVVTypes = std::vector<RVVTypePtr>;
254class RVVTypeCache;
255
256// This class is compact representation of a valid and invalid RVVType.
257class RVVType {
258 friend class RVVTypeCache;
259
260 BasicType BT;
261 ScalarTypeKind ScalarType = Undefined;
262 LMULType LMUL;
263 bool IsPointer = false;
264 // IsConstant indices are "int", but have the constant expression.
265 bool IsImmediate = false;
266 // Const qualifier for pointer to const object or object of const type.
267 bool IsConstant = false;
268 unsigned ElementBitwidth = 0;
269 VScaleVal Scale = 0;
270 bool Valid;
271 bool IsTuple = false;
272 unsigned NF = 0;
273
274 std::string BuiltinStr;
275 std::string ClangBuiltinStr;
276 std::string Str;
277 std::string ShortStr;
278
279 enum class FixedLMULType { LargerThan, SmallerThan, SmallerOrEqual };
280
281 RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile);
282
283public:
284 // Return the string representation of a type, which is an encoded string for
285 // passing to the BUILTIN() macro in Builtins.def.
286 const std::string &getBuiltinStr() const { return BuiltinStr; }
287
288 // Return the clang builtin type for RVV vector type which are used in the
289 // riscv_vector.h header file.
290 const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; }
291
292 // Return the C/C++ string representation of a type for use in the
293 // riscv_vector.h header file.
294 const std::string &getTypeStr() const { return Str; }
295
296 // Return the short name of a type for C/C++ name suffix.
297 const std::string &getShortStr() {
298 // Not all types are used in short name, so compute the short name by
299 // demanded.
300 if (ShortStr.empty())
301 initShortStr();
302 return ShortStr;
303 }
304
305 bool isValid() const { return Valid; }
306 bool isScalar() const { return Scale && *Scale == 0; }
307 bool isVector() const { return Scale && *Scale != 0; }
308 bool isVector(unsigned Width) const {
309 return isVector() && ElementBitwidth == Width;
310 }
311 bool isFloat() const { return ScalarType == ScalarTypeKind::Float; }
312 bool isBFloat() const { return ScalarType == ScalarTypeKind::BFloat; }
313 bool isSignedInteger() const {
314 return ScalarType == ScalarTypeKind::SignedInteger;
315 }
316 bool isFloatVector(unsigned Width) const {
317 return isVector() && isFloat() && ElementBitwidth == Width;
318 }
319 bool isFloat(unsigned Width) const {
320 return isFloat() && ElementBitwidth == Width;
321 }
322 bool isConstant() const { return IsConstant; }
323 bool isPointer() const { return IsPointer; }
324 bool isTuple() const { return IsTuple; }
325 unsigned getElementBitwidth() const { return ElementBitwidth; }
326
327 ScalarTypeKind getScalarType() const { return ScalarType; }
328 VScaleVal getScale() const { return Scale; }
329 unsigned getNF() const {
330 assert(NF > 1 && NF <= 8 && "Only legal NF should be fetched");
331 return NF;
332 }
333
334private:
335 // Verify RVV vector type and set Valid.
336 bool verifyType() const;
337
338 // Creates a type based on basic types of TypeRange
339 void applyBasicType();
340
341 // Applies a prototype modifier to the current type. The result maybe an
342 // invalid type.
343 void applyModifier(const PrototypeDescriptor &prototype);
344
345 void applyLog2EEW(unsigned Log2EEW);
346 void applyFixedSEW(unsigned NewSEW);
347 void applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type);
348
349 // Compute and record a string for legal type.
350 void initBuiltinStr();
351 // Compute and record a builtin RVV vector type string.
352 void initClangBuiltinStr();
353 // Compute and record a type string for used in the header.
354 void initTypeStr();
355 // Compute and record a short name of a type for C/C++ name suffix.
356 void initShortStr();
357};
358
359// This class is used to manage RVVType, RVVType should only created by this
360// class, also provided thread-safe cache capability.
362private:
363 std::unordered_map<uint64_t, RVVType> LegalTypes;
364 std::set<uint64_t> IllegalTypes;
365
366public:
367 /// Compute output and input types by applying different config (basic type
368 /// and LMUL with type transformers). It also record result of type in legal
369 /// or illegal set to avoid compute the same config again. The result maybe
370 /// have illegal RVVType.
371 std::optional<RVVTypes>
372 computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
374 std::optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL,
375 PrototypeDescriptor Proto);
376};
377
378enum PolicyScheme : uint8_t {
380 // Passthru operand is at first parameter in C builtin.
383};
384
385llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, enum PolicyScheme PS);
386
387// TODO refactor RVVIntrinsic class design after support all intrinsic
388// combination. This represents an instantiation of an intrinsic with a
389// particular type and prototype
391
392private:
393 std::string BuiltinName; // Builtin name
394 std::string Name; // C intrinsic name.
395 std::string OverloadedName;
396 std::string IRName;
397 bool IsMasked;
398 bool HasMaskedOffOperand;
399 bool HasVL;
400 PolicyScheme Scheme;
401 bool SupportOverloading;
402 bool HasBuiltinAlias;
403 std::string ManualCodegen;
404 RVVTypePtr OutputType; // Builtin output type
405 RVVTypes InputTypes; // Builtin input types
406 // The types we use to obtain the specific LLVM intrinsic. They are index of
407 // InputTypes. -1 means the return type.
408 std::vector<int64_t> IntrinsicTypes;
409 unsigned NF = 1;
410 bool HasSegInstSEW = false;
411 Policy PolicyAttrs;
412 unsigned TWiden = 0;
413
414public:
415 RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix,
416 llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix,
417 llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand,
418 bool HasVL, PolicyScheme Scheme, bool SupportOverloading,
419 bool HasBuiltinAlias, llvm::StringRef ManualCodegen,
420 const RVVTypes &Types,
421 const std::vector<int64_t> &IntrinsicTypes, unsigned NF,
422 bool HasSegInstSEW, Policy PolicyAttrs, bool HasFRMRoundModeOp,
423 unsigned TWiden, bool AltFmt);
424 ~RVVIntrinsic() = default;
425
426 RVVTypePtr getOutputType() const { return OutputType; }
427 const RVVTypes &getInputTypes() const { return InputTypes; }
428 llvm::StringRef getBuiltinName() const { return BuiltinName; }
429 bool hasMaskedOffOperand() const { return HasMaskedOffOperand; }
430 bool hasVL() const { return HasVL; }
431 bool hasPolicy() const { return Scheme != PolicyScheme::SchemeNone; }
432 bool hasPassthruOperand() const {
433 return Scheme == PolicyScheme::HasPassthruOperand;
434 }
435 bool hasPolicyOperand() const {
436 return Scheme == PolicyScheme::HasPolicyOperand;
437 }
438 bool supportOverloading() const { return SupportOverloading; }
439 bool hasBuiltinAlias() const { return HasBuiltinAlias; }
440 bool hasManualCodegen() const { return !ManualCodegen.empty(); }
441 bool isMasked() const { return IsMasked; }
442 llvm::StringRef getOverloadedName() const { return OverloadedName; }
443 llvm::StringRef getIRName() const { return IRName; }
444 llvm::StringRef getManualCodegen() const { return ManualCodegen; }
445 PolicyScheme getPolicyScheme() const { return Scheme; }
446 unsigned getNF() const { return NF; }
447 bool hasSegInstSEW() const { return HasSegInstSEW; }
448 unsigned getTWiden() const { return TWiden; }
449 const std::vector<int64_t> &getIntrinsicTypes() const {
450 return IntrinsicTypes;
451 }
453 return PolicyAttrs;
454 }
455 unsigned getPolicyAttrsBits() const {
456 // CGBuiltin.cpp
457 // The 0th bit simulates the `vta` of RVV
458 // The 1st bit simulates the `vma` of RVV
459 // int PolicyAttrs = 0;
460
461 if (PolicyAttrs.isTUMAPolicy())
462 return 2;
463 if (PolicyAttrs.isTAMAPolicy())
464 return 3;
465 if (PolicyAttrs.isTUMUPolicy())
466 return 0;
467 if (PolicyAttrs.isTAMUPolicy())
468 return 1;
469
470 llvm_unreachable("unsupport policy");
471 return 0;
472 }
473
474 // Return the type string for a BUILTIN() macro in Builtins.def.
475 std::string getBuiltinTypeStr() const;
476
477 static std::string
478 getSuffixStr(RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
479 llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
480
483 bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
484 unsigned NF, PolicyScheme DefaultScheme,
485 Policy PolicyAttrs, bool IsTuple);
486
489 getSupportedMaskedPolicies(bool HasTailPolicy, bool HasMaskPolicy);
490
491 static void updateNamesAndPolicy(bool IsMasked, bool HasPolicy,
492 std::string &Name, std::string &BuiltinName,
493 std::string &OverloadedName,
494 Policy &PolicyAttrs, bool HasFRMRoundModeOp,
495 bool AltFmt);
496};
497
498// Raw RVV intrinsic info, used to expand later.
499// This struct is highly compact for minimized code size.
501 // Intrinsic name, e.g. vadd_vv
502 const char *Name;
503
504 // Overloaded intrinsic name, could be empty if it can be computed from Name.
505 // e.g. vadd
506 const char *OverloadedName;
507
508 // Required target features for this intrinsic.
510
511 // Prototype for this intrinsic, index of RVVSignatureTable.
513
514 // Suffix of intrinsic name, index of RVVSignatureTable.
515 uint16_t SuffixIndex;
516
517 // Suffix of overloaded intrinsic name, index of RVVSignatureTable.
519
520 // Length of the prototype.
522
523 // Length of intrinsic name suffix.
525
526 // Length of overloaded intrinsic suffix.
528
529 // Supported type, mask of BasicType.
531
532 // Supported LMUL.
534
535 // Number of fields, greater than 1 if it's segment load/store.
536 uint8_t NF;
537
538 bool HasMasked : 1;
539 bool HasVL : 1;
544 bool AltFmt : 1;
545 bool IsTuple : 1;
546 LLVM_PREFERRED_TYPE(PolicyScheme)
548 LLVM_PREFERRED_TYPE(PolicyScheme)
550};
551
552llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
553 const RVVIntrinsicRecord &RVVInstrRecord);
554
556} // end namespace RISCV
557
558} // end namespace clang
559
560#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)
RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix, llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix, llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand, bool HasVL, PolicyScheme Scheme, bool SupportOverloading, bool HasBuiltinAlias, llvm::StringRef ManualCodegen, const RVVTypes &Types, const std::vector< int64_t > &IntrinsicTypes, unsigned NF, bool HasSegInstSEW, Policy PolicyAttrs, bool HasFRMRoundModeOp, unsigned TWiden, bool AltFmt)
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)
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, bool HasFRMRoundModeOp, bool AltFmt)
static llvm::SmallVector< Policy > getSupportedUnMaskedPolicies()
llvm::StringRef getManualCodegen() const
const RVVTypes & getInputTypes() 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
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 TypeBase.h:1875
RISCV builtins.
std::optional< unsigned > VScaleVal
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, enum PolicyScheme PS)
llvm::SmallVector< PrototypeDescriptor > parsePrototypes(llvm::StringRef Prototypes)
std::vector< RVVTypePtr > RVVTypes
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()
The JSON file list parser is used to communicate input to InstallAPI.
@ Other
Other implicit parameter.
Definition Decl.h:1763
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
std::optional< unsigned > getScale(unsigned ElementBitwidth) const
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