This information will be needed in more emitters, so start factoring it to be more reusable.
575 lines
19 KiB
C++
575 lines
19 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "runtime-libcall-emitter"
|
|
|
|
#include "RuntimeLibcalls.h"
|
|
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#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/Support/xxhash.h"
|
|
#include "llvm/TableGen/CodeGenHelpers.h"
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/TableGen/Record.h"
|
|
#include "llvm/TableGen/SetTheory.h"
|
|
#include "llvm/TableGen/StringToOffsetTable.h"
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
// Pair of a RuntimeLibcallPredicate and LibcallCallingConv to use as a map key.
|
|
struct PredicateWithCC {
|
|
const Record *Predicate = nullptr;
|
|
const Record *CallingConv = nullptr;
|
|
|
|
PredicateWithCC() = default;
|
|
PredicateWithCC(std::pair<const Record *, const Record *> P)
|
|
: Predicate(P.first), CallingConv(P.second) {}
|
|
|
|
PredicateWithCC(const Record *P, const Record *C)
|
|
: Predicate(P), CallingConv(C) {}
|
|
};
|
|
|
|
inline bool operator==(PredicateWithCC LHS, PredicateWithCC RHS) {
|
|
return LHS.Predicate == RHS.Predicate && LHS.CallingConv == RHS.CallingConv;
|
|
}
|
|
} // namespace
|
|
|
|
namespace llvm {
|
|
template <> struct DenseMapInfo<PredicateWithCC, void> {
|
|
static inline PredicateWithCC getEmptyKey() {
|
|
return DenseMapInfo<
|
|
std::pair<const Record *, const Record *>>::getEmptyKey();
|
|
}
|
|
|
|
static inline PredicateWithCC getTombstoneKey() {
|
|
return DenseMapInfo<
|
|
std::pair<const Record *, const Record *>>::getTombstoneKey();
|
|
}
|
|
|
|
static unsigned getHashValue(const PredicateWithCC Val) {
|
|
auto Pair = std::make_pair(Val.Predicate, Val.CallingConv);
|
|
return DenseMapInfo<
|
|
std::pair<const Record *, const Record *>>::getHashValue(Pair);
|
|
}
|
|
|
|
static bool isEqual(PredicateWithCC LHS, PredicateWithCC RHS) {
|
|
return LHS == RHS;
|
|
}
|
|
};
|
|
|
|
class RuntimeLibcallEmitter {
|
|
private:
|
|
const RecordKeeper &Records;
|
|
RuntimeLibcalls Libcalls;
|
|
|
|
void emitGetRuntimeLibcallEnum(raw_ostream &OS) const;
|
|
|
|
void emitNameMatchHashTable(raw_ostream &OS,
|
|
StringToOffsetTable &OffsetTable) const;
|
|
|
|
void emitGetInitRuntimeLibcallNames(raw_ostream &OS) const;
|
|
|
|
void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const;
|
|
|
|
public:
|
|
RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R), Libcalls(R) {}
|
|
|
|
void run(raw_ostream &OS);
|
|
};
|
|
|
|
} // End anonymous namespace.
|
|
|
|
void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const {
|
|
IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_ENUM");
|
|
|
|
OS << "namespace llvm {\n"
|
|
"namespace RTLIB {\n"
|
|
"enum Libcall : unsigned short {\n";
|
|
|
|
for (const RuntimeLibcall &LibCall : Libcalls.getRuntimeLibcallDefList()) {
|
|
StringRef Name = LibCall.getName();
|
|
OS << " " << Name << " = " << LibCall.getEnumVal() << ",\n";
|
|
}
|
|
|
|
OS << " UNKNOWN_LIBCALL = " << Libcalls.getRuntimeLibcallDefList().size()
|
|
<< "\n};\n\n"
|
|
"enum LibcallImpl : unsigned short {\n"
|
|
" Unsupported = 0,\n";
|
|
|
|
for (const RuntimeLibcallImpl &LibCall :
|
|
Libcalls.getRuntimeLibcallImplDefList()) {
|
|
OS << " impl_" << LibCall.getName() << " = " << LibCall.getEnumVal()
|
|
<< ", // " << LibCall.getLibcallFuncName() << '\n';
|
|
}
|
|
|
|
OS << "};\n"
|
|
<< "constexpr size_t NumLibcallImpls = "
|
|
<< Libcalls.getRuntimeLibcallImplDefList().size() + 1
|
|
<< ";\n"
|
|
"} // End namespace RTLIB\n"
|
|
"} // End namespace llvm\n";
|
|
}
|
|
|
|
// StringMap uses xxh3_64bits, truncated to uint32_t.
|
|
static uint64_t hash(StringRef Str) {
|
|
return static_cast<uint32_t>(xxh3_64bits(Str));
|
|
}
|
|
|
|
static void emitHashFunction(raw_ostream &OS) {
|
|
OS << "static inline uint64_t hash(StringRef Str) {\n"
|
|
" return static_cast<uint32_t>(xxh3_64bits(Str));\n"
|
|
"}\n\n";
|
|
}
|
|
|
|
/// Return the table size, maximum number of collisions for the set of hashes
|
|
static std::pair<int, int>
|
|
computePerfectHashParameters(ArrayRef<uint64_t> Hashes) {
|
|
// Chosen based on experimentation with llvm/benchmarks/RuntimeLibcalls.cpp
|
|
const int SizeOverhead = 4;
|
|
|
|
// Index derived from hash -> number of collisions.
|
|
DenseMap<uint64_t, int> Table;
|
|
|
|
unsigned NumHashes = Hashes.size();
|
|
|
|
for (int MaxCollisions = 1;; ++MaxCollisions) {
|
|
for (unsigned N = NextPowerOf2(NumHashes - 1); N < SizeOverhead * NumHashes;
|
|
N <<= 1) {
|
|
Table.clear();
|
|
|
|
bool NeedResize = false;
|
|
for (uint64_t H : Hashes) {
|
|
uint64_t Idx = H % static_cast<uint64_t>(N);
|
|
if (++Table[Idx] > MaxCollisions) {
|
|
// Need to resize the final table if we increased the collision count.
|
|
NeedResize = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!NeedResize)
|
|
return {N, MaxCollisions};
|
|
}
|
|
}
|
|
}
|
|
|
|
static std::vector<unsigned>
|
|
constructPerfectHashTable(ArrayRef<RuntimeLibcallImpl> Keywords,
|
|
ArrayRef<uint64_t> Hashes,
|
|
ArrayRef<unsigned> TableValues, int Size,
|
|
int Collisions, StringToOffsetTable &OffsetTable) {
|
|
std::vector<unsigned> Lookup(Size * Collisions);
|
|
|
|
for (auto [HashValue, TableValue] : zip(Hashes, TableValues)) {
|
|
uint64_t Idx = (HashValue % static_cast<uint64_t>(Size)) *
|
|
static_cast<uint64_t>(Collisions);
|
|
|
|
bool Found = false;
|
|
for (int J = 0; J < Collisions; ++J) {
|
|
unsigned &Entry = Lookup[Idx + J];
|
|
if (Entry == 0) {
|
|
Entry = TableValue;
|
|
Found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Found)
|
|
reportFatalInternalError("failure to hash");
|
|
}
|
|
|
|
return Lookup;
|
|
}
|
|
|
|
/// Generate hash table based lookup by name.
|
|
void RuntimeLibcallEmitter::emitNameMatchHashTable(
|
|
raw_ostream &OS, StringToOffsetTable &OffsetTable) const {
|
|
ArrayRef<RuntimeLibcallImpl> RuntimeLibcallImplDefList =
|
|
Libcalls.getRuntimeLibcallImplDefList();
|
|
std::vector<uint64_t> Hashes(RuntimeLibcallImplDefList.size());
|
|
std::vector<unsigned> TableValues(RuntimeLibcallImplDefList.size());
|
|
DenseSet<StringRef> SeenFuncNames;
|
|
|
|
size_t MaxFuncNameSize = 0;
|
|
size_t Index = 0;
|
|
|
|
for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) {
|
|
StringRef ImplName = LibCallImpl.getLibcallFuncName();
|
|
if (SeenFuncNames.insert(ImplName).second) {
|
|
MaxFuncNameSize = std::max(MaxFuncNameSize, ImplName.size());
|
|
TableValues[Index] = LibCallImpl.getEnumVal();
|
|
Hashes[Index++] = hash(ImplName);
|
|
}
|
|
}
|
|
|
|
// Trim excess elements from non-unique entries.
|
|
Hashes.resize(SeenFuncNames.size());
|
|
TableValues.resize(SeenFuncNames.size());
|
|
|
|
LLVM_DEBUG({
|
|
for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) {
|
|
StringRef ImplName = LibCallImpl.getLibcallFuncName();
|
|
if (ImplName.size() == MaxFuncNameSize) {
|
|
dbgs() << "Maximum runtime libcall name size: " << ImplName << '('
|
|
<< MaxFuncNameSize << ")\n";
|
|
}
|
|
}
|
|
});
|
|
|
|
// Early exiting on the symbol name provides a significant speedup in the miss
|
|
// case on the set of symbols in a clang binary. Emit this as an inlinable
|
|
// precondition in the header.
|
|
//
|
|
// The empty check is also used to get sensible behavior on anonymous
|
|
// functions.
|
|
//
|
|
// TODO: It may make more sense to split the search by string size more. There
|
|
// are a few outliers, most call names are small.
|
|
{
|
|
IfDefEmitter IfDef(OS, "GET_LOOKUP_LIBCALL_IMPL_NAME_BODY");
|
|
|
|
OS << " size_t Size = Name.size();\n"
|
|
" if (Size == 0 || Size > "
|
|
<< MaxFuncNameSize
|
|
<< ")\n"
|
|
" return enum_seq(RTLIB::Unsupported, RTLIB::Unsupported);\n"
|
|
" return lookupLibcallImplNameImpl(Name);\n";
|
|
}
|
|
|
|
auto [Size, Collisions] = computePerfectHashParameters(Hashes);
|
|
std::vector<unsigned> Lookup =
|
|
constructPerfectHashTable(RuntimeLibcallImplDefList, Hashes, TableValues,
|
|
Size, Collisions, OffsetTable);
|
|
|
|
LLVM_DEBUG(dbgs() << "Runtime libcall perfect hashing parameters: Size = "
|
|
<< Size << ", maximum collisions = " << Collisions << '\n');
|
|
|
|
IfDefEmitter IfDef(OS, "DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME");
|
|
emitHashFunction(OS);
|
|
|
|
OS << "iota_range<RTLIB::LibcallImpl> RTLIB::RuntimeLibcallsInfo::"
|
|
"lookupLibcallImplNameImpl(StringRef Name) {\n";
|
|
|
|
// Emit RTLIB::LibcallImpl values
|
|
OS << " static constexpr uint16_t HashTableNameToEnum[" << Lookup.size()
|
|
<< "] = {\n";
|
|
|
|
for (unsigned TableVal : Lookup)
|
|
OS << " " << TableVal << ",\n";
|
|
|
|
OS << " };\n\n";
|
|
|
|
OS << " unsigned Idx = (hash(Name) % " << Size << ") * " << Collisions
|
|
<< ";\n\n"
|
|
" for (int I = 0; I != "
|
|
<< Collisions << R"(; ++I) {
|
|
const uint16_t Entry = HashTableNameToEnum[Idx + I];
|
|
const uint16_t StrOffset = RuntimeLibcallNameOffsetTable[Entry];
|
|
const uint8_t StrSize = RuntimeLibcallNameSizeTable[Entry];
|
|
StringRef Str(
|
|
&RTLIB::RuntimeLibcallsInfo::RuntimeLibcallImplNameTableStorage[StrOffset],
|
|
StrSize);
|
|
if (Str == Name)
|
|
return libcallImplNameHit(Entry, StrOffset);
|
|
}
|
|
|
|
return enum_seq(RTLIB::Unsupported, RTLIB::Unsupported);
|
|
}
|
|
)";
|
|
}
|
|
|
|
void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames(
|
|
raw_ostream &OS) const {
|
|
// Emit the implementation names
|
|
StringToOffsetTable Table(/*AppendZero=*/true,
|
|
"RTLIB::RuntimeLibcallsInfo::");
|
|
|
|
{
|
|
IfDefEmitter IfDef(OS, "GET_INIT_RUNTIME_LIBCALL_NAMES");
|
|
|
|
for (const RuntimeLibcallImpl &LibCallImpl :
|
|
Libcalls.getRuntimeLibcallImplDefList())
|
|
Table.GetOrAddStringOffset(LibCallImpl.getLibcallFuncName());
|
|
|
|
Table.EmitStringTableDef(OS, "RuntimeLibcallImplNameTable");
|
|
OS << R"(
|
|
const uint16_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameOffsetTable[] = {
|
|
)";
|
|
|
|
OS << formatv(" {}, // {}\n", Table.GetStringOffset(""),
|
|
""); // Unsupported entry
|
|
for (const RuntimeLibcallImpl &LibCallImpl :
|
|
Libcalls.getRuntimeLibcallImplDefList()) {
|
|
StringRef ImplName = LibCallImpl.getLibcallFuncName();
|
|
OS << formatv(" {}, // {}\n", Table.GetStringOffset(ImplName), ImplName);
|
|
}
|
|
OS << "};\n";
|
|
|
|
OS << R"(
|
|
const uint8_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameSizeTable[] = {
|
|
)";
|
|
|
|
OS << " 0,\n";
|
|
for (const RuntimeLibcallImpl &LibCallImpl :
|
|
Libcalls.getRuntimeLibcallImplDefList())
|
|
OS << " " << LibCallImpl.getLibcallFuncName().size() << ",\n";
|
|
OS << "};\n\n";
|
|
|
|
// Emit the reverse mapping from implementation libraries to RTLIB::Libcall
|
|
OS << "const RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::"
|
|
"ImplToLibcall[RTLIB::NumLibcallImpls] = {\n"
|
|
" RTLIB::UNKNOWN_LIBCALL, // RTLIB::Unsupported\n";
|
|
|
|
for (const RuntimeLibcallImpl &LibCallImpl :
|
|
Libcalls.getRuntimeLibcallImplDefList()) {
|
|
const RuntimeLibcall *Provides = LibCallImpl.getProvides();
|
|
OS << " ";
|
|
Provides->emitEnumEntry(OS);
|
|
OS << ", // ";
|
|
LibCallImpl.emitEnumEntry(OS);
|
|
OS << '\n';
|
|
}
|
|
|
|
OS << "};\n\n";
|
|
}
|
|
|
|
emitNameMatchHashTable(OS, Table);
|
|
}
|
|
|
|
void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
|
|
raw_ostream &OS) const {
|
|
OS << "void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets("
|
|
"const llvm::Triple &TT, ExceptionHandling ExceptionModel, "
|
|
"FloatABI::ABIType FloatABI, EABI EABIVersion, "
|
|
"StringRef ABIName) {\n";
|
|
|
|
ArrayRef<const Record *> AllLibs =
|
|
Records.getAllDerivedDefinitions("SystemRuntimeLibrary");
|
|
|
|
for (const Record *R : AllLibs) {
|
|
OS << '\n';
|
|
|
|
AvailabilityPredicate TopLevelPredicate(R->getValueAsDef("TriplePred"));
|
|
|
|
OS << indent(2);
|
|
TopLevelPredicate.emitIf(OS);
|
|
|
|
if (const Record *DefaultCCClass =
|
|
R->getValueAsDef("DefaultLibcallCallingConv")) {
|
|
StringRef DefaultCC =
|
|
DefaultCCClass->getValueAsString("CallingConv").trim();
|
|
|
|
if (!DefaultCC.empty()) {
|
|
OS << " const CallingConv::ID DefaultCC = " << DefaultCC << ";\n"
|
|
<< " for (CallingConv::ID &Entry : LibcallImplCallingConvs) {\n"
|
|
" Entry = DefaultCC;\n"
|
|
" }\n\n";
|
|
}
|
|
}
|
|
|
|
SetTheory Sets;
|
|
|
|
DenseMap<const RuntimeLibcallImpl *,
|
|
std::pair<std::vector<const Record *>, const Record *>>
|
|
Func2Preds;
|
|
Sets.addExpander("LibcallImpls", std::make_unique<LibcallPredicateExpander>(
|
|
Libcalls, Func2Preds));
|
|
|
|
const SetTheory::RecVec *Elements =
|
|
Sets.expand(R->getValueAsDef("MemberList"));
|
|
|
|
// Sort to get deterministic output
|
|
SetVector<PredicateWithCC> PredicateSorter;
|
|
PredicateSorter.insert(
|
|
PredicateWithCC()); // No predicate or CC override first.
|
|
|
|
constexpr unsigned BitsPerStorageElt = 64;
|
|
DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs;
|
|
|
|
SmallVector<uint64_t, 32> BitsetValues(divideCeil(
|
|
Libcalls.getRuntimeLibcallImplDefList().size() + 1, BitsPerStorageElt));
|
|
|
|
for (const Record *Elt : *Elements) {
|
|
const RuntimeLibcallImpl *LibCallImpl =
|
|
Libcalls.getRuntimeLibcallImpl(Elt);
|
|
if (!LibCallImpl) {
|
|
PrintError(R, "entry for SystemLibrary is not a RuntimeLibcallImpl");
|
|
PrintNote(Elt->getLoc(), "invalid entry `" + Elt->getName() + "`");
|
|
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;
|
|
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;
|
|
PredicateSorter.insert(Key);
|
|
}
|
|
}
|
|
|
|
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();
|
|
|
|
llvm::sort(SortedPredicates, [](PredicateWithCC A, PredicateWithCC B) {
|
|
StringRef AName = A.Predicate ? A.Predicate->getName() : "";
|
|
StringRef BName = B.Predicate ? B.Predicate->getName() : "";
|
|
return AName < BName;
|
|
});
|
|
|
|
for (PredicateWithCC Entry : SortedPredicates) {
|
|
AvailabilityPredicate SubsetPredicate(Entry.Predicate);
|
|
unsigned IndentDepth = 2;
|
|
|
|
auto It = Pred2Funcs.find(Entry);
|
|
if (It == Pred2Funcs.end())
|
|
continue;
|
|
|
|
if (!SubsetPredicate.isAlwaysAvailable()) {
|
|
IndentDepth = 4;
|
|
|
|
OS << indent(IndentDepth);
|
|
SubsetPredicate.emitIf(OS);
|
|
}
|
|
|
|
LibcallsWithCC &FuncsWithCC = It->second;
|
|
|
|
std::vector<const RuntimeLibcallImpl *> &Funcs = FuncsWithCC.LibcallImpls;
|
|
|
|
// Ensure we only emit a unique implementation per libcall in the
|
|
// selection table.
|
|
//
|
|
// FIXME: We need to generate separate functions for
|
|
// is-libcall-available and should-libcall-be-used to avoid this.
|
|
//
|
|
// This also makes it annoying to make use of the default set, since the
|
|
// entries from the default set may win over the replacements unless
|
|
// they are explicitly removed.
|
|
stable_sort(Funcs, [](const RuntimeLibcallImpl *A,
|
|
const RuntimeLibcallImpl *B) {
|
|
return A->getProvides()->getEnumVal() < B->getProvides()->getEnumVal();
|
|
});
|
|
|
|
auto UniqueI = llvm::unique(
|
|
Funcs, [&](const RuntimeLibcallImpl *A, const RuntimeLibcallImpl *B) {
|
|
if (A->getProvides() == B->getProvides()) {
|
|
PrintWarning(R->getLoc(),
|
|
Twine("conflicting implementations for libcall " +
|
|
A->getProvides()->getName() + ": " +
|
|
A->getLibcallFuncName() + ", " +
|
|
B->getLibcallFuncName()));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
Funcs.erase(UniqueI, Funcs.end());
|
|
|
|
OS << indent(IndentDepth + 2)
|
|
<< "static const RTLIB::LibcallImpl LibraryCalls";
|
|
SubsetPredicate.emitTableVariableNameSuffix(OS);
|
|
if (FuncsWithCC.CallingConv)
|
|
OS << '_' << FuncsWithCC.CallingConv->getName();
|
|
|
|
OS << "[] = {\n";
|
|
for (const RuntimeLibcallImpl *LibCallImpl : Funcs) {
|
|
OS << indent(IndentDepth + 6);
|
|
LibCallImpl->emitEnumEntry(OS);
|
|
OS << ", // " << LibCallImpl->getLibcallFuncName() << '\n';
|
|
}
|
|
|
|
OS << indent(IndentDepth + 2) << "};\n\n"
|
|
<< indent(IndentDepth + 2)
|
|
<< "for (const RTLIB::LibcallImpl Impl : LibraryCalls";
|
|
SubsetPredicate.emitTableVariableNameSuffix(OS);
|
|
if (FuncsWithCC.CallingConv)
|
|
OS << '_' << FuncsWithCC.CallingConv->getName();
|
|
|
|
OS << ") {\n" << indent(IndentDepth + 4) << "setAvailable(Impl);\n";
|
|
|
|
if (FuncsWithCC.CallingConv) {
|
|
StringRef CCEnum =
|
|
FuncsWithCC.CallingConv->getValueAsString("CallingConv");
|
|
OS << indent(IndentDepth + 4) << "setLibcallImplCallingConv(Impl, "
|
|
<< CCEnum << ");\n";
|
|
}
|
|
|
|
OS << indent(IndentDepth + 2) << "}\n";
|
|
OS << '\n';
|
|
|
|
if (!SubsetPredicate.isAlwaysAvailable()) {
|
|
OS << indent(IndentDepth);
|
|
SubsetPredicate.emitEndIf(OS);
|
|
OS << '\n';
|
|
}
|
|
}
|
|
|
|
OS << indent(4) << "return;\n" << indent(2);
|
|
TopLevelPredicate.emitEndIf(OS);
|
|
}
|
|
|
|
// FIXME: This should be a fatal error. A few contexts are improperly relying
|
|
// on RuntimeLibcalls constructed with fully unknown triples.
|
|
OS << " LLVM_DEBUG(dbgs() << \"no system runtime library applied to target "
|
|
"\\'\" << TT.str() << \"\\'\\n\");\n"
|
|
"}\n\n";
|
|
}
|
|
|
|
void RuntimeLibcallEmitter::run(raw_ostream &OS) {
|
|
emitSourceFileHeader("Runtime LibCalls Source Fragment", OS, Records);
|
|
emitGetRuntimeLibcallEnum(OS);
|
|
|
|
emitGetInitRuntimeLibcallNames(OS);
|
|
|
|
{
|
|
IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALLS_INFO");
|
|
emitSystemRuntimeLibrarySetCalls(OS);
|
|
}
|
|
}
|
|
|
|
static TableGen::Emitter::OptClass<RuntimeLibcallEmitter>
|
|
X("gen-runtime-libcalls", "Generate RuntimeLibcalls");
|