1//===- TargetLibraryInfoEmitter.cpp - Properties from TargetLibraryInfo.td ===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "SequenceToOffsetTable.h"
10#include "llvm/ADT/StringRef.h"
11#include "llvm/Support/Debug.h"
12#include "llvm/Support/raw_ostream.h"
13#include "llvm/TableGen/Error.h"
14#include "llvm/TableGen/Record.h"
15#include "llvm/TableGen/SetTheory.h"
16#include "llvm/TableGen/StringToOffsetTable.h"
17#include "llvm/TableGen/TableGenBackend.h"
18#include <cstddef>
19
20#define DEBUG_TYPE "target-library-info-emitter"
21
22using namespace llvm;
23
24namespace {
25class TargetLibraryInfoEmitter {
26private:
27 const RecordKeeper &Records;
28 SmallVector<const Record *, 1024> AllTargetLibcalls;
29
30private:
31 void emitTargetLibraryInfoEnum(raw_ostream &OS) const;
32 void emitTargetLibraryInfoStringTable(raw_ostream &OS) const;
33 void emitTargetLibraryInfoSignatureTable(raw_ostream &OS) const;
34
35public:
36 TargetLibraryInfoEmitter(const RecordKeeper &R);
37
38 void run(raw_ostream &OS);
39};
40
41} // End anonymous namespace.
42
43TargetLibraryInfoEmitter::TargetLibraryInfoEmitter(const RecordKeeper &R)
44 : Records(R) {
45 ArrayRef<const Record *> All =
46 Records.getAllDerivedDefinitions(ClassName: "TargetLibCall");
47 AllTargetLibcalls.append(in_start: All.begin(), in_end: All.end());
48 // Make sure that the records are in the same order as the input.
49 // TODO Find a better sorting order when all is migrated.
50 sort(C&: AllTargetLibcalls, Comp: [](const Record *A, const Record *B) {
51 return A->getID() < B->getID();
52 });
53}
54
55// Emits the LibFunc enumeration, which is an abstract name for each library
56// function.
57void TargetLibraryInfoEmitter::emitTargetLibraryInfoEnum(
58 raw_ostream &OS) const {
59 OS << "#ifdef GET_TARGET_LIBRARY_INFO_ENUM\n";
60 OS << "#undef GET_TARGET_LIBRARY_INFO_ENUM\n";
61 OS << "enum LibFunc : unsigned {\n";
62 OS.indent(NumSpaces: 2) << "NotLibFunc = 0,\n";
63 for (const auto *R : AllTargetLibcalls) {
64 OS.indent(NumSpaces: 2) << "LibFunc_" << R->getName() << ",\n";
65 }
66 OS.indent(NumSpaces: 2) << "NumLibFuncs,\n";
67 OS.indent(NumSpaces: 2) << "End_LibFunc = NumLibFuncs,\n";
68 if (AllTargetLibcalls.size()) {
69 OS.indent(NumSpaces: 2) << "Begin_LibFunc = LibFunc_"
70 << AllTargetLibcalls[0]->getName() << ",\n";
71 } else {
72 OS.indent(NumSpaces: 2) << "Begin_LibFunc = NotLibFunc,\n";
73 }
74 OS << "};\n";
75 OS << "#endif\n\n";
76}
77
78// The names of the functions are stored in a long string, along with support
79// tables for accessing the offsets of the function names from the beginning of
80// the string.
81void TargetLibraryInfoEmitter::emitTargetLibraryInfoStringTable(
82 raw_ostream &OS) const {
83 llvm::StringToOffsetTable Table(
84 /*AppendZero=*/true,
85 "TargetLibraryInfoImpl::", /*UsePrefixForStorageMember=*/false);
86 for (const auto *R : AllTargetLibcalls)
87 Table.GetOrAddStringOffset(Str: R->getValueAsString(FieldName: "String"));
88
89 OS << "#ifdef GET_TARGET_LIBRARY_INFO_STRING_TABLE\n";
90 OS << "#undef GET_TARGET_LIBRARY_INFO_STRING_TABLE\n";
91 Table.EmitStringTableDef(OS, Name: "StandardNamesStrTable");
92 OS << "\n";
93 size_t NumEl = AllTargetLibcalls.size() + 1;
94 OS << "const llvm::StringTable::Offset "
95 "TargetLibraryInfoImpl::StandardNamesOffsets["
96 << NumEl
97 << "] = "
98 "{\n";
99 OS.indent(NumSpaces: 2) << "0, //\n";
100 for (const auto *R : AllTargetLibcalls) {
101 StringRef Str = R->getValueAsString(FieldName: "String");
102 OS.indent(NumSpaces: 2) << Table.GetStringOffset(Str) << ", // " << Str << "\n";
103 }
104 OS << "};\n";
105 OS << "const uint8_t TargetLibraryInfoImpl::StandardNamesSizeTable[" << NumEl
106 << "] = {\n";
107 OS << " 0,\n";
108 for (const auto *R : AllTargetLibcalls)
109 OS.indent(NumSpaces: 2) << R->getValueAsString(FieldName: "String").size() << ",\n";
110 OS << "};\n";
111 OS << "#endif\n\n";
112 OS << "#ifdef GET_TARGET_LIBRARY_INFO_IMPL_DECL\n";
113 OS << "#undef GET_TARGET_LIBRARY_INFO_IMPL_DECL\n";
114 OS << "LLVM_ABI static const llvm::StringTable StandardNamesStrTable;\n";
115 OS << "LLVM_ABI static const llvm::StringTable::Offset StandardNamesOffsets["
116 << NumEl << "];\n";
117 OS << "LLVM_ABI static const uint8_t StandardNamesSizeTable[" << NumEl
118 << "];\n";
119 OS << "#endif\n\n";
120}
121
122// Since there are much less type signatures then library functions, the type
123// signatures are stored reusing existing entries. To access a table entry, an
124// offset table is used.
125void TargetLibraryInfoEmitter::emitTargetLibraryInfoSignatureTable(
126 raw_ostream &OS) const {
127 SmallVector<const Record *, 1024> FuncTypeArgs(
128 Records.getAllDerivedDefinitions(ClassName: "FuncArgType"));
129
130 // Sort the records by ID.
131 sort(C&: FuncTypeArgs, Comp: [](const Record *A, const Record *B) {
132 return A->getID() < B->getID();
133 });
134
135 using Signature = std::vector<StringRef>;
136 SequenceToOffsetTable<Signature> SignatureTable("NoFuncArgType");
137 auto GetSignature = [](const Record *R) -> Signature {
138 const auto *Tys = R->getValueAsListInit(FieldName: "ArgumentTypes");
139 Signature Sig;
140 Sig.reserve(n: Tys->size() + 1);
141 const Record *RetType = R->getValueAsOptionalDef(FieldName: "ReturnType");
142 if (RetType)
143 Sig.push_back(x: RetType->getName());
144 for (unsigned I = 0, E = Tys->size(); I < E; ++I) {
145 Sig.push_back(x: Tys->getElementAsRecord(Idx: I)->getName());
146 }
147 return Sig;
148 };
149 Signature NoFuncSig({StringRef("Void")});
150 SignatureTable.add(Seq: NoFuncSig);
151 for (const auto *R : AllTargetLibcalls)
152 SignatureTable.add(Seq: GetSignature(R));
153 SignatureTable.layout();
154
155 OS << "#ifdef GET_TARGET_LIBRARY_INFO_SIGNATURE_TABLE\n";
156 OS << "#undef GET_TARGET_LIBRARY_INFO_SIGNATURE_TABLE\n";
157 OS << "enum FuncArgTypeID : char {\n";
158 OS.indent(NumSpaces: 2) << "NoFuncArgType = 0,\n";
159 for (const auto *R : FuncTypeArgs) {
160 OS.indent(NumSpaces: 2) << R->getName() << ",\n";
161 }
162 OS << "};\n";
163 OS << "static const FuncArgTypeID SignatureTable[] = {\n";
164 SignatureTable.emit(OS, Print: [](raw_ostream &OS, StringRef E) { OS << E; });
165 OS << "};\n";
166 OS << "static const uint16_t SignatureOffset[] = {\n";
167 OS.indent(NumSpaces: 2) << SignatureTable.get(Seq: NoFuncSig) << ", //\n";
168 for (const auto *R : AllTargetLibcalls) {
169 OS.indent(NumSpaces: 2) << SignatureTable.get(Seq: GetSignature(R)) << ", // "
170 << R->getName() << "\n";
171 }
172 OS << "};\n";
173 OS << "#endif\n\n";
174}
175
176void TargetLibraryInfoEmitter::run(raw_ostream &OS) {
177 emitSourceFileHeader(Desc: "Target Library Info Source Fragment", OS, Record: Records);
178
179 emitTargetLibraryInfoEnum(OS);
180 emitTargetLibraryInfoStringTable(OS);
181 emitTargetLibraryInfoSignatureTable(OS);
182}
183
184static TableGen::Emitter::OptClass<TargetLibraryInfoEmitter>
185 X("gen-target-library-info", "Generate TargetLibraryInfo");
186