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#define DEBUG_TYPE "runtime-libcall-emitter"
10
11#include "RuntimeLibcalls.h"
12
13#include "llvm/ADT/DenseSet.h"
14#include "llvm/ADT/MapVector.h"
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/Support/Debug.h"
18#include "llvm/Support/Format.h"
19#include "llvm/Support/FormatVariadic.h"
20#include "llvm/Support/raw_ostream.h"
21#include "llvm/Support/xxhash.h"
22#include "llvm/TableGen/CodeGenHelpers.h"
23#include "llvm/TableGen/Error.h"
24#include "llvm/TableGen/Record.h"
25#include "llvm/TableGen/SetTheory.h"
26#include "llvm/TableGen/StringToOffsetTable.h"
27#include "llvm/TableGen/TableGenBackend.h"
28
29using namespace llvm;
30
31namespace {
32// Pair of a RuntimeLibcallAvailability and LibcallCallingConv to use as a map
33// key.
34struct PredicateWithCC {
35 const Record *Availability = nullptr;
36 const Record *CallingConv = nullptr;
37
38 PredicateWithCC() = default;
39 PredicateWithCC(std::pair<const Record *, const Record *> P)
40 : Availability(P.first), CallingConv(P.second) {}
41
42 PredicateWithCC(const Record *P, const Record *C)
43 : Availability(P), CallingConv(C) {}
44};
45
46inline bool operator==(PredicateWithCC LHS, PredicateWithCC RHS) {
47 return LHS.Availability == RHS.Availability &&
48 LHS.CallingConv == RHS.CallingConv;
49}
50} // namespace
51
52namespace {
53/// A floating-point libcall family parsed from a RuntimeLibcallFamily record.
54struct FPLibcallFamily {
55 StringRef Base;
56 std::vector<StringRef> Intrinsics;
57 std::vector<StringRef> VectorSuffixes;
58
59 explicit FPLibcallFamily(const Record *R)
60 : Base(R->getValueAsString(FieldName: "LibcallBase")),
61 Intrinsics(R->getValueAsListOfStrings(FieldName: "Intrinsics")),
62 VectorSuffixes(R->getValueAsListOfStrings(FieldName: "VectorSuffixes")) {}
63};
64} // namespace
65
66namespace llvm {
67template <> struct DenseMapInfo<PredicateWithCC, void> {
68 static unsigned getHashValue(const PredicateWithCC Val) {
69 auto Pair = std::make_pair(x: Val.Availability, y: Val.CallingConv);
70 return DenseMapInfo<
71 std::pair<const Record *, const Record *>>::getHashValue(PairVal: Pair);
72 }
73
74 static bool isEqual(PredicateWithCC LHS, PredicateWithCC RHS) {
75 return LHS == RHS;
76 }
77};
78
79class RuntimeLibcallEmitter {
80private:
81 const RecordKeeper &Records;
82 RuntimeLibcalls Libcalls;
83
84 void emitGetRuntimeLibcallEnum(raw_ostream &OS) const;
85
86 void emitNameMatchHashTable(raw_ostream &OS,
87 StringToOffsetTable &OffsetTable) const;
88
89 void emitGetInitRuntimeLibcallNames(raw_ostream &OS) const;
90
91 // Emit the sorted per-predicate `setAvailable` tables/loops. The
92 // always-available bucket emits at \p BaseIndent; each predicated bucket is
93 // wrapped in `if (pred)`. All calls are emitted in member context (no
94 // receiver prefix).
95 void
96 emitPredicateGroups(raw_ostream &OS, const Record *R,
97 DenseMap<PredicateWithCC, LibcallsWithCC> &Pred2Funcs,
98 SetVector<PredicateWithCC> &PredicateSorter,
99 unsigned BaseIndent) const;
100
101 // A LibraryRef opt-out: the impls a consumer drops from a shared library,
102 // plus the consumer's triple predicate.
103 struct LibraryExclusion {
104 const Record *TriplePred;
105 std::vector<const RuntimeLibcallImpl *> Impls;
106 };
107
108 // A single LibcallLibrary variant, expanded into its per-predicate impl
109 // groups. Unconditional impls are tracked separately for cross-variant
110 // deduplication. A variant is Deferred when it re-adds an impl its own
111 // consumer excludes; deferred variants are emitted after the LibraryRef
112 // exclusions so the re-add wins over the opt-out.
113 struct ExpandedLibrary {
114 const Record *Lib;
115 DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs;
116 SetVector<PredicateWithCC> PredicateSorter;
117 SetVector<const RuntimeLibcallImpl *> Unconditional;
118 bool Deferred = false;
119 };
120
121 // Emit one variant's guarded `setAvailable` block into the enclosing
122 // `setAvailableLibFuncs_<name>` function.
123 void emitLibraryVariant(raw_ostream &OS, ExpandedLibrary &EL) const;
124
125 // Emit a `setAvailableLibFuncs_<name>` member function for all LibcallLibrary
126 // defs sharing \p Name, each gated by its own availability predicate. \p
127 // Exclusions are emitted as guarded setUnavailable calls at the end.
128 void emitLibraryFunction(raw_ostream &OS, StringRef Name,
129 ArrayRef<const Record *> Libs,
130 ArrayRef<LibraryExclusion> Exclusions) const;
131
132 // Group all LibcallLibrary defs by their shared LibraryName, preserving
133 // definition order. Both the member-declaration fragment and the definitions
134 // iterate this to stay in lockstep.
135 MapVector<StringRef, std::vector<const Record *>>
136 collectLibrariesByName() const;
137
138 void emitRuntimeLibcallsInfoMemberDecls(raw_ostream &OS) const;
139
140 void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const;
141
142 DenseSet<StringRef> collectLibcallNames() const;
143
144 void checkFPLibcallFamilies(ArrayRef<FPLibcallFamily> Families,
145 const DenseSet<StringRef> &LibcallNames) const;
146
147 void emitFPLibcallSelectorDecls(raw_ostream &OS,
148 ArrayRef<FPLibcallFamily> Families) const;
149
150 void emitFPLibcallSelectors(raw_ostream &OS,
151 ArrayRef<FPLibcallFamily> Families,
152 const DenseSet<StringRef> &LibcallNames) const;
153
154 void
155 emitGetLibcallForIntrinsic(raw_ostream &OS,
156 ArrayRef<FPLibcallFamily> Families,
157 const DenseSet<StringRef> &LibcallNames) const;
158
159public:
160 RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R), Libcalls(R) {}
161
162 void run(raw_ostream &OS);
163};
164
165} // End anonymous namespace.
166
167void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const {
168 IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_ENUM");
169
170 OS << "namespace llvm {\n"
171 "namespace RTLIB {\n"
172 "enum Libcall : unsigned short {\n";
173
174 for (const RuntimeLibcall &LibCall : Libcalls.getRuntimeLibcallDefList()) {
175 StringRef Name = LibCall.getName();
176 OS << " " << Name << " = " << LibCall.getEnumVal() << ",\n";
177 }
178
179 OS << " UNKNOWN_LIBCALL = " << Libcalls.getRuntimeLibcallDefList().size()
180 << "\n};\n\n"
181 "enum LibcallImpl : unsigned short {\n"
182 " Unsupported = 0,\n";
183
184 for (const RuntimeLibcallImpl &LibCall :
185 Libcalls.getRuntimeLibcallImplDefList()) {
186 OS << " impl_" << LibCall.getName() << " = " << LibCall.getEnumVal()
187 << ", // " << LibCall.getLibcallFuncName() << '\n';
188 }
189
190 OS << "};\n"
191 << "constexpr size_t NumLibcallImpls = "
192 << Libcalls.getRuntimeLibcallImplDefList().size() + 1
193 << ";\n"
194 "} // End namespace RTLIB\n"
195 "} // End namespace llvm\n";
196}
197
198// StringMap uses xxh3_64bits, truncated to uint32_t.
199static uint64_t hash(StringRef Str) {
200 return static_cast<uint32_t>(xxh3_64bits(data: Str));
201}
202
203static void emitHashFunction(raw_ostream &OS) {
204 OS << "static inline uint64_t hash(StringRef Str) {\n"
205 " return static_cast<uint32_t>(xxh3_64bits(Str));\n"
206 "}\n\n";
207}
208
209/// Return the table size, maximum number of collisions for the set of hashes
210static std::pair<int, int>
211computePerfectHashParameters(ArrayRef<uint64_t> Hashes) {
212 // Chosen based on experimentation with llvm/benchmarks/RuntimeLibcalls.cpp
213 const int SizeOverhead = 4;
214
215 // Index derived from hash -> number of collisions.
216 DenseMap<uint64_t, int> Table;
217
218 unsigned NumHashes = Hashes.size();
219
220 for (int MaxCollisions = 1;; ++MaxCollisions) {
221 for (unsigned N = NextPowerOf2(A: NumHashes - 1); N < SizeOverhead * NumHashes;
222 N <<= 1) {
223 Table.clear();
224
225 bool NeedResize = false;
226 for (uint64_t H : Hashes) {
227 uint64_t Idx = H % static_cast<uint64_t>(N);
228 if (++Table[Idx] > MaxCollisions) {
229 // Need to resize the final table if we increased the collision count.
230 NeedResize = true;
231 break;
232 }
233 }
234
235 if (!NeedResize)
236 return {N, MaxCollisions};
237 }
238 }
239}
240
241static std::vector<unsigned>
242constructPerfectHashTable(ArrayRef<RuntimeLibcallImpl> Keywords,
243 ArrayRef<uint64_t> Hashes,
244 ArrayRef<unsigned> TableValues, int Size,
245 int Collisions, StringToOffsetTable &OffsetTable) {
246 std::vector<unsigned> Lookup(Size * Collisions);
247
248 for (auto [HashValue, TableValue] : zip(t&: Hashes, u&: TableValues)) {
249 uint64_t Idx = (HashValue % static_cast<uint64_t>(Size)) *
250 static_cast<uint64_t>(Collisions);
251
252 bool Found = false;
253 for (int J = 0; J < Collisions; ++J) {
254 unsigned &Entry = Lookup[Idx + J];
255 if (Entry == 0) {
256 Entry = TableValue;
257 Found = true;
258 break;
259 }
260 }
261
262 if (!Found)
263 reportFatalInternalError(reason: "failure to hash");
264 }
265
266 return Lookup;
267}
268
269/// Generate hash table based lookup by name.
270void RuntimeLibcallEmitter::emitNameMatchHashTable(
271 raw_ostream &OS, StringToOffsetTable &OffsetTable) const {
272 ArrayRef<RuntimeLibcallImpl> RuntimeLibcallImplDefList =
273 Libcalls.getRuntimeLibcallImplDefList();
274 std::vector<uint64_t> Hashes(RuntimeLibcallImplDefList.size());
275 std::vector<unsigned> TableValues(RuntimeLibcallImplDefList.size());
276 DenseSet<StringRef> SeenFuncNames;
277
278 size_t MaxFuncNameSize = 0;
279 size_t Index = 0;
280
281 for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) {
282 StringRef ImplName = LibCallImpl.getLibcallFuncName();
283 if (SeenFuncNames.insert(V: ImplName).second) {
284 MaxFuncNameSize = std::max(a: MaxFuncNameSize, b: ImplName.size());
285 TableValues[Index] = LibCallImpl.getEnumVal();
286 Hashes[Index++] = hash(Str: ImplName);
287 }
288 }
289
290 // Trim excess elements from non-unique entries.
291 Hashes.resize(new_size: SeenFuncNames.size());
292 TableValues.resize(new_size: SeenFuncNames.size());
293
294 LLVM_DEBUG({
295 for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) {
296 StringRef ImplName = LibCallImpl.getLibcallFuncName();
297 if (ImplName.size() == MaxFuncNameSize) {
298 dbgs() << "Maximum runtime libcall name size: " << ImplName << '('
299 << MaxFuncNameSize << ")\n";
300 }
301 }
302 });
303
304 // Early exiting on the symbol name provides a significant speedup in the miss
305 // case on the set of symbols in a clang binary. Emit this as an inlinable
306 // precondition in the header.
307 //
308 // The empty check is also used to get sensible behavior on anonymous
309 // functions.
310 //
311 // TODO: It may make more sense to split the search by string size more. There
312 // are a few outliers, most call names are small.
313 {
314 IfDefEmitter IfDef(OS, "GET_LOOKUP_LIBCALL_IMPL_NAME_BODY");
315
316 OS << " size_t Size = Name.size();\n"
317 " if (Size == 0 || Size > "
318 << MaxFuncNameSize
319 << ")\n"
320 " return enum_seq(RTLIB::Unsupported, RTLIB::Unsupported);\n"
321 " return lookupLibcallImplNameImpl(Name);\n";
322 }
323
324 auto [Size, Collisions] = computePerfectHashParameters(Hashes);
325 std::vector<unsigned> Lookup =
326 constructPerfectHashTable(Keywords: RuntimeLibcallImplDefList, Hashes, TableValues,
327 Size, Collisions, OffsetTable);
328
329 LLVM_DEBUG(dbgs() << "Runtime libcall perfect hashing parameters: Size = "
330 << Size << ", maximum collisions = " << Collisions << '\n');
331
332 IfDefEmitter IfDef(OS, "DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME");
333 emitHashFunction(OS);
334
335 OS << "iota_range<RTLIB::LibcallImpl> RTLIB::RuntimeLibcallsInfo::"
336 "lookupLibcallImplNameImpl(StringRef Name) {\n";
337
338 // Emit RTLIB::LibcallImpl values
339 OS << " static constexpr uint16_t HashTableNameToEnum[" << Lookup.size()
340 << "] = {\n";
341
342 for (unsigned TableVal : Lookup)
343 OS << " " << TableVal << ",\n";
344
345 OS << " };\n\n";
346
347 OS << " unsigned Idx = (hash(Name) % " << Size << ") * " << Collisions
348 << ";\n\n"
349 " for (int I = 0; I != "
350 << Collisions << R"(; ++I) {
351 const uint16_t Entry = HashTableNameToEnum[Idx + I];
352 const uint16_t StrOffset = RuntimeLibcallNameOffsetTable[Entry];
353 const uint8_t StrSize = RuntimeLibcallNameSizeTable[Entry];
354 StringRef Str(
355 &RTLIB::RuntimeLibcallsInfo::RuntimeLibcallImplNameTableStorage[StrOffset],
356 StrSize);
357 if (Str == Name)
358 return libcallImplNameHit(Entry, StrOffset);
359 }
360
361 return enum_seq(RTLIB::Unsupported, RTLIB::Unsupported);
362}
363)";
364}
365
366void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames(
367 raw_ostream &OS) const {
368 // Emit the implementation names
369 StringToOffsetTable Table(/*AppendZero=*/true,
370 "RTLIB::RuntimeLibcallsInfo::");
371
372 {
373 IfDefEmitter IfDef(OS, "GET_INIT_RUNTIME_LIBCALL_NAMES");
374
375 for (const RuntimeLibcallImpl &LibCallImpl :
376 Libcalls.getRuntimeLibcallImplDefList())
377 Table.GetOrAddStringOffset(Str: LibCallImpl.getLibcallFuncName());
378
379 Table.EmitStringTableDef(OS, Name: "RuntimeLibcallImplNameTable");
380 OS << R"(
381const uint16_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameOffsetTable[] = {
382)";
383
384 OS << formatv(Fmt: " {}, // {}\n", Vals: Table.GetStringOffset(Str: ""),
385 Vals: ""); // Unsupported entry
386 for (const RuntimeLibcallImpl &LibCallImpl :
387 Libcalls.getRuntimeLibcallImplDefList()) {
388 StringRef ImplName = LibCallImpl.getLibcallFuncName();
389 OS << formatv(Fmt: " {}, // {}\n", Vals: Table.GetStringOffset(Str: ImplName), Vals&: ImplName);
390 }
391 OS << "};\n";
392
393 OS << R"(
394const uint8_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameSizeTable[] = {
395)";
396
397 OS << " 0,\n";
398 for (const RuntimeLibcallImpl &LibCallImpl :
399 Libcalls.getRuntimeLibcallImplDefList())
400 OS << " " << LibCallImpl.getLibcallFuncName().size() << ",\n";
401 OS << "};\n\n";
402
403 // Emit the reverse mapping from implementation libraries to RTLIB::Libcall
404 OS << "const RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::"
405 "ImplToLibcall[RTLIB::NumLibcallImpls] = {\n"
406 " RTLIB::UNKNOWN_LIBCALL, // RTLIB::Unsupported\n";
407
408 for (const RuntimeLibcallImpl &LibCallImpl :
409 Libcalls.getRuntimeLibcallImplDefList()) {
410 const RuntimeLibcall *Provides = LibCallImpl.getProvides();
411 OS << " ";
412 Provides->emitEnumEntry(OS);
413 OS << ", // ";
414 LibCallImpl.emitEnumEntry(OS);
415 OS << '\n';
416 }
417
418 OS << "};\n\n";
419 }
420
421 emitNameMatchHashTable(OS, OffsetTable&: Table);
422}
423
424void RuntimeLibcallEmitter::emitPredicateGroups(
425 raw_ostream &OS, const Record *R,
426 DenseMap<PredicateWithCC, LibcallsWithCC> &Pred2Funcs,
427 SetVector<PredicateWithCC> &PredicateSorter, unsigned BaseIndent) const {
428 SmallVector<PredicateWithCC, 0> SortedPredicates =
429 PredicateSorter.takeVector();
430
431 llvm::sort(C&: SortedPredicates, Comp: [](PredicateWithCC A, PredicateWithCC B) {
432 StringRef AName = A.Availability ? A.Availability->getName() : "";
433 StringRef BName = B.Availability ? B.Availability->getName() : "";
434 if (AName != BName)
435 return AName < BName;
436 // Break name ties on the calling convention for a deterministic order.
437 StringRef ACC = A.CallingConv ? A.CallingConv->getName() : "";
438 StringRef BCC = B.CallingConv ? B.CallingConv->getName() : "";
439 return ACC < BCC;
440 });
441
442 for (PredicateWithCC Entry : SortedPredicates) {
443 AvailabilityPredicate SubsetPredicate(Entry.Availability);
444 unsigned IndentDepth = BaseIndent;
445
446 auto It = Pred2Funcs.find(Val: Entry);
447 if (It == Pred2Funcs.end())
448 continue;
449
450 // Shared-core deduplication can empty a bucket.
451 if (It->second.LibcallImpls.empty())
452 continue;
453
454 if (!SubsetPredicate.isAlwaysAvailable()) {
455 IndentDepth = BaseIndent + 2;
456
457 OS << indent(IndentDepth);
458 SubsetPredicate.emitIf(OS);
459 }
460
461 LibcallsWithCC &FuncsWithCC = It->second;
462
463 std::vector<const RuntimeLibcallImpl *> &Funcs = FuncsWithCC.LibcallImpls;
464
465 // Records which impls are available, not which is selected, so a libcall
466 // may have more than one. Order is irrelevant (each entry is a setAvailable
467 // call); sort by the provided libcall, breaking ties on the impl enum for a
468 // deterministic total order.
469 llvm::sort(C&: Funcs, Comp: [](const RuntimeLibcallImpl *A,
470 const RuntimeLibcallImpl *B) {
471 return std::make_pair(x: A->getProvides()->getEnumVal(), y: A->getEnumVal()) <
472 std::make_pair(x: B->getProvides()->getEnumVal(), y: B->getEnumVal());
473 });
474
475 OS << indent(IndentDepth + 2)
476 << "static const RTLIB::LibcallImpl LibraryCalls";
477 SubsetPredicate.emitTableVariableNameSuffix(OS);
478 if (FuncsWithCC.CallingConv)
479 OS << '_' << FuncsWithCC.CallingConv->getName();
480
481 OS << "[] = {\n";
482 for (const RuntimeLibcallImpl *LibCallImpl : Funcs) {
483 OS << indent(IndentDepth + 6);
484 LibCallImpl->emitEnumEntry(OS);
485 OS << ", // " << LibCallImpl->getLibcallFuncName() << '\n';
486 }
487
488 OS << indent(IndentDepth + 2) << "};\n\n"
489 << indent(IndentDepth + 2)
490 << "for (const RTLIB::LibcallImpl Impl : LibraryCalls";
491 SubsetPredicate.emitTableVariableNameSuffix(OS);
492 if (FuncsWithCC.CallingConv)
493 OS << '_' << FuncsWithCC.CallingConv->getName();
494
495 OS << ") {\n" << indent(IndentDepth + 4) << "setAvailable(Impl);\n";
496
497 if (FuncsWithCC.CallingConv) {
498 StringRef CCEnum =
499 FuncsWithCC.CallingConv->getValueAsString(FieldName: "CallingConv");
500 OS << indent(IndentDepth + 4) << "setLibcallImplCallingConv(Impl, "
501 << CCEnum << ");\n";
502 }
503
504 OS << indent(IndentDepth + 2) << "}\n";
505 OS << '\n';
506
507 if (!SubsetPredicate.isAlwaysAvailable()) {
508 OS << indent(IndentDepth);
509 SubsetPredicate.emitEndIf(OS);
510 OS << '\n';
511 }
512 }
513}
514
515// Emit the linker name \p Name as a C++ identifier suffix, replacing characters
516// invalid in an identifier (e.g. the '-' in "compiler-rt") with '_'.
517static void emitLibFuncSuffix(raw_ostream &OS, StringRef Name) {
518 for (char C : Name)
519 OS << (isAlnum(C) || C == '_' ? C : '_');
520}
521
522void RuntimeLibcallEmitter::emitLibraryVariant(raw_ostream &OS,
523 ExpandedLibrary &EL) const {
524 AvailabilityPredicate LibPred(EL.Lib->getValueAsDef(FieldName: "Pred"));
525
526 if (!LibPred.isAlwaysAvailable()) {
527 OS << indent(2);
528 LibPred.emitIf(OS);
529 } else {
530 // Own block scope so per-variant `LibraryCalls` tables do not collide.
531 OS << indent(2) << "{\n";
532 }
533
534 emitPredicateGroups(OS, R: EL.Lib, Pred2Funcs&: EL.Pred2Funcs, PredicateSorter&: EL.PredicateSorter,
535 /*BaseIndent=*/2);
536
537 if (!LibPred.isAlwaysAvailable()) {
538 OS << indent(2);
539 LibPred.emitEndIf(OS);
540 } else {
541 OS << indent(2) << "}\n";
542 }
543}
544
545void RuntimeLibcallEmitter::emitLibraryFunction(
546 raw_ostream &OS, StringRef Name, ArrayRef<const Record *> Libs,
547 ArrayRef<LibraryExclusion> Exclusions) const {
548 OS << "void llvm::RTLIB::RuntimeLibcallsInfo::setAvailableLibFuncs_";
549 emitLibFuncSuffix(OS, Name);
550 OS << "(const llvm::Triple &TT, "
551 "ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, "
552 "StringRef ABIName, "
553 "LongDoubleFormat LongDoubleFormat) {\n";
554
555 SmallVector<ExpandedLibrary, 2> Expanded;
556 for (const Record *Lib : Libs) {
557 ExpandedLibrary EL;
558 EL.Lib = Lib;
559
560 // Expand this library's members with a library-local Func2Preds.
561 SetTheory Sets;
562 DenseMap<const RuntimeLibcallImpl *,
563 std::pair<std::vector<const Record *>, const Record *>>
564 Func2Preds;
565 Sets.addExpander(ClassName: "LibcallImpls", std::make_unique<LibcallPredicateExpander>(
566 args: Libcalls, args&: Func2Preds));
567
568 SetTheory::RecSet Elements;
569 Sets.evaluate(Expr: Lib->getValueInit(FieldName: "Impls"), Elts&: Elements, Loc: Lib->getLoc());
570
571 EL.PredicateSorter.insert(
572 X: PredicateWithCC()); // No predicate or CC override first.
573
574 for (const Record *Elt : Elements) {
575 const RuntimeLibcallImpl *LibCallImpl =
576 Libcalls.getRuntimeLibcallImpl(Def: Elt);
577 if (!LibCallImpl) {
578 PrintError(Rec: Lib, Msg: "entry for LibcallLibrary is not a RuntimeLibcallImpl");
579 PrintNote(NoteLoc: Elt->getLoc(), Msg: "invalid entry `" + Elt->getName() + "`");
580 continue;
581 }
582
583 auto It = Func2Preds.find(Val: LibCallImpl);
584 if (It == Func2Preds.end()) {
585 EL.Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(x: LibCallImpl);
586 EL.Unconditional.insert(X: LibCallImpl);
587 continue;
588 }
589
590 for (const Record *Pred : It->second.first) {
591 const Record *CC = It->second.second;
592 PredicateWithCC Key(Pred, CC);
593 auto &Entry = EL.Pred2Funcs[Key];
594 Entry.LibcallImpls.push_back(x: LibCallImpl);
595 Entry.CallingConv = CC;
596 EL.PredicateSorter.insert(X: Key);
597 }
598 }
599
600 Expanded.push_back(Elt: std::move(EL));
601 }
602
603 // Impls unconditional in every variant are emitted once and stripped from
604 // each variant, so the shared core is not repeated.
605 SetVector<const RuntimeLibcallImpl *> SharedCore;
606 if (Expanded.size() > 1) {
607 for (const RuntimeLibcallImpl *Impl : Expanded.front().Unconditional) {
608 if (all_of(Range: drop_begin(RangeOrContainer&: Expanded), P: [&](const ExpandedLibrary &EL) {
609 return EL.Unconditional.contains(key: Impl);
610 }))
611 SharedCore.insert(X: Impl);
612 }
613 }
614
615 if (!SharedCore.empty()) {
616 // Emit the shared core once, then strip it from every variant.
617 DenseMap<PredicateWithCC, LibcallsWithCC> CorePred2Funcs;
618 SetVector<PredicateWithCC> CoreSorter;
619 CoreSorter.insert(X: PredicateWithCC());
620 for (const RuntimeLibcallImpl *Impl : SharedCore)
621 CorePred2Funcs[PredicateWithCC()].LibcallImpls.push_back(x: Impl);
622 emitPredicateGroups(OS, R: Libs.front(), Pred2Funcs&: CorePred2Funcs, PredicateSorter&: CoreSorter,
623 /*BaseIndent=*/0);
624
625 for (ExpandedLibrary &EL : Expanded) {
626 auto &Funcs = EL.Pred2Funcs[PredicateWithCC()].LibcallImpls;
627 llvm::erase_if(C&: Funcs, P: [&](const RuntimeLibcallImpl *Impl) {
628 return SharedCore.contains(key: Impl);
629 });
630 }
631 }
632
633 // Mark a variant deferred when it re-adds an impl its own consumer excludes
634 // (same triple, via LibraryRef). Such a variant must be emitted after the
635 // exclusion so the re-add wins while the exclusion still suppresses every
636 // other variant's contribution.
637 for (ExpandedLibrary &EL : Expanded) {
638 const Record *ELPred = EL.Lib->getValueAsDef(FieldName: "Pred");
639 SetVector<const RuntimeLibcallImpl *> Impls;
640 for (const auto &[Key, Funcs] : EL.Pred2Funcs)
641 Impls.insert(Start: Funcs.LibcallImpls.begin(), End: Funcs.LibcallImpls.end());
642
643 for (const LibraryExclusion &Excl : Exclusions) {
644 if (Excl.TriplePred != ELPred)
645 continue;
646 if (any_of(Range: Excl.Impls, P: [&](const RuntimeLibcallImpl *Impl) {
647 return Impls.contains(key: Impl);
648 })) {
649 EL.Deferred = true;
650 break;
651 }
652 }
653 }
654
655 // Emit each non-deferred variant under its own Pred.
656 for (ExpandedLibrary &EL : Expanded) {
657 if (!EL.Deferred)
658 emitLibraryVariant(OS, EL);
659 }
660
661 // Emit each consumer's LibraryRef opt-outs.
662 for (const LibraryExclusion &Excl : Exclusions) {
663 OS << '\n' << indent(2);
664 AvailabilityPredicate ExcludePred(Excl.TriplePred);
665 ExcludePred.emitIf(OS);
666 for (const RuntimeLibcallImpl *Impl : Excl.Impls) {
667 OS << indent(4) << "setUnavailable(";
668 Impl->emitEnumEntry(OS);
669 OS << "); // " << Impl->getLibcallFuncName() << '\n';
670 }
671
672 OS << indent(2);
673 ExcludePred.emitEndIf(OS);
674 }
675
676 // Deferred variants: emitted after exclusions so a target's own re-adds
677 // override its own LibraryRef opt-outs (the exclusion still applied above
678 // to every other variant's contributions).
679 for (ExpandedLibrary &EL : Expanded) {
680 if (EL.Deferred)
681 emitLibraryVariant(OS, EL);
682 }
683
684 OS << "}\n\n";
685}
686
687MapVector<StringRef, std::vector<const Record *>>
688RuntimeLibcallEmitter::collectLibrariesByName() const {
689 MapVector<StringRef, std::vector<const Record *>> LibsByName;
690 for (const Record *Lib : Records.getAllDerivedDefinitions(ClassName: "LibcallLibrary"))
691 LibsByName[Lib->getValueAsString(FieldName: "LibraryName")].push_back(x: Lib);
692 return LibsByName;
693}
694
695void RuntimeLibcallEmitter::emitRuntimeLibcallsInfoMemberDecls(
696 raw_ostream &OS) const {
697 IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALLS_INFO_MEMBER_DECLS");
698 for (const auto &[Name, Libs] : collectLibrariesByName()) {
699 OS << "void setAvailableLibFuncs_";
700 emitLibFuncSuffix(OS, Name);
701 OS << "(const llvm::Triple &TT, ExceptionHandling ExceptionModel, "
702 "FloatABI::ABIType FloatABI, StringRef ABIName, "
703 "LongDoubleFormat LongDoubleFormat);\n";
704 }
705}
706
707void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
708 raw_ostream &OS) const {
709 ArrayRef<const Record *> AllLibs =
710 Records.getAllDerivedDefinitions(ClassName: "SystemRuntimeLibrary");
711
712 // Collect each shared library's LibraryRef opt-outs, keyed by library name,
713 // so its library function can emit them.
714 MapVector<StringRef, std::vector<LibraryExclusion>> ExclusionsByLibName;
715 for (const Record *R : AllLibs) {
716 const DagInit *MemberDag =
717 R->getValueAsDef(FieldName: "MemberList")->getValueAsDag(FieldName: "MemberList");
718 for (const Init *Arg : MemberDag->getArgs()) {
719 const auto *DI = dyn_cast<DefInit>(Val: Arg);
720 if (!DI || !DI->getDef()->isSubClassOf(Name: "LibraryRef"))
721 continue;
722 const Record *Def = DI->getDef();
723 LibraryExclusion Excl{.TriplePred: R->getValueAsDef(FieldName: "TriplePred"), .Impls: {}};
724 for (const Record *ExcludeRec : Def->getValueAsListOfDefs(FieldName: "Exclude")) {
725 if (const RuntimeLibcallImpl *Impl =
726 Libcalls.getRuntimeLibcallImpl(Def: ExcludeRec))
727 Excl.Impls.push_back(x: Impl);
728 }
729
730 if (!Excl.Impls.empty()) {
731 StringRef LibName =
732 Def->getValueAsDef(FieldName: "Library")->getValueAsString(FieldName: "LibraryName");
733 ExclusionsByLibName[LibName].push_back(x: std::move(Excl));
734 }
735 }
736 }
737
738 for (const auto &[Name, Libs] : collectLibrariesByName())
739 emitLibraryFunction(OS, Name, Libs, Exclusions: ExclusionsByLibName.lookup(Key: Name));
740
741 OS << "void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets("
742 "const llvm::Triple &TT, ExceptionHandling ExceptionModel, "
743 "FloatABI::ABIType FloatABI, "
744 "StringRef ABIName, LongDoubleFormat LongDoubleFormat) {\n";
745
746 for (const Record *R : AllLibs) {
747 OS << '\n';
748
749 AvailabilityPredicate TopLevelPredicate(R->getValueAsDef(FieldName: "TriplePred"));
750
751 OS << indent(2);
752 TopLevelPredicate.emitIf(OS);
753
754 if (const Record *DefaultCCClass =
755 R->getValueAsDef(FieldName: "DefaultLibcallCallingConv")) {
756 StringRef DefaultCC =
757 DefaultCCClass->getValueAsString(FieldName: "CallingConv").trim();
758
759 if (!DefaultCC.empty()) {
760 OS << " const CallingConv::ID DefaultCC = " << DefaultCC << ";\n"
761 << " for (CallingConv::ID &Entry : LibcallImplCallingConvs) {\n"
762 " Entry = DefaultCC;\n"
763 " }\n\n";
764 }
765 }
766
767 // Split the top-level member list into named LibcallLibrary references
768 // (dispatched to their own setAvailableLibFuncs_<name> under an
769 // isLibraryAvailable guard) and the remaining bare impl / LibcallImpls
770 // members. A LibraryRef also records impls to drop.
771 struct DispatchLib {
772 StringRef Name;
773 std::vector<const RuntimeLibcallImpl *> Exclude;
774 };
775 const DagInit *MemberDag =
776 R->getValueAsDef(FieldName: "MemberList")->getValueAsDag(FieldName: "MemberList");
777 SmallVector<DispatchLib, 4> DispatchLibs;
778 SmallVector<const Init *, 16> InlineArgs;
779 SmallVector<const StringInit *, 16> InlineArgNames;
780 for (auto [Arg, ArgName] :
781 zip_equal(t: MemberDag->getArgs(), u: MemberDag->getArgNames())) {
782 if (const auto *DI = dyn_cast<DefInit>(Val: Arg)) {
783 const Record *Def = DI->getDef();
784 if (Def->isSubClassOf(Name: "LibcallLibrary")) {
785 DispatchLibs.push_back(Elt: {.Name: Def->getValueAsString(FieldName: "LibraryName"), .Exclude: {}});
786 continue;
787 }
788
789 if (Def->isSubClassOf(Name: "LibraryRef")) {
790 const Record *Lib = Def->getValueAsDef(FieldName: "Library");
791 DispatchLib DL{.Name: Lib->getValueAsString(FieldName: "LibraryName"), .Exclude: {}};
792 for (const Record *ExcludeRec :
793 Def->getValueAsListOfDefs(FieldName: "Exclude")) {
794 if (const RuntimeLibcallImpl *Impl =
795 Libcalls.getRuntimeLibcallImpl(Def: ExcludeRec))
796 DL.Exclude.push_back(x: Impl);
797 }
798
799 DispatchLibs.push_back(Elt: std::move(DL));
800 continue;
801 }
802 }
803 InlineArgs.push_back(Elt: Arg);
804 InlineArgNames.push_back(Elt: ArgName);
805 }
806
807 const DagInit *InlineDag =
808 DagInit::get(V: MemberDag->getOperator(), Args: InlineArgs, ArgNames: InlineArgNames);
809
810 SetTheory Sets;
811
812 DenseMap<const RuntimeLibcallImpl *,
813 std::pair<std::vector<const Record *>, const Record *>>
814 Func2Preds;
815 Sets.addExpander(ClassName: "LibcallImpls", std::make_unique<LibcallPredicateExpander>(
816 args: Libcalls, args&: Func2Preds));
817
818 SetTheory::RecSet ElementsSet;
819 Sets.evaluate(Expr: InlineDag, Elts&: ElementsSet, Loc: R->getLoc());
820 const SetTheory::RecSet *Elements = &ElementsSet;
821
822 // Sort to get deterministic output
823 SetVector<PredicateWithCC> PredicateSorter;
824 PredicateSorter.insert(
825 X: PredicateWithCC()); // No predicate or CC override first.
826
827 constexpr unsigned BitsPerStorageElt = 64;
828 DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs;
829
830 SmallVector<uint64_t, 32> BitsetValues(divideCeil(
831 Numerator: Libcalls.getRuntimeLibcallImplDefList().size() + 1, Denominator: BitsPerStorageElt));
832
833 for (const Record *Elt : *Elements) {
834 const RuntimeLibcallImpl *LibCallImpl =
835 Libcalls.getRuntimeLibcallImpl(Def: Elt);
836 if (!LibCallImpl) {
837 PrintError(Rec: R, Msg: "entry for SystemLibrary is not a RuntimeLibcallImpl");
838 PrintNote(NoteLoc: Elt->getLoc(), Msg: "invalid entry `" + Elt->getName() + "`");
839 continue;
840 }
841
842 size_t BitIdx = LibCallImpl->getEnumVal();
843 uint64_t BitmaskVal = uint64_t(1) << (BitIdx % BitsPerStorageElt);
844 size_t BitsetIdx = BitIdx / BitsPerStorageElt;
845
846 auto It = Func2Preds.find(Val: LibCallImpl);
847 if (It == Func2Preds.end()) {
848 BitsetValues[BitsetIdx] |= BitmaskVal;
849 Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(x: LibCallImpl);
850 continue;
851 }
852
853 for (const Record *Pred : It->second.first) {
854 const Record *CC = It->second.second;
855 AvailabilityPredicate SubsetPredicate(Pred);
856 if (SubsetPredicate.isAlwaysAvailable())
857 BitsetValues[BitsetIdx] |= BitmaskVal;
858
859 PredicateWithCC Key(Pred, CC);
860 auto &Entry = Pred2Funcs[Key];
861 Entry.LibcallImpls.push_back(x: LibCallImpl);
862 Entry.CallingConv = It->second.second;
863 PredicateSorter.insert(X: Key);
864 }
865 }
866
867 OS << " static constexpr LibcallImplBitset SystemAvailableImpls({\n"
868 << indent(6);
869
870 ListSeparator LS;
871 unsigned EntryCount = 0;
872 for (uint64_t Bits : BitsetValues) {
873 if (EntryCount++ == 4) {
874 EntryCount = 1;
875 OS << ",\n" << indent(6);
876 } else
877 OS << LS;
878 OS << format_hex(N: Bits, Width: 16);
879 }
880 OS << "\n });\n"
881 " AvailableLibcallImpls = SystemAvailableImpls;\n\n";
882
883 // Dispatch to each named library's setup function. This must come after the
884 // SystemAvailableImpls assignment above (which overwrites the bitset); the
885 // library functions union their members in on top via setAvailable.
886 for (const DispatchLib &DL : DispatchLibs) {
887 OS << indent(4) << "if (isLibraryAvailable(\"" << DL.Name << "\"))\n"
888 << indent(6) << "setAvailableLibFuncs_";
889 emitLibFuncSuffix(OS, Name: DL.Name);
890 OS << "(TT, ExceptionModel, FloatABI, ABIName, LongDoubleFormat);\n";
891 }
892 if (!DispatchLibs.empty())
893 OS << '\n';
894
895 emitPredicateGroups(OS, R, Pred2Funcs, PredicateSorter, /*BaseIndent=*/2);
896
897 OS << indent(4) << "return;\n" << indent(2);
898 TopLevelPredicate.emitEndIf(OS);
899 }
900
901 // FIXME: This should be a fatal error. A few contexts are improperly relying
902 // on RuntimeLibcalls constructed with fully unknown triples.
903 OS << " LLVM_DEBUG(dbgs() << \"no system runtime library applied to target "
904 "\\'\" << TT.str() << \"\\'\\n\");\n"
905 "}\n\n";
906}
907
908// Scalar FP type suffixes in the argument order of RTLIB::getFPLibCall, paired
909// with the llvm::Type predicate used by the IR-level mapping.
910static constexpr std::pair<StringRef, StringRef> ScalarFPSuffixes[] = {
911 {"F32", "isFloatTy()"}, {"F64", "isDoubleTy()"},
912 {"F80", "isX86_FP80Ty()"}, {"F128", "isFP128Ty()"},
913 {"PPCF128", "isPPC_FP128Ty()"},
914};
915
916static std::vector<FPLibcallFamily>
917collectFPLibcallFamilies(const RecordKeeper &Records) {
918 std::vector<FPLibcallFamily> Families;
919 for (const Record *R :
920 Records.getAllDerivedDefinitions(ClassName: "RuntimeLibcallFamily"))
921 Families.emplace_back(args&: R);
922 llvm::sort(C&: Families, Comp: [](const FPLibcallFamily &A, const FPLibcallFamily &B) {
923 return A.Base < B.Base;
924 });
925 return Families;
926}
927
928DenseSet<StringRef> RuntimeLibcallEmitter::collectLibcallNames() const {
929 DenseSet<StringRef> LibcallNames;
930 for (const RuntimeLibcall &LC : Libcalls.getRuntimeLibcallDefList())
931 LibcallNames.insert(V: LC.getName());
932 return LibcallNames;
933}
934
935void RuntimeLibcallEmitter::checkFPLibcallFamilies(
936 ArrayRef<FPLibcallFamily> Families,
937 const DenseSet<StringRef> &LibcallNames) const {
938 std::vector<std::pair<StringRef, StringRef>> IntrinsicToBase;
939 for (const FPLibcallFamily &Family : Families)
940 for (StringRef Intrinsic : Family.Intrinsics)
941 IntrinsicToBase.emplace_back(args&: Intrinsic, args: Family.Base);
942 llvm::sort(C&: IntrinsicToBase);
943
944 for (size_t I = 1, E = IntrinsicToBase.size(); I < E; ++I) {
945 if (IntrinsicToBase[I].first == IntrinsicToBase[I - 1].first)
946 PrintFatalError(
947 Msg: "intrinsic '" + IntrinsicToBase[I].first +
948 "' is mapped by multiple RuntimeLibcallFamily records ('" +
949 IntrinsicToBase[I - 1].second + "' and '" +
950 IntrinsicToBase[I].second + "')");
951 }
952
953 for (const FPLibcallFamily &Family : Families) {
954 bool AnyScalarLibcall = any_of(
955 Range: ScalarFPSuffixes, P: [&](const std::pair<StringRef, StringRef> &Entry) {
956 return LibcallNames.contains(V: (Family.Base + "_" + Entry.first).str());
957 });
958 if (!AnyScalarLibcall)
959 PrintFatalError(Msg: "no runtime libcall found for base name '" + Family.Base +
960 "'");
961 }
962}
963
964/// Generate the declarations for the RTLIB::get<base>(EVT) selectors.
965void RuntimeLibcallEmitter::emitFPLibcallSelectorDecls(
966 raw_ostream &OS, ArrayRef<FPLibcallFamily> Families) const {
967 IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_FP_SELECTOR_DECLS");
968 for (const FPLibcallFamily &Family : Families)
969 OS << "LLVM_ABI Libcall get" << Family.Base << "(EVT VT);\n";
970}
971
972/// Generate the backend RTLIB::get<base>(EVT) selectors from the floating-point
973/// libcall families.
974void RuntimeLibcallEmitter::emitFPLibcallSelectors(
975 raw_ostream &OS, ArrayRef<FPLibcallFamily> Families,
976 const DenseSet<StringRef> &LibcallNames) const {
977 IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_FP_SELECTORS");
978
979 // Only emit a libcall enumerator if it actually exists in the declared set.
980 auto scalarEnum = [&](StringRef Base, StringRef Suffix) -> std::string {
981 if (LibcallNames.contains(V: (Base + "_" + Suffix).str()))
982 return ("RTLIB::" + Base + "_" + Suffix).str();
983 return "RTLIB::UNKNOWN_LIBCALL";
984 };
985
986 for (const FPLibcallFamily &Family : Families) {
987 StringRef Base = Family.Base;
988 OS << "RTLIB::Libcall llvm::RTLIB::get" << Base << "(EVT VT) {\n";
989
990 if (!Family.VectorSuffixes.empty()) {
991 OS << " if (VT.isVector()) {\n"
992 " if (!VT.isSimple())\n"
993 " return RTLIB::UNKNOWN_LIBCALL;\n"
994 " switch (VT.getSimpleVT().SimpleTy) {\n";
995 for (StringRef Suffix : Family.VectorSuffixes) {
996 OS << " case MVT::" << Suffix.lower()
997 << ":\n return RTLIB::" << Base << "_" << Suffix << ";\n";
998 }
999 OS << " default:\n"
1000 " return RTLIB::UNKNOWN_LIBCALL;\n"
1001 " }\n"
1002 " }\n";
1003 }
1004
1005 OS << " return getFPLibCall(VT";
1006 for (auto [Suffix, Pred] : ScalarFPSuffixes)
1007 OS << ", " << scalarEnum(Base, Suffix);
1008 OS << ");\n}\n\n";
1009 }
1010}
1011
1012/// Emit the mapping from floating-point math intrinsics to the runtime libcall
1013/// they may lower to, keyed by intrinsic ID and floating-point type. This is
1014/// the IR-level counterpart to the backend's RTLIB::getXXX(EVT) selectors.
1015void RuntimeLibcallEmitter::emitGetLibcallForIntrinsic(
1016 raw_ostream &OS, ArrayRef<FPLibcallFamily> Families,
1017 const DenseSet<StringRef> &LibcallNames) const {
1018 IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_INTRINSIC_TO_LIBCALL");
1019
1020 std::vector<std::pair<StringRef, StringRef>> IntrinsicToBase;
1021 for (const FPLibcallFamily &Family : Families)
1022 for (StringRef Intrinsic : Family.Intrinsics)
1023 IntrinsicToBase.emplace_back(args&: Intrinsic, args: Family.Base);
1024 llvm::sort(C&: IntrinsicToBase);
1025
1026 MapVector<StringRef, SmallVector<StringRef, 2>> BaseToIntrinsics;
1027 for (auto [Intrinsic, Base] : IntrinsicToBase)
1028 BaseToIntrinsics[Base].push_back(Elt: Intrinsic);
1029
1030 OS << "RTLIB::Libcall "
1031 "llvm::RTLIB::RuntimeLibcallsInfo::getLibcallForIntrinsic("
1032 "Intrinsic::ID ID, FunctionType *FTy) {\n"
1033 " Type *Ty = FTy->getReturnType();\n"
1034 " if (!Ty->isFloatingPointTy()) {\n"
1035 " for (Type *ParamTy : FTy->params()) {\n"
1036 " if (ParamTy->isFloatingPointTy()) {\n"
1037 " Ty = ParamTy;\n"
1038 " break;\n"
1039 " }\n"
1040 " }\n"
1041 " }\n"
1042 " if (!Ty->isFloatingPointTy())\n"
1043 " return RTLIB::UNKNOWN_LIBCALL;\n"
1044 " switch (ID) {\n";
1045
1046 for (const auto &[Base, Intrinsics] : BaseToIntrinsics) {
1047 SmallVector<std::pair<StringRef, StringRef>, 5> Arms;
1048 for (auto [Suffix, Pred] : ScalarFPSuffixes)
1049 if (LibcallNames.contains(V: (Base + "_" + Suffix).str()))
1050 Arms.emplace_back(Args&: Suffix, Args&: Pred);
1051
1052 for (StringRef Intrinsic : Intrinsics)
1053 OS << " case Intrinsic::" << Intrinsic << ":\n";
1054 for (auto [Suffix, Pred] : Arms)
1055 OS << " if (Ty->" << Pred << ")\n return RTLIB::" << Base << "_"
1056 << Suffix << ";\n";
1057 OS << " return RTLIB::UNKNOWN_LIBCALL;\n";
1058 }
1059
1060 OS << " default:\n"
1061 " return RTLIB::UNKNOWN_LIBCALL;\n"
1062 " }\n"
1063 "}\n";
1064}
1065
1066void RuntimeLibcallEmitter::run(raw_ostream &OS) {
1067 emitSourceFileHeader(Desc: "Runtime LibCalls Source Fragment", OS, Record: Records);
1068 emitGetRuntimeLibcallEnum(OS);
1069
1070 emitGetInitRuntimeLibcallNames(OS);
1071
1072 emitRuntimeLibcallsInfoMemberDecls(OS);
1073
1074 {
1075 IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALLS_INFO");
1076 emitSystemRuntimeLibrarySetCalls(OS);
1077 }
1078
1079 std::vector<FPLibcallFamily> FPFamilies = collectFPLibcallFamilies(Records);
1080 DenseSet<StringRef> LibcallNames = collectLibcallNames();
1081 checkFPLibcallFamilies(Families: FPFamilies, LibcallNames);
1082 emitFPLibcallSelectorDecls(OS, Families: FPFamilies);
1083 emitFPLibcallSelectors(OS, Families: FPFamilies, LibcallNames);
1084 emitGetLibcallForIntrinsic(OS, Families: FPFamilies, LibcallNames);
1085}
1086
1087static TableGen::Emitter::OptClass<RuntimeLibcallEmitter>
1088 X("gen-runtime-libcalls", "Generate RuntimeLibcalls");
1089