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