https://github.com/vhscampos updated https://github.com/llvm/llvm-project/pull/110657
>From 4c9756a323f67dbe5fbdb45cf2ddb5f97adad18d Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@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 | 28 +++- clang/lib/Driver/Multilib.cpp | 73 ++++++++-- ...remetal-multilib-custom-flags-parsing.yaml | 133 ++++++++++++++++++ 3 files changed, 223 insertions(+), 11 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..69d0b9b31714ff 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 Declaration; +using DeclarationPtr = std::shared_ptr<Declaration>; + +struct ValueDetail { + std::string Name; + std::optional<SmallVector<std::string>> DriverArgs; + DeclarationPtr Decl; +}; + +struct Declaration { + std::string Name; + SmallVector<ValueDetail> ValueList; + std::optional<size_t> DefaultValueIdx; +}; + +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::DeclarationPtr> CustomFlagDecls; IncludeDirsFunc IncludeCallback; IncludeDirsFunc FilePathsCallback; public: MultilibSet() = default; MultilibSet(multilib_list &&Multilibs, - std::vector<FlagMatcher> &&FlagMatchers = {}) - : Multilibs(Multilibs), FlagMatchers(FlagMatchers) {} + SmallVector<FlagMatcher> &&FlagMatchers = {}, + SmallVector<custom_flag::DeclarationPtr> &&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 0207e0f2eb2ded..0d7d590a0eed8b 100644 --- a/clang/lib/Driver/Multilib.cpp +++ b/clang/lib/Driver/Multilib.cpp @@ -10,6 +10,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Driver/Driver.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" @@ -201,13 +202,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::DeclarationPtr> 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::ValueDetail) +LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::DeclarationPtr) + template <> struct llvm::yaml::MappingTraits<MultilibSerialization> { static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) { io.mapOptional("Dir", V.Dir); @@ -255,11 +263,63 @@ template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> { } }; +template <> +struct llvm::yaml::MappingContextTraits<custom_flag::ValueDetail, + llvm::SmallSet<std::string, 32>> { + static void mapping(llvm::yaml::IO &io, custom_flag::ValueDetail &V, + llvm::SmallSet<std::string, 32> &) { + io.mapRequired("Name", V.Name); + io.mapOptional("DriverArgs", V.DriverArgs); + } + 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"; + if (!NameSet.insert(V.Name).second) + return "duplicate custom flag value name: \"" + V.Name + "\""; + return {}; + } +}; + +template <> +struct llvm::yaml::MappingContextTraits<custom_flag::DeclarationPtr, + llvm::SmallSet<std::string, 32>> { + 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::Declaration>(); + 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); + V->DefaultValueIdx = Idx; + } + } + } + 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) + return "custom flag must have a default value"; + 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) { @@ -288,10 +348,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, @@ -319,7 +375,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..dc4d1b31a71165 --- /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 + DriverArgs: [-DFEATURE_A] + - Name: b + DriverArgs: [-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 96e089e5b075cf5376109cae6eadea9b4b9a054d Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Mon, 9 Dec 2024 09:36:52 +0000 Subject: [PATCH 2/2] Change in specification: DriverArgs now MacroDefines We've decided to restrict the driver arguments that can be specified to only macro definitions. Hence this patch adjusts the YAML parsing for that. --- clang/include/clang/Driver/Multilib.h | 2 +- clang/lib/Driver/Multilib.cpp | 2 +- .../baremetal-multilib-custom-flags-parsing.yaml | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h index 69d0b9b31714ff..1dab45c062aeec 100644 --- a/clang/include/clang/Driver/Multilib.h +++ b/clang/include/clang/Driver/Multilib.h @@ -107,7 +107,7 @@ using DeclarationPtr = std::shared_ptr<Declaration>; struct ValueDetail { std::string Name; - std::optional<SmallVector<std::string>> DriverArgs; + std::optional<SmallVector<std::string>> MacroDefines; DeclarationPtr Decl; }; diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp index 0d7d590a0eed8b..b4b5dbd1bdb5e3 100644 --- a/clang/lib/Driver/Multilib.cpp +++ b/clang/lib/Driver/Multilib.cpp @@ -269,7 +269,7 @@ struct llvm::yaml::MappingContextTraits<custom_flag::ValueDetail, static void mapping(llvm::yaml::IO &io, custom_flag::ValueDetail &V, llvm::SmallSet<std::string, 32> &) { io.mapRequired("Name", V.Name); - io.mapOptional("DriverArgs", V.DriverArgs); + io.mapOptional("MacroDefines", V.MacroDefines); } static std::string validate(IO &io, custom_flag::ValueDetail &V, llvm::SmallSet<std::string, 32> &NameSet) { diff --git a/clang/test/Driver/baremetal-multilib-custom-flags-parsing.yaml b/clang/test/Driver/baremetal-multilib-custom-flags-parsing.yaml index dc4d1b31a71165..fe6a9a8d7f1ee7 100644 --- a/clang/test/Driver/baremetal-multilib-custom-flags-parsing.yaml +++ b/clang/test/Driver/baremetal-multilib-custom-flags-parsing.yaml @@ -1,8 +1,8 @@ # 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: %clang --target=arm-none-eabi --multi-lib-config=%t/multilib-without-macro-defines.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: %clang --target=arm-none-eabi --multi-lib-config=%t/multilib-with-macro-defines.yaml %s -### -o /dev/null 2>&1 \ # RUN: | FileCheck %s # CHECK-NOT: error: @@ -27,7 +27,7 @@ # 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 +#--- multilib-without-macro-defines.yaml --- MultilibVersion: 1.0 @@ -42,7 +42,7 @@ Flags: - Name: b Default: a -#--- multilib-with-extra-build-args.yaml +#--- multilib-with-macro-defines.yaml --- MultilibVersion: 1.0 @@ -54,9 +54,9 @@ Flags: - Name: flag Values: - Name: a - DriverArgs: [-DFEATURE_A] + MacroDefines: [FEATURE_A] - Name: b - DriverArgs: [-DFEATURE_B] + MacroDefines: [FEATURE_B] Default: a #--- missing-flag-name.yaml _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits