10
10
11
11
#include " utils/LibcTableGenUtil/APIIndexer.h"
12
12
13
+ #include " llvm/ADT/STLExtras.h"
13
14
#include " llvm/ADT/SmallVector.h"
14
15
#include " llvm/ADT/StringExtras.h"
15
16
#include " llvm/ADT/StringRef.h"
17
+ #include " llvm/ADT/StringSwitch.h"
16
18
#include " llvm/Support/SourceMgr.h"
17
19
#include " llvm/TableGen/Record.h"
20
+ #include < algorithm>
21
+ #include < vector>
18
22
19
23
// Text blocks for macro definitions and type decls can be indented to
20
24
// suit the surrounding tablegen listing. We need to dedent such blocks
@@ -47,12 +51,170 @@ static std::string getTypeHdrName(const std::string &Name) {
47
51
48
52
namespace llvm_libc {
49
53
50
- void writeAPIFromIndex (APIIndexer &G,
51
- std::vector<std::string> EntrypointNameList,
52
- llvm::raw_ostream &OS) {
54
+ static bool isAsciiStart (char C) {
55
+ return (C >= ' A' && C <= ' Z' ) || (C >= ' a' && C <= ' z' ) || C == ' _' ;
56
+ }
57
+
58
+ static bool isAsciiContinue (char C) {
59
+ return isAsciiStart (C) || (C >= ' 0' && C <= ' 9' );
60
+ }
61
+
62
+ static bool isAsciiIdentifier (llvm::StringRef S) {
63
+ if (S.empty ())
64
+ return false ;
65
+ if (!isAsciiStart (S[0 ]))
66
+ return false ;
67
+ for (char C : S.drop_front ())
68
+ if (!isAsciiContinue (C))
69
+ return false ;
70
+ return true ;
71
+ }
72
+
73
+ static AttributeStyle getAttributeStyle (llvm::Record *Instance) {
74
+ llvm::StringRef Style = Instance->getValueAsString (" Style" );
75
+ return llvm::StringSwitch<AttributeStyle>(Style)
76
+ .Case (" cxx11" , AttributeStyle::Cxx11)
77
+ .Case (" gnu" , AttributeStyle::Gnu)
78
+ .Case (" declspec" , AttributeStyle::Declspec)
79
+ .Default (AttributeStyle::Gnu);
80
+ }
81
+
82
+ static AttributeNamespace getAttributeNamespace (llvm::Record *Instance) {
83
+ llvm::StringRef Namespace = Instance->getValueAsString (" Namespace" );
84
+ return llvm::StringSwitch<AttributeNamespace>(Namespace)
85
+ .Case (" clang" , AttributeNamespace::Clang)
86
+ .Case (" gnu" , AttributeNamespace::Gnu)
87
+ .Default (AttributeNamespace::None);
88
+ }
89
+
90
+ using AttributeMap = llvm::DenseMap<llvm::StringRef, llvm::Record *>;
91
+
92
+ template <class SpecMap , class FuncList >
93
+ static AttributeMap collectAttributeMacros (const SpecMap &Spec,
94
+ const FuncList &Funcs) {
95
+ llvm::DenseMap<llvm::StringRef, llvm::Record *> MacroAttr;
96
+ for (const auto &Name : Funcs) {
97
+ auto Iter = Spec.find (Name);
98
+ if (Iter == Spec.end ())
99
+ continue ;
100
+
101
+ llvm::Record *FunctionSpec = Iter->second ;
102
+ std::vector<llvm::Record *> Attributes =
103
+ FunctionSpec->getValueAsListOfDefs (" Attributes" );
104
+ for (llvm::Record *Attr : Attributes)
105
+ MacroAttr[Attr->getValueAsString (" Macro" )] = Attr;
106
+ }
107
+ return MacroAttr;
108
+ }
109
+
110
+ static void emitAttributeMacroDecls (const AttributeMap &MacroAttr,
111
+ llvm::raw_ostream &OS) {
112
+ for (auto &[Macro, Attr] : MacroAttr) {
113
+ std::vector<llvm::Record *> Instances =
114
+ Attr->getValueAsListOfDefs (" Instances" );
115
+ llvm::SmallVector<std::pair<AttributeStyle, llvm::Record *>> Styles;
116
+ std::transform (Instances.begin (), Instances.end (),
117
+ std::back_inserter (Styles),
118
+ [&](llvm::Record *Instance)
119
+ -> std::pair<AttributeStyle, llvm::Record *> {
120
+ auto Style = getAttributeStyle (Instance);
121
+ return {Style, Instance};
122
+ });
123
+ // 1. If __cplusplus is defined and cxx11 style is provided, define the
124
+ // macro using cxx11 version with the following priority:
125
+ // 1a. If there is no namespace (so the macro is supposed to be
126
+ // compiler-independent), use this version first. This macro will be
127
+ // tested via __has_cpp_attribute.
128
+ // 1b. If the attribute is a clang attribute, check for __clang__.
129
+ // 1c. If the attribute is a gnu attribute, check for __GNUC__.
130
+ // 2. Otherwise, if __GNUC__ is defined and gnu style is provided,
131
+ // define the macro using gnu version;
132
+ // 3. Otherwise, if _MSC_VER is defined and __declspec is provided, define
133
+ // the macro using __declspec version;
134
+ // 4. Fallback to empty macro.
135
+ std::sort (Styles.begin (), Styles.end (), [&](auto &a, auto &b) {
136
+ if (a.first == AttributeStyle::Cxx11 && b.first == AttributeStyle::Cxx11)
137
+ return getAttributeNamespace (a.second ) <
138
+ getAttributeNamespace (b.second );
139
+ return a.first < b.first ;
140
+ });
141
+ for (auto &[Style, Instance] : Styles) {
142
+ llvm::StringRef Attr = Instance->getValueAsString (" Attr" );
143
+ if (Style == AttributeStyle::Cxx11) {
144
+ OS << " #if !defined(" << Macro << " ) && defined(__cplusplus)" ;
145
+ AttributeNamespace Namespace = getAttributeNamespace (Instance);
146
+ if (Namespace == AttributeNamespace::Clang)
147
+ OS << " && defined(__clang__)\n " ;
148
+ else if (Namespace == AttributeNamespace::Gnu)
149
+ OS << " && defined(__GNUC__)\n " ;
150
+ else
151
+ OS << ' \n ' ;
152
+ if (isAsciiIdentifier (Attr) && Namespace != AttributeNamespace::None)
153
+ OS << " #if __has_attribute(" << Attr << " )\n " ;
154
+ else
155
+ OS << " #if __has_cpp_attribute(" << Attr << " )\n " ;
156
+ OS << " #define " << Macro << " [[" ;
157
+ if (Namespace == AttributeNamespace::Clang)
158
+ OS << " clang::" ;
159
+ else if (Namespace == AttributeNamespace::Gnu)
160
+ OS << " gnu::" ;
161
+ OS << Attr << " ]]\n " ;
162
+ if (isAsciiIdentifier (Attr))
163
+ OS << " #endif\n " ;
164
+ OS << " #endif\n " ;
165
+ }
166
+ if (Style == AttributeStyle::Gnu) {
167
+ OS << " #if !defined(" << Macro << " ) && defined(__GNUC__)\n " ;
168
+ if (isAsciiIdentifier (Attr))
169
+ OS << " #if __has_attribute(" << Attr << " )\n " ;
170
+ OS << " #define " << Macro << " __attribute__((" ;
171
+ OS << Attr << " ))\n " ;
172
+ if (isAsciiIdentifier (Attr))
173
+ OS << " #endif\n " ;
174
+ OS << " #endif\n " ;
175
+ }
176
+ if (Style == AttributeStyle::Declspec) {
177
+ OS << " #if !defined(" << Macro << " ) && defined(_MSC_VER)\n " ;
178
+ OS << " #define " << Macro << " __declspec(" ;
179
+ OS << Attr << " )\n " ;
180
+ OS << " #endif\n " ;
181
+ }
182
+ }
183
+ OS << " #if !defined(" << Macro << " )\n " ;
184
+ OS << " #define " << Macro << ' \n ' ;
185
+ OS << " #endif\n " ;
186
+ }
187
+
188
+ if (!MacroAttr.empty ())
189
+ OS << ' \n ' ;
190
+ }
191
+
192
+ static void emitAttributeMacroForFunction (const llvm::Record *FunctionSpec,
193
+ llvm::raw_ostream &OS) {
194
+ std::vector<llvm::Record *> Attributes =
195
+ 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
+ }
203
+
204
+ static void emitUndefsForAttributeMacros (const AttributeMap &MacroAttr,
205
+ llvm::raw_ostream &OS) {
206
+ if (!MacroAttr.empty ())
207
+ OS << ' \n ' ;
208
+ for (auto &[Macro, Attr] : MacroAttr)
209
+ OS << " #undef " << Macro << ' \n ' ;
210
+ }
211
+
212
+ static void writeAPIFromIndex (APIIndexer &G,
213
+ std::vector<std::string> EntrypointNameList,
214
+ llvm::raw_ostream &OS) {
53
215
for (auto &Pair : G.MacroDefsMap ) {
54
216
const std::string &Name = Pair.first ;
55
- if (G.MacroSpecMap .find (Name) == G. MacroSpecMap . end ( ))
217
+ if (! G.MacroSpecMap .count (Name))
56
218
llvm::PrintFatalError (Name + " not found in any standard spec.\n " );
57
219
58
220
llvm::Record *MacroDef = Pair.second ;
@@ -62,7 +224,7 @@ void writeAPIFromIndex(APIIndexer &G,
62
224
}
63
225
64
226
for (auto &TypeName : G.RequiredTypes ) {
65
- if (G.TypeSpecMap .find (TypeName) == G. TypeSpecMap . end ( ))
227
+ if (! G.TypeSpecMap .count (TypeName))
66
228
llvm::PrintFatalError (TypeName + " not found in any standard spec.\n " );
67
229
OS << " #include <llvm-libc-types/" << getTypeHdrName (TypeName) << " .h>\n " ;
68
230
}
@@ -71,7 +233,7 @@ void writeAPIFromIndex(APIIndexer &G,
71
233
if (G.Enumerations .size () != 0 )
72
234
OS << " enum {" << ' \n ' ;
73
235
for (const auto &Name : G.Enumerations ) {
74
- if (G.EnumerationSpecMap .find (Name) == G. EnumerationSpecMap . end ( ))
236
+ if (! G.EnumerationSpecMap .count (Name))
75
237
llvm::PrintFatalError (
76
238
Name + " is not listed as an enumeration in any standard spec.\n " );
77
239
@@ -87,18 +249,25 @@ void writeAPIFromIndex(APIIndexer &G,
87
249
if (G.Enumerations .size () != 0 )
88
250
OS << " };\n\n " ;
89
251
252
+ // Collect and declare macros for attributes
253
+ AttributeMap MacroAttr =
254
+ collectAttributeMacros (G.FunctionSpecMap , EntrypointNameList);
255
+ emitAttributeMacroDecls (MacroAttr, OS);
256
+
90
257
OS << " __BEGIN_C_DECLS\n\n " ;
91
258
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.
99
- }
259
+ auto Iter = G.FunctionSpecMap .find (Name);
100
260
101
- llvm::Record *FunctionSpec = G.FunctionSpecMap [Name];
261
+ // Functions that aren't in this header file are skipped as
262
+ // opposed to erroring out because the list of functions being
263
+ // iterated over is the complete list of functions with
264
+ // entrypoints. Thus this is filtering out the functions that
265
+ // don't go to this header file, whereas the other, similar
266
+ // conditionals above are more of a sanity check.
267
+ if (Iter == G.FunctionSpecMap .end ())
268
+ continue ;
269
+
270
+ llvm::Record *FunctionSpec = Iter->second ;
102
271
llvm::Record *RetValSpec = FunctionSpec->getValueAsDef (" Return" );
103
272
llvm::Record *ReturnType = RetValSpec->getValueAsDef (" ReturnType" );
104
273
@@ -110,6 +279,8 @@ void writeAPIFromIndex(APIIndexer &G,
110
279
if (Guarded)
111
280
OS << " #ifdef " << FunctionSpec->getValueAsString (" Guard" ) << " \n " ;
112
281
282
+ // Emit attribute macros for the function. Space is automatically added.
283
+ emitAttributeMacroForFunction (FunctionSpec, OS);
113
284
OS << G.getTypeAsString (ReturnType) << " " << Name << " (" ;
114
285
115
286
auto ArgsList = FunctionSpec->getValueAsListOfDefs (" Args" );
@@ -130,13 +301,17 @@ void writeAPIFromIndex(APIIndexer &G,
130
301
131
302
// Make another pass over entrypoints to emit object declarations.
132
303
for (const auto &Name : EntrypointNameList) {
133
- if (G.ObjectSpecMap .find (Name) == G.ObjectSpecMap .end ())
304
+ auto Iter = G.ObjectSpecMap .find (Name);
305
+ if (Iter == G.ObjectSpecMap .end ())
134
306
continue ;
135
- llvm::Record *ObjectSpec = G. ObjectSpecMap [Name] ;
307
+ llvm::Record *ObjectSpec = Iter-> second ;
136
308
auto Type = ObjectSpec->getValueAsString (" Type" );
137
309
OS << " extern " << Type << " " << Name << " ;\n " ;
138
310
}
139
311
OS << " __END_C_DECLS\n " ;
312
+
313
+ // Undef file-level attribute macros.
314
+ emitUndefsForAttributeMacros (MacroAttr, OS);
140
315
}
141
316
142
317
void writePublicAPI (llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}
@@ -147,9 +322,8 @@ void PublicAPICommand::run(llvm::raw_ostream &OS, const ArgVector &Args,
147
322
llvm::StringRef StdHeader,
148
323
llvm::RecordKeeper &Records,
149
324
const Command::ErrorReporter &Reporter) const {
150
- if (Args.size () != 0 ) {
325
+ if (Args.size () != 0 )
151
326
Reporter.printFatalError (" public_api command does not take any arguments." );
152
- }
153
327
154
328
APIIndexer G (StdHeader, Records);
155
329
writeAPIFromIndex (G, EntrypointNameList, OS);
0 commit comments