1010
1111#include " utils/LibcTableGenUtil/APIIndexer.h"
1212
13+ #include " llvm/ADT/STLExtras.h"
1314#include " llvm/ADT/SmallVector.h"
1415#include " llvm/ADT/StringExtras.h"
1516#include " llvm/ADT/StringRef.h"
17+ #include " llvm/ADT/StringSwitch.h"
1618#include " llvm/Support/SourceMgr.h"
1719#include " llvm/TableGen/Record.h"
20+ #include < algorithm>
21+ #include < vector>
1822
1923// Text blocks for macro definitions and type decls can be indented to
2024// suit the surrounding tablegen listing. We need to dedent such blocks
@@ -47,12 +51,170 @@ static std::string getTypeHdrName(const std::string &Name) {
4751
4852namespace llvm_libc {
4953
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) {
53215 for (auto &Pair : G.MacroDefsMap ) {
54216 const std::string &Name = Pair.first ;
55- if (G.MacroSpecMap .find (Name) == G. MacroSpecMap . end ( ))
217+ if (! G.MacroSpecMap .count (Name))
56218 llvm::PrintFatalError (Name + " not found in any standard spec.\n " );
57219
58220 llvm::Record *MacroDef = Pair.second ;
@@ -62,7 +224,7 @@ void writeAPIFromIndex(APIIndexer &G,
62224 }
63225
64226 for (auto &TypeName : G.RequiredTypes ) {
65- if (G.TypeSpecMap .find (TypeName) == G. TypeSpecMap . end ( ))
227+ if (! G.TypeSpecMap .count (TypeName))
66228 llvm::PrintFatalError (TypeName + " not found in any standard spec.\n " );
67229 OS << " #include <llvm-libc-types/" << getTypeHdrName (TypeName) << " .h>\n " ;
68230 }
@@ -71,7 +233,7 @@ void writeAPIFromIndex(APIIndexer &G,
71233 if (G.Enumerations .size () != 0 )
72234 OS << " enum {" << ' \n ' ;
73235 for (const auto &Name : G.Enumerations ) {
74- if (G.EnumerationSpecMap .find (Name) == G. EnumerationSpecMap . end ( ))
236+ if (! G.EnumerationSpecMap .count (Name))
75237 llvm::PrintFatalError (
76238 Name + " is not listed as an enumeration in any standard spec.\n " );
77239
@@ -87,18 +249,25 @@ void writeAPIFromIndex(APIIndexer &G,
87249 if (G.Enumerations .size () != 0 )
88250 OS << " };\n\n " ;
89251
252+ // Collect and declare macros for attributes
253+ AttributeMap MacroAttr =
254+ collectAttributeMacros (G.FunctionSpecMap , EntrypointNameList);
255+ emitAttributeMacroDecls (MacroAttr, OS);
256+
90257 OS << " __BEGIN_C_DECLS\n\n " ;
91258 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);
100260
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 ;
102271 llvm::Record *RetValSpec = FunctionSpec->getValueAsDef (" Return" );
103272 llvm::Record *ReturnType = RetValSpec->getValueAsDef (" ReturnType" );
104273
@@ -110,6 +279,8 @@ void writeAPIFromIndex(APIIndexer &G,
110279 if (Guarded)
111280 OS << " #ifdef " << FunctionSpec->getValueAsString (" Guard" ) << " \n " ;
112281
282+ // Emit attribute macros for the function. Space is automatically added.
283+ emitAttributeMacroForFunction (FunctionSpec, OS);
113284 OS << G.getTypeAsString (ReturnType) << " " << Name << " (" ;
114285
115286 auto ArgsList = FunctionSpec->getValueAsListOfDefs (" Args" );
@@ -130,13 +301,17 @@ void writeAPIFromIndex(APIIndexer &G,
130301
131302 // Make another pass over entrypoints to emit object declarations.
132303 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 ())
134306 continue ;
135- llvm::Record *ObjectSpec = G. ObjectSpecMap [Name] ;
307+ llvm::Record *ObjectSpec = Iter-> second ;
136308 auto Type = ObjectSpec->getValueAsString (" Type" );
137309 OS << " extern " << Type << " " << Name << " ;\n " ;
138310 }
139311 OS << " __END_C_DECLS\n " ;
312+
313+ // Undef file-level attribute macros.
314+ emitUndefsForAttributeMacros (MacroAttr, OS);
140315}
141316
142317void writePublicAPI (llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}
@@ -147,9 +322,8 @@ void PublicAPICommand::run(llvm::raw_ostream &OS, const ArgVector &Args,
147322 llvm::StringRef StdHeader,
148323 llvm::RecordKeeper &Records,
149324 const Command::ErrorReporter &Reporter) const {
150- if (Args.size () != 0 ) {
325+ if (Args.size () != 0 )
151326 Reporter.printFatalError (" public_api command does not take any arguments." );
152- }
153327
154328 APIIndexer G (StdHeader, Records);
155329 writeAPIFromIndex (G, EntrypointNameList, OS);
0 commit comments