Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
213799 views
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
588