[clang] [Multilib] Custom flags YAML parsing (PR #110657)
Victor Campos via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 4 05:28:38 PST 2024
https://github.com/vhscampos updated https://github.com/llvm/llvm-project/pull/110657
>From e194bdad39ea7f719e1a133eca94f9ce6ef3e881 Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Thu, 26 Sep 2024 14:43:18 +0100
Subject: [PATCH 1/2] [Multilib] Custom flags YAML parsing
This patch adds support for custom flags in the multilib YAML file.
Details about this change can be found in:
https://discourse.llvm.org/t/rfc-multilib-custom-flags/81058
CustomFlagDeclaration objects are instantiated using shared_ptr. This is
motivated by the fact that each custom flag value,
CustomFlagValueDetail, contains a back reference to their corresponding
flag declaration.
Since the CustomFlagDeclaration objects are transferred from the YAML
parser to the MultilibSet instance after the parsing is finished, back
references implemented as raw pointers would become dangling. This would
need to be remediated in the copy/move constructors by updating the
pointer.
Therefore it's just simpler and less error-prone to have all references
to CustomFlagDeclaration, including the back reference, as shared_ptr.
This way dangling pointers are not a concern.
---
clang/include/clang/Driver/Multilib.h | 30 +++-
clang/lib/Driver/Multilib.cpp | 80 +++++++++--
...remetal-multilib-custom-flags-parsing.yaml | 133 ++++++++++++++++++
3 files changed, 230 insertions(+), 13 deletions(-)
create mode 100644 clang/test/Driver/baremetal-multilib-custom-flags-parsing.yaml
diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h
index dbed70f4f9008f..333b1d2b555bd9 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -101,6 +101,25 @@ class Multilib {
raw_ostream &operator<<(raw_ostream &OS, const Multilib &M);
+namespace custom_flag {
+struct CustomFlagDeclaration;
+using CustomFlagDeclarationPtr = std::shared_ptr<CustomFlagDeclaration>;
+
+struct CustomFlagValueDetail {
+ std::string Name;
+ std::optional<SmallVector<std::string>> ExtraBuildArgs;
+ CustomFlagDeclarationPtr Decl;
+};
+
+struct CustomFlagDeclaration {
+ std::string Name;
+ SmallVector<CustomFlagValueDetail> ValueList;
+ size_t DefaultValueIdx = ~0UL;
+};
+
+static constexpr StringRef Prefix = "-fmultilib-flag=";
+} // namespace custom_flag
+
/// See also MultilibSetBuilder for combining multilibs into a set.
class MultilibSet {
public:
@@ -120,15 +139,18 @@ class MultilibSet {
private:
multilib_list Multilibs;
- std::vector<FlagMatcher> FlagMatchers;
+ SmallVector<FlagMatcher> FlagMatchers;
+ SmallVector<custom_flag::CustomFlagDeclarationPtr> CustomFlagDecls;
IncludeDirsFunc IncludeCallback;
IncludeDirsFunc FilePathsCallback;
public:
MultilibSet() = default;
- MultilibSet(multilib_list &&Multilibs,
- std::vector<FlagMatcher> &&FlagMatchers = {})
- : Multilibs(Multilibs), FlagMatchers(FlagMatchers) {}
+ MultilibSet(
+ multilib_list &&Multilibs, SmallVector<FlagMatcher> &&FlagMatchers = {},
+ SmallVector<custom_flag::CustomFlagDeclarationPtr> &&CustomFlagDecls = {})
+ : Multilibs(std::move(Multilibs)), FlagMatchers(std::move(FlagMatchers)),
+ CustomFlagDecls(std::move(CustomFlagDecls)) {}
const multilib_list &getMultilibs() { return Multilibs; }
diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp
index c56417c6f6d0b0..81fe97517b0f91 100644
--- a/clang/lib/Driver/Multilib.cpp
+++ b/clang/lib/Driver/Multilib.cpp
@@ -11,7 +11,7 @@
#include "clang/Basic/Version.h"
#include "clang/Driver/Driver.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
@@ -205,13 +205,20 @@ struct MultilibGroupSerialization {
struct MultilibSetSerialization {
llvm::VersionTuple MultilibVersion;
- std::vector<MultilibGroupSerialization> Groups;
- std::vector<MultilibSerialization> Multilibs;
- std::vector<MultilibSet::FlagMatcher> FlagMatchers;
+ SmallVector<MultilibGroupSerialization> Groups;
+ SmallVector<MultilibSerialization> Multilibs;
+ SmallVector<MultilibSet::FlagMatcher> FlagMatchers;
+ SmallVector<custom_flag::CustomFlagDeclarationPtr> CustomFlagDeclarations;
};
} // end anonymous namespace
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization)
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::FlagMatcher)
+LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::CustomFlagValueDetail)
+LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::CustomFlagDeclarationPtr)
+
template <> struct llvm::yaml::MappingTraits<MultilibSerialization> {
static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) {
io.mapOptional("Dir", V.Dir);
@@ -259,11 +266,69 @@ template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> {
}
};
+template <>
+struct llvm::yaml::MappingContextTraits<custom_flag::CustomFlagValueDetail,
+ llvm::SmallSet<std::string, 32>> {
+ static void mapping(llvm::yaml::IO &io, custom_flag::CustomFlagValueDetail &V,
+ llvm::SmallSet<std::string, 32> &) {
+ io.mapRequired("Name", V.Name);
+ io.mapOptional("ExtraBuildArgs", V.ExtraBuildArgs);
+ }
+ static std::string validate(IO &io, custom_flag::CustomFlagValueDetail &V,
+ llvm::SmallSet<std::string, 32> &NameSet) {
+ if (V.Name.empty())
+ return "custom flag value requires a name";
+ if (!NameSet.insert(V.Name).second)
+ return "duplicate custom flag value name: \"" + V.Name + "\"";
+ return {};
+ }
+};
+
+template <>
+struct llvm::yaml::MappingContextTraits<custom_flag::CustomFlagDeclarationPtr,
+ llvm::SmallSet<std::string, 32>> {
+ static void mapping(llvm::yaml::IO &io,
+ custom_flag::CustomFlagDeclarationPtr &V,
+ llvm::SmallSet<std::string, 32> &NameSet) {
+ assert(!V);
+ V = std::make_shared<custom_flag::CustomFlagDeclaration>();
+ io.mapRequired("Name", V->Name);
+ io.mapRequired("Values", V->ValueList, NameSet);
+ std::string DefaultValueName;
+ io.mapRequired("Default", DefaultValueName);
+
+ for (auto [Idx, Value] : llvm::enumerate(V->ValueList)) {
+ Value.Decl = V;
+ if (Value.Name == DefaultValueName) {
+ assert(V->DefaultValueIdx == ~0UL);
+ V->DefaultValueIdx = Idx;
+ }
+ }
+ }
+ static std::string validate(IO &io, custom_flag::CustomFlagDeclarationPtr &V,
+ llvm::SmallSet<std::string, 32> &) {
+ if (V->Name.empty())
+ return "custom flag requires a name";
+ if (V->ValueList.empty())
+ return "custom flag must have at least one value";
+ if (V->DefaultValueIdx >= V->ValueList.size())
+ return "custom flag must have a default value";
+ if (llvm::any_of(V->ValueList, [&V](const auto &Value) {
+ return !Value.Decl || Value.Decl != V;
+ }))
+ return "custom flag value missing reference to its custom flag "
+ "declaration";
+ return {};
+ }
+};
+
template <> struct llvm::yaml::MappingTraits<MultilibSetSerialization> {
static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) {
io.mapRequired("MultilibVersion", M.MultilibVersion);
io.mapRequired("Variants", M.Multilibs);
io.mapOptional("Groups", M.Groups);
+ llvm::SmallSet<std::string, 32> NameSet;
+ io.mapOptionalWithContext("Flags", M.CustomFlagDeclarations, NameSet);
io.mapOptional("Mappings", M.FlagMatchers);
}
static std::string validate(IO &io, MultilibSetSerialization &M) {
@@ -292,10 +357,6 @@ template <> struct llvm::yaml::MappingTraits<MultilibSetSerialization> {
}
};
-LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
-LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization)
-LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::FlagMatcher)
-
llvm::ErrorOr<MultilibSet>
MultilibSet::parseYaml(llvm::MemoryBufferRef Input,
llvm::SourceMgr::DiagHandlerTy DiagHandler,
@@ -323,7 +384,8 @@ MultilibSet::parseYaml(llvm::MemoryBufferRef Input,
}
}
- return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers));
+ return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers),
+ std::move(MS.CustomFlagDeclarations));
}
LLVM_DUMP_METHOD void MultilibSet::dump() const {
diff --git a/clang/test/Driver/baremetal-multilib-custom-flags-parsing.yaml b/clang/test/Driver/baremetal-multilib-custom-flags-parsing.yaml
new file mode 100644
index 00000000000000..4d751cfe7c9edd
--- /dev/null
+++ b/clang/test/Driver/baremetal-multilib-custom-flags-parsing.yaml
@@ -0,0 +1,133 @@
+# RUN: split-file %s %t
+
+# RUN: %clang --target=arm-none-eabi --multi-lib-config=%t/multilib-without-extra-build-args.yaml %s -### -o /dev/null 2>&1 \
+# RUN: | FileCheck %s
+# RUN: %clang --target=arm-none-eabi --multi-lib-config=%t/multilib-with-extra-build-args.yaml %s -### -o /dev/null 2>&1 \
+# RUN: | FileCheck %s
+# CHECK-NOT: error:
+
+# RUN: %clang --target=arm-none-eabi --multi-lib-config=%t/missing-flag-name.yaml %s -### -o /dev/null 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-MISSING-FLAG-NAME
+# CHECK-MISSING-FLAG-NAME: error: custom flag requires a name
+
+# RUN: %clang --target=arm-none-eabi --multi-lib-config=%t/missing-flag-values.yaml %s -### -o /dev/null 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-MISSING-FLAG-VALUES
+# CHECK-MISSING-FLAG-VALUES: error: custom flag must have at least one value
+
+# RUN: %clang --target=arm-none-eabi --multi-lib-config=%t/missing-flag-value-default.yaml %s -### -o /dev/null 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-MISSING-FLAG-VALUE-DEFAULT
+# CHECK-MISSING-FLAG-VALUE-DEFAULT: error: custom flag must have a default value
+
+# RUN: %clang --target=arm-none-eabi --multi-lib-config=%t/missing-flag-value-name.yaml %s -### -o /dev/null 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-MISSING-FLAG-VALUE-NAME
+# CHECK-MISSING-FLAG-VALUE-NAME: error: custom flag value requires a name
+
+# RUN: %clang --target=arm-none-eabi --multi-lib-config=%t/duplicate-flag-value-name.yaml %s -### -o /dev/null 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-DUPLICATE-FLAG-VALUE-NAME
+# CHECK-DUPLICATE-FLAG-VALUE-NAME: error: duplicate custom flag value name: "value-name"
+# CHECK-DUPLICATE-FLAG-VALUE-NAME-NEXT: - Name: value-name
+
+#--- multilib-without-extra-build-args.yaml
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: libc
+ Flags: [-fmultilib-flag=a]
+
+Flags:
+ - Name: flag
+ Values:
+ - Name: a
+ - Name: b
+ Default: a
+
+#--- multilib-with-extra-build-args.yaml
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: libc
+ Flags: [-fmultilib-flag=a]
+
+Flags:
+ - Name: flag
+ Values:
+ - Name: a
+ ExtraBuildArgs: [-DFEATURE_A]
+ - Name: b
+ ExtraBuildArgs: [-DFEATURE_B]
+ Default: a
+
+#--- missing-flag-name.yaml
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: libc
+ Flags: [-fmultilib-flag=a]
+
+Flags:
+ - Values:
+ - Name: a
+ Default: a
+
+#--- missing-flag-values.yaml
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: libc
+ Flags: [-fmultilib-flag=a]
+
+Flags:
+ - Name: flag
+ Values:
+ Default: a
+
+#--- missing-flag-value-default.yaml
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: libc
+ Flags: [-fmultilib-flag=a]
+
+Flags:
+ - Name: flag
+ Values:
+ - Name: a
+ Default:
+
+#--- missing-flag-value-name.yaml
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: libc
+ Flags: [-fmultilib-flag=a]
+
+Flags:
+ - Name: flag
+ Values:
+ - Name:
+ Default: a
+
+#--- duplicate-flag-value-name.yaml
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: libc
+ Flags: [-fmultilib-flag=value-name]
+
+Flags:
+ - Name: a
+ Values:
+ - Name: value-name
+ - Name: value-a
+ Default: value-name
+ - Name: b
+ Values:
+ - Name: value-name
+ Default: value-name
>From 78a8c8a845fdd4a0e4440f3bed03be677989aacb Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Mon, 4 Nov 2024 13:24:56 +0000
Subject: [PATCH 2/2] Addressing comments #1
---
clang/include/clang/Driver/Multilib.h | 22 ++++++++++----------
clang/lib/Driver/Multilib.cpp | 30 +++++++++++----------------
2 files changed, 23 insertions(+), 29 deletions(-)
diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h
index 333b1d2b555bd9..0662feb114c796 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -102,19 +102,19 @@ class Multilib {
raw_ostream &operator<<(raw_ostream &OS, const Multilib &M);
namespace custom_flag {
-struct CustomFlagDeclaration;
-using CustomFlagDeclarationPtr = std::shared_ptr<CustomFlagDeclaration>;
+struct Declaration;
+using DeclarationPtr = std::shared_ptr<Declaration>;
-struct CustomFlagValueDetail {
+struct ValueDetail {
std::string Name;
std::optional<SmallVector<std::string>> ExtraBuildArgs;
- CustomFlagDeclarationPtr Decl;
+ DeclarationPtr Decl;
};
-struct CustomFlagDeclaration {
+struct Declaration {
std::string Name;
- SmallVector<CustomFlagValueDetail> ValueList;
- size_t DefaultValueIdx = ~0UL;
+ SmallVector<ValueDetail> ValueList;
+ std::optional<size_t> DefaultValueIdx;
};
static constexpr StringRef Prefix = "-fmultilib-flag=";
@@ -140,15 +140,15 @@ class MultilibSet {
private:
multilib_list Multilibs;
SmallVector<FlagMatcher> FlagMatchers;
- SmallVector<custom_flag::CustomFlagDeclarationPtr> CustomFlagDecls;
+ SmallVector<custom_flag::DeclarationPtr> CustomFlagDecls;
IncludeDirsFunc IncludeCallback;
IncludeDirsFunc FilePathsCallback;
public:
MultilibSet() = default;
- MultilibSet(
- multilib_list &&Multilibs, SmallVector<FlagMatcher> &&FlagMatchers = {},
- SmallVector<custom_flag::CustomFlagDeclarationPtr> &&CustomFlagDecls = {})
+ MultilibSet(multilib_list &&Multilibs,
+ SmallVector<FlagMatcher> &&FlagMatchers = {},
+ SmallVector<custom_flag::DeclarationPtr> &&CustomFlagDecls = {})
: Multilibs(std::move(Multilibs)), FlagMatchers(std::move(FlagMatchers)),
CustomFlagDecls(std::move(CustomFlagDecls)) {}
diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp
index 81fe97517b0f91..236074478e7d84 100644
--- a/clang/lib/Driver/Multilib.cpp
+++ b/clang/lib/Driver/Multilib.cpp
@@ -208,7 +208,7 @@ struct MultilibSetSerialization {
SmallVector<MultilibGroupSerialization> Groups;
SmallVector<MultilibSerialization> Multilibs;
SmallVector<MultilibSet::FlagMatcher> FlagMatchers;
- SmallVector<custom_flag::CustomFlagDeclarationPtr> CustomFlagDeclarations;
+ SmallVector<custom_flag::DeclarationPtr> CustomFlagDeclarations;
};
} // end anonymous namespace
@@ -216,8 +216,8 @@ struct MultilibSetSerialization {
LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization)
LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::FlagMatcher)
-LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::CustomFlagValueDetail)
-LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::CustomFlagDeclarationPtr)
+LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::ValueDetail)
+LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::DeclarationPtr)
template <> struct llvm::yaml::MappingTraits<MultilibSerialization> {
static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) {
@@ -267,14 +267,14 @@ template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> {
};
template <>
-struct llvm::yaml::MappingContextTraits<custom_flag::CustomFlagValueDetail,
+struct llvm::yaml::MappingContextTraits<custom_flag::ValueDetail,
llvm::SmallSet<std::string, 32>> {
- static void mapping(llvm::yaml::IO &io, custom_flag::CustomFlagValueDetail &V,
+ static void mapping(llvm::yaml::IO &io, custom_flag::ValueDetail &V,
llvm::SmallSet<std::string, 32> &) {
io.mapRequired("Name", V.Name);
io.mapOptional("ExtraBuildArgs", V.ExtraBuildArgs);
}
- static std::string validate(IO &io, custom_flag::CustomFlagValueDetail &V,
+ static std::string validate(IO &io, custom_flag::ValueDetail &V,
llvm::SmallSet<std::string, 32> &NameSet) {
if (V.Name.empty())
return "custom flag value requires a name";
@@ -285,13 +285,12 @@ struct llvm::yaml::MappingContextTraits<custom_flag::CustomFlagValueDetail,
};
template <>
-struct llvm::yaml::MappingContextTraits<custom_flag::CustomFlagDeclarationPtr,
+struct llvm::yaml::MappingContextTraits<custom_flag::DeclarationPtr,
llvm::SmallSet<std::string, 32>> {
- static void mapping(llvm::yaml::IO &io,
- custom_flag::CustomFlagDeclarationPtr &V,
+ static void mapping(llvm::yaml::IO &io, custom_flag::DeclarationPtr &V,
llvm::SmallSet<std::string, 32> &NameSet) {
assert(!V);
- V = std::make_shared<custom_flag::CustomFlagDeclaration>();
+ V = std::make_shared<custom_flag::Declaration>();
io.mapRequired("Name", V->Name);
io.mapRequired("Values", V->ValueList, NameSet);
std::string DefaultValueName;
@@ -300,24 +299,19 @@ struct llvm::yaml::MappingContextTraits<custom_flag::CustomFlagDeclarationPtr,
for (auto [Idx, Value] : llvm::enumerate(V->ValueList)) {
Value.Decl = V;
if (Value.Name == DefaultValueName) {
- assert(V->DefaultValueIdx == ~0UL);
+ assert(!V->DefaultValueIdx);
V->DefaultValueIdx = Idx;
}
}
}
- static std::string validate(IO &io, custom_flag::CustomFlagDeclarationPtr &V,
+ static std::string validate(IO &io, custom_flag::DeclarationPtr &V,
llvm::SmallSet<std::string, 32> &) {
if (V->Name.empty())
return "custom flag requires a name";
if (V->ValueList.empty())
return "custom flag must have at least one value";
- if (V->DefaultValueIdx >= V->ValueList.size())
+ if (!V->DefaultValueIdx)
return "custom flag must have a default value";
- if (llvm::any_of(V->ValueList, [&V](const auto &Value) {
- return !Value.Decl || Value.Decl != V;
- }))
- return "custom flag value missing reference to its custom flag "
- "declaration";
return {};
}
};
More information about the cfe-commits
mailing list