diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h index 93183bc6b4aa9..e6894cda9fee2 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.h +++ b/llvm/include/llvm/IR/RuntimeLibcalls.h @@ -15,6 +15,7 @@ #define LLVM_IR_RUNTIME_LIBCALLS_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Bitset.h" #include "llvm/ADT/Sequence.h" #include "llvm/ADT/StringTable.h" #include "llvm/IR/CallingConv.h" @@ -54,8 +55,22 @@ static inline auto libcall_impls() { static_cast(RTLIB::NumLibcallImpls)); } +/// Manage a bitset representing the list of available libcalls for a module. +class LibcallImplBitset : public Bitset { +public: + constexpr LibcallImplBitset() = default; + constexpr LibcallImplBitset( + const std::array &Src) + : Bitset(Src) {} +}; + /// 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, @@ -129,6 +144,14 @@ struct RuntimeLibcallsInfo { return getLibcallName(RTLIB::MEMMOVE); } + bool isAvailable(RTLIB::LibcallImpl Impl) const { + return AvailableLibcallImpls.test(Impl); + } + + void setAvailable(RTLIB::LibcallImpl Impl) { + AvailableLibcallImpls.set(Impl); + } + /// Return the libcall provided by \p Impl static RTLIB::Libcall getLibcallFromImpl(RTLIB::LibcallImpl Impl) { return ImplToLibcall[Impl]; diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td b/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td index 98a376bc5c524..2904474f6110b 100644 --- a/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td +++ b/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td @@ -48,6 +48,11 @@ def MSP430LibraryWithCondCC : SystemRuntimeLibrary; // func_a and func_b both provide SOME_FUNC. // CHECK: if (isTargetArchA()) { -// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { -// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_b}, // func_b -// CHECK-NEXT: }; +// 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::impl_func_b}, // func_b +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) { +// CHECK-NEXT: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: return; +// CHECK-NEXT: } // ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_b, func_a def TheSystemLibraryA : SystemRuntimeLibrary; // CHECK: if (isTargetArchB()) { -// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { -// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::impl_other_func}, // other_func -// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_a}, // func_a -// CHECK-NEXT: }; +// 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::impl_other_func}, // other_func +// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_a}, // func_a +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) { +// CHECK-NEXT: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: return; +// CHECK-NEXT: } // ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b def TheSystemLibraryB : SystemRuntimeLibrary; // CHECK: if (isTargetArchC()) { -// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { -// CHECK-NEXT: {RTLIB::ANOTHER_DUP, RTLIB::impl_dup1}, // dup1 -// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::impl_other_func}, // other_func -// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_a}, // func_a -// CHECK-NEXT: }; +// 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::impl_dup1}, // dup1 +// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::impl_other_func}, // other_func +// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::impl_func_a}, // func_a +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) { +// CHECK-NEXT: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: return; +// CHECK-NEXT: } // ERR: :[[@LINE+3]]:5: warning: conflicting implementations for libcall ANOTHER_DUP: dup1, dup0 // ERR: :[[@LINE+2]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter.td b/llvm/test/TableGen/RuntimeLibcallEmitter.td index c336fee956ce1..0c23e3bac195e 100644 --- a/llvm/test/TableGen/RuntimeLibcallEmitter.td +++ b/llvm/test/TableGen/RuntimeLibcallEmitter.td @@ -196,15 +196,20 @@ def BlahLibrary : SystemRuntimeLibrary Pred2Funcs; + + SmallVector BitsetValues( + divideCeil(RuntimeLibcallImplDefList.size(), BitsPerStorageElt)); + for (const Record *Elt : *Elements) { const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt); if (!LibCallImpl) { @@ -597,16 +602,24 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls( continue; } + size_t BitIdx = LibCallImpl->getEnumVal(); + uint64_t BitmaskVal = uint64_t(1) << (BitIdx % BitsPerStorageElt); + size_t BitsetIdx = BitIdx / BitsPerStorageElt; + auto It = Func2Preds.find(LibCallImpl); if (It == Func2Preds.end()) { + BitsetValues[BitsetIdx] |= BitmaskVal; Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(LibCallImpl); continue; } for (const Record *Pred : It->second.first) { const Record *CC = It->second.second; - PredicateWithCC Key(Pred, CC); + AvailabilityPredicate SubsetPredicate(Pred); + if (SubsetPredicate.isAlwaysAvailable()) + BitsetValues[BitsetIdx] |= BitmaskVal; + PredicateWithCC Key(Pred, CC); auto &Entry = Pred2Funcs[Key]; Entry.LibcallImpls.push_back(LibCallImpl); Entry.CallingConv = It->second.second; @@ -614,6 +627,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 SortedPredicates = PredicateSorter.takeVector();