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 /// Emits the intrinsic declaration to the ostream. 212 void emitIntrinsic(raw_ostream &OS) const; 213 214 private: 215 std::string getMergeSuffix() const { return MergeSuffix; } 216 std::string mangleName(ClassKind LocalCK) const; 217 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS, 218 std::string Proto) const; 219 }; 220 221 class SVEEmitter { 222 private: 223 RecordKeeper &Records; 224 llvm::StringMap<uint64_t> EltTypes; 225 llvm::StringMap<uint64_t> MemEltTypes; 226 llvm::StringMap<uint64_t> FlagTypes; 227 llvm::StringMap<uint64_t> MergeTypes; 228 llvm::StringMap<uint64_t> ImmCheckTypes; 229 230 public: 231 SVEEmitter(RecordKeeper &R) : Records(R) { 232 for (auto *RV : Records.getAllDerivedDefinitions("EltType")) 233 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 234 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType")) 235 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 236 for (auto *RV : Records.getAllDerivedDefinitions("FlagType")) 237 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 238 for (auto *RV : Records.getAllDerivedDefinitions("MergeType")) 239 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 240 for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType")) 241 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 242 } 243 244 /// Returns the enum value for the immcheck type 245 unsigned getEnumValueForImmCheck(StringRef C) const { 246 auto It = ImmCheckTypes.find(C); 247 if (It != ImmCheckTypes.end()) 248 return It->getValue(); 249 llvm_unreachable("Unsupported imm check"); 250 } 251 252 // Returns the SVETypeFlags for a given value and mask. 253 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const { 254 auto It = FlagTypes.find(MaskName); 255 if (It != FlagTypes.end()) { 256 uint64_t Mask = It->getValue(); 257 unsigned Shift = llvm::countTrailingZeros(Mask); 258 return (V << Shift) & Mask; 259 } 260 llvm_unreachable("Unsupported flag"); 261 } 262 263 // Returns the SVETypeFlags for the given element type. 264 uint64_t encodeEltType(StringRef EltName) { 265 auto It = EltTypes.find(EltName); 266 if (It != EltTypes.end()) 267 return encodeFlag(It->getValue(), "EltTypeMask"); 268 llvm_unreachable("Unsupported EltType"); 269 } 270 271 // Returns the SVETypeFlags for the given memory element type. 272 uint64_t encodeMemoryElementType(uint64_t MT) { 273 return encodeFlag(MT, "MemEltTypeMask"); 274 } 275 276 // Returns the SVETypeFlags for the given merge type. 277 uint64_t encodeMergeType(uint64_t MT) { 278 return encodeFlag(MT, "MergeTypeMask"); 279 } 280 281 // Returns the SVETypeFlags value for the given SVEType. 282 uint64_t encodeTypeFlags(const SVEType &T); 283 284 /// Emit arm_sve.h. 285 void createHeader(raw_ostream &o); 286 287 /// Emit all the __builtin prototypes and code needed by Sema. 288 void createBuiltins(raw_ostream &o); 289 290 /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 291 void createCodeGenMap(raw_ostream &o); 292 293 /// Emit all the range checks for the immediates. 294 void createRangeChecks(raw_ostream &o); 295 296 /// Create the SVETypeFlags used in CGBuiltins 297 void createTypeFlags(raw_ostream &o); 298 299 /// Create intrinsic and add it to \p Out 300 void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out); 301 }; 302 303 } // end anonymous namespace 304 305 306 //===----------------------------------------------------------------------===// 307 // Type implementation 308 //===----------------------------------------------------------------------===// 309 310 std::string SVEType::builtin_str() const { 311 std::string S; 312 if (isVoid()) 313 return "v"; 314 315 if (isVoidPointer()) 316 S += "v"; 317 else if (!Float) 318 switch (ElementBitwidth) { 319 case 1: S += "b"; break; 320 case 8: S += "c"; break; 321 case 16: S += "s"; break; 322 case 32: S += "i"; break; 323 case 64: S += "Wi"; break; 324 case 128: S += "LLLi"; break; 325 default: llvm_unreachable("Unhandled case!"); 326 } 327 else 328 switch (ElementBitwidth) { 329 case 16: S += "h"; break; 330 case 32: S += "f"; break; 331 case 64: S += "d"; break; 332 default: llvm_unreachable("Unhandled case!"); 333 } 334 335 if (!isFloat()) { 336 if ((isChar() || isPointer()) && !isVoidPointer()) { 337 // Make chars and typed pointers explicitly signed. 338 if (Signed) 339 S = "S" + S; 340 else if (!Signed) 341 S = "U" + S; 342 } else if (!isVoidPointer() && !Signed) { 343 S = "U" + S; 344 } 345 } 346 347 // Constant indices are "int", but have the "constant expression" modifier. 348 if (isImmediate()) { 349 assert(!isFloat() && "fp immediates are not supported"); 350 S = "I" + S; 351 } 352 353 if (isScalar()) { 354 if (Constant) S += "C"; 355 if (Pointer) S += "*"; 356 return S; 357 } 358 359 assert(isScalableVector() && "Unsupported type"); 360 return "q" + utostr(getNumElements() * NumVectors) + S; 361 } 362 363 std::string SVEType::str() const { 364 if (isPredicatePattern()) 365 return "sv_pattern"; 366 367 if (isPrefetchOp()) 368 return "sv_prfop"; 369 370 std::string S; 371 if (Void) 372 S += "void"; 373 else { 374 if (isScalableVector()) 375 S += "sv"; 376 if (!Signed && !Float) 377 S += "u"; 378 379 if (Float) 380 S += "float"; 381 else if (isScalarPredicate()) 382 S += "bool"; 383 else 384 S += "int"; 385 386 if (!isScalarPredicate()) 387 S += utostr(ElementBitwidth); 388 if (!isScalableVector() && isVector()) 389 S += "x" + utostr(getNumElements()); 390 if (NumVectors > 1) 391 S += "x" + utostr(NumVectors); 392 S += "_t"; 393 } 394 395 if (Constant) 396 S += " const"; 397 if (Pointer) 398 S += " *"; 399 400 return S; 401 } 402 void SVEType::applyTypespec() { 403 for (char I : TS) { 404 switch (I) { 405 case 'P': 406 Predicate = true; 407 ElementBitwidth = 1; 408 break; 409 case 'U': 410 Signed = false; 411 break; 412 case 'c': 413 ElementBitwidth = 8; 414 break; 415 case 's': 416 ElementBitwidth = 16; 417 break; 418 case 'i': 419 ElementBitwidth = 32; 420 break; 421 case 'l': 422 ElementBitwidth = 64; 423 break; 424 case 'h': 425 Float = true; 426 ElementBitwidth = 16; 427 break; 428 case 'f': 429 Float = true; 430 ElementBitwidth = 32; 431 break; 432 case 'd': 433 Float = true; 434 ElementBitwidth = 64; 435 break; 436 default: 437 llvm_unreachable("Unhandled type code!"); 438 } 439 } 440 assert(ElementBitwidth != ~0U && "Bad element bitwidth!"); 441 } 442 443 void SVEType::applyModifier(char Mod) { 444 switch (Mod) { 445 case 'v': 446 Void = true; 447 break; 448 case 'd': 449 DefaultType = true; 450 break; 451 case 'c': 452 Constant = true; 453 LLVM_FALLTHROUGH; 454 case 'p': 455 Pointer = true; 456 Bitwidth = ElementBitwidth; 457 NumVectors = 0; 458 break; 459 case 'P': 460 Signed = true; 461 Float = false; 462 Predicate = true; 463 Bitwidth = 16; 464 ElementBitwidth = 1; 465 break; 466 case 'i': 467 Predicate = false; 468 Float = false; 469 ElementBitwidth = Bitwidth = 64; 470 NumVectors = 0; 471 Signed = false; 472 Immediate = true; 473 break; 474 case 'I': 475 Predicate = false; 476 Float = false; 477 ElementBitwidth = Bitwidth = 32; 478 NumVectors = 0; 479 Signed = true; 480 Immediate = true; 481 PredicatePattern = true; 482 break; 483 case 'l': 484 Predicate = false; 485 Signed = true; 486 Float = false; 487 ElementBitwidth = Bitwidth = 64; 488 NumVectors = 0; 489 break; 490 case 'S': 491 Constant = true; 492 Pointer = true; 493 ElementBitwidth = Bitwidth = 8; 494 NumVectors = 0; 495 Signed = true; 496 break; 497 case 'W': 498 Constant = true; 499 Pointer = true; 500 ElementBitwidth = Bitwidth = 8; 501 NumVectors = 0; 502 Signed = false; 503 break; 504 case 'T': 505 Constant = true; 506 Pointer = true; 507 ElementBitwidth = Bitwidth = 16; 508 NumVectors = 0; 509 Signed = true; 510 break; 511 case 'X': 512 Constant = true; 513 Pointer = true; 514 ElementBitwidth = Bitwidth = 16; 515 NumVectors = 0; 516 Signed = false; 517 break; 518 case 'Y': 519 Constant = true; 520 Pointer = true; 521 ElementBitwidth = Bitwidth = 32; 522 NumVectors = 0; 523 Signed = false; 524 break; 525 case 'U': 526 Constant = true; 527 Pointer = true; 528 ElementBitwidth = Bitwidth = 32; 529 NumVectors = 0; 530 Signed = true; 531 break; 532 case 'A': 533 Pointer = true; 534 ElementBitwidth = Bitwidth = 8; 535 NumVectors = 0; 536 Signed = true; 537 break; 538 case 'B': 539 Pointer = true; 540 ElementBitwidth = Bitwidth = 16; 541 NumVectors = 0; 542 Signed = true; 543 break; 544 case 'C': 545 Pointer = true; 546 ElementBitwidth = Bitwidth = 32; 547 NumVectors = 0; 548 Signed = true; 549 break; 550 case 'D': 551 Pointer = true; 552 ElementBitwidth = Bitwidth = 64; 553 NumVectors = 0; 554 Signed = true; 555 break; 556 case 'E': 557 Pointer = true; 558 ElementBitwidth = Bitwidth = 8; 559 NumVectors = 0; 560 Signed = false; 561 break; 562 case 'F': 563 Pointer = true; 564 ElementBitwidth = Bitwidth = 16; 565 NumVectors = 0; 566 Signed = false; 567 break; 568 case 'G': 569 Pointer = true; 570 ElementBitwidth = Bitwidth = 32; 571 NumVectors = 0; 572 Signed = false; 573 break; 574 default: 575 llvm_unreachable("Unhandled character!"); 576 } 577 } 578 579 580 //===----------------------------------------------------------------------===// 581 // Intrinsic implementation 582 //===----------------------------------------------------------------------===// 583 584 Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, 585 StringRef MergeSuffix, uint64_t MemoryElementTy, 586 StringRef LLVMName, uint64_t Flags, 587 ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class, 588 SVEEmitter &Emitter, StringRef Guard) 589 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), 590 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), 591 MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags), 592 ImmChecks(Checks.begin(), Checks.end()) { 593 594 // Types[0] is the return value. 595 for (unsigned I = 0; I < Proto.size(); ++I) { 596 SVEType T(BaseTypeSpec, Proto[I]); 597 Types.push_back(T); 598 599 // Add range checks for immediates 600 if (I > 0) { 601 if (T.isPredicatePattern()) 602 ImmChecks.emplace_back( 603 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31")); 604 } 605 } 606 607 // Set flags based on properties 608 this->Flags |= Emitter.encodeTypeFlags(BaseType); 609 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy); 610 this->Flags |= Emitter.encodeMergeType(MergeTy); 611 } 612 613 std::string Intrinsic::getBuiltinTypeStr() { 614 std::string S; 615 616 SVEType RetT = getReturnType(); 617 // Since the return value must be one type, return a vector type of the 618 // appropriate width which we will bitcast. An exception is made for 619 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like 620 // fashion, storing them to a pointer arg. 621 if (RetT.getNumVectors() > 1) { 622 S += "vv*"; // void result with void* first argument 623 } else 624 S += RetT.builtin_str(); 625 626 for (unsigned I = 0; I < getNumParams(); ++I) 627 S += getParamType(I).builtin_str(); 628 629 return S; 630 } 631 632 std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, 633 std::string Proto) const { 634 std::string Ret = Name; 635 while (Ret.find('{') != std::string::npos) { 636 size_t Pos = Ret.find('{'); 637 size_t End = Ret.find('}'); 638 unsigned NumChars = End - Pos + 1; 639 assert(NumChars == 3 && "Unexpected template argument"); 640 641 SVEType T; 642 char C = Ret[Pos+1]; 643 switch(C) { 644 default: 645 llvm_unreachable("Unknown predication specifier"); 646 case 'd': 647 T = SVEType(TS, 'd'); 648 break; 649 case '0': 650 case '1': 651 case '2': 652 case '3': 653 T = SVEType(TS, Proto[C - '0']); 654 break; 655 } 656 657 // Replace templated arg with the right suffix (e.g. u32) 658 std::string TypeCode; 659 if (T.isInteger()) 660 TypeCode = T.isSigned() ? 's' : 'u'; 661 else if (T.isPredicateVector()) 662 TypeCode = 'b'; 663 else 664 TypeCode = 'f'; 665 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits())); 666 } 667 668 return Ret; 669 } 670 671 std::string Intrinsic::mangleName(ClassKind LocalCK) const { 672 std::string S = getName(); 673 674 if (LocalCK == ClassG) { 675 // Remove the square brackets and everything in between. 676 while (S.find("[") != std::string::npos) { 677 auto Start = S.find("["); 678 auto End = S.find(']'); 679 S.erase(Start, (End-Start)+1); 680 } 681 } else { 682 // Remove the square brackets. 683 while (S.find("[") != std::string::npos) { 684 auto BrPos = S.find('['); 685 if (BrPos != std::string::npos) 686 S.erase(BrPos, 1); 687 BrPos = S.find(']'); 688 if (BrPos != std::string::npos) 689 S.erase(BrPos, 1); 690 } 691 } 692 693 // Replace all {d} like expressions with e.g. 'u32' 694 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) + 695 getMergeSuffix(); 696 } 697 698 void Intrinsic::emitIntrinsic(raw_ostream &OS) const { 699 // Use the preprocessor to 700 if (getClassKind() != ClassG || getProto().size() <= 1) { 701 OS << "#define " << mangleName(getClassKind()) 702 << "(...) __builtin_sve_" << mangleName(ClassS) 703 << "(__VA_ARGS__)\n"; 704 } else { 705 std::string FullName = mangleName(ClassS); 706 std::string ProtoName = mangleName(ClassG); 707 708 OS << "__aio __attribute__((__clang_arm_builtin_alias(" 709 << "__builtin_sve_" << FullName << ")))\n"; 710 711 OS << getTypes()[0].str() << " " << ProtoName << "("; 712 for (unsigned I = 0; I < getTypes().size() - 1; ++I) { 713 if (I != 0) 714 OS << ", "; 715 OS << getTypes()[I + 1].str(); 716 } 717 OS << ");\n"; 718 } 719 } 720 721 //===----------------------------------------------------------------------===// 722 // SVEEmitter implementation 723 //===----------------------------------------------------------------------===// 724 uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) { 725 if (T.isFloat()) { 726 switch (T.getElementSizeInBits()) { 727 case 16: 728 return encodeEltType("EltTyFloat16"); 729 case 32: 730 return encodeEltType("EltTyFloat32"); 731 case 64: 732 return encodeEltType("EltTyFloat64"); 733 default: 734 llvm_unreachable("Unhandled float element bitwidth!"); 735 } 736 } 737 738 if (T.isPredicateVector()) { 739 switch (T.getElementSizeInBits()) { 740 case 8: 741 return encodeEltType("EltTyBool8"); 742 case 16: 743 return encodeEltType("EltTyBool16"); 744 case 32: 745 return encodeEltType("EltTyBool32"); 746 case 64: 747 return encodeEltType("EltTyBool64"); 748 default: 749 llvm_unreachable("Unhandled predicate element bitwidth!"); 750 } 751 } 752 753 switch (T.getElementSizeInBits()) { 754 case 8: 755 return encodeEltType("EltTyInt8"); 756 case 16: 757 return encodeEltType("EltTyInt16"); 758 case 32: 759 return encodeEltType("EltTyInt32"); 760 case 64: 761 return encodeEltType("EltTyInt64"); 762 default: 763 llvm_unreachable("Unhandled integer element bitwidth!"); 764 } 765 } 766 767 void SVEEmitter::createIntrinsic( 768 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) { 769 StringRef Name = R->getValueAsString("Name"); 770 StringRef Proto = R->getValueAsString("Prototype"); 771 StringRef Types = R->getValueAsString("Types"); 772 StringRef Guard = R->getValueAsString("ArchGuard"); 773 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic"); 774 uint64_t Merge = R->getValueAsInt("Merge"); 775 StringRef MergeSuffix = R->getValueAsString("MergeSuffix"); 776 uint64_t MemEltType = R->getValueAsInt("MemEltType"); 777 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags"); 778 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks"); 779 780 int64_t Flags = 0; 781 for (auto FlagRec : FlagsList) 782 Flags |= FlagRec->getValueAsInt("Value"); 783 784 // Extract type specs from string 785 SmallVector<TypeSpec, 8> TypeSpecs; 786 TypeSpec Acc; 787 for (char I : Types) { 788 Acc.push_back(I); 789 if (islower(I)) { 790 TypeSpecs.push_back(TypeSpec(Acc)); 791 Acc.clear(); 792 } 793 } 794 795 // Remove duplicate type specs. 796 llvm::sort(TypeSpecs); 797 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()), 798 TypeSpecs.end()); 799 800 // Create an Intrinsic for each type spec. 801 for (auto TS : TypeSpecs) { 802 // Collate a list of range/option checks for the immediates. 803 SmallVector<ImmCheck, 2> ImmChecks; 804 for (auto *R : ImmCheckList) { 805 int64_t Arg = R->getValueAsInt("Arg"); 806 int64_t EltSizeArg = R->getValueAsInt("EltSizeArg"); 807 int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value"); 808 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative"); 809 810 unsigned ElementSizeInBits = 0; 811 if (EltSizeArg >= 0) 812 ElementSizeInBits = 813 SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1]) 814 .getElementSizeInBits(); 815 ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits)); 816 } 817 818 Out.push_back(std::make_unique<Intrinsic>( 819 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks, 820 TS, ClassS, *this, Guard)); 821 822 // Also generate the short-form (e.g. svadd_m) for the given type-spec. 823 if (Intrinsic::isOverloadedIntrinsic(Name)) 824 Out.push_back(std::make_unique<Intrinsic>( 825 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, 826 ImmChecks, TS, ClassG, *this, Guard)); 827 } 828 } 829 830 void SVEEmitter::createHeader(raw_ostream &OS) { 831 OS << "/*===---- arm_sve.h - ARM SVE intrinsics " 832 "-----------------------------------===\n" 833 " *\n" 834 " *\n" 835 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 836 "Exceptions.\n" 837 " * See https://llvm.org/LICENSE.txt for license information.\n" 838 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 839 " *\n" 840 " *===-----------------------------------------------------------------" 841 "------===\n" 842 " */\n\n"; 843 844 OS << "#ifndef __ARM_SVE_H\n"; 845 OS << "#define __ARM_SVE_H\n\n"; 846 847 OS << "#if !defined(__ARM_FEATURE_SVE)\n"; 848 OS << "#error \"SVE support not enabled\"\n"; 849 OS << "#else\n\n"; 850 851 OS << "#include <stdint.h>\n\n"; 852 OS << "#ifdef __cplusplus\n"; 853 OS << "extern \"C\" {\n"; 854 OS << "#else\n"; 855 OS << "#include <stdbool.h>\n"; 856 OS << "#endif\n\n"; 857 858 OS << "typedef __fp16 float16_t;\n"; 859 OS << "typedef float float32_t;\n"; 860 OS << "typedef double float64_t;\n"; 861 OS << "typedef bool bool_t;\n\n"; 862 863 OS << "typedef __SVInt8_t svint8_t;\n"; 864 OS << "typedef __SVInt16_t svint16_t;\n"; 865 OS << "typedef __SVInt32_t svint32_t;\n"; 866 OS << "typedef __SVInt64_t svint64_t;\n"; 867 OS << "typedef __SVUint8_t svuint8_t;\n"; 868 OS << "typedef __SVUint16_t svuint16_t;\n"; 869 OS << "typedef __SVUint32_t svuint32_t;\n"; 870 OS << "typedef __SVUint64_t svuint64_t;\n"; 871 OS << "typedef __SVFloat16_t svfloat16_t;\n"; 872 OS << "typedef __SVFloat32_t svfloat32_t;\n"; 873 OS << "typedef __SVFloat64_t svfloat64_t;\n"; 874 OS << "typedef __SVBool_t svbool_t;\n\n"; 875 876 OS << "typedef enum\n"; 877 OS << "{\n"; 878 OS << " SV_POW2 = 0,\n"; 879 OS << " SV_VL1 = 1,\n"; 880 OS << " SV_VL2 = 2,\n"; 881 OS << " SV_VL3 = 3,\n"; 882 OS << " SV_VL4 = 4,\n"; 883 OS << " SV_VL5 = 5,\n"; 884 OS << " SV_VL6 = 6,\n"; 885 OS << " SV_VL7 = 7,\n"; 886 OS << " SV_VL8 = 8,\n"; 887 OS << " SV_VL16 = 9,\n"; 888 OS << " SV_VL32 = 10,\n"; 889 OS << " SV_VL64 = 11,\n"; 890 OS << " SV_VL128 = 12,\n"; 891 OS << " SV_VL256 = 13,\n"; 892 OS << " SV_MUL4 = 29,\n"; 893 OS << " SV_MUL3 = 30,\n"; 894 OS << " SV_ALL = 31\n"; 895 OS << "} sv_pattern;\n\n"; 896 897 OS << "/* Function attributes */\n"; 898 OS << "#define __aio static inline __attribute__((__always_inline__, " 899 "__nodebug__, __overloadable__))\n\n"; 900 901 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 902 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 903 for (auto *R : RV) 904 createIntrinsic(R, Defs); 905 906 // Sort intrinsics in header file by following order/priority: 907 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES) 908 // - Class (is intrinsic overloaded or not) 909 // - Intrinsic name 910 std::stable_sort( 911 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A, 912 const std::unique_ptr<Intrinsic> &B) { 913 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) { 914 return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName()); 915 }; 916 return ToTuple(A) < ToTuple(B); 917 }); 918 919 StringRef InGuard = ""; 920 for (auto &I : Defs) { 921 // Emit #endif/#if pair if needed. 922 if (I->getGuard() != InGuard) { 923 if (!InGuard.empty()) 924 OS << "#endif //" << InGuard << "\n"; 925 InGuard = I->getGuard(); 926 if (!InGuard.empty()) 927 OS << "\n#if " << InGuard << "\n"; 928 } 929 930 // Actually emit the intrinsic declaration. 931 I->emitIntrinsic(OS); 932 } 933 934 if (!InGuard.empty()) 935 OS << "#endif //" << InGuard << "\n"; 936 937 OS << "#ifdef __cplusplus\n"; 938 OS << "} // extern \"C\"\n"; 939 OS << "#endif\n\n"; 940 OS << "#endif /*__ARM_FEATURE_SVE */\n\n"; 941 OS << "#endif /* __ARM_SVE_H */\n"; 942 } 943 944 void SVEEmitter::createBuiltins(raw_ostream &OS) { 945 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 946 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 947 for (auto *R : RV) 948 createIntrinsic(R, Defs); 949 950 // The mappings must be sorted based on BuiltinID. 951 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 952 const std::unique_ptr<Intrinsic> &B) { 953 return A->getMangledName() < B->getMangledName(); 954 }); 955 956 OS << "#ifdef GET_SVE_BUILTINS\n"; 957 for (auto &Def : Defs) { 958 // Only create BUILTINs for non-overloaded intrinsics, as overloaded 959 // declarations only live in the header file. 960 if (Def->getClassKind() != ClassG) 961 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \"" 962 << Def->getBuiltinTypeStr() << "\", \"n\")\n"; 963 } 964 OS << "#endif\n\n"; 965 } 966 967 void SVEEmitter::createCodeGenMap(raw_ostream &OS) { 968 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 969 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 970 for (auto *R : RV) 971 createIntrinsic(R, Defs); 972 973 // The mappings must be sorted based on BuiltinID. 974 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 975 const std::unique_ptr<Intrinsic> &B) { 976 return A->getMangledName() < B->getMangledName(); 977 }); 978 979 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n"; 980 for (auto &Def : Defs) { 981 // Builtins only exist for non-overloaded intrinsics, overloaded 982 // declarations only live in the header file. 983 if (Def->getClassKind() == ClassG) 984 continue; 985 986 uint64_t Flags = Def->getFlags(); 987 auto FlagString = std::to_string(Flags); 988 989 std::string LLVMName = Def->getLLVMName(); 990 std::string Builtin = Def->getMangledName(); 991 if (!LLVMName.empty()) 992 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString 993 << "),\n"; 994 else 995 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n"; 996 } 997 OS << "#endif\n\n"; 998 } 999 1000 void SVEEmitter::createRangeChecks(raw_ostream &OS) { 1001 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1002 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1003 for (auto *R : RV) 1004 createIntrinsic(R, Defs); 1005 1006 // The mappings must be sorted based on BuiltinID. 1007 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1008 const std::unique_ptr<Intrinsic> &B) { 1009 return A->getMangledName() < B->getMangledName(); 1010 }); 1011 1012 1013 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n"; 1014 1015 // Ensure these are only emitted once. 1016 std::set<std::string> Emitted; 1017 1018 for (auto &Def : Defs) { 1019 if (Emitted.find(Def->getMangledName()) != Emitted.end() || 1020 Def->getImmChecks().empty()) 1021 continue; 1022 1023 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n"; 1024 for (auto &Check : Def->getImmChecks()) 1025 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", " 1026 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n"; 1027 OS << " break;\n"; 1028 1029 Emitted.insert(Def->getMangledName()); 1030 } 1031 1032 OS << "#endif\n\n"; 1033 } 1034 1035 /// Create the SVETypeFlags used in CGBuiltins 1036 void SVEEmitter::createTypeFlags(raw_ostream &OS) { 1037 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n"; 1038 for (auto &KV : FlagTypes) 1039 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n"; 1040 OS << "#endif\n\n"; 1041 1042 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n"; 1043 for (auto &KV : EltTypes) 1044 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1045 OS << "#endif\n\n"; 1046 1047 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n"; 1048 for (auto &KV : MemEltTypes) 1049 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1050 OS << "#endif\n\n"; 1051 1052 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n"; 1053 for (auto &KV : MergeTypes) 1054 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1055 OS << "#endif\n\n"; 1056 1057 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n"; 1058 for (auto &KV : ImmCheckTypes) 1059 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1060 OS << "#endif\n\n"; 1061 } 1062 1063 namespace clang { 1064 void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) { 1065 SVEEmitter(Records).createHeader(OS); 1066 } 1067 1068 void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1069 SVEEmitter(Records).createBuiltins(OS); 1070 } 1071 1072 void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1073 SVEEmitter(Records).createCodeGenMap(OS); 1074 } 1075 1076 void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) { 1077 SVEEmitter(Records).createRangeChecks(OS); 1078 } 1079 1080 void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) { 1081 SVEEmitter(Records).createTypeFlags(OS); 1082 } 1083 1084 } // End namespace clang 1085