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;
PredicateWithCC__anonf9119db00111::PredicateWithCC26 PredicateWithCC(std::pair<const Record *, const Record *> P)
27 : Predicate(P.first), CallingConv(P.second) {}
28
PredicateWithCC__anonf9119db00111::PredicateWithCC29 PredicateWithCC(const Record *P, const Record *C)
30 : Predicate(P), CallingConv(C) {}
31 };
32
operator ==(PredicateWithCC LHS,PredicateWithCC RHS)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> {
getEmptyKeyllvm::DenseMapInfo40 static inline PredicateWithCC getEmptyKey() {
41 return DenseMapInfo<
42 std::pair<const Record *, const Record *>>::getEmptyKey();
43 }
44
getTombstoneKeyllvm::DenseMapInfo45 static inline PredicateWithCC getTombstoneKey() {
46 return DenseMapInfo<
47 std::pair<const Record *, const Record *>>::getTombstoneKey();
48 }
49
getHashValuellvm::DenseMapInfo50 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
isEqualllvm::DenseMapInfo56 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:
AvailabilityPredicate(const Record * Def)69 AvailabilityPredicate(const Record *Def) : TheDef(Def) {
70 if (TheDef)
71 PredicateString = TheDef->getValueAsString("Cond");
72 }
73
getDef() const74 const Record *getDef() const { return TheDef; }
75
isAlwaysAvailable() const76 bool isAlwaysAvailable() const { return PredicateString.empty(); }
77
emitIf(raw_ostream & OS) const78 void emitIf(raw_ostream &OS) const {
79 OS << "if (" << PredicateString << ") {\n";
80 }
81
emitEndIf(raw_ostream & OS) const82 void emitEndIf(raw_ostream &OS) const { OS << "}\n"; }
83
emitTableVariableNameSuffix(raw_ostream & OS) const84 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
LibcallPredicateExpander__anonf9119db00211::LibcallPredicateExpander99 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;
RuntimeLibcall(const Record * Def,size_t EnumVal)116 RuntimeLibcall(const Record *Def, size_t EnumVal)
117 : TheDef(Def), EnumVal(EnumVal) {
118 assert(Def);
119 }
120
~RuntimeLibcall()121 ~RuntimeLibcall() { assert(TheDef); }
122
getDef() const123 const Record *getDef() const { return TheDef; }
124
getName() const125 StringRef getName() const { return TheDef->getName(); }
126
getEnumVal() const127 size_t getEnumVal() const { return EnumVal; }
128
emitEnumEntry(raw_ostream & OS) const129 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:
RuntimeLibcallImpl(const Record * Def,const DenseMap<const Record *,const RuntimeLibcall * > & ProvideMap,size_t EnumVal)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
~RuntimeLibcallImpl()149 ~RuntimeLibcallImpl() {}
150
getDef() const151 const Record *getDef() const { return TheDef; }
152
getName() const153 StringRef getName() const { return TheDef->getName(); }
154
getEnumVal() const155 size_t getEnumVal() const { return EnumVal; }
156
getProvides() const157 const RuntimeLibcall *getProvides() const { return Provides; }
158
getLibcallFuncName() const159 StringRef getLibcallFuncName() const {
160 return TheDef->getValueAsString("LibCallFuncName");
161 }
162
getCallingConv() const163 const Record *getCallingConv() const {
164 return TheDef->getValueAsOptionalDef("CallingConv");
165 }
166
emitQuotedLibcallFuncName(raw_ostream & OS) const167 void emitQuotedLibcallFuncName(raw_ostream &OS) const {
168 OS << '\"' << getLibcallFuncName() << '\"';
169 }
170
isDefault() const171 bool isDefault() const { return TheDef->getValueAsBit("IsDefault"); }
172
emitEnumEntry(raw_ostream & OS) const173 void emitEnumEntry(raw_ostream &OS) const {
174 OS << "RTLIB::" << TheDef->getName();
175 }
176
emitSetImplCall(raw_ostream & OS) const177 void emitSetImplCall(raw_ostream &OS) const {
178 OS << "setLibcallImpl(";
179 Provides->emitEnumEntry(OS);
180 OS << ", ";
181 emitEnumEntry(OS);
182 OS << "); // " << getLibcallFuncName() << '\n';
183 }
184
emitTableEntry(raw_ostream & OS) const185 void emitTableEntry(raw_ostream &OS) const {
186 OS << '{';
187 Provides->emitEnumEntry(OS);
188 OS << ", ";
189 emitEnumEntry(OS);
190 OS << "}, // " << getLibcallFuncName() << '\n';
191 }
192
emitSetCallingConv(raw_ostream & OS) const193 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:
RuntimeLibcallEmitter(const RecordKeeper & R)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
getRuntimeLibcall(const Record * Def) const262 const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const {
263 return Def2RuntimeLibcall.lookup(Def);
264 }
265
getRuntimeLibcallImpl(const Record * Def) const266 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
emitGetRuntimeLibcallEnum(raw_ostream & OS) const275 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
emitGetInitRuntimeLibcallNames(raw_ostream & OS) const306 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
emitSystemRuntimeLibrarySetCalls(raw_ostream & OS) const362 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
run(raw_ostream & OS)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
expand(SetTheory & ST,const Record * Def,SetTheory::RecSet & Elts)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