| //===- TargetLibraryInfoEmitter.cpp - Properties from TargetLibraryInfo.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 "SequenceToOffsetTable.h" |
| #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/SetTheory.h" |
| #include "llvm/TableGen/StringToOffsetTable.h" |
| #include "llvm/TableGen/TableGenBackend.h" |
| #include <cstddef> |
| |
| #define DEBUG_TYPE "target-library-info-emitter" |
| |
| using namespace llvm; |
| |
| namespace { |
| class TargetLibraryInfoEmitter { |
| private: |
| const RecordKeeper &Records; |
| SmallVector<const Record *, 1024> AllTargetLibcalls; |
| |
| private: |
| void emitTargetLibraryInfoEnum(raw_ostream &OS) const; |
| void emitTargetLibraryInfoStringTable(raw_ostream &OS) const; |
| void emitTargetLibraryInfoSignatureTable(raw_ostream &OS) const; |
| |
| public: |
| TargetLibraryInfoEmitter(const RecordKeeper &R); |
| |
| void run(raw_ostream &OS); |
| }; |
| |
| } // End anonymous namespace. |
| |
| TargetLibraryInfoEmitter::TargetLibraryInfoEmitter(const RecordKeeper &R) |
| : Records(R) { |
| ArrayRef<const Record *> All = |
| Records.getAllDerivedDefinitions("TargetLibCall"); |
| AllTargetLibcalls.append(All.begin(), All.end()); |
| // Make sure that the records are in the same order as the input. |
| // TODO Find a better sorting order when all is migrated. |
| sort(AllTargetLibcalls, [](const Record *A, const Record *B) { |
| return A->getID() < B->getID(); |
| }); |
| } |
| |
| // Emits the LibFunc enumeration, which is an abstract name for each library |
| // function. |
| void TargetLibraryInfoEmitter::emitTargetLibraryInfoEnum( |
| raw_ostream &OS) const { |
| OS << "#ifdef GET_TARGET_LIBRARY_INFO_ENUM\n"; |
| OS << "#undef GET_TARGET_LIBRARY_INFO_ENUM\n"; |
| OS << "enum LibFunc : unsigned {\n"; |
| OS.indent(2) << "NotLibFunc = 0,\n"; |
| for (const auto *R : AllTargetLibcalls) { |
| OS.indent(2) << "LibFunc_" << R->getName() << ",\n"; |
| } |
| OS.indent(2) << "NumLibFuncs,\n"; |
| OS.indent(2) << "End_LibFunc = NumLibFuncs,\n"; |
| if (AllTargetLibcalls.size()) { |
| OS.indent(2) << "Begin_LibFunc = LibFunc_" |
| << AllTargetLibcalls[0]->getName() << ",\n"; |
| } else { |
| OS.indent(2) << "Begin_LibFunc = NotLibFunc,\n"; |
| } |
| OS << "};\n"; |
| OS << "#endif\n\n"; |
| } |
| |
| // The names of the functions are stored in a long string, along with support |
| // tables for accessing the offsets of the function names from the beginning of |
| // the string. |
| void TargetLibraryInfoEmitter::emitTargetLibraryInfoStringTable( |
| raw_ostream &OS) const { |
| llvm::StringToOffsetTable Table( |
| /*AppendZero=*/true, |
| "TargetLibraryInfoImpl::", /*UsePrefixForStorageMember=*/false); |
| for (const auto *R : AllTargetLibcalls) |
| Table.GetOrAddStringOffset(R->getValueAsString("String")); |
| |
| OS << "#ifdef GET_TARGET_LIBRARY_INFO_STRING_TABLE\n"; |
| OS << "#undef GET_TARGET_LIBRARY_INFO_STRING_TABLE\n"; |
| Table.EmitStringTableDef(OS, "StandardNamesStrTable"); |
| OS << "\n"; |
| size_t NumEl = AllTargetLibcalls.size() + 1; |
| OS << "const llvm::StringTable::Offset " |
| "TargetLibraryInfoImpl::StandardNamesOffsets[" |
| << NumEl |
| << "] = " |
| "{\n"; |
| OS.indent(2) << "0, //\n"; |
| for (const auto *R : AllTargetLibcalls) { |
| StringRef Str = R->getValueAsString("String"); |
| OS.indent(2) << Table.GetStringOffset(Str) << ", // " << Str << "\n"; |
| } |
| OS << "};\n"; |
| OS << "const uint8_t TargetLibraryInfoImpl::StandardNamesSizeTable[" << NumEl |
| << "] = {\n"; |
| OS << " 0,\n"; |
| for (const auto *R : AllTargetLibcalls) |
| OS.indent(2) << R->getValueAsString("String").size() << ",\n"; |
| OS << "};\n"; |
| OS << "#endif\n\n"; |
| OS << "#ifdef GET_TARGET_LIBRARY_INFO_IMPL_DECL\n"; |
| OS << "#undef GET_TARGET_LIBRARY_INFO_IMPL_DECL\n"; |
| OS << "LLVM_ABI static const llvm::StringTable StandardNamesStrTable;\n"; |
| OS << "LLVM_ABI static const llvm::StringTable::Offset StandardNamesOffsets[" |
| << NumEl << "];\n"; |
| OS << "LLVM_ABI static const uint8_t StandardNamesSizeTable[" << NumEl |
| << "];\n"; |
| OS << "#endif\n\n"; |
| } |
| |
| // Since there are much less type signatures then library functions, the type |
| // signatures are stored reusing existing entries. To access a table entry, an |
| // offset table is used. |
| void TargetLibraryInfoEmitter::emitTargetLibraryInfoSignatureTable( |
| raw_ostream &OS) const { |
| SmallVector<const Record *, 1024> FuncTypeArgs( |
| Records.getAllDerivedDefinitions("FuncArgType")); |
| |
| // Sort the records by ID. |
| sort(FuncTypeArgs, [](const Record *A, const Record *B) { |
| return A->getID() < B->getID(); |
| }); |
| |
| using Signature = std::vector<StringRef>; |
| SequenceToOffsetTable<Signature> SignatureTable("NoFuncArgType"); |
| auto GetSignature = [](const Record *R) -> Signature { |
| const auto *Tys = R->getValueAsListInit("ArgumentTypes"); |
| Signature Sig; |
| Sig.reserve(Tys->size() + 1); |
| const Record *RetType = R->getValueAsOptionalDef("ReturnType"); |
| if (RetType) |
| Sig.push_back(RetType->getName()); |
| for (unsigned I = 0, E = Tys->size(); I < E; ++I) { |
| Sig.push_back(Tys->getElementAsRecord(I)->getName()); |
| } |
| return Sig; |
| }; |
| Signature NoFuncSig({StringRef("Void")}); |
| SignatureTable.add(NoFuncSig); |
| for (const auto *R : AllTargetLibcalls) |
| SignatureTable.add(GetSignature(R)); |
| SignatureTable.layout(); |
| |
| OS << "#ifdef GET_TARGET_LIBRARY_INFO_SIGNATURE_TABLE\n"; |
| OS << "#undef GET_TARGET_LIBRARY_INFO_SIGNATURE_TABLE\n"; |
| OS << "enum FuncArgTypeID : char {\n"; |
| OS.indent(2) << "NoFuncArgType = 0,\n"; |
| for (const auto *R : FuncTypeArgs) { |
| OS.indent(2) << R->getName() << ",\n"; |
| } |
| OS << "};\n"; |
| OS << "static const FuncArgTypeID SignatureTable[] = {\n"; |
| SignatureTable.emit(OS, [](raw_ostream &OS, StringRef E) { OS << E; }); |
| OS << "};\n"; |
| OS << "static const uint16_t SignatureOffset[] = {\n"; |
| OS.indent(2) << SignatureTable.get(NoFuncSig) << ", //\n"; |
| for (const auto *R : AllTargetLibcalls) { |
| OS.indent(2) << SignatureTable.get(GetSignature(R)) << ", // " |
| << R->getName() << "\n"; |
| } |
| OS << "};\n"; |
| OS << "#endif\n\n"; |
| } |
| |
| void TargetLibraryInfoEmitter::run(raw_ostream &OS) { |
| emitSourceFileHeader("Target Library Info Source Fragment", OS, Records); |
| |
| emitTargetLibraryInfoEnum(OS); |
| emitTargetLibraryInfoStringTable(OS); |
| emitTargetLibraryInfoSignatureTable(OS); |
| } |
| |
| static TableGen::Emitter::OptClass<TargetLibraryInfoEmitter> |
| X("gen-target-library-info", "Generate TargetLibraryInfo"); |