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