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