Skip to content

Commit e2d7109

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 56131e3 commit e2d7109

File tree

6 files changed

+151
-12
lines changed

6 files changed

+151
-12
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
@@ -96,12 +96,8 @@ RuntimeLibcallsInfo::getSupportedLibcallImpl(StringRef FuncName) const {
9696
for (auto I = Range.begin(); I != Range.end(); ++I) {
9797
RTLIB::LibcallImpl Impl =
9898
static_cast<RTLIB::LibcallImpl>(I - RuntimeLibcallNameOffsets.begin());
99-
100-
// FIXME: This should not depend on looking up ImplToLibcall, only the list
101-
// of libcalls for the module.
102-
RTLIB::LibcallImpl Recognized = LibcallImpls[ImplToLibcall[Impl]];
103-
if (Recognized != RTLIB::Unsupported)
104-
return Recognized;
99+
if (isAvailable(Impl))
100+
return Impl;
105101
}
106102

107103
return RTLIB::Unsupported;

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::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::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::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::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::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: setLibcallsImpl({
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: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,21 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
157157
// CHECK-NEXT: };
158158
// CHECK-NEXT: auto setLibcallsImpl = [this](
159159
// CHECK-NEXT: ArrayRef<LibcallImplPair> Libcalls,
160-
// CHECK-NEXT: std::optional<llvm::CallingConv::ID> CC = {})
161-
// CHECK-NEXT: {
160+
// CHECK-NEXT: std::optional<llvm::CallingConv::ID> CC = {}) {
162161
// CHECK-NEXT: for (const auto [Func, Impl] : Libcalls) {
163162
// CHECK-NEXT: setLibcallImpl(Func, Impl);
163+
// CHECK-NEXT: setAvailable(Impl);
164164
// CHECK-NEXT: if (CC)
165165
// CHECK-NEXT: setLibcallImplCallingConv(Impl, *CC);
166166
// CHECK-NEXT: }
167167
// CHECK-NEXT: };
168168
// CHECK-EMPTY:
169169
// CHECK-NEXT: if (TT.getArch() == Triple::blah) {
170+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
171+
// CHECK-NEXT: 0x000000000000e0
172+
// CHECK-NEXT: });
173+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
174+
// CHECK-EMPTY:
170175
// CHECK-NEXT: setLibcallsImpl({
171176
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::bzero}, // bzero
172177
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::calloc}, // calloc
@@ -192,6 +197,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
192197
// CHECK-NEXT: }
193198
// CHECK-EMPTY:
194199
// CHECK-NEXT: if (TT.getArch() == Triple::buzz) {
200+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
201+
// CHECK-NEXT: 0x00000000000118
202+
// CHECK-NEXT: });
203+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
204+
// CHECK-EMPTY:
195205
// CHECK-NEXT: setLibcallsImpl({
196206
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3
197207
// CHECK-NEXT: {RTLIB::SQRT_F80, RTLIB::sqrtl_f80}, // sqrtl
@@ -202,6 +212,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
202212
// CHECK-NEXT: }
203213
// CHECK-EMPTY:
204214
// CHECK-NEXT: if (TT.getArch() == Triple::foo) {
215+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
216+
// CHECK-NEXT: 0x000000000000a0
217+
// CHECK-NEXT: });
218+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
219+
// CHECK-EMPTY:
205220
// CHECK-NEXT: setLibcallsImpl({
206221
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::bzero}, // bzero
207222
// CHECK-NEXT: {RTLIB::SQRT_F128, RTLIB::sqrtl_f128}, // sqrtl
@@ -218,6 +233,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
218233
// CHECK-NEXT: }
219234
// CHECK-EMPTY:
220235
// CHECK-NEXT: if (TT.getArch() == Triple::simple) {
236+
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
237+
// CHECK-NEXT: 0x00000000000158
238+
// CHECK-NEXT: });
239+
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
240+
// CHECK-EMPTY:
221241
// CHECK-NEXT: setLibcallsImpl({
222242
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::calloc}, // calloc
223243
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3

llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "llvm/ADT/StringRef.h"
1010
#include "llvm/Support/Debug.h"
11+
#include "llvm/Support/Format.h"
1112
#include "llvm/Support/FormatVariadic.h"
1213
#include "llvm/Support/raw_ostream.h"
1314
#include "llvm/TableGen/Error.h"
@@ -363,10 +364,10 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
363364
" };\n"
364365
" auto setLibcallsImpl = [this](\n"
365366
" ArrayRef<LibcallImplPair> Libcalls,\n"
366-
" std::optional<llvm::CallingConv::ID> CC = {})\n"
367-
" {\n"
367+
" std::optional<llvm::CallingConv::ID> CC = {}) {\n"
368368
" for (const auto [Func, Impl] : Libcalls) {\n"
369369
" setLibcallImpl(Func, Impl);\n"
370+
" setAvailable(Impl);\n"
370371
" if (CC)\n"
371372
" setLibcallImplCallingConv(Impl, *CC);\n"
372373
" }\n"
@@ -412,6 +413,10 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
412413
PredicateWithCC()); // No predicate or CC override first.
413414

414415
DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs;
416+
417+
SmallVector<uint64_t, 32> BitsetValues(
418+
divideCeil(RuntimeLibcallImplDefList.size(), 64));
419+
415420
for (const Record *Elt : *Elements) {
416421
const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt);
417422
if (!LibCallImpl) {
@@ -420,23 +425,47 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
420425
continue;
421426
}
422427

428+
size_t BitIdx = LibCallImpl->getEnumVal();
429+
uint64_t BitmaskVal = uint64_t(1) << (BitIdx % 64);
430+
size_t BitsetIdx = BitIdx / 64;
431+
423432
auto It = Func2Preds.find(LibCallImpl);
424433
if (It == Func2Preds.end()) {
434+
BitsetValues[BitsetIdx] |= BitmaskVal;
425435
Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(LibCallImpl);
426436
continue;
427437
}
428438

429439
for (const Record *Pred : It->second.first) {
430440
const Record *CC = It->second.second;
431-
PredicateWithCC Key(Pred, CC);
441+
AvailabilityPredicate SubsetPredicate(Pred);
442+
if (SubsetPredicate.isAlwaysAvailable())
443+
BitsetValues[BitsetIdx] |= BitmaskVal;
432444

445+
PredicateWithCC Key(Pred, CC);
433446
auto &Entry = Pred2Funcs[Key];
434447
Entry.LibcallImpls.push_back(LibCallImpl);
435448
Entry.CallingConv = It->second.second;
436449
PredicateSorter.insert(Key);
437450
}
438451
}
439452

453+
OS << " static constexpr LibcallImplBitset SystemAvailableImpls({\n"
454+
<< indent(6);
455+
456+
ListSeparator LS;
457+
unsigned EntryCount = 0;
458+
for (uint64_t Bits : BitsetValues) {
459+
if (EntryCount++ == 4) {
460+
EntryCount = 1;
461+
OS << ",\n" << indent(6);
462+
} else
463+
OS << LS;
464+
OS << format_hex(Bits, 16);
465+
}
466+
OS << "\n });\n"
467+
" AvailableLibcallImpls = SystemAvailableImpls;\n\n";
468+
440469
SmallVector<PredicateWithCC, 0> SortedPredicates =
441470
PredicateSorter.takeVector();
442471

@@ -500,7 +529,7 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
500529
OS << indent(IndentDepth + 4);
501530
LibCallImpl->emitTableEntry(OS);
502531
}
503-
OS << indent(IndentDepth + 2) << "}";
532+
OS << indent(IndentDepth + 2) << '}';
504533
if (FuncsWithCC.CallingConv) {
505534
StringRef CCEnum =
506535
FuncsWithCC.CallingConv->getValueAsString("CallingConv");

0 commit comments

Comments
 (0)