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