Skip to content

Commit 601ec04

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 44b7abc commit 601ec04

File tree

5 files changed

+148
-6
lines changed

5 files changed

+148
-6
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: 15 additions & 0 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: setLibcallsImpl({
5257
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::impl_malloc}, // malloc
5358
// CHECK-NEXT: });
@@ -61,6 +66,11 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
6166
// CHECK-NEXT: }
6267
// CHECK-EMPTY:
6368
// CHECK-NEXT: if (TT.getArch() == Triple::avr) {
69+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
70+
// CHECK-NEXT: 0x0000000000001a
71+
// CHECK-NEXT: });
72+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
73+
// CHECK-EMPTY:
6474
// CHECK-NEXT: setLibcallsImpl({
6575
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::impl_malloc}, // malloc
6676
// CHECK-NEXT: });
@@ -74,6 +84,11 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
7484
// CHECK-NEXT: }
7585
// CHECK-EMPTY:
7686
// CHECK-NEXT: if (TT.getArch() == Triple::msp430) {
87+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
88+
// CHECK-NEXT: 0x00000000000010
89+
// CHECK-NEXT: });
90+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
91+
// CHECK-EMPTY:
7792
// CHECK-NEXT: setLibcallsImpl({
7893
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::impl_malloc}, // malloc
7994
// CHECK-NEXT: });

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: setLibcallsImpl({
2934
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_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: setLibcallsImpl({
3949
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::impl_other_func}, // other_func
4050
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_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: setLibcallsImpl({
5065
// CHECK-NEXT: {RTLIB::ANOTHER_DUP, RTLIB::impl_dup1}, // dup1
5166
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::impl_other_func}, // other_func

llvm/test/TableGen/RuntimeLibcallEmitter.td

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,16 +196,21 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
196196
// CHECK-NEXT: };
197197
// CHECK-NEXT: auto setLibcallsImpl = [this](
198198
// CHECK-NEXT: ArrayRef<LibcallImplPair> Libcalls,
199-
// CHECK-NEXT: std::optional<llvm::CallingConv::ID> CC = {})
200-
// CHECK-NEXT: {
199+
// CHECK-NEXT: std::optional<llvm::CallingConv::ID> CC = {}) {
201200
// CHECK-NEXT: for (const auto [Func, Impl] : Libcalls) {
202201
// CHECK-NEXT: setLibcallImpl(Func, Impl);
202+
// CHECK-NEXT: setAvailable(Impl);
203203
// CHECK-NEXT: if (CC)
204204
// CHECK-NEXT: setLibcallImplCallingConv(Impl, *CC);
205205
// CHECK-NEXT: }
206206
// CHECK-NEXT: };
207207
// CHECK-EMPTY:
208208
// CHECK-NEXT: if (TT.getArch() == Triple::blah) {
209+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
210+
// CHECK-NEXT: 0x000000000000e0
211+
// CHECK-NEXT: });
212+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
213+
// CHECK-EMPTY:
209214
// CHECK-NEXT: setLibcallsImpl({
210215
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::impl_bzero}, // bzero
211216
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::impl_calloc}, // calloc
@@ -231,6 +236,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
231236
// CHECK-NEXT: }
232237
// CHECK-EMPTY:
233238
// CHECK-NEXT: if (TT.getArch() == Triple::buzz) {
239+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
240+
// CHECK-NEXT: 0x00000000000118
241+
// CHECK-NEXT: });
242+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
243+
// CHECK-EMPTY:
234244
// CHECK-NEXT: setLibcallsImpl({
235245
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::impl___ashlsi3}, // __ashlsi3
236246
// CHECK-NEXT: {RTLIB::SQRT_F80, RTLIB::impl_sqrtl_f80}, // sqrtl
@@ -241,6 +251,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
241251
// CHECK-NEXT: }
242252
// CHECK-EMPTY:
243253
// CHECK-NEXT: if (TT.getArch() == Triple::foo) {
254+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
255+
// CHECK-NEXT: 0x000000000000a0
256+
// CHECK-NEXT: });
257+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
258+
// CHECK-EMPTY:
244259
// CHECK-NEXT: setLibcallsImpl({
245260
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::impl_bzero}, // bzero
246261
// CHECK-NEXT: {RTLIB::SQRT_F128, RTLIB::impl_sqrtl_f128}, // sqrtl
@@ -257,6 +272,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
257272
// CHECK-NEXT: }
258273
// CHECK-EMPTY:
259274
// CHECK-NEXT: if (TT.getArch() == Triple::simple) {
275+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
276+
// CHECK-NEXT: 0x00000000000158
277+
// CHECK-NEXT: });
278+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
279+
// CHECK-EMPTY:
260280
// CHECK-NEXT: setLibcallsImpl({
261281
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::impl_calloc}, // calloc
262282
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::impl___ashlsi3}, // __ashlsi3

llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,10 +550,10 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
550550
" };\n"
551551
" auto setLibcallsImpl = [this](\n"
552552
" ArrayRef<LibcallImplPair> Libcalls,\n"
553-
" std::optional<llvm::CallingConv::ID> CC = {})\n"
554-
" {\n"
553+
" std::optional<llvm::CallingConv::ID> CC = {}) {\n"
555554
" for (const auto [Func, Impl] : Libcalls) {\n"
556555
" setLibcallImpl(Func, Impl);\n"
556+
" setAvailable(Impl);\n"
557557
" if (CC)\n"
558558
" setLibcallImplCallingConv(Impl, *CC);\n"
559559
" }\n"
@@ -599,6 +599,10 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
599599
PredicateWithCC()); // No predicate or CC override first.
600600

601601
DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs;
602+
603+
SmallVector<uint64_t, 32> BitsetValues(
604+
divideCeil(RuntimeLibcallImplDefList.size(), 64));
605+
602606
for (const Record *Elt : *Elements) {
603607
const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt);
604608
if (!LibCallImpl) {
@@ -607,23 +611,47 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
607611
continue;
608612
}
609613

614+
size_t BitIdx = LibCallImpl->getEnumVal();
615+
uint64_t BitmaskVal = uint64_t(1) << (BitIdx % 64);
616+
size_t BitsetIdx = BitIdx / 64;
617+
610618
auto It = Func2Preds.find(LibCallImpl);
611619
if (It == Func2Preds.end()) {
620+
BitsetValues[BitsetIdx] |= BitmaskVal;
612621
Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(LibCallImpl);
613622
continue;
614623
}
615624

616625
for (const Record *Pred : It->second.first) {
617626
const Record *CC = It->second.second;
618-
PredicateWithCC Key(Pred, CC);
627+
AvailabilityPredicate SubsetPredicate(Pred);
628+
if (SubsetPredicate.isAlwaysAvailable())
629+
BitsetValues[BitsetIdx] |= BitmaskVal;
619630

631+
PredicateWithCC Key(Pred, CC);
620632
auto &Entry = Pred2Funcs[Key];
621633
Entry.LibcallImpls.push_back(LibCallImpl);
622634
Entry.CallingConv = It->second.second;
623635
PredicateSorter.insert(Key);
624636
}
625637
}
626638

639+
OS << " static constexpr LibcallImplBitset SystemAvailableImpls({\n"
640+
<< indent(6);
641+
642+
ListSeparator LS;
643+
unsigned EntryCount = 0;
644+
for (uint64_t Bits : BitsetValues) {
645+
if (EntryCount++ == 4) {
646+
EntryCount = 1;
647+
OS << ",\n" << indent(6);
648+
} else
649+
OS << LS;
650+
OS << format_hex(Bits, 16);
651+
}
652+
OS << "\n });\n"
653+
" AvailableLibcallImpls = SystemAvailableImpls;\n\n";
654+
627655
SmallVector<PredicateWithCC, 0> SortedPredicates =
628656
PredicateSorter.takeVector();
629657

@@ -687,7 +715,7 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
687715
OS << indent(IndentDepth + 4);
688716
LibCallImpl->emitTableEntry(OS);
689717
}
690-
OS << indent(IndentDepth + 2) << "}";
718+
OS << indent(IndentDepth + 2) << '}';
691719
if (FuncsWithCC.CallingConv) {
692720
StringRef CCEnum =
693721
FuncsWithCC.CallingConv->getValueAsString("CallingConv");

0 commit comments

Comments
 (0)