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 SVEType { 50 TypeSpec TS; 51 bool Float, Signed, Immediate, Void, Constant, Pointer; 52 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp; 53 unsigned Bitwidth, ElementBitwidth, NumVectors; 54 55 public: 56 SVEType() : SVEType(TypeSpec(), 'v') {} 57 58 SVEType(TypeSpec TS, char CharMod) 59 : TS(TS), Float(false), Signed(true), Immediate(false), Void(false), 60 Constant(false), Pointer(false), DefaultType(false), IsScalable(true), 61 Predicate(false), PredicatePattern(false), PrefetchOp(false), 62 Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) { 63 if (!TS.empty()) 64 applyTypespec(); 65 applyModifier(CharMod); 66 } 67 68 /// Return the value in SVETypeFlags for this type. 69 unsigned getTypeFlags() const; 70 71 bool isPointer() const { return Pointer; } 72 bool isVoidPointer() const { return Pointer && Void; } 73 bool isSigned() const { return Signed; } 74 bool isImmediate() const { return Immediate; } 75 bool isScalar() const { return NumVectors == 0; } 76 bool isVector() const { return NumVectors > 0; } 77 bool isScalableVector() const { return isVector() && IsScalable; } 78 bool isChar() const { return ElementBitwidth == 8; } 79 bool isVoid() const { return Void & !Pointer; } 80 bool isDefault() const { return DefaultType; } 81 bool isFloat() const { return Float; } 82 bool isInteger() const { return !Float && !Predicate; } 83 bool isScalarPredicate() const { return !Float && ElementBitwidth == 1; } 84 bool isPredicateVector() const { return Predicate; } 85 bool isPredicatePattern() const { return PredicatePattern; } 86 bool isPrefetchOp() const { return PrefetchOp; } 87 bool isConstant() const { return Constant; } 88 unsigned getElementSizeInBits() const { return ElementBitwidth; } 89 unsigned getNumVectors() const { return NumVectors; } 90 91 unsigned getNumElements() const { 92 assert(ElementBitwidth != ~0U); 93 return Bitwidth / ElementBitwidth; 94 } 95 unsigned getSizeInBits() const { 96 return Bitwidth; 97 } 98 99 /// Return the string representation of a type, which is an encoded 100 /// string for passing to the BUILTIN() macro in Builtins.def. 101 std::string builtin_str() const; 102 103 /// Return the C/C++ string representation of a type for use in the 104 /// arm_sve.h header file. 105 std::string str() const; 106 107 private: 108 /// Creates the type based on the typespec string in TS. 109 void applyTypespec(); 110 111 /// Applies a prototype modifier to the type. 112 void applyModifier(char Mod); 113 }; 114 115 116 class SVEEmitter; 117 118 /// The main grunt class. This represents an instantiation of an intrinsic with 119 /// a particular typespec and prototype. 120 class Intrinsic { 121 /// The unmangled name. 122 std::string Name; 123 124 /// The name of the corresponding LLVM IR intrinsic. 125 std::string LLVMName; 126 127 /// Intrinsic prototype. 128 std::string Proto; 129 130 /// The base type spec for this intrinsic. 131 TypeSpec BaseTypeSpec; 132 133 /// The base class kind. Most intrinsics use ClassS, which has full type 134 /// info for integers (_s32/_u32), or ClassG which is used for overloaded 135 /// intrinsics. 136 ClassKind Class; 137 138 /// The architectural #ifdef guard. 139 std::string Guard; 140 141 /// The types of return value [0] and parameters [1..]. 142 std::vector<SVEType> Types; 143 144 /// The "base type", which is VarType('d', BaseTypeSpec). 145 SVEType BaseType; 146 147 unsigned Flags; 148 149 public: 150 /// The type of predication. 151 enum MergeType { 152 MergeNone, 153 MergeAny, 154 MergeOp1, 155 MergeZero, 156 MergeAnyExp, 157 MergeZeroExp, 158 MergeInvalid 159 } Merge; 160 161 Intrinsic(StringRef Name, StringRef Proto, int64_t MT, StringRef LLVMName, 162 unsigned Flags, TypeSpec BT, ClassKind Class, SVEEmitter &Emitter, 163 StringRef Guard) 164 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), 165 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), BaseType(BT, 'd'), 166 Flags(Flags), Merge(MergeType(MT)) { 167 // Types[0] is the return value. 168 for (unsigned I = 0; I < Proto.size(); ++I) 169 Types.emplace_back(BaseTypeSpec, Proto[I]); 170 } 171 172 ~Intrinsic()=default; 173 174 std::string getName() const { return Name; } 175 std::string getLLVMName() const { return LLVMName; } 176 std::string getProto() const { return Proto; } 177 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; } 178 SVEType getBaseType() const { return BaseType; } 179 180 StringRef getGuard() const { return Guard; } 181 ClassKind getClassKind() const { return Class; } 182 MergeType getMergeType() const { return Merge; } 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 unsigned getFlags() const { return Flags; } 190 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;} 191 192 /// Return the type string for a BUILTIN() macro in Builtins.def. 193 std::string getBuiltinTypeStr(); 194 195 /// Return the name, mangled with type information. The name is mangled for 196 /// ClassS, so will add type suffixes such as _u32/_s32. 197 std::string getMangledName() const { return mangleName(ClassS); } 198 199 /// Returns true if the intrinsic is overloaded, in that it should also generate 200 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of 201 /// 'svld1_u32(..)'. 202 static bool isOverloadedIntrinsic(StringRef Name) { 203 auto BrOpen = Name.find("["); 204 auto BrClose = Name.find(']'); 205 return BrOpen != std::string::npos && BrClose != std::string::npos; 206 } 207 208 /// Emits the intrinsic declaration to the ostream. 209 void emitIntrinsic(raw_ostream &OS) const; 210 211 private: 212 std::string getMergeSuffix() const; 213 std::string mangleName(ClassKind LocalCK) const; 214 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS, 215 std::string Proto) const; 216 }; 217 218 class SVEEmitter { 219 private: 220 RecordKeeper &Records; 221 llvm::StringMap<uint64_t> EltTypes; 222 llvm::StringMap<uint64_t> MemEltTypes; 223 llvm::StringMap<uint64_t> FlagTypes; 224 225 unsigned getTypeFlags(const SVEType &T); 226 public: 227 SVEEmitter(RecordKeeper &R) : Records(R) { 228 for (auto *RV : Records.getAllDerivedDefinitions("EltType")) 229 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 230 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType")) 231 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 232 for (auto *RV : Records.getAllDerivedDefinitions("FlagType")) 233 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 234 } 235 236 /// Emit arm_sve.h. 237 void createHeader(raw_ostream &o); 238 239 /// Emit all the __builtin prototypes and code needed by Sema. 240 void createBuiltins(raw_ostream &o); 241 242 /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 243 void createCodeGenMap(raw_ostream &o); 244 245 /// Create the SVETypeFlags used in CGBuiltins 246 void createTypeFlags(raw_ostream &o); 247 248 /// Create intrinsic and add it to \p Out 249 void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out); 250 }; 251 252 } // end anonymous namespace 253 254 255 //===----------------------------------------------------------------------===// 256 // Type implementation 257 //===----------------------------------------------------------------------===// 258 259 unsigned SVEEmitter::getTypeFlags(const SVEType &T) { 260 unsigned FirstEltType = EltTypes["FirstEltType"]; 261 if (T.isFloat()) { 262 switch (T.getElementSizeInBits()) { 263 case 16: return FirstEltType + EltTypes["EltTyFloat16"]; 264 case 32: return FirstEltType + EltTypes["EltTyFloat32"]; 265 case 64: return FirstEltType + EltTypes["EltTyFloat64"]; 266 default: llvm_unreachable("Unhandled float element bitwidth!"); 267 } 268 } 269 270 if (T.isPredicateVector()) { 271 switch (T.getElementSizeInBits()) { 272 case 8: return FirstEltType + EltTypes["EltTyBool8"]; 273 case 16: return FirstEltType + EltTypes["EltTyBool16"]; 274 case 32: return FirstEltType + EltTypes["EltTyBool32"]; 275 case 64: return FirstEltType + EltTypes["EltTyBool64"]; 276 default: llvm_unreachable("Unhandled predicate element bitwidth!"); 277 } 278 } 279 280 switch (T.getElementSizeInBits()) { 281 case 8: return FirstEltType + EltTypes["EltTyInt8"]; 282 case 16: return FirstEltType + EltTypes["EltTyInt16"]; 283 case 32: return FirstEltType + EltTypes["EltTyInt32"]; 284 case 64: return FirstEltType + EltTypes["EltTyInt64"]; 285 default: llvm_unreachable("Unhandled integer element bitwidth!"); 286 } 287 } 288 289 std::string SVEType::builtin_str() const { 290 std::string S; 291 if (isVoid()) 292 return "v"; 293 294 if (isVoidPointer()) 295 S += "v"; 296 else if (!Float) 297 switch (ElementBitwidth) { 298 case 1: S += "b"; break; 299 case 8: S += "c"; break; 300 case 16: S += "s"; break; 301 case 32: S += "i"; break; 302 case 64: S += "Wi"; break; 303 case 128: S += "LLLi"; break; 304 default: llvm_unreachable("Unhandled case!"); 305 } 306 else 307 switch (ElementBitwidth) { 308 case 16: S += "h"; break; 309 case 32: S += "f"; break; 310 case 64: S += "d"; break; 311 default: llvm_unreachable("Unhandled case!"); 312 } 313 314 if (!isFloat()) { 315 if ((isChar() || isPointer()) && !isVoidPointer()) { 316 // Make chars and typed pointers explicitly signed. 317 if (Signed) 318 S = "S" + S; 319 else if (!Signed) 320 S = "U" + S; 321 } else if (!isVoidPointer() && !Signed) { 322 S = "U" + S; 323 } 324 } 325 326 // Constant indices are "int", but have the "constant expression" modifier. 327 if (isImmediate()) { 328 assert(!isFloat() && "fp immediates are not supported"); 329 S = "I" + S; 330 } 331 332 if (isScalar()) { 333 if (Constant) S += "C"; 334 if (Pointer) S += "*"; 335 return S; 336 } 337 338 assert(isScalableVector() && "Unsupported type"); 339 return "q" + utostr(getNumElements() * NumVectors) + S; 340 } 341 342 std::string SVEType::str() const { 343 if (isPredicatePattern()) 344 return "sv_pattern"; 345 346 if (isPrefetchOp()) 347 return "sv_prfop"; 348 349 std::string S; 350 if (Void) 351 S += "void"; 352 else { 353 if (isScalableVector()) 354 S += "sv"; 355 if (!Signed && !Float) 356 S += "u"; 357 358 if (Float) 359 S += "float"; 360 else if (isScalarPredicate()) 361 S += "bool"; 362 else 363 S += "int"; 364 365 if (!isScalarPredicate()) 366 S += utostr(ElementBitwidth); 367 if (!isScalableVector() && isVector()) 368 S += "x" + utostr(getNumElements()); 369 if (NumVectors > 1) 370 S += "x" + utostr(NumVectors); 371 S += "_t"; 372 } 373 374 if (Constant) 375 S += " const"; 376 if (Pointer) 377 S += " *"; 378 379 return S; 380 } 381 void SVEType::applyTypespec() { 382 for (char I : TS) { 383 switch (I) { 384 case 'P': 385 Predicate = true; 386 ElementBitwidth = 1; 387 break; 388 case 'U': 389 Signed = false; 390 break; 391 case 'c': 392 ElementBitwidth = 8; 393 break; 394 case 's': 395 ElementBitwidth = 16; 396 break; 397 case 'i': 398 ElementBitwidth = 32; 399 break; 400 case 'l': 401 ElementBitwidth = 64; 402 break; 403 case 'h': 404 Float = true; 405 ElementBitwidth = 16; 406 break; 407 case 'f': 408 Float = true; 409 ElementBitwidth = 32; 410 break; 411 case 'd': 412 Float = true; 413 ElementBitwidth = 64; 414 break; 415 default: 416 llvm_unreachable("Unhandled type code!"); 417 } 418 } 419 assert(ElementBitwidth != ~0U && "Bad element bitwidth!"); 420 } 421 422 void SVEType::applyModifier(char Mod) { 423 switch (Mod) { 424 case 'v': 425 Void = true; 426 break; 427 case 'd': 428 DefaultType = true; 429 break; 430 case 'c': 431 Constant = true; 432 LLVM_FALLTHROUGH; 433 case 'p': 434 Pointer = true; 435 Bitwidth = ElementBitwidth; 436 NumVectors = 0; 437 break; 438 case 'P': 439 Signed = true; 440 Float = false; 441 Predicate = true; 442 Bitwidth = 16; 443 ElementBitwidth = 1; 444 break; 445 default: 446 llvm_unreachable("Unhandled character!"); 447 } 448 } 449 450 451 //===----------------------------------------------------------------------===// 452 // Intrinsic implementation 453 //===----------------------------------------------------------------------===// 454 455 std::string Intrinsic::getBuiltinTypeStr() { 456 std::string S; 457 458 SVEType RetT = getReturnType(); 459 // Since the return value must be one type, return a vector type of the 460 // appropriate width which we will bitcast. An exception is made for 461 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like 462 // fashion, storing them to a pointer arg. 463 if (RetT.getNumVectors() > 1) { 464 S += "vv*"; // void result with void* first argument 465 } else 466 S += RetT.builtin_str(); 467 468 for (unsigned I = 0; I < getNumParams(); ++I) 469 S += getParamType(I).builtin_str(); 470 471 return S; 472 } 473 474 std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, 475 std::string Proto) const { 476 std::string Ret = Name; 477 while (Ret.find('{') != std::string::npos) { 478 size_t Pos = Ret.find('{'); 479 size_t End = Ret.find('}'); 480 unsigned NumChars = End - Pos + 1; 481 assert(NumChars == 3 && "Unexpected template argument"); 482 483 SVEType T; 484 char C = Ret[Pos+1]; 485 switch(C) { 486 default: 487 llvm_unreachable("Unknown predication specifier"); 488 case 'd': 489 T = SVEType(TS, 'd'); 490 break; 491 case '0': 492 case '1': 493 case '2': 494 case '3': 495 T = SVEType(TS, Proto[C - '0']); 496 break; 497 } 498 499 // Replace templated arg with the right suffix (e.g. u32) 500 std::string TypeCode; 501 if (T.isInteger()) 502 TypeCode = T.isSigned() ? 's' : 'u'; 503 else if (T.isPredicateVector()) 504 TypeCode = 'b'; 505 else 506 TypeCode = 'f'; 507 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits())); 508 } 509 510 return Ret; 511 } 512 513 // ACLE function names have a merge style postfix. 514 std::string Intrinsic::getMergeSuffix() const { 515 switch (getMergeType()) { 516 default: 517 llvm_unreachable("Unknown predication specifier"); 518 case MergeNone: return ""; 519 case MergeAny: 520 case MergeAnyExp: return "_x"; 521 case MergeOp1: return "_m"; 522 case MergeZero: 523 case MergeZeroExp: return "_z"; 524 } 525 } 526 527 std::string Intrinsic::mangleName(ClassKind LocalCK) const { 528 std::string S = getName(); 529 530 if (LocalCK == ClassG) { 531 // Remove the square brackets and everything in between. 532 while (S.find("[") != std::string::npos) { 533 auto Start = S.find("["); 534 auto End = S.find(']'); 535 S.erase(Start, (End-Start)+1); 536 } 537 } else { 538 // Remove the square brackets. 539 while (S.find("[") != std::string::npos) { 540 auto BrPos = S.find('['); 541 if (BrPos != std::string::npos) 542 S.erase(BrPos, 1); 543 BrPos = S.find(']'); 544 if (BrPos != std::string::npos) 545 S.erase(BrPos, 1); 546 } 547 } 548 549 // Replace all {d} like expressions with e.g. 'u32' 550 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) + 551 getMergeSuffix(); 552 } 553 554 void Intrinsic::emitIntrinsic(raw_ostream &OS) const { 555 // Use the preprocessor to 556 if (getClassKind() != ClassG || getProto().size() <= 1) { 557 OS << "#define " << mangleName(getClassKind()) 558 << "(...) __builtin_sve_" << mangleName(ClassS) 559 << "(__VA_ARGS__)\n"; 560 } else { 561 std::string FullName = mangleName(ClassS); 562 std::string ProtoName = mangleName(ClassG); 563 564 OS << "__aio __attribute__((__clang_arm_builtin_alias(" 565 << "__builtin_sve_" << FullName << ")))\n"; 566 567 OS << getTypes()[0].str() << " " << ProtoName << "("; 568 for (unsigned I = 0; I < getTypes().size() - 1; ++I) { 569 if (I != 0) 570 OS << ", "; 571 OS << getTypes()[I + 1].str(); 572 } 573 OS << ");\n"; 574 } 575 } 576 577 //===----------------------------------------------------------------------===// 578 // SVEEmitter implementation 579 //===----------------------------------------------------------------------===// 580 void SVEEmitter::createIntrinsic( 581 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) { 582 StringRef Name = R->getValueAsString("Name"); 583 StringRef Proto = R->getValueAsString("Prototype"); 584 StringRef Types = R->getValueAsString("Types"); 585 StringRef Guard = R->getValueAsString("ArchGuard"); 586 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic"); 587 int64_t Merge = R->getValueAsInt("Merge"); 588 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags"); 589 590 int64_t Flags = 0; 591 for (auto FlagRec : FlagsList) 592 Flags |= FlagRec->getValueAsInt("Value"); 593 Flags |= R->getValueAsInt("MemEltType") + MemEltTypes["FirstMemEltType"]; 594 595 // Extract type specs from string 596 SmallVector<TypeSpec, 8> TypeSpecs; 597 TypeSpec Acc; 598 for (char I : Types) { 599 Acc.push_back(I); 600 if (islower(I)) { 601 TypeSpecs.push_back(TypeSpec(Acc)); 602 Acc.clear(); 603 } 604 } 605 606 // Remove duplicate type specs. 607 llvm::sort(TypeSpecs); 608 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()), 609 TypeSpecs.end()); 610 611 // Create an Intrinsic for each type spec. 612 for (auto TS : TypeSpecs) { 613 Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge, 614 LLVMName, Flags, TS, ClassS, 615 *this, Guard)); 616 617 // Also generate the short-form (e.g. svadd_m) for the given type-spec. 618 if (Intrinsic::isOverloadedIntrinsic(Name)) 619 Out.push_back(std::make_unique<Intrinsic>( 620 Name, Proto, Merge, LLVMName, Flags, TS, ClassG, *this, Guard)); 621 } 622 } 623 624 void SVEEmitter::createHeader(raw_ostream &OS) { 625 OS << "/*===---- arm_sve.h - ARM SVE intrinsics " 626 "-----------------------------------===\n" 627 " *\n" 628 " *\n" 629 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 630 "Exceptions.\n" 631 " * See https://llvm.org/LICENSE.txt for license information.\n" 632 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 633 " *\n" 634 " *===-----------------------------------------------------------------" 635 "------===\n" 636 " */\n\n"; 637 638 OS << "#ifndef __ARM_SVE_H\n"; 639 OS << "#define __ARM_SVE_H\n\n"; 640 641 OS << "#if !defined(__ARM_FEATURE_SVE)\n"; 642 OS << "#error \"SVE support not enabled\"\n"; 643 OS << "#else\n\n"; 644 645 OS << "#include <stdint.h>\n\n"; 646 OS << "#ifdef __cplusplus\n"; 647 OS << "extern \"C\" {\n"; 648 OS << "#else\n"; 649 OS << "#include <stdbool.h>\n"; 650 OS << "#endif\n\n"; 651 652 OS << "typedef __fp16 float16_t;\n"; 653 OS << "typedef float float32_t;\n"; 654 OS << "typedef double float64_t;\n"; 655 OS << "typedef bool bool_t;\n\n"; 656 657 OS << "typedef __SVInt8_t svint8_t;\n"; 658 OS << "typedef __SVInt16_t svint16_t;\n"; 659 OS << "typedef __SVInt32_t svint32_t;\n"; 660 OS << "typedef __SVInt64_t svint64_t;\n"; 661 OS << "typedef __SVUint8_t svuint8_t;\n"; 662 OS << "typedef __SVUint16_t svuint16_t;\n"; 663 OS << "typedef __SVUint32_t svuint32_t;\n"; 664 OS << "typedef __SVUint64_t svuint64_t;\n"; 665 OS << "typedef __SVFloat16_t svfloat16_t;\n"; 666 OS << "typedef __SVFloat32_t svfloat32_t;\n"; 667 OS << "typedef __SVFloat64_t svfloat64_t;\n"; 668 OS << "typedef __SVBool_t svbool_t;\n\n"; 669 670 OS << "/* Function attributes */\n"; 671 OS << "#define __aio static inline __attribute__((__always_inline__, " 672 "__nodebug__, __overloadable__))\n\n"; 673 674 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 675 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 676 for (auto *R : RV) 677 createIntrinsic(R, Defs); 678 679 // Sort intrinsics in header file by following order/priority: 680 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES) 681 // - Class (is intrinsic overloaded or not) 682 // - Intrinsic name 683 std::stable_sort( 684 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A, 685 const std::unique_ptr<Intrinsic> &B) { 686 return A->getGuard() < B->getGuard() || 687 (unsigned)A->getClassKind() < (unsigned)B->getClassKind() || 688 A->getName() < B->getName(); 689 }); 690 691 StringRef InGuard = ""; 692 for (auto &I : Defs) { 693 // Emit #endif/#if pair if needed. 694 if (I->getGuard() != InGuard) { 695 if (!InGuard.empty()) 696 OS << "#endif //" << InGuard << "\n"; 697 InGuard = I->getGuard(); 698 if (!InGuard.empty()) 699 OS << "\n#if " << InGuard << "\n"; 700 } 701 702 // Actually emit the intrinsic declaration. 703 I->emitIntrinsic(OS); 704 } 705 706 if (!InGuard.empty()) 707 OS << "#endif //" << InGuard << "\n"; 708 709 OS << "#ifdef __cplusplus\n"; 710 OS << "} // extern \"C\"\n"; 711 OS << "#endif\n\n"; 712 OS << "#endif /*__ARM_FEATURE_SVE */\n\n"; 713 OS << "#endif /* __ARM_SVE_H */\n"; 714 } 715 716 void SVEEmitter::createBuiltins(raw_ostream &OS) { 717 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 718 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 719 for (auto *R : RV) 720 createIntrinsic(R, Defs); 721 722 // The mappings must be sorted based on BuiltinID. 723 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 724 const std::unique_ptr<Intrinsic> &B) { 725 return A->getMangledName() < B->getMangledName(); 726 }); 727 728 OS << "#ifdef GET_SVE_BUILTINS\n"; 729 for (auto &Def : Defs) { 730 // Only create BUILTINs for non-overloaded intrinsics, as overloaded 731 // declarations only live in the header file. 732 if (Def->getClassKind() != ClassG) 733 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \"" 734 << Def->getBuiltinTypeStr() << "\", \"n\")\n"; 735 } 736 OS << "#endif\n\n"; 737 } 738 739 void SVEEmitter::createCodeGenMap(raw_ostream &OS) { 740 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 741 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 742 for (auto *R : RV) 743 createIntrinsic(R, Defs); 744 745 // The mappings must be sorted based on BuiltinID. 746 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 747 const std::unique_ptr<Intrinsic> &B) { 748 return A->getMangledName() < B->getMangledName(); 749 }); 750 751 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n"; 752 for (auto &Def : Defs) { 753 // Builtins only exist for non-overloaded intrinsics, overloaded 754 // declarations only live in the header file. 755 if (Def->getClassKind() == ClassG) 756 continue; 757 758 uint64_t Flags = Def->getFlags() | getTypeFlags(Def->getBaseType()); 759 auto FlagString = std::to_string(Flags); 760 761 std::string LLVMName = Def->getLLVMName(); 762 std::string Builtin = Def->getMangledName(); 763 if (!LLVMName.empty()) 764 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString 765 << "),\n"; 766 else 767 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n"; 768 } 769 OS << "#endif\n\n"; 770 } 771 772 /// Create the SVETypeFlags used in CGBuiltins 773 void SVEEmitter::createTypeFlags(raw_ostream &OS) { 774 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n"; 775 for (auto &KV : FlagTypes) 776 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n"; 777 OS << "#endif\n\n"; 778 779 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n"; 780 for (auto &KV : EltTypes) 781 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 782 OS << "#endif\n\n"; 783 784 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n"; 785 for (auto &KV : MemEltTypes) 786 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 787 OS << "#endif\n\n"; 788 } 789 790 namespace clang { 791 void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) { 792 SVEEmitter(Records).createHeader(OS); 793 } 794 795 void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) { 796 SVEEmitter(Records).createBuiltins(OS); 797 } 798 799 void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 800 SVEEmitter(Records).createCodeGenMap(OS); 801 } 802 void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) { 803 SVEEmitter(Records).createTypeFlags(OS); 804 } 805 806 } // End namespace clang 807