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