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