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