-
Notifications
You must be signed in to change notification settings - Fork 14.8k
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
RuntimeLibcalls: Add bitset for available libcalls #150869
Conversation
@llvm/pr-subscribers-llvm-adt @llvm/pr-subscribers-llvm-ir Author: Matt Arsenault (arsenm) ChangesThis is a step towards separating the set of available libcalls Full diff: https://github.com/llvm/llvm-project/pull/150869.diff 6 Files Affected:
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h
index ad3bb4eca1c56..0de7d14bd0f60 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.h
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.h
@@ -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,
@@ -132,6 +188,10 @@ struct RuntimeLibcallsInfo {
return ImplToLibcall[Impl];
}
+ bool isAvailable(RTLIB::LibcallImpl Impl) const {
+ return AvailableLibcallImpls.test(Impl);
+ }
+
/// Check if this is valid libcall for the current module, otherwise
/// RTLIB::Unsupported.
RTLIB::LibcallImpl getSupportedLibcallImpl(StringRef FuncName) const;
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index 8c90c52141dc7..569f63f28db77 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -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;
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td b/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td
index 49d5ecaa0e5c5..c2aeae285a427 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td
@@ -48,6 +48,11 @@ 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: };
@@ -70,6 +75,11 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
// 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: };
@@ -92,6 +102,11 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary<isMSP430,
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.getArch() == Triple::msp430) {
+// 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: };
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td b/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td
index 00c9d53846326..2a8739335a8dd 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td
@@ -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: };
@@ -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
@@ -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
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter.td b/llvm/test/TableGen/RuntimeLibcallEmitter.td
index 642f8b85a89c6..fe4159201574b 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter.td
@@ -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: 0x000000000000fc
+// 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
@@ -194,6 +199,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
@@ -208,6 +218,11 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: if (TT.getArch() == Triple::foo) {
+// CHECK-NEXT: static constexpr LibcallImplBitset SystemAvailableImpls({
+// CHECK-NEXT: 0x000000000000a4
+// 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
@@ -232,6 +247,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
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index 412431b96d030..853209f94ea2c 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -8,6 +8,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
@@ -402,6 +403,10 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
PredicateWithCC()); // No predicate or CC override first.
DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs;
+
+ SmallVector<uint64_t, 32> BitsetValues(
+ divideCeil(RuntimeLibcallImplDefList.size(), 64));
+
for (const Record *Elt : *Elements) {
const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt);
if (!LibCallImpl) {
@@ -410,6 +415,9 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
continue;
}
+ size_t Idx = LibCallImpl->getEnumVal();
+ BitsetValues[Idx / 64] |= uint64_t(1) << (Idx % 64);
+
auto It = Func2Preds.find(LibCallImpl);
if (It == Func2Preds.end()) {
Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(LibCallImpl);
@@ -427,6 +435,22 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
}
}
+ OS << " static constexpr LibcallImplBitset SystemAvailableImpls({\n"
+ << indent(6);
+
+ ListSeparator LS;
+ unsigned EntryCount = 0;
+ for (uint64_t Bits : BitsetValues) {
+ if (EntryCount++ == 4) {
+ EntryCount = 1;
+ OS << ",\n" << indent(6);
+ } else
+ OS << LS;
+ OS << format_hex(Bits, 16);
+ }
+ OS << "\n });\n"
+ " AvailableLibcallImpls = SystemAvailableImpls;\n\n";
+
SmallVector<PredicateWithCC, 0> SortedPredicates =
PredicateSorter.takeVector();
|
61b2148
to
78b0865
Compare
5843fba
to
a8d3505
Compare
1481306
to
c992d2b
Compare
a8d3505
to
744161e
Compare
c992d2b
to
d3ad2c4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this what llvm/include/llvm/ADT/Bitset.h is for?
d3ad2c4
to
7b13ce5
Compare
b2cb9ad
to
226968e
Compare
f48e119
to
a4c65ba
Compare
a4c65ba
to
b7c546f
Compare
llvm/cmake/config-ix.cmake
Outdated
endif () | ||
|
||
foreach(i IN ITEMS 8 4) | ||
try_compile(SIZEOF_UINTPTR_T_IS_${i} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try_compile compiles for target arch, not native arch, AFAIK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which is correct? The point is to match what the compiler is being compiled for
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TL;DR I don't know.
When I wrote this comment I assumed LLVM_NATIVE_ARCH is the architecutre the compiler will run on. It doesn't seem to be the case: it gets its value from LLVM_TARGET_ARCH (unless it equals to "host"), which has the following comment:
LLVM_TARGET_ARCH Set target to use for LLVM JIT or use \"host\" for automatic detection.
I guess it is not what we need here.
If LLVM_TARGET_ARCH == "host", LLVM_NATIVE_ARCH is set to the value of LLVM_HOST_TRIPLE and the above if/else adjusts it as necessary.
https://llvm.org/docs/HowToCrossCompileLLVM.html says
LLVM_HOST_TRIPLE: Specifies the target triple of the system the built LLVM will run on
This does look relevant, but I don't know how to pass it to try_compile or whether it is passed automatically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try_compile should be the correct check for the current compile target. The hazard would be for the tablegen bootstrap, but since this is in the base config I think it should work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the end, it might be easier to change SmallBitVector to use uint64_t.
Or size_t, it's close enough to uintptr_t |
796f028
to
f38dc22
Compare
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.
f38dc22
to
17f78f0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Co-authored-by: Nikita Popov <[email protected]>
This is failing to build on 32-bit:
I'll merge my other fix to BitSet and figure out how to fix it from there. |
Somehow #162814 fixed it. If it fails like this for anyone else, you could try using |
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.
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.
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.