1 //===- RuntimeLibcallEmitter.cpp - Properties from RuntimeLibcalls.td -----===// 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 #include "llvm/ADT/StringRef.h" 10 #include "llvm/Support/Debug.h" 11 #include "llvm/Support/raw_ostream.h" 12 #include "llvm/TableGen/Error.h" 13 #include "llvm/TableGen/Record.h" 14 #include "llvm/TableGen/SetTheory.h" 15 #include "llvm/TableGen/TableGenBackend.h" 16 17 using namespace llvm; 18 19 namespace { 20 // Pair of a RuntimeLibcallPredicate and LibcallCallingConv to use as a map key. 21 struct PredicateWithCC { 22 const Record *Predicate = nullptr; 23 const Record *CallingConv = nullptr; 24 25 PredicateWithCC() = default; 26 PredicateWithCC(std::pair<const Record *, const Record *> P) 27 : Predicate(P.first), CallingConv(P.second) {} 28 29 PredicateWithCC(const Record *P, const Record *C) 30 : Predicate(P), CallingConv(C) {} 31 }; 32 33 inline bool operator==(PredicateWithCC LHS, PredicateWithCC RHS) { 34 return LHS.Predicate == RHS.Predicate && LHS.CallingConv == RHS.CallingConv; 35 } 36 } // namespace 37 38 namespace llvm { 39 template <> struct DenseMapInfo<PredicateWithCC, void> { 40 static inline PredicateWithCC getEmptyKey() { 41 return DenseMapInfo< 42 std::pair<const Record *, const Record *>>::getEmptyKey(); 43 } 44 45 static inline PredicateWithCC getTombstoneKey() { 46 return DenseMapInfo< 47 std::pair<const Record *, const Record *>>::getTombstoneKey(); 48 } 49 50 static unsigned getHashValue(const PredicateWithCC Val) { 51 auto Pair = std::make_pair(Val.Predicate, Val.CallingConv); 52 return DenseMapInfo< 53 std::pair<const Record *, const Record *>>::getHashValue(Pair); 54 } 55 56 static bool isEqual(PredicateWithCC LHS, PredicateWithCC RHS) { 57 return LHS == RHS; 58 } 59 }; 60 } // namespace llvm 61 62 namespace { 63 64 class AvailabilityPredicate { 65 const Record *TheDef; 66 StringRef PredicateString; 67 68 public: 69 AvailabilityPredicate(const Record *Def) : TheDef(Def) { 70 if (TheDef) 71 PredicateString = TheDef->getValueAsString("Cond"); 72 } 73 74 const Record *getDef() const { return TheDef; } 75 76 bool isAlwaysAvailable() const { return PredicateString.empty(); } 77 78 void emitIf(raw_ostream &OS) const { 79 OS << "if (" << PredicateString << ") {\n"; 80 } 81 82 void emitEndIf(raw_ostream &OS) const { OS << "}\n"; } 83 84 void emitTableVariableNameSuffix(raw_ostream &OS) const { 85 if (TheDef) 86 OS << '_' << TheDef->getName(); 87 } 88 }; 89 90 class RuntimeLibcallEmitter; 91 class RuntimeLibcallImpl; 92 93 /// Used to apply predicates to nested sets of libcalls. 94 struct LibcallPredicateExpander : SetTheory::Expander { 95 const RuntimeLibcallEmitter &LibcallEmitter; 96 DenseMap<const RuntimeLibcallImpl *, 97 std::pair<std::vector<const Record *>, const Record *>> &Func2Preds; 98 99 LibcallPredicateExpander( 100 const RuntimeLibcallEmitter &LibcallEmitter, 101 DenseMap<const RuntimeLibcallImpl *, 102 std::pair<std::vector<const Record *>, const Record *>> 103 &Func2Preds) 104 : LibcallEmitter(LibcallEmitter), Func2Preds(Func2Preds) {} 105 106 void expand(SetTheory &ST, const Record *Def, 107 SetTheory::RecSet &Elts) override; 108 }; 109 110 class RuntimeLibcall { 111 const Record *TheDef = nullptr; 112 const size_t EnumVal; 113 114 public: 115 RuntimeLibcall() = delete; 116 RuntimeLibcall(const Record *Def, size_t EnumVal) 117 : TheDef(Def), EnumVal(EnumVal) { 118 assert(Def); 119 } 120 121 ~RuntimeLibcall() { assert(TheDef); } 122 123 const Record *getDef() const { return TheDef; } 124 125 StringRef getName() const { return TheDef->getName(); } 126 127 size_t getEnumVal() const { return EnumVal; } 128 129 void emitEnumEntry(raw_ostream &OS) const { 130 OS << "RTLIB::" << TheDef->getValueAsString("Name"); 131 } 132 }; 133 134 class RuntimeLibcallImpl { 135 const Record *TheDef; 136 const RuntimeLibcall *Provides = nullptr; 137 const size_t EnumVal; 138 139 public: 140 RuntimeLibcallImpl( 141 const Record *Def, 142 const DenseMap<const Record *, const RuntimeLibcall *> &ProvideMap, 143 size_t EnumVal) 144 : TheDef(Def), EnumVal(EnumVal) { 145 if (const Record *ProvidesDef = Def->getValueAsDef("Provides")) 146 Provides = ProvideMap.lookup(ProvidesDef); 147 } 148 149 ~RuntimeLibcallImpl() {} 150 151 const Record *getDef() const { return TheDef; } 152 153 StringRef getName() const { return TheDef->getName(); } 154 155 size_t getEnumVal() const { return EnumVal; } 156 157 const RuntimeLibcall *getProvides() const { return Provides; } 158 159 StringRef getLibcallFuncName() const { 160 return TheDef->getValueAsString("LibCallFuncName"); 161 } 162 163 const Record *getCallingConv() const { 164 return TheDef->getValueAsOptionalDef("CallingConv"); 165 } 166 167 void emitQuotedLibcallFuncName(raw_ostream &OS) const { 168 OS << '\"' << getLibcallFuncName() << '\"'; 169 } 170 171 bool isDefault() const { return TheDef->getValueAsBit("IsDefault"); } 172 173 void emitEnumEntry(raw_ostream &OS) const { 174 OS << "RTLIB::" << TheDef->getName(); 175 } 176 177 void emitSetImplCall(raw_ostream &OS) const { 178 OS << "setLibcallImpl("; 179 Provides->emitEnumEntry(OS); 180 OS << ", "; 181 emitEnumEntry(OS); 182 OS << "); // " << getLibcallFuncName() << '\n'; 183 } 184 185 void emitTableEntry(raw_ostream &OS) const { 186 OS << '{'; 187 Provides->emitEnumEntry(OS); 188 OS << ", "; 189 emitEnumEntry(OS); 190 OS << "}, // " << getLibcallFuncName() << '\n'; 191 } 192 193 void emitSetCallingConv(raw_ostream &OS) const {} 194 }; 195 196 struct LibcallsWithCC { 197 std::vector<const RuntimeLibcallImpl *> LibcallImpls; 198 const Record *CallingConv = nullptr; 199 }; 200 201 class RuntimeLibcallEmitter { 202 private: 203 const RecordKeeper &Records; 204 DenseMap<const Record *, const RuntimeLibcall *> Def2RuntimeLibcall; 205 DenseMap<const Record *, const RuntimeLibcallImpl *> Def2RuntimeLibcallImpl; 206 207 std::vector<RuntimeLibcall> RuntimeLibcallDefList; 208 std::vector<RuntimeLibcallImpl> RuntimeLibcallImplDefList; 209 210 DenseMap<const RuntimeLibcall *, const RuntimeLibcallImpl *> 211 LibCallToDefaultImpl; 212 213 private: 214 void emitGetRuntimeLibcallEnum(raw_ostream &OS) const; 215 216 void emitGetInitRuntimeLibcallNames(raw_ostream &OS) const; 217 218 void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const; 219 220 public: 221 RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R) { 222 223 ArrayRef<const Record *> AllRuntimeLibcalls = 224 Records.getAllDerivedDefinitions("RuntimeLibcall"); 225 226 RuntimeLibcallDefList.reserve(AllRuntimeLibcalls.size()); 227 228 size_t CallTypeEnumVal = 0; 229 for (const Record *RuntimeLibcallDef : AllRuntimeLibcalls) { 230 RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef, CallTypeEnumVal++); 231 Def2RuntimeLibcall[RuntimeLibcallDef] = &RuntimeLibcallDefList.back(); 232 } 233 234 for (RuntimeLibcall &LibCall : RuntimeLibcallDefList) 235 Def2RuntimeLibcall[LibCall.getDef()] = &LibCall; 236 237 ArrayRef<const Record *> AllRuntimeLibcallImpls = 238 Records.getAllDerivedDefinitions("RuntimeLibcallImpl"); 239 RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size()); 240 241 size_t LibCallImplEnumVal = 1; 242 for (const Record *LibCallImplDef : AllRuntimeLibcallImpls) { 243 RuntimeLibcallImplDefList.emplace_back(LibCallImplDef, Def2RuntimeLibcall, 244 LibCallImplEnumVal++); 245 246 RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back(); 247 248 Def2RuntimeLibcallImpl[LibCallImplDef] = &LibCallImpl; 249 250 // const RuntimeLibcallImpl &LibCallImpl = 251 // RuntimeLibcallImplDefList.back(); 252 if (LibCallImpl.isDefault()) { 253 const RuntimeLibcall *Provides = LibCallImpl.getProvides(); 254 if (!Provides) 255 PrintFatalError(LibCallImplDef->getLoc(), 256 "default implementations must provide a libcall"); 257 LibCallToDefaultImpl[Provides] = &LibCallImpl; 258 } 259 } 260 } 261 262 const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const { 263 return Def2RuntimeLibcall.lookup(Def); 264 } 265 266 const RuntimeLibcallImpl *getRuntimeLibcallImpl(const Record *Def) const { 267 return Def2RuntimeLibcallImpl.lookup(Def); 268 } 269 270 void run(raw_ostream &OS); 271 }; 272 273 } // End anonymous namespace. 274 275 void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const { 276 OS << "#ifdef GET_RUNTIME_LIBCALL_ENUM\n" 277 "namespace llvm {\n" 278 "namespace RTLIB {\n" 279 "enum Libcall : unsigned short {\n"; 280 281 for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) { 282 StringRef Name = LibCall.getName(); 283 OS << " " << Name << " = " << LibCall.getEnumVal() << ",\n"; 284 } 285 286 // TODO: Emit libcall names as string offset table. 287 288 OS << " UNKNOWN_LIBCALL = " << RuntimeLibcallDefList.size() 289 << "\n};\n\n" 290 "enum LibcallImpl : unsigned short {\n" 291 " Unsupported = 0,\n"; 292 293 // FIXME: Emit this in a different namespace. And maybe use enum class. 294 for (const RuntimeLibcallImpl &LibCall : RuntimeLibcallImplDefList) { 295 OS << " " << LibCall.getName() << " = " << LibCall.getEnumVal() << ", // " 296 << LibCall.getLibcallFuncName() << '\n'; 297 } 298 299 OS << " NumLibcallImpls = " << RuntimeLibcallImplDefList.size() + 1 300 << "\n};\n" 301 "} // End namespace RTLIB\n" 302 "} // End namespace llvm\n" 303 "#endif\n\n"; 304 } 305 306 void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames( 307 raw_ostream &OS) const { 308 // TODO: Emit libcall names as string offset table. 309 310 OS << "const RTLIB::LibcallImpl " 311 "llvm::RTLIB::RuntimeLibcallsInfo::" 312 "DefaultLibcallImpls[RTLIB::UNKNOWN_LIBCALL + 1] = {\n"; 313 314 for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) { 315 auto I = LibCallToDefaultImpl.find(&LibCall); 316 if (I == LibCallToDefaultImpl.end()) { 317 OS << " RTLIB::Unsupported,"; 318 } else { 319 const RuntimeLibcallImpl *LibCallImpl = I->second; 320 OS << " "; 321 LibCallImpl->emitEnumEntry(OS); 322 OS << ','; 323 } 324 325 OS << " // "; 326 LibCall.emitEnumEntry(OS); 327 OS << '\n'; 328 } 329 330 OS << " RTLIB::Unsupported\n" 331 "};\n\n"; 332 333 // Emit the implementation names 334 OS << "const char *const llvm::RTLIB::RuntimeLibcallsInfo::" 335 "LibCallImplNames[RTLIB::NumLibcallImpls] = {\n" 336 " nullptr, // RTLIB::Unsupported\n"; 337 338 for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) { 339 OS << " \"" << LibCallImpl.getLibcallFuncName() << "\", // "; 340 LibCallImpl.emitEnumEntry(OS); 341 OS << '\n'; 342 } 343 344 OS << "};\n\n"; 345 346 // Emit the reverse mapping from implementation libraries to RTLIB::Libcall 347 OS << "const RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::" 348 "ImplToLibcall[RTLIB::NumLibcallImpls] = {\n" 349 " RTLIB::UNKNOWN_LIBCALL, // RTLIB::Unsupported\n"; 350 351 for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) { 352 const RuntimeLibcall *Provides = LibCallImpl.getProvides(); 353 OS << " "; 354 Provides->emitEnumEntry(OS); 355 OS << ", // "; 356 LibCallImpl.emitEnumEntry(OS); 357 OS << '\n'; 358 } 359 OS << "};\n\n"; 360 } 361 362 void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls( 363 raw_ostream &OS) const { 364 OS << "void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets(" 365 "const llvm::Triple &TT, FloatABI::ABIType FloatABI) {\n" 366 " struct LibcallImplPair {\n" 367 " RTLIB::Libcall Func;\n" 368 " RTLIB::LibcallImpl Impl;\n" 369 " };\n"; 370 ArrayRef<const Record *> AllLibs = 371 Records.getAllDerivedDefinitions("SystemRuntimeLibrary"); 372 373 for (const Record *R : AllLibs) { 374 OS << '\n'; 375 376 AvailabilityPredicate TopLevelPredicate(R->getValueAsDef("TriplePred")); 377 378 OS << indent(2); 379 TopLevelPredicate.emitIf(OS); 380 381 if (const Record *DefaultCCClass = 382 R->getValueAsDef("DefaultLibcallCallingConv")) { 383 StringRef DefaultCC = 384 DefaultCCClass->getValueAsString("CallingConv").trim(); 385 386 if (!DefaultCC.empty()) { 387 OS << " const CallingConv::ID DefaultCC = " << DefaultCC << ";\n" 388 << " for (CallingConv::ID &Entry : LibcallImplCallingConvs) {\n" 389 " Entry = DefaultCC;\n" 390 " }\n\n"; 391 } 392 } 393 394 SetTheory Sets; 395 396 DenseMap<const RuntimeLibcallImpl *, 397 std::pair<std::vector<const Record *>, const Record *>> 398 Func2Preds; 399 Sets.addExpander("LibcallImpls", std::make_unique<LibcallPredicateExpander>( 400 *this, Func2Preds)); 401 402 const SetTheory::RecVec *Elements = 403 Sets.expand(R->getValueAsDef("MemberList")); 404 405 // Sort to get deterministic output 406 SetVector<PredicateWithCC> PredicateSorter; 407 PredicateSorter.insert( 408 PredicateWithCC()); // No predicate or CC override first. 409 410 DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs; 411 for (const Record *Elt : *Elements) { 412 const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt); 413 if (!LibCallImpl) { 414 PrintError(R, "entry for SystemLibrary is not a RuntimeLibcallImpl"); 415 PrintNote(Elt->getLoc(), "invalid entry `" + Elt->getName() + "`"); 416 continue; 417 } 418 419 auto It = Func2Preds.find(LibCallImpl); 420 if (It == Func2Preds.end()) { 421 Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(LibCallImpl); 422 continue; 423 } 424 425 for (const Record *Pred : It->second.first) { 426 const Record *CC = It->second.second; 427 PredicateWithCC Key(Pred, CC); 428 429 auto &Entry = Pred2Funcs[Key]; 430 Entry.LibcallImpls.push_back(LibCallImpl); 431 Entry.CallingConv = It->second.second; 432 PredicateSorter.insert(Key); 433 } 434 } 435 436 SmallVector<PredicateWithCC, 0> SortedPredicates = 437 PredicateSorter.takeVector(); 438 439 llvm::sort(SortedPredicates, [](PredicateWithCC A, PredicateWithCC B) { 440 StringRef AName = A.Predicate ? A.Predicate->getName() : ""; 441 StringRef BName = B.Predicate ? B.Predicate->getName() : ""; 442 return AName < BName; 443 }); 444 445 for (PredicateWithCC Entry : SortedPredicates) { 446 AvailabilityPredicate SubsetPredicate(Entry.Predicate); 447 unsigned IndentDepth = 2; 448 449 auto It = Pred2Funcs.find(Entry); 450 if (It == Pred2Funcs.end()) 451 continue; 452 453 if (!SubsetPredicate.isAlwaysAvailable()) { 454 IndentDepth = 4; 455 456 OS << indent(IndentDepth); 457 SubsetPredicate.emitIf(OS); 458 } 459 460 LibcallsWithCC &FuncsWithCC = It->second; 461 462 std::vector<const RuntimeLibcallImpl *> &Funcs = FuncsWithCC.LibcallImpls; 463 464 // Ensure we only emit a unique implementation per libcall in the 465 // selection table. 466 // 467 // FIXME: We need to generate separate functions for 468 // is-libcall-available and should-libcall-be-used to avoid this. 469 // 470 // This also makes it annoying to make use of the default set, since the 471 // entries from the default set may win over the replacements unless 472 // they are explicitly removed. 473 stable_sort(Funcs, [](const RuntimeLibcallImpl *A, 474 const RuntimeLibcallImpl *B) { 475 return A->getProvides()->getEnumVal() < B->getProvides()->getEnumVal(); 476 }); 477 478 auto UniqueI = llvm::unique( 479 Funcs, [&](const RuntimeLibcallImpl *A, const RuntimeLibcallImpl *B) { 480 if (A->getProvides() == B->getProvides()) { 481 PrintWarning(R->getLoc(), 482 Twine("conflicting implementations for libcall " + 483 A->getProvides()->getName() + ": " + 484 A->getLibcallFuncName() + ", " + 485 B->getLibcallFuncName())); 486 return true; 487 } 488 489 return false; 490 }); 491 492 Funcs.erase(UniqueI, Funcs.end()); 493 494 OS << indent(IndentDepth + 2) 495 << "static const LibcallImplPair LibraryCalls"; 496 SubsetPredicate.emitTableVariableNameSuffix(OS); 497 OS << "[] = {\n"; 498 for (const RuntimeLibcallImpl *LibCallImpl : Funcs) { 499 OS << indent(IndentDepth + 6); 500 LibCallImpl->emitTableEntry(OS); 501 } 502 503 OS << indent(IndentDepth + 2) << "};\n\n" 504 << indent(IndentDepth + 2) 505 << "for (const auto [Func, Impl] : LibraryCalls"; 506 SubsetPredicate.emitTableVariableNameSuffix(OS); 507 OS << ") {\n" 508 << indent(IndentDepth + 4) << "setLibcallImpl(Func, Impl);\n"; 509 510 if (FuncsWithCC.CallingConv) { 511 StringRef CCEnum = 512 FuncsWithCC.CallingConv->getValueAsString("CallingConv"); 513 OS << indent(IndentDepth + 4) << "setLibcallImplCallingConv(Impl, " 514 << CCEnum << ");\n"; 515 } 516 517 OS << indent(IndentDepth + 2) << "}\n"; 518 OS << '\n'; 519 520 if (!SubsetPredicate.isAlwaysAvailable()) { 521 OS << indent(IndentDepth); 522 SubsetPredicate.emitEndIf(OS); 523 OS << '\n'; 524 } 525 } 526 527 OS << indent(4) << "return;\n" << indent(2); 528 TopLevelPredicate.emitEndIf(OS); 529 } 530 531 // Fallback to the old default set for manual table entries. 532 // 533 // TODO: Remove this when targets have switched to using generated tables by 534 // default. 535 OS << " initDefaultLibCallImpls();\n"; 536 537 OS << "}\n\n"; 538 } 539 540 void RuntimeLibcallEmitter::run(raw_ostream &OS) { 541 emitSourceFileHeader("Runtime LibCalls Source Fragment", OS, Records); 542 emitGetRuntimeLibcallEnum(OS); 543 544 OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_NAMES\n"; 545 emitGetInitRuntimeLibcallNames(OS); 546 OS << "#endif\n\n"; 547 548 OS << "#ifdef GET_SET_TARGET_RUNTIME_LIBCALL_SETS\n"; 549 emitSystemRuntimeLibrarySetCalls(OS); 550 OS << "#endif\n\n"; 551 } 552 553 void LibcallPredicateExpander::expand(SetTheory &ST, const Record *Def, 554 SetTheory::RecSet &Elts) { 555 assert(Def->isSubClassOf("LibcallImpls")); 556 557 SetTheory::RecSet TmpElts; 558 559 ST.evaluate(Def->getValueInit("MemberList"), TmpElts, Def->getLoc()); 560 561 Elts.insert(TmpElts.begin(), TmpElts.end()); 562 563 AvailabilityPredicate AP(Def->getValueAsDef("AvailabilityPredicate")); 564 const Record *CCClass = Def->getValueAsOptionalDef("CallingConv"); 565 566 // This is assuming we aren't conditionally applying a calling convention to 567 // some subsets, and not another, but this doesn't appear to be used. 568 569 for (const Record *LibcallImplDef : TmpElts) { 570 const RuntimeLibcallImpl *LibcallImpl = 571 LibcallEmitter.getRuntimeLibcallImpl(LibcallImplDef); 572 if (!AP.isAlwaysAvailable() || CCClass) { 573 auto [It, Inserted] = Func2Preds.insert({LibcallImpl, {{}, CCClass}}); 574 if (!Inserted) { 575 PrintError( 576 Def, "combining nested libcall set predicates currently unhandled"); 577 } 578 579 It->second.first.push_back(AP.getDef()); 580 It->second.second = CCClass; 581 } 582 } 583 } 584 585 static TableGen::Emitter::OptClass<RuntimeLibcallEmitter> 586 X("gen-runtime-libcalls", "Generate RuntimeLibcalls"); 587