Skip to content

Commit b76bc42

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 ccae485 commit b76bc42

File tree

5 files changed

+188
-24
lines changed

5 files changed

+188
-24
lines changed

llvm/include/llvm/IR/RuntimeLibcalls.h

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

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

188+
bool isAvailable(RTLIB::LibcallImpl Impl) const {
189+
return AvailableLibcallImpls.test(Impl);
190+
}
191+
192+
void setAvailable(RTLIB::LibcallImpl Impl) {
193+
AvailableLibcallImpls.set(Impl);
194+
}
195+
132196
/// Return the libcall provided by \p Impl
133197
static RTLIB::Libcall getLibcallFromImpl(RTLIB::LibcallImpl Impl) {
134198
return ImplToLibcall[Impl];

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ 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::impl_malloc}, // malloc
5358
// CHECK-NEXT: };
@@ -70,9 +75,14 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
7075
// CHECK-NEXT: }
7176
// CHECK-EMPTY:
7277
// CHECK-NEXT: if (TT.getArch() == Triple::avr) {
73-
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
74-
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::impl_malloc}, // malloc
75-
// CHECK-NEXT: };
78+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
79+
// CHECK-NEXT: 0x0000000000001a
80+
// CHECK-NEXT: });
81+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
82+
// CHECK-EMPTY:
83+
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
84+
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::impl_malloc}, // malloc
85+
// CHECK-NEXT: };
7686
// CHECK-EMPTY:
7787
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
7888
// CHECK-NEXT: setLibcallImpl(Func, Impl);
@@ -92,6 +102,11 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
92102
// CHECK-NEXT: }
93103
// CHECK-EMPTY:
94104
// CHECK-NEXT: if (TT.getArch() == Triple::msp430) {
105+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
106+
// CHECK-NEXT: 0x00000000000010
107+
// CHECK-NEXT: });
108+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
109+
// CHECK-EMPTY:
95110
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
96111
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::impl_malloc}, // malloc
97112
// CHECK-NEXT: };

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

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

2727
// CHECK: if (isTargetArchA()) {
28-
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
29-
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_b}, // func_b
30-
// CHECK-NEXT: };
28+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
29+
// CHECK-NEXT: 0x00000000000018
30+
// CHECK-NEXT: });
31+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
32+
// CHECK-EMPTY:
33+
34+
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
35+
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_b}, // func_b
36+
// CHECK-NEXT: };
37+
// CHECK-EMPTY:
38+
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
39+
// CHECK-NEXT: setLibcallImpl(Func, Impl);
40+
// CHECK-NEXT: }
41+
// CHECK-EMPTY:
42+
// CHECK-NEXT: return;
43+
// CHECK-NEXT: }
3144

3245
// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_b, func_a
3346
def TheSystemLibraryA : SystemRuntimeLibrary<isTargetArchA,
3447
(add func_b, func_a)
3548
>;
3649

3750
// CHECK: if (isTargetArchB()) {
38-
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
39-
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::impl_other_func}, // other_func
40-
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_a}, // func_a
41-
// CHECK-NEXT: };
51+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
52+
// CHECK-NEXT: 0x00000000000058
53+
// CHECK-NEXT: });
54+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
55+
// CHECK-EMPTY:
56+
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
57+
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::impl_other_func}, // other_func
58+
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_a}, // func_a
59+
// CHECK-NEXT: };
60+
// CHECK-EMPTY:
61+
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
62+
// CHECK-NEXT: setLibcallImpl(Func, Impl);
63+
// CHECK-NEXT: }
64+
// CHECK-EMPTY:
65+
// CHECK-NEXT: return;
66+
// CHECK-NEXT: }
4267

4368
// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b
4469
def TheSystemLibraryB : SystemRuntimeLibrary<isTargetArchB,
4570
(add func_a, other_func, func_b)
4671
>;
4772

4873
// CHECK: if (isTargetArchC()) {
49-
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
50-
// CHECK-NEXT: {RTLIB::ANOTHER_DUP, RTLIB::impl_dup1}, // dup1
51-
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::impl_other_func}, // other_func
52-
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_a}, // func_a
53-
// CHECK-NEXT: };
74+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
75+
// CHECK-NEXT: 0x0000000000007e
76+
// CHECK-NEXT: });
77+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
78+
// CHECK-EMPTY:
79+
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
80+
// CHECK-NEXT: {RTLIB::ANOTHER_DUP, RTLIB::impl_dup1}, // dup1
81+
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::impl_other_func}, // other_func
82+
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_a}, // func_a
83+
// CHECK-NEXT: };
84+
// CHECK-EMPTY:
85+
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
86+
// CHECK-NEXT: setLibcallImpl(Func, Impl);
87+
// CHECK-NEXT: }
88+
// CHECK-EMPTY:
89+
// CHECK-NEXT: return;
90+
// CHECK-NEXT: }
5491

5592
// ERR: :[[@LINE+3]]:5: warning: conflicting implementations for libcall ANOTHER_DUP: dup1, dup0
5693
// ERR: :[[@LINE+2]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b

llvm/test/TableGen/RuntimeLibcallEmitter.td

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,20 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
196196
// CHECK-NEXT: };
197197
// CHECK-EMPTY:
198198
// CHECK-NEXT: if (TT.getArch() == Triple::blah) {
199-
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
200-
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::impl_bzero}, // bzero
201-
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::impl_calloc}, // calloc
202-
// CHECK-NEXT: {RTLIB::SQRT_F128, RTLIB::impl_sqrtl_f128}, // sqrtl
203-
// CHECK-NEXT: };
199+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
200+
// CHECK-NEXT: 0x000000000000e0
201+
// CHECK-NEXT: });
202+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
204203
// CHECK-EMPTY:
205-
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
206-
// CHECK-NEXT: setLibcallImpl(Func, Impl);
207-
// CHECK-NEXT: }
204+
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
205+
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::impl_bzero}, // bzero
206+
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::impl_calloc}, // calloc
207+
// CHECK-NEXT: {RTLIB::SQRT_F128, RTLIB::impl_sqrtl_f128}, // sqrtl
208+
// CHECK-NEXT: };
209+
// CHECK-EMPTY:
210+
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
211+
// CHECK-NEXT: setLibcallImpl(Func, Impl);
212+
// CHECK-NEXT: }
208213
// CHECK-EMPTY:
209214
// CHECK-NEXT: if (TT.hasCompilerRT()) {
210215
// CHECK-NEXT: static const LibcallImplPair LibraryCalls_hasCompilerRT[] = {
@@ -233,6 +238,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
233238
// CHECK-NEXT: }
234239
// CHECK-EMPTY:
235240
// CHECK-NEXT: if (TT.getArch() == Triple::buzz) {
241+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
242+
// CHECK-NEXT: 0x00000000000118
243+
// CHECK-NEXT: });
244+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
245+
// CHECK-EMPTY:
236246
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
237247
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::impl___ashlsi3}, // __ashlsi3
238248
// CHECK-NEXT: {RTLIB::SQRT_F80, RTLIB::impl_sqrtl_f80}, // sqrtl
@@ -247,6 +257,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
247257
// CHECK-NEXT: }
248258
// CHECK-EMPTY:
249259
// CHECK-NEXT: if (TT.getArch() == Triple::foo) {
260+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
261+
// CHECK-NEXT: 0x000000000000a0
262+
// CHECK-NEXT: });
263+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
264+
// CHECK-EMPTY:
250265
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
251266
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::impl_bzero}, // bzero
252267
// CHECK-NEXT: {RTLIB::SQRT_F128, RTLIB::impl_sqrtl_f128}, // sqrtl
@@ -271,6 +286,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
271286
// CHECK-NEXT: }
272287
// CHECK-EMPTY:
273288
// CHECK-NEXT: if (TT.getArch() == Triple::simple) {
289+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
290+
// CHECK-NEXT: 0x00000000000158
291+
// CHECK-NEXT: });
292+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
293+
// CHECK-EMPTY:
274294
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
275295
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::impl_calloc}, // calloc
276296
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::impl___ashlsi3}, // __ashlsi3

llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,10 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
589589
PredicateWithCC()); // No predicate or CC override first.
590590

591591
DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs;
592+
593+
SmallVector<uint64_t, 32> BitsetValues(
594+
divideCeil(RuntimeLibcallImplDefList.size(), 64));
595+
592596
for (const Record *Elt : *Elements) {
593597
const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt);
594598
if (!LibCallImpl) {
@@ -597,23 +601,47 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
597601
continue;
598602
}
599603

604+
size_t BitIdx = LibCallImpl->getEnumVal();
605+
uint64_t BitmaskVal = uint64_t(1) << (BitIdx % 64);
606+
size_t BitsetIdx = BitIdx / 64;
607+
600608
auto It = Func2Preds.find(LibCallImpl);
601609
if (It == Func2Preds.end()) {
610+
BitsetValues[BitsetIdx] |= BitmaskVal;
602611
Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(LibCallImpl);
603612
continue;
604613
}
605614

606615
for (const Record *Pred : It->second.first) {
607616
const Record *CC = It->second.second;
608-
PredicateWithCC Key(Pred, CC);
617+
AvailabilityPredicate SubsetPredicate(Pred);
618+
if (SubsetPredicate.isAlwaysAvailable())
619+
BitsetValues[BitsetIdx] |= BitmaskVal;
609620

621+
PredicateWithCC Key(Pred, CC);
610622
auto &Entry = Pred2Funcs[Key];
611623
Entry.LibcallImpls.push_back(LibCallImpl);
612624
Entry.CallingConv = It->second.second;
613625
PredicateSorter.insert(Key);
614626
}
615627
}
616628

629+
OS << " static constexpr LibcallImplBitset SystemAvailableImpls({\n"
630+
<< indent(6);
631+
632+
ListSeparator LS;
633+
unsigned EntryCount = 0;
634+
for (uint64_t Bits : BitsetValues) {
635+
if (EntryCount++ == 4) {
636+
EntryCount = 1;
637+
OS << ",\n" << indent(6);
638+
} else
639+
OS << LS;
640+
OS << format_hex(Bits, 16);
641+
}
642+
OS << "\n });\n"
643+
" AvailableLibcallImpls = SystemAvailableImpls;\n\n";
644+
617645
SmallVector<PredicateWithCC, 0> SortedPredicates =
618646
PredicateSorter.takeVector();
619647

0 commit comments

Comments
 (0)