1 //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===// 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 // This tablegen backend is responsible for emitting riscv_vector.h which 10 // includes a declaration and definition of each intrinsic functions specified 11 // in https://github.com/riscv/rvv-intrinsic-doc. 12 // 13 // See also the documentation in include/clang/Basic/riscv_vector.td. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "llvm/ADT/ArrayRef.h" 18 #include "llvm/ADT/SmallSet.h" 19 #include "llvm/ADT/StringExtras.h" 20 #include "llvm/ADT/StringMap.h" 21 #include "llvm/ADT/StringSet.h" 22 #include "llvm/ADT/Twine.h" 23 #include "llvm/TableGen/Error.h" 24 #include "llvm/TableGen/Record.h" 25 #include <numeric> 26 27 using namespace llvm; 28 using BasicType = char; 29 using VScaleVal = Optional<unsigned>; 30 31 namespace { 32 33 // Exponential LMUL 34 struct LMULType { 35 int Log2LMUL; 36 LMULType(int Log2LMUL); 37 // Return the C/C++ string representation of LMUL 38 std::string str() const; 39 Optional<unsigned> getScale(unsigned ElementBitwidth) const; 40 void MulLog2LMUL(int Log2LMUL); 41 LMULType &operator*=(uint32_t RHS); 42 }; 43 44 // This class is compact representation of a valid and invalid RVVType. 45 class RVVType { 46 enum ScalarTypeKind : uint32_t { 47 Void, 48 Size_t, 49 Ptrdiff_t, 50 UnsignedLong, 51 SignedLong, 52 Boolean, 53 SignedInteger, 54 UnsignedInteger, 55 Float, 56 Invalid, 57 }; 58 BasicType BT; 59 ScalarTypeKind ScalarType = Invalid; 60 LMULType LMUL; 61 bool IsPointer = false; 62 // IsConstant indices are "int", but have the constant expression. 63 bool IsImmediate = false; 64 // Const qualifier for pointer to const object or object of const type. 65 bool IsConstant = false; 66 unsigned ElementBitwidth = 0; 67 VScaleVal Scale = 0; 68 bool Valid; 69 70 std::string BuiltinStr; 71 std::string ClangBuiltinStr; 72 std::string Str; 73 std::string ShortStr; 74 75 public: 76 RVVType() : RVVType(BasicType(), 0, StringRef()) {} 77 RVVType(BasicType BT, int Log2LMUL, StringRef prototype); 78 79 // Return the string representation of a type, which is an encoded string for 80 // passing to the BUILTIN() macro in Builtins.def. 81 const std::string &getBuiltinStr() const { return BuiltinStr; } 82 83 // Return the clang builtin type for RVV vector type which are used in the 84 // riscv_vector.h header file. 85 const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; } 86 87 // Return the C/C++ string representation of a type for use in the 88 // riscv_vector.h header file. 89 const std::string &getTypeStr() const { return Str; } 90 91 // Return the short name of a type for C/C++ name suffix. 92 const std::string &getShortStr() { 93 // Not all types are used in short name, so compute the short name by 94 // demanded. 95 if (ShortStr.empty()) 96 initShortStr(); 97 return ShortStr; 98 } 99 100 bool isValid() const { return Valid; } 101 bool isScalar() const { return Scale.hasValue() && Scale.getValue() == 0; } 102 bool isVector() const { return Scale.hasValue() && Scale.getValue() != 0; } 103 bool isVector(unsigned Width) const { 104 return isVector() && ElementBitwidth == Width; 105 } 106 bool isFloat() const { return ScalarType == ScalarTypeKind::Float; } 107 bool isSignedInteger() const { 108 return ScalarType == ScalarTypeKind::SignedInteger; 109 } 110 bool isFloatVector(unsigned Width) const { 111 return isVector() && isFloat() && ElementBitwidth == Width; 112 } 113 bool isFloat(unsigned Width) const { 114 return isFloat() && ElementBitwidth == Width; 115 } 116 117 private: 118 // Verify RVV vector type and set Valid. 119 bool verifyType() const; 120 121 // Creates a type based on basic types of TypeRange 122 void applyBasicType(); 123 124 // Applies a prototype modifier to the current type. The result maybe an 125 // invalid type. 126 void applyModifier(StringRef prototype); 127 128 // Compute and record a string for legal type. 129 void initBuiltinStr(); 130 // Compute and record a builtin RVV vector type string. 131 void initClangBuiltinStr(); 132 // Compute and record a type string for used in the header. 133 void initTypeStr(); 134 // Compute and record a short name of a type for C/C++ name suffix. 135 void initShortStr(); 136 }; 137 138 using RVVTypePtr = RVVType *; 139 using RVVTypes = std::vector<RVVTypePtr>; 140 using RISCVPredefinedMacroT = uint8_t; 141 142 enum RISCVPredefinedMacro : RISCVPredefinedMacroT { 143 Basic = 0, 144 V = 1 << 1, 145 Zfh = 1 << 2, 146 RV64 = 1 << 3, 147 VectorMaxELen64 = 1 << 4, 148 VectorMaxELenFp32 = 1 << 5, 149 VectorMaxELenFp64 = 1 << 6, 150 }; 151 152 // TODO refactor RVVIntrinsic class design after support all intrinsic 153 // combination. This represents an instantiation of an intrinsic with a 154 // particular type and prototype 155 class RVVIntrinsic { 156 157 private: 158 std::string BuiltinName; // Builtin name 159 std::string Name; // C intrinsic name. 160 std::string MangledName; 161 std::string IRName; 162 bool IsMask; 163 bool HasVL; 164 bool HasPolicy; 165 bool HasNoMaskedOverloaded; 166 bool HasAutoDef; // There is automiatic definition in header 167 std::string ManualCodegen; 168 RVVTypePtr OutputType; // Builtin output type 169 RVVTypes InputTypes; // Builtin input types 170 // The types we use to obtain the specific LLVM intrinsic. They are index of 171 // InputTypes. -1 means the return type. 172 std::vector<int64_t> IntrinsicTypes; 173 RISCVPredefinedMacroT RISCVPredefinedMacros = 0; 174 unsigned NF = 1; 175 176 public: 177 RVVIntrinsic(StringRef Name, StringRef Suffix, StringRef MangledName, 178 StringRef MangledSuffix, StringRef IRName, bool IsMask, 179 bool HasMaskedOffOperand, bool HasVL, bool HasPolicy, 180 bool HasNoMaskedOverloaded, bool HasAutoDef, 181 StringRef ManualCodegen, const RVVTypes &Types, 182 const std::vector<int64_t> &IntrinsicTypes, 183 const std::vector<StringRef> &RequiredFeatures, unsigned NF); 184 ~RVVIntrinsic() = default; 185 186 StringRef getBuiltinName() const { return BuiltinName; } 187 StringRef getName() const { return Name; } 188 StringRef getMangledName() const { return MangledName; } 189 bool hasVL() const { return HasVL; } 190 bool hasPolicy() const { return HasPolicy; } 191 bool hasNoMaskedOverloaded() const { return HasNoMaskedOverloaded; } 192 bool hasManualCodegen() const { return !ManualCodegen.empty(); } 193 bool hasAutoDef() const { return HasAutoDef; } 194 bool isMask() const { return IsMask; } 195 StringRef getIRName() const { return IRName; } 196 StringRef getManualCodegen() const { return ManualCodegen; } 197 RISCVPredefinedMacroT getRISCVPredefinedMacros() const { 198 return RISCVPredefinedMacros; 199 } 200 unsigned getNF() const { return NF; } 201 const std::vector<int64_t> &getIntrinsicTypes() const { 202 return IntrinsicTypes; 203 } 204 205 // Return the type string for a BUILTIN() macro in Builtins.def. 206 std::string getBuiltinTypeStr() const; 207 208 // Emit the code block for switch body in EmitRISCVBuiltinExpr, it should 209 // init the RVVIntrinsic ID and IntrinsicTypes. 210 void emitCodeGenSwitchBody(raw_ostream &o) const; 211 212 // Emit the macros for mapping C/C++ intrinsic function to builtin functions. 213 void emitIntrinsicFuncDef(raw_ostream &o) const; 214 215 // Emit the mangled function definition. 216 void emitMangledFuncDef(raw_ostream &o) const; 217 }; 218 219 class RVVEmitter { 220 private: 221 RecordKeeper &Records; 222 std::string HeaderCode; 223 // Concat BasicType, LMUL and Proto as key 224 StringMap<RVVType> LegalTypes; 225 StringSet<> IllegalTypes; 226 227 public: 228 RVVEmitter(RecordKeeper &R) : Records(R) {} 229 230 /// Emit riscv_vector.h 231 void createHeader(raw_ostream &o); 232 233 /// Emit all the __builtin prototypes and code needed by Sema. 234 void createBuiltins(raw_ostream &o); 235 236 /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 237 void createCodeGen(raw_ostream &o); 238 239 std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes); 240 241 private: 242 /// Create all intrinsics and add them to \p Out 243 void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out); 244 /// Create Headers and add them to \p Out 245 void createRVVHeaders(raw_ostream &OS); 246 /// Compute output and input types by applying different config (basic type 247 /// and LMUL with type transformers). It also record result of type in legal 248 /// or illegal set to avoid compute the same config again. The result maybe 249 /// have illegal RVVType. 250 Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL, unsigned NF, 251 ArrayRef<std::string> PrototypeSeq); 252 Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto); 253 254 /// Emit Acrh predecessor definitions and body, assume the element of Defs are 255 /// sorted by extension. 256 void emitArchMacroAndBody( 257 std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o, 258 std::function<void(raw_ostream &, const RVVIntrinsic &)>); 259 260 // Emit the architecture preprocessor definitions. Return true when emits 261 // non-empty string. 262 bool emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, 263 raw_ostream &o); 264 // Slice Prototypes string into sub prototype string and process each sub 265 // prototype string individually in the Handler. 266 void parsePrototypes(StringRef Prototypes, 267 std::function<void(StringRef)> Handler); 268 }; 269 270 } // namespace 271 272 //===----------------------------------------------------------------------===// 273 // Type implementation 274 //===----------------------------------------------------------------------===// 275 276 LMULType::LMULType(int NewLog2LMUL) { 277 // Check Log2LMUL is -3, -2, -1, 0, 1, 2, 3 278 assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!"); 279 Log2LMUL = NewLog2LMUL; 280 } 281 282 std::string LMULType::str() const { 283 if (Log2LMUL < 0) 284 return "mf" + utostr(1ULL << (-Log2LMUL)); 285 return "m" + utostr(1ULL << Log2LMUL); 286 } 287 288 VScaleVal LMULType::getScale(unsigned ElementBitwidth) const { 289 int Log2ScaleResult = 0; 290 switch (ElementBitwidth) { 291 default: 292 break; 293 case 8: 294 Log2ScaleResult = Log2LMUL + 3; 295 break; 296 case 16: 297 Log2ScaleResult = Log2LMUL + 2; 298 break; 299 case 32: 300 Log2ScaleResult = Log2LMUL + 1; 301 break; 302 case 64: 303 Log2ScaleResult = Log2LMUL; 304 break; 305 } 306 // Illegal vscale result would be less than 1 307 if (Log2ScaleResult < 0) 308 return None; 309 return 1 << Log2ScaleResult; 310 } 311 312 void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; } 313 314 LMULType &LMULType::operator*=(uint32_t RHS) { 315 assert(isPowerOf2_32(RHS)); 316 this->Log2LMUL = this->Log2LMUL + Log2_32(RHS); 317 return *this; 318 } 319 320 RVVType::RVVType(BasicType BT, int Log2LMUL, StringRef prototype) 321 : BT(BT), LMUL(LMULType(Log2LMUL)) { 322 applyBasicType(); 323 applyModifier(prototype); 324 Valid = verifyType(); 325 if (Valid) { 326 initBuiltinStr(); 327 initTypeStr(); 328 if (isVector()) { 329 initClangBuiltinStr(); 330 } 331 } 332 } 333 334 // clang-format off 335 // boolean type are encoded the ratio of n (SEW/LMUL) 336 // SEW/LMUL | 1 | 2 | 4 | 8 | 16 | 32 | 64 337 // c type | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t | vbool2_t | vbool1_t 338 // IR type | nxv1i1 | nxv2i1 | nxv4i1 | nxv8i1 | nxv16i1 | nxv32i1 | nxv64i1 339 340 // type\lmul | 1/8 | 1/4 | 1/2 | 1 | 2 | 4 | 8 341 // -------- |------ | -------- | ------- | ------- | -------- | -------- | -------- 342 // i64 | N/A | N/A | N/A | nxv1i64 | nxv2i64 | nxv4i64 | nxv8i64 343 // i32 | N/A | N/A | nxv1i32 | nxv2i32 | nxv4i32 | nxv8i32 | nxv16i32 344 // i16 | N/A | nxv1i16 | nxv2i16 | nxv4i16 | nxv8i16 | nxv16i16 | nxv32i16 345 // i8 | nxv1i8 | nxv2i8 | nxv4i8 | nxv8i8 | nxv16i8 | nxv32i8 | nxv64i8 346 // double | N/A | N/A | N/A | nxv1f64 | nxv2f64 | nxv4f64 | nxv8f64 347 // float | N/A | N/A | nxv1f32 | nxv2f32 | nxv4f32 | nxv8f32 | nxv16f32 348 // half | N/A | nxv1f16 | nxv2f16 | nxv4f16 | nxv8f16 | nxv16f16 | nxv32f16 349 // clang-format on 350 351 bool RVVType::verifyType() const { 352 if (ScalarType == Invalid) 353 return false; 354 if (isScalar()) 355 return true; 356 if (!Scale.hasValue()) 357 return false; 358 if (isFloat() && ElementBitwidth == 8) 359 return false; 360 unsigned V = Scale.getValue(); 361 switch (ElementBitwidth) { 362 case 1: 363 case 8: 364 // Check Scale is 1,2,4,8,16,32,64 365 return (V <= 64 && isPowerOf2_32(V)); 366 case 16: 367 // Check Scale is 1,2,4,8,16,32 368 return (V <= 32 && isPowerOf2_32(V)); 369 case 32: 370 // Check Scale is 1,2,4,8,16 371 return (V <= 16 && isPowerOf2_32(V)); 372 case 64: 373 // Check Scale is 1,2,4,8 374 return (V <= 8 && isPowerOf2_32(V)); 375 } 376 return false; 377 } 378 379 void RVVType::initBuiltinStr() { 380 assert(isValid() && "RVVType is invalid"); 381 switch (ScalarType) { 382 case ScalarTypeKind::Void: 383 BuiltinStr = "v"; 384 return; 385 case ScalarTypeKind::Size_t: 386 BuiltinStr = "z"; 387 if (IsImmediate) 388 BuiltinStr = "I" + BuiltinStr; 389 if (IsPointer) 390 BuiltinStr += "*"; 391 return; 392 case ScalarTypeKind::Ptrdiff_t: 393 BuiltinStr = "Y"; 394 return; 395 case ScalarTypeKind::UnsignedLong: 396 BuiltinStr = "ULi"; 397 return; 398 case ScalarTypeKind::SignedLong: 399 BuiltinStr = "Li"; 400 return; 401 case ScalarTypeKind::Boolean: 402 assert(ElementBitwidth == 1); 403 BuiltinStr += "b"; 404 break; 405 case ScalarTypeKind::SignedInteger: 406 case ScalarTypeKind::UnsignedInteger: 407 switch (ElementBitwidth) { 408 case 8: 409 BuiltinStr += "c"; 410 break; 411 case 16: 412 BuiltinStr += "s"; 413 break; 414 case 32: 415 BuiltinStr += "i"; 416 break; 417 case 64: 418 BuiltinStr += "Wi"; 419 break; 420 default: 421 llvm_unreachable("Unhandled ElementBitwidth!"); 422 } 423 if (isSignedInteger()) 424 BuiltinStr = "S" + BuiltinStr; 425 else 426 BuiltinStr = "U" + BuiltinStr; 427 break; 428 case ScalarTypeKind::Float: 429 switch (ElementBitwidth) { 430 case 16: 431 BuiltinStr += "x"; 432 break; 433 case 32: 434 BuiltinStr += "f"; 435 break; 436 case 64: 437 BuiltinStr += "d"; 438 break; 439 default: 440 llvm_unreachable("Unhandled ElementBitwidth!"); 441 } 442 break; 443 default: 444 llvm_unreachable("ScalarType is invalid!"); 445 } 446 if (IsImmediate) 447 BuiltinStr = "I" + BuiltinStr; 448 if (isScalar()) { 449 if (IsConstant) 450 BuiltinStr += "C"; 451 if (IsPointer) 452 BuiltinStr += "*"; 453 return; 454 } 455 BuiltinStr = "q" + utostr(Scale.getValue()) + BuiltinStr; 456 // Pointer to vector types. Defined for segment load intrinsics. 457 // segment load intrinsics have pointer type arguments to store the loaded 458 // vector values. 459 if (IsPointer) 460 BuiltinStr += "*"; 461 } 462 463 void RVVType::initClangBuiltinStr() { 464 assert(isValid() && "RVVType is invalid"); 465 assert(isVector() && "Handle Vector type only"); 466 467 ClangBuiltinStr = "__rvv_"; 468 switch (ScalarType) { 469 case ScalarTypeKind::Boolean: 470 ClangBuiltinStr += "bool" + utostr(64 / Scale.getValue()) + "_t"; 471 return; 472 case ScalarTypeKind::Float: 473 ClangBuiltinStr += "float"; 474 break; 475 case ScalarTypeKind::SignedInteger: 476 ClangBuiltinStr += "int"; 477 break; 478 case ScalarTypeKind::UnsignedInteger: 479 ClangBuiltinStr += "uint"; 480 break; 481 default: 482 llvm_unreachable("ScalarTypeKind is invalid"); 483 } 484 ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() + "_t"; 485 } 486 487 void RVVType::initTypeStr() { 488 assert(isValid() && "RVVType is invalid"); 489 490 if (IsConstant) 491 Str += "const "; 492 493 auto getTypeString = [&](StringRef TypeStr) { 494 if (isScalar()) 495 return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str(); 496 return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() + "_t") 497 .str(); 498 }; 499 500 switch (ScalarType) { 501 case ScalarTypeKind::Void: 502 Str = "void"; 503 return; 504 case ScalarTypeKind::Size_t: 505 Str = "size_t"; 506 if (IsPointer) 507 Str += " *"; 508 return; 509 case ScalarTypeKind::Ptrdiff_t: 510 Str = "ptrdiff_t"; 511 return; 512 case ScalarTypeKind::UnsignedLong: 513 Str = "unsigned long"; 514 return; 515 case ScalarTypeKind::SignedLong: 516 Str = "long"; 517 return; 518 case ScalarTypeKind::Boolean: 519 if (isScalar()) 520 Str += "bool"; 521 else 522 // Vector bool is special case, the formulate is 523 // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1 524 Str += "vbool" + utostr(64 / Scale.getValue()) + "_t"; 525 break; 526 case ScalarTypeKind::Float: 527 if (isScalar()) { 528 if (ElementBitwidth == 64) 529 Str += "double"; 530 else if (ElementBitwidth == 32) 531 Str += "float"; 532 else if (ElementBitwidth == 16) 533 Str += "_Float16"; 534 else 535 llvm_unreachable("Unhandled floating type."); 536 } else 537 Str += getTypeString("float"); 538 break; 539 case ScalarTypeKind::SignedInteger: 540 Str += getTypeString("int"); 541 break; 542 case ScalarTypeKind::UnsignedInteger: 543 Str += getTypeString("uint"); 544 break; 545 default: 546 llvm_unreachable("ScalarType is invalid!"); 547 } 548 if (IsPointer) 549 Str += " *"; 550 } 551 552 void RVVType::initShortStr() { 553 switch (ScalarType) { 554 case ScalarTypeKind::Boolean: 555 assert(isVector()); 556 ShortStr = "b" + utostr(64 / Scale.getValue()); 557 return; 558 case ScalarTypeKind::Float: 559 ShortStr = "f" + utostr(ElementBitwidth); 560 break; 561 case ScalarTypeKind::SignedInteger: 562 ShortStr = "i" + utostr(ElementBitwidth); 563 break; 564 case ScalarTypeKind::UnsignedInteger: 565 ShortStr = "u" + utostr(ElementBitwidth); 566 break; 567 default: 568 PrintFatalError("Unhandled case!"); 569 } 570 if (isVector()) 571 ShortStr += LMUL.str(); 572 } 573 574 void RVVType::applyBasicType() { 575 switch (BT) { 576 case 'c': 577 ElementBitwidth = 8; 578 ScalarType = ScalarTypeKind::SignedInteger; 579 break; 580 case 's': 581 ElementBitwidth = 16; 582 ScalarType = ScalarTypeKind::SignedInteger; 583 break; 584 case 'i': 585 ElementBitwidth = 32; 586 ScalarType = ScalarTypeKind::SignedInteger; 587 break; 588 case 'l': 589 ElementBitwidth = 64; 590 ScalarType = ScalarTypeKind::SignedInteger; 591 break; 592 case 'x': 593 ElementBitwidth = 16; 594 ScalarType = ScalarTypeKind::Float; 595 break; 596 case 'f': 597 ElementBitwidth = 32; 598 ScalarType = ScalarTypeKind::Float; 599 break; 600 case 'd': 601 ElementBitwidth = 64; 602 ScalarType = ScalarTypeKind::Float; 603 break; 604 default: 605 PrintFatalError("Unhandled type code!"); 606 } 607 assert(ElementBitwidth != 0 && "Bad element bitwidth!"); 608 } 609 610 void RVVType::applyModifier(StringRef Transformer) { 611 if (Transformer.empty()) 612 return; 613 // Handle primitive type transformer 614 auto PType = Transformer.back(); 615 switch (PType) { 616 case 'e': 617 Scale = 0; 618 break; 619 case 'v': 620 Scale = LMUL.getScale(ElementBitwidth); 621 break; 622 case 'w': 623 ElementBitwidth *= 2; 624 LMUL *= 2; 625 Scale = LMUL.getScale(ElementBitwidth); 626 break; 627 case 'q': 628 ElementBitwidth *= 4; 629 LMUL *= 4; 630 Scale = LMUL.getScale(ElementBitwidth); 631 break; 632 case 'o': 633 ElementBitwidth *= 8; 634 LMUL *= 8; 635 Scale = LMUL.getScale(ElementBitwidth); 636 break; 637 case 'm': 638 ScalarType = ScalarTypeKind::Boolean; 639 Scale = LMUL.getScale(ElementBitwidth); 640 ElementBitwidth = 1; 641 break; 642 case '0': 643 ScalarType = ScalarTypeKind::Void; 644 break; 645 case 'z': 646 ScalarType = ScalarTypeKind::Size_t; 647 break; 648 case 't': 649 ScalarType = ScalarTypeKind::Ptrdiff_t; 650 break; 651 case 'u': 652 ScalarType = ScalarTypeKind::UnsignedLong; 653 break; 654 case 'l': 655 ScalarType = ScalarTypeKind::SignedLong; 656 break; 657 default: 658 PrintFatalError("Illegal primitive type transformers!"); 659 } 660 Transformer = Transformer.drop_back(); 661 662 // Extract and compute complex type transformer. It can only appear one time. 663 if (Transformer.startswith("(")) { 664 size_t Idx = Transformer.find(')'); 665 assert(Idx != StringRef::npos); 666 StringRef ComplexType = Transformer.slice(1, Idx); 667 Transformer = Transformer.drop_front(Idx + 1); 668 assert(!Transformer.contains('(') && 669 "Only allow one complex type transformer"); 670 671 auto UpdateAndCheckComplexProto = [&]() { 672 Scale = LMUL.getScale(ElementBitwidth); 673 const StringRef VectorPrototypes("vwqom"); 674 if (!VectorPrototypes.contains(PType)) 675 PrintFatalError("Complex type transformer only supports vector type!"); 676 if (Transformer.find_first_of("PCKWS") != StringRef::npos) 677 PrintFatalError( 678 "Illegal type transformer for Complex type transformer"); 679 }; 680 auto ComputeFixedLog2LMUL = 681 [&](StringRef Value, 682 std::function<bool(const int32_t &, const int32_t &)> Compare) { 683 int32_t Log2LMUL; 684 Value.getAsInteger(10, Log2LMUL); 685 if (!Compare(Log2LMUL, LMUL.Log2LMUL)) { 686 ScalarType = Invalid; 687 return false; 688 } 689 // Update new LMUL 690 LMUL = LMULType(Log2LMUL); 691 UpdateAndCheckComplexProto(); 692 return true; 693 }; 694 auto ComplexTT = ComplexType.split(":"); 695 if (ComplexTT.first == "Log2EEW") { 696 uint32_t Log2EEW; 697 ComplexTT.second.getAsInteger(10, Log2EEW); 698 // update new elmul = (eew/sew) * lmul 699 LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth)); 700 // update new eew 701 ElementBitwidth = 1 << Log2EEW; 702 ScalarType = ScalarTypeKind::SignedInteger; 703 UpdateAndCheckComplexProto(); 704 } else if (ComplexTT.first == "FixedSEW") { 705 uint32_t NewSEW; 706 ComplexTT.second.getAsInteger(10, NewSEW); 707 // Set invalid type if src and dst SEW are same. 708 if (ElementBitwidth == NewSEW) { 709 ScalarType = Invalid; 710 return; 711 } 712 // Update new SEW 713 ElementBitwidth = NewSEW; 714 UpdateAndCheckComplexProto(); 715 } else if (ComplexTT.first == "LFixedLog2LMUL") { 716 // New LMUL should be larger than old 717 if (!ComputeFixedLog2LMUL(ComplexTT.second, std::greater<int32_t>())) 718 return; 719 } else if (ComplexTT.first == "SFixedLog2LMUL") { 720 // New LMUL should be smaller than old 721 if (!ComputeFixedLog2LMUL(ComplexTT.second, std::less<int32_t>())) 722 return; 723 } else { 724 PrintFatalError("Illegal complex type transformers!"); 725 } 726 } 727 728 // Compute the remain type transformers 729 for (char I : Transformer) { 730 switch (I) { 731 case 'P': 732 if (IsConstant) 733 PrintFatalError("'P' transformer cannot be used after 'C'"); 734 if (IsPointer) 735 PrintFatalError("'P' transformer cannot be used twice"); 736 IsPointer = true; 737 break; 738 case 'C': 739 if (IsConstant) 740 PrintFatalError("'C' transformer cannot be used twice"); 741 IsConstant = true; 742 break; 743 case 'K': 744 IsImmediate = true; 745 break; 746 case 'U': 747 ScalarType = ScalarTypeKind::UnsignedInteger; 748 break; 749 case 'I': 750 ScalarType = ScalarTypeKind::SignedInteger; 751 break; 752 case 'F': 753 ScalarType = ScalarTypeKind::Float; 754 break; 755 case 'S': 756 LMUL = LMULType(0); 757 // Update ElementBitwidth need to update Scale too. 758 Scale = LMUL.getScale(ElementBitwidth); 759 break; 760 default: 761 PrintFatalError("Illegal non-primitive type transformer!"); 762 } 763 } 764 } 765 766 //===----------------------------------------------------------------------===// 767 // RVVIntrinsic implementation 768 //===----------------------------------------------------------------------===// 769 RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix, 770 StringRef NewMangledName, StringRef MangledSuffix, 771 StringRef IRName, bool IsMask, 772 bool HasMaskedOffOperand, bool HasVL, bool HasPolicy, 773 bool HasNoMaskedOverloaded, bool HasAutoDef, 774 StringRef ManualCodegen, const RVVTypes &OutInTypes, 775 const std::vector<int64_t> &NewIntrinsicTypes, 776 const std::vector<StringRef> &RequiredFeatures, 777 unsigned NF) 778 : IRName(IRName), IsMask(IsMask), HasVL(HasVL), HasPolicy(HasPolicy), 779 HasNoMaskedOverloaded(HasNoMaskedOverloaded), HasAutoDef(HasAutoDef), 780 ManualCodegen(ManualCodegen.str()), NF(NF) { 781 782 // Init BuiltinName, Name and MangledName 783 BuiltinName = NewName.str(); 784 Name = BuiltinName; 785 if (NewMangledName.empty()) 786 MangledName = NewName.split("_").first.str(); 787 else 788 MangledName = NewMangledName.str(); 789 if (!Suffix.empty()) 790 Name += "_" + Suffix.str(); 791 if (!MangledSuffix.empty()) 792 MangledName += "_" + MangledSuffix.str(); 793 if (IsMask) { 794 BuiltinName += "_m"; 795 Name += "_m"; 796 } 797 798 // Init RISC-V extensions 799 for (const auto &T : OutInTypes) { 800 if (T->isFloatVector(16) || T->isFloat(16)) 801 RISCVPredefinedMacros |= RISCVPredefinedMacro::Zfh; 802 if (T->isFloatVector(32)) 803 RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELenFp32; 804 if (T->isFloatVector(64)) 805 RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELenFp64; 806 if (T->isVector(64)) 807 RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELen64; 808 } 809 for (auto Feature : RequiredFeatures) { 810 if (Feature == "RV64") 811 RISCVPredefinedMacros |= RISCVPredefinedMacro::RV64; 812 // Note: Full multiply instruction (mulh, mulhu, mulhsu, smul) for EEW=64 813 // require V. 814 if (Feature == "FullMultiply" && 815 (RISCVPredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64)) 816 RISCVPredefinedMacros |= RISCVPredefinedMacro::V; 817 } 818 819 // Init OutputType and InputTypes 820 OutputType = OutInTypes[0]; 821 InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end()); 822 823 // IntrinsicTypes is nonmasked version index. Need to update it 824 // if there is maskedoff operand (It is always in first operand). 825 IntrinsicTypes = NewIntrinsicTypes; 826 if (IsMask && HasMaskedOffOperand) { 827 for (auto &I : IntrinsicTypes) { 828 if (I >= 0) 829 I += NF; 830 } 831 } 832 } 833 834 std::string RVVIntrinsic::getBuiltinTypeStr() const { 835 std::string S; 836 S += OutputType->getBuiltinStr(); 837 for (const auto &T : InputTypes) { 838 S += T->getBuiltinStr(); 839 } 840 return S; 841 } 842 843 void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const { 844 if (!getIRName().empty()) 845 OS << " ID = Intrinsic::riscv_" + getIRName() + ";\n"; 846 if (NF >= 2) 847 OS << " NF = " + utostr(getNF()) + ";\n"; 848 if (hasManualCodegen()) { 849 OS << ManualCodegen; 850 OS << "break;\n"; 851 return; 852 } 853 854 if (isMask()) { 855 if (hasVL()) { 856 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 857 if (hasPolicy()) 858 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 859 " TAIL_UNDISTURBED));\n"; 860 } else { 861 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 862 } 863 } 864 865 OS << " IntrinsicTypes = {"; 866 ListSeparator LS; 867 for (const auto &Idx : IntrinsicTypes) { 868 if (Idx == -1) 869 OS << LS << "ResultType"; 870 else 871 OS << LS << "Ops[" << Idx << "]->getType()"; 872 } 873 874 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 875 // always last operand. 876 if (hasVL()) 877 OS << ", Ops.back()->getType()"; 878 OS << "};\n"; 879 OS << " break;\n"; 880 } 881 882 void RVVIntrinsic::emitIntrinsicFuncDef(raw_ostream &OS) const { 883 OS << "__attribute__((__clang_builtin_alias__("; 884 OS << "__builtin_rvv_" << getBuiltinName() << ")))\n"; 885 OS << OutputType->getTypeStr() << " " << getName() << "("; 886 // Emit function arguments 887 if (!InputTypes.empty()) { 888 ListSeparator LS; 889 for (unsigned i = 0; i < InputTypes.size(); ++i) 890 OS << LS << InputTypes[i]->getTypeStr(); 891 } 892 OS << ");\n"; 893 } 894 895 void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const { 896 OS << "__attribute__((__clang_builtin_alias__("; 897 OS << "__builtin_rvv_" << getBuiltinName() << ")))\n"; 898 OS << OutputType->getTypeStr() << " " << getMangledName() << "("; 899 // Emit function arguments 900 if (!InputTypes.empty()) { 901 ListSeparator LS; 902 for (unsigned i = 0; i < InputTypes.size(); ++i) 903 OS << LS << InputTypes[i]->getTypeStr(); 904 } 905 OS << ");\n"; 906 } 907 908 //===----------------------------------------------------------------------===// 909 // RVVEmitter implementation 910 //===----------------------------------------------------------------------===// 911 void RVVEmitter::createHeader(raw_ostream &OS) { 912 913 OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 914 "-------------------===\n" 915 " *\n" 916 " *\n" 917 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 918 "Exceptions.\n" 919 " * See https://llvm.org/LICENSE.txt for license information.\n" 920 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 921 " *\n" 922 " *===-----------------------------------------------------------------" 923 "------===\n" 924 " */\n\n"; 925 926 OS << "#ifndef __RISCV_VECTOR_H\n"; 927 OS << "#define __RISCV_VECTOR_H\n\n"; 928 929 OS << "#include <stdint.h>\n"; 930 OS << "#include <stddef.h>\n\n"; 931 932 OS << "#ifndef __riscv_vector\n"; 933 OS << "#error \"Vector intrinsics require the vector extension.\"\n"; 934 OS << "#endif\n\n"; 935 936 OS << "#ifdef __cplusplus\n"; 937 OS << "extern \"C\" {\n"; 938 OS << "#endif\n\n"; 939 940 createRVVHeaders(OS); 941 942 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 943 createRVVIntrinsics(Defs); 944 945 // Print header code 946 if (!HeaderCode.empty()) { 947 OS << HeaderCode; 948 } 949 950 auto printType = [&](auto T) { 951 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 952 << ";\n"; 953 }; 954 955 constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 956 // Print RVV boolean types. 957 for (int Log2LMUL : Log2LMULs) { 958 auto T = computeType('c', Log2LMUL, "m"); 959 if (T.hasValue()) 960 printType(T.getValue()); 961 } 962 // Print RVV int/float types. 963 for (char I : StringRef("csil")) { 964 for (int Log2LMUL : Log2LMULs) { 965 auto T = computeType(I, Log2LMUL, "v"); 966 if (T.hasValue()) { 967 printType(T.getValue()); 968 auto UT = computeType(I, Log2LMUL, "Uv"); 969 printType(UT.getValue()); 970 } 971 } 972 } 973 OS << "#if defined(__riscv_zfh)\n"; 974 for (int Log2LMUL : Log2LMULs) { 975 auto T = computeType('x', Log2LMUL, "v"); 976 if (T.hasValue()) 977 printType(T.getValue()); 978 } 979 OS << "#endif\n"; 980 981 OS << "#if defined(__riscv_f)\n"; 982 for (int Log2LMUL : Log2LMULs) { 983 auto T = computeType('f', Log2LMUL, "v"); 984 if (T.hasValue()) 985 printType(T.getValue()); 986 } 987 OS << "#endif\n"; 988 989 OS << "#if defined(__riscv_d)\n"; 990 for (int Log2LMUL : Log2LMULs) { 991 auto T = computeType('d', Log2LMUL, "v"); 992 if (T.hasValue()) 993 printType(T.getValue()); 994 } 995 OS << "#endif\n\n"; 996 997 // The same extension include in the same arch guard marco. 998 llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 999 const std::unique_ptr<RVVIntrinsic> &B) { 1000 return A->getRISCVPredefinedMacros() < B->getRISCVPredefinedMacros(); 1001 }); 1002 1003 OS << "#define __rvv_ai static __inline__\n"; 1004 1005 // Print intrinsic functions with macro 1006 emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 1007 OS << "__rvv_ai "; 1008 Inst.emitIntrinsicFuncDef(OS); 1009 }); 1010 1011 OS << "#undef __rvv_ai\n\n"; 1012 1013 OS << "#define __riscv_v_intrinsic_overloading 1\n"; 1014 1015 // Print Overloaded APIs 1016 OS << "#define __rvv_aio static __inline__ " 1017 "__attribute__((__overloadable__))\n"; 1018 1019 emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 1020 if (!Inst.isMask() && !Inst.hasNoMaskedOverloaded()) 1021 return; 1022 OS << "__rvv_aio "; 1023 Inst.emitMangledFuncDef(OS); 1024 }); 1025 1026 OS << "#undef __rvv_aio\n"; 1027 1028 OS << "\n#ifdef __cplusplus\n"; 1029 OS << "}\n"; 1030 OS << "#endif // __cplusplus\n"; 1031 OS << "#endif // __RISCV_VECTOR_H\n"; 1032 } 1033 1034 void RVVEmitter::createBuiltins(raw_ostream &OS) { 1035 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 1036 createRVVIntrinsics(Defs); 1037 1038 // Map to keep track of which builtin names have already been emitted. 1039 StringMap<RVVIntrinsic *> BuiltinMap; 1040 1041 OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 1042 OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 1043 "ATTRS, \"zve32x|v\")\n"; 1044 OS << "#endif\n"; 1045 for (auto &Def : Defs) { 1046 auto P = 1047 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 1048 if (!P.second) { 1049 // Verify that this would have produced the same builtin definition. 1050 if (P.first->second->hasAutoDef() != Def->hasAutoDef()) { 1051 PrintFatalError("Builtin with same name has different hasAutoDef"); 1052 } else if (!Def->hasAutoDef() && P.first->second->getBuiltinTypeStr() != 1053 Def->getBuiltinTypeStr()) { 1054 PrintFatalError("Builtin with same name has different type string"); 1055 } 1056 continue; 1057 } 1058 1059 OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; 1060 if (!Def->hasAutoDef()) 1061 OS << Def->getBuiltinTypeStr(); 1062 OS << "\", \"n\")\n"; 1063 } 1064 OS << "#undef RISCVV_BUILTIN\n"; 1065 } 1066 1067 void RVVEmitter::createCodeGen(raw_ostream &OS) { 1068 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 1069 createRVVIntrinsics(Defs); 1070 // IR name could be empty, use the stable sort preserves the relative order. 1071 llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 1072 const std::unique_ptr<RVVIntrinsic> &B) { 1073 return A->getIRName() < B->getIRName(); 1074 }); 1075 1076 // Map to keep track of which builtin names have already been emitted. 1077 StringMap<RVVIntrinsic *> BuiltinMap; 1078 1079 // Print switch body when the ir name or ManualCodegen changes from previous 1080 // iteration. 1081 RVVIntrinsic *PrevDef = Defs.begin()->get(); 1082 for (auto &Def : Defs) { 1083 StringRef CurIRName = Def->getIRName(); 1084 if (CurIRName != PrevDef->getIRName() || 1085 (Def->getManualCodegen() != PrevDef->getManualCodegen())) { 1086 PrevDef->emitCodeGenSwitchBody(OS); 1087 } 1088 PrevDef = Def.get(); 1089 1090 auto P = 1091 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 1092 if (P.second) { 1093 OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 1094 << ":\n"; 1095 continue; 1096 } 1097 1098 if (P.first->second->getIRName() != Def->getIRName()) 1099 PrintFatalError("Builtin with same name has different IRName"); 1100 else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 1101 PrintFatalError("Builtin with same name has different ManualCodegen"); 1102 else if (P.first->second->getNF() != Def->getNF()) 1103 PrintFatalError("Builtin with same name has different NF"); 1104 else if (P.first->second->isMask() != Def->isMask()) 1105 PrintFatalError("Builtin with same name has different isMask"); 1106 else if (P.first->second->hasVL() != Def->hasVL()) 1107 PrintFatalError("Builtin with same name has different HasPolicy"); 1108 else if (P.first->second->hasPolicy() != Def->hasPolicy()) 1109 PrintFatalError("Builtin with same name has different HasPolicy"); 1110 else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 1111 PrintFatalError("Builtin with same name has different IntrinsicTypes"); 1112 } 1113 Defs.back()->emitCodeGenSwitchBody(OS); 1114 OS << "\n"; 1115 } 1116 1117 void RVVEmitter::parsePrototypes(StringRef Prototypes, 1118 std::function<void(StringRef)> Handler) { 1119 const StringRef Primaries("evwqom0ztul"); 1120 while (!Prototypes.empty()) { 1121 size_t Idx = 0; 1122 // Skip over complex prototype because it could contain primitive type 1123 // character. 1124 if (Prototypes[0] == '(') 1125 Idx = Prototypes.find_first_of(')'); 1126 Idx = Prototypes.find_first_of(Primaries, Idx); 1127 assert(Idx != StringRef::npos); 1128 Handler(Prototypes.slice(0, Idx + 1)); 1129 Prototypes = Prototypes.drop_front(Idx + 1); 1130 } 1131 } 1132 1133 std::string RVVEmitter::getSuffixStr(char Type, int Log2LMUL, 1134 StringRef Prototypes) { 1135 SmallVector<std::string> SuffixStrs; 1136 parsePrototypes(Prototypes, [&](StringRef Proto) { 1137 auto T = computeType(Type, Log2LMUL, Proto); 1138 SuffixStrs.push_back(T.getValue()->getShortStr()); 1139 }); 1140 return join(SuffixStrs, "_"); 1141 } 1142 1143 void RVVEmitter::createRVVIntrinsics( 1144 std::vector<std::unique_ptr<RVVIntrinsic>> &Out) { 1145 std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 1146 for (auto *R : RV) { 1147 StringRef Name = R->getValueAsString("Name"); 1148 StringRef SuffixProto = R->getValueAsString("Suffix"); 1149 StringRef MangledName = R->getValueAsString("MangledName"); 1150 StringRef MangledSuffixProto = R->getValueAsString("MangledSuffix"); 1151 StringRef Prototypes = R->getValueAsString("Prototype"); 1152 StringRef TypeRange = R->getValueAsString("TypeRange"); 1153 bool HasMask = R->getValueAsBit("HasMask"); 1154 bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 1155 bool HasVL = R->getValueAsBit("HasVL"); 1156 bool HasPolicy = R->getValueAsBit("HasPolicy"); 1157 bool HasNoMaskedOverloaded = R->getValueAsBit("HasNoMaskedOverloaded"); 1158 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 1159 StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 1160 StringRef ManualCodegenMask = R->getValueAsString("ManualCodegenMask"); 1161 std::vector<int64_t> IntrinsicTypes = 1162 R->getValueAsListOfInts("IntrinsicTypes"); 1163 std::vector<StringRef> RequiredFeatures = 1164 R->getValueAsListOfStrings("RequiredFeatures"); 1165 StringRef IRName = R->getValueAsString("IRName"); 1166 StringRef IRNameMask = R->getValueAsString("IRNameMask"); 1167 unsigned NF = R->getValueAsInt("NF"); 1168 1169 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 1170 bool HasAutoDef = HeaderCodeStr.empty(); 1171 if (!HeaderCodeStr.empty()) { 1172 HeaderCode += HeaderCodeStr.str(); 1173 } 1174 // Parse prototype and create a list of primitive type with transformers 1175 // (operand) in ProtoSeq. ProtoSeq[0] is output operand. 1176 SmallVector<std::string> ProtoSeq; 1177 parsePrototypes(Prototypes, [&ProtoSeq](StringRef Proto) { 1178 ProtoSeq.push_back(Proto.str()); 1179 }); 1180 1181 // Compute Builtin types 1182 SmallVector<std::string> ProtoMaskSeq = ProtoSeq; 1183 if (HasMask) { 1184 // If HasMaskedOffOperand, insert result type as first input operand. 1185 if (HasMaskedOffOperand) { 1186 if (NF == 1) { 1187 ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]); 1188 } else { 1189 // Convert 1190 // (void, op0 address, op1 address, ...) 1191 // to 1192 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 1193 for (unsigned I = 0; I < NF; ++I) 1194 ProtoMaskSeq.insert( 1195 ProtoMaskSeq.begin() + NF + 1, 1196 ProtoSeq[1].substr(1)); // Use substr(1) to skip '*' 1197 } 1198 } 1199 if (HasMaskedOffOperand && NF > 1) { 1200 // Convert 1201 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 1202 // to 1203 // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1, 1204 // ...) 1205 ProtoMaskSeq.insert(ProtoMaskSeq.begin() + NF + 1, "m"); 1206 } else { 1207 // If HasMask, insert 'm' as first input operand. 1208 ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m"); 1209 } 1210 } 1211 // If HasVL, append 'z' to last operand 1212 if (HasVL) { 1213 ProtoSeq.push_back("z"); 1214 ProtoMaskSeq.push_back("z"); 1215 } 1216 1217 // Create Intrinsics for each type and LMUL. 1218 for (char I : TypeRange) { 1219 for (int Log2LMUL : Log2LMULList) { 1220 Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, NF, ProtoSeq); 1221 // Ignored to create new intrinsic if there are any illegal types. 1222 if (!Types.hasValue()) 1223 continue; 1224 1225 auto SuffixStr = getSuffixStr(I, Log2LMUL, SuffixProto); 1226 auto MangledSuffixStr = getSuffixStr(I, Log2LMUL, MangledSuffixProto); 1227 // Create a non-mask intrinsic 1228 Out.push_back(std::make_unique<RVVIntrinsic>( 1229 Name, SuffixStr, MangledName, MangledSuffixStr, IRName, 1230 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, HasPolicy, 1231 HasNoMaskedOverloaded, HasAutoDef, ManualCodegen, Types.getValue(), 1232 IntrinsicTypes, RequiredFeatures, NF)); 1233 if (HasMask) { 1234 // Create a mask intrinsic 1235 Optional<RVVTypes> MaskTypes = 1236 computeTypes(I, Log2LMUL, NF, ProtoMaskSeq); 1237 Out.push_back(std::make_unique<RVVIntrinsic>( 1238 Name, SuffixStr, MangledName, MangledSuffixStr, IRNameMask, 1239 /*IsMask=*/true, HasMaskedOffOperand, HasVL, HasPolicy, 1240 HasNoMaskedOverloaded, HasAutoDef, ManualCodegenMask, 1241 MaskTypes.getValue(), IntrinsicTypes, RequiredFeatures, NF)); 1242 } 1243 } // end for Log2LMULList 1244 } // end for TypeRange 1245 } 1246 } 1247 1248 void RVVEmitter::createRVVHeaders(raw_ostream &OS) { 1249 std::vector<Record *> RVVHeaders = 1250 Records.getAllDerivedDefinitions("RVVHeader"); 1251 for (auto *R : RVVHeaders) { 1252 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 1253 OS << HeaderCodeStr.str(); 1254 } 1255 } 1256 1257 Optional<RVVTypes> 1258 RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, unsigned NF, 1259 ArrayRef<std::string> PrototypeSeq) { 1260 // LMUL x NF must be less than or equal to 8. 1261 if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8) 1262 return llvm::None; 1263 1264 RVVTypes Types; 1265 for (const std::string &Proto : PrototypeSeq) { 1266 auto T = computeType(BT, Log2LMUL, Proto); 1267 if (!T.hasValue()) 1268 return llvm::None; 1269 // Record legal type index 1270 Types.push_back(T.getValue()); 1271 } 1272 return Types; 1273 } 1274 1275 Optional<RVVTypePtr> RVVEmitter::computeType(BasicType BT, int Log2LMUL, 1276 StringRef Proto) { 1277 std::string Idx = Twine(Twine(BT) + Twine(Log2LMUL) + Proto).str(); 1278 // Search first 1279 auto It = LegalTypes.find(Idx); 1280 if (It != LegalTypes.end()) 1281 return &(It->second); 1282 if (IllegalTypes.count(Idx)) 1283 return llvm::None; 1284 // Compute type and record the result. 1285 RVVType T(BT, Log2LMUL, Proto); 1286 if (T.isValid()) { 1287 // Record legal type index and value. 1288 LegalTypes.insert({Idx, T}); 1289 return &(LegalTypes[Idx]); 1290 } 1291 // Record illegal type index. 1292 IllegalTypes.insert(Idx); 1293 return llvm::None; 1294 } 1295 1296 void RVVEmitter::emitArchMacroAndBody( 1297 std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS, 1298 std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) { 1299 RISCVPredefinedMacroT PrevMacros = 1300 (*Defs.begin())->getRISCVPredefinedMacros(); 1301 bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS); 1302 for (auto &Def : Defs) { 1303 RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros(); 1304 if (CurMacros != PrevMacros) { 1305 if (NeedEndif) 1306 OS << "#endif\n\n"; 1307 NeedEndif = emitMacroRestrictionStr(CurMacros, OS); 1308 PrevMacros = CurMacros; 1309 } 1310 if (Def->hasAutoDef()) 1311 PrintBody(OS, *Def); 1312 } 1313 if (NeedEndif) 1314 OS << "#endif\n\n"; 1315 } 1316 1317 bool RVVEmitter::emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, 1318 raw_ostream &OS) { 1319 if (PredefinedMacros == RISCVPredefinedMacro::Basic) 1320 return false; 1321 OS << "#if "; 1322 ListSeparator LS(" && "); 1323 if (PredefinedMacros & RISCVPredefinedMacro::V) 1324 OS << LS << "defined(__riscv_v)"; 1325 if (PredefinedMacros & RISCVPredefinedMacro::Zfh) 1326 OS << LS << "defined(__riscv_zfh)"; 1327 if (PredefinedMacros & RISCVPredefinedMacro::RV64) 1328 OS << LS << "(__riscv_xlen == 64)"; 1329 if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64) 1330 OS << LS << "(__riscv_v_elen >= 64)"; 1331 if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32) 1332 OS << LS << "(__riscv_v_elen_fp >= 32)"; 1333 if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64) 1334 OS << LS << "(__riscv_v_elen_fp >= 64)"; 1335 OS << "\n"; 1336 return true; 1337 } 1338 1339 namespace clang { 1340 void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 1341 RVVEmitter(Records).createHeader(OS); 1342 } 1343 1344 void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1345 RVVEmitter(Records).createBuiltins(OS); 1346 } 1347 1348 void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1349 RVVEmitter(Records).createCodeGen(OS); 1350 } 1351 1352 } // End namespace clang 1353