Skip to content

Commit 0469ff0

Browse files
authored
TableGen: Split RuntimeLibcallsEmitter into separate utility header (#166583)
This information will be needed in more emitters, so start factoring it to be more reusable.
1 parent 6c4f968 commit 0469ff0

File tree

4 files changed

+308
-250
lines changed

4 files changed

+308
-250
lines changed

llvm/utils/TableGen/Basic/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_llvm_library(LLVMTableGenBasic OBJECT EXCLUDE_FROM_ALL DISABLE_LLVM_LINK_LLV
1616
IntrinsicEmitter.cpp
1717
RISCVTargetDefEmitter.cpp
1818
RuntimeLibcallsEmitter.cpp
19+
RuntimeLibcalls.cpp
1920
SDNodeProperties.cpp
2021
TableGen.cpp
2122
TargetFeaturesEmitter.cpp
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//===----------------------------------------------------------------------===//
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 "RuntimeLibcalls.h"
10+
#include "llvm/TableGen/Error.h"
11+
12+
using namespace llvm;
13+
14+
RuntimeLibcalls::RuntimeLibcalls(const RecordKeeper &Records) {
15+
ArrayRef<const Record *> AllRuntimeLibcalls =
16+
Records.getAllDerivedDefinitions("RuntimeLibcall");
17+
18+
RuntimeLibcallDefList.reserve(AllRuntimeLibcalls.size());
19+
20+
size_t CallTypeEnumVal = 0;
21+
for (const Record *RuntimeLibcallDef : AllRuntimeLibcalls) {
22+
RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef, CallTypeEnumVal++);
23+
Def2RuntimeLibcall[RuntimeLibcallDef] = &RuntimeLibcallDefList.back();
24+
}
25+
26+
for (RuntimeLibcall &LibCall : RuntimeLibcallDefList)
27+
Def2RuntimeLibcall[LibCall.getDef()] = &LibCall;
28+
29+
ArrayRef<const Record *> AllRuntimeLibcallImplsRaw =
30+
Records.getAllDerivedDefinitions("RuntimeLibcallImpl");
31+
32+
SmallVector<const Record *, 1024> AllRuntimeLibcallImpls(
33+
AllRuntimeLibcallImplsRaw);
34+
35+
// Sort by libcall impl name and secondarily by the enum name.
36+
sort(AllRuntimeLibcallImpls, [](const Record *A, const Record *B) {
37+
return std::pair(A->getValueAsString("LibCallFuncName"), A->getName()) <
38+
std::pair(B->getValueAsString("LibCallFuncName"), B->getName());
39+
});
40+
41+
RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size());
42+
43+
size_t LibCallImplEnumVal = 1;
44+
for (const Record *LibCallImplDef : AllRuntimeLibcallImpls) {
45+
RuntimeLibcallImplDefList.emplace_back(LibCallImplDef, Def2RuntimeLibcall,
46+
LibCallImplEnumVal++);
47+
48+
const RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back();
49+
Def2RuntimeLibcallImpl[LibCallImplDef] = &LibCallImpl;
50+
51+
if (LibCallImpl.isDefault()) {
52+
const RuntimeLibcall *Provides = LibCallImpl.getProvides();
53+
if (!Provides)
54+
PrintFatalError(LibCallImplDef->getLoc(),
55+
"default implementations must provide a libcall");
56+
LibCallToDefaultImpl[Provides] = &LibCallImpl;
57+
}
58+
}
59+
}
60+
61+
void LibcallPredicateExpander::expand(SetTheory &ST, const Record *Def,
62+
SetTheory::RecSet &Elts) {
63+
assert(Def->isSubClassOf("LibcallImpls"));
64+
65+
SetTheory::RecSet TmpElts;
66+
67+
ST.evaluate(Def->getValueInit("MemberList"), TmpElts, Def->getLoc());
68+
69+
Elts.insert(TmpElts.begin(), TmpElts.end());
70+
71+
AvailabilityPredicate AP(Def->getValueAsDef("AvailabilityPredicate"));
72+
const Record *CCClass = Def->getValueAsOptionalDef("CallingConv");
73+
74+
// This is assuming we aren't conditionally applying a calling convention to
75+
// some subsets, and not another, but this doesn't appear to be used.
76+
77+
for (const Record *LibcallImplDef : TmpElts) {
78+
const RuntimeLibcallImpl *LibcallImpl =
79+
Libcalls.getRuntimeLibcallImpl(LibcallImplDef);
80+
if (!AP.isAlwaysAvailable() || CCClass) {
81+
auto [It, Inserted] = Func2Preds.insert({LibcallImpl, {{}, CCClass}});
82+
if (!Inserted) {
83+
PrintError(
84+
Def,
85+
"combining nested libcall set predicates currently unhandled: '" +
86+
LibcallImpl->getLibcallFuncName() + "'");
87+
}
88+
89+
It->second.first.push_back(AP.getDef());
90+
It->second.second = CCClass;
91+
}
92+
}
93+
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
//===------------------------------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_UTILS_TABLEGEN_COMMON_RUNTIMELIBCALLS_H
10+
#define LLVM_UTILS_TABLEGEN_COMMON_RUNTIMELIBCALLS_H
11+
12+
#include "llvm/ADT/StringRef.h"
13+
#include "llvm/Support/raw_ostream.h"
14+
#include "llvm/TableGen/Record.h"
15+
#include "llvm/TableGen/SetTheory.h"
16+
17+
namespace llvm {
18+
19+
class AvailabilityPredicate {
20+
const Record *TheDef;
21+
StringRef PredicateString;
22+
23+
public:
24+
AvailabilityPredicate(const Record *Def) : TheDef(Def) {
25+
if (TheDef)
26+
PredicateString = TheDef->getValueAsString("Cond");
27+
}
28+
29+
const Record *getDef() const { return TheDef; }
30+
31+
bool isAlwaysAvailable() const { return PredicateString.empty(); }
32+
33+
void emitIf(raw_ostream &OS) const {
34+
OS << "if (" << PredicateString << ") {\n";
35+
}
36+
37+
void emitEndIf(raw_ostream &OS) const { OS << "}\n"; }
38+
39+
void emitTableVariableNameSuffix(raw_ostream &OS) const {
40+
if (TheDef)
41+
OS << '_' << TheDef->getName();
42+
}
43+
};
44+
45+
class RuntimeLibcalls;
46+
class RuntimeLibcallImpl;
47+
48+
/// Used to apply predicates to nested sets of libcalls.
49+
struct LibcallPredicateExpander : SetTheory::Expander {
50+
const RuntimeLibcalls &Libcalls;
51+
DenseMap<const RuntimeLibcallImpl *,
52+
std::pair<std::vector<const Record *>, const Record *>> &Func2Preds;
53+
54+
LibcallPredicateExpander(
55+
const RuntimeLibcalls &Libcalls,
56+
DenseMap<const RuntimeLibcallImpl *,
57+
std::pair<std::vector<const Record *>, const Record *>>
58+
&Func2Preds)
59+
: Libcalls(Libcalls), Func2Preds(Func2Preds) {}
60+
61+
void expand(SetTheory &ST, const Record *Def,
62+
SetTheory::RecSet &Elts) override;
63+
};
64+
65+
class RuntimeLibcall {
66+
const Record *TheDef = nullptr;
67+
const size_t EnumVal;
68+
69+
public:
70+
RuntimeLibcall() = delete;
71+
RuntimeLibcall(const Record *Def, size_t EnumVal)
72+
: TheDef(Def), EnumVal(EnumVal) {
73+
assert(Def);
74+
}
75+
76+
~RuntimeLibcall() { assert(TheDef); }
77+
78+
const Record *getDef() const { return TheDef; }
79+
80+
StringRef getName() const { return TheDef->getName(); }
81+
82+
size_t getEnumVal() const { return EnumVal; }
83+
84+
void emitEnumEntry(raw_ostream &OS) const {
85+
OS << "RTLIB::" << TheDef->getValueAsString("Name");
86+
}
87+
};
88+
89+
class RuntimeLibcallImpl {
90+
const Record *TheDef;
91+
const RuntimeLibcall *Provides = nullptr;
92+
const size_t EnumVal;
93+
94+
public:
95+
RuntimeLibcallImpl(
96+
const Record *Def,
97+
const DenseMap<const Record *, const RuntimeLibcall *> &ProvideMap,
98+
size_t EnumVal)
99+
: TheDef(Def), EnumVal(EnumVal) {
100+
if (const Record *ProvidesDef = Def->getValueAsDef("Provides"))
101+
Provides = ProvideMap.lookup(ProvidesDef);
102+
}
103+
104+
~RuntimeLibcallImpl() = default;
105+
106+
const Record *getDef() const { return TheDef; }
107+
108+
StringRef getName() const { return TheDef->getName(); }
109+
110+
size_t getEnumVal() const { return EnumVal; }
111+
112+
const RuntimeLibcall *getProvides() const { return Provides; }
113+
114+
StringRef getLibcallFuncName() const {
115+
return TheDef->getValueAsString("LibCallFuncName");
116+
}
117+
118+
const Record *getCallingConv() const {
119+
return TheDef->getValueAsOptionalDef("CallingConv");
120+
}
121+
122+
void emitQuotedLibcallFuncName(raw_ostream &OS) const {
123+
OS << '\"' << getLibcallFuncName() << '\"';
124+
}
125+
126+
bool isDefault() const { return TheDef->getValueAsBit("IsDefault"); }
127+
128+
void emitEnumEntry(raw_ostream &OS) const {
129+
OS << "RTLIB::impl_" << this->getName();
130+
}
131+
132+
void emitSetImplCall(raw_ostream &OS) const {
133+
OS << "setLibcallImpl(";
134+
Provides->emitEnumEntry(OS);
135+
OS << ", ";
136+
emitEnumEntry(OS);
137+
OS << "); // " << getLibcallFuncName() << '\n';
138+
}
139+
140+
void emitTableEntry(raw_ostream &OS) const {
141+
OS << '{';
142+
Provides->emitEnumEntry(OS);
143+
OS << ", ";
144+
emitEnumEntry(OS);
145+
OS << "}, // " << getLibcallFuncName() << '\n';
146+
}
147+
148+
void emitSetCallingConv(raw_ostream &OS) const {}
149+
};
150+
151+
struct LibcallsWithCC {
152+
std::vector<const RuntimeLibcallImpl *> LibcallImpls;
153+
const Record *CallingConv = nullptr;
154+
};
155+
156+
class RuntimeLibcalls {
157+
private:
158+
DenseMap<const Record *, const RuntimeLibcall *> Def2RuntimeLibcall;
159+
DenseMap<const Record *, const RuntimeLibcallImpl *> Def2RuntimeLibcallImpl;
160+
161+
std::vector<RuntimeLibcall> RuntimeLibcallDefList;
162+
std::vector<RuntimeLibcallImpl> RuntimeLibcallImplDefList;
163+
164+
DenseMap<const RuntimeLibcall *, const RuntimeLibcallImpl *>
165+
LibCallToDefaultImpl;
166+
167+
public:
168+
RuntimeLibcalls(const RecordKeeper &Records);
169+
170+
ArrayRef<RuntimeLibcall> getRuntimeLibcallDefList() const {
171+
return RuntimeLibcallDefList;
172+
}
173+
174+
ArrayRef<RuntimeLibcallImpl> getRuntimeLibcallImplDefList() const {
175+
return RuntimeLibcallImplDefList;
176+
}
177+
178+
const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const {
179+
return Def2RuntimeLibcall.lookup(Def);
180+
}
181+
182+
const RuntimeLibcallImpl *getRuntimeLibcallImpl(const Record *Def) const {
183+
return Def2RuntimeLibcallImpl.lookup(Def);
184+
}
185+
};
186+
187+
} // namespace llvm
188+
189+
#endif // LLVM_UTILS_TABLEGEN_COMMON_RUNTIMELIBCALLS_H

0 commit comments

Comments
 (0)