Skip to content

Commit 9eef290

Browse files
[libc][RFC] add support for function level attributes
1 parent 0166fde commit 9eef290

File tree

4 files changed

+92
-76
lines changed

4 files changed

+92
-76
lines changed

libc/spec/spec.td

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,17 +175,18 @@ class GnuFunctionAttr<string attr> : FunctionAttr {
175175
string Attr = attr;
176176
string Style = "gnu";
177177
}
178-
class C23FunctionAttr<string attr, string namespace> : FunctionAttr {
178+
class Cxx11FunctionAttr<string attr, string namespace> : FunctionAttr {
179179
string Attr = attr;
180180
string Namespace = namespace;
181-
string Style = "c23";
181+
string Style = "cxx11";
182182
}
183183
class DeclspecFunctionAttr<string attr> : FunctionAttr {
184184
string Attr = attr;
185185
string Style = "declspec";
186186
}
187-
class FunctionAttrSpec<list<FunctionAttr> instances> {
187+
class FunctionAttrSpec<string macro, list<FunctionAttr> instances> {
188188
list<FunctionAttr> Instances = instances;
189+
string Macro = macro;
189190
}
190191

191192
class FunctionSpec<string name, RetValSpec return, list<ArgSpec> args, list<FunctionAttrSpec> attrs = []> {

libc/spec/stdc.td

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ def StdC : StandardSpec<"stdc"> {
2626
[]
2727
>;
2828

29+
FunctionAttrSpec ConstAttr = FunctionAttrSpec<"__LIBC_CONST_ATTR", [
30+
Cxx11FunctionAttr<"const", "gnu">,
31+
GnuFunctionAttr<"const">,
32+
]>;
33+
2934
HeaderSpec CType = HeaderSpec<
3035
"ctype.h",
3136
[], // Macros
@@ -364,7 +369,7 @@ def StdC : StandardSpec<"stdc"> {
364369
FunctionSpec<"ceilf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
365370
FunctionSpec<"ceill", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
366371

367-
FunctionSpec<"fabs", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
372+
FunctionSpec<"fabs", RetValSpec<DoubleType>, [ArgSpec<DoubleType>], [ConstAttr]>,
368373
FunctionSpec<"fabsf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
369374
FunctionSpec<"fabsl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
370375
FunctionSpec<"fabsf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>]>,

libc/utils/HdrGen/PublicAPICommand.cpp

Lines changed: 81 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "llvm/ADT/StringRef.h"
1616
#include "llvm/Support/SourceMgr.h"
1717
#include "llvm/TableGen/Record.h"
18+
#include <algorithm>
1819
#include <llvm/ADT/STLExtras.h>
1920

2021
// Text blocks for macro definitions and type decls can be indented to
@@ -50,7 +51,7 @@ namespace llvm_libc {
5051

5152
void writeAPIFromIndex(APIIndexer &G,
5253
std::vector<std::string> EntrypointNameList,
53-
llvm::raw_ostream &OS, AttributeStyle PreferedStyle) {
54+
llvm::raw_ostream &OS) {
5455
for (auto &Pair : G.MacroDefsMap) {
5556
const std::string &Name = Pair.first;
5657
if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
@@ -88,6 +89,71 @@ void writeAPIFromIndex(APIIndexer &G,
8889
if (G.Enumerations.size() != 0)
8990
OS << "};\n\n";
9091

92+
// declare macros for attributes
93+
llvm::DenseMap<llvm::StringRef, llvm::Record *> MacroAttr;
94+
for (auto &Name : EntrypointNameList) {
95+
if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) {
96+
continue;
97+
}
98+
llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
99+
auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
100+
for (auto *Attr : Attributes) {
101+
MacroAttr[Attr->getValueAsString("Macro")] = Attr;
102+
}
103+
}
104+
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+
for (auto &[Macro, Attr] : MacroAttr) {
115+
auto Instances = Attr->getValueAsListOfDefs("Instances");
116+
llvm::SmallVector<std::pair<AttributeStyle, llvm::Record *>> Styles;
117+
std::transform(Instances.begin(), Instances.end(),
118+
std::back_inserter(Styles),
119+
[&](llvm::Record *Instance)
120+
-> std::pair<AttributeStyle, llvm::Record *> {
121+
auto Style = GetStyle(Instance);
122+
return {Style, Instance};
123+
});
124+
// Effectively sort on the first field
125+
std::sort(Styles.begin(), Styles.end());
126+
for (auto &[Style, Instance] : Styles) {
127+
if (Style == AttributeStyle::Cxx11) {
128+
OS << "#if !defined(" << Macro << ") && defined(__cplusplus)\n";
129+
OS << "#define " << Macro << " [[";
130+
auto Namespace = Instance->getValueAsString("Namespace");
131+
if (Namespace != "")
132+
OS << Namespace << "::";
133+
OS << Instance->getValueAsString("Attr") << "]]\n";
134+
OS << "#endif\n";
135+
}
136+
if (Style == AttributeStyle::Gnu) {
137+
OS << "#if !defined(" << Macro << ") && defined(__GNUC__)\n";
138+
OS << "#define " << Macro << " __attribute__((";
139+
OS << Instance->getValueAsString("Attr") << "))\n";
140+
OS << "#endif\n";
141+
}
142+
if (Style == AttributeStyle::Declspec) {
143+
OS << "#if !defined(" << Macro << ") && defined(_MSC_VER)\n";
144+
OS << "#define " << Macro << " __declspec(";
145+
OS << Instance->getValueAsString("Attr") << ")\n";
146+
OS << "#endif\n";
147+
}
148+
}
149+
OS << "#if !defined(" << Macro << ")\n";
150+
OS << "#define " << Macro << '\n';
151+
OS << "#endif\n";
152+
}
153+
154+
if (!MacroAttr.empty())
155+
OS << '\n';
156+
91157
OS << "__BEGIN_C_DECLS\n\n";
92158
for (auto &Name : EntrypointNameList) {
93159
if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) {
@@ -103,61 +169,13 @@ void writeAPIFromIndex(APIIndexer &G,
103169
llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
104170
llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
105171

106-
auto GetStyle = [](llvm::Record *Instance) {
107-
auto Style = Instance->getValueAsString("Style");
108-
if (Style == "gnu")
109-
return AttributeStyle::Gnu;
110-
if (Style == "c23")
111-
return AttributeStyle::C23;
112-
if (Style == "declspec")
113-
return AttributeStyle::Declspec;
114-
return AttributeStyle::None;
115-
};
116-
117-
if (PreferedStyle != AttributeStyle::None) {
118-
auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
119-
llvm::SmallVector<llvm::Record *> Attrs;
120-
for (auto *Attr : Attributes) {
121-
auto Instances = Attr->getValueAsListOfDefs("Instances");
122-
for (auto *Instance : Instances) {
123-
if (GetStyle(Instance) == PreferedStyle) {
124-
Attrs.push_back(Instance);
125-
}
126-
}
127-
}
128-
129-
if (Attrs.size() != 0) {
130-
if (PreferedStyle == AttributeStyle::Gnu) {
131-
OS << "__attribute__((";
132-
llvm::interleaveComma(Attrs, OS, [&](llvm::Record *Instance) {
133-
OS << Instance->getValueAsString("Attr");
134-
});
135-
OS << ")) ";
136-
}
137-
138-
if (PreferedStyle == AttributeStyle::C23) {
139-
OS << "__attribute__((";
140-
llvm::interleaveComma(Attrs, OS, [&](llvm::Record *Instance) {
141-
auto Namespace = Instance->getValueAsString("Namespace");
142-
if (Namespace != "")
143-
OS << Namespace << "::";
144-
OS << Instance->getValueAsString("Attr");
145-
});
146-
OS << ")) ";
147-
}
148-
149-
if (PreferedStyle == AttributeStyle::Declspec) {
150-
OS << "__declspec(";
151-
llvm::interleave(
152-
Attrs.begin(), Attrs.end(),
153-
[&](llvm::Record *Instance) {
154-
OS << Instance->getValueAsString("Attr");
155-
},
156-
[&]() { OS << ' '; });
157-
OS << ") ";
158-
}
159-
}
160-
}
172+
auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
173+
llvm::interleave(
174+
Attributes.begin(), Attributes.end(),
175+
[&](llvm::Record *Attr) { OS << Attr->getValueAsString("Macro"); },
176+
[&]() { OS << ' '; });
177+
if (!Attributes.empty())
178+
OS << ' ';
161179

162180
OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
163181

@@ -181,6 +199,10 @@ void writeAPIFromIndex(APIIndexer &G,
181199
OS << "extern " << Type << " " << Name << ";\n";
182200
}
183201
OS << "__END_C_DECLS\n";
202+
203+
// undef the macros
204+
for (auto &[Macro, Attr] : MacroAttr)
205+
OS << "\n#undef " << Macro << '\n';
184206
}
185207

186208
void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}
@@ -191,24 +213,12 @@ void PublicAPICommand::run(llvm::raw_ostream &OS, const ArgVector &Args,
191213
llvm::StringRef StdHeader,
192214
llvm::RecordKeeper &Records,
193215
const Command::ErrorReporter &Reporter) const {
194-
if (Args.size() > 1) {
195-
Reporter.printFatalError(
196-
"public_api command does not take more than one arguments.");
197-
}
198-
199-
AttributeStyle PreferedStyle = AttributeStyle::Gnu;
200-
201-
for (auto &arg : Args) {
202-
if (arg == "prefer-c23-attributes") {
203-
PreferedStyle = AttributeStyle::C23;
204-
}
205-
if (arg == "prefer-no-attributes") {
206-
PreferedStyle = AttributeStyle::None;
207-
}
216+
if (Args.size() != 0) {
217+
Reporter.printFatalError("public_api command does not take any arguments.");
208218
}
209219

210220
APIIndexer G(StdHeader, Records);
211-
writeAPIFromIndex(G, EntrypointNameList, OS, PreferedStyle);
221+
writeAPIFromIndex(G, EntrypointNameList, OS);
212222
}
213223

214224
} // namespace llvm_libc

libc/utils/HdrGen/PublicAPICommand.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class RecordKeeper;
2525

2626
namespace llvm_libc {
2727

28-
enum class AttributeStyle { None, Gnu, C23, Declspec };
28+
enum class AttributeStyle { Cxx11 = 0, Gnu = 1, Declspec = 2 };
2929

3030
class PublicAPICommand : public Command {
3131
private:

0 commit comments

Comments
 (0)