181ad6265SDimitry Andric //===--- RISCVVIntrinsicUtils.h - RISC-V Vector Intrinsic Utils -*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #ifndef CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
1081ad6265SDimitry Andric #define CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
1181ad6265SDimitry Andric 
1281ad6265SDimitry Andric #include "llvm/ADT/ArrayRef.h"
1381ad6265SDimitry Andric #include "llvm/ADT/BitmaskEnum.h"
1481ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
1581ad6265SDimitry Andric #include "llvm/ADT/StringRef.h"
1681ad6265SDimitry Andric #include <cstdint>
17bdd1243dSDimitry Andric #include <optional>
18bdd1243dSDimitry Andric #include <set>
1981ad6265SDimitry Andric #include <string>
20bdd1243dSDimitry Andric #include <unordered_map>
2181ad6265SDimitry Andric #include <vector>
2281ad6265SDimitry Andric 
23972a253aSDimitry Andric namespace llvm {
24972a253aSDimitry Andric class raw_ostream;
25972a253aSDimitry Andric } // end namespace llvm
26972a253aSDimitry Andric 
2781ad6265SDimitry Andric namespace clang {
2881ad6265SDimitry Andric namespace RISCV {
2981ad6265SDimitry Andric 
30bdd1243dSDimitry Andric using VScaleVal = std::optional<unsigned>;
3181ad6265SDimitry Andric 
3281ad6265SDimitry Andric // Modifier for vector type.
3381ad6265SDimitry Andric enum class VectorTypeModifier : uint8_t {
3481ad6265SDimitry Andric   NoModifier,
3581ad6265SDimitry Andric   Widening2XVector,
3681ad6265SDimitry Andric   Widening4XVector,
3781ad6265SDimitry Andric   Widening8XVector,
3881ad6265SDimitry Andric   MaskVector,
3981ad6265SDimitry Andric   Log2EEW3,
4081ad6265SDimitry Andric   Log2EEW4,
4181ad6265SDimitry Andric   Log2EEW5,
4281ad6265SDimitry Andric   Log2EEW6,
4381ad6265SDimitry Andric   FixedSEW8,
4481ad6265SDimitry Andric   FixedSEW16,
4581ad6265SDimitry Andric   FixedSEW32,
4681ad6265SDimitry Andric   FixedSEW64,
4781ad6265SDimitry Andric   LFixedLog2LMULN3,
4881ad6265SDimitry Andric   LFixedLog2LMULN2,
4981ad6265SDimitry Andric   LFixedLog2LMULN1,
5081ad6265SDimitry Andric   LFixedLog2LMUL0,
5181ad6265SDimitry Andric   LFixedLog2LMUL1,
5281ad6265SDimitry Andric   LFixedLog2LMUL2,
5381ad6265SDimitry Andric   LFixedLog2LMUL3,
5481ad6265SDimitry Andric   SFixedLog2LMULN3,
5581ad6265SDimitry Andric   SFixedLog2LMULN2,
5681ad6265SDimitry Andric   SFixedLog2LMULN1,
5781ad6265SDimitry Andric   SFixedLog2LMUL0,
5881ad6265SDimitry Andric   SFixedLog2LMUL1,
5981ad6265SDimitry Andric   SFixedLog2LMUL2,
6081ad6265SDimitry Andric   SFixedLog2LMUL3,
615f757f3fSDimitry Andric   SEFixedLog2LMULN3,
625f757f3fSDimitry Andric   SEFixedLog2LMULN2,
635f757f3fSDimitry Andric   SEFixedLog2LMULN1,
645f757f3fSDimitry Andric   SEFixedLog2LMUL0,
655f757f3fSDimitry Andric   SEFixedLog2LMUL1,
665f757f3fSDimitry Andric   SEFixedLog2LMUL2,
675f757f3fSDimitry Andric   SEFixedLog2LMUL3,
6806c3fb27SDimitry Andric   Tuple2,
6906c3fb27SDimitry Andric   Tuple3,
7006c3fb27SDimitry Andric   Tuple4,
7106c3fb27SDimitry Andric   Tuple5,
7206c3fb27SDimitry Andric   Tuple6,
7306c3fb27SDimitry Andric   Tuple7,
7406c3fb27SDimitry Andric   Tuple8,
7581ad6265SDimitry Andric };
7681ad6265SDimitry Andric 
7781ad6265SDimitry Andric // Similar to basic type but used to describe what's kind of type related to
7881ad6265SDimitry Andric // basic vector type, used to compute type info of arguments.
7981ad6265SDimitry Andric enum class BaseTypeModifier : uint8_t {
8081ad6265SDimitry Andric   Invalid,
8181ad6265SDimitry Andric   Scalar,
8281ad6265SDimitry Andric   Vector,
8381ad6265SDimitry Andric   Void,
8481ad6265SDimitry Andric   SizeT,
8581ad6265SDimitry Andric   Ptrdiff,
8681ad6265SDimitry Andric   UnsignedLong,
8781ad6265SDimitry Andric   SignedLong,
885f757f3fSDimitry Andric   Float32
8981ad6265SDimitry Andric };
9081ad6265SDimitry Andric 
9181ad6265SDimitry Andric // Modifier for type, used for both scalar and vector types.
9281ad6265SDimitry Andric enum class TypeModifier : uint8_t {
9381ad6265SDimitry Andric   NoModifier = 0,
9481ad6265SDimitry Andric   Pointer = 1 << 0,
9581ad6265SDimitry Andric   Const = 1 << 1,
9681ad6265SDimitry Andric   Immediate = 1 << 2,
9781ad6265SDimitry Andric   UnsignedInteger = 1 << 3,
9881ad6265SDimitry Andric   SignedInteger = 1 << 4,
9981ad6265SDimitry Andric   Float = 1 << 5,
1005f757f3fSDimitry Andric   BFloat = 1 << 6,
10181ad6265SDimitry Andric   // LMUL1 should be kind of VectorTypeModifier, but that might come with
10281ad6265SDimitry Andric   // Widening2XVector for widening reduction.
10381ad6265SDimitry Andric   // However that might require VectorTypeModifier become bitmask rather than
10481ad6265SDimitry Andric   // simple enum, so we decide keek LMUL1 in TypeModifier for code size
10581ad6265SDimitry Andric   // optimization of clang binary size.
1065f757f3fSDimitry Andric   LMUL1 = 1 << 7,
1075f757f3fSDimitry Andric   MaxOffset = 7,
10881ad6265SDimitry Andric   LLVM_MARK_AS_BITMASK_ENUM(LMUL1),
10981ad6265SDimitry Andric };
11081ad6265SDimitry Andric 
1111ac55f4cSDimitry Andric class Policy {
1121ac55f4cSDimitry Andric public:
113bdd1243dSDimitry Andric   enum PolicyType {
114bdd1243dSDimitry Andric     Undisturbed,
115bdd1243dSDimitry Andric     Agnostic,
116bdd1243dSDimitry Andric   };
1171ac55f4cSDimitry Andric 
1181ac55f4cSDimitry Andric private:
1191ac55f4cSDimitry Andric   // The default assumption for an RVV instruction is TAMA, as an undisturbed
1201ac55f4cSDimitry Andric   // policy generally will affect the performance of an out-of-order core.
1211ac55f4cSDimitry Andric   const PolicyType TailPolicy = Agnostic;
1221ac55f4cSDimitry Andric   const PolicyType MaskPolicy = Agnostic;
1231ac55f4cSDimitry Andric 
1241ac55f4cSDimitry Andric public:
1251ac55f4cSDimitry Andric   Policy() = default;
Policy(PolicyType TailPolicy)1261ac55f4cSDimitry Andric   Policy(PolicyType TailPolicy) : TailPolicy(TailPolicy) {}
Policy(PolicyType TailPolicy,PolicyType MaskPolicy)1271ac55f4cSDimitry Andric   Policy(PolicyType TailPolicy, PolicyType MaskPolicy)
1281ac55f4cSDimitry Andric       : TailPolicy(TailPolicy), MaskPolicy(MaskPolicy) {}
129bdd1243dSDimitry Andric 
isTAMAPolicy()130bdd1243dSDimitry Andric   bool isTAMAPolicy() const {
131bdd1243dSDimitry Andric     return TailPolicy == Agnostic && MaskPolicy == Agnostic;
132bdd1243dSDimitry Andric   }
133bdd1243dSDimitry Andric 
isTAMUPolicy()134bdd1243dSDimitry Andric   bool isTAMUPolicy() const {
135bdd1243dSDimitry Andric     return TailPolicy == Agnostic && MaskPolicy == Undisturbed;
136bdd1243dSDimitry Andric   }
137bdd1243dSDimitry Andric 
isTUMAPolicy()138bdd1243dSDimitry Andric   bool isTUMAPolicy() const {
139bdd1243dSDimitry Andric     return TailPolicy == Undisturbed && MaskPolicy == Agnostic;
140bdd1243dSDimitry Andric   }
141bdd1243dSDimitry Andric 
isTUMUPolicy()142bdd1243dSDimitry Andric   bool isTUMUPolicy() const {
143bdd1243dSDimitry Andric     return TailPolicy == Undisturbed && MaskPolicy == Undisturbed;
144bdd1243dSDimitry Andric   }
145bdd1243dSDimitry Andric 
isTAPolicy()146bdd1243dSDimitry Andric   bool isTAPolicy() const { return TailPolicy == Agnostic; }
147bdd1243dSDimitry Andric 
isTUPolicy()148bdd1243dSDimitry Andric   bool isTUPolicy() const { return TailPolicy == Undisturbed; }
149bdd1243dSDimitry Andric 
isMAPolicy()150bdd1243dSDimitry Andric   bool isMAPolicy() const { return MaskPolicy == Agnostic; }
151bdd1243dSDimitry Andric 
isMUPolicy()152bdd1243dSDimitry Andric   bool isMUPolicy() const { return MaskPolicy == Undisturbed; }
153bdd1243dSDimitry Andric 
154bdd1243dSDimitry Andric   bool operator==(const Policy &Other) const {
1551ac55f4cSDimitry Andric     return TailPolicy == Other.TailPolicy && MaskPolicy == Other.MaskPolicy;
156bdd1243dSDimitry Andric   }
157bdd1243dSDimitry Andric 
158bdd1243dSDimitry Andric   bool operator!=(const Policy &Other) const { return !(*this == Other); }
159bdd1243dSDimitry Andric 
160bdd1243dSDimitry Andric   bool operator<(const Policy &Other) const {
161bdd1243dSDimitry Andric     // Just for maintain the old order for quick test.
162bdd1243dSDimitry Andric     if (MaskPolicy != Other.MaskPolicy)
163bdd1243dSDimitry Andric       return Other.MaskPolicy < MaskPolicy;
164bdd1243dSDimitry Andric     return TailPolicy < Other.TailPolicy;
165bdd1243dSDimitry Andric   }
166bdd1243dSDimitry Andric };
167bdd1243dSDimitry Andric 
16881ad6265SDimitry Andric // PrototypeDescriptor is used to compute type info of arguments or return
16981ad6265SDimitry Andric // value.
17081ad6265SDimitry Andric struct PrototypeDescriptor {
17181ad6265SDimitry Andric   constexpr PrototypeDescriptor() = default;
17281ad6265SDimitry Andric   constexpr PrototypeDescriptor(
17381ad6265SDimitry Andric       BaseTypeModifier PT,
17481ad6265SDimitry Andric       VectorTypeModifier VTM = VectorTypeModifier::NoModifier,
17581ad6265SDimitry Andric       TypeModifier TM = TypeModifier::NoModifier)
PTPrototypeDescriptor17681ad6265SDimitry Andric       : PT(static_cast<uint8_t>(PT)), VTM(static_cast<uint8_t>(VTM)),
17781ad6265SDimitry Andric         TM(static_cast<uint8_t>(TM)) {}
PrototypeDescriptorPrototypeDescriptor17881ad6265SDimitry Andric   constexpr PrototypeDescriptor(uint8_t PT, uint8_t VTM, uint8_t TM)
17981ad6265SDimitry Andric       : PT(PT), VTM(VTM), TM(TM) {}
18081ad6265SDimitry Andric 
18181ad6265SDimitry Andric   uint8_t PT = static_cast<uint8_t>(BaseTypeModifier::Invalid);
18281ad6265SDimitry Andric   uint8_t VTM = static_cast<uint8_t>(VectorTypeModifier::NoModifier);
18381ad6265SDimitry Andric   uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier);
18481ad6265SDimitry Andric 
18581ad6265SDimitry Andric   bool operator!=(const PrototypeDescriptor &PD) const {
186972a253aSDimitry Andric     return !(*this == PD);
18781ad6265SDimitry Andric   }
188972a253aSDimitry Andric   bool operator==(const PrototypeDescriptor &PD) const {
189972a253aSDimitry Andric     return PD.PT == PT && PD.VTM == VTM && PD.TM == TM;
19081ad6265SDimitry Andric   }
191972a253aSDimitry Andric   bool operator<(const PrototypeDescriptor &PD) const {
192972a253aSDimitry Andric     return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM);
193972a253aSDimitry Andric   }
19481ad6265SDimitry Andric   static const PrototypeDescriptor Mask;
19581ad6265SDimitry Andric   static const PrototypeDescriptor Vector;
19681ad6265SDimitry Andric   static const PrototypeDescriptor VL;
197bdd1243dSDimitry Andric   static std::optional<PrototypeDescriptor>
19881ad6265SDimitry Andric   parsePrototypeDescriptor(llvm::StringRef PrototypeStr);
19981ad6265SDimitry Andric };
20081ad6265SDimitry Andric 
20181ad6265SDimitry Andric llvm::SmallVector<PrototypeDescriptor>
20281ad6265SDimitry Andric parsePrototypes(llvm::StringRef Prototypes);
20381ad6265SDimitry Andric 
20481ad6265SDimitry Andric // Basic type of vector type.
20581ad6265SDimitry Andric enum class BasicType : uint8_t {
20681ad6265SDimitry Andric   Unknown = 0,
20781ad6265SDimitry Andric   Int8 = 1 << 0,
20881ad6265SDimitry Andric   Int16 = 1 << 1,
20981ad6265SDimitry Andric   Int32 = 1 << 2,
21081ad6265SDimitry Andric   Int64 = 1 << 3,
2115f757f3fSDimitry Andric   BFloat16 = 1 << 4,
2125f757f3fSDimitry Andric   Float16 = 1 << 5,
2135f757f3fSDimitry Andric   Float32 = 1 << 6,
2145f757f3fSDimitry Andric   Float64 = 1 << 7,
2155f757f3fSDimitry Andric   MaxOffset = 7,
21681ad6265SDimitry Andric   LLVM_MARK_AS_BITMASK_ENUM(Float64),
21781ad6265SDimitry Andric };
21881ad6265SDimitry Andric 
21981ad6265SDimitry Andric // Type of vector type.
22081ad6265SDimitry Andric enum ScalarTypeKind : uint8_t {
22181ad6265SDimitry Andric   Void,
22281ad6265SDimitry Andric   Size_t,
22381ad6265SDimitry Andric   Ptrdiff_t,
22481ad6265SDimitry Andric   UnsignedLong,
22581ad6265SDimitry Andric   SignedLong,
22681ad6265SDimitry Andric   Boolean,
22781ad6265SDimitry Andric   SignedInteger,
22881ad6265SDimitry Andric   UnsignedInteger,
22981ad6265SDimitry Andric   Float,
2305f757f3fSDimitry Andric   BFloat,
23181ad6265SDimitry Andric   Invalid,
2325f757f3fSDimitry Andric   Undefined,
23381ad6265SDimitry Andric };
23481ad6265SDimitry Andric 
23581ad6265SDimitry Andric // Exponential LMUL
23681ad6265SDimitry Andric struct LMULType {
23781ad6265SDimitry Andric   int Log2LMUL;
23881ad6265SDimitry Andric   LMULType(int Log2LMUL);
23981ad6265SDimitry Andric   // Return the C/C++ string representation of LMUL
24081ad6265SDimitry Andric   std::string str() const;
241bdd1243dSDimitry Andric   std::optional<unsigned> getScale(unsigned ElementBitwidth) const;
24281ad6265SDimitry Andric   void MulLog2LMUL(int Log2LMUL);
24381ad6265SDimitry Andric };
24481ad6265SDimitry Andric 
24581ad6265SDimitry Andric class RVVType;
24681ad6265SDimitry Andric using RVVTypePtr = RVVType *;
24781ad6265SDimitry Andric using RVVTypes = std::vector<RVVTypePtr>;
248bdd1243dSDimitry Andric class RVVTypeCache;
24981ad6265SDimitry Andric 
25081ad6265SDimitry Andric // This class is compact representation of a valid and invalid RVVType.
25181ad6265SDimitry Andric class RVVType {
252bdd1243dSDimitry Andric   friend class RVVTypeCache;
253bdd1243dSDimitry Andric 
25481ad6265SDimitry Andric   BasicType BT;
2555f757f3fSDimitry Andric   ScalarTypeKind ScalarType = Undefined;
25681ad6265SDimitry Andric   LMULType LMUL;
25781ad6265SDimitry Andric   bool IsPointer = false;
25881ad6265SDimitry Andric   // IsConstant indices are "int", but have the constant expression.
25981ad6265SDimitry Andric   bool IsImmediate = false;
26081ad6265SDimitry Andric   // Const qualifier for pointer to const object or object of const type.
26181ad6265SDimitry Andric   bool IsConstant = false;
26281ad6265SDimitry Andric   unsigned ElementBitwidth = 0;
26381ad6265SDimitry Andric   VScaleVal Scale = 0;
26481ad6265SDimitry Andric   bool Valid;
26506c3fb27SDimitry Andric   bool IsTuple = false;
26606c3fb27SDimitry Andric   unsigned NF = 0;
26781ad6265SDimitry Andric 
26881ad6265SDimitry Andric   std::string BuiltinStr;
26981ad6265SDimitry Andric   std::string ClangBuiltinStr;
27081ad6265SDimitry Andric   std::string Str;
27181ad6265SDimitry Andric   std::string ShortStr;
27281ad6265SDimitry Andric 
2735f757f3fSDimitry Andric   enum class FixedLMULType { LargerThan, SmallerThan, SmallerOrEqual };
27481ad6265SDimitry Andric 
27581ad6265SDimitry Andric   RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile);
27681ad6265SDimitry Andric 
277bdd1243dSDimitry Andric public:
27881ad6265SDimitry Andric   // Return the string representation of a type, which is an encoded string for
27981ad6265SDimitry Andric   // passing to the BUILTIN() macro in Builtins.def.
getBuiltinStr()28081ad6265SDimitry Andric   const std::string &getBuiltinStr() const { return BuiltinStr; }
28181ad6265SDimitry Andric 
28281ad6265SDimitry Andric   // Return the clang builtin type for RVV vector type which are used in the
28381ad6265SDimitry Andric   // riscv_vector.h header file.
getClangBuiltinStr()28481ad6265SDimitry Andric   const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; }
28581ad6265SDimitry Andric 
28681ad6265SDimitry Andric   // Return the C/C++ string representation of a type for use in the
28781ad6265SDimitry Andric   // riscv_vector.h header file.
getTypeStr()28881ad6265SDimitry Andric   const std::string &getTypeStr() const { return Str; }
28981ad6265SDimitry Andric 
29081ad6265SDimitry Andric   // Return the short name of a type for C/C++ name suffix.
getShortStr()29181ad6265SDimitry Andric   const std::string &getShortStr() {
29281ad6265SDimitry Andric     // Not all types are used in short name, so compute the short name by
29381ad6265SDimitry Andric     // demanded.
29481ad6265SDimitry Andric     if (ShortStr.empty())
29581ad6265SDimitry Andric       initShortStr();
29681ad6265SDimitry Andric     return ShortStr;
29781ad6265SDimitry Andric   }
29881ad6265SDimitry Andric 
isValid()29981ad6265SDimitry Andric   bool isValid() const { return Valid; }
isScalar()300bdd1243dSDimitry Andric   bool isScalar() const { return Scale && *Scale == 0; }
isVector()301bdd1243dSDimitry Andric   bool isVector() const { return Scale && *Scale != 0; }
isVector(unsigned Width)30281ad6265SDimitry Andric   bool isVector(unsigned Width) const {
30381ad6265SDimitry Andric     return isVector() && ElementBitwidth == Width;
30481ad6265SDimitry Andric   }
isFloat()30581ad6265SDimitry Andric   bool isFloat() const { return ScalarType == ScalarTypeKind::Float; }
isBFloat()3065f757f3fSDimitry Andric   bool isBFloat() const { return ScalarType == ScalarTypeKind::BFloat; }
isSignedInteger()30781ad6265SDimitry Andric   bool isSignedInteger() const {
30881ad6265SDimitry Andric     return ScalarType == ScalarTypeKind::SignedInteger;
30981ad6265SDimitry Andric   }
isFloatVector(unsigned Width)31081ad6265SDimitry Andric   bool isFloatVector(unsigned Width) const {
31181ad6265SDimitry Andric     return isVector() && isFloat() && ElementBitwidth == Width;
31281ad6265SDimitry Andric   }
isFloat(unsigned Width)31381ad6265SDimitry Andric   bool isFloat(unsigned Width) const {
31481ad6265SDimitry Andric     return isFloat() && ElementBitwidth == Width;
31581ad6265SDimitry Andric   }
isConstant()316972a253aSDimitry Andric   bool isConstant() const { return IsConstant; }
isPointer()317753f127fSDimitry Andric   bool isPointer() const { return IsPointer; }
isTuple()31806c3fb27SDimitry Andric   bool isTuple() const { return IsTuple; }
getElementBitwidth()319972a253aSDimitry Andric   unsigned getElementBitwidth() const { return ElementBitwidth; }
320972a253aSDimitry Andric 
getScalarType()321972a253aSDimitry Andric   ScalarTypeKind getScalarType() const { return ScalarType; }
getScale()322972a253aSDimitry Andric   VScaleVal getScale() const { return Scale; }
getNF()32306c3fb27SDimitry Andric   unsigned getNF() const {
32406c3fb27SDimitry Andric     assert(NF > 1 && NF <= 8 && "Only legal NF should be fetched");
32506c3fb27SDimitry Andric     return NF;
32606c3fb27SDimitry Andric   }
327753f127fSDimitry Andric 
32881ad6265SDimitry Andric private:
32981ad6265SDimitry Andric   // Verify RVV vector type and set Valid.
33081ad6265SDimitry Andric   bool verifyType() const;
33181ad6265SDimitry Andric 
33281ad6265SDimitry Andric   // Creates a type based on basic types of TypeRange
33381ad6265SDimitry Andric   void applyBasicType();
33481ad6265SDimitry Andric 
33581ad6265SDimitry Andric   // Applies a prototype modifier to the current type. The result maybe an
33681ad6265SDimitry Andric   // invalid type.
33781ad6265SDimitry Andric   void applyModifier(const PrototypeDescriptor &prototype);
33881ad6265SDimitry Andric 
33981ad6265SDimitry Andric   void applyLog2EEW(unsigned Log2EEW);
34081ad6265SDimitry Andric   void applyFixedSEW(unsigned NewSEW);
34181ad6265SDimitry Andric   void applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type);
34281ad6265SDimitry Andric 
34381ad6265SDimitry Andric   // Compute and record a string for legal type.
34481ad6265SDimitry Andric   void initBuiltinStr();
34581ad6265SDimitry Andric   // Compute and record a builtin RVV vector type string.
34681ad6265SDimitry Andric   void initClangBuiltinStr();
34781ad6265SDimitry Andric   // Compute and record a type string for used in the header.
34881ad6265SDimitry Andric   void initTypeStr();
34981ad6265SDimitry Andric   // Compute and record a short name of a type for C/C++ name suffix.
35081ad6265SDimitry Andric   void initShortStr();
351bdd1243dSDimitry Andric };
352bdd1243dSDimitry Andric 
353bdd1243dSDimitry Andric // This class is used to manage RVVType, RVVType should only created by this
354bdd1243dSDimitry Andric // class, also provided thread-safe cache capability.
355bdd1243dSDimitry Andric class RVVTypeCache {
356bdd1243dSDimitry Andric private:
357bdd1243dSDimitry Andric   std::unordered_map<uint64_t, RVVType> LegalTypes;
358bdd1243dSDimitry Andric   std::set<uint64_t> IllegalTypes;
35981ad6265SDimitry Andric 
36081ad6265SDimitry Andric public:
36181ad6265SDimitry Andric   /// Compute output and input types by applying different config (basic type
36281ad6265SDimitry Andric   /// and LMUL with type transformers). It also record result of type in legal
36381ad6265SDimitry Andric   /// or illegal set to avoid compute the same config again. The result maybe
36481ad6265SDimitry Andric   /// have illegal RVVType.
365bdd1243dSDimitry Andric   std::optional<RVVTypes>
36681ad6265SDimitry Andric   computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
36781ad6265SDimitry Andric                llvm::ArrayRef<PrototypeDescriptor> Prototype);
368bdd1243dSDimitry Andric   std::optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL,
36981ad6265SDimitry Andric                                         PrototypeDescriptor Proto);
37081ad6265SDimitry Andric };
37181ad6265SDimitry Andric 
37281ad6265SDimitry Andric enum PolicyScheme : uint8_t {
37381ad6265SDimitry Andric   SchemeNone,
374bdd1243dSDimitry Andric   // Passthru operand is at first parameter in C builtin.
37581ad6265SDimitry Andric   HasPassthruOperand,
37681ad6265SDimitry Andric   HasPolicyOperand,
37781ad6265SDimitry Andric };
37881ad6265SDimitry Andric 
37981ad6265SDimitry Andric // TODO refactor RVVIntrinsic class design after support all intrinsic
38081ad6265SDimitry Andric // combination. This represents an instantiation of an intrinsic with a
38181ad6265SDimitry Andric // particular type and prototype
38281ad6265SDimitry Andric class RVVIntrinsic {
38381ad6265SDimitry Andric 
38481ad6265SDimitry Andric private:
38581ad6265SDimitry Andric   std::string BuiltinName; // Builtin name
38681ad6265SDimitry Andric   std::string Name;        // C intrinsic name.
38781ad6265SDimitry Andric   std::string OverloadedName;
38881ad6265SDimitry Andric   std::string IRName;
38981ad6265SDimitry Andric   bool IsMasked;
390bdd1243dSDimitry Andric   bool HasMaskedOffOperand;
39181ad6265SDimitry Andric   bool HasVL;
39281ad6265SDimitry Andric   PolicyScheme Scheme;
393bdd1243dSDimitry Andric   bool SupportOverloading;
39481ad6265SDimitry Andric   bool HasBuiltinAlias;
39581ad6265SDimitry Andric   std::string ManualCodegen;
39681ad6265SDimitry Andric   RVVTypePtr OutputType; // Builtin output type
39781ad6265SDimitry Andric   RVVTypes InputTypes;   // Builtin input types
39881ad6265SDimitry Andric   // The types we use to obtain the specific LLVM intrinsic. They are index of
39981ad6265SDimitry Andric   // InputTypes. -1 means the return type.
40081ad6265SDimitry Andric   std::vector<int64_t> IntrinsicTypes;
40181ad6265SDimitry Andric   unsigned NF = 1;
402bdd1243dSDimitry Andric   Policy PolicyAttrs;
40381ad6265SDimitry Andric 
40481ad6265SDimitry Andric public:
40581ad6265SDimitry Andric   RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix,
40681ad6265SDimitry Andric                llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix,
40781ad6265SDimitry Andric                llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand,
408bdd1243dSDimitry Andric                bool HasVL, PolicyScheme Scheme, bool SupportOverloading,
40981ad6265SDimitry Andric                bool HasBuiltinAlias, llvm::StringRef ManualCodegen,
41081ad6265SDimitry Andric                const RVVTypes &Types,
41181ad6265SDimitry Andric                const std::vector<int64_t> &IntrinsicTypes,
41281ad6265SDimitry Andric                const std::vector<llvm::StringRef> &RequiredFeatures,
41306c3fb27SDimitry Andric                unsigned NF, Policy PolicyAttrs, bool HasFRMRoundModeOp);
41481ad6265SDimitry Andric   ~RVVIntrinsic() = default;
41581ad6265SDimitry Andric 
getOutputType()41681ad6265SDimitry Andric   RVVTypePtr getOutputType() const { return OutputType; }
getInputTypes()41781ad6265SDimitry Andric   const RVVTypes &getInputTypes() const { return InputTypes; }
getBuiltinName()41881ad6265SDimitry Andric   llvm::StringRef getBuiltinName() const { return BuiltinName; }
getName()41981ad6265SDimitry Andric   llvm::StringRef getName() const { return Name; }
getOverloadedName()42081ad6265SDimitry Andric   llvm::StringRef getOverloadedName() const { return OverloadedName; }
hasMaskedOffOperand()421bdd1243dSDimitry Andric   bool hasMaskedOffOperand() const { return HasMaskedOffOperand; }
hasVL()42281ad6265SDimitry Andric   bool hasVL() const { return HasVL; }
hasPolicy()423bdd1243dSDimitry Andric   bool hasPolicy() const { return Scheme != PolicyScheme::SchemeNone; }
hasPassthruOperand()424bdd1243dSDimitry Andric   bool hasPassthruOperand() const {
425bdd1243dSDimitry Andric     return Scheme == PolicyScheme::HasPassthruOperand;
426bdd1243dSDimitry Andric   }
hasPolicyOperand()427bdd1243dSDimitry Andric   bool hasPolicyOperand() const {
428bdd1243dSDimitry Andric     return Scheme == PolicyScheme::HasPolicyOperand;
429bdd1243dSDimitry Andric   }
supportOverloading()430bdd1243dSDimitry Andric   bool supportOverloading() const { return SupportOverloading; }
hasBuiltinAlias()43181ad6265SDimitry Andric   bool hasBuiltinAlias() const { return HasBuiltinAlias; }
hasManualCodegen()43281ad6265SDimitry Andric   bool hasManualCodegen() const { return !ManualCodegen.empty(); }
isMasked()43381ad6265SDimitry Andric   bool isMasked() const { return IsMasked; }
getIRName()43481ad6265SDimitry Andric   llvm::StringRef getIRName() const { return IRName; }
getManualCodegen()43581ad6265SDimitry Andric   llvm::StringRef getManualCodegen() const { return ManualCodegen; }
getPolicyScheme()43681ad6265SDimitry Andric   PolicyScheme getPolicyScheme() const { return Scheme; }
getNF()43781ad6265SDimitry Andric   unsigned getNF() const { return NF; }
getIntrinsicTypes()43881ad6265SDimitry Andric   const std::vector<int64_t> &getIntrinsicTypes() const {
43981ad6265SDimitry Andric     return IntrinsicTypes;
44081ad6265SDimitry Andric   }
getPolicyAttrs()441bdd1243dSDimitry Andric   Policy getPolicyAttrs() const {
442bdd1243dSDimitry Andric     return PolicyAttrs;
443bdd1243dSDimitry Andric   }
getPolicyAttrsBits()444bdd1243dSDimitry Andric   unsigned getPolicyAttrsBits() const {
445bdd1243dSDimitry Andric     // CGBuiltin.cpp
446bdd1243dSDimitry Andric     // The 0th bit simulates the `vta` of RVV
447bdd1243dSDimitry Andric     // The 1st bit simulates the `vma` of RVV
448bdd1243dSDimitry Andric     // int PolicyAttrs = 0;
449bdd1243dSDimitry Andric 
450bdd1243dSDimitry Andric     if (PolicyAttrs.isTUMAPolicy())
451bdd1243dSDimitry Andric       return 2;
452bdd1243dSDimitry Andric     if (PolicyAttrs.isTAMAPolicy())
453bdd1243dSDimitry Andric       return 3;
454bdd1243dSDimitry Andric     if (PolicyAttrs.isTUMUPolicy())
455bdd1243dSDimitry Andric       return 0;
456bdd1243dSDimitry Andric     if (PolicyAttrs.isTAMUPolicy())
457bdd1243dSDimitry Andric       return 1;
458bdd1243dSDimitry Andric 
459bdd1243dSDimitry Andric     llvm_unreachable("unsupport policy");
460bdd1243dSDimitry Andric     return 0;
461bdd1243dSDimitry Andric   }
46281ad6265SDimitry Andric 
46381ad6265SDimitry Andric   // Return the type string for a BUILTIN() macro in Builtins.def.
46481ad6265SDimitry Andric   std::string getBuiltinTypeStr() const;
46581ad6265SDimitry Andric 
46681ad6265SDimitry Andric   static std::string
467bdd1243dSDimitry Andric   getSuffixStr(RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
46881ad6265SDimitry Andric                llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
469972a253aSDimitry Andric 
470972a253aSDimitry Andric   static llvm::SmallVector<PrototypeDescriptor>
471972a253aSDimitry Andric   computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
472972a253aSDimitry Andric                       bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
473bdd1243dSDimitry Andric                       unsigned NF, PolicyScheme DefaultScheme,
47406c3fb27SDimitry Andric                       Policy PolicyAttrs, bool IsTuple);
475bdd1243dSDimitry Andric 
4761ac55f4cSDimitry Andric   static llvm::SmallVector<Policy> getSupportedUnMaskedPolicies();
477bdd1243dSDimitry Andric   static llvm::SmallVector<Policy>
478bdd1243dSDimitry Andric       getSupportedMaskedPolicies(bool HasTailPolicy, bool HasMaskPolicy);
479bdd1243dSDimitry Andric 
480bdd1243dSDimitry Andric   static void updateNamesAndPolicy(bool IsMasked, bool HasPolicy,
481bdd1243dSDimitry Andric                                    std::string &Name, std::string &BuiltinName,
482bdd1243dSDimitry Andric                                    std::string &OverloadedName,
48306c3fb27SDimitry Andric                                    Policy &PolicyAttrs, bool HasFRMRoundModeOp);
48481ad6265SDimitry Andric };
48581ad6265SDimitry Andric 
486972a253aSDimitry Andric // RVVRequire should be sync'ed with target features, but only
487972a253aSDimitry Andric // required features used in riscv_vector.td.
488cb14a3feSDimitry Andric enum RVVRequire : uint32_t {
489972a253aSDimitry Andric   RVV_REQ_None = 0,
490972a253aSDimitry Andric   RVV_REQ_RV64 = 1 << 0,
491*7a6dacacSDimitry Andric   RVV_REQ_Zvfhmin = 1 << 1,
4925f757f3fSDimitry Andric   RVV_REQ_Xsfvcp = 1 << 2,
4935f757f3fSDimitry Andric   RVV_REQ_Xsfvfnrclipxfqf = 1 << 3,
4945f757f3fSDimitry Andric   RVV_REQ_Xsfvfwmaccqqq = 1 << 4,
4955f757f3fSDimitry Andric   RVV_REQ_Xsfvqmaccdod = 1 << 5,
4965f757f3fSDimitry Andric   RVV_REQ_Xsfvqmaccqoq = 1 << 6,
4975f757f3fSDimitry Andric   RVV_REQ_Zvbb = 1 << 7,
4985f757f3fSDimitry Andric   RVV_REQ_Zvbc = 1 << 8,
4995f757f3fSDimitry Andric   RVV_REQ_Zvkb = 1 << 9,
5005f757f3fSDimitry Andric   RVV_REQ_Zvkg = 1 << 10,
5015f757f3fSDimitry Andric   RVV_REQ_Zvkned = 1 << 11,
5025f757f3fSDimitry Andric   RVV_REQ_Zvknha = 1 << 12,
5035f757f3fSDimitry Andric   RVV_REQ_Zvknhb = 1 << 13,
5045f757f3fSDimitry Andric   RVV_REQ_Zvksed = 1 << 14,
5055f757f3fSDimitry Andric   RVV_REQ_Zvksh = 1 << 15,
506cb14a3feSDimitry Andric   RVV_REQ_Experimental = 1 << 16,
507972a253aSDimitry Andric 
508cb14a3feSDimitry Andric   LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_Experimental)
509972a253aSDimitry Andric };
510972a253aSDimitry Andric 
511972a253aSDimitry Andric // Raw RVV intrinsic info, used to expand later.
512972a253aSDimitry Andric // This struct is highly compact for minimized code size.
513972a253aSDimitry Andric struct RVVIntrinsicRecord {
514972a253aSDimitry Andric   // Intrinsic name, e.g. vadd_vv
515972a253aSDimitry Andric   const char *Name;
516972a253aSDimitry Andric 
517972a253aSDimitry Andric   // Overloaded intrinsic name, could be empty if it can be computed from Name.
518972a253aSDimitry Andric   // e.g. vadd
519972a253aSDimitry Andric   const char *OverloadedName;
520972a253aSDimitry Andric 
521972a253aSDimitry Andric   // Prototype for this intrinsic, index of RVVSignatureTable.
522972a253aSDimitry Andric   uint16_t PrototypeIndex;
523972a253aSDimitry Andric 
524972a253aSDimitry Andric   // Suffix of intrinsic name, index of RVVSignatureTable.
525972a253aSDimitry Andric   uint16_t SuffixIndex;
526972a253aSDimitry Andric 
527972a253aSDimitry Andric   // Suffix of overloaded intrinsic name, index of RVVSignatureTable.
528972a253aSDimitry Andric   uint16_t OverloadedSuffixIndex;
529972a253aSDimitry Andric 
530972a253aSDimitry Andric   // Length of the prototype.
531972a253aSDimitry Andric   uint8_t PrototypeLength;
532972a253aSDimitry Andric 
533972a253aSDimitry Andric   // Length of intrinsic name suffix.
534972a253aSDimitry Andric   uint8_t SuffixLength;
535972a253aSDimitry Andric 
536972a253aSDimitry Andric   // Length of overloaded intrinsic suffix.
537972a253aSDimitry Andric   uint8_t OverloadedSuffixSize;
538972a253aSDimitry Andric 
539972a253aSDimitry Andric   // Required target features for this intrinsic.
540cb14a3feSDimitry Andric   uint32_t RequiredExtensions;
541972a253aSDimitry Andric 
542972a253aSDimitry Andric   // Supported type, mask of BasicType.
543972a253aSDimitry Andric   uint8_t TypeRangeMask;
544972a253aSDimitry Andric 
545972a253aSDimitry Andric   // Supported LMUL.
546972a253aSDimitry Andric   uint8_t Log2LMULMask;
547972a253aSDimitry Andric 
548972a253aSDimitry Andric   // Number of fields, greater than 1 if it's segment load/store.
549972a253aSDimitry Andric   uint8_t NF;
550972a253aSDimitry Andric 
551972a253aSDimitry Andric   bool HasMasked : 1;
552972a253aSDimitry Andric   bool HasVL : 1;
553972a253aSDimitry Andric   bool HasMaskedOffOperand : 1;
554bdd1243dSDimitry Andric   bool HasTailPolicy : 1;
555bdd1243dSDimitry Andric   bool HasMaskPolicy : 1;
55606c3fb27SDimitry Andric   bool HasFRMRoundModeOp : 1;
55706c3fb27SDimitry Andric   bool IsTuple : 1;
558bdd1243dSDimitry Andric   uint8_t UnMaskedPolicyScheme : 2;
559bdd1243dSDimitry Andric   uint8_t MaskedPolicyScheme : 2;
560972a253aSDimitry Andric };
561972a253aSDimitry Andric 
562972a253aSDimitry Andric llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
563972a253aSDimitry Andric                               const RVVIntrinsicRecord &RVVInstrRecord);
564972a253aSDimitry Andric 
565972a253aSDimitry Andric LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
56681ad6265SDimitry Andric } // end namespace RISCV
56781ad6265SDimitry Andric 
56881ad6265SDimitry Andric } // end namespace clang
56981ad6265SDimitry Andric 
57081ad6265SDimitry Andric #endif // CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
571