Skip to content

Commit d3ad2c4

Browse files
committed
RuntimeLibcalls: Add bitset for available libcalls
This is a step towards separating the set of available libcalls from the lowering decision of which call to use. Libcall recognition now directly checks availability instead of indirectly checking through the lowering table.
1 parent 144cd87 commit d3ad2c4

File tree

6 files changed

+164
-8
lines changed

6 files changed

+164
-8
lines changed

llvm/include/llvm/IR/RuntimeLibcalls.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,64 @@ static inline auto libcall_impls() {
5353
return enum_seq(static_cast<RTLIB::LibcallImpl>(1), RTLIB::NumLibcallImpls);
5454
}
5555

56+
/// Manage a bitset representing the list of available libcalls for a module.
57+
///
58+
/// Most of this exists because std::bitset cannot be statically constructed in
59+
/// a size large enough before c++23
60+
class LibcallImplBitset {
61+
private:
62+
using BitWord = uint64_t;
63+
static constexpr unsigned BitWordSize = sizeof(BitWord) * CHAR_BIT;
64+
static constexpr size_t NumArrayElts =
65+
divideCeil(RTLIB::NumLibcallImpls, BitWordSize);
66+
using Storage = BitWord[NumArrayElts];
67+
68+
Storage Bits = {};
69+
70+
/// Get bitmask for \p Impl in its Bits element.
71+
static constexpr BitWord getBitmask(RTLIB::LibcallImpl Impl) {
72+
unsigned Idx = static_cast<unsigned>(Impl);
73+
return BitWord(1) << (Idx % BitWordSize);
74+
}
75+
76+
/// Get index of array element of Bits for \p Impl
77+
static constexpr unsigned getArrayIdx(RTLIB::LibcallImpl Impl) {
78+
return static_cast<unsigned>(Impl) / BitWordSize;
79+
}
80+
81+
public:
82+
constexpr LibcallImplBitset() = default;
83+
constexpr LibcallImplBitset(const Storage &Src) {
84+
for (size_t I = 0; I != NumArrayElts; ++I)
85+
Bits[I] = Src[I];
86+
}
87+
88+
/// Check if a LibcallImpl is available.
89+
constexpr bool test(RTLIB::LibcallImpl Impl) const {
90+
BitWord Mask = getBitmask(Impl);
91+
return (Bits[getArrayIdx(Impl)] & Mask) != 0;
92+
}
93+
94+
/// Mark a LibcallImpl as available
95+
void set(RTLIB::LibcallImpl Impl) {
96+
assert(Impl != RTLIB::Unsupported && "cannot enable unsupported libcall");
97+
Bits[getArrayIdx(Impl)] |= getBitmask(Impl);
98+
}
99+
100+
/// Mark a LibcallImpl as unavailable
101+
void unset(RTLIB::LibcallImpl Impl) {
102+
assert(Impl != RTLIB::Unsupported && "cannot enable unsupported libcall");
103+
Bits[getArrayIdx(Impl)] &= ~getBitmask(Impl);
104+
}
105+
};
106+
56107
/// A simple container for information about the supported runtime calls.
57108
struct RuntimeLibcallsInfo {
109+
private:
110+
/// Bitset of libcalls a module may emit a call to.
111+
LibcallImplBitset AvailableLibcallImpls;
112+
113+
public:
58114
explicit RuntimeLibcallsInfo(
59115
const Triple &TT,
60116
ExceptionHandling ExceptionModel = ExceptionHandling::None,
@@ -132,6 +188,14 @@ struct RuntimeLibcallsInfo {
132188
return ImplToLibcall[Impl];
133189
}
134190

191+
bool isAvailable(RTLIB::LibcallImpl Impl) const {
192+
return AvailableLibcallImpls.test(Impl);
193+
}
194+
195+
void setAvailable(RTLIB::LibcallImpl Impl) {
196+
AvailableLibcallImpls.set(Impl);
197+
}
198+
135199
/// Check if this is valid libcall for the current module, otherwise
136200
/// RTLIB::Unsupported.
137201
LLVM_ABI RTLIB::LibcallImpl getSupportedLibcallImpl(StringRef FuncName) const;

llvm/lib/IR/RuntimeLibcalls.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,8 @@ RuntimeLibcallsInfo::getSupportedLibcallImpl(StringRef FuncName) const {
101101
for (auto I = Range.begin(); I != Range.end(); ++I) {
102102
RTLIB::LibcallImpl Impl =
103103
static_cast<RTLIB::LibcallImpl>(I - RuntimeLibcallNameOffsets.begin());
104-
105-
// FIXME: This should not depend on looking up ImplToLibcall, only the list
106-
// of libcalls for the module.
107-
RTLIB::LibcallImpl Recognized = LibcallImpls[ImplToLibcall[Impl]];
108-
if (Recognized != RTLIB::Unsupported)
109-
return Recognized;
104+
if (isAvailable(Impl))
105+
return Impl;
110106
}
111107

112108
return RTLIB::Unsupported;

llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,18 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
4848
// CHECK-NEXT: Entry = DefaultCC;
4949
// CHECK-NEXT: }
5050
// CHECK-EMPTY:
51+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
52+
// CHECK-NEXT: 0x0000000000001a
53+
// CHECK-NEXT: });
54+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
55+
// CHECK-EMPTY:
5156
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
5257
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::malloc}, // malloc
5358
// CHECK-NEXT: };
5459
// CHECK-EMPTY:
5560
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
5661
// CHECK-NEXT: setLibcallImpl(Func, Impl);
62+
// CHECK-NEXT: setAvailable(Impl);
5763
// CHECK-NEXT: }
5864
// CHECK-EMPTY:
5965
// CHECK-NEXT: static const LibcallImplPair LibraryCalls_AlwaysAvailable[] = {
@@ -63,19 +69,26 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
6369
// CHECK-EMPTY:
6470
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_AlwaysAvailable) {
6571
// CHECK-NEXT: setLibcallImpl(Func, Impl);
72+
// CHECK-NEXT: setAvailable(Impl);
6673
// CHECK-NEXT: setLibcallImplCallingConv(Impl, CallingConv::AVR_BUILTIN);
6774
// CHECK-NEXT: }
6875
// CHECK-EMPTY:
6976
// CHECK-NEXT: return;
7077
// CHECK-NEXT: }
7178
// CHECK-EMPTY:
7279
// CHECK-NEXT: if (TT.getArch() == Triple::avr) {
80+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
81+
// CHECK-NEXT: 0x0000000000001a
82+
// CHECK-NEXT: });
83+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
84+
// CHECK-EMPTY:
7385
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
7486
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::malloc}, // malloc
7587
// CHECK-NEXT: };
7688
// CHECK-EMPTY:
7789
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
7890
// CHECK-NEXT: setLibcallImpl(Func, Impl);
91+
// CHECK-NEXT: setAvailable(Impl);
7992
// CHECK-NEXT: }
8093
// CHECK-EMPTY:
8194
// CHECK-NEXT: static const LibcallImplPair LibraryCalls_AlwaysAvailable[] = {
@@ -85,19 +98,26 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
8598
// CHECK-EMPTY:
8699
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_AlwaysAvailable) {
87100
// CHECK-NEXT: setLibcallImpl(Func, Impl);
101+
// CHECK-NEXT: setAvailable(Impl);
88102
// CHECK-NEXT: setLibcallImplCallingConv(Impl, CallingConv::AVR_BUILTIN);
89103
// CHECK-NEXT: }
90104
// CHECK-EMPTY:
91105
// CHECK-NEXT: return;
92106
// CHECK-NEXT: }
93107
// CHECK-EMPTY:
94108
// CHECK-NEXT: if (TT.getArch() == Triple::msp430) {
109+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
110+
// CHECK-NEXT: 0x00000000000010
111+
// CHECK-NEXT: });
112+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
113+
// CHECK-EMPTY:
95114
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
96115
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::malloc}, // malloc
97116
// CHECK-NEXT: };
98117
// CHECK-EMPTY:
99118
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
100119
// CHECK-NEXT: setLibcallImpl(Func, Impl);
120+
// CHECK-NEXT: setAvailable(Impl);
101121
// CHECK-NEXT: }
102122
// CHECK-EMPTY:
103123
// CHECK-NEXT: if ( isFoo() ) {
@@ -107,6 +127,7 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
107127
// CHECK-EMPTY:
108128
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_anonymous_3) {
109129
// CHECK-NEXT: setLibcallImpl(Func, Impl);
130+
// CHECK-NEXT: setAvailable(Impl);
110131
// CHECK-NEXT: setLibcallImplCallingConv(Impl, CallingConv::AVR_BUILTIN);
111132
// CHECK-NEXT: }
112133
// CHECK-EMPTY:
@@ -119,6 +140,7 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
119140
// CHECK-EMPTY:
120141
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_anonymous_5) {
121142
// CHECK-NEXT: setLibcallImpl(Func, Impl);
143+
// CHECK-NEXT: setAvailable(Impl);
122144
// CHECK-NEXT: setLibcallImplCallingConv(Impl, CallingConv::MSP430_BUILTIN);
123145
// CHECK-NEXT: }
124146
// CHECK-EMPTY:

llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ def dup1 : RuntimeLibcallImpl<ANOTHER_DUP>;
2525
// func_a and func_b both provide SOME_FUNC.
2626

2727
// CHECK: if (isTargetArchA()) {
28+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
29+
// CHECK-NEXT: 0x00000000000018
30+
// CHECK-NEXT: });
31+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
32+
// CHECK-EMPTY:
2833
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
2934
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_b}, // func_b
3035
// CHECK-NEXT: };
@@ -35,6 +40,11 @@ def TheSystemLibraryA : SystemRuntimeLibrary<isTargetArchA,
3540
>;
3641

3742
// CHECK: if (isTargetArchB()) {
43+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
44+
// CHECK-NEXT: 0x00000000000058
45+
// CHECK-NEXT: });
46+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
47+
// CHECK-EMPTY:
3848
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
3949
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func
4050
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a
@@ -46,6 +56,11 @@ def TheSystemLibraryB : SystemRuntimeLibrary<isTargetArchB,
4656
>;
4757

4858
// CHECK: if (isTargetArchC()) {
59+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
60+
// CHECK-NEXT: 0x0000000000007e
61+
// CHECK-NEXT: });
62+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
63+
// CHECK-EMPTY:
4964
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
5065
// CHECK-NEXT: {RTLIB::ANOTHER_DUP, RTLIB::dup1}, // dup1
5166
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func

llvm/test/TableGen/RuntimeLibcallEmitter.td

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
157157
// CHECK-NEXT: };
158158
// CHECK-EMPTY:
159159
// CHECK-NEXT: if (TT.getArch() == Triple::blah) {
160+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
161+
// CHECK-NEXT: 0x000000000000e0
162+
// CHECK-NEXT: });
163+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
164+
// CHECK-EMPTY:
160165
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
161166
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::bzero}, // bzero
162167
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::calloc}, // calloc
@@ -165,6 +170,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
165170
// CHECK-EMPTY:
166171
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
167172
// CHECK-NEXT: setLibcallImpl(Func, Impl);
173+
// CHECK-NEXT: setAvailable(Impl);
168174
// CHECK-NEXT: }
169175
// CHECK-EMPTY:
170176
// CHECK-NEXT: if (TT.hasCompilerRT()) {
@@ -175,6 +181,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
175181
// CHECK-EMPTY:
176182
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_hasCompilerRT) {
177183
// CHECK-NEXT: setLibcallImpl(Func, Impl);
184+
// CHECK-NEXT: setAvailable(Impl);
178185
// CHECK-NEXT: }
179186
// CHECK-EMPTY:
180187
// CHECK-NEXT: }
@@ -186,6 +193,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
186193
// CHECK-EMPTY:
187194
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_isBarOS) {
188195
// CHECK-NEXT: setLibcallImpl(Func, Impl);
196+
// CHECK-NEXT: setAvailable(Impl);
189197
// CHECK-NEXT: }
190198
// CHECK-EMPTY:
191199
// CHECK-NEXT: }
@@ -194,6 +202,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
194202
// CHECK-NEXT: }
195203
// CHECK-EMPTY:
196204
// CHECK-NEXT: if (TT.getArch() == Triple::buzz) {
205+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
206+
// CHECK-NEXT: 0x00000000000118
207+
// CHECK-NEXT: });
208+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
209+
// CHECK-EMPTY:
197210
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
198211
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3
199212
// CHECK-NEXT: {RTLIB::SQRT_F80, RTLIB::sqrtl_f80}, // sqrtl
@@ -202,19 +215,26 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
202215
// CHECK-EMPTY:
203216
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
204217
// CHECK-NEXT: setLibcallImpl(Func, Impl);
218+
// CHECK-NEXT: setAvailable(Impl);
205219
// CHECK-NEXT: }
206220
// CHECK-EMPTY:
207221
// CHECK-NEXT: return;
208222
// CHECK-NEXT: }
209223
// CHECK-EMPTY:
210224
// CHECK-NEXT: if (TT.getArch() == Triple::foo) {
225+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
226+
// CHECK-NEXT: 0x000000000000a0
227+
// CHECK-NEXT: });
228+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
229+
// CHECK-EMPTY:
211230
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
212231
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::bzero}, // bzero
213232
// CHECK-NEXT: {RTLIB::SQRT_F128, RTLIB::sqrtl_f128}, // sqrtl
214233
// CHECK-NEXT: };
215234
// CHECK-EMPTY:
216235
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
217236
// CHECK-NEXT: setLibcallImpl(Func, Impl);
237+
// CHECK-NEXT: setAvailable(Impl);
218238
// CHECK-NEXT: }
219239
// CHECK-EMPTY:
220240
// CHECK-NEXT: if (TT.getOS() == Triple::bar) {
@@ -224,6 +244,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
224244
// CHECK-EMPTY:
225245
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_isBarOS) {
226246
// CHECK-NEXT: setLibcallImpl(Func, Impl);
247+
// CHECK-NEXT: setAvailable(Impl);
227248
// CHECK-NEXT: }
228249
// CHECK-EMPTY:
229250
// CHECK-NEXT: }
@@ -232,6 +253,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
232253
// CHECK-NEXT: }
233254
// CHECK-EMPTY:
234255
// CHECK-NEXT: if (TT.getArch() == Triple::simple) {
256+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
257+
// CHECK-NEXT: 0x00000000000158
258+
// CHECK-NEXT: });
259+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
260+
// CHECK-EMPTY:
235261
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
236262
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::calloc}, // calloc
237263
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3
@@ -241,6 +267,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
241267
// CHECK-EMPTY:
242268
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
243269
// CHECK-NEXT: setLibcallImpl(Func, Impl);
270+
// CHECK-NEXT: setAvailable(Impl);
244271
// CHECK-NEXT: }
245272
// CHECK-EMPTY:
246273
// CHECK-NEXT: return;

0 commit comments

Comments
 (0)