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; 69 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp; 70 unsigned Bitwidth, ElementBitwidth, NumVectors; 71 72 public: 73 SVEType() : SVEType(TypeSpec(), 'v') {} 74 75 SVEType(TypeSpec TS, char CharMod) 76 : TS(TS), Float(false), Signed(true), Immediate(false), Void(false), 77 Constant(false), Pointer(false), DefaultType(false), IsScalable(true), 78 Predicate(false), PredicatePattern(false), PrefetchOp(false), 79 Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) { 80 if (!TS.empty()) 81 applyTypespec(); 82 applyModifier(CharMod); 83 } 84 85 bool isPointer() const { return Pointer; } 86 bool isVoidPointer() const { return Pointer && Void; } 87 bool isSigned() const { return Signed; } 88 bool isImmediate() const { return Immediate; } 89 bool isScalar() const { return NumVectors == 0; } 90 bool isVector() const { return NumVectors > 0; } 91 bool isScalableVector() const { return isVector() && IsScalable; } 92 bool isChar() const { return ElementBitwidth == 8; } 93 bool isVoid() const { return Void & !Pointer; } 94 bool isDefault() const { return DefaultType; } 95 bool isFloat() const { return Float; } 96 bool isInteger() const { return !Float && !Predicate; } 97 bool isScalarPredicate() const { 98 return !Float && Predicate && NumVectors == 0; 99 } 100 bool isPredicateVector() const { return Predicate; } 101 bool isPredicatePattern() const { return PredicatePattern; } 102 bool isPrefetchOp() const { return PrefetchOp; } 103 bool isConstant() const { return Constant; } 104 unsigned getElementSizeInBits() const { return ElementBitwidth; } 105 unsigned getNumVectors() const { return NumVectors; } 106 107 unsigned getNumElements() const { 108 assert(ElementBitwidth != ~0U); 109 return Bitwidth / ElementBitwidth; 110 } 111 unsigned getSizeInBits() const { 112 return Bitwidth; 113 } 114 115 /// Return the string representation of a type, which is an encoded 116 /// string for passing to the BUILTIN() macro in Builtins.def. 117 std::string builtin_str() const; 118 119 /// Return the C/C++ string representation of a type for use in the 120 /// arm_sve.h header file. 121 std::string str() const; 122 123 private: 124 /// Creates the type based on the typespec string in TS. 125 void applyTypespec(); 126 127 /// Applies a prototype modifier to the type. 128 void applyModifier(char Mod); 129 }; 130 131 132 class SVEEmitter; 133 134 /// The main grunt class. This represents an instantiation of an intrinsic with 135 /// a particular typespec and prototype. 136 class Intrinsic { 137 /// The unmangled name. 138 std::string Name; 139 140 /// The name of the corresponding LLVM IR intrinsic. 141 std::string LLVMName; 142 143 /// Intrinsic prototype. 144 std::string Proto; 145 146 /// The base type spec for this intrinsic. 147 TypeSpec BaseTypeSpec; 148 149 /// The base class kind. Most intrinsics use ClassS, which has full type 150 /// info for integers (_s32/_u32), or ClassG which is used for overloaded 151 /// intrinsics. 152 ClassKind Class; 153 154 /// The architectural #ifdef guard. 155 std::string Guard; 156 157 // The merge suffix such as _m, _x or _z. 158 std::string MergeSuffix; 159 160 /// The types of return value [0] and parameters [1..]. 161 std::vector<SVEType> Types; 162 163 /// The "base type", which is VarType('d', BaseTypeSpec). 164 SVEType BaseType; 165 166 uint64_t Flags; 167 168 SmallVector<ImmCheck, 2> ImmChecks; 169 170 public: 171 Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, 172 StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName, 173 uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT, 174 ClassKind Class, SVEEmitter &Emitter, StringRef Guard); 175 176 ~Intrinsic()=default; 177 178 std::string getName() const { return Name; } 179 std::string getLLVMName() const { return LLVMName; } 180 std::string getProto() const { return Proto; } 181 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; } 182 SVEType getBaseType() const { return BaseType; } 183 184 StringRef getGuard() const { return Guard; } 185 ClassKind getClassKind() const { return Class; } 186 187 SVEType getReturnType() const { return Types[0]; } 188 ArrayRef<SVEType> getTypes() const { return Types; } 189 SVEType getParamType(unsigned I) const { return Types[I + 1]; } 190 unsigned getNumParams() const { return Proto.size() - 1; } 191 192 uint64_t getFlags() const { return Flags; } 193 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;} 194 195 ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; } 196 197 /// Return the type string for a BUILTIN() macro in Builtins.def. 198 std::string getBuiltinTypeStr(); 199 200 /// Return the name, mangled with type information. The name is mangled for 201 /// ClassS, so will add type suffixes such as _u32/_s32. 202 std::string getMangledName() const { return mangleName(ClassS); } 203 204 /// Returns true if the intrinsic is overloaded, in that it should also generate 205 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of 206 /// 'svld1_u32(..)'. 207 static bool isOverloadedIntrinsic(StringRef Name) { 208 auto BrOpen = Name.find("["); 209 auto BrClose = Name.find(']'); 210 return BrOpen != std::string::npos && BrClose != std::string::npos; 211 } 212 213 /// Return true if the intrinsic takes a splat operand. 214 bool hasSplat() const { 215 // These prototype modifiers are described in arm_sve.td. 216 return Proto.find_first_of("ajfrKLR@") != std::string::npos; 217 } 218 219 /// Return the parameter index of the splat operand. 220 unsigned getSplatIdx() const { 221 // These prototype modifiers are described in arm_sve.td. 222 auto Idx = Proto.find_first_of("ajfrKLR@"); 223 assert(Idx != std::string::npos && Idx > 0 && 224 "Prototype has no splat operand"); 225 return Idx - 1; 226 } 227 228 /// Emits the intrinsic declaration to the ostream. 229 void emitIntrinsic(raw_ostream &OS) const; 230 231 private: 232 std::string getMergeSuffix() const { return MergeSuffix; } 233 std::string mangleName(ClassKind LocalCK) const; 234 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS, 235 std::string Proto) const; 236 }; 237 238 class SVEEmitter { 239 private: 240 // The reinterpret builtins are generated separately because they 241 // need the cross product of all types (121 functions in total), 242 // which is inconvenient to specify in the arm_sve.td file or 243 // generate in CGBuiltin.cpp. 244 struct ReinterpretTypeInfo { 245 const char *Suffix; 246 const char *Type; 247 const char *BuiltinType; 248 }; 249 SmallVector<ReinterpretTypeInfo, 11> Reinterprets = { 250 {"s8", "svint8_t", "q16Sc"}, {"s16", "svint16_t", "q8Ss"}, 251 {"s32", "svint32_t", "q4Si"}, {"s64", "svint64_t", "q2SWi"}, 252 {"u8", "svuint8_t", "q16Uc"}, {"u16", "svuint16_t", "q8Us"}, 253 {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"}, 254 {"f16", "svfloat16_t", "q8h"}, {"f32", "svfloat32_t", "q4f"}, 255 {"f64", "svfloat64_t", "q2d"}}; 256 257 RecordKeeper &Records; 258 llvm::StringMap<uint64_t> EltTypes; 259 llvm::StringMap<uint64_t> MemEltTypes; 260 llvm::StringMap<uint64_t> FlagTypes; 261 llvm::StringMap<uint64_t> MergeTypes; 262 llvm::StringMap<uint64_t> ImmCheckTypes; 263 264 public: 265 SVEEmitter(RecordKeeper &R) : Records(R) { 266 for (auto *RV : Records.getAllDerivedDefinitions("EltType")) 267 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 268 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType")) 269 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 270 for (auto *RV : Records.getAllDerivedDefinitions("FlagType")) 271 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 272 for (auto *RV : Records.getAllDerivedDefinitions("MergeType")) 273 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 274 for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType")) 275 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 276 } 277 278 /// Returns the enum value for the immcheck type 279 unsigned getEnumValueForImmCheck(StringRef C) const { 280 auto It = ImmCheckTypes.find(C); 281 if (It != ImmCheckTypes.end()) 282 return It->getValue(); 283 llvm_unreachable("Unsupported imm check"); 284 } 285 286 /// Returns the enum value for the flag type 287 uint64_t getEnumValueForFlag(StringRef C) const { 288 auto Res = FlagTypes.find(C); 289 if (Res != FlagTypes.end()) 290 return Res->getValue(); 291 llvm_unreachable("Unsupported flag"); 292 } 293 294 // Returns the SVETypeFlags for a given value and mask. 295 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const { 296 auto It = FlagTypes.find(MaskName); 297 if (It != FlagTypes.end()) { 298 uint64_t Mask = It->getValue(); 299 unsigned Shift = llvm::countTrailingZeros(Mask); 300 return (V << Shift) & Mask; 301 } 302 llvm_unreachable("Unsupported flag"); 303 } 304 305 // Returns the SVETypeFlags for the given element type. 306 uint64_t encodeEltType(StringRef EltName) { 307 auto It = EltTypes.find(EltName); 308 if (It != EltTypes.end()) 309 return encodeFlag(It->getValue(), "EltTypeMask"); 310 llvm_unreachable("Unsupported EltType"); 311 } 312 313 // Returns the SVETypeFlags for the given memory element type. 314 uint64_t encodeMemoryElementType(uint64_t MT) { 315 return encodeFlag(MT, "MemEltTypeMask"); 316 } 317 318 // Returns the SVETypeFlags for the given merge type. 319 uint64_t encodeMergeType(uint64_t MT) { 320 return encodeFlag(MT, "MergeTypeMask"); 321 } 322 323 // Returns the SVETypeFlags for the given splat operand. 324 unsigned encodeSplatOperand(unsigned SplatIdx) { 325 assert(SplatIdx < 7 && "SplatIdx out of encodable range"); 326 return encodeFlag(SplatIdx + 1, "SplatOperandMask"); 327 } 328 329 // Returns the SVETypeFlags value for the given SVEType. 330 uint64_t encodeTypeFlags(const SVEType &T); 331 332 /// Emit arm_sve.h. 333 void createHeader(raw_ostream &o); 334 335 /// Emit all the __builtin prototypes and code needed by Sema. 336 void createBuiltins(raw_ostream &o); 337 338 /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 339 void createCodeGenMap(raw_ostream &o); 340 341 /// Emit all the range checks for the immediates. 342 void createRangeChecks(raw_ostream &o); 343 344 /// Create the SVETypeFlags used in CGBuiltins 345 void createTypeFlags(raw_ostream &o); 346 347 /// Create intrinsic and add it to \p Out 348 void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out); 349 }; 350 351 } // end anonymous namespace 352 353 354 //===----------------------------------------------------------------------===// 355 // Type implementation 356 //===----------------------------------------------------------------------===// 357 358 std::string SVEType::builtin_str() const { 359 std::string S; 360 if (isVoid()) 361 return "v"; 362 363 if (isVoidPointer()) 364 S += "v"; 365 else if (!Float) 366 switch (ElementBitwidth) { 367 case 1: S += "b"; break; 368 case 8: S += "c"; break; 369 case 16: S += "s"; break; 370 case 32: S += "i"; break; 371 case 64: S += "Wi"; break; 372 case 128: S += "LLLi"; break; 373 default: llvm_unreachable("Unhandled case!"); 374 } 375 else 376 switch (ElementBitwidth) { 377 case 16: S += "h"; break; 378 case 32: S += "f"; break; 379 case 64: S += "d"; break; 380 default: llvm_unreachable("Unhandled case!"); 381 } 382 383 if (!isFloat()) { 384 if ((isChar() || isPointer()) && !isVoidPointer()) { 385 // Make chars and typed pointers explicitly signed. 386 if (Signed) 387 S = "S" + S; 388 else if (!Signed) 389 S = "U" + S; 390 } else if (!isVoidPointer() && !Signed) { 391 S = "U" + S; 392 } 393 } 394 395 // Constant indices are "int", but have the "constant expression" modifier. 396 if (isImmediate()) { 397 assert(!isFloat() && "fp immediates are not supported"); 398 S = "I" + S; 399 } 400 401 if (isScalar()) { 402 if (Constant) S += "C"; 403 if (Pointer) S += "*"; 404 return S; 405 } 406 407 assert(isScalableVector() && "Unsupported type"); 408 return "q" + utostr(getNumElements() * NumVectors) + S; 409 } 410 411 std::string SVEType::str() const { 412 if (isPredicatePattern()) 413 return "sv_pattern"; 414 415 if (isPrefetchOp()) 416 return "sv_prfop"; 417 418 std::string S; 419 if (Void) 420 S += "void"; 421 else { 422 if (isScalableVector()) 423 S += "sv"; 424 if (!Signed && !Float) 425 S += "u"; 426 427 if (Float) 428 S += "float"; 429 else if (isScalarPredicate() || isPredicateVector()) 430 S += "bool"; 431 else 432 S += "int"; 433 434 if (!isScalarPredicate() && !isPredicateVector()) 435 S += utostr(ElementBitwidth); 436 if (!isScalableVector() && isVector()) 437 S += "x" + utostr(getNumElements()); 438 if (NumVectors > 1) 439 S += "x" + utostr(NumVectors); 440 S += "_t"; 441 } 442 443 if (Constant) 444 S += " const"; 445 if (Pointer) 446 S += " *"; 447 448 return S; 449 } 450 void SVEType::applyTypespec() { 451 for (char I : TS) { 452 switch (I) { 453 case 'P': 454 Predicate = true; 455 break; 456 case 'U': 457 Signed = false; 458 break; 459 case 'c': 460 ElementBitwidth = 8; 461 break; 462 case 's': 463 ElementBitwidth = 16; 464 break; 465 case 'i': 466 ElementBitwidth = 32; 467 break; 468 case 'l': 469 ElementBitwidth = 64; 470 break; 471 case 'h': 472 Float = true; 473 ElementBitwidth = 16; 474 break; 475 case 'f': 476 Float = true; 477 ElementBitwidth = 32; 478 break; 479 case 'd': 480 Float = true; 481 ElementBitwidth = 64; 482 break; 483 default: 484 llvm_unreachable("Unhandled type code!"); 485 } 486 } 487 assert(ElementBitwidth != ~0U && "Bad element bitwidth!"); 488 } 489 490 void SVEType::applyModifier(char Mod) { 491 switch (Mod) { 492 case 'v': 493 Void = true; 494 break; 495 case 'd': 496 DefaultType = true; 497 break; 498 case 'c': 499 Constant = true; 500 LLVM_FALLTHROUGH; 501 case 'p': 502 Pointer = true; 503 Bitwidth = ElementBitwidth; 504 NumVectors = 0; 505 break; 506 case 'e': 507 Signed = false; 508 ElementBitwidth /= 2; 509 break; 510 case 'h': 511 ElementBitwidth /= 2; 512 break; 513 case 'q': 514 ElementBitwidth /= 4; 515 break; 516 case 'b': 517 Signed = false; 518 Float = false; 519 ElementBitwidth /= 4; 520 break; 521 case 'o': 522 ElementBitwidth *= 4; 523 break; 524 case 'P': 525 Signed = true; 526 Float = false; 527 Predicate = true; 528 Bitwidth = 16; 529 ElementBitwidth = 1; 530 break; 531 case 's': 532 case 'a': 533 Bitwidth = ElementBitwidth; 534 NumVectors = 0; 535 break; 536 case 'R': 537 ElementBitwidth /= 2; 538 NumVectors = 0; 539 break; 540 case 'r': 541 ElementBitwidth /= 4; 542 NumVectors = 0; 543 break; 544 case '@': 545 Signed = false; 546 Float = false; 547 ElementBitwidth /= 4; 548 NumVectors = 0; 549 break; 550 case 'K': 551 Signed = true; 552 Float = false; 553 Bitwidth = ElementBitwidth; 554 NumVectors = 0; 555 break; 556 case 'L': 557 Signed = false; 558 Float = false; 559 Bitwidth = ElementBitwidth; 560 NumVectors = 0; 561 break; 562 case 'u': 563 Predicate = false; 564 Signed = false; 565 Float = false; 566 break; 567 case 'x': 568 Predicate = false; 569 Signed = true; 570 Float = false; 571 break; 572 case 'i': 573 Predicate = false; 574 Float = false; 575 ElementBitwidth = Bitwidth = 64; 576 NumVectors = 0; 577 Signed = false; 578 Immediate = true; 579 break; 580 case 'I': 581 Predicate = false; 582 Float = false; 583 ElementBitwidth = Bitwidth = 32; 584 NumVectors = 0; 585 Signed = true; 586 Immediate = true; 587 PredicatePattern = true; 588 break; 589 case 'J': 590 Predicate = false; 591 Float = false; 592 ElementBitwidth = Bitwidth = 32; 593 NumVectors = 0; 594 Signed = true; 595 Immediate = true; 596 PrefetchOp = true; 597 break; 598 case 'k': 599 Predicate = false; 600 Signed = true; 601 Float = false; 602 ElementBitwidth = Bitwidth = 32; 603 NumVectors = 0; 604 break; 605 case 'l': 606 Predicate = false; 607 Signed = true; 608 Float = false; 609 ElementBitwidth = Bitwidth = 64; 610 NumVectors = 0; 611 break; 612 case 'm': 613 Predicate = false; 614 Signed = false; 615 Float = false; 616 ElementBitwidth = Bitwidth = 32; 617 NumVectors = 0; 618 break; 619 case 'n': 620 Predicate = false; 621 Signed = false; 622 Float = false; 623 ElementBitwidth = Bitwidth = 64; 624 NumVectors = 0; 625 break; 626 case 'w': 627 ElementBitwidth = 64; 628 break; 629 case 'j': 630 ElementBitwidth = Bitwidth = 64; 631 NumVectors = 0; 632 break; 633 case 'f': 634 Signed = false; 635 ElementBitwidth = Bitwidth = 64; 636 NumVectors = 0; 637 break; 638 case 'g': 639 Signed = false; 640 Float = false; 641 ElementBitwidth = 64; 642 break; 643 case 't': 644 Signed = true; 645 Float = false; 646 ElementBitwidth = 32; 647 break; 648 case 'z': 649 Signed = false; 650 Float = false; 651 ElementBitwidth = 32; 652 break; 653 case 'O': 654 Predicate = false; 655 Float = true; 656 ElementBitwidth = 16; 657 break; 658 case 'M': 659 Predicate = false; 660 Float = true; 661 ElementBitwidth = 32; 662 break; 663 case 'N': 664 Predicate = false; 665 Float = true; 666 ElementBitwidth = 64; 667 break; 668 case 'Q': 669 Constant = true; 670 Pointer = true; 671 Void = true; 672 NumVectors = 0; 673 break; 674 case 'S': 675 Constant = true; 676 Pointer = true; 677 ElementBitwidth = Bitwidth = 8; 678 NumVectors = 0; 679 Signed = true; 680 break; 681 case 'W': 682 Constant = true; 683 Pointer = true; 684 ElementBitwidth = Bitwidth = 8; 685 NumVectors = 0; 686 Signed = false; 687 break; 688 case 'T': 689 Constant = true; 690 Pointer = true; 691 ElementBitwidth = Bitwidth = 16; 692 NumVectors = 0; 693 Signed = true; 694 break; 695 case 'X': 696 Constant = true; 697 Pointer = true; 698 ElementBitwidth = Bitwidth = 16; 699 NumVectors = 0; 700 Signed = false; 701 break; 702 case 'Y': 703 Constant = true; 704 Pointer = true; 705 ElementBitwidth = Bitwidth = 32; 706 NumVectors = 0; 707 Signed = false; 708 break; 709 case 'U': 710 Constant = true; 711 Pointer = true; 712 ElementBitwidth = Bitwidth = 32; 713 NumVectors = 0; 714 Signed = true; 715 break; 716 case 'A': 717 Pointer = true; 718 ElementBitwidth = Bitwidth = 8; 719 NumVectors = 0; 720 Signed = true; 721 break; 722 case 'B': 723 Pointer = true; 724 ElementBitwidth = Bitwidth = 16; 725 NumVectors = 0; 726 Signed = true; 727 break; 728 case 'C': 729 Pointer = true; 730 ElementBitwidth = Bitwidth = 32; 731 NumVectors = 0; 732 Signed = true; 733 break; 734 case 'D': 735 Pointer = true; 736 ElementBitwidth = Bitwidth = 64; 737 NumVectors = 0; 738 Signed = true; 739 break; 740 case 'E': 741 Pointer = true; 742 ElementBitwidth = Bitwidth = 8; 743 NumVectors = 0; 744 Signed = false; 745 break; 746 case 'F': 747 Pointer = true; 748 ElementBitwidth = Bitwidth = 16; 749 NumVectors = 0; 750 Signed = false; 751 break; 752 case 'G': 753 Pointer = true; 754 ElementBitwidth = Bitwidth = 32; 755 NumVectors = 0; 756 Signed = false; 757 break; 758 default: 759 llvm_unreachable("Unhandled character!"); 760 } 761 } 762 763 764 //===----------------------------------------------------------------------===// 765 // Intrinsic implementation 766 //===----------------------------------------------------------------------===// 767 768 Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, 769 StringRef MergeSuffix, uint64_t MemoryElementTy, 770 StringRef LLVMName, uint64_t Flags, 771 ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class, 772 SVEEmitter &Emitter, StringRef Guard) 773 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), 774 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), 775 MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags), 776 ImmChecks(Checks.begin(), Checks.end()) { 777 778 // Types[0] is the return value. 779 for (unsigned I = 0; I < Proto.size(); ++I) { 780 SVEType T(BaseTypeSpec, Proto[I]); 781 Types.push_back(T); 782 783 // Add range checks for immediates 784 if (I > 0) { 785 if (T.isPredicatePattern()) 786 ImmChecks.emplace_back( 787 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31")); 788 else if (T.isPrefetchOp()) 789 ImmChecks.emplace_back( 790 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13")); 791 } 792 } 793 794 // Set flags based on properties 795 this->Flags |= Emitter.encodeTypeFlags(BaseType); 796 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy); 797 this->Flags |= Emitter.encodeMergeType(MergeTy); 798 if (hasSplat()) 799 this->Flags |= Emitter.encodeSplatOperand(getSplatIdx()); 800 } 801 802 std::string Intrinsic::getBuiltinTypeStr() { 803 std::string S; 804 805 SVEType RetT = getReturnType(); 806 // Since the return value must be one type, return a vector type of the 807 // appropriate width which we will bitcast. An exception is made for 808 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like 809 // fashion, storing them to a pointer arg. 810 if (RetT.getNumVectors() > 1) { 811 S += "vv*"; // void result with void* first argument 812 } else 813 S += RetT.builtin_str(); 814 815 for (unsigned I = 0; I < getNumParams(); ++I) 816 S += getParamType(I).builtin_str(); 817 818 return S; 819 } 820 821 std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, 822 std::string Proto) const { 823 std::string Ret = Name; 824 while (Ret.find('{') != std::string::npos) { 825 size_t Pos = Ret.find('{'); 826 size_t End = Ret.find('}'); 827 unsigned NumChars = End - Pos + 1; 828 assert(NumChars == 3 && "Unexpected template argument"); 829 830 SVEType T; 831 char C = Ret[Pos+1]; 832 switch(C) { 833 default: 834 llvm_unreachable("Unknown predication specifier"); 835 case 'd': 836 T = SVEType(TS, 'd'); 837 break; 838 case '0': 839 case '1': 840 case '2': 841 case '3': 842 T = SVEType(TS, Proto[C - '0']); 843 break; 844 } 845 846 // Replace templated arg with the right suffix (e.g. u32) 847 std::string TypeCode; 848 if (T.isInteger()) 849 TypeCode = T.isSigned() ? 's' : 'u'; 850 else if (T.isPredicateVector()) 851 TypeCode = 'b'; 852 else 853 TypeCode = 'f'; 854 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits())); 855 } 856 857 return Ret; 858 } 859 860 std::string Intrinsic::mangleName(ClassKind LocalCK) const { 861 std::string S = getName(); 862 863 if (LocalCK == ClassG) { 864 // Remove the square brackets and everything in between. 865 while (S.find("[") != std::string::npos) { 866 auto Start = S.find("["); 867 auto End = S.find(']'); 868 S.erase(Start, (End-Start)+1); 869 } 870 } else { 871 // Remove the square brackets. 872 while (S.find("[") != std::string::npos) { 873 auto BrPos = S.find('['); 874 if (BrPos != std::string::npos) 875 S.erase(BrPos, 1); 876 BrPos = S.find(']'); 877 if (BrPos != std::string::npos) 878 S.erase(BrPos, 1); 879 } 880 } 881 882 // Replace all {d} like expressions with e.g. 'u32' 883 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) + 884 getMergeSuffix(); 885 } 886 887 void Intrinsic::emitIntrinsic(raw_ostream &OS) const { 888 // Use the preprocessor to 889 if (getClassKind() != ClassG || getProto().size() <= 1) { 890 OS << "#define " << mangleName(getClassKind()) 891 << "(...) __builtin_sve_" << mangleName(ClassS) 892 << "(__VA_ARGS__)\n"; 893 } else { 894 std::string FullName = mangleName(ClassS); 895 std::string ProtoName = mangleName(ClassG); 896 897 OS << "__aio __attribute__((__clang_arm_builtin_alias(" 898 << "__builtin_sve_" << FullName << ")))\n"; 899 900 OS << getTypes()[0].str() << " " << ProtoName << "("; 901 for (unsigned I = 0; I < getTypes().size() - 1; ++I) { 902 if (I != 0) 903 OS << ", "; 904 OS << getTypes()[I + 1].str(); 905 } 906 OS << ");\n"; 907 } 908 } 909 910 //===----------------------------------------------------------------------===// 911 // SVEEmitter implementation 912 //===----------------------------------------------------------------------===// 913 uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) { 914 if (T.isFloat()) { 915 switch (T.getElementSizeInBits()) { 916 case 16: 917 return encodeEltType("EltTyFloat16"); 918 case 32: 919 return encodeEltType("EltTyFloat32"); 920 case 64: 921 return encodeEltType("EltTyFloat64"); 922 default: 923 llvm_unreachable("Unhandled float element bitwidth!"); 924 } 925 } 926 927 if (T.isPredicateVector()) { 928 switch (T.getElementSizeInBits()) { 929 case 8: 930 return encodeEltType("EltTyBool8"); 931 case 16: 932 return encodeEltType("EltTyBool16"); 933 case 32: 934 return encodeEltType("EltTyBool32"); 935 case 64: 936 return encodeEltType("EltTyBool64"); 937 default: 938 llvm_unreachable("Unhandled predicate element bitwidth!"); 939 } 940 } 941 942 switch (T.getElementSizeInBits()) { 943 case 8: 944 return encodeEltType("EltTyInt8"); 945 case 16: 946 return encodeEltType("EltTyInt16"); 947 case 32: 948 return encodeEltType("EltTyInt32"); 949 case 64: 950 return encodeEltType("EltTyInt64"); 951 default: 952 llvm_unreachable("Unhandled integer element bitwidth!"); 953 } 954 } 955 956 void SVEEmitter::createIntrinsic( 957 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) { 958 StringRef Name = R->getValueAsString("Name"); 959 StringRef Proto = R->getValueAsString("Prototype"); 960 StringRef Types = R->getValueAsString("Types"); 961 StringRef Guard = R->getValueAsString("ArchGuard"); 962 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic"); 963 uint64_t Merge = R->getValueAsInt("Merge"); 964 StringRef MergeSuffix = R->getValueAsString("MergeSuffix"); 965 uint64_t MemEltType = R->getValueAsInt("MemEltType"); 966 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags"); 967 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks"); 968 969 int64_t Flags = 0; 970 for (auto FlagRec : FlagsList) 971 Flags |= FlagRec->getValueAsInt("Value"); 972 973 // Create a dummy TypeSpec for non-overloaded builtins. 974 if (Types.empty()) { 975 assert((Flags & getEnumValueForFlag("IsOverloadNone")) && 976 "Expect TypeSpec for overloaded builtin!"); 977 Types = "i"; 978 } 979 980 // Extract type specs from string 981 SmallVector<TypeSpec, 8> TypeSpecs; 982 TypeSpec Acc; 983 for (char I : Types) { 984 Acc.push_back(I); 985 if (islower(I)) { 986 TypeSpecs.push_back(TypeSpec(Acc)); 987 Acc.clear(); 988 } 989 } 990 991 // Remove duplicate type specs. 992 llvm::sort(TypeSpecs); 993 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()), 994 TypeSpecs.end()); 995 996 // Create an Intrinsic for each type spec. 997 for (auto TS : TypeSpecs) { 998 // Collate a list of range/option checks for the immediates. 999 SmallVector<ImmCheck, 2> ImmChecks; 1000 for (auto *R : ImmCheckList) { 1001 int64_t Arg = R->getValueAsInt("Arg"); 1002 int64_t EltSizeArg = R->getValueAsInt("EltSizeArg"); 1003 int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value"); 1004 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative"); 1005 1006 unsigned ElementSizeInBits = 0; 1007 if (EltSizeArg >= 0) 1008 ElementSizeInBits = 1009 SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1]) 1010 .getElementSizeInBits(); 1011 ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits)); 1012 } 1013 1014 Out.push_back(std::make_unique<Intrinsic>( 1015 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks, 1016 TS, ClassS, *this, Guard)); 1017 1018 // Also generate the short-form (e.g. svadd_m) for the given type-spec. 1019 if (Intrinsic::isOverloadedIntrinsic(Name)) 1020 Out.push_back(std::make_unique<Intrinsic>( 1021 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, 1022 ImmChecks, TS, ClassG, *this, Guard)); 1023 } 1024 } 1025 1026 void SVEEmitter::createHeader(raw_ostream &OS) { 1027 OS << "/*===---- arm_sve.h - ARM SVE intrinsics " 1028 "-----------------------------------===\n" 1029 " *\n" 1030 " *\n" 1031 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 1032 "Exceptions.\n" 1033 " * See https://llvm.org/LICENSE.txt for license information.\n" 1034 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 1035 " *\n" 1036 " *===-----------------------------------------------------------------" 1037 "------===\n" 1038 " */\n\n"; 1039 1040 OS << "#ifndef __ARM_SVE_H\n"; 1041 OS << "#define __ARM_SVE_H\n\n"; 1042 1043 OS << "#if !defined(__ARM_FEATURE_SVE)\n"; 1044 OS << "#error \"SVE support not enabled\"\n"; 1045 OS << "#else\n\n"; 1046 1047 OS << "#if !defined(__LITTLE_ENDIAN__)\n"; 1048 OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n"; 1049 OS << "#endif\n"; 1050 1051 OS << "#include <stdint.h>\n\n"; 1052 OS << "#ifdef __cplusplus\n"; 1053 OS << "extern \"C\" {\n"; 1054 OS << "#else\n"; 1055 OS << "#include <stdbool.h>\n"; 1056 OS << "#endif\n\n"; 1057 1058 OS << "typedef __fp16 float16_t;\n"; 1059 OS << "typedef float float32_t;\n"; 1060 OS << "typedef double float64_t;\n"; 1061 OS << "typedef bool bool_t;\n\n"; 1062 1063 OS << "typedef __SVInt8_t svint8_t;\n"; 1064 OS << "typedef __SVInt16_t svint16_t;\n"; 1065 OS << "typedef __SVInt32_t svint32_t;\n"; 1066 OS << "typedef __SVInt64_t svint64_t;\n"; 1067 OS << "typedef __SVUint8_t svuint8_t;\n"; 1068 OS << "typedef __SVUint16_t svuint16_t;\n"; 1069 OS << "typedef __SVUint32_t svuint32_t;\n"; 1070 OS << "typedef __SVUint64_t svuint64_t;\n"; 1071 OS << "typedef __SVFloat16_t svfloat16_t;\n"; 1072 OS << "typedef __SVFloat32_t svfloat32_t;\n"; 1073 OS << "typedef __SVFloat64_t svfloat64_t;\n"; 1074 OS << "typedef __SVBool_t svbool_t;\n\n"; 1075 1076 OS << "typedef enum\n"; 1077 OS << "{\n"; 1078 OS << " SV_POW2 = 0,\n"; 1079 OS << " SV_VL1 = 1,\n"; 1080 OS << " SV_VL2 = 2,\n"; 1081 OS << " SV_VL3 = 3,\n"; 1082 OS << " SV_VL4 = 4,\n"; 1083 OS << " SV_VL5 = 5,\n"; 1084 OS << " SV_VL6 = 6,\n"; 1085 OS << " SV_VL7 = 7,\n"; 1086 OS << " SV_VL8 = 8,\n"; 1087 OS << " SV_VL16 = 9,\n"; 1088 OS << " SV_VL32 = 10,\n"; 1089 OS << " SV_VL64 = 11,\n"; 1090 OS << " SV_VL128 = 12,\n"; 1091 OS << " SV_VL256 = 13,\n"; 1092 OS << " SV_MUL4 = 29,\n"; 1093 OS << " SV_MUL3 = 30,\n"; 1094 OS << " SV_ALL = 31\n"; 1095 OS << "} sv_pattern;\n\n"; 1096 1097 OS << "typedef enum\n"; 1098 OS << "{\n"; 1099 OS << " SV_PLDL1KEEP = 0,\n"; 1100 OS << " SV_PLDL1STRM = 1,\n"; 1101 OS << " SV_PLDL2KEEP = 2,\n"; 1102 OS << " SV_PLDL2STRM = 3,\n"; 1103 OS << " SV_PLDL3KEEP = 4,\n"; 1104 OS << " SV_PLDL3STRM = 5,\n"; 1105 OS << " SV_PSTL1KEEP = 8,\n"; 1106 OS << " SV_PSTL1STRM = 9,\n"; 1107 OS << " SV_PSTL2KEEP = 10,\n"; 1108 OS << " SV_PSTL2STRM = 11,\n"; 1109 OS << " SV_PSTL3KEEP = 12,\n"; 1110 OS << " SV_PSTL3STRM = 13\n"; 1111 OS << "} sv_prfop;\n\n"; 1112 1113 OS << "/* Function attributes */\n"; 1114 OS << "#define __aio static inline __attribute__((__always_inline__, " 1115 "__nodebug__, __overloadable__))\n\n"; 1116 1117 // Add reinterpret functions. 1118 for (auto ShortForm : { false, true } ) 1119 for (const ReinterpretTypeInfo &From : Reinterprets) 1120 for (const ReinterpretTypeInfo &To : Reinterprets) { 1121 if (ShortForm) { 1122 OS << "__aio " << From.Type << " svreinterpret_" << From.Suffix; 1123 OS << "(" << To.Type << " op) {\n"; 1124 OS << " return __builtin_sve_reinterpret_" << From.Suffix << "_" 1125 << To.Suffix << "(op);\n"; 1126 OS << "}\n\n"; 1127 } else 1128 OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix 1129 << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_" 1130 << To.Suffix << "(__VA_ARGS__)\n"; 1131 } 1132 1133 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1134 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1135 for (auto *R : RV) 1136 createIntrinsic(R, Defs); 1137 1138 // Sort intrinsics in header file by following order/priority: 1139 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES) 1140 // - Class (is intrinsic overloaded or not) 1141 // - Intrinsic name 1142 std::stable_sort( 1143 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A, 1144 const std::unique_ptr<Intrinsic> &B) { 1145 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) { 1146 return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName()); 1147 }; 1148 return ToTuple(A) < ToTuple(B); 1149 }); 1150 1151 StringRef InGuard = ""; 1152 for (auto &I : Defs) { 1153 // Emit #endif/#if pair if needed. 1154 if (I->getGuard() != InGuard) { 1155 if (!InGuard.empty()) 1156 OS << "#endif //" << InGuard << "\n"; 1157 InGuard = I->getGuard(); 1158 if (!InGuard.empty()) 1159 OS << "\n#if " << InGuard << "\n"; 1160 } 1161 1162 // Actually emit the intrinsic declaration. 1163 I->emitIntrinsic(OS); 1164 } 1165 1166 if (!InGuard.empty()) 1167 OS << "#endif //" << InGuard << "\n"; 1168 1169 OS << "#if defined(__ARM_FEATURE_SVE2)\n"; 1170 OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n"; 1171 OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n"; 1172 OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n"; 1173 OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n"; 1174 1175 OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n"; 1176 OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n"; 1177 1178 OS << "#endif /*__ARM_FEATURE_SVE2 */\n\n"; 1179 1180 OS << "#ifdef __cplusplus\n"; 1181 OS << "} // extern \"C\"\n"; 1182 OS << "#endif\n\n"; 1183 OS << "#endif /*__ARM_FEATURE_SVE */\n\n"; 1184 OS << "#endif /* __ARM_SVE_H */\n"; 1185 } 1186 1187 void SVEEmitter::createBuiltins(raw_ostream &OS) { 1188 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1189 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1190 for (auto *R : RV) 1191 createIntrinsic(R, Defs); 1192 1193 // The mappings must be sorted based on BuiltinID. 1194 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1195 const std::unique_ptr<Intrinsic> &B) { 1196 return A->getMangledName() < B->getMangledName(); 1197 }); 1198 1199 OS << "#ifdef GET_SVE_BUILTINS\n"; 1200 for (auto &Def : Defs) { 1201 // Only create BUILTINs for non-overloaded intrinsics, as overloaded 1202 // declarations only live in the header file. 1203 if (Def->getClassKind() != ClassG) 1204 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \"" 1205 << Def->getBuiltinTypeStr() << "\", \"n\")\n"; 1206 } 1207 1208 // Add reinterpret builtins 1209 for (const ReinterpretTypeInfo &From : Reinterprets) 1210 for (const ReinterpretTypeInfo &To : Reinterprets) 1211 OS << "BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_" 1212 << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType 1213 << "\", \"n\")\n"; 1214 1215 OS << "#endif\n\n"; 1216 } 1217 1218 void SVEEmitter::createCodeGenMap(raw_ostream &OS) { 1219 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1220 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1221 for (auto *R : RV) 1222 createIntrinsic(R, Defs); 1223 1224 // The mappings must be sorted based on BuiltinID. 1225 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1226 const std::unique_ptr<Intrinsic> &B) { 1227 return A->getMangledName() < B->getMangledName(); 1228 }); 1229 1230 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n"; 1231 for (auto &Def : Defs) { 1232 // Builtins only exist for non-overloaded intrinsics, overloaded 1233 // declarations only live in the header file. 1234 if (Def->getClassKind() == ClassG) 1235 continue; 1236 1237 uint64_t Flags = Def->getFlags(); 1238 auto FlagString = std::to_string(Flags); 1239 1240 std::string LLVMName = Def->getLLVMName(); 1241 std::string Builtin = Def->getMangledName(); 1242 if (!LLVMName.empty()) 1243 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString 1244 << "),\n"; 1245 else 1246 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n"; 1247 } 1248 OS << "#endif\n\n"; 1249 } 1250 1251 void SVEEmitter::createRangeChecks(raw_ostream &OS) { 1252 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1253 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1254 for (auto *R : RV) 1255 createIntrinsic(R, Defs); 1256 1257 // The mappings must be sorted based on BuiltinID. 1258 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1259 const std::unique_ptr<Intrinsic> &B) { 1260 return A->getMangledName() < B->getMangledName(); 1261 }); 1262 1263 1264 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n"; 1265 1266 // Ensure these are only emitted once. 1267 std::set<std::string> Emitted; 1268 1269 for (auto &Def : Defs) { 1270 if (Emitted.find(Def->getMangledName()) != Emitted.end() || 1271 Def->getImmChecks().empty()) 1272 continue; 1273 1274 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n"; 1275 for (auto &Check : Def->getImmChecks()) 1276 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", " 1277 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n"; 1278 OS << " break;\n"; 1279 1280 Emitted.insert(Def->getMangledName()); 1281 } 1282 1283 OS << "#endif\n\n"; 1284 } 1285 1286 /// Create the SVETypeFlags used in CGBuiltins 1287 void SVEEmitter::createTypeFlags(raw_ostream &OS) { 1288 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n"; 1289 for (auto &KV : FlagTypes) 1290 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n"; 1291 OS << "#endif\n\n"; 1292 1293 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n"; 1294 for (auto &KV : EltTypes) 1295 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1296 OS << "#endif\n\n"; 1297 1298 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n"; 1299 for (auto &KV : MemEltTypes) 1300 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1301 OS << "#endif\n\n"; 1302 1303 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n"; 1304 for (auto &KV : MergeTypes) 1305 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1306 OS << "#endif\n\n"; 1307 1308 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n"; 1309 for (auto &KV : ImmCheckTypes) 1310 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1311 OS << "#endif\n\n"; 1312 } 1313 1314 namespace clang { 1315 void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) { 1316 SVEEmitter(Records).createHeader(OS); 1317 } 1318 1319 void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1320 SVEEmitter(Records).createBuiltins(OS); 1321 } 1322 1323 void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1324 SVEEmitter(Records).createCodeGenMap(OS); 1325 } 1326 1327 void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) { 1328 SVEEmitter(Records).createRangeChecks(OS); 1329 } 1330 1331 void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) { 1332 SVEEmitter(Records).createTypeFlags(OS); 1333 } 1334 1335 } // End namespace clang 1336