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