Replace RuntimeLibcalls.def with a tablegenerated version. This is in preparation for splitting RuntimeLibcalls into two components. For now match the existing functionality.
306 lines
9.6 KiB
C++
306 lines
9.6 KiB
C++
//===- RuntimeLibcallEmitter.cpp - Properties from RuntimeLibcalls.td -----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/TableGen/Record.h"
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
class RuntimeLibcall {
|
|
const Record *TheDef = nullptr;
|
|
|
|
public:
|
|
RuntimeLibcall() = delete;
|
|
RuntimeLibcall(const Record *Def) : TheDef(Def) { assert(Def); }
|
|
|
|
~RuntimeLibcall() { assert(TheDef); }
|
|
|
|
const Record *getDef() const { return TheDef; }
|
|
|
|
StringRef getName() const { return TheDef->getName(); }
|
|
|
|
void emitEnumEntry(raw_ostream &OS) const {
|
|
OS << "RTLIB::" << TheDef->getValueAsString("Name");
|
|
}
|
|
};
|
|
|
|
class RuntimeLibcallImpl {
|
|
const Record *TheDef;
|
|
const RuntimeLibcall *Provides = nullptr;
|
|
|
|
public:
|
|
RuntimeLibcallImpl(
|
|
const Record *Def,
|
|
const DenseMap<const Record *, const RuntimeLibcall *> &ProvideMap)
|
|
: TheDef(Def) {
|
|
if (const Record *ProvidesDef = Def->getValueAsDef("Provides"))
|
|
Provides = ProvideMap.lookup(ProvidesDef);
|
|
}
|
|
|
|
~RuntimeLibcallImpl() {}
|
|
|
|
const Record *getDef() const { return TheDef; }
|
|
|
|
StringRef getName() const { return TheDef->getName(); }
|
|
|
|
const RuntimeLibcall *getProvides() const { return Provides; }
|
|
|
|
StringRef getLibcallFuncName() const {
|
|
return TheDef->getValueAsString("LibCallFuncName");
|
|
}
|
|
|
|
void emitQuotedLibcallFuncName(raw_ostream &OS) const {
|
|
OS << '\"' << getLibcallFuncName() << '\"';
|
|
}
|
|
|
|
bool isDefault() const { return TheDef->getValueAsBit("IsDefault"); }
|
|
|
|
void emitEnumEntry(raw_ostream &OS) const {
|
|
OS << "RTLIB::" << TheDef->getName();
|
|
}
|
|
};
|
|
|
|
class RuntimeLibcallEmitter {
|
|
private:
|
|
const RecordKeeper &Records;
|
|
|
|
DenseMap<const Record *, const RuntimeLibcall *> Def2RuntimeLibcall;
|
|
|
|
const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const {
|
|
return Def2RuntimeLibcall.lookup(Def);
|
|
}
|
|
|
|
std::vector<RuntimeLibcall> RuntimeLibcallDefList;
|
|
std::vector<RuntimeLibcallImpl> RuntimeLibcallImplDefList;
|
|
|
|
DenseMap<const RuntimeLibcall *, const RuntimeLibcallImpl *>
|
|
LibCallToDefaultImpl;
|
|
|
|
void
|
|
emitTargetOverrideFunc(raw_ostream &OS, StringRef FuncName,
|
|
ArrayRef<RuntimeLibcallImpl> LibCallImplList) const;
|
|
|
|
void emitGetRuntimeLibcallEnum(raw_ostream &OS) const;
|
|
|
|
void emitWindowsArm64LibCallNameOverrides(raw_ostream &OS) const;
|
|
|
|
void emitGetInitRuntimeLibcallNames(raw_ostream &OS) const;
|
|
void emitGetInitRuntimeLibcallUtils(raw_ostream &OS) const;
|
|
|
|
public:
|
|
RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R) {
|
|
|
|
ArrayRef<const Record *> AllRuntimeLibcalls =
|
|
Records.getAllDerivedDefinitions("RuntimeLibcall");
|
|
|
|
RuntimeLibcallDefList.reserve(AllRuntimeLibcalls.size());
|
|
|
|
for (const Record *RuntimeLibcallDef : AllRuntimeLibcalls) {
|
|
RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef);
|
|
Def2RuntimeLibcall[RuntimeLibcallDef] = &RuntimeLibcallDefList.back();
|
|
}
|
|
|
|
for (RuntimeLibcall &LibCall : RuntimeLibcallDefList)
|
|
Def2RuntimeLibcall[LibCall.getDef()] = &LibCall;
|
|
|
|
ArrayRef<const Record *> AllRuntimeLibcallImpls =
|
|
Records.getAllDerivedDefinitions("RuntimeLibcallImpl");
|
|
RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size());
|
|
|
|
for (const Record *LibCallImplDef : AllRuntimeLibcallImpls) {
|
|
RuntimeLibcallImplDefList.emplace_back(LibCallImplDef,
|
|
Def2RuntimeLibcall);
|
|
|
|
RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back();
|
|
|
|
// const RuntimeLibcallImpl &LibCallImpl =
|
|
// RuntimeLibcallImplDefList.back();
|
|
if (LibCallImpl.isDefault()) {
|
|
const RuntimeLibcall *Provides = LibCallImpl.getProvides();
|
|
if (!Provides)
|
|
PrintFatalError(LibCallImplDef->getLoc(),
|
|
"default implementations must provide a libcall");
|
|
LibCallToDefaultImpl[Provides] = &LibCallImpl;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<RuntimeLibcallImpl>
|
|
getRuntimeLibcallImplSet(StringRef Name) const {
|
|
std::vector<RuntimeLibcallImpl> Result;
|
|
ArrayRef<const Record *> ImplSet =
|
|
Records.getAllDerivedDefinitionsIfDefined(Name);
|
|
Result.reserve(ImplSet.size());
|
|
|
|
for (const Record *LibCallImplDef : ImplSet)
|
|
Result.emplace_back(LibCallImplDef, Def2RuntimeLibcall);
|
|
return Result;
|
|
}
|
|
|
|
void run(raw_ostream &OS);
|
|
};
|
|
|
|
} // End anonymous namespace.
|
|
|
|
/// Emit a method \p FuncName of RTLIB::RuntimeLibcallsInfo to override the
|
|
/// libcall names in \p LibCallImplList.
|
|
void RuntimeLibcallEmitter::emitTargetOverrideFunc(
|
|
raw_ostream &OS, StringRef FuncName,
|
|
ArrayRef<RuntimeLibcallImpl> LibCallImplList) const {
|
|
OS << "void llvm::RTLIB::RuntimeLibcallsInfo::" << FuncName << "() {\n";
|
|
|
|
if (LibCallImplList.empty()) {
|
|
OS << " llvm_unreachable(\"override set not defined\");\n";
|
|
} else {
|
|
// for (const Record *LibCallImpl : LibCallImplList) {
|
|
for (const RuntimeLibcallImpl &LibCallImpl : LibCallImplList) {
|
|
const RuntimeLibcall *Provides = LibCallImpl.getProvides();
|
|
OS << " LibcallRoutineNames[";
|
|
Provides->emitEnumEntry(OS);
|
|
OS << "] = ";
|
|
LibCallImpl.emitQuotedLibcallFuncName(OS);
|
|
OS << ";\n";
|
|
}
|
|
}
|
|
|
|
OS << "}\n\n";
|
|
}
|
|
|
|
void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const {
|
|
OS << "#ifdef GET_RUNTIME_LIBCALL_ENUM\n"
|
|
"namespace llvm {\n"
|
|
"namespace RTLIB {\n"
|
|
"enum Libcall {\n";
|
|
|
|
size_t CallTypeEnumVal = 0;
|
|
for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) {
|
|
StringRef Name = LibCall.getName();
|
|
OS << " " << Name << " = " << CallTypeEnumVal++ << ",\n";
|
|
}
|
|
|
|
// TODO: Emit libcall names as string offset table.
|
|
|
|
OS << " UNKNOWN_LIBCALL = " << CallTypeEnumVal
|
|
<< "\n};\n\n"
|
|
"} // End namespace RTLIB\n"
|
|
"} // End namespace llvm\n"
|
|
"#endif\n\n";
|
|
}
|
|
|
|
void RuntimeLibcallEmitter::emitWindowsArm64LibCallNameOverrides(
|
|
raw_ostream &OS) const {
|
|
// FIXME: Stop treating this as a special case
|
|
OS << "void "
|
|
"llvm::RTLIB::RuntimeLibcallsInfo::setWindowsArm64LibCallNameOverrides("
|
|
") {\n"
|
|
" static const char *const "
|
|
"WindowsArm64RoutineNames[RTLIB::UNKNOWN_LIBCALL + 1] = {\n";
|
|
for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) {
|
|
auto I = LibCallToDefaultImpl.find(&LibCall);
|
|
if (I == LibCallToDefaultImpl.end())
|
|
OS << " nullptr,";
|
|
else {
|
|
const RuntimeLibcallImpl *LibCallImpl = I->second;
|
|
assert(LibCallImpl);
|
|
OS << " \"#" << LibCallImpl->getLibcallFuncName() << "\",";
|
|
}
|
|
|
|
OS << " // ";
|
|
LibCall.emitEnumEntry(OS);
|
|
OS << '\n';
|
|
}
|
|
|
|
OS << " nullptr // RTLIB::UNKNOWN_LIBCALL\n"
|
|
" };\n\n"
|
|
" std::memcpy(LibcallRoutineNames, WindowsArm64RoutineNames,\n"
|
|
" sizeof(LibcallRoutineNames));\n"
|
|
" static_assert(sizeof(LibcallRoutineNames) == "
|
|
"sizeof(WindowsArm64RoutineNames),\n"
|
|
" \"libcall array size should match\");\n"
|
|
"}\n#endif\n\n";
|
|
}
|
|
|
|
void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames(
|
|
raw_ostream &OS) const {
|
|
// TODO: Emit libcall names as string offset table.
|
|
|
|
OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_NAMES\n"
|
|
"const char *const "
|
|
"llvm::RTLIB::RuntimeLibcallsInfo::"
|
|
"DefaultLibcallRoutineNames[RTLIB::UNKNOWN_LIBCALL + 1] = {\n";
|
|
|
|
for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) {
|
|
auto I = LibCallToDefaultImpl.find(&LibCall);
|
|
if (I == LibCallToDefaultImpl.end())
|
|
OS << " nullptr,";
|
|
else {
|
|
const RuntimeLibcallImpl *LibCallImpl = I->second;
|
|
OS << " ";
|
|
LibCallImpl->emitQuotedLibcallFuncName(OS);
|
|
OS << ',';
|
|
}
|
|
|
|
OS << " // ";
|
|
LibCall.emitEnumEntry(OS);
|
|
OS << '\n';
|
|
}
|
|
|
|
OS << " nullptr // RTLIB::UNKNOWN_LIBCALL\n"
|
|
"};\n\n";
|
|
|
|
std::vector<RuntimeLibcallImpl> ZOSRuntimeLibcallImplList =
|
|
getRuntimeLibcallImplSet("ZOSRuntimeLibcallImpl");
|
|
emitTargetOverrideFunc(OS, "setZOSLibCallNameOverrides",
|
|
ZOSRuntimeLibcallImplList);
|
|
|
|
std::vector<RuntimeLibcallImpl> PPCRuntimeLibcallImplList =
|
|
getRuntimeLibcallImplSet("PPCRuntimeLibcallImpl");
|
|
emitTargetOverrideFunc(OS, "setPPCLibCallNameOverrides",
|
|
PPCRuntimeLibcallImplList);
|
|
|
|
emitWindowsArm64LibCallNameOverrides(OS);
|
|
}
|
|
|
|
void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallUtils(
|
|
raw_ostream &OS) const {
|
|
// FIXME: Hack we shouldn't really need
|
|
OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_UTILS\n"
|
|
"static inline bool isAtomicLibCall(llvm::RTLIB::Libcall LC) {\n"
|
|
" switch (LC) {\n";
|
|
for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) {
|
|
StringRef Name = LibCall.getName();
|
|
if (Name.contains("ATOMIC")) {
|
|
OS << " case ";
|
|
LibCall.emitEnumEntry(OS);
|
|
OS << ":\n";
|
|
}
|
|
}
|
|
|
|
OS << " return true;\n"
|
|
" default:\n"
|
|
" return false;\n"
|
|
" }\n\n"
|
|
" llvm_unreachable(\"covered switch over libcalls\");\n"
|
|
"}\n#endif\n\n";
|
|
}
|
|
|
|
void RuntimeLibcallEmitter::run(raw_ostream &OS) {
|
|
emitSourceFileHeader("Runtime LibCalls Source Fragment", OS, Records);
|
|
emitGetRuntimeLibcallEnum(OS);
|
|
emitGetInitRuntimeLibcallNames(OS);
|
|
emitGetInitRuntimeLibcallUtils(OS);
|
|
}
|
|
|
|
static TableGen::Emitter::OptClass<RuntimeLibcallEmitter>
|
|
X("gen-runtime-libcalls", "Generate RuntimeLibcalls");
|