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