[libc-commits] [libc] [libc][RFC] add support for function level attributes (PR #79891)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Wed Jan 31 06:27:54 PST 2024
https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/79891
>From 0166fde93dc1165fd0743f85a5262d5762b2c0e9 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Mon, 29 Jan 2024 14:21:25 -0500
Subject: [PATCH 1/4] [libc][RFC] add support for function level attributes
---
libc/spec/spec.td | 21 ++++++-
libc/utils/HdrGen/PublicAPICommand.cpp | 77 ++++++++++++++++++++++++--
libc/utils/HdrGen/PublicAPICommand.h | 2 +
3 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/libc/spec/spec.td b/libc/spec/spec.td
index 16abf97bf0b1c..16019fbf4fd3f 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -170,10 +170,29 @@ class ArgSpec<Type type, list<Annotation> annotations = [], string name = ""> {
string Name = name;
}
-class FunctionSpec<string name, RetValSpec return, list<ArgSpec> args> {
+class FunctionAttr {}
+class GnuFunctionAttr<string attr> : FunctionAttr {
+ string Attr = attr;
+ string Style = "gnu";
+}
+class C23FunctionAttr<string attr, string namespace> : FunctionAttr {
+ string Attr = attr;
+ string Namespace = namespace;
+ string Style = "c23";
+}
+class DeclspecFunctionAttr<string attr> : FunctionAttr {
+ string Attr = attr;
+ string Style = "declspec";
+}
+class FunctionAttrSpec<list<FunctionAttr> instances> {
+ list<FunctionAttr> Instances = instances;
+}
+
+class FunctionSpec<string name, RetValSpec return, list<ArgSpec> args, list<FunctionAttrSpec> attrs = []> {
string Name = name;
RetValSpec Return = return;
list<ArgSpec> Args = args;
+ list<FunctionAttrSpec> Attributes = attrs;
}
class ObjectSpec<string name, string type> {
diff --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp
index b1c7a072658ff..26eb14c758920 100644
--- a/libc/utils/HdrGen/PublicAPICommand.cpp
+++ b/libc/utils/HdrGen/PublicAPICommand.cpp
@@ -15,6 +15,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/TableGen/Record.h"
+#include <llvm/ADT/STLExtras.h>
// Text blocks for macro definitions and type decls can be indented to
// suit the surrounding tablegen listing. We need to dedent such blocks
@@ -49,7 +50,7 @@ namespace llvm_libc {
void writeAPIFromIndex(APIIndexer &G,
std::vector<std::string> EntrypointNameList,
- llvm::raw_ostream &OS) {
+ llvm::raw_ostream &OS, AttributeStyle PreferedStyle) {
for (auto &Pair : G.MacroDefsMap) {
const std::string &Name = Pair.first;
if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
@@ -102,6 +103,62 @@ void writeAPIFromIndex(APIIndexer &G,
llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
+ auto GetStyle = [](llvm::Record *Instance) {
+ auto Style = Instance->getValueAsString("Style");
+ if (Style == "gnu")
+ return AttributeStyle::Gnu;
+ if (Style == "c23")
+ return AttributeStyle::C23;
+ if (Style == "declspec")
+ return AttributeStyle::Declspec;
+ return AttributeStyle::None;
+ };
+
+ if (PreferedStyle != AttributeStyle::None) {
+ auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
+ llvm::SmallVector<llvm::Record *> Attrs;
+ for (auto *Attr : Attributes) {
+ auto Instances = Attr->getValueAsListOfDefs("Instances");
+ for (auto *Instance : Instances) {
+ if (GetStyle(Instance) == PreferedStyle) {
+ Attrs.push_back(Instance);
+ }
+ }
+ }
+
+ if (Attrs.size() != 0) {
+ if (PreferedStyle == AttributeStyle::Gnu) {
+ OS << "__attribute__((";
+ llvm::interleaveComma(Attrs, OS, [&](llvm::Record *Instance) {
+ OS << Instance->getValueAsString("Attr");
+ });
+ OS << ")) ";
+ }
+
+ if (PreferedStyle == AttributeStyle::C23) {
+ OS << "__attribute__((";
+ llvm::interleaveComma(Attrs, OS, [&](llvm::Record *Instance) {
+ auto Namespace = Instance->getValueAsString("Namespace");
+ if (Namespace != "")
+ OS << Namespace << "::";
+ OS << Instance->getValueAsString("Attr");
+ });
+ OS << ")) ";
+ }
+
+ if (PreferedStyle == AttributeStyle::Declspec) {
+ OS << "__declspec(";
+ llvm::interleave(
+ Attrs.begin(), Attrs.end(),
+ [&](llvm::Record *Instance) {
+ OS << Instance->getValueAsString("Attr");
+ },
+ [&]() { OS << ' '; });
+ OS << ") ";
+ }
+ }
+ }
+
OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
@@ -134,12 +191,24 @@ void PublicAPICommand::run(llvm::raw_ostream &OS, const ArgVector &Args,
llvm::StringRef StdHeader,
llvm::RecordKeeper &Records,
const Command::ErrorReporter &Reporter) const {
- if (Args.size() != 0) {
- Reporter.printFatalError("public_api command does not take any arguments.");
+ if (Args.size() > 1) {
+ Reporter.printFatalError(
+ "public_api command does not take more than one arguments.");
+ }
+
+ AttributeStyle PreferedStyle = AttributeStyle::Gnu;
+
+ for (auto &arg : Args) {
+ if (arg == "prefer-c23-attributes") {
+ PreferedStyle = AttributeStyle::C23;
+ }
+ if (arg == "prefer-no-attributes") {
+ PreferedStyle = AttributeStyle::None;
+ }
}
APIIndexer G(StdHeader, Records);
- writeAPIFromIndex(G, EntrypointNameList, OS);
+ writeAPIFromIndex(G, EntrypointNameList, OS, PreferedStyle);
}
} // namespace llvm_libc
diff --git a/libc/utils/HdrGen/PublicAPICommand.h b/libc/utils/HdrGen/PublicAPICommand.h
index fb0a7a81cf277..035e1c71f4f12 100644
--- a/libc/utils/HdrGen/PublicAPICommand.h
+++ b/libc/utils/HdrGen/PublicAPICommand.h
@@ -25,6 +25,8 @@ class RecordKeeper;
namespace llvm_libc {
+enum class AttributeStyle { None, Gnu, C23, Declspec };
+
class PublicAPICommand : public Command {
private:
const std::vector<std::string> &EntrypointNameList;
>From 9eef29083ad0ffcce341d1c9af47fad8909102ec Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Mon, 29 Jan 2024 15:05:04 -0500
Subject: [PATCH 2/4] [libc][RFC] add support for function level attributes
---
libc/spec/spec.td | 7 +-
libc/spec/stdc.td | 7 +-
libc/utils/HdrGen/PublicAPICommand.cpp | 152 +++++++++++++------------
libc/utils/HdrGen/PublicAPICommand.h | 2 +-
4 files changed, 92 insertions(+), 76 deletions(-)
diff --git a/libc/spec/spec.td b/libc/spec/spec.td
index 16019fbf4fd3f..8813f69ac3aa7 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -175,17 +175,18 @@ class GnuFunctionAttr<string attr> : FunctionAttr {
string Attr = attr;
string Style = "gnu";
}
-class C23FunctionAttr<string attr, string namespace> : FunctionAttr {
+class Cxx11FunctionAttr<string attr, string namespace> : FunctionAttr {
string Attr = attr;
string Namespace = namespace;
- string Style = "c23";
+ string Style = "cxx11";
}
class DeclspecFunctionAttr<string attr> : FunctionAttr {
string Attr = attr;
string Style = "declspec";
}
-class FunctionAttrSpec<list<FunctionAttr> instances> {
+class FunctionAttrSpec<string macro, list<FunctionAttr> instances> {
list<FunctionAttr> Instances = instances;
+ string Macro = macro;
}
class FunctionSpec<string name, RetValSpec return, list<ArgSpec> args, list<FunctionAttrSpec> attrs = []> {
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index b21f620d0766a..1951638aa55dd 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -26,6 +26,11 @@ def StdC : StandardSpec<"stdc"> {
[]
>;
+ FunctionAttrSpec ConstAttr = FunctionAttrSpec<"__LIBC_CONST_ATTR", [
+ Cxx11FunctionAttr<"const", "gnu">,
+ GnuFunctionAttr<"const">,
+ ]>;
+
HeaderSpec CType = HeaderSpec<
"ctype.h",
[], // Macros
@@ -364,7 +369,7 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"ceilf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"ceill", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
- FunctionSpec<"fabs", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
+ FunctionSpec<"fabs", RetValSpec<DoubleType>, [ArgSpec<DoubleType>], [ConstAttr]>,
FunctionSpec<"fabsf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"fabsl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
FunctionSpec<"fabsf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>]>,
diff --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp
index 26eb14c758920..d24637db0f788 100644
--- a/libc/utils/HdrGen/PublicAPICommand.cpp
+++ b/libc/utils/HdrGen/PublicAPICommand.cpp
@@ -15,6 +15,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/TableGen/Record.h"
+#include <algorithm>
#include <llvm/ADT/STLExtras.h>
// Text blocks for macro definitions and type decls can be indented to
@@ -50,7 +51,7 @@ namespace llvm_libc {
void writeAPIFromIndex(APIIndexer &G,
std::vector<std::string> EntrypointNameList,
- llvm::raw_ostream &OS, AttributeStyle PreferedStyle) {
+ llvm::raw_ostream &OS) {
for (auto &Pair : G.MacroDefsMap) {
const std::string &Name = Pair.first;
if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
@@ -88,6 +89,71 @@ void writeAPIFromIndex(APIIndexer &G,
if (G.Enumerations.size() != 0)
OS << "};\n\n";
+ // declare macros for attributes
+ llvm::DenseMap<llvm::StringRef, llvm::Record *> MacroAttr;
+ for (auto &Name : EntrypointNameList) {
+ if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) {
+ continue;
+ }
+ llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+ auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
+ for (auto *Attr : Attributes) {
+ MacroAttr[Attr->getValueAsString("Macro")] = Attr;
+ }
+ }
+
+ auto GetStyle = [](llvm::Record *Instance) {
+ auto Style = Instance->getValueAsString("Style");
+ if (Style == "cxx11")
+ return AttributeStyle::Cxx11;
+ if (Style == "gnu")
+ return AttributeStyle::Gnu;
+ return AttributeStyle::Declspec;
+ };
+
+ for (auto &[Macro, Attr] : MacroAttr) {
+ auto Instances = Attr->getValueAsListOfDefs("Instances");
+ llvm::SmallVector<std::pair<AttributeStyle, llvm::Record *>> Styles;
+ std::transform(Instances.begin(), Instances.end(),
+ std::back_inserter(Styles),
+ [&](llvm::Record *Instance)
+ -> std::pair<AttributeStyle, llvm::Record *> {
+ auto Style = GetStyle(Instance);
+ return {Style, Instance};
+ });
+ // Effectively sort on the first field
+ std::sort(Styles.begin(), Styles.end());
+ for (auto &[Style, Instance] : Styles) {
+ if (Style == AttributeStyle::Cxx11) {
+ OS << "#if !defined(" << Macro << ") && defined(__cplusplus)\n";
+ OS << "#define " << Macro << " [[";
+ auto Namespace = Instance->getValueAsString("Namespace");
+ if (Namespace != "")
+ OS << Namespace << "::";
+ OS << Instance->getValueAsString("Attr") << "]]\n";
+ OS << "#endif\n";
+ }
+ if (Style == AttributeStyle::Gnu) {
+ OS << "#if !defined(" << Macro << ") && defined(__GNUC__)\n";
+ OS << "#define " << Macro << " __attribute__((";
+ OS << Instance->getValueAsString("Attr") << "))\n";
+ OS << "#endif\n";
+ }
+ if (Style == AttributeStyle::Declspec) {
+ OS << "#if !defined(" << Macro << ") && defined(_MSC_VER)\n";
+ OS << "#define " << Macro << " __declspec(";
+ OS << Instance->getValueAsString("Attr") << ")\n";
+ OS << "#endif\n";
+ }
+ }
+ OS << "#if !defined(" << Macro << ")\n";
+ OS << "#define " << Macro << '\n';
+ OS << "#endif\n";
+ }
+
+ if (!MacroAttr.empty())
+ OS << '\n';
+
OS << "__BEGIN_C_DECLS\n\n";
for (auto &Name : EntrypointNameList) {
if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) {
@@ -103,61 +169,13 @@ void writeAPIFromIndex(APIIndexer &G,
llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
- auto GetStyle = [](llvm::Record *Instance) {
- auto Style = Instance->getValueAsString("Style");
- if (Style == "gnu")
- return AttributeStyle::Gnu;
- if (Style == "c23")
- return AttributeStyle::C23;
- if (Style == "declspec")
- return AttributeStyle::Declspec;
- return AttributeStyle::None;
- };
-
- if (PreferedStyle != AttributeStyle::None) {
- auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
- llvm::SmallVector<llvm::Record *> Attrs;
- for (auto *Attr : Attributes) {
- auto Instances = Attr->getValueAsListOfDefs("Instances");
- for (auto *Instance : Instances) {
- if (GetStyle(Instance) == PreferedStyle) {
- Attrs.push_back(Instance);
- }
- }
- }
-
- if (Attrs.size() != 0) {
- if (PreferedStyle == AttributeStyle::Gnu) {
- OS << "__attribute__((";
- llvm::interleaveComma(Attrs, OS, [&](llvm::Record *Instance) {
- OS << Instance->getValueAsString("Attr");
- });
- OS << ")) ";
- }
-
- if (PreferedStyle == AttributeStyle::C23) {
- OS << "__attribute__((";
- llvm::interleaveComma(Attrs, OS, [&](llvm::Record *Instance) {
- auto Namespace = Instance->getValueAsString("Namespace");
- if (Namespace != "")
- OS << Namespace << "::";
- OS << Instance->getValueAsString("Attr");
- });
- OS << ")) ";
- }
-
- if (PreferedStyle == AttributeStyle::Declspec) {
- OS << "__declspec(";
- llvm::interleave(
- Attrs.begin(), Attrs.end(),
- [&](llvm::Record *Instance) {
- OS << Instance->getValueAsString("Attr");
- },
- [&]() { OS << ' '; });
- OS << ") ";
- }
- }
- }
+ auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
+ llvm::interleave(
+ Attributes.begin(), Attributes.end(),
+ [&](llvm::Record *Attr) { OS << Attr->getValueAsString("Macro"); },
+ [&]() { OS << ' '; });
+ if (!Attributes.empty())
+ OS << ' ';
OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
@@ -181,6 +199,10 @@ void writeAPIFromIndex(APIIndexer &G,
OS << "extern " << Type << " " << Name << ";\n";
}
OS << "__END_C_DECLS\n";
+
+ // undef the macros
+ for (auto &[Macro, Attr] : MacroAttr)
+ OS << "\n#undef " << Macro << '\n';
}
void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}
@@ -191,24 +213,12 @@ void PublicAPICommand::run(llvm::raw_ostream &OS, const ArgVector &Args,
llvm::StringRef StdHeader,
llvm::RecordKeeper &Records,
const Command::ErrorReporter &Reporter) const {
- if (Args.size() > 1) {
- Reporter.printFatalError(
- "public_api command does not take more than one arguments.");
- }
-
- AttributeStyle PreferedStyle = AttributeStyle::Gnu;
-
- for (auto &arg : Args) {
- if (arg == "prefer-c23-attributes") {
- PreferedStyle = AttributeStyle::C23;
- }
- if (arg == "prefer-no-attributes") {
- PreferedStyle = AttributeStyle::None;
- }
+ if (Args.size() != 0) {
+ Reporter.printFatalError("public_api command does not take any arguments.");
}
APIIndexer G(StdHeader, Records);
- writeAPIFromIndex(G, EntrypointNameList, OS, PreferedStyle);
+ writeAPIFromIndex(G, EntrypointNameList, OS);
}
} // namespace llvm_libc
diff --git a/libc/utils/HdrGen/PublicAPICommand.h b/libc/utils/HdrGen/PublicAPICommand.h
index 035e1c71f4f12..72401cfe068e3 100644
--- a/libc/utils/HdrGen/PublicAPICommand.h
+++ b/libc/utils/HdrGen/PublicAPICommand.h
@@ -25,7 +25,7 @@ class RecordKeeper;
namespace llvm_libc {
-enum class AttributeStyle { None, Gnu, C23, Declspec };
+enum class AttributeStyle { Cxx11 = 0, Gnu = 1, Declspec = 2 };
class PublicAPICommand : public Command {
private:
>From 126630ef7d1871fd748b12d07e0ccaddd926b1fb Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 30 Jan 2024 09:38:49 -0500
Subject: [PATCH 3/4] add checks for namespaces
---
libc/utils/HdrGen/PublicAPICommand.cpp | 33 ++++++++++++++++++++++----
libc/utils/HdrGen/PublicAPICommand.h | 1 +
2 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp
index d24637db0f788..8ddb2ea5eaf90 100644
--- a/libc/utils/HdrGen/PublicAPICommand.cpp
+++ b/libc/utils/HdrGen/PublicAPICommand.cpp
@@ -111,6 +111,17 @@ void writeAPIFromIndex(APIIndexer &G,
return AttributeStyle::Declspec;
};
+ auto GetNamespace = [](llvm::Record *Instance) {
+ auto Namespace = Instance->getValueAsString("Namespace");
+ // Empty namespace is likely to be most standard-compliant.
+ if (Namespace == "")
+ return AttributeNamespace::None;
+ // Dispatch clang version before gnu version.
+ if (Namespace == "clang")
+ return AttributeNamespace::Clang;
+ return AttributeNamespace::Gnu;
+ };
+
for (auto &[Macro, Attr] : MacroAttr) {
auto Instances = Attr->getValueAsListOfDefs("Instances");
llvm::SmallVector<std::pair<AttributeStyle, llvm::Record *>> Styles;
@@ -122,14 +133,26 @@ void writeAPIFromIndex(APIIndexer &G,
return {Style, Instance};
});
// Effectively sort on the first field
- std::sort(Styles.begin(), Styles.end());
+ std::sort(Styles.begin(), Styles.end(), [&](auto &a, auto &b) {
+ if (a.first == AttributeStyle::Cxx11 && b.first == AttributeStyle::Cxx11)
+ return GetNamespace(a.second) < GetNamespace(b.second);
+ return a.first < b.first;
+ });
for (auto &[Style, Instance] : Styles) {
if (Style == AttributeStyle::Cxx11) {
- OS << "#if !defined(" << Macro << ") && defined(__cplusplus)\n";
+ OS << "#if !defined(" << Macro << ") && defined(__cplusplus)";
+ auto Namespace = GetNamespace(Instance);
+ if (Namespace == AttributeNamespace::Clang)
+ OS << " && defined(__clang__)\n";
+ else if (Namespace == AttributeNamespace::Gnu)
+ OS << " && defined(__GNUC__)\n";
+ else
+ OS << '\n';
OS << "#define " << Macro << " [[";
- auto Namespace = Instance->getValueAsString("Namespace");
- if (Namespace != "")
- OS << Namespace << "::";
+ if (Namespace == AttributeNamespace::Clang)
+ OS << "clang::";
+ else if (Namespace == AttributeNamespace::Gnu)
+ OS << "gnu::";
OS << Instance->getValueAsString("Attr") << "]]\n";
OS << "#endif\n";
}
diff --git a/libc/utils/HdrGen/PublicAPICommand.h b/libc/utils/HdrGen/PublicAPICommand.h
index 72401cfe068e3..41aa53e51c326 100644
--- a/libc/utils/HdrGen/PublicAPICommand.h
+++ b/libc/utils/HdrGen/PublicAPICommand.h
@@ -26,6 +26,7 @@ class RecordKeeper;
namespace llvm_libc {
enum class AttributeStyle { Cxx11 = 0, Gnu = 1, Declspec = 2 };
+enum class AttributeNamespace { None = 0, Clang = 1, Gnu = 2 };
class PublicAPICommand : public Command {
private:
>From 79419bddeacc22d5e52b27eca8c38feb3028e6e7 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 30 Jan 2024 09:40:07 -0500
Subject: [PATCH 4/4] use empty() instead of literal
---
libc/utils/HdrGen/PublicAPICommand.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp
index 8ddb2ea5eaf90..799be24ee0d8c 100644
--- a/libc/utils/HdrGen/PublicAPICommand.cpp
+++ b/libc/utils/HdrGen/PublicAPICommand.cpp
@@ -114,7 +114,7 @@ void writeAPIFromIndex(APIIndexer &G,
auto GetNamespace = [](llvm::Record *Instance) {
auto Namespace = Instance->getValueAsString("Namespace");
// Empty namespace is likely to be most standard-compliant.
- if (Namespace == "")
+ if (Namespace.empty())
return AttributeNamespace::None;
// Dispatch clang version before gnu version.
if (Namespace == "clang")
More information about the libc-commits
mailing list