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