[clang] d98ced1 - [Multilib] Custom flags YAML parsing (#110657)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 13 05:51:56 PST 2025
Author: Victor Campos
Date: 2025-01-13T13:51:52Z
New Revision: d98ced1a9d641539d5bbb287bd16378ba3f5dba9
URL: https://github.com/llvm/llvm-project/commit/d98ced1a9d641539d5bbb287bd16378ba3f5dba9
DIFF: https://github.com/llvm/llvm-project/commit/d98ced1a9d641539d5bbb287bd16378ba3f5dba9.diff
LOG: [Multilib] Custom flags YAML parsing (#110657)
This patch is the first step to extend the current multilib system to
support the selection of library variants which do not correspond to
existing command-line options.
Proposal can be found in
https://discourse.llvm.org/t/rfc-multilib-custom-flags/81058
The multilib mechanism supports libraries that target code generation or
language options such as `--target`, `-mcpu`, `-mfpu`,
`-mbranch-protection`. However, some library variants are particular to
features that do not correspond to any command-line options. Examples
include variants for multithreading and semihosting.
This work introduces a way to instruct the multilib system to consider
these features in library selection. This particular patch comprises a
new section in `multilib.yaml` to declare flags for which no option
exists. Henceforth this sort of flag will be called `custom flag` for
clarity.
The `multilib.yaml` file will have a new section called Flags which
contains the declarations of the target’s custom flags:
```yaml
Flags:
- Name: multithreaded
Values:
- Name: no-multithreaded
MacroDefines: [__SINGLE_THREAD__]
- Name: multithreaded
Default: no-multithreaded
- Name: io
Values:
- Name: io-none
- Name: io-semihosting
MacroDefines: [SEMIHOSTING]
- Name: io-linux-syscalls
MacroDefines: [LINUX_SYSCALLS, HOSTED=1]
Default: io-none
```
- Name: the name to categorize a flag.
- Values: a list of possible values.
- Default: it specifies which value this flag should take if not
specified in the command-line invocation. It must be one value from the
Values field.
Each flag Value follows this description:
- Name (required): the name of the custom flag value (string). This is
the string to be used in `-fmultilib-flag=<string>`.
- MacroDefines (optional): a list of strings to be used as macro
definitions. Each string
is fed into the driver as ``-D<string>``.
A Default value is useful to save users from specifying custom flags
that have a most commonly used value.
The namespace of flag values is common across all flags. This means that
flag values must be unique.
Added:
clang/test/Driver/baremetal-multilib-custom-flags-parsing.yaml
Modified:
clang/include/clang/Driver/Multilib.h
clang/lib/Driver/Multilib.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h
index dbed70f4f9008f..1dab45c062aeec 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>> MacroDefines;
+ 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..b4b5dbd1bdb5e3 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("MacroDefines", V.MacroDefines);
+ }
+ 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..fe6a9a8d7f1ee7
--- /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-macro-defines.yaml %s -### -o /dev/null 2>&1 \
+# RUN: | FileCheck %s
+# 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:
+
+# 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-macro-defines.yaml
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: libc
+ Flags: [-fmultilib-flag=a]
+
+Flags:
+ - Name: flag
+ Values:
+ - Name: a
+ - Name: b
+ Default: a
+
+#--- multilib-with-macro-defines.yaml
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: libc
+ Flags: [-fmultilib-flag=a]
+
+Flags:
+ - Name: flag
+ Values:
+ - Name: a
+ MacroDefines: [FEATURE_A]
+ - Name: b
+ MacroDefines: [FEATURE_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
More information about the cfe-commits
mailing list