Skip to content

Commit ff22577

Browse files
refactor
1 parent fba67bd commit ff22577

File tree

1 file changed

+117
-81
lines changed

1 file changed

+117
-81
lines changed

libc/utils/HdrGen/PublicAPICommand.cpp

Lines changed: 117 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
#include "llvm/ADT/SmallVector.h"
1515
#include "llvm/ADT/StringExtras.h"
1616
#include "llvm/ADT/StringRef.h"
17+
#include "llvm/ADT/StringSwitch.h"
1718
#include "llvm/Support/SourceMgr.h"
1819
#include "llvm/TableGen/Record.h"
1920
#include <algorithm>
21+
#include <vector>
2022

2123
// Text blocks for macro definitions and type decls can be indented to
2224
// suit the surrounding tablegen listing. We need to dedent such blocks
@@ -49,99 +51,74 @@ static std::string getTypeHdrName(const std::string &Name) {
4951

5052
namespace llvm_libc {
5153

52-
void writeAPIFromIndex(APIIndexer &G,
53-
std::vector<std::string> EntrypointNameList,
54-
llvm::raw_ostream &OS) {
55-
for (auto &Pair : G.MacroDefsMap) {
56-
const std::string &Name = Pair.first;
57-
if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
58-
llvm::PrintFatalError(Name + " not found in any standard spec.\n");
59-
60-
llvm::Record *MacroDef = Pair.second;
61-
dedentAndWrite(MacroDef->getValueAsString("Defn"), OS);
62-
63-
OS << '\n';
64-
}
65-
66-
for (auto &TypeName : G.RequiredTypes) {
67-
if (G.TypeSpecMap.find(TypeName) == G.TypeSpecMap.end())
68-
llvm::PrintFatalError(TypeName + " not found in any standard spec.\n");
69-
OS << "#include <llvm-libc-types/" << getTypeHdrName(TypeName) << ".h>\n";
70-
}
71-
OS << '\n';
54+
static AttributeStyle getAttributeStyle(llvm::Record *Instance) {
55+
llvm::StringRef Style = Instance->getValueAsString("Style");
56+
return llvm::StringSwitch<AttributeStyle>(Style)
57+
.Case("cxx11", AttributeStyle::Cxx11)
58+
.Case("gnu", AttributeStyle::Gnu)
59+
.Case("declspec", AttributeStyle::Declspec)
60+
.Default(AttributeStyle::Gnu);
61+
}
7262

73-
if (G.Enumerations.size() != 0)
74-
OS << "enum {" << '\n';
75-
for (const auto &Name : G.Enumerations) {
76-
if (G.EnumerationSpecMap.find(Name) == G.EnumerationSpecMap.end())
77-
llvm::PrintFatalError(
78-
Name + " is not listed as an enumeration in any standard spec.\n");
63+
static AttributeNamespace getAttributeNamespace(llvm::Record *Instance) {
64+
llvm::StringRef Namespace = Instance->getValueAsString("Namespace");
65+
return llvm::StringSwitch<AttributeNamespace>(Namespace)
66+
.Case("clang", AttributeNamespace::Clang)
67+
.Case("gnu", AttributeNamespace::Gnu)
68+
.Default(AttributeNamespace::None);
69+
}
7970

80-
llvm::Record *EnumerationSpec = G.EnumerationSpecMap[Name];
81-
OS << " " << EnumerationSpec->getValueAsString("Name");
82-
auto Value = EnumerationSpec->getValueAsString("Value");
83-
if (Value == "__default__") {
84-
OS << ",\n";
85-
} else {
86-
OS << " = " << Value << ",\n";
87-
}
88-
}
89-
if (G.Enumerations.size() != 0)
90-
OS << "};\n\n";
71+
using AttributeMap = llvm::DenseMap<llvm::StringRef, llvm::Record *>;
9172

92-
// declare macros for attributes
73+
template <class SpecMap, class FuncList>
74+
static AttributeMap collectAttributeMacros(const SpecMap &Spec,
75+
const FuncList &Funcs) {
9376
llvm::DenseMap<llvm::StringRef, llvm::Record *> MacroAttr;
94-
for (auto &Name : EntrypointNameList) {
95-
if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) {
77+
for (const auto &Name : Funcs) {
78+
if (!Spec.count(Name))
9679
continue;
97-
}
98-
llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
99-
auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
100-
for (auto *Attr : Attributes) {
80+
81+
llvm::Record *FunctionSpec = Spec.at(Name);
82+
std::vector<llvm::Record *> Attributes =
83+
FunctionSpec->getValueAsListOfDefs("Attributes");
84+
for (llvm::Record *Attr : Attributes)
10185
MacroAttr[Attr->getValueAsString("Macro")] = Attr;
102-
}
10386
}
87+
return MacroAttr;
88+
}
10489

105-
auto GetStyle = [](llvm::Record *Instance) {
106-
auto Style = Instance->getValueAsString("Style");
107-
if (Style == "cxx11")
108-
return AttributeStyle::Cxx11;
109-
if (Style == "gnu")
110-
return AttributeStyle::Gnu;
111-
return AttributeStyle::Declspec;
112-
};
113-
114-
auto GetNamespace = [](llvm::Record *Instance) {
115-
auto Namespace = Instance->getValueAsString("Namespace");
116-
// Empty namespace is likely to be most standard-compliant.
117-
if (Namespace.empty())
118-
return AttributeNamespace::None;
119-
// Dispatch clang version before gnu version.
120-
if (Namespace == "clang")
121-
return AttributeNamespace::Clang;
122-
return AttributeNamespace::Gnu;
123-
};
124-
90+
static void emitAttributeMacroDecls(const AttributeMap &MacroAttr,
91+
llvm::raw_ostream &OS) {
12592
for (auto &[Macro, Attr] : MacroAttr) {
126-
auto Instances = Attr->getValueAsListOfDefs("Instances");
93+
std::vector<llvm::Record *> Instances =
94+
Attr->getValueAsListOfDefs("Instances");
12795
llvm::SmallVector<std::pair<AttributeStyle, llvm::Record *>> Styles;
12896
std::transform(Instances.begin(), Instances.end(),
12997
std::back_inserter(Styles),
13098
[&](llvm::Record *Instance)
13199
-> std::pair<AttributeStyle, llvm::Record *> {
132-
auto Style = GetStyle(Instance);
100+
auto Style = getAttributeStyle(Instance);
133101
return {Style, Instance};
134102
});
135-
// Effectively sort on the first field
103+
// 1. If __cplusplus is defined and cxx11 style is provided, define the
104+
// macro using cxx11 version with the following priority:
105+
// 1a. If the attribute is a clang attribute, check for __clang__.
106+
// 2b. If the attribute is a gnu attribute, check for __GNUC__.
107+
// 2. Otherwise, if __GNUC__ is defined and gnu
108+
// style is provided, define the macro using gnu version;
109+
// 3. Otherwise, if _MSC_VER is defined and __declspec is provided, define
110+
// the macro using __declspec version;
111+
// 4. Fallback to empty macro.
136112
std::sort(Styles.begin(), Styles.end(), [&](auto &a, auto &b) {
137113
if (a.first == AttributeStyle::Cxx11 && b.first == AttributeStyle::Cxx11)
138-
return GetNamespace(a.second) < GetNamespace(b.second);
114+
return getAttributeNamespace(a.second) <
115+
getAttributeNamespace(b.second);
139116
return a.first < b.first;
140117
});
141118
for (auto &[Style, Instance] : Styles) {
142119
if (Style == AttributeStyle::Cxx11) {
143120
OS << "#if !defined(" << Macro << ") && defined(__cplusplus)";
144-
auto Namespace = GetNamespace(Instance);
121+
AttributeNamespace Namespace = getAttributeNamespace(Instance);
145122
if (Namespace == AttributeNamespace::Clang)
146123
OS << " && defined(__clang__)\n";
147124
else if (Namespace == AttributeNamespace::Gnu)
@@ -176,6 +153,72 @@ void writeAPIFromIndex(APIIndexer &G,
176153

177154
if (!MacroAttr.empty())
178155
OS << '\n';
156+
}
157+
158+
static void emitAttributeMacroForFunction(const llvm::Record *FunctionSpec,
159+
llvm::raw_ostream &OS) {
160+
std::vector<llvm::Record *> Attributes =
161+
FunctionSpec->getValueAsListOfDefs("Attributes");
162+
llvm::interleave(
163+
Attributes.begin(), Attributes.end(),
164+
[&](llvm::Record *Attr) { OS << Attr->getValueAsString("Macro"); },
165+
[&]() { OS << ' '; });
166+
if (!Attributes.empty())
167+
OS << ' ';
168+
}
169+
170+
static void emitUndefsForAttributeMacros(const AttributeMap &MacroAttr,
171+
llvm::raw_ostream &OS) {
172+
if (!MacroAttr.empty())
173+
OS << '\n';
174+
for (auto &[Macro, Attr] : MacroAttr)
175+
OS << "#undef " << Macro << '\n';
176+
}
177+
178+
static void writeAPIFromIndex(APIIndexer &G,
179+
std::vector<std::string> EntrypointNameList,
180+
llvm::raw_ostream &OS) {
181+
for (auto &Pair : G.MacroDefsMap) {
182+
const std::string &Name = Pair.first;
183+
if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
184+
llvm::PrintFatalError(Name + " not found in any standard spec.\n");
185+
186+
llvm::Record *MacroDef = Pair.second;
187+
dedentAndWrite(MacroDef->getValueAsString("Defn"), OS);
188+
189+
OS << '\n';
190+
}
191+
192+
for (auto &TypeName : G.RequiredTypes) {
193+
if (G.TypeSpecMap.find(TypeName) == G.TypeSpecMap.end())
194+
llvm::PrintFatalError(TypeName + " not found in any standard spec.\n");
195+
OS << "#include <llvm-libc-types/" << getTypeHdrName(TypeName) << ".h>\n";
196+
}
197+
OS << '\n';
198+
199+
if (G.Enumerations.size() != 0)
200+
OS << "enum {" << '\n';
201+
for (const auto &Name : G.Enumerations) {
202+
if (!G.EnumerationSpecMap.count(Name))
203+
llvm::PrintFatalError(
204+
Name + " is not listed as an enumeration in any standard spec.\n");
205+
206+
llvm::Record *EnumerationSpec = G.EnumerationSpecMap[Name];
207+
OS << " " << EnumerationSpec->getValueAsString("Name");
208+
auto Value = EnumerationSpec->getValueAsString("Value");
209+
if (Value == "__default__") {
210+
OS << ",\n";
211+
} else {
212+
OS << " = " << Value << ",\n";
213+
}
214+
}
215+
if (G.Enumerations.size() != 0)
216+
OS << "};\n\n";
217+
218+
// Collect and declare macros for attributes
219+
AttributeMap MacroAttr =
220+
collectAttributeMacros(G.FunctionSpecMap, EntrypointNameList);
221+
emitAttributeMacroDecls(MacroAttr, OS);
179222

180223
OS << "__BEGIN_C_DECLS\n\n";
181224
for (auto &Name : EntrypointNameList) {
@@ -192,14 +235,8 @@ void writeAPIFromIndex(APIIndexer &G,
192235
llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
193236
llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
194237

195-
auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
196-
llvm::interleave(
197-
Attributes.begin(), Attributes.end(),
198-
[&](llvm::Record *Attr) { OS << Attr->getValueAsString("Macro"); },
199-
[&]() { OS << ' '; });
200-
if (!Attributes.empty())
201-
OS << ' ';
202-
238+
// Emit attribute macros for the function. Space is automatically added.
239+
emitAttributeMacroForFunction(FunctionSpec, OS);
203240
OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
204241

205242
auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
@@ -223,9 +260,8 @@ void writeAPIFromIndex(APIIndexer &G,
223260
}
224261
OS << "__END_C_DECLS\n";
225262

226-
// undef the macros
227-
for (auto &[Macro, Attr] : MacroAttr)
228-
OS << "\n#undef " << Macro << '\n';
263+
// Undef file-level attribute macros.
264+
emitUndefsForAttributeMacros(MacroAttr, OS);
229265
}
230266

231267
void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}

0 commit comments

Comments
 (0)