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