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