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 assert(isVector() && "only handle vector type"); 532 switch (ScalarType) { 533 case ScalarTypeKind::Boolean: 534 ShortStr = "b" + utostr(64 / Scale.getValue()); 535 break; 536 case ScalarTypeKind::Float: 537 ShortStr = "f" + utostr(ElementBitwidth) + LMUL.str(); 538 break; 539 case ScalarTypeKind::SignedInteger: 540 ShortStr = "i" + utostr(ElementBitwidth) + LMUL.str(); 541 break; 542 case ScalarTypeKind::UnsignedInteger: 543 ShortStr = "u" + utostr(ElementBitwidth) + LMUL.str(); 544 break; 545 default: 546 llvm_unreachable("Unhandled case!"); 547 } 548 } 549 550 void RVVType::applyBasicType() { 551 switch (BT) { 552 case 'c': 553 ElementBitwidth = 8; 554 ScalarType = ScalarTypeKind::SignedInteger; 555 break; 556 case 's': 557 ElementBitwidth = 16; 558 ScalarType = ScalarTypeKind::SignedInteger; 559 break; 560 case 'i': 561 ElementBitwidth = 32; 562 ScalarType = ScalarTypeKind::SignedInteger; 563 break; 564 case 'l': 565 ElementBitwidth = 64; 566 ScalarType = ScalarTypeKind::SignedInteger; 567 break; 568 case 'h': 569 ElementBitwidth = 16; 570 ScalarType = ScalarTypeKind::Float; 571 break; 572 case 'f': 573 ElementBitwidth = 32; 574 ScalarType = ScalarTypeKind::Float; 575 break; 576 case 'd': 577 ElementBitwidth = 64; 578 ScalarType = ScalarTypeKind::Float; 579 break; 580 default: 581 PrintFatalError("Unhandled type code!"); 582 } 583 assert(ElementBitwidth != 0 && "Bad element bitwidth!"); 584 } 585 586 void RVVType::applyModifier(StringRef Transformer) { 587 if (Transformer.empty()) 588 return; 589 // Handle primitive type transformer 590 auto PType = Transformer.back(); 591 switch (PType) { 592 case 'e': 593 Scale = 0; 594 break; 595 case 'v': 596 Scale = LMUL.getScale(ElementBitwidth); 597 break; 598 case 'w': 599 ElementBitwidth *= 2; 600 LMUL *= 2; 601 Scale = LMUL.getScale(ElementBitwidth); 602 break; 603 case 'q': 604 ElementBitwidth *= 4; 605 LMUL *= 4; 606 Scale = LMUL.getScale(ElementBitwidth); 607 break; 608 case 'o': 609 ElementBitwidth *= 8; 610 LMUL *= 8; 611 Scale = LMUL.getScale(ElementBitwidth); 612 break; 613 case 'm': 614 ScalarType = ScalarTypeKind::Boolean; 615 Scale = LMUL.getScale(ElementBitwidth); 616 ElementBitwidth = 1; 617 break; 618 case '0': 619 ScalarType = ScalarTypeKind::Void; 620 break; 621 case 'z': 622 ScalarType = ScalarTypeKind::Size_t; 623 break; 624 case 't': 625 ScalarType = ScalarTypeKind::Ptrdiff_t; 626 break; 627 case 'u': 628 ScalarType = ScalarTypeKind::UnsignedLong; 629 break; 630 case 'l': 631 ScalarType = ScalarTypeKind::SignedLong; 632 break; 633 default: 634 PrintFatalError("Illegal primitive type transformers!"); 635 } 636 Transformer = Transformer.drop_back(); 637 638 // Extract and compute complex type transformer. It can only appear one time. 639 if (Transformer.startswith("(")) { 640 size_t Idx = Transformer.find(')'); 641 assert(Idx != StringRef::npos); 642 StringRef ComplexType = Transformer.slice(1, Idx); 643 Transformer = Transformer.drop_front(Idx + 1); 644 assert(Transformer.find('(') == StringRef::npos && 645 "Only allow one complex type transformer"); 646 647 auto UpdateAndCheckComplexProto = [&]() { 648 Scale = LMUL.getScale(ElementBitwidth); 649 const StringRef VectorPrototypes("vwqom"); 650 if (!VectorPrototypes.contains(PType)) 651 PrintFatalError("Complex type transformer only supports vector type!"); 652 if (Transformer.find_first_of("PCKWS") != StringRef::npos) 653 PrintFatalError( 654 "Illegal type transformer for Complex type transformer"); 655 }; 656 auto ComplexTT = ComplexType.split(":"); 657 if (ComplexTT.first == "Log2EEW") { 658 uint32_t Log2EEW; 659 ComplexTT.second.getAsInteger(10, Log2EEW); 660 // update new elmul = (eew/sew) * lmul 661 LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth)); 662 // update new eew 663 ElementBitwidth = 1 << Log2EEW; 664 ScalarType = ScalarTypeKind::SignedInteger; 665 UpdateAndCheckComplexProto(); 666 } else { 667 PrintFatalError("Illegal complex type transformers!"); 668 } 669 } 670 671 // Compute the remain type transformers 672 for (char I : Transformer) { 673 switch (I) { 674 case 'P': 675 if (IsConstant) 676 PrintFatalError("'P' transformer cannot be used after 'C'"); 677 if (IsPointer) 678 PrintFatalError("'P' transformer cannot be used twice"); 679 IsPointer = true; 680 break; 681 case 'C': 682 if (IsConstant) 683 PrintFatalError("'C' transformer cannot be used twice"); 684 IsConstant = true; 685 break; 686 case 'K': 687 IsImmediate = true; 688 break; 689 case 'U': 690 ScalarType = ScalarTypeKind::UnsignedInteger; 691 break; 692 case 'I': 693 ScalarType = ScalarTypeKind::SignedInteger; 694 break; 695 case 'F': 696 ScalarType = ScalarTypeKind::Float; 697 break; 698 case 'S': 699 LMUL = LMULType(0); 700 // Update ElementBitwidth need to update Scale too. 701 Scale = LMUL.getScale(ElementBitwidth); 702 break; 703 default: 704 PrintFatalError("Illegal non-primitive type transformer!"); 705 } 706 } 707 } 708 709 //===----------------------------------------------------------------------===// 710 // RVVIntrinsic implementation 711 //===----------------------------------------------------------------------===// 712 RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix, 713 StringRef NewMangledName, StringRef IRName, 714 bool HasSideEffects, bool IsMask, 715 bool HasMaskedOffOperand, bool HasVL, 716 bool HasNoMaskedOverloaded, bool HasAutoDef, 717 StringRef ManualCodegen, const RVVTypes &OutInTypes, 718 const std::vector<int64_t> &NewIntrinsicTypes, 719 const std::vector<int64_t> &PermuteOperands) 720 : IRName(IRName), HasSideEffects(HasSideEffects), IsMask(IsMask), 721 HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), 722 HasNoMaskedOverloaded(HasNoMaskedOverloaded), HasAutoDef(HasAutoDef), 723 ManualCodegen(ManualCodegen.str()) { 724 725 // Init Name and MangledName 726 Name = NewName.str(); 727 if (NewMangledName.empty()) 728 MangledName = NewName.split("_").first.str(); 729 else 730 MangledName = NewMangledName.str(); 731 if (!Suffix.empty()) 732 Name += "_" + Suffix.str(); 733 if (IsMask) { 734 Name += "_m"; 735 } 736 // Init RISC-V extensions 737 for (const auto &T : OutInTypes) { 738 if (T->isFloatVector(16)) 739 RISCVExtensions |= RISCVExtension::Zfh; 740 else if (T->isFloatVector(32)) 741 RISCVExtensions |= RISCVExtension::F; 742 else if (T->isFloatVector(64)) 743 RISCVExtensions |= RISCVExtension::D; 744 } 745 746 // Init OutputType and InputTypes 747 OutputType = OutInTypes[0]; 748 InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end()); 749 CTypeOrder.resize(InputTypes.size()); 750 std::iota(CTypeOrder.begin(), CTypeOrder.end(), 0); 751 // Update default order if we need permutate. 752 if (!PermuteOperands.empty()) { 753 // PermuteOperands is nonmasked version index. Update index when there is 754 // maskedoff operand which is always in first operand. 755 756 unsigned Skew = HasMaskedOffOperand ? 1 : 0; 757 for (unsigned i = 0; i < PermuteOperands.size(); ++i) { 758 if (i != PermuteOperands[i]) 759 CTypeOrder[i] = PermuteOperands[i] + Skew; 760 } 761 // Verify the result of CTypeOrder has legal value. 762 if (*std::max_element(CTypeOrder.begin(), CTypeOrder.end()) >= 763 CTypeOrder.size()) 764 PrintFatalError( 765 "The index of PermuteOperand is bigger than the operand number"); 766 SmallSet<unsigned, 8> Seen; 767 for (auto Idx : CTypeOrder) { 768 if (!Seen.insert(Idx).second) 769 PrintFatalError( 770 "The different element in PermuteOperand could not be equal"); 771 } 772 } 773 774 if (IsMask) { 775 if (HasVL) 776 // Builtin type order: op0, op1, ..., mask, vl 777 // C type order: mask, op0, op1, ..., vl 778 std::rotate(CTypeOrder.begin(), CTypeOrder.end() - 2, 779 CTypeOrder.end() - 1); 780 else 781 // Builtin type order: op0, op1, ..., mask 782 // C type order: mask, op0, op1, ..., 783 std::rotate(CTypeOrder.begin(), CTypeOrder.end() - 1, CTypeOrder.end()); 784 } 785 786 // IntrinsicTypes is nonmasked version index. Need to update it 787 // if there is maskedoff operand (It is always in first operand). 788 IntrinsicTypes = NewIntrinsicTypes; 789 if (IsMask && HasMaskedOffOperand) { 790 for (auto &I : IntrinsicTypes) { 791 if (I >= 0) 792 I += 1; 793 } 794 } 795 } 796 797 std::string RVVIntrinsic::getBuiltinTypeStr() const { 798 std::string S; 799 S += OutputType->getBuiltinStr(); 800 for (const auto &T : InputTypes) { 801 S += T->getBuiltinStr(); 802 } 803 return S; 804 } 805 806 void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const { 807 808 OS << " ID = Intrinsic::riscv_" + getIRName() + ";\n"; 809 if (hasManualCodegen()) { 810 OS << ManualCodegen; 811 OS << "break;\n"; 812 return; 813 } 814 OS << " IntrinsicTypes = {"; 815 ListSeparator LS; 816 for (const auto &Idx : IntrinsicTypes) { 817 if (Idx == -1) 818 OS << LS << "ResultType"; 819 else 820 OS << LS << "Ops[" << Idx << "]->getType()"; 821 } 822 823 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 824 // always last operand. 825 if (hasVL()) 826 OS << ", Ops[" << getNumOperand() - 1 << "]->getType()"; 827 OS << "};\n"; 828 OS << " break;\n"; 829 } 830 831 void RVVIntrinsic::emitIntrinsicMacro(raw_ostream &OS) const { 832 OS << "#define " << getName() << "("; 833 if (getNumOperand() > 0) { 834 ListSeparator LS; 835 for (const auto &I : CTypeOrder) 836 OS << LS << "op" << I; 837 } 838 OS << ") \\\n"; 839 OS << "__builtin_rvv_" << getName() << "("; 840 if (getNumOperand() > 0) { 841 ListSeparator LS; 842 for (unsigned i = 0; i < InputTypes.size(); ++i) 843 OS << LS << "(" << InputTypes[i]->getTypeStr() << ")(op" << i << ")"; 844 } 845 OS << ")\n"; 846 } 847 848 void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const { 849 OS << OutputType->getTypeStr() << " " << getMangledName() << "("; 850 // Emit function arguments 851 if (getNumOperand() > 0) { 852 ListSeparator LS; 853 for (unsigned i = 0; i < CTypeOrder.size(); ++i) 854 OS << LS << InputTypes[CTypeOrder[i]]->getTypeStr() << " op" << i; 855 } 856 OS << "){\n"; 857 OS << " return " << getName() << "("; 858 // Emit parameter variables 859 if (getNumOperand() > 0) { 860 ListSeparator LS; 861 for (unsigned i = 0; i < CTypeOrder.size(); ++i) 862 OS << LS << "op" << i; 863 } 864 OS << ");\n"; 865 OS << "}\n\n"; 866 } 867 868 //===----------------------------------------------------------------------===// 869 // RVVEmitter implementation 870 //===----------------------------------------------------------------------===// 871 void RVVEmitter::createHeader(raw_ostream &OS) { 872 873 OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 874 "-------------------===\n" 875 " *\n" 876 " *\n" 877 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 878 "Exceptions.\n" 879 " * See https://llvm.org/LICENSE.txt for license information.\n" 880 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 881 " *\n" 882 " *===-----------------------------------------------------------------" 883 "------===\n" 884 " */\n\n"; 885 886 OS << "#ifndef __RISCV_VECTOR_H\n"; 887 OS << "#define __RISCV_VECTOR_H\n\n"; 888 889 OS << "#include <stdint.h>\n"; 890 OS << "#include <stddef.h>\n\n"; 891 892 OS << "#ifndef __riscv_vector\n"; 893 OS << "#error \"Vector intrinsics require the vector extension.\"\n"; 894 OS << "#endif\n\n"; 895 896 OS << "#ifdef __cplusplus\n"; 897 OS << "extern \"C\" {\n"; 898 OS << "#endif\n\n"; 899 900 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 901 createRVVIntrinsics(Defs); 902 903 // Print header code 904 if (!HeaderCode.empty()) { 905 OS << HeaderCode; 906 } 907 908 auto printType = [&](auto T) { 909 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 910 << ";\n"; 911 }; 912 913 constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 914 // Print RVV boolean types. 915 for (int Log2LMUL : Log2LMULs) { 916 auto T = computeType('c', Log2LMUL, "m"); 917 if (T.hasValue()) 918 printType(T.getValue()); 919 } 920 // Print RVV int/float types. 921 for (char I : StringRef("csil")) { 922 for (int Log2LMUL : Log2LMULs) { 923 auto T = computeType(I, Log2LMUL, "v"); 924 if (T.hasValue()) { 925 printType(T.getValue()); 926 auto UT = computeType(I, Log2LMUL, "Uv"); 927 printType(UT.getValue()); 928 } 929 } 930 } 931 OS << "#if defined(__riscv_zfh)\n"; 932 for (int Log2LMUL : Log2LMULs) { 933 auto T = computeType('h', Log2LMUL, "v"); 934 if (T.hasValue()) 935 printType(T.getValue()); 936 } 937 OS << "#endif\n"; 938 939 OS << "#if defined(__riscv_f)\n"; 940 for (int Log2LMUL : Log2LMULs) { 941 auto T = computeType('f', Log2LMUL, "v"); 942 if (T.hasValue()) 943 printType(T.getValue()); 944 } 945 OS << "#endif\n"; 946 947 OS << "#if defined(__riscv_d)\n"; 948 for (int Log2LMUL : Log2LMULs) { 949 auto T = computeType('d', Log2LMUL, "v"); 950 if (T.hasValue()) 951 printType(T.getValue()); 952 } 953 OS << "#endif\n\n"; 954 955 // The same extension include in the same arch guard marco. 956 std::stable_sort(Defs.begin(), Defs.end(), 957 [](const std::unique_ptr<RVVIntrinsic> &A, 958 const std::unique_ptr<RVVIntrinsic> &B) { 959 return A->getRISCVExtensions() < B->getRISCVExtensions(); 960 }); 961 962 // Print intrinsic functions with macro 963 emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 964 Inst.emitIntrinsicMacro(OS); 965 }); 966 967 OS << "#define __riscv_v_intrinsic_overloading 1\n"; 968 969 // Print Overloaded APIs 970 OS << "#define __rvv_overloaded static inline " 971 "__attribute__((__always_inline__, __nodebug__, __overloadable__))\n"; 972 973 emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 974 if (!Inst.isMask() && !Inst.hasNoMaskedOverloaded()) 975 return; 976 OS << "__rvv_overloaded "; 977 Inst.emitMangledFuncDef(OS); 978 }); 979 980 OS << "\n#ifdef __cplusplus\n"; 981 OS << "}\n"; 982 OS << "#endif // __riscv_vector\n"; 983 OS << "#endif // __RISCV_VECTOR_H\n"; 984 } 985 986 void RVVEmitter::createBuiltins(raw_ostream &OS) { 987 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 988 createRVVIntrinsics(Defs); 989 990 OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 991 OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 992 "ATTRS, \"experimental-v\")\n"; 993 OS << "#endif\n"; 994 for (auto &Def : Defs) { 995 OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getName() << ",\"" 996 << Def->getBuiltinTypeStr() << "\", "; 997 if (!Def->hasSideEffects()) 998 OS << "\"n\")\n"; 999 else 1000 OS << "\"\")\n"; 1001 } 1002 OS << "#undef RISCVV_BUILTIN\n"; 1003 } 1004 1005 void RVVEmitter::createCodeGen(raw_ostream &OS) { 1006 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 1007 createRVVIntrinsics(Defs); 1008 1009 // The same intrinsic IR name has the same switch body. 1010 std::stable_sort(Defs.begin(), Defs.end(), 1011 [](const std::unique_ptr<RVVIntrinsic> &A, 1012 const std::unique_ptr<RVVIntrinsic> &B) { 1013 return A->getIRName() < B->getIRName(); 1014 }); 1015 // Print switch body when the ir name changes from previous iteration. 1016 RVVIntrinsic *PrevDef = Defs.begin()->get(); 1017 for (auto &Def : Defs) { 1018 StringRef CurIRName = Def->getIRName(); 1019 if (CurIRName != PrevDef->getIRName()) { 1020 PrevDef->emitCodeGenSwitchBody(OS); 1021 } 1022 PrevDef = Def.get(); 1023 OS << "case RISCV::BI__builtin_rvv_" << Def->getName() << ":\n"; 1024 } 1025 Defs.back()->emitCodeGenSwitchBody(OS); 1026 OS << "\n"; 1027 } 1028 1029 void RVVEmitter::parsePrototypes(StringRef Prototypes, 1030 std::function<void(StringRef)> Handler) { 1031 const StringRef Primaries("evwqom0ztul"); 1032 while (!Prototypes.empty()) { 1033 size_t Idx = 0; 1034 // Skip over complex prototype because it could contain primitive type 1035 // character. 1036 if (Prototypes[0] == '(') 1037 Idx = Prototypes.find_first_of(')'); 1038 Idx = Prototypes.find_first_of(Primaries, Idx); 1039 assert(Idx != StringRef::npos); 1040 Handler(Prototypes.slice(0, Idx + 1)); 1041 Prototypes = Prototypes.drop_front(Idx + 1); 1042 } 1043 } 1044 1045 std::string RVVEmitter::getSuffixStr(char Type, int Log2LMUL, 1046 StringRef Prototypes) { 1047 SmallVector<std::string> SuffixStrs; 1048 parsePrototypes(Prototypes, [&](StringRef Proto) { 1049 auto T = computeType(Type, Log2LMUL, Proto); 1050 SuffixStrs.push_back(T.getValue()->getShortStr()); 1051 }); 1052 return join(SuffixStrs, "_"); 1053 } 1054 1055 void RVVEmitter::createRVVIntrinsics( 1056 std::vector<std::unique_ptr<RVVIntrinsic>> &Out) { 1057 std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 1058 for (auto *R : RV) { 1059 StringRef Name = R->getValueAsString("Name"); 1060 StringRef SuffixProto = R->getValueAsString("Suffix"); 1061 StringRef MangledName = R->getValueAsString("MangledName"); 1062 StringRef Prototypes = R->getValueAsString("Prototype"); 1063 StringRef TypeRange = R->getValueAsString("TypeRange"); 1064 bool HasMask = R->getValueAsBit("HasMask"); 1065 bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 1066 bool HasVL = R->getValueAsBit("HasVL"); 1067 bool HasNoMaskedOverloaded = R->getValueAsBit("HasNoMaskedOverloaded"); 1068 bool HasSideEffects = R->getValueAsBit("HasSideEffects"); 1069 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 1070 StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 1071 StringRef ManualCodegenMask = R->getValueAsString("ManualCodegenMask"); 1072 std::vector<int64_t> IntrinsicTypes = 1073 R->getValueAsListOfInts("IntrinsicTypes"); 1074 std::vector<int64_t> PermuteOperands = 1075 R->getValueAsListOfInts("PermuteOperands"); 1076 StringRef IRName = R->getValueAsString("IRName"); 1077 StringRef IRNameMask = R->getValueAsString("IRNameMask"); 1078 1079 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 1080 bool HasAutoDef = HeaderCodeStr.empty(); 1081 if (!HeaderCodeStr.empty()) { 1082 HeaderCode += HeaderCodeStr.str(); 1083 } 1084 // Parse prototype and create a list of primitive type with transformers 1085 // (operand) in ProtoSeq. ProtoSeq[0] is output operand. 1086 SmallVector<std::string> ProtoSeq; 1087 parsePrototypes(Prototypes, [&ProtoSeq](StringRef Proto) { 1088 ProtoSeq.push_back(Proto.str()); 1089 }); 1090 1091 // Compute Builtin types 1092 SmallVector<std::string> ProtoMaskSeq = ProtoSeq; 1093 if (HasMask) { 1094 // If HasMask, append 'm' to last operand. 1095 ProtoMaskSeq.push_back("m"); 1096 // If HasMaskedOffOperand, insert result type as first input operand. 1097 if (HasMaskedOffOperand) 1098 ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]); 1099 } 1100 // If HasVL, append 'z' to last operand 1101 if (HasVL) { 1102 ProtoSeq.push_back("z"); 1103 ProtoMaskSeq.push_back("z"); 1104 } 1105 1106 // Create Intrinsics for each type and LMUL. 1107 for (char I : TypeRange) { 1108 for (int Log2LMUL : Log2LMULList) { 1109 Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, ProtoSeq); 1110 // Ignored to create new intrinsic if there are any illegal types. 1111 if (!Types.hasValue()) 1112 continue; 1113 1114 auto SuffixStr = getSuffixStr(I, Log2LMUL, SuffixProto); 1115 // Create a non-mask intrinsic 1116 Out.push_back(std::make_unique<RVVIntrinsic>( 1117 Name, SuffixStr, MangledName, IRName, HasSideEffects, 1118 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, 1119 HasNoMaskedOverloaded, HasAutoDef, ManualCodegen, Types.getValue(), 1120 IntrinsicTypes, PermuteOperands)); 1121 if (HasMask) { 1122 // Create a mask intrinsic 1123 Optional<RVVTypes> MaskTypes = 1124 computeTypes(I, Log2LMUL, ProtoMaskSeq); 1125 Out.push_back(std::make_unique<RVVIntrinsic>( 1126 Name, SuffixStr, MangledName, IRNameMask, HasSideEffects, 1127 /*IsMask=*/true, HasMaskedOffOperand, HasVL, 1128 HasNoMaskedOverloaded, HasAutoDef, ManualCodegenMask, 1129 MaskTypes.getValue(), IntrinsicTypes, PermuteOperands)); 1130 } 1131 } // end for Log2LMULList 1132 } // end for TypeRange 1133 } 1134 } 1135 1136 Optional<RVVTypes> 1137 RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, 1138 ArrayRef<std::string> PrototypeSeq) { 1139 RVVTypes Types; 1140 for (const std::string &Proto : PrototypeSeq) { 1141 auto T = computeType(BT, Log2LMUL, Proto); 1142 if (!T.hasValue()) 1143 return llvm::None; 1144 // Record legal type index 1145 Types.push_back(T.getValue()); 1146 } 1147 return Types; 1148 } 1149 1150 Optional<RVVTypePtr> RVVEmitter::computeType(BasicType BT, int Log2LMUL, 1151 StringRef Proto) { 1152 std::string Idx = Twine(Twine(BT) + Twine(Log2LMUL) + Proto).str(); 1153 // Search first 1154 auto It = LegalTypes.find(Idx); 1155 if (It != LegalTypes.end()) 1156 return &(It->second); 1157 if (IllegalTypes.count(Idx)) 1158 return llvm::None; 1159 // Compute type and record the result. 1160 RVVType T(BT, Log2LMUL, Proto); 1161 if (T.isValid()) { 1162 // Record legal type index and value. 1163 LegalTypes.insert({Idx, T}); 1164 return &(LegalTypes[Idx]); 1165 } 1166 // Record illegal type index. 1167 IllegalTypes.insert(Idx); 1168 return llvm::None; 1169 } 1170 1171 void RVVEmitter::emitArchMacroAndBody( 1172 std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS, 1173 std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) { 1174 uint8_t PrevExt = (*Defs.begin())->getRISCVExtensions(); 1175 bool NeedEndif = emitExtDefStr(PrevExt, OS); 1176 for (auto &Def : Defs) { 1177 uint8_t CurExt = Def->getRISCVExtensions(); 1178 if (CurExt != PrevExt) { 1179 if (NeedEndif) 1180 OS << "#endif\n\n"; 1181 NeedEndif = emitExtDefStr(CurExt, OS); 1182 PrevExt = CurExt; 1183 } 1184 if (Def->hasAutoDef()) 1185 PrintBody(OS, *Def); 1186 } 1187 if (NeedEndif) 1188 OS << "#endif\n\n"; 1189 } 1190 1191 bool RVVEmitter::emitExtDefStr(uint8_t Extents, raw_ostream &OS) { 1192 if (Extents == RISCVExtension::Basic) 1193 return false; 1194 OS << "#if "; 1195 ListSeparator LS(" && "); 1196 if (Extents & RISCVExtension::F) 1197 OS << LS << "defined(__riscv_f)"; 1198 if (Extents & RISCVExtension::D) 1199 OS << LS << "defined(__riscv_d)"; 1200 if (Extents & RISCVExtension::Zfh) 1201 OS << LS << "defined(__riscv_zfh)"; 1202 OS << "\n"; 1203 return true; 1204 } 1205 1206 namespace clang { 1207 void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 1208 RVVEmitter(Records).createHeader(OS); 1209 } 1210 1211 void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1212 RVVEmitter(Records).createBuiltins(OS); 1213 } 1214 1215 void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1216 RVVEmitter(Records).createCodeGen(OS); 1217 } 1218 1219 } // End namespace clang 1220