Skip to content

RuntimeLibcalls: Add methods to recognize libcall names #149001

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

Merged
Merged
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
9 changes: 9 additions & 0 deletions llvm/include/llvm/ADT/StringTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ class StringTable {
constexpr Iterator(const Iterator &RHS) = default;
constexpr Iterator(Iterator &&RHS) = default;

Iterator &operator=(const Iterator &RHS) {
Table = RHS.Table;
O = RHS.O;
S = RHS.S;
return *this;
}

bool operator==(const Iterator &RHS) const {
assert(Table == RHS.Table && "Compared iterators for unrelated tables!");
return O == RHS.O;
Expand All @@ -132,6 +139,8 @@ class StringTable {
O = O.value() + (*Table)[O].size() + 1;
return *this;
}

Offset offset() const { return O; }
};

constexpr Iterator begin() const { return Iterator(*this, 0); }
Expand Down
12 changes: 12 additions & 0 deletions llvm/include/llvm/IR/RuntimeLibcalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ struct RuntimeLibcallsInfo {
return ImplToLibcall[Impl];
}

/// Check if this is valid libcall for the current module, otherwise
/// RTLIB::Unsupported.
RTLIB::LibcallImpl getSupportedLibcallImpl(StringRef FuncName) const;

private:
static const RTLIB::LibcallImpl
DefaultLibcallImpls[RTLIB::UNKNOWN_LIBCALL + 1];
Expand All @@ -156,6 +160,14 @@ struct RuntimeLibcallsInfo {
/// Map from a concrete LibcallImpl implementation to its RTLIB::Libcall kind.
LLVM_ABI static const RTLIB::Libcall ImplToLibcall[RTLIB::NumLibcallImpls];

/// Check if a function name is a recognized runtime call of any kind. This
/// does not consider if this call is available for any current compilation,
/// just that it is a known call somewhere. This returns the set of all
/// LibcallImpls which match the name; multiple implementations with the same
/// name may exist but differ in interpretation based on the target context.
LLVM_ABI static iterator_range<ArrayRef<uint16_t>::const_iterator>
getRecognizedLibcallImpls(StringRef FuncName);

static bool darwinHasSinCosStret(const Triple &TT) {
if (!TT.isOSDarwin())
return false;
Expand Down
45 changes: 45 additions & 0 deletions llvm/lib/IR/RuntimeLibcalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,51 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
}
}

RTLIB::LibcallImpl
RuntimeLibcallsInfo::getSupportedLibcallImpl(StringRef FuncName) const {
const ArrayRef<uint16_t> RuntimeLibcallNameOffsets(
RuntimeLibcallNameOffsetTable);

iterator_range<ArrayRef<uint16_t>::const_iterator> Range =
getRecognizedLibcallImpls(FuncName);

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;
}

return RTLIB::Unsupported;
}

iterator_range<ArrayRef<uint16_t>::const_iterator>
RuntimeLibcallsInfo::getRecognizedLibcallImpls(StringRef FuncName) {
StringTable::Iterator It = lower_bound(RuntimeLibcallImplNameTable, FuncName);
if (It == RuntimeLibcallImplNameTable.end() || *It != FuncName)
return iterator_range(ArrayRef<uint16_t>());

uint16_t IndexVal = It.offset().value();
const ArrayRef<uint16_t> TableRef(RuntimeLibcallNameOffsetTable);

ArrayRef<uint16_t>::const_iterator E = TableRef.end();
ArrayRef<uint16_t>::const_iterator EntriesBegin =
std::lower_bound(TableRef.begin(), E, IndexVal);
ArrayRef<uint16_t>::const_iterator EntriesEnd = EntriesBegin;

while (EntriesEnd != E && *EntriesEnd == IndexVal)
++EntriesEnd;

assert(EntriesBegin != E &&
"libcall found in name table but not offset table");

return make_range(EntriesBegin, EntriesEnd);
}

bool RuntimeLibcallsInfo::darwinHasExp10(const Triple &TT) {
switch (TT.getOS()) {
case Triple::MacOSX:
Expand Down
45 changes: 22 additions & 23 deletions llvm/lib/Object/IRSymtab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ static const char *PreservedSymbols[] = {
"__stack_chk_guard",
};

static bool isPreservedGlobalVarName(StringRef Name) {
return StringRef(PreservedSymbols[0]) == Name ||
StringRef(PreservedSymbols[1]) == Name;
}

namespace {

const char *getExpectedProducerName() {
Expand Down Expand Up @@ -81,12 +86,16 @@ struct Builder {
// The StringTableBuilder does not create a copy of any strings added to it,
// so this provides somewhere to store any strings that we create.
Builder(SmallVector<char, 0> &Symtab, StringTableBuilder &StrtabBuilder,
BumpPtrAllocator &Alloc)
: Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc) {}
BumpPtrAllocator &Alloc, const Triple &TT)
: Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc), TT(TT),
Libcalls(TT) {}

DenseMap<const Comdat *, int> ComdatMap;
Mangler Mang;
Triple TT;
const Triple &TT;

// FIXME: This shouldn't be here.
RTLIB::RuntimeLibcallsInfo Libcalls;

std::vector<storage::Comdat> Comdats;
std::vector<storage::Module> Mods;
Expand All @@ -98,6 +107,10 @@ struct Builder {

std::vector<storage::Str> DependentLibraries;

bool isPreservedLibFuncName(StringRef Name) {
return Libcalls.getSupportedLibcallImpl(Name) != RTLIB::Unsupported;
}

void setStr(storage::Str &S, StringRef Value) {
S.Offset = StrtabBuilder.add(Value);
S.Size = Value.size();
Expand Down Expand Up @@ -213,18 +226,6 @@ Expected<int> Builder::getComdatIndex(const Comdat *C, const Module *M) {
return P.first->second;
}

static DenseSet<StringRef> buildPreservedSymbolsSet(const Triple &TT) {
DenseSet<StringRef> PreservedSymbolSet(std::begin(PreservedSymbols),
std::end(PreservedSymbols));
// FIXME: Do we need to pass in ABI fields from TargetOptions?
RTLIB::RuntimeLibcallsInfo Libcalls(TT);
for (RTLIB::LibcallImpl Impl : Libcalls.getLibcallImpls()) {
if (Impl != RTLIB::Unsupported)
PreservedSymbolSet.insert(Libcalls.getLibcallImplName(Impl));
}
return PreservedSymbolSet;
}

Error Builder::addSymbol(const ModuleSymbolTable &Msymtab,
const SmallPtrSet<GlobalValue *, 4> &Used,
ModuleSymbolTable::Symbol Msym) {
Expand Down Expand Up @@ -278,13 +279,11 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab,
return Error::success();
}

setStr(Sym.IRName, GV->getName());

static const DenseSet<StringRef> PreservedSymbolsSet =
buildPreservedSymbolsSet(GV->getParent()->getTargetTriple());
bool IsPreservedSymbol = PreservedSymbolsSet.contains(GV->getName());
StringRef GVName = GV->getName();
setStr(Sym.IRName, GVName);

if (Used.count(GV) || IsPreservedSymbol)
if (Used.count(GV) || isPreservedLibFuncName(GVName) ||
isPreservedGlobalVarName(GVName))
Sym.Flags |= 1 << storage::Symbol::FB_used;
if (GV->isThreadLocal())
Sym.Flags |= 1 << storage::Symbol::FB_tls;
Expand Down Expand Up @@ -351,7 +350,6 @@ Error Builder::build(ArrayRef<Module *> IRMods) {
setStr(Hdr.Producer, kExpectedProducerName);
setStr(Hdr.TargetTriple, IRMods[0]->getTargetTriple().str());
setStr(Hdr.SourceFileName, IRMods[0]->getSourceFileName());
TT = IRMods[0]->getTargetTriple();

for (auto *M : IRMods)
if (Error Err = addModule(M))
Expand All @@ -377,7 +375,8 @@ Error Builder::build(ArrayRef<Module *> IRMods) {
Error irsymtab::build(ArrayRef<Module *> Mods, SmallVector<char, 0> &Symtab,
StringTableBuilder &StrtabBuilder,
BumpPtrAllocator &Alloc) {
return Builder(Symtab, StrtabBuilder, Alloc).build(Mods);
const Triple &TT = Mods[0]->getTargetTriple();
return Builder(Symtab, StrtabBuilder, Alloc, TT).build(Mods);
}

// Upgrade a vector of bitcode modules created by an old version of LLVM by
Expand Down
13 changes: 12 additions & 1 deletion llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,19 @@ class RuntimeLibcallEmitter {
for (RuntimeLibcall &LibCall : RuntimeLibcallDefList)
Def2RuntimeLibcall[LibCall.getDef()] = &LibCall;

ArrayRef<const Record *> AllRuntimeLibcallImpls =
ArrayRef<const Record *> AllRuntimeLibcallImplsRaw =
Records.getAllDerivedDefinitions("RuntimeLibcallImpl");

SmallVector<const Record *, 1024> AllRuntimeLibcallImpls(
AllRuntimeLibcallImplsRaw);

// Sort by libcall impl name, not the enum name. This keeps the order
// suitable for using the name table for libcall recognition binary search.
llvm::sort(AllRuntimeLibcallImpls, [](const Record *A, const Record *B) {
return A->getValueAsString("LibCallFuncName") <
B->getValueAsString("LibCallFuncName");
});

RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size());

size_t LibCallImplEnumVal = 1;
Expand Down
Loading