[libc-commits] [libc] [libc] add support for function level attributes (PR #79891)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Mon Feb 5 06:32:42 PST 2024
https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/79891
>From 20da6728bb49ee92e6dcab890ef7ca84dcf654f5 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/8] [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 0b557c807a546..b20362855c630 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 f233699191529fccff7a80619700b62234c6aa62 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/8] [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 b20362855c630..a14668bd15e53 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 607dda7c9041f..3552ed2cc6ca4 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
@@ -366,7 +371,7 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"ceill", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
FunctionSpec<"ceilf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>]>,
- 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 61812478bc205e3566ae19971467ae4cee398202 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/8] 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 0ba87950b15a38bd24073868d67a998166d86bd5 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/8] 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")
>From 69771d89bc9f4f3c78f70dbb1124d75523ae86a0 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Wed, 31 Jan 2024 09:28:33 -0500
Subject: [PATCH 5/8] adjust include style
---
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 799be24ee0d8c..4b915a900969c 100644
--- a/libc/utils/HdrGen/PublicAPICommand.cpp
+++ b/libc/utils/HdrGen/PublicAPICommand.cpp
@@ -10,13 +10,13 @@
#include "utils/LibcTableGenUtil/APIIndexer.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#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
// suit the surrounding tablegen listing. We need to dedent such blocks
>From fba67bd12d34acc47b1fd4879d80803a25e2e873 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Wed, 31 Jan 2024 09:42:50 -0500
Subject: [PATCH 6/8] add comments
---
libc/spec/spec.td | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/libc/spec/spec.td b/libc/spec/spec.td
index a14668bd15e53..10b7f41d4b7bb 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -170,20 +170,23 @@ class ArgSpec<Type type, list<Annotation> annotations = [], string name = ""> {
string Name = name;
}
-class FunctionAttr {}
-class GnuFunctionAttr<string attr> : FunctionAttr {
- string Attr = attr;
- string Style = "gnu";
-}
-class Cxx11FunctionAttr<string attr, string namespace> : FunctionAttr {
+// The following classes are used to describe function attributes.
+// In the future, we may consider supporting parameter attributes as well.
+// https://clang.llvm.org/docs/AttributeReference.html
+class FunctionAttr<string style, string attr> {
string Attr = attr;
+ // The style of the attribute, e.g. "gnu", "cxx11", "declspec".
+ // - "gnu" is for GNU-style attributes: __attribute__((...))
+ // - "cxx11" is for C++11-style attributes: [[...]]
+ // - "declspec" is for Microsoft-style attributes: __declspec(...)
+ string Style = style;
+}
+class GnuFunctionAttr<string attr> : FunctionAttr<"gnu", attr> {}
+class Cxx11FunctionAttr<string attr, string namespace> : FunctionAttr<"cxx11", attr> {
+ // The namespace of the attribute, e.g. "gnu" or "clang".
string Namespace = namespace;
- string Style = "cxx11";
-}
-class DeclspecFunctionAttr<string attr> : FunctionAttr {
- string Attr = attr;
- string Style = "declspec";
}
+class DeclspecFunctionAttr<string attr> : FunctionAttr<"declspec", attr> {}
class FunctionAttrSpec<string macro, list<FunctionAttr> instances> {
list<FunctionAttr> Instances = instances;
string Macro = macro;
>From ff22577bb32c98d923f8a6134ba92422221ac05c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Wed, 31 Jan 2024 10:22:53 -0500
Subject: [PATCH 7/8] refactor
---
libc/utils/HdrGen/PublicAPICommand.cpp | 198 +++++++++++++++----------
1 file changed, 117 insertions(+), 81 deletions(-)
diff --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp
index 4b915a900969c..192c941d965ea 100644
--- a/libc/utils/HdrGen/PublicAPICommand.cpp
+++ b/libc/utils/HdrGen/PublicAPICommand.cpp
@@ -14,9 +14,11 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/TableGen/Record.h"
#include <algorithm>
+#include <vector>
// Text blocks for macro definitions and type decls can be indented to
// suit the surrounding tablegen listing. We need to dedent such blocks
@@ -49,99 +51,74 @@ static std::string getTypeHdrName(const std::string &Name) {
namespace llvm_libc {
-void writeAPIFromIndex(APIIndexer &G,
- std::vector<std::string> EntrypointNameList,
- llvm::raw_ostream &OS) {
- for (auto &Pair : G.MacroDefsMap) {
- const std::string &Name = Pair.first;
- if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
- llvm::PrintFatalError(Name + " not found in any standard spec.\n");
-
- llvm::Record *MacroDef = Pair.second;
- dedentAndWrite(MacroDef->getValueAsString("Defn"), OS);
-
- OS << '\n';
- }
-
- for (auto &TypeName : G.RequiredTypes) {
- if (G.TypeSpecMap.find(TypeName) == G.TypeSpecMap.end())
- llvm::PrintFatalError(TypeName + " not found in any standard spec.\n");
- OS << "#include <llvm-libc-types/" << getTypeHdrName(TypeName) << ".h>\n";
- }
- OS << '\n';
+static AttributeStyle getAttributeStyle(llvm::Record *Instance) {
+ llvm::StringRef Style = Instance->getValueAsString("Style");
+ return llvm::StringSwitch<AttributeStyle>(Style)
+ .Case("cxx11", AttributeStyle::Cxx11)
+ .Case("gnu", AttributeStyle::Gnu)
+ .Case("declspec", AttributeStyle::Declspec)
+ .Default(AttributeStyle::Gnu);
+}
- if (G.Enumerations.size() != 0)
- OS << "enum {" << '\n';
- for (const auto &Name : G.Enumerations) {
- if (G.EnumerationSpecMap.find(Name) == G.EnumerationSpecMap.end())
- llvm::PrintFatalError(
- Name + " is not listed as an enumeration in any standard spec.\n");
+static AttributeNamespace getAttributeNamespace(llvm::Record *Instance) {
+ llvm::StringRef Namespace = Instance->getValueAsString("Namespace");
+ return llvm::StringSwitch<AttributeNamespace>(Namespace)
+ .Case("clang", AttributeNamespace::Clang)
+ .Case("gnu", AttributeNamespace::Gnu)
+ .Default(AttributeNamespace::None);
+}
- llvm::Record *EnumerationSpec = G.EnumerationSpecMap[Name];
- OS << " " << EnumerationSpec->getValueAsString("Name");
- auto Value = EnumerationSpec->getValueAsString("Value");
- if (Value == "__default__") {
- OS << ",\n";
- } else {
- OS << " = " << Value << ",\n";
- }
- }
- if (G.Enumerations.size() != 0)
- OS << "};\n\n";
+using AttributeMap = llvm::DenseMap<llvm::StringRef, llvm::Record *>;
- // declare macros for attributes
+template <class SpecMap, class FuncList>
+static AttributeMap collectAttributeMacros(const SpecMap &Spec,
+ const FuncList &Funcs) {
llvm::DenseMap<llvm::StringRef, llvm::Record *> MacroAttr;
- for (auto &Name : EntrypointNameList) {
- if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) {
+ for (const auto &Name : Funcs) {
+ if (!Spec.count(Name))
continue;
- }
- llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
- auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
- for (auto *Attr : Attributes) {
+
+ llvm::Record *FunctionSpec = Spec.at(Name);
+ std::vector<llvm::Record *> Attributes =
+ FunctionSpec->getValueAsListOfDefs("Attributes");
+ for (llvm::Record *Attr : Attributes)
MacroAttr[Attr->getValueAsString("Macro")] = Attr;
- }
}
+ return MacroAttr;
+}
- 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;
- };
-
- auto GetNamespace = [](llvm::Record *Instance) {
- auto Namespace = Instance->getValueAsString("Namespace");
- // Empty namespace is likely to be most standard-compliant.
- if (Namespace.empty())
- return AttributeNamespace::None;
- // Dispatch clang version before gnu version.
- if (Namespace == "clang")
- return AttributeNamespace::Clang;
- return AttributeNamespace::Gnu;
- };
-
+static void emitAttributeMacroDecls(const AttributeMap &MacroAttr,
+ llvm::raw_ostream &OS) {
for (auto &[Macro, Attr] : MacroAttr) {
- auto Instances = Attr->getValueAsListOfDefs("Instances");
+ std::vector<llvm::Record *> 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);
+ auto Style = getAttributeStyle(Instance);
return {Style, Instance};
});
- // Effectively sort on the first field
+ // 1. If __cplusplus is defined and cxx11 style is provided, define the
+ // macro using cxx11 version with the following priority:
+ // 1a. If the attribute is a clang attribute, check for __clang__.
+ // 2b. If the attribute is a gnu attribute, check for __GNUC__.
+ // 2. Otherwise, if __GNUC__ is defined and gnu
+ // style is provided, define the macro using gnu version;
+ // 3. Otherwise, if _MSC_VER is defined and __declspec is provided, define
+ // the macro using __declspec version;
+ // 4. Fallback to empty macro.
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 getAttributeNamespace(a.second) <
+ getAttributeNamespace(b.second);
return a.first < b.first;
});
for (auto &[Style, Instance] : Styles) {
if (Style == AttributeStyle::Cxx11) {
OS << "#if !defined(" << Macro << ") && defined(__cplusplus)";
- auto Namespace = GetNamespace(Instance);
+ AttributeNamespace Namespace = getAttributeNamespace(Instance);
if (Namespace == AttributeNamespace::Clang)
OS << " && defined(__clang__)\n";
else if (Namespace == AttributeNamespace::Gnu)
@@ -176,6 +153,72 @@ void writeAPIFromIndex(APIIndexer &G,
if (!MacroAttr.empty())
OS << '\n';
+}
+
+static void emitAttributeMacroForFunction(const llvm::Record *FunctionSpec,
+ llvm::raw_ostream &OS) {
+ std::vector<llvm::Record *> Attributes =
+ FunctionSpec->getValueAsListOfDefs("Attributes");
+ llvm::interleave(
+ Attributes.begin(), Attributes.end(),
+ [&](llvm::Record *Attr) { OS << Attr->getValueAsString("Macro"); },
+ [&]() { OS << ' '; });
+ if (!Attributes.empty())
+ OS << ' ';
+}
+
+static void emitUndefsForAttributeMacros(const AttributeMap &MacroAttr,
+ llvm::raw_ostream &OS) {
+ if (!MacroAttr.empty())
+ OS << '\n';
+ for (auto &[Macro, Attr] : MacroAttr)
+ OS << "#undef " << Macro << '\n';
+}
+
+static void writeAPIFromIndex(APIIndexer &G,
+ std::vector<std::string> EntrypointNameList,
+ llvm::raw_ostream &OS) {
+ for (auto &Pair : G.MacroDefsMap) {
+ const std::string &Name = Pair.first;
+ if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
+ llvm::PrintFatalError(Name + " not found in any standard spec.\n");
+
+ llvm::Record *MacroDef = Pair.second;
+ dedentAndWrite(MacroDef->getValueAsString("Defn"), OS);
+
+ OS << '\n';
+ }
+
+ for (auto &TypeName : G.RequiredTypes) {
+ if (G.TypeSpecMap.find(TypeName) == G.TypeSpecMap.end())
+ llvm::PrintFatalError(TypeName + " not found in any standard spec.\n");
+ OS << "#include <llvm-libc-types/" << getTypeHdrName(TypeName) << ".h>\n";
+ }
+ OS << '\n';
+
+ if (G.Enumerations.size() != 0)
+ OS << "enum {" << '\n';
+ for (const auto &Name : G.Enumerations) {
+ if (!G.EnumerationSpecMap.count(Name))
+ llvm::PrintFatalError(
+ Name + " is not listed as an enumeration in any standard spec.\n");
+
+ llvm::Record *EnumerationSpec = G.EnumerationSpecMap[Name];
+ OS << " " << EnumerationSpec->getValueAsString("Name");
+ auto Value = EnumerationSpec->getValueAsString("Value");
+ if (Value == "__default__") {
+ OS << ",\n";
+ } else {
+ OS << " = " << Value << ",\n";
+ }
+ }
+ if (G.Enumerations.size() != 0)
+ OS << "};\n\n";
+
+ // Collect and declare macros for attributes
+ AttributeMap MacroAttr =
+ collectAttributeMacros(G.FunctionSpecMap, EntrypointNameList);
+ emitAttributeMacroDecls(MacroAttr, OS);
OS << "__BEGIN_C_DECLS\n\n";
for (auto &Name : EntrypointNameList) {
@@ -192,14 +235,8 @@ void writeAPIFromIndex(APIIndexer &G,
llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
- auto Attributes = FunctionSpec->getValueAsListOfDefs("Attributes");
- llvm::interleave(
- Attributes.begin(), Attributes.end(),
- [&](llvm::Record *Attr) { OS << Attr->getValueAsString("Macro"); },
- [&]() { OS << ' '; });
- if (!Attributes.empty())
- OS << ' ';
-
+ // Emit attribute macros for the function. Space is automatically added.
+ emitAttributeMacroForFunction(FunctionSpec, OS);
OS << G.getTypeAsString(ReturnType) << " " << Name << "(";
auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args");
@@ -223,9 +260,8 @@ void writeAPIFromIndex(APIIndexer &G,
}
OS << "__END_C_DECLS\n";
- // undef the macros
- for (auto &[Macro, Attr] : MacroAttr)
- OS << "\n#undef " << Macro << '\n';
+ // Undef file-level attribute macros.
+ emitUndefsForAttributeMacros(MacroAttr, OS);
}
void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}
>From c3138d0b1a66f92c47f4a83789d35fd36aa74f9a Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Mon, 5 Feb 2024 09:32:15 -0500
Subject: [PATCH 8/8] more clean up
---
libc/utils/HdrGen/PublicAPICommand.cpp | 37 ++++++++++++++------------
1 file changed, 20 insertions(+), 17 deletions(-)
diff --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp
index 192c941d965ea..4a49d715b0583 100644
--- a/libc/utils/HdrGen/PublicAPICommand.cpp
+++ b/libc/utils/HdrGen/PublicAPICommand.cpp
@@ -75,10 +75,11 @@ static AttributeMap collectAttributeMacros(const SpecMap &Spec,
const FuncList &Funcs) {
llvm::DenseMap<llvm::StringRef, llvm::Record *> MacroAttr;
for (const auto &Name : Funcs) {
- if (!Spec.count(Name))
+ auto Iter = Spec.find(Name);
+ if (Iter == Spec.end())
continue;
- llvm::Record *FunctionSpec = Spec.at(Name);
+ llvm::Record *FunctionSpec = Iter->second;
std::vector<llvm::Record *> Attributes =
FunctionSpec->getValueAsListOfDefs("Attributes");
for (llvm::Record *Attr : Attributes)
@@ -180,7 +181,7 @@ static void writeAPIFromIndex(APIIndexer &G,
llvm::raw_ostream &OS) {
for (auto &Pair : G.MacroDefsMap) {
const std::string &Name = Pair.first;
- if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end())
+ if (!G.MacroSpecMap.count(Name))
llvm::PrintFatalError(Name + " not found in any standard spec.\n");
llvm::Record *MacroDef = Pair.second;
@@ -190,7 +191,7 @@ static void writeAPIFromIndex(APIIndexer &G,
}
for (auto &TypeName : G.RequiredTypes) {
- if (G.TypeSpecMap.find(TypeName) == G.TypeSpecMap.end())
+ if (!G.TypeSpecMap.count(TypeName))
llvm::PrintFatalError(TypeName + " not found in any standard spec.\n");
OS << "#include <llvm-libc-types/" << getTypeHdrName(TypeName) << ".h>\n";
}
@@ -222,16 +223,18 @@ static void writeAPIFromIndex(APIIndexer &G,
OS << "__BEGIN_C_DECLS\n\n";
for (auto &Name : EntrypointNameList) {
- if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) {
- continue; // Functions that aren't in this header file are skipped as
- // opposed to erroring out because the list of functions being
- // iterated over is the complete list of functions with
- // entrypoints. Thus this is filtering out the functions that
- // don't go to this header file, whereas the other, similar
- // conditionals above are more of a sanity check.
- }
+ auto Iter = G.FunctionSpecMap.find(Name);
+
+ // Functions that aren't in this header file are skipped as
+ // opposed to erroring out because the list of functions being
+ // iterated over is the complete list of functions with
+ // entrypoints. Thus this is filtering out the functions that
+ // don't go to this header file, whereas the other, similar
+ // conditionals above are more of a sanity check.
+ if (Iter == G.FunctionSpecMap.end())
+ continue;
- llvm::Record *FunctionSpec = G.FunctionSpecMap[Name];
+ llvm::Record *FunctionSpec = Iter->second;
llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return");
llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType");
@@ -252,9 +255,10 @@ static void writeAPIFromIndex(APIIndexer &G,
// Make another pass over entrypoints to emit object declarations.
for (const auto &Name : EntrypointNameList) {
- if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
+ auto Iter = G.ObjectSpecMap.find(Name);
+ if (Iter == G.ObjectSpecMap.end())
continue;
- llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
+ llvm::Record *ObjectSpec = Iter->second;
auto Type = ObjectSpec->getValueAsString("Type");
OS << "extern " << Type << " " << Name << ";\n";
}
@@ -272,9 +276,8 @@ 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) {
+ if (Args.size() != 0)
Reporter.printFatalError("public_api command does not take any arguments.");
- }
APIIndexer G(StdHeader, Records);
writeAPIFromIndex(G, EntrypointNameList, OS);
More information about the libc-commits
mailing list