1 //===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===// 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 arm_sve.h, which includes 10 // a declaration and definition of each function specified by the ARM C/C++ 11 // Language Extensions (ACLE). 12 // 13 // For details, visit: 14 // https://developer.arm.com/architectures/system-architectures/software-standards/acle 15 // 16 // Each SVE instruction is implemented in terms of 1 or more functions which 17 // are suffixed with the element type of the input vectors. Functions may be 18 // implemented in terms of generic vector operations such as +, *, -, etc. or 19 // by calling a __builtin_-prefixed function which will be handled by clang's 20 // CodeGen library. 21 // 22 // See also the documentation in include/clang/Basic/arm_sve.td. 23 // 24 //===----------------------------------------------------------------------===// 25 26 #include "llvm/ADT/STLExtras.h" 27 #include "llvm/ADT/StringMap.h" 28 #include "llvm/ADT/ArrayRef.h" 29 #include "llvm/ADT/StringExtras.h" 30 #include "llvm/TableGen/Record.h" 31 #include "llvm/TableGen/Error.h" 32 #include <string> 33 #include <sstream> 34 #include <set> 35 #include <cctype> 36 #include <tuple> 37 38 using namespace llvm; 39 40 enum ClassKind { 41 ClassNone, 42 ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix 43 ClassG, // Overloaded name without type suffix 44 }; 45 46 using TypeSpec = std::string; 47 48 namespace { 49 50 class ImmCheck { 51 unsigned Arg; 52 unsigned Kind; 53 unsigned ElementSizeInBits; 54 55 public: 56 ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0) 57 : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {} 58 ImmCheck(const ImmCheck &Other) = default; 59 ~ImmCheck() = default; 60 61 unsigned getArg() const { return Arg; } 62 unsigned getKind() const { return Kind; } 63 unsigned getElementSizeInBits() const { return ElementSizeInBits; } 64 }; 65 66 class SVEType { 67 TypeSpec TS; 68 bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat; 69 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp, 70 Svcount; 71 unsigned Bitwidth, ElementBitwidth, NumVectors; 72 73 public: 74 SVEType() : SVEType(TypeSpec(), 'v') {} 75 76 SVEType(TypeSpec TS, char CharMod) 77 : TS(TS), Float(false), Signed(true), Immediate(false), Void(false), 78 Constant(false), Pointer(false), BFloat(false), DefaultType(false), 79 IsScalable(true), Predicate(false), PredicatePattern(false), 80 PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U), 81 NumVectors(1) { 82 if (!TS.empty()) 83 applyTypespec(); 84 applyModifier(CharMod); 85 } 86 87 bool isPointer() const { return Pointer; } 88 bool isVoidPointer() const { return Pointer && Void; } 89 bool isSigned() const { return Signed; } 90 bool isImmediate() const { return Immediate; } 91 bool isScalar() const { return NumVectors == 0; } 92 bool isVector() const { return NumVectors > 0; } 93 bool isScalableVector() const { return isVector() && IsScalable; } 94 bool isChar() const { return ElementBitwidth == 8; } 95 bool isVoid() const { return Void & !Pointer; } 96 bool isDefault() const { return DefaultType; } 97 bool isFloat() const { return Float && !BFloat; } 98 bool isBFloat() const { return BFloat && !Float; } 99 bool isFloatingPoint() const { return Float || BFloat; } 100 bool isInteger() const { 101 return !isFloatingPoint() && !Predicate && !Svcount; 102 } 103 bool isScalarPredicate() const { 104 return !isFloatingPoint() && Predicate && NumVectors == 0; 105 } 106 bool isPredicateVector() const { return Predicate; } 107 bool isPredicatePattern() const { return PredicatePattern; } 108 bool isPrefetchOp() const { return PrefetchOp; } 109 bool isSvcount() const { return Svcount; } 110 bool isConstant() const { return Constant; } 111 unsigned getElementSizeInBits() const { return ElementBitwidth; } 112 unsigned getNumVectors() const { return NumVectors; } 113 114 unsigned getNumElements() const { 115 assert(ElementBitwidth != ~0U); 116 return Bitwidth / ElementBitwidth; 117 } 118 unsigned getSizeInBits() const { 119 return Bitwidth; 120 } 121 122 /// Return the string representation of a type, which is an encoded 123 /// string for passing to the BUILTIN() macro in Builtins.def. 124 std::string builtin_str() const; 125 126 /// Return the C/C++ string representation of a type for use in the 127 /// arm_sve.h header file. 128 std::string str() const; 129 130 private: 131 /// Creates the type based on the typespec string in TS. 132 void applyTypespec(); 133 134 /// Applies a prototype modifier to the type. 135 void applyModifier(char Mod); 136 }; 137 138 139 class SVEEmitter; 140 141 /// The main grunt class. This represents an instantiation of an intrinsic with 142 /// a particular typespec and prototype. 143 class Intrinsic { 144 /// The unmangled name. 145 std::string Name; 146 147 /// The name of the corresponding LLVM IR intrinsic. 148 std::string LLVMName; 149 150 /// Intrinsic prototype. 151 std::string Proto; 152 153 /// The base type spec for this intrinsic. 154 TypeSpec BaseTypeSpec; 155 156 /// The base class kind. Most intrinsics use ClassS, which has full type 157 /// info for integers (_s32/_u32), or ClassG which is used for overloaded 158 /// intrinsics. 159 ClassKind Class; 160 161 /// The architectural #ifdef guard. 162 std::string Guard; 163 164 // The merge suffix such as _m, _x or _z. 165 std::string MergeSuffix; 166 167 /// The types of return value [0] and parameters [1..]. 168 std::vector<SVEType> Types; 169 170 /// The "base type", which is VarType('d', BaseTypeSpec). 171 SVEType BaseType; 172 173 uint64_t Flags; 174 175 SmallVector<ImmCheck, 2> ImmChecks; 176 177 public: 178 Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, 179 StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName, 180 uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT, 181 ClassKind Class, SVEEmitter &Emitter, StringRef Guard); 182 183 ~Intrinsic()=default; 184 185 std::string getName() const { return Name; } 186 std::string getLLVMName() const { return LLVMName; } 187 std::string getProto() const { return Proto; } 188 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; } 189 SVEType getBaseType() const { return BaseType; } 190 191 StringRef getGuard() const { return Guard; } 192 ClassKind getClassKind() const { return Class; } 193 194 SVEType getReturnType() const { return Types[0]; } 195 ArrayRef<SVEType> getTypes() const { return Types; } 196 SVEType getParamType(unsigned I) const { return Types[I + 1]; } 197 unsigned getNumParams() const { return Proto.size() - 1; } 198 199 uint64_t getFlags() const { return Flags; } 200 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;} 201 202 ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; } 203 204 /// Return the type string for a BUILTIN() macro in Builtins.def. 205 std::string getBuiltinTypeStr(); 206 207 /// Return the name, mangled with type information. The name is mangled for 208 /// ClassS, so will add type suffixes such as _u32/_s32. 209 std::string getMangledName() const { return mangleName(ClassS); } 210 211 /// As above, but mangles the LLVM name instead. 212 std::string getMangledLLVMName() const { return mangleLLVMName(); } 213 214 /// Returns true if the intrinsic is overloaded, in that it should also generate 215 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of 216 /// 'svld1_u32(..)'. 217 static bool isOverloadedIntrinsic(StringRef Name) { 218 auto BrOpen = Name.find('['); 219 auto BrClose = Name.find(']'); 220 return BrOpen != std::string::npos && BrClose != std::string::npos; 221 } 222 223 /// Return true if the intrinsic takes a splat operand. 224 bool hasSplat() const { 225 // These prototype modifiers are described in arm_sve.td. 226 return Proto.find_first_of("ajfrKLR@") != std::string::npos; 227 } 228 229 /// Return the parameter index of the splat operand. 230 unsigned getSplatIdx() const { 231 // These prototype modifiers are described in arm_sve.td. 232 auto Idx = Proto.find_first_of("ajfrKLR@"); 233 assert(Idx != std::string::npos && Idx > 0 && 234 "Prototype has no splat operand"); 235 return Idx - 1; 236 } 237 238 /// Emits the intrinsic declaration to the ostream. 239 void emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter) const; 240 241 private: 242 std::string getMergeSuffix() const { return MergeSuffix; } 243 std::string mangleName(ClassKind LocalCK) const; 244 std::string mangleLLVMName() const; 245 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS, 246 std::string Proto) const; 247 }; 248 249 class SVEEmitter { 250 private: 251 // The reinterpret builtins are generated separately because they 252 // need the cross product of all types (121 functions in total), 253 // which is inconvenient to specify in the arm_sve.td file or 254 // generate in CGBuiltin.cpp. 255 struct ReinterpretTypeInfo { 256 const char *Suffix; 257 const char *Type; 258 const char *BuiltinType; 259 }; 260 SmallVector<ReinterpretTypeInfo, 12> Reinterprets = { 261 {"s8", "svint8_t", "q16Sc"}, {"s16", "svint16_t", "q8Ss"}, 262 {"s32", "svint32_t", "q4Si"}, {"s64", "svint64_t", "q2SWi"}, 263 {"u8", "svuint8_t", "q16Uc"}, {"u16", "svuint16_t", "q8Us"}, 264 {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"}, 265 {"f16", "svfloat16_t", "q8h"}, {"bf16", "svbfloat16_t", "q8y"}, 266 {"f32", "svfloat32_t", "q4f"}, {"f64", "svfloat64_t", "q2d"}}; 267 268 RecordKeeper &Records; 269 llvm::StringMap<uint64_t> EltTypes; 270 llvm::StringMap<uint64_t> MemEltTypes; 271 llvm::StringMap<uint64_t> FlagTypes; 272 llvm::StringMap<uint64_t> MergeTypes; 273 llvm::StringMap<uint64_t> ImmCheckTypes; 274 275 public: 276 SVEEmitter(RecordKeeper &R) : Records(R) { 277 for (auto *RV : Records.getAllDerivedDefinitions("EltType")) 278 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 279 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType")) 280 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 281 for (auto *RV : Records.getAllDerivedDefinitions("FlagType")) 282 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 283 for (auto *RV : Records.getAllDerivedDefinitions("MergeType")) 284 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 285 for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType")) 286 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 287 } 288 289 /// Returns the enum value for the immcheck type 290 unsigned getEnumValueForImmCheck(StringRef C) const { 291 auto It = ImmCheckTypes.find(C); 292 if (It != ImmCheckTypes.end()) 293 return It->getValue(); 294 llvm_unreachable("Unsupported imm check"); 295 } 296 297 /// Returns the enum value for the flag type 298 uint64_t getEnumValueForFlag(StringRef C) const { 299 auto Res = FlagTypes.find(C); 300 if (Res != FlagTypes.end()) 301 return Res->getValue(); 302 llvm_unreachable("Unsupported flag"); 303 } 304 305 // Returns the SVETypeFlags for a given value and mask. 306 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const { 307 auto It = FlagTypes.find(MaskName); 308 if (It != FlagTypes.end()) { 309 uint64_t Mask = It->getValue(); 310 unsigned Shift = llvm::countr_zero(Mask); 311 assert(Shift < 64 && "Mask value produced an invalid shift value"); 312 return (V << Shift) & Mask; 313 } 314 llvm_unreachable("Unsupported flag"); 315 } 316 317 // Returns the SVETypeFlags for the given element type. 318 uint64_t encodeEltType(StringRef EltName) { 319 auto It = EltTypes.find(EltName); 320 if (It != EltTypes.end()) 321 return encodeFlag(It->getValue(), "EltTypeMask"); 322 llvm_unreachable("Unsupported EltType"); 323 } 324 325 // Returns the SVETypeFlags for the given memory element type. 326 uint64_t encodeMemoryElementType(uint64_t MT) { 327 return encodeFlag(MT, "MemEltTypeMask"); 328 } 329 330 // Returns the SVETypeFlags for the given merge type. 331 uint64_t encodeMergeType(uint64_t MT) { 332 return encodeFlag(MT, "MergeTypeMask"); 333 } 334 335 // Returns the SVETypeFlags for the given splat operand. 336 unsigned encodeSplatOperand(unsigned SplatIdx) { 337 assert(SplatIdx < 7 && "SplatIdx out of encodable range"); 338 return encodeFlag(SplatIdx + 1, "SplatOperandMask"); 339 } 340 341 // Returns the SVETypeFlags value for the given SVEType. 342 uint64_t encodeTypeFlags(const SVEType &T); 343 344 /// Emit arm_sve.h. 345 void createHeader(raw_ostream &o); 346 347 /// Emit all the __builtin prototypes and code needed by Sema. 348 void createBuiltins(raw_ostream &o); 349 350 /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 351 void createCodeGenMap(raw_ostream &o); 352 353 /// Emit all the range checks for the immediates. 354 void createRangeChecks(raw_ostream &o); 355 356 /// Create the SVETypeFlags used in CGBuiltins 357 void createTypeFlags(raw_ostream &o); 358 359 /// Emit arm_sme.h. 360 void createSMEHeader(raw_ostream &o); 361 362 /// Emit all the SME __builtin prototypes and code needed by Sema. 363 void createSMEBuiltins(raw_ostream &o); 364 365 /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 366 void createSMECodeGenMap(raw_ostream &o); 367 368 /// Emit all the range checks for the immediates. 369 void createSMERangeChecks(raw_ostream &o); 370 371 /// Create intrinsic and add it to \p Out 372 void createIntrinsic(Record *R, 373 SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out); 374 }; 375 376 } // end anonymous namespace 377 378 379 //===----------------------------------------------------------------------===// 380 // Type implementation 381 //===----------------------------------------------------------------------===// 382 383 std::string SVEType::builtin_str() const { 384 std::string S; 385 if (isVoid()) 386 return "v"; 387 388 if (isScalarPredicate()) 389 return "b"; 390 391 if (isSvcount()) 392 return "Qa"; 393 394 if (isVoidPointer()) 395 S += "v"; 396 else if (!isFloatingPoint()) 397 switch (ElementBitwidth) { 398 case 1: S += "b"; break; 399 case 8: S += "c"; break; 400 case 16: S += "s"; break; 401 case 32: S += "i"; break; 402 case 64: S += "Wi"; break; 403 case 128: S += "LLLi"; break; 404 default: llvm_unreachable("Unhandled case!"); 405 } 406 else if (isFloat()) 407 switch (ElementBitwidth) { 408 case 16: S += "h"; break; 409 case 32: S += "f"; break; 410 case 64: S += "d"; break; 411 default: llvm_unreachable("Unhandled case!"); 412 } 413 else if (isBFloat()) { 414 assert(ElementBitwidth == 16 && "Not a valid BFloat."); 415 S += "y"; 416 } 417 418 if (!isFloatingPoint()) { 419 if ((isChar() || isPointer()) && !isVoidPointer()) { 420 // Make chars and typed pointers explicitly signed. 421 if (Signed) 422 S = "S" + S; 423 else if (!Signed) 424 S = "U" + S; 425 } else if (!isVoidPointer() && !Signed) { 426 S = "U" + S; 427 } 428 } 429 430 // Constant indices are "int", but have the "constant expression" modifier. 431 if (isImmediate()) { 432 assert(!isFloat() && "fp immediates are not supported"); 433 S = "I" + S; 434 } 435 436 if (isScalar()) { 437 if (Constant) S += "C"; 438 if (Pointer) S += "*"; 439 return S; 440 } 441 442 assert(isScalableVector() && "Unsupported type"); 443 return "q" + utostr(getNumElements() * NumVectors) + S; 444 } 445 446 std::string SVEType::str() const { 447 if (isPredicatePattern()) 448 return "enum svpattern"; 449 450 if (isPrefetchOp()) 451 return "enum svprfop"; 452 453 std::string S; 454 if (Void) 455 S += "void"; 456 else { 457 if (isScalableVector() || isSvcount()) 458 S += "sv"; 459 if (!Signed && !isFloatingPoint()) 460 S += "u"; 461 462 if (Float) 463 S += "float"; 464 else if (isSvcount()) 465 S += "count"; 466 else if (isScalarPredicate() || isPredicateVector()) 467 S += "bool"; 468 else if (isBFloat()) 469 S += "bfloat"; 470 else 471 S += "int"; 472 473 if (!isScalarPredicate() && !isPredicateVector() && !isSvcount()) 474 S += utostr(ElementBitwidth); 475 if (!isScalableVector() && isVector()) 476 S += "x" + utostr(getNumElements()); 477 if (NumVectors > 1) 478 S += "x" + utostr(NumVectors); 479 if (!isScalarPredicate()) 480 S += "_t"; 481 } 482 483 if (Constant) 484 S += " const"; 485 if (Pointer) 486 S += " *"; 487 488 return S; 489 } 490 void SVEType::applyTypespec() { 491 for (char I : TS) { 492 switch (I) { 493 case 'Q': 494 Svcount = true; 495 break; 496 case 'P': 497 Predicate = true; 498 break; 499 case 'U': 500 Signed = false; 501 break; 502 case 'c': 503 ElementBitwidth = 8; 504 break; 505 case 's': 506 ElementBitwidth = 16; 507 break; 508 case 'i': 509 ElementBitwidth = 32; 510 break; 511 case 'l': 512 ElementBitwidth = 64; 513 break; 514 case 'q': 515 ElementBitwidth = 128; 516 break; 517 case 'h': 518 Float = true; 519 ElementBitwidth = 16; 520 break; 521 case 'f': 522 Float = true; 523 ElementBitwidth = 32; 524 break; 525 case 'd': 526 Float = true; 527 ElementBitwidth = 64; 528 break; 529 case 'b': 530 BFloat = true; 531 Float = false; 532 ElementBitwidth = 16; 533 break; 534 default: 535 llvm_unreachable("Unhandled type code!"); 536 } 537 } 538 assert(ElementBitwidth != ~0U && "Bad element bitwidth!"); 539 } 540 541 void SVEType::applyModifier(char Mod) { 542 switch (Mod) { 543 case '2': 544 NumVectors = 2; 545 break; 546 case '3': 547 NumVectors = 3; 548 break; 549 case '4': 550 NumVectors = 4; 551 break; 552 case 'v': 553 Void = true; 554 break; 555 case 'd': 556 DefaultType = true; 557 break; 558 case 'c': 559 Constant = true; 560 [[fallthrough]]; 561 case 'p': 562 Pointer = true; 563 Bitwidth = ElementBitwidth; 564 NumVectors = 0; 565 break; 566 case 'e': 567 Signed = false; 568 ElementBitwidth /= 2; 569 break; 570 case 'h': 571 ElementBitwidth /= 2; 572 break; 573 case 'q': 574 ElementBitwidth /= 4; 575 break; 576 case 'b': 577 Signed = false; 578 Float = false; 579 BFloat = false; 580 ElementBitwidth /= 4; 581 break; 582 case 'o': 583 ElementBitwidth *= 4; 584 break; 585 case 'P': 586 Signed = true; 587 Float = false; 588 BFloat = false; 589 Predicate = true; 590 Svcount = false; 591 Bitwidth = 16; 592 ElementBitwidth = 1; 593 break; 594 case 's': 595 case 'a': 596 Bitwidth = ElementBitwidth; 597 NumVectors = 0; 598 break; 599 case 'R': 600 ElementBitwidth /= 2; 601 NumVectors = 0; 602 break; 603 case 'r': 604 ElementBitwidth /= 4; 605 NumVectors = 0; 606 break; 607 case '@': 608 Signed = false; 609 Float = false; 610 BFloat = false; 611 ElementBitwidth /= 4; 612 NumVectors = 0; 613 break; 614 case 'K': 615 Signed = true; 616 Float = false; 617 BFloat = false; 618 Bitwidth = ElementBitwidth; 619 NumVectors = 0; 620 break; 621 case 'L': 622 Signed = false; 623 Float = false; 624 BFloat = false; 625 Bitwidth = ElementBitwidth; 626 NumVectors = 0; 627 break; 628 case 'u': 629 Predicate = false; 630 Svcount = false; 631 Signed = false; 632 Float = false; 633 BFloat = false; 634 break; 635 case 'x': 636 Predicate = false; 637 Svcount = false; 638 Signed = true; 639 Float = false; 640 BFloat = false; 641 break; 642 case 'i': 643 Predicate = false; 644 Svcount = false; 645 Float = false; 646 BFloat = false; 647 ElementBitwidth = Bitwidth = 64; 648 NumVectors = 0; 649 Signed = false; 650 Immediate = true; 651 break; 652 case 'I': 653 Predicate = false; 654 Svcount = false; 655 Float = false; 656 BFloat = false; 657 ElementBitwidth = Bitwidth = 32; 658 NumVectors = 0; 659 Signed = true; 660 Immediate = true; 661 PredicatePattern = true; 662 break; 663 case 'J': 664 Predicate = false; 665 Svcount = false; 666 Float = false; 667 BFloat = false; 668 ElementBitwidth = Bitwidth = 32; 669 NumVectors = 0; 670 Signed = true; 671 Immediate = true; 672 PrefetchOp = true; 673 break; 674 case 'k': 675 Predicate = false; 676 Svcount = false; 677 Signed = true; 678 Float = false; 679 BFloat = false; 680 ElementBitwidth = Bitwidth = 32; 681 NumVectors = 0; 682 break; 683 case 'l': 684 Predicate = false; 685 Svcount = false; 686 Signed = true; 687 Float = false; 688 BFloat = false; 689 ElementBitwidth = Bitwidth = 64; 690 NumVectors = 0; 691 break; 692 case 'm': 693 Predicate = false; 694 Svcount = false; 695 Signed = false; 696 Float = false; 697 BFloat = false; 698 ElementBitwidth = Bitwidth = 32; 699 NumVectors = 0; 700 break; 701 case 'n': 702 Predicate = false; 703 Svcount = false; 704 Signed = false; 705 Float = false; 706 BFloat = false; 707 ElementBitwidth = Bitwidth = 64; 708 NumVectors = 0; 709 break; 710 case 'w': 711 ElementBitwidth = 64; 712 break; 713 case 'j': 714 ElementBitwidth = Bitwidth = 64; 715 NumVectors = 0; 716 break; 717 case 'f': 718 Signed = false; 719 ElementBitwidth = Bitwidth = 64; 720 NumVectors = 0; 721 break; 722 case 'g': 723 Signed = false; 724 Float = false; 725 BFloat = false; 726 ElementBitwidth = 64; 727 break; 728 case 't': 729 Signed = true; 730 Float = false; 731 BFloat = false; 732 ElementBitwidth = 32; 733 break; 734 case 'z': 735 Signed = false; 736 Float = false; 737 BFloat = false; 738 ElementBitwidth = 32; 739 break; 740 case 'O': 741 Predicate = false; 742 Svcount = false; 743 Float = true; 744 ElementBitwidth = 16; 745 break; 746 case 'M': 747 Predicate = false; 748 Svcount = false; 749 Float = true; 750 BFloat = false; 751 ElementBitwidth = 32; 752 break; 753 case 'N': 754 Predicate = false; 755 Svcount = false; 756 Float = true; 757 ElementBitwidth = 64; 758 break; 759 case 'Q': 760 Constant = true; 761 Pointer = true; 762 Void = true; 763 NumVectors = 0; 764 break; 765 case 'S': 766 Constant = true; 767 Pointer = true; 768 ElementBitwidth = Bitwidth = 8; 769 NumVectors = 0; 770 Signed = true; 771 break; 772 case 'W': 773 Constant = true; 774 Pointer = true; 775 ElementBitwidth = Bitwidth = 8; 776 NumVectors = 0; 777 Signed = false; 778 break; 779 case 'T': 780 Constant = true; 781 Pointer = true; 782 ElementBitwidth = Bitwidth = 16; 783 NumVectors = 0; 784 Signed = true; 785 break; 786 case 'X': 787 Constant = true; 788 Pointer = true; 789 ElementBitwidth = Bitwidth = 16; 790 NumVectors = 0; 791 Signed = false; 792 break; 793 case 'Y': 794 Constant = true; 795 Pointer = true; 796 ElementBitwidth = Bitwidth = 32; 797 NumVectors = 0; 798 Signed = false; 799 break; 800 case 'U': 801 Constant = true; 802 Pointer = true; 803 ElementBitwidth = Bitwidth = 32; 804 NumVectors = 0; 805 Signed = true; 806 break; 807 case '%': 808 Pointer = true; 809 Void = true; 810 NumVectors = 0; 811 break; 812 case 'A': 813 Pointer = true; 814 ElementBitwidth = Bitwidth = 8; 815 NumVectors = 0; 816 Signed = true; 817 break; 818 case 'B': 819 Pointer = true; 820 ElementBitwidth = Bitwidth = 16; 821 NumVectors = 0; 822 Signed = true; 823 break; 824 case 'C': 825 Pointer = true; 826 ElementBitwidth = Bitwidth = 32; 827 NumVectors = 0; 828 Signed = true; 829 break; 830 case 'D': 831 Pointer = true; 832 ElementBitwidth = Bitwidth = 64; 833 NumVectors = 0; 834 Signed = true; 835 break; 836 case 'E': 837 Pointer = true; 838 ElementBitwidth = Bitwidth = 8; 839 NumVectors = 0; 840 Signed = false; 841 break; 842 case 'F': 843 Pointer = true; 844 ElementBitwidth = Bitwidth = 16; 845 NumVectors = 0; 846 Signed = false; 847 break; 848 case 'G': 849 Pointer = true; 850 ElementBitwidth = Bitwidth = 32; 851 NumVectors = 0; 852 Signed = false; 853 break; 854 case '}': 855 Predicate = false; 856 Signed = true; 857 Svcount = true; 858 NumVectors = 0; 859 Float = false; 860 BFloat = false; 861 break; 862 default: 863 llvm_unreachable("Unhandled character!"); 864 } 865 } 866 867 868 //===----------------------------------------------------------------------===// 869 // Intrinsic implementation 870 //===----------------------------------------------------------------------===// 871 872 Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, 873 StringRef MergeSuffix, uint64_t MemoryElementTy, 874 StringRef LLVMName, uint64_t Flags, 875 ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class, 876 SVEEmitter &Emitter, StringRef Guard) 877 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), 878 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), 879 MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags), 880 ImmChecks(Checks.begin(), Checks.end()) { 881 // Types[0] is the return value. 882 for (unsigned I = 0; I < Proto.size(); ++I) { 883 SVEType T(BaseTypeSpec, Proto[I]); 884 Types.push_back(T); 885 886 // Add range checks for immediates 887 if (I > 0) { 888 if (T.isPredicatePattern()) 889 ImmChecks.emplace_back( 890 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31")); 891 else if (T.isPrefetchOp()) 892 ImmChecks.emplace_back( 893 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13")); 894 } 895 } 896 897 // Set flags based on properties 898 this->Flags |= Emitter.encodeTypeFlags(BaseType); 899 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy); 900 this->Flags |= Emitter.encodeMergeType(MergeTy); 901 if (hasSplat()) 902 this->Flags |= Emitter.encodeSplatOperand(getSplatIdx()); 903 } 904 905 std::string Intrinsic::getBuiltinTypeStr() { 906 std::string S = getReturnType().builtin_str(); 907 for (unsigned I = 0; I < getNumParams(); ++I) 908 S += getParamType(I).builtin_str(); 909 910 return S; 911 } 912 913 std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, 914 std::string Proto) const { 915 std::string Ret = Name; 916 while (Ret.find('{') != std::string::npos) { 917 size_t Pos = Ret.find('{'); 918 size_t End = Ret.find('}'); 919 unsigned NumChars = End - Pos + 1; 920 assert(NumChars == 3 && "Unexpected template argument"); 921 922 SVEType T; 923 char C = Ret[Pos+1]; 924 switch(C) { 925 default: 926 llvm_unreachable("Unknown predication specifier"); 927 case 'd': 928 T = SVEType(TS, 'd'); 929 break; 930 case '0': 931 case '1': 932 case '2': 933 case '3': 934 T = SVEType(TS, Proto[C - '0']); 935 break; 936 } 937 938 // Replace templated arg with the right suffix (e.g. u32) 939 std::string TypeCode; 940 if (T.isInteger()) 941 TypeCode = T.isSigned() ? 's' : 'u'; 942 else if (T.isSvcount()) 943 TypeCode = 'c'; 944 else if (T.isPredicateVector()) 945 TypeCode = 'b'; 946 else if (T.isBFloat()) 947 TypeCode = "bf"; 948 else 949 TypeCode = 'f'; 950 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits())); 951 } 952 953 return Ret; 954 } 955 956 std::string Intrinsic::mangleLLVMName() const { 957 std::string S = getLLVMName(); 958 959 // Replace all {d} like expressions with e.g. 'u32' 960 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()); 961 } 962 963 std::string Intrinsic::mangleName(ClassKind LocalCK) const { 964 std::string S = getName(); 965 966 if (LocalCK == ClassG) { 967 // Remove the square brackets and everything in between. 968 while (S.find('[') != std::string::npos) { 969 auto Start = S.find('['); 970 auto End = S.find(']'); 971 S.erase(Start, (End-Start)+1); 972 } 973 } else { 974 // Remove the square brackets. 975 while (S.find('[') != std::string::npos) { 976 auto BrPos = S.find('['); 977 if (BrPos != std::string::npos) 978 S.erase(BrPos, 1); 979 BrPos = S.find(']'); 980 if (BrPos != std::string::npos) 981 S.erase(BrPos, 1); 982 } 983 } 984 985 // Replace all {d} like expressions with e.g. 'u32' 986 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) + 987 getMergeSuffix(); 988 } 989 990 void Intrinsic::emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter) const { 991 bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1; 992 993 std::string FullName = mangleName(ClassS); 994 std::string ProtoName = mangleName(getClassKind()); 995 std::string SMEAttrs = ""; 996 997 if (Flags & Emitter.getEnumValueForFlag("IsStreaming")) 998 SMEAttrs += ", arm_streaming"; 999 if (Flags & Emitter.getEnumValueForFlag("IsStreamingCompatible")) 1000 SMEAttrs += ", arm_streaming_compatible"; 1001 if (Flags & Emitter.getEnumValueForFlag("IsSharedZA")) 1002 SMEAttrs += ", arm_shared_za"; 1003 if (Flags & Emitter.getEnumValueForFlag("IsPreservesZA")) 1004 SMEAttrs += ", arm_preserves_za"; 1005 1006 OS << (IsOverloaded ? "__aio " : "__ai ") 1007 << "__attribute__((__clang_arm_builtin_alias(" 1008 << (SMEAttrs.empty() ? "__builtin_sve_" : "__builtin_sme_") 1009 << FullName << ")"; 1010 if (!SMEAttrs.empty()) 1011 OS << SMEAttrs; 1012 OS << "))\n"; 1013 1014 OS << getTypes()[0].str() << " " << ProtoName << "("; 1015 for (unsigned I = 0; I < getTypes().size() - 1; ++I) { 1016 if (I != 0) 1017 OS << ", "; 1018 OS << getTypes()[I + 1].str(); 1019 } 1020 OS << ");\n"; 1021 } 1022 1023 //===----------------------------------------------------------------------===// 1024 // SVEEmitter implementation 1025 //===----------------------------------------------------------------------===// 1026 uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) { 1027 if (T.isFloat()) { 1028 switch (T.getElementSizeInBits()) { 1029 case 16: 1030 return encodeEltType("EltTyFloat16"); 1031 case 32: 1032 return encodeEltType("EltTyFloat32"); 1033 case 64: 1034 return encodeEltType("EltTyFloat64"); 1035 default: 1036 llvm_unreachable("Unhandled float element bitwidth!"); 1037 } 1038 } 1039 1040 if (T.isBFloat()) { 1041 assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat."); 1042 return encodeEltType("EltTyBFloat16"); 1043 } 1044 1045 if (T.isPredicateVector() || T.isSvcount()) { 1046 switch (T.getElementSizeInBits()) { 1047 case 8: 1048 return encodeEltType("EltTyBool8"); 1049 case 16: 1050 return encodeEltType("EltTyBool16"); 1051 case 32: 1052 return encodeEltType("EltTyBool32"); 1053 case 64: 1054 return encodeEltType("EltTyBool64"); 1055 default: 1056 llvm_unreachable("Unhandled predicate element bitwidth!"); 1057 } 1058 } 1059 1060 switch (T.getElementSizeInBits()) { 1061 case 8: 1062 return encodeEltType("EltTyInt8"); 1063 case 16: 1064 return encodeEltType("EltTyInt16"); 1065 case 32: 1066 return encodeEltType("EltTyInt32"); 1067 case 64: 1068 return encodeEltType("EltTyInt64"); 1069 case 128: 1070 return encodeEltType("EltTyInt128"); 1071 default: 1072 llvm_unreachable("Unhandled integer element bitwidth!"); 1073 } 1074 } 1075 1076 void SVEEmitter::createIntrinsic( 1077 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) { 1078 StringRef Name = R->getValueAsString("Name"); 1079 StringRef Proto = R->getValueAsString("Prototype"); 1080 StringRef Types = R->getValueAsString("Types"); 1081 StringRef Guard = R->getValueAsString("TargetGuard"); 1082 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic"); 1083 uint64_t Merge = R->getValueAsInt("Merge"); 1084 StringRef MergeSuffix = R->getValueAsString("MergeSuffix"); 1085 uint64_t MemEltType = R->getValueAsInt("MemEltType"); 1086 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags"); 1087 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks"); 1088 1089 int64_t Flags = 0; 1090 for (auto FlagRec : FlagsList) 1091 Flags |= FlagRec->getValueAsInt("Value"); 1092 1093 // Create a dummy TypeSpec for non-overloaded builtins. 1094 if (Types.empty()) { 1095 assert((Flags & getEnumValueForFlag("IsOverloadNone")) && 1096 "Expect TypeSpec for overloaded builtin!"); 1097 Types = "i"; 1098 } 1099 1100 // Extract type specs from string 1101 SmallVector<TypeSpec, 8> TypeSpecs; 1102 TypeSpec Acc; 1103 for (char I : Types) { 1104 Acc.push_back(I); 1105 if (islower(I)) { 1106 TypeSpecs.push_back(TypeSpec(Acc)); 1107 Acc.clear(); 1108 } 1109 } 1110 1111 // Remove duplicate type specs. 1112 llvm::sort(TypeSpecs); 1113 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()), 1114 TypeSpecs.end()); 1115 1116 // Create an Intrinsic for each type spec. 1117 for (auto TS : TypeSpecs) { 1118 // Collate a list of range/option checks for the immediates. 1119 SmallVector<ImmCheck, 2> ImmChecks; 1120 for (auto *R : ImmCheckList) { 1121 int64_t Arg = R->getValueAsInt("Arg"); 1122 int64_t EltSizeArg = R->getValueAsInt("EltSizeArg"); 1123 int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value"); 1124 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative"); 1125 1126 unsigned ElementSizeInBits = 0; 1127 if (EltSizeArg >= 0) 1128 ElementSizeInBits = 1129 SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1]) 1130 .getElementSizeInBits(); 1131 ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits)); 1132 } 1133 1134 Out.push_back(std::make_unique<Intrinsic>( 1135 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks, 1136 TS, ClassS, *this, Guard)); 1137 1138 // Also generate the short-form (e.g. svadd_m) for the given type-spec. 1139 if (Intrinsic::isOverloadedIntrinsic(Name)) 1140 Out.push_back(std::make_unique<Intrinsic>( 1141 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, 1142 ImmChecks, TS, ClassG, *this, Guard)); 1143 } 1144 } 1145 1146 void SVEEmitter::createHeader(raw_ostream &OS) { 1147 OS << "/*===---- arm_sve.h - ARM SVE intrinsics " 1148 "-----------------------------------===\n" 1149 " *\n" 1150 " *\n" 1151 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 1152 "Exceptions.\n" 1153 " * See https://llvm.org/LICENSE.txt for license information.\n" 1154 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 1155 " *\n" 1156 " *===-----------------------------------------------------------------" 1157 "------===\n" 1158 " */\n\n"; 1159 1160 OS << "#ifndef __ARM_SVE_H\n"; 1161 OS << "#define __ARM_SVE_H\n\n"; 1162 1163 OS << "#if !defined(__LITTLE_ENDIAN__)\n"; 1164 OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n"; 1165 OS << "#endif\n"; 1166 1167 OS << "#include <stdint.h>\n\n"; 1168 OS << "#ifdef __cplusplus\n"; 1169 OS << "extern \"C\" {\n"; 1170 OS << "#else\n"; 1171 OS << "#include <stdbool.h>\n"; 1172 OS << "#endif\n\n"; 1173 1174 OS << "typedef __fp16 float16_t;\n"; 1175 OS << "typedef float float32_t;\n"; 1176 OS << "typedef double float64_t;\n"; 1177 1178 OS << "typedef __SVInt8_t svint8_t;\n"; 1179 OS << "typedef __SVInt16_t svint16_t;\n"; 1180 OS << "typedef __SVInt32_t svint32_t;\n"; 1181 OS << "typedef __SVInt64_t svint64_t;\n"; 1182 OS << "typedef __SVUint8_t svuint8_t;\n"; 1183 OS << "typedef __SVUint16_t svuint16_t;\n"; 1184 OS << "typedef __SVUint32_t svuint32_t;\n"; 1185 OS << "typedef __SVUint64_t svuint64_t;\n"; 1186 OS << "typedef __SVFloat16_t svfloat16_t;\n\n"; 1187 1188 OS << "typedef __SVBFloat16_t svbfloat16_t;\n"; 1189 1190 OS << "#include <arm_bf16.h>\n"; 1191 1192 OS << "typedef __SVFloat32_t svfloat32_t;\n"; 1193 OS << "typedef __SVFloat64_t svfloat64_t;\n"; 1194 OS << "typedef __clang_svint8x2_t svint8x2_t;\n"; 1195 OS << "typedef __clang_svint16x2_t svint16x2_t;\n"; 1196 OS << "typedef __clang_svint32x2_t svint32x2_t;\n"; 1197 OS << "typedef __clang_svint64x2_t svint64x2_t;\n"; 1198 OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n"; 1199 OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n"; 1200 OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n"; 1201 OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n"; 1202 OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n"; 1203 OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n"; 1204 OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n"; 1205 OS << "typedef __clang_svint8x3_t svint8x3_t;\n"; 1206 OS << "typedef __clang_svint16x3_t svint16x3_t;\n"; 1207 OS << "typedef __clang_svint32x3_t svint32x3_t;\n"; 1208 OS << "typedef __clang_svint64x3_t svint64x3_t;\n"; 1209 OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n"; 1210 OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n"; 1211 OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n"; 1212 OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n"; 1213 OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n"; 1214 OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n"; 1215 OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n"; 1216 OS << "typedef __clang_svint8x4_t svint8x4_t;\n"; 1217 OS << "typedef __clang_svint16x4_t svint16x4_t;\n"; 1218 OS << "typedef __clang_svint32x4_t svint32x4_t;\n"; 1219 OS << "typedef __clang_svint64x4_t svint64x4_t;\n"; 1220 OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n"; 1221 OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n"; 1222 OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n"; 1223 OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n"; 1224 OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n"; 1225 OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n"; 1226 OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n"; 1227 OS << "typedef __SVBool_t svbool_t;\n"; 1228 OS << "typedef __clang_svboolx2_t svboolx2_t;\n"; 1229 OS << "typedef __clang_svboolx4_t svboolx4_t;\n\n"; 1230 1231 OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n"; 1232 OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n"; 1233 OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n"; 1234 1235 OS << "typedef __SVCount_t svcount_t;\n\n"; 1236 1237 OS << "enum svpattern\n"; 1238 OS << "{\n"; 1239 OS << " SV_POW2 = 0,\n"; 1240 OS << " SV_VL1 = 1,\n"; 1241 OS << " SV_VL2 = 2,\n"; 1242 OS << " SV_VL3 = 3,\n"; 1243 OS << " SV_VL4 = 4,\n"; 1244 OS << " SV_VL5 = 5,\n"; 1245 OS << " SV_VL6 = 6,\n"; 1246 OS << " SV_VL7 = 7,\n"; 1247 OS << " SV_VL8 = 8,\n"; 1248 OS << " SV_VL16 = 9,\n"; 1249 OS << " SV_VL32 = 10,\n"; 1250 OS << " SV_VL64 = 11,\n"; 1251 OS << " SV_VL128 = 12,\n"; 1252 OS << " SV_VL256 = 13,\n"; 1253 OS << " SV_MUL4 = 29,\n"; 1254 OS << " SV_MUL3 = 30,\n"; 1255 OS << " SV_ALL = 31\n"; 1256 OS << "};\n\n"; 1257 1258 OS << "enum svprfop\n"; 1259 OS << "{\n"; 1260 OS << " SV_PLDL1KEEP = 0,\n"; 1261 OS << " SV_PLDL1STRM = 1,\n"; 1262 OS << " SV_PLDL2KEEP = 2,\n"; 1263 OS << " SV_PLDL2STRM = 3,\n"; 1264 OS << " SV_PLDL3KEEP = 4,\n"; 1265 OS << " SV_PLDL3STRM = 5,\n"; 1266 OS << " SV_PSTL1KEEP = 8,\n"; 1267 OS << " SV_PSTL1STRM = 9,\n"; 1268 OS << " SV_PSTL2KEEP = 10,\n"; 1269 OS << " SV_PSTL2STRM = 11,\n"; 1270 OS << " SV_PSTL3KEEP = 12,\n"; 1271 OS << " SV_PSTL3STRM = 13\n"; 1272 OS << "};\n\n"; 1273 1274 OS << "/* Function attributes */\n"; 1275 OS << "#define __ai static __inline__ __attribute__((__always_inline__, " 1276 "__nodebug__))\n\n"; 1277 OS << "#define __aio static __inline__ __attribute__((__always_inline__, " 1278 "__nodebug__, __overloadable__))\n\n"; 1279 1280 // Add reinterpret functions. 1281 for (auto ShortForm : { false, true } ) 1282 for (const ReinterpretTypeInfo &From : Reinterprets) 1283 for (const ReinterpretTypeInfo &To : Reinterprets) { 1284 if (ShortForm) { 1285 OS << "__aio __attribute__((target(\"sve\"))) " << From.Type 1286 << " svreinterpret_" << From.Suffix; 1287 OS << "(" << To.Type << " op) {\n"; 1288 OS << " return __builtin_sve_reinterpret_" << From.Suffix << "_" 1289 << To.Suffix << "(op);\n"; 1290 OS << "}\n\n"; 1291 } else 1292 OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix 1293 << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_" 1294 << To.Suffix << "(__VA_ARGS__)\n"; 1295 } 1296 1297 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1298 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1299 for (auto *R : RV) 1300 createIntrinsic(R, Defs); 1301 1302 // Sort intrinsics in header file by following order/priority: 1303 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES) 1304 // - Class (is intrinsic overloaded or not) 1305 // - Intrinsic name 1306 std::stable_sort( 1307 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A, 1308 const std::unique_ptr<Intrinsic> &B) { 1309 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) { 1310 return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName()); 1311 }; 1312 return ToTuple(A) < ToTuple(B); 1313 }); 1314 1315 // Actually emit the intrinsic declarations. 1316 for (auto &I : Defs) 1317 I->emitIntrinsic(OS, *this); 1318 1319 OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n"; 1320 OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n"; 1321 1322 OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n"; 1323 OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n"; 1324 OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n"; 1325 OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n"; 1326 1327 OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n"; 1328 OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n"; 1329 1330 OS << "#ifdef __cplusplus\n"; 1331 OS << "} // extern \"C\"\n"; 1332 OS << "#endif\n\n"; 1333 OS << "#undef __ai\n\n"; 1334 OS << "#undef __aio\n\n"; 1335 OS << "#endif /* __ARM_SVE_H */\n"; 1336 } 1337 1338 void SVEEmitter::createBuiltins(raw_ostream &OS) { 1339 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1340 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1341 for (auto *R : RV) 1342 createIntrinsic(R, Defs); 1343 1344 // The mappings must be sorted based on BuiltinID. 1345 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1346 const std::unique_ptr<Intrinsic> &B) { 1347 return A->getMangledName() < B->getMangledName(); 1348 }); 1349 1350 OS << "#ifdef GET_SVE_BUILTINS\n"; 1351 for (auto &Def : Defs) { 1352 // Only create BUILTINs for non-overloaded intrinsics, as overloaded 1353 // declarations only live in the header file. 1354 if (Def->getClassKind() != ClassG) 1355 OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \"" 1356 << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard() 1357 << "\")\n"; 1358 } 1359 1360 // Add reinterpret builtins 1361 for (const ReinterpretTypeInfo &From : Reinterprets) 1362 for (const ReinterpretTypeInfo &To : Reinterprets) 1363 OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_" 1364 << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType 1365 << "\", \"n\", \"sve\")\n"; 1366 1367 OS << "#endif\n\n"; 1368 } 1369 1370 void SVEEmitter::createCodeGenMap(raw_ostream &OS) { 1371 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1372 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1373 for (auto *R : RV) 1374 createIntrinsic(R, Defs); 1375 1376 // The mappings must be sorted based on BuiltinID. 1377 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1378 const std::unique_ptr<Intrinsic> &B) { 1379 return A->getMangledName() < B->getMangledName(); 1380 }); 1381 1382 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n"; 1383 for (auto &Def : Defs) { 1384 // Builtins only exist for non-overloaded intrinsics, overloaded 1385 // declarations only live in the header file. 1386 if (Def->getClassKind() == ClassG) 1387 continue; 1388 1389 uint64_t Flags = Def->getFlags(); 1390 auto FlagString = std::to_string(Flags); 1391 1392 std::string LLVMName = Def->getMangledLLVMName(); 1393 std::string Builtin = Def->getMangledName(); 1394 if (!LLVMName.empty()) 1395 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString 1396 << "),\n"; 1397 else 1398 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n"; 1399 } 1400 OS << "#endif\n\n"; 1401 } 1402 1403 void SVEEmitter::createRangeChecks(raw_ostream &OS) { 1404 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1405 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1406 for (auto *R : RV) 1407 createIntrinsic(R, Defs); 1408 1409 // The mappings must be sorted based on BuiltinID. 1410 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1411 const std::unique_ptr<Intrinsic> &B) { 1412 return A->getMangledName() < B->getMangledName(); 1413 }); 1414 1415 1416 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n"; 1417 1418 // Ensure these are only emitted once. 1419 std::set<std::string> Emitted; 1420 1421 for (auto &Def : Defs) { 1422 if (Emitted.find(Def->getMangledName()) != Emitted.end() || 1423 Def->getImmChecks().empty()) 1424 continue; 1425 1426 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n"; 1427 for (auto &Check : Def->getImmChecks()) 1428 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", " 1429 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n"; 1430 OS << " break;\n"; 1431 1432 Emitted.insert(Def->getMangledName()); 1433 } 1434 1435 OS << "#endif\n\n"; 1436 } 1437 1438 /// Create the SVETypeFlags used in CGBuiltins 1439 void SVEEmitter::createTypeFlags(raw_ostream &OS) { 1440 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n"; 1441 for (auto &KV : FlagTypes) 1442 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n"; 1443 OS << "#endif\n\n"; 1444 1445 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n"; 1446 for (auto &KV : EltTypes) 1447 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1448 OS << "#endif\n\n"; 1449 1450 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n"; 1451 for (auto &KV : MemEltTypes) 1452 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1453 OS << "#endif\n\n"; 1454 1455 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n"; 1456 for (auto &KV : MergeTypes) 1457 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1458 OS << "#endif\n\n"; 1459 1460 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n"; 1461 for (auto &KV : ImmCheckTypes) 1462 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1463 OS << "#endif\n\n"; 1464 } 1465 1466 void SVEEmitter::createSMEHeader(raw_ostream &OS) { 1467 OS << "/*===---- arm_sme_draft_spec_subject_to_change.h - ARM SME intrinsics " 1468 "------===\n" 1469 " *\n" 1470 " *\n" 1471 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 1472 "Exceptions.\n" 1473 " * See https://llvm.org/LICENSE.txt for license information.\n" 1474 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 1475 " *\n" 1476 " *===-----------------------------------------------------------------" 1477 "------===\n" 1478 " */\n\n"; 1479 1480 OS << "#ifndef __ARM_SME_H\n"; 1481 OS << "#define __ARM_SME_H\n\n"; 1482 1483 OS << "#if !defined(__LITTLE_ENDIAN__)\n"; 1484 OS << "#error \"Big endian is currently not supported for arm_sme_draft_spec_subject_to_change.h\"\n"; 1485 OS << "#endif\n"; 1486 1487 OS << "#include <arm_sve.h> \n\n"; 1488 1489 OS << "/* Function attributes */\n"; 1490 OS << "#define __ai static __inline__ __attribute__((__always_inline__, " 1491 "__nodebug__))\n\n"; 1492 OS << "#define __aio static __inline__ __attribute__((__always_inline__, " 1493 "__nodebug__, __overloadable__))\n\n"; 1494 1495 OS << "#ifdef __cplusplus\n"; 1496 OS << "extern \"C\" {\n"; 1497 OS << "#endif\n\n"; 1498 1499 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1500 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1501 for (auto *R : RV) 1502 createIntrinsic(R, Defs); 1503 1504 // Sort intrinsics in header file by following order/priority similar to SVE: 1505 // - Architectural guard 1506 // - Class (is intrinsic overloaded or not) 1507 // - Intrinsic name 1508 std::stable_sort(Defs.begin(), Defs.end(), 1509 [](const std::unique_ptr<Intrinsic> &A, 1510 const std::unique_ptr<Intrinsic> &B) { 1511 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) { 1512 return std::make_tuple(I->getGuard(), 1513 (unsigned)I->getClassKind(), 1514 I->getName()); 1515 }; 1516 return ToTuple(A) < ToTuple(B); 1517 }); 1518 1519 // Actually emit the intrinsic declaration. 1520 for (auto &I : Defs) { 1521 I->emitIntrinsic(OS, *this); 1522 } 1523 1524 OS << "#ifdef __cplusplus\n"; 1525 OS << "} // extern \"C\"\n"; 1526 OS << "#endif\n\n"; 1527 OS << "#undef __ai\n\n"; 1528 OS << "#endif /* __ARM_SME_H */\n"; 1529 } 1530 1531 void SVEEmitter::createSMEBuiltins(raw_ostream &OS) { 1532 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1533 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1534 for (auto *R : RV) { 1535 createIntrinsic(R, Defs); 1536 } 1537 1538 // The mappings must be sorted based on BuiltinID. 1539 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1540 const std::unique_ptr<Intrinsic> &B) { 1541 return A->getMangledName() < B->getMangledName(); 1542 }); 1543 1544 OS << "#ifdef GET_SME_BUILTINS\n"; 1545 for (auto &Def : Defs) { 1546 // Only create BUILTINs for non-overloaded intrinsics, as overloaded 1547 // declarations only live in the header file. 1548 if (Def->getClassKind() != ClassG) 1549 OS << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \"" 1550 << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard() 1551 << "\")\n"; 1552 } 1553 1554 OS << "#endif\n\n"; 1555 } 1556 1557 void SVEEmitter::createSMECodeGenMap(raw_ostream &OS) { 1558 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1559 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1560 for (auto *R : RV) { 1561 createIntrinsic(R, Defs); 1562 } 1563 1564 // The mappings must be sorted based on BuiltinID. 1565 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1566 const std::unique_ptr<Intrinsic> &B) { 1567 return A->getMangledName() < B->getMangledName(); 1568 }); 1569 1570 OS << "#ifdef GET_SME_LLVM_INTRINSIC_MAP\n"; 1571 for (auto &Def : Defs) { 1572 // Builtins only exist for non-overloaded intrinsics, overloaded 1573 // declarations only live in the header file. 1574 if (Def->getClassKind() == ClassG) 1575 continue; 1576 1577 uint64_t Flags = Def->getFlags(); 1578 auto FlagString = std::to_string(Flags); 1579 1580 std::string LLVMName = Def->getLLVMName(); 1581 std::string Builtin = Def->getMangledName(); 1582 if (!LLVMName.empty()) 1583 OS << "SMEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString 1584 << "),\n"; 1585 else 1586 OS << "SMEMAP2(" << Builtin << ", " << FlagString << "),\n"; 1587 } 1588 OS << "#endif\n\n"; 1589 } 1590 1591 void SVEEmitter::createSMERangeChecks(raw_ostream &OS) { 1592 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1593 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1594 for (auto *R : RV) { 1595 createIntrinsic(R, Defs); 1596 } 1597 1598 // The mappings must be sorted based on BuiltinID. 1599 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1600 const std::unique_ptr<Intrinsic> &B) { 1601 return A->getMangledName() < B->getMangledName(); 1602 }); 1603 1604 1605 OS << "#ifdef GET_SME_IMMEDIATE_CHECK\n"; 1606 1607 // Ensure these are only emitted once. 1608 std::set<std::string> Emitted; 1609 1610 for (auto &Def : Defs) { 1611 if (Emitted.find(Def->getMangledName()) != Emitted.end() || 1612 Def->getImmChecks().empty()) 1613 continue; 1614 1615 OS << "case SME::BI__builtin_sme_" << Def->getMangledName() << ":\n"; 1616 for (auto &Check : Def->getImmChecks()) 1617 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", " 1618 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n"; 1619 OS << " break;\n"; 1620 1621 Emitted.insert(Def->getMangledName()); 1622 } 1623 1624 OS << "#endif\n\n"; 1625 } 1626 1627 namespace clang { 1628 void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) { 1629 SVEEmitter(Records).createHeader(OS); 1630 } 1631 1632 void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1633 SVEEmitter(Records).createBuiltins(OS); 1634 } 1635 1636 void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1637 SVEEmitter(Records).createCodeGenMap(OS); 1638 } 1639 1640 void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) { 1641 SVEEmitter(Records).createRangeChecks(OS); 1642 } 1643 1644 void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) { 1645 SVEEmitter(Records).createTypeFlags(OS); 1646 } 1647 1648 void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) { 1649 SVEEmitter(Records).createSMEHeader(OS); 1650 } 1651 1652 void EmitSmeBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1653 SVEEmitter(Records).createSMEBuiltins(OS); 1654 } 1655 1656 void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1657 SVEEmitter(Records).createSMECodeGenMap(OS); 1658 } 1659 1660 void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) { 1661 SVEEmitter(Records).createSMERangeChecks(OS); 1662 } 1663 } // End namespace clang 1664