173
|
1 //===-- Implementation of PublicAPICommand --------------------------------===//
|
150
|
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 "PublicAPICommand.h"
|
|
10
|
221
|
11 #include "utils/LibcTableGenUtil/APIIndexer.h"
|
|
12
|
236
|
13 #include "llvm/ADT/SmallVector.h"
|
150
|
14 #include "llvm/ADT/StringExtras.h"
|
|
15 #include "llvm/ADT/StringRef.h"
|
|
16 #include "llvm/Support/SourceMgr.h"
|
|
17 #include "llvm/TableGen/Record.h"
|
|
18
|
|
19 // Text blocks for macro definitions and type decls can be indented to
|
|
20 // suit the surrounding tablegen listing. We need to dedent such blocks
|
|
21 // before writing them out.
|
|
22 static void dedentAndWrite(llvm::StringRef Text, llvm::raw_ostream &OS) {
|
|
23 llvm::SmallVector<llvm::StringRef, 10> Lines;
|
|
24 llvm::SplitString(Text, Lines, "\n");
|
|
25 size_t shortest_indent = 1024;
|
|
26 for (llvm::StringRef L : Lines) {
|
|
27 llvm::StringRef Indent = L.take_while([](char c) { return c == ' '; });
|
|
28 size_t IndentSize = Indent.size();
|
|
29 if (Indent.size() == L.size()) {
|
|
30 // Line is all spaces so no point noting the indent.
|
|
31 continue;
|
|
32 }
|
|
33 if (IndentSize < shortest_indent)
|
|
34 shortest_indent = IndentSize;
|
|
35 }
|
|
36 for (llvm::StringRef L : Lines) {
|
|
37 if (L.size() >= shortest_indent)
|
|
38 OS << L.drop_front(shortest_indent) << '\n';
|
|
39 }
|
|
40 }
|
|
41
|
236
|
42 static std::string getTypeHdrName(const std::string &Name) {
|
|
43 llvm::SmallVector<llvm::StringRef> Parts;
|
|
44 llvm::SplitString(llvm::StringRef(Name), Parts);
|
|
45 return llvm::join(Parts.begin(), Parts.end(), "_");
|
|
46 }
|
|
47
|
221
|
48 namespace llvm_libc {
|
150
|
49
|
221
|
50 void writeAPIFromIndex(APIIndexer &G,
|
|
51 std::vector<std::string> EntrypointNameList,
|
|
52 llvm::raw_ostream &OS) {
|
|
53 for (auto &Pair : G.MacroDefsMap) {
|
|
54 const std::string &Name = Pair.first;
|
|
55 if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
|
|
56 llvm::PrintFatalError(Name + " not found in any standard spec.\n");
|
150
|
57
|
221
|
58 llvm::Record *MacroDef = Pair.second;
|
|
59 dedentAndWrite(MacroDef->getValueAsString("Defn"), OS);
|
150
|
60
|
221
|
61 OS << '\n';
|
150
|
62 }
|
|
63
|
236
|
64 for (auto &TypeName : G.RequiredTypes) {
|
|
65 if (G.TypeSpecMap.find(TypeName) == G.TypeSpecMap.end())
|
|
66 llvm::PrintFatalError(TypeName + " not found in any standard spec.\n");
|
|
67 OS << "#include <llvm-libc-types/" << getTypeHdrName(TypeName) << ".h>\n";
|
150
|
68 }
|
236
|
69 OS << '\n';
|
150
|
70
|
221
|
71 if (G.Enumerations.size() != 0)
|
|
72 OS << "enum {" << '\n';
|
|
73 for (const auto &Name : G.Enumerations) {
|
|
74 if (G.EnumerationSpecMap.find(Name) == G.EnumerationSpecMap.end())
|
|
75 llvm::PrintFatalError(
|
|
76 Name + " is not listed as an enumeration in any standard spec.\n");
|
173
|
77
|
221
|
78 llvm::Record *EnumerationSpec = G.EnumerationSpecMap[Name];
|
|
79 OS << " " << EnumerationSpec->getValueAsString("Name");
|
|
80 auto Value = EnumerationSpec->getValueAsString("Value");
|
|
81 if (Value == "__default__") {
|
|
82 OS << ",\n";
|
|
83 } else {
|
|
84 OS << " = " << Value << ",\n";
|
150
|
85 }
|
|
86 }
|
221
|
87 if (G.Enumerations.size() != 0)
|
|
88 OS << "};\n\n";
|
150
|
89
|
221
|
90 OS << "__BEGIN_C_DECLS\n\n";
|
|
91 for (auto &Name : EntrypointNameList) {
|
|
92 if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) {
|
|
93 continue; // Functions that aren't in this header file are skipped as
|
|
94 // opposed to erroring out because the list of functions being
|
|
95 // iterated over is the complete list of functions with
|
|
96 // entrypoints. Thus this is filtering out the functions that
|
|
97 // don't go to this header file, whereas the other, similar
|
|
98 // conditionals above are more of a sanity check.
|
150
|
99 }
|
|
100
|
221
|
101 llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
|
|
102 llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
|
|
103 llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
|
173
|
104
|
221
|
105 OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
|
173
|
106
|
221
|
107 auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
|
|
108 for (size_t i = 0; i < ArgsList.size(); ++i) {
|
|
109 llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType");
|
|
110 OS << G.getTypeAsString(ArgType);
|
|
111 if (i < ArgsList.size() - 1)
|
|
112 OS << ", ";
|
|
113 }
|
150
|
114
|
252
|
115 OS << ") __NOEXCEPT;\n\n";
|
150
|
116 }
|
236
|
117
|
|
118 // Make another pass over entrypoints to emit object declarations.
|
|
119 for (const auto &Name : EntrypointNameList) {
|
|
120 if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
|
|
121 continue;
|
|
122 llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
|
|
123 auto Type = ObjectSpec->getValueAsString("Type");
|
|
124 OS << "extern " << Type << " " << Name << ";\n";
|
|
125 }
|
221
|
126 OS << "__END_C_DECLS\n";
|
|
127 }
|
150
|
128
|
|
129 void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}
|
|
130
|
|
131 const char PublicAPICommand::Name[] = "public_api";
|
|
132
|
|
133 void PublicAPICommand::run(llvm::raw_ostream &OS, const ArgVector &Args,
|
|
134 llvm::StringRef StdHeader,
|
|
135 llvm::RecordKeeper &Records,
|
|
136 const Command::ErrorReporter &Reporter) const {
|
|
137 if (Args.size() != 0) {
|
|
138 Reporter.printFatalError("public_api command does not take any arguments.");
|
|
139 }
|
|
140
|
221
|
141 APIIndexer G(StdHeader, Records);
|
|
142 writeAPIFromIndex(G, EntrypointNameList, OS);
|
150
|
143 }
|
|
144
|
|
145 } // namespace llvm_libc
|