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