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