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/Optional.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringRef.h" 17 #include <cstdint> 18 #include <string> 19 #include <vector> 20 21 namespace llvm { 22 class raw_ostream; 23 } // end namespace llvm 24 25 namespace clang { 26 namespace RISCV { 27 28 using VScaleVal = llvm::Optional<unsigned>; 29 30 // Modifier for vector type. 31 enum class VectorTypeModifier : uint8_t { 32 NoModifier, 33 Widening2XVector, 34 Widening4XVector, 35 Widening8XVector, 36 MaskVector, 37 Log2EEW3, 38 Log2EEW4, 39 Log2EEW5, 40 Log2EEW6, 41 FixedSEW8, 42 FixedSEW16, 43 FixedSEW32, 44 FixedSEW64, 45 LFixedLog2LMULN3, 46 LFixedLog2LMULN2, 47 LFixedLog2LMULN1, 48 LFixedLog2LMUL0, 49 LFixedLog2LMUL1, 50 LFixedLog2LMUL2, 51 LFixedLog2LMUL3, 52 SFixedLog2LMULN3, 53 SFixedLog2LMULN2, 54 SFixedLog2LMULN1, 55 SFixedLog2LMUL0, 56 SFixedLog2LMUL1, 57 SFixedLog2LMUL2, 58 SFixedLog2LMUL3, 59 }; 60 61 // Similar to basic type but used to describe what's kind of type related to 62 // basic vector type, used to compute type info of arguments. 63 enum class BaseTypeModifier : uint8_t { 64 Invalid, 65 Scalar, 66 Vector, 67 Void, 68 SizeT, 69 Ptrdiff, 70 UnsignedLong, 71 SignedLong, 72 }; 73 74 // Modifier for type, used for both scalar and vector types. 75 enum class TypeModifier : uint8_t { 76 NoModifier = 0, 77 Pointer = 1 << 0, 78 Const = 1 << 1, 79 Immediate = 1 << 2, 80 UnsignedInteger = 1 << 3, 81 SignedInteger = 1 << 4, 82 Float = 1 << 5, 83 // LMUL1 should be kind of VectorTypeModifier, but that might come with 84 // Widening2XVector for widening reduction. 85 // However that might require VectorTypeModifier become bitmask rather than 86 // simple enum, so we decide keek LMUL1 in TypeModifier for code size 87 // optimization of clang binary size. 88 LMUL1 = 1 << 6, 89 MaxOffset = 6, 90 LLVM_MARK_AS_BITMASK_ENUM(LMUL1), 91 }; 92 93 // PrototypeDescriptor is used to compute type info of arguments or return 94 // value. 95 struct PrototypeDescriptor { 96 constexpr PrototypeDescriptor() = default; 97 constexpr PrototypeDescriptor( 98 BaseTypeModifier PT, 99 VectorTypeModifier VTM = VectorTypeModifier::NoModifier, 100 TypeModifier TM = TypeModifier::NoModifier) 101 : PT(static_cast<uint8_t>(PT)), VTM(static_cast<uint8_t>(VTM)), 102 TM(static_cast<uint8_t>(TM)) {} 103 constexpr PrototypeDescriptor(uint8_t PT, uint8_t VTM, uint8_t TM) 104 : PT(PT), VTM(VTM), TM(TM) {} 105 106 uint8_t PT = static_cast<uint8_t>(BaseTypeModifier::Invalid); 107 uint8_t VTM = static_cast<uint8_t>(VectorTypeModifier::NoModifier); 108 uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier); 109 110 bool operator!=(const PrototypeDescriptor &PD) const { 111 return !(*this == PD); 112 } 113 bool operator==(const PrototypeDescriptor &PD) const { 114 return PD.PT == PT && PD.VTM == VTM && PD.TM == TM; 115 } 116 bool operator<(const PrototypeDescriptor &PD) const { 117 return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM); 118 } 119 static const PrototypeDescriptor Mask; 120 static const PrototypeDescriptor Vector; 121 static const PrototypeDescriptor VL; 122 static llvm::Optional<PrototypeDescriptor> 123 parsePrototypeDescriptor(llvm::StringRef PrototypeStr); 124 }; 125 126 llvm::SmallVector<PrototypeDescriptor> 127 parsePrototypes(llvm::StringRef Prototypes); 128 129 // Basic type of vector type. 130 enum class BasicType : uint8_t { 131 Unknown = 0, 132 Int8 = 1 << 0, 133 Int16 = 1 << 1, 134 Int32 = 1 << 2, 135 Int64 = 1 << 3, 136 Float16 = 1 << 4, 137 Float32 = 1 << 5, 138 Float64 = 1 << 6, 139 MaxOffset = 6, 140 LLVM_MARK_AS_BITMASK_ENUM(Float64), 141 }; 142 143 // Type of vector type. 144 enum ScalarTypeKind : uint8_t { 145 Void, 146 Size_t, 147 Ptrdiff_t, 148 UnsignedLong, 149 SignedLong, 150 Boolean, 151 SignedInteger, 152 UnsignedInteger, 153 Float, 154 Invalid, 155 }; 156 157 // Exponential LMUL 158 struct LMULType { 159 int Log2LMUL; 160 LMULType(int Log2LMUL); 161 // Return the C/C++ string representation of LMUL 162 std::string str() const; 163 llvm::Optional<unsigned> getScale(unsigned ElementBitwidth) const; 164 void MulLog2LMUL(int Log2LMUL); 165 }; 166 167 class RVVType; 168 using RVVTypePtr = RVVType *; 169 using RVVTypes = std::vector<RVVTypePtr>; 170 171 // This class is compact representation of a valid and invalid RVVType. 172 class RVVType { 173 BasicType BT; 174 ScalarTypeKind ScalarType = Invalid; 175 LMULType LMUL; 176 bool IsPointer = false; 177 // IsConstant indices are "int", but have the constant expression. 178 bool IsImmediate = false; 179 // Const qualifier for pointer to const object or object of const type. 180 bool IsConstant = false; 181 unsigned ElementBitwidth = 0; 182 VScaleVal Scale = 0; 183 bool Valid; 184 185 std::string BuiltinStr; 186 std::string ClangBuiltinStr; 187 std::string Str; 188 std::string ShortStr; 189 190 enum class FixedLMULType { LargerThan, SmallerThan }; 191 192 public: 193 RVVType() : BT(BasicType::Unknown), LMUL(0), Valid(false) {} 194 RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile); 195 196 // Return the string representation of a type, which is an encoded string for 197 // passing to the BUILTIN() macro in Builtins.def. 198 const std::string &getBuiltinStr() const { return BuiltinStr; } 199 200 // Return the clang builtin type for RVV vector type which are used in the 201 // riscv_vector.h header file. 202 const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; } 203 204 // Return the C/C++ string representation of a type for use in the 205 // riscv_vector.h header file. 206 const std::string &getTypeStr() const { return Str; } 207 208 // Return the short name of a type for C/C++ name suffix. 209 const std::string &getShortStr() { 210 // Not all types are used in short name, so compute the short name by 211 // demanded. 212 if (ShortStr.empty()) 213 initShortStr(); 214 return ShortStr; 215 } 216 217 bool isValid() const { return Valid; } 218 bool isScalar() const { return Scale && Scale.value() == 0; } 219 bool isVector() const { return Scale && Scale.value() != 0; } 220 bool isVector(unsigned Width) const { 221 return isVector() && ElementBitwidth == Width; 222 } 223 bool isFloat() const { return ScalarType == ScalarTypeKind::Float; } 224 bool isSignedInteger() const { 225 return ScalarType == ScalarTypeKind::SignedInteger; 226 } 227 bool isFloatVector(unsigned Width) const { 228 return isVector() && isFloat() && ElementBitwidth == Width; 229 } 230 bool isFloat(unsigned Width) const { 231 return isFloat() && ElementBitwidth == Width; 232 } 233 bool isConstant() const { return IsConstant; } 234 bool isPointer() const { return IsPointer; } 235 unsigned getElementBitwidth() const { return ElementBitwidth; } 236 237 ScalarTypeKind getScalarType() const { return ScalarType; } 238 VScaleVal getScale() const { return Scale; } 239 240 private: 241 // Verify RVV vector type and set Valid. 242 bool verifyType() const; 243 244 // Creates a type based on basic types of TypeRange 245 void applyBasicType(); 246 247 // Applies a prototype modifier to the current type. The result maybe an 248 // invalid type. 249 void applyModifier(const PrototypeDescriptor &prototype); 250 251 void applyLog2EEW(unsigned Log2EEW); 252 void applyFixedSEW(unsigned NewSEW); 253 void applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type); 254 255 // Compute and record a string for legal type. 256 void initBuiltinStr(); 257 // Compute and record a builtin RVV vector type string. 258 void initClangBuiltinStr(); 259 // Compute and record a type string for used in the header. 260 void initTypeStr(); 261 // Compute and record a short name of a type for C/C++ name suffix. 262 void initShortStr(); 263 264 public: 265 /// Compute output and input types by applying different config (basic type 266 /// and LMUL with type transformers). It also record result of type in legal 267 /// or illegal set to avoid compute the same config again. The result maybe 268 /// have illegal RVVType. 269 static llvm::Optional<RVVTypes> 270 computeTypes(BasicType BT, int Log2LMUL, unsigned NF, 271 llvm::ArrayRef<PrototypeDescriptor> Prototype); 272 static llvm::Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, 273 PrototypeDescriptor Proto); 274 }; 275 276 enum PolicyScheme : uint8_t { 277 SchemeNone, 278 HasPassthruOperand, 279 HasPolicyOperand, 280 }; 281 282 // TODO refactor RVVIntrinsic class design after support all intrinsic 283 // combination. This represents an instantiation of an intrinsic with a 284 // particular type and prototype 285 class RVVIntrinsic { 286 287 private: 288 std::string BuiltinName; // Builtin name 289 std::string Name; // C intrinsic name. 290 std::string OverloadedName; 291 std::string IRName; 292 bool IsMasked; 293 bool HasVL; 294 PolicyScheme Scheme; 295 bool HasUnMaskedOverloaded; 296 bool HasBuiltinAlias; 297 std::string ManualCodegen; 298 RVVTypePtr OutputType; // Builtin output type 299 RVVTypes InputTypes; // Builtin input types 300 // The types we use to obtain the specific LLVM intrinsic. They are index of 301 // InputTypes. -1 means the return type. 302 std::vector<int64_t> IntrinsicTypes; 303 unsigned NF = 1; 304 305 public: 306 RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix, 307 llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix, 308 llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand, 309 bool HasVL, PolicyScheme Scheme, bool HasUnMaskedOverloaded, 310 bool HasBuiltinAlias, llvm::StringRef ManualCodegen, 311 const RVVTypes &Types, 312 const std::vector<int64_t> &IntrinsicTypes, 313 const std::vector<llvm::StringRef> &RequiredFeatures, 314 unsigned NF); 315 ~RVVIntrinsic() = default; 316 317 RVVTypePtr getOutputType() const { return OutputType; } 318 const RVVTypes &getInputTypes() const { return InputTypes; } 319 llvm::StringRef getBuiltinName() const { return BuiltinName; } 320 llvm::StringRef getName() const { return Name; } 321 llvm::StringRef getOverloadedName() const { return OverloadedName; } 322 bool hasVL() const { return HasVL; } 323 bool hasPolicy() const { return Scheme != SchemeNone; } 324 bool hasPassthruOperand() const { return Scheme == HasPassthruOperand; } 325 bool hasPolicyOperand() const { return Scheme == HasPolicyOperand; } 326 bool hasUnMaskedOverloaded() const { return HasUnMaskedOverloaded; } 327 bool hasBuiltinAlias() const { return HasBuiltinAlias; } 328 bool hasManualCodegen() const { return !ManualCodegen.empty(); } 329 bool isMasked() const { return IsMasked; } 330 llvm::StringRef getIRName() const { return IRName; } 331 llvm::StringRef getManualCodegen() const { return ManualCodegen; } 332 PolicyScheme getPolicyScheme() const { return Scheme; } 333 unsigned getNF() const { return NF; } 334 const std::vector<int64_t> &getIntrinsicTypes() const { 335 return IntrinsicTypes; 336 } 337 338 // Return the type string for a BUILTIN() macro in Builtins.def. 339 std::string getBuiltinTypeStr() const; 340 341 static std::string 342 getSuffixStr(BasicType Type, int Log2LMUL, 343 llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors); 344 345 static llvm::SmallVector<PrototypeDescriptor> 346 computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype, 347 bool IsMasked, bool HasMaskedOffOperand, bool HasVL, 348 unsigned NF); 349 }; 350 351 // RVVRequire should be sync'ed with target features, but only 352 // required features used in riscv_vector.td. 353 enum RVVRequire : uint8_t { 354 RVV_REQ_None = 0, 355 RVV_REQ_RV64 = 1 << 0, 356 RVV_REQ_FullMultiply = 1 << 1, 357 358 LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_FullMultiply) 359 }; 360 361 // Raw RVV intrinsic info, used to expand later. 362 // This struct is highly compact for minimized code size. 363 struct RVVIntrinsicRecord { 364 // Intrinsic name, e.g. vadd_vv 365 const char *Name; 366 367 // Overloaded intrinsic name, could be empty if it can be computed from Name. 368 // e.g. vadd 369 const char *OverloadedName; 370 371 // Prototype for this intrinsic, index of RVVSignatureTable. 372 uint16_t PrototypeIndex; 373 374 // Suffix of intrinsic name, index of RVVSignatureTable. 375 uint16_t SuffixIndex; 376 377 // Suffix of overloaded intrinsic name, index of RVVSignatureTable. 378 uint16_t OverloadedSuffixIndex; 379 380 // Length of the prototype. 381 uint8_t PrototypeLength; 382 383 // Length of intrinsic name suffix. 384 uint8_t SuffixLength; 385 386 // Length of overloaded intrinsic suffix. 387 uint8_t OverloadedSuffixSize; 388 389 // Required target features for this intrinsic. 390 uint8_t RequiredExtensions; 391 392 // Supported type, mask of BasicType. 393 uint8_t TypeRangeMask; 394 395 // Supported LMUL. 396 uint8_t Log2LMULMask; 397 398 // Number of fields, greater than 1 if it's segment load/store. 399 uint8_t NF; 400 401 bool HasMasked : 1; 402 bool HasVL : 1; 403 bool HasMaskedOffOperand : 1; 404 }; 405 406 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 407 const RVVIntrinsicRecord &RVVInstrRecord); 408 409 LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); 410 } // end namespace RISCV 411 412 } // end namespace clang 413 414 #endif // CLANG_SUPPORT_RISCVVINTRINSICUTILS_H 415