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