14
14
#include " llvm/ADT/SmallVector.h"
15
15
#include " llvm/ADT/StringExtras.h"
16
16
#include " llvm/ADT/StringRef.h"
17
+ #include " llvm/ADT/StringSwitch.h"
17
18
#include " llvm/Support/SourceMgr.h"
18
19
#include " llvm/TableGen/Record.h"
19
20
#include < algorithm>
21
+ #include < vector>
20
22
21
23
// Text blocks for macro definitions and type decls can be indented to
22
24
// suit the surrounding tablegen listing. We need to dedent such blocks
@@ -49,99 +51,74 @@ static std::string getTypeHdrName(const std::string &Name) {
49
51
50
52
namespace llvm_libc {
51
53
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
+ }
72
62
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
+ }
79
70
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 *>;
91
72
92
- // declare macros for attributes
73
+ template <class SpecMap , class FuncList >
74
+ static AttributeMap collectAttributeMacros (const SpecMap &Spec,
75
+ const FuncList &Funcs) {
93
76
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))
96
79
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)
101
85
MacroAttr[Attr->getValueAsString (" Macro" )] = Attr;
102
- }
103
86
}
87
+ return MacroAttr;
88
+ }
104
89
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) {
125
92
for (auto &[Macro, Attr] : MacroAttr) {
126
- auto Instances = Attr->getValueAsListOfDefs (" Instances" );
93
+ std::vector<llvm::Record *> Instances =
94
+ Attr->getValueAsListOfDefs (" Instances" );
127
95
llvm::SmallVector<std::pair<AttributeStyle, llvm::Record *>> Styles;
128
96
std::transform (Instances.begin (), Instances.end (),
129
97
std::back_inserter (Styles),
130
98
[&](llvm::Record *Instance)
131
99
-> std::pair<AttributeStyle, llvm::Record *> {
132
- auto Style = GetStyle (Instance);
100
+ auto Style = getAttributeStyle (Instance);
133
101
return {Style, Instance};
134
102
});
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.
136
112
std::sort (Styles.begin (), Styles.end (), [&](auto &a, auto &b) {
137
113
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 );
139
116
return a.first < b.first ;
140
117
});
141
118
for (auto &[Style, Instance] : Styles) {
142
119
if (Style == AttributeStyle::Cxx11) {
143
120
OS << " #if !defined(" << Macro << " ) && defined(__cplusplus)" ;
144
- auto Namespace = GetNamespace (Instance);
121
+ AttributeNamespace Namespace = getAttributeNamespace (Instance);
145
122
if (Namespace == AttributeNamespace::Clang)
146
123
OS << " && defined(__clang__)\n " ;
147
124
else if (Namespace == AttributeNamespace::Gnu)
@@ -176,6 +153,72 @@ void writeAPIFromIndex(APIIndexer &G,
176
153
177
154
if (!MacroAttr.empty ())
178
155
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);
179
222
180
223
OS << " __BEGIN_C_DECLS\n\n " ;
181
224
for (auto &Name : EntrypointNameList) {
@@ -192,14 +235,8 @@ void writeAPIFromIndex(APIIndexer &G,
192
235
llvm::Record *RetValSpec = FunctionSpec->getValueAsDef (" Return" );
193
236
llvm::Record *ReturnType = RetValSpec->getValueAsDef (" ReturnType" );
194
237
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);
203
240
OS << G.getTypeAsString (ReturnType) << " " << Name << " (" ;
204
241
205
242
auto ArgsList = FunctionSpec->getValueAsListOfDefs (" Args" );
@@ -223,9 +260,8 @@ void writeAPIFromIndex(APIIndexer &G,
223
260
}
224
261
OS << " __END_C_DECLS\n " ;
225
262
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);
229
265
}
230
266
231
267
void writePublicAPI (llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}
0 commit comments