Skip to content

RuntimeLibcalls: Add bitset for available libcalls #150869

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: users/arsenm/runtime-libcalls/use-tablegen-default-handling
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions llvm/include/llvm/IR/RuntimeLibcalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,64 @@ static inline auto libcall_impls() {
return enum_seq(static_cast<RTLIB::LibcallImpl>(1), RTLIB::NumLibcallImpls);
}

/// Manage a bitset representing the list of available libcalls for a module.
///
/// Most of this exists because std::bitset cannot be statically constructed in
/// a size large enough before c++23
class LibcallImplBitset {
private:
using BitWord = uint64_t;
static constexpr unsigned BitWordSize = sizeof(BitWord) * CHAR_BIT;
static constexpr size_t NumArrayElts =
divideCeil(RTLIB::NumLibcallImpls, BitWordSize);
using Storage = BitWord[NumArrayElts];

Storage Bits = {};

/// Get bitmask for \p Impl in its Bits element.
static constexpr BitWord getBitmask(RTLIB::LibcallImpl Impl) {
unsigned Idx = static_cast<unsigned>(Impl);
return BitWord(1) << (Idx % BitWordSize);
}

/// Get index of array element of Bits for \p Impl
static constexpr unsigned getArrayIdx(RTLIB::LibcallImpl Impl) {
return static_cast<unsigned>(Impl) / BitWordSize;
}

public:
constexpr LibcallImplBitset() = default;
constexpr LibcallImplBitset(const Storage &Src) {
for (size_t I = 0; I != NumArrayElts; ++I)
Bits[I] = Src[I];
}

/// Check if a LibcallImpl is available.
constexpr bool test(RTLIB::LibcallImpl Impl) const {
BitWord Mask = getBitmask(Impl);
return (Bits[getArrayIdx(Impl)] & Mask) != 0;
}

/// Mark a LibcallImpl as available
void set(RTLIB::LibcallImpl Impl) {
assert(Impl != RTLIB::Unsupported && "cannot enable unsupported libcall");
Bits[getArrayIdx(Impl)] |= getBitmask(Impl);
}

/// Mark a LibcallImpl as unavailable
void unset(RTLIB::LibcallImpl Impl) {
assert(Impl != RTLIB::Unsupported && "cannot enable unsupported libcall");
Bits[getArrayIdx(Impl)] &= ~getBitmask(Impl);
}
};

/// A simple container for information about the supported runtime calls.
struct RuntimeLibcallsInfo {
private:
/// Bitset of libcalls a module may emit a call to.
LibcallImplBitset AvailableLibcallImpls;

public:
explicit RuntimeLibcallsInfo(
const Triple &TT,
ExceptionHandling ExceptionModel = ExceptionHandling::None,
Expand Down Expand Up @@ -132,6 +188,14 @@ struct RuntimeLibcallsInfo {
return ImplToLibcall[Impl];
}

bool isAvailable(RTLIB::LibcallImpl Impl) const {
return AvailableLibcallImpls.test(Impl);
}

void setAvailable(RTLIB::LibcallImpl Impl) {
AvailableLibcallImpls.set(Impl);
}

/// Check if this is valid libcall for the current module, otherwise
/// RTLIB::Unsupported.
RTLIB::LibcallImpl getSupportedLibcallImpl(StringRef FuncName) const;
Expand Down
8 changes: 2 additions & 6 deletions llvm/lib/IR/RuntimeLibcalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,8 @@ RuntimeLibcallsInfo::getSupportedLibcallImpl(StringRef FuncName) const {
for (auto I = Range.begin(); I != Range.end(); ++I) {
RTLIB::LibcallImpl Impl =
static_cast<RTLIB::LibcallImpl>(I - RuntimeLibcallNameOffsets.begin());

// FIXME: This should not depend on looking up ImplToLibcall, only the list
// of libcalls for the module.
RTLIB::LibcallImpl Recognized = LibcallImpls[ImplToLibcall[Impl]];
if (Recognized != RTLIB::Unsupported)
return Recognized;
if (isAvailable(Impl))
return Impl;
}

return RTLIB::Unsupported;
Expand Down
22 changes: 22 additions & 0 deletions llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,18 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
// CHECK-NEXT: Entry = DefaultCC;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x0000000000001a
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::malloc}, // malloc
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls_AlwaysAvailable[] = {
Expand All @@ -63,19 +69,26 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_AlwaysAvailable) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: setLibcallImplCallingConv(Impl, CallingConv::AVR_BUILTIN);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: return;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.getArch() == Triple::avr) {
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x0000000000001a
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::malloc}, // malloc
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls_AlwaysAvailable[] = {
Expand All @@ -85,19 +98,26 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_AlwaysAvailable) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: setLibcallImplCallingConv(Impl, CallingConv::AVR_BUILTIN);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: return;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.getArch() == Triple::msp430) {
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x00000000000010
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::MALLOC, RTLIB::malloc}, // malloc
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if ( isFoo() ) {
Expand All @@ -107,6 +127,7 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_anonymous_3) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: setLibcallImplCallingConv(Impl, CallingConv::AVR_BUILTIN);
// CHECK-NEXT: }
// CHECK-EMPTY:
Expand All @@ -119,6 +140,7 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_anonymous_5) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: setLibcallImplCallingConv(Impl, CallingConv::MSP430_BUILTIN);
// CHECK-NEXT: }
// CHECK-EMPTY:
Expand Down
15 changes: 15 additions & 0 deletions llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ def dup1 : RuntimeLibcallImpl<ANOTHER_DUP>;
// func_a and func_b both provide SOME_FUNC.

// CHECK: if (isTargetArchA()) {
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x00000000000018
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_b}, // func_b
// CHECK-NEXT: };
Expand All @@ -35,6 +40,11 @@ def TheSystemLibraryA : SystemRuntimeLibrary<isTargetArchA,
>;

// CHECK: if (isTargetArchB()) {
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x00000000000058
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func
// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a
Expand All @@ -46,6 +56,11 @@ def TheSystemLibraryB : SystemRuntimeLibrary<isTargetArchB,
>;

// CHECK: if (isTargetArchC()) {
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x0000000000007e
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::ANOTHER_DUP, RTLIB::dup1}, // dup1
// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func
Expand Down
27 changes: 27 additions & 0 deletions llvm/test/TableGen/RuntimeLibcallEmitter.td
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.getArch() == Triple::blah) {
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x000000000000e0
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::bzero}, // bzero
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::calloc}, // calloc
Expand All @@ -165,6 +170,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.hasCompilerRT()) {
Expand All @@ -175,6 +181,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_hasCompilerRT) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: }
Expand All @@ -186,6 +193,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_isBarOS) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: }
Expand All @@ -194,6 +202,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.getArch() == Triple::buzz) {
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x00000000000118
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3
// CHECK-NEXT: {RTLIB::SQRT_F80, RTLIB::sqrtl_f80}, // sqrtl
Expand All @@ -202,19 +215,26 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: return;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.getArch() == Triple::foo) {
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x000000000000a0
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::BZERO, RTLIB::bzero}, // bzero
// CHECK-NEXT: {RTLIB::SQRT_F128, RTLIB::sqrtl_f128}, // sqrtl
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.getOS() == Triple::bar) {
Expand All @@ -224,6 +244,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls_isBarOS) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: }
Expand All @@ -232,6 +253,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.getArch() == Triple::simple) {
// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
// CHECK-NEXT: 0x00000000000158
// CHECK-NEXT: });
// CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
// CHECK-EMPTY:
// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::calloc}, // calloc
// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3
Expand All @@ -241,6 +267,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-EMPTY:
// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) {
// CHECK-NEXT: setLibcallImpl(Func, Impl);
// CHECK-NEXT: setAvailable(Impl);
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: return;
Expand Down
Loading