Skip to content

Commit aa406aa

Browse files
authored
RuntimeLibcalls: Add bitset for available libcalls (llvm#150869)
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 eace84d commit aa406aa

File tree

5 files changed

+148
-24
lines changed

5 files changed

+148
-24
lines changed

llvm/include/llvm/IR/RuntimeLibcalls.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_IR_RUNTIME_LIBCALLS_H
1616

1717
#include "llvm/ADT/ArrayRef.h"
18+
#include "llvm/ADT/Bitset.h"
1819
#include "llvm/ADT/Sequence.h"
1920
#include "llvm/ADT/StringTable.h"
2021
#include "llvm/IR/CallingConv.h"
@@ -54,8 +55,22 @@ static inline auto libcall_impls() {
5455
static_cast<RTLIB::LibcallImpl>(RTLIB::NumLibcallImpls));
5556
}
5657

58+
/// Manage a bitset representing the list of available libcalls for a module.
59+
class LibcallImplBitset : public Bitset<RTLIB::NumLibcallImpls> {
60+
public:
61+
constexpr LibcallImplBitset() = default;
62+
constexpr LibcallImplBitset(
63+
const std::array<uint64_t, (RTLIB::NumLibcallImpls + 63) / 64> &Src)
64+
: Bitset(Src) {}
65+
};
66+
5767
/// A simple container for information about the supported runtime calls.
5868
struct RuntimeLibcallsInfo {
69+
private:
70+
/// Bitset of libcalls a module may emit a call to.
71+
LibcallImplBitset AvailableLibcallImpls;
72+
73+
public:
5974
explicit RuntimeLibcallsInfo(
6075
const Triple &TT,
6176
ExceptionHandling ExceptionModel = ExceptionHandling::None,
@@ -129,6 +144,14 @@ struct RuntimeLibcallsInfo {
129144
return getLibcallName(RTLIB::MEMMOVE);
130145
}
131146

147+
bool isAvailable(RTLIB::LibcallImpl Impl) const {
148+
return AvailableLibcallImpls.test(Impl);
149+
}
150+
151+
void setAvailable(RTLIB::LibcallImpl Impl) {
152+
AvailableLibcallImpls.set(Impl);
153+
}
154+
132155
/// Return the libcall provided by \p Impl
133156
static RTLIB::Libcall getLibcallFromImpl(RTLIB::LibcallImpl Impl) {
134157
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: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,12 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
588588
PredicateSorter.insert(
589589
PredicateWithCC()); // No predicate or CC override first.
590590

591+
constexpr unsigned BitsPerStorageElt = 64;
591592
DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs;
593+
594+
SmallVector<uint64_t, 32> BitsetValues(
595+
divideCeil(RuntimeLibcallImplDefList.size(), BitsPerStorageElt));
596+
592597
for (const Record *Elt : *Elements) {
593598
const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt);
594599
if (!LibCallImpl) {
@@ -597,23 +602,47 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
597602
continue;
598603
}
599604

605+
size_t BitIdx = LibCallImpl->getEnumVal();
606+
uint64_t BitmaskVal = uint64_t(1) << (BitIdx % BitsPerStorageElt);
607+
size_t BitsetIdx = BitIdx / BitsPerStorageElt;
608+
600609
auto It = Func2Preds.find(LibCallImpl);
601610
if (It == Func2Preds.end()) {
611+
BitsetValues[BitsetIdx] |= BitmaskVal;
602612
Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(LibCallImpl);
603613
continue;
604614
}
605615

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

622+
PredicateWithCC Key(Pred, CC);
610623
auto &Entry = Pred2Funcs[Key];
611624
Entry.LibcallImpls.push_back(LibCallImpl);
612625
Entry.CallingConv = It->second.second;
613626
PredicateSorter.insert(Key);
614627
}
615628
}
616629

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

0 commit comments

Comments
 (0)