https://github.com/vhscampos updated https://github.com/llvm/llvm-project/pull/114998
>From 16aa4a010c22288ba363e4ab680a38fe0b6a327d Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Mon, 13 Jan 2025 13:51:52 +0000 Subject: [PATCH 01/12] [Multilib] Custom flags YAML parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- clang/include/clang/Driver/Multilib.h | 33 ++++- clang/lib/Driver/Multilib.cpp | 109 ++++++++++++-- ...remetal-multilib-custom-flags-parsing.yaml | 133 ++++++++++++++++++ 3 files changed, 264 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..0a533ed2804e25 100644 --- a/clang/include/clang/Driver/Multilib.h +++ b/clang/include/clang/Driver/Multilib.h @@ -101,6 +101,30 @@ class Multilib { raw_ostream &operator<<(raw_ostream &OS, const Multilib &M); +namespace custom_flag { +struct Declaration; + +struct ValueDetail { + std::string Name; + std::optional<SmallVector<std::string>> MacroDefines; + Declaration *Decl; +}; + +struct Declaration { + std::string Name; + SmallVector<ValueDetail> ValueList; + std::optional<size_t> DefaultValueIdx; + + Declaration() = default; + Declaration(const Declaration &); + Declaration(Declaration &&); + Declaration &operator=(const Declaration &); + Declaration &operator=(Declaration &&); +}; + +static constexpr StringRef Prefix = "-fmultilib-flag="; +} // namespace custom_flag + /// See also MultilibSetBuilder for combining multilibs into a set. class MultilibSet { public: @@ -120,15 +144,18 @@ class MultilibSet { private: multilib_list Multilibs; - std::vector<FlagMatcher> FlagMatchers; + SmallVector<FlagMatcher> FlagMatchers; + SmallVector<custom_flag::Declaration> 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::Declaration> &&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..ccf747e90cb2ca 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::Declaration> 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::Declaration) + template <> struct llvm::yaml::MappingTraits<MultilibSerialization> { static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) { io.mapOptional("Dir", V.Dir); @@ -255,11 +263,61 @@ 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::Declaration, + llvm::SmallSet<std::string, 32>> { + static void mapping(llvm::yaml::IO &io, custom_flag::Declaration &V, + llvm::SmallSet<std::string, 32> &NameSet) { + 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::Declaration &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 +346,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 +373,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 { @@ -335,3 +390,41 @@ raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) { MS.print(OS); return OS; } + +namespace clang::driver::custom_flag { +Declaration::Declaration(const Declaration &Other) + : Name(Other.Name), ValueList(Other.ValueList), + DefaultValueIdx(Other.DefaultValueIdx) { + for (ValueDetail &Detail : ValueList) + Detail.Decl = this; +} + +Declaration::Declaration(Declaration &&Other) + : Name(std::move(Other.Name)), ValueList(std::move(Other.ValueList)), + DefaultValueIdx(std::move(Other.DefaultValueIdx)) { + for (ValueDetail &Detail : ValueList) + Detail.Decl = this; +} + +Declaration &Declaration::operator=(const Declaration &Other) { + if (this == &Other) + return *this; + Name = Other.Name; + ValueList = Other.ValueList; + DefaultValueIdx = Other.DefaultValueIdx; + for (ValueDetail &Detail : ValueList) + Detail.Decl = this; + return *this; +} + +Declaration &Declaration::operator=(Declaration &&Other) { + if (this == &Other) + return *this; + Name = std::move(Other.Name); + ValueList = std::move(Other.ValueList); + DefaultValueIdx = std::move(Other.DefaultValueIdx); + for (ValueDetail &Detail : ValueList) + Detail.Decl = this; + return *this; +} +} // namespace clang::driver::custom_flag 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 >From 7d36f0fd176c85bfeee7a890ab638a16ca43c44d Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Thu, 26 Sep 2024 14:44:33 +0100 Subject: [PATCH 02/12] [Multilib] Custom flags processing for library selection Select library variants in the multilib system using the flags passed following the '-fmultilib-flag=' format. Multilib flags that were not passed in the command-line have their default value fed into the library selection mechanism. A warning is shown if the flag's value name is invalid. If the wrong name is close enough to any valid one, according to edit distance, the closest valid value name is suggested. Details about this change can be found in this thread: https://discourse.llvm.org/t/rfc-multilib-custom-flags/81058 --- clang/include/clang/Driver/Driver.h | 2 +- clang/include/clang/Driver/Multilib.h | 11 +- clang/include/clang/Driver/ToolChain.h | 7 + clang/lib/Driver/Driver.cpp | 141 ++++++++++-------- clang/lib/Driver/Multilib.cpp | 136 ++++++++++++++++- clang/lib/Driver/ToolChains/BareMetal.cpp | 22 ++- clang/lib/Driver/ToolChains/BareMetal.h | 5 + .../baremetal-multilib-custom-flags.yaml | 79 ++++++++++ 8 files changed, 328 insertions(+), 75 deletions(-) create mode 100644 clang/test/Driver/baremetal-multilib-custom-flags.yaml diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 80bce574a3b647..3f29bdf2ff23f4 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -466,7 +466,7 @@ class Driver { /// ArgList. llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args, bool UseDriverMode, - bool &ContainsError); + bool &ContainsError) const; /// BuildInputs - Construct the list of inputs and their types from /// the given arguments. diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h index 0a533ed2804e25..a8cba32de84e7a 100644 --- a/clang/include/clang/Driver/Multilib.h +++ b/clang/include/clang/Driver/Multilib.h @@ -168,9 +168,18 @@ class MultilibSet { const_iterator begin() const { return Multilibs.begin(); } const_iterator end() const { return Multilibs.end(); } + /// Process custom flags from \p Flags and returns an expanded flags list and + /// a list of extra compilation arguments. + /// Returns a pair where: + /// - first: the new flags list including custom flags after processing. + /// - second: the extra compilation arguments to be fed to the driver. + std::pair<Multilib::flags_list, SmallVector<StringRef>> + processCustomFlags(const Driver &D, const Multilib::flags_list &Flags) const; + /// Select compatible variants, \returns false if none are compatible bool select(const Driver &D, const Multilib::flags_list &Flags, - llvm::SmallVectorImpl<Multilib> &) const; + llvm::SmallVectorImpl<Multilib> &, + llvm::SmallVector<StringRef> * = nullptr) const; unsigned size() const { return Multilibs.size(); } diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 701a1d25ca4c8d..17bddf0120215b 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -686,6 +686,13 @@ class ToolChain { /// Add warning options that need to be passed to cc1 for this target. virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const; + // Get the list of extra driver arguments strings requested by the multilib + // configuration. + virtual SmallVector<std::string> + getMultilibDriverArgsStr(llvm::opt::ArgList &Args) const { + return {}; + }; + // GetRuntimeLibType - Determine the runtime library type to use with the // given compilation arguments. virtual RuntimeLibType diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 9a947f32283c3a..4463f01ee052ff 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -264,7 +264,7 @@ void Driver::setDriverMode(StringRef Value) { } InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, - bool UseDriverMode, bool &ContainsError) { + bool UseDriverMode, bool &ContainsError) const { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); ContainsError = false; @@ -1397,8 +1397,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { bool HasConfigFileTail = !ContainsError && CfgOptionsTail; // All arguments, from both config file and command line. - InputArgList Args = - HasConfigFileHead ? std::move(*CfgOptionsHead) : std::move(*CLOptions); + auto UArgs = std::make_unique<InputArgList>(HasConfigFileHead ? std::move(*CfgOptionsHead) : std::move(*CLOptions)); + InputArgList &Args = *UArgs; if (HasConfigFileHead) for (auto *Opt : *CLOptions) @@ -1426,52 +1426,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { } } - // Check for working directory option before accessing any files - if (Arg *WD = Args.getLastArg(options::OPT_working_directory)) - if (VFS->setCurrentWorkingDirectory(WD->getValue())) - Diag(diag::err_drv_unable_to_set_working_directory) << WD->getValue(); - - // Check for missing include directories. - if (!Diags.isIgnored(diag::warn_missing_include_dirs, SourceLocation())) { - for (auto IncludeDir : Args.getAllArgValues(options::OPT_I_Group)) { - if (!VFS->exists(IncludeDir)) - Diag(diag::warn_missing_include_dirs) << IncludeDir; - } - } - - // FIXME: This stuff needs to go into the Compilation, not the driver. - bool CCCPrintPhases; - - // -canonical-prefixes, -no-canonical-prefixes are used very early in main. - Args.ClaimAllArgs(options::OPT_canonical_prefixes); - Args.ClaimAllArgs(options::OPT_no_canonical_prefixes); - - // f(no-)integated-cc1 is also used very early in main. - Args.ClaimAllArgs(options::OPT_fintegrated_cc1); - Args.ClaimAllArgs(options::OPT_fno_integrated_cc1); - - // Ignore -pipe. - Args.ClaimAllArgs(options::OPT_pipe); - - // Extract -ccc args. - // - // FIXME: We need to figure out where this behavior should live. Most of it - // should be outside in the client; the parts that aren't should have proper - // options, either by introducing new ones or by overloading gcc ones like -V - // or -b. - CCCPrintPhases = Args.hasArg(options::OPT_ccc_print_phases); - CCCPrintBindings = Args.hasArg(options::OPT_ccc_print_bindings); - if (const Arg *A = Args.getLastArg(options::OPT_ccc_gcc_name)) - CCCGenericGCCName = A->getValue(); - - // Process -fproc-stat-report options. - if (const Arg *A = Args.getLastArg(options::OPT_fproc_stat_report_EQ)) { - CCPrintProcessStats = true; - CCPrintStatReportFilename = A->getValue(); - } - if (Args.hasArg(options::OPT_fproc_stat_report)) - CCPrintProcessStats = true; - // FIXME: TargetTriple is used by the target-prefixed calls to as/ld // and getToolChain is const. if (IsCLMode()) { @@ -1529,6 +1483,79 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { TargetTriple = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT_ccc_install_dir)) Dir = Dir = A->getValue(); + if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) + SysRoot = A->getValue(); + if (const Arg *A = Args.getLastArg(options::OPT_resource_dir)) + ResourceDir = A->getValue(); + if (const Arg *A = Args.getLastArg(options::OPT__dyld_prefix_EQ)) + DyldPrefix = A->getValue(); + + setLTOMode(Args); + + // Owned by the host. + const ToolChain &TC = + getToolChain(Args, computeTargetTriple(*this, TargetTriple, Args)); + + SmallVector<std::string> MultilibDriverArgsStr = + TC.getMultilibDriverArgsStr(Args); + SmallVector<const char *> MLArgsChar( + llvm::map_range(MultilibDriverArgsStr, [&Args](const auto &S) { + return Args.MakeArgString(S); + })); + bool MLContainsError; + auto MultilibDriverArgList = std::make_unique<InputArgList>( + ParseArgStrings(MLArgsChar, /*UseDriverMode=*/false, MLContainsError)); + if (!MLContainsError) + for (auto *Opt : *MultilibDriverArgList) { + appendOneArg(Args, Opt, nullptr); + } + + // Check for working directory option before accessing any files + if (Arg *WD = Args.getLastArg(options::OPT_working_directory)) + if (VFS->setCurrentWorkingDirectory(WD->getValue())) + Diag(diag::err_drv_unable_to_set_working_directory) << WD->getValue(); + + // Check for missing include directories. + if (!Diags.isIgnored(diag::warn_missing_include_dirs, SourceLocation())) { + for (auto IncludeDir : Args.getAllArgValues(options::OPT_I_Group)) { + if (!VFS->exists(IncludeDir)) + Diag(diag::warn_missing_include_dirs) << IncludeDir; + } + } + + // FIXME: This stuff needs to go into the Compilation, not the driver. + bool CCCPrintPhases; + + // -canonical-prefixes, -no-canonical-prefixes are used very early in main. + Args.ClaimAllArgs(options::OPT_canonical_prefixes); + Args.ClaimAllArgs(options::OPT_no_canonical_prefixes); + + // f(no-)integated-cc1 is also used very early in main. + Args.ClaimAllArgs(options::OPT_fintegrated_cc1); + Args.ClaimAllArgs(options::OPT_fno_integrated_cc1); + + // Ignore -pipe. + Args.ClaimAllArgs(options::OPT_pipe); + + // Extract -ccc args. + // + // FIXME: We need to figure out where this behavior should live. Most of it + // should be outside in the client; the parts that aren't should have proper + // options, either by introducing new ones or by overloading gcc ones like -V + // or -b. + CCCPrintPhases = Args.hasArg(options::OPT_ccc_print_phases); + CCCPrintBindings = Args.hasArg(options::OPT_ccc_print_bindings); + if (const Arg *A = Args.getLastArg(options::OPT_ccc_gcc_name)) + CCCGenericGCCName = A->getValue(); + + // Process -fproc-stat-report options. + if (const Arg *A = Args.getLastArg(options::OPT_fproc_stat_report_EQ)) { + CCPrintProcessStats = true; + CCPrintStatReportFilename = A->getValue(); + } + if (Args.hasArg(options::OPT_fproc_stat_report)) + CCPrintProcessStats = true; + for (const Arg *A : Args.filtered(options::OPT_B)) { A->claim(); PrefixDirs.push_back(A->getValue(0)); @@ -1543,13 +1570,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { CompilerPath = Split.second; } } - if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) - SysRoot = A->getValue(); - if (const Arg *A = Args.getLastArg(options::OPT__dyld_prefix_EQ)) - DyldPrefix = A->getValue(); - - if (const Arg *A = Args.getLastArg(options::OPT_resource_dir)) - ResourceDir = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT_save_temps_EQ)) { SaveTemps = llvm::StringSwitch<SaveTempsMode>(A->getValue()) @@ -1569,8 +1589,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { Offload = OffloadHostDevice; } - setLTOMode(Args); - // Process -fembed-bitcode= flags. if (Arg *A = Args.getLastArg(options::OPT_fembed_bitcode_EQ)) { StringRef Name = A->getValue(); @@ -1624,16 +1642,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { } } - std::unique_ptr<llvm::opt::InputArgList> UArgs = - std::make_unique<InputArgList>(std::move(Args)); - // Perform the default argument translations. DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); - // Owned by the host. - const ToolChain &TC = getToolChain( - *UArgs, computeTargetTriple(*this, TargetTriple, *UArgs)); - // Check if the environment version is valid except wasm case. llvm::Triple Triple = TC.getTriple(); if (!Triple.isWasm()) { diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp index ccf747e90cb2ca..d33302850b3235 100644 --- a/clang/lib/Driver/Multilib.cpp +++ b/clang/lib/Driver/Multilib.cpp @@ -11,6 +11,7 @@ #include "clang/Driver/Driver.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" @@ -92,12 +93,141 @@ MultilibSet &MultilibSet::FilterOut(FilterCallback F) { void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } -bool MultilibSet::select(const Driver &D, const Multilib::flags_list &Flags, - llvm::SmallVectorImpl<Multilib> &Selected) const { - llvm::StringSet<> FlagSet(expandFlags(Flags)); +static void DiagnoseUnclaimedMultilibCustomFlags( + const Driver &D, const SmallVector<StringRef> &UnclaimedCustomFlagValues, + const SmallVector<custom_flag::DeclarationPtr> &CustomFlagDecls) { + struct EditDistanceInfo { + StringRef FlagValue; + unsigned EditDistance; + }; + const unsigned MaxEditDistance = 5; + + for (StringRef Unclaimed : UnclaimedCustomFlagValues) { + std::optional<EditDistanceInfo> BestCandidate; + for (const auto &Decl : CustomFlagDecls) { + for (const auto &Value : Decl->ValueList) { + const std::string &FlagValueName = Value.Name; + unsigned EditDistance = + Unclaimed.edit_distance(FlagValueName, /*AllowReplacements=*/true, + /*MaxEditDistance=*/MaxEditDistance); + if (!BestCandidate || (EditDistance <= MaxEditDistance && + EditDistance < BestCandidate->EditDistance)) { + BestCandidate = {FlagValueName, EditDistance}; + } + } + } + if (!BestCandidate) + D.Diag(clang::diag::err_drv_unsupported_opt) + << (custom_flag::Prefix + Unclaimed).str(); + else + D.Diag(clang::diag::err_drv_unsupported_opt_with_suggestion) + << (custom_flag::Prefix + Unclaimed).str() + << (custom_flag::Prefix + BestCandidate->FlagValue).str(); + } +} + +namespace clang::driver::custom_flag { +// Map implemented using linear searches as the expected size is too small for +// the overhead of a search tree or a hash table. +class ValueNameToDetailMap { + SmallVector<std::pair<StringRef, const ValueDetail *>> Mapping; + +public: + template <typename It> + ValueNameToDetailMap(It FlagDeclsBegin, It FlagDeclsEnd) { + for (auto DeclIt = FlagDeclsBegin; DeclIt != FlagDeclsEnd; ++DeclIt) { + const DeclarationPtr &Decl = *DeclIt; + for (const auto &Value : Decl->ValueList) + Mapping.emplace_back(Value.Name, &Value); + } + } + + const ValueDetail *get(StringRef Key) const { + auto Iter = llvm::find_if( + Mapping, [&](const auto &Pair) { return Pair.first == Key; }); + return Iter != Mapping.end() ? Iter->second : nullptr; + } +}; +} // namespace clang::driver::custom_flag + +std::pair<Multilib::flags_list, SmallVector<StringRef>> +MultilibSet::processCustomFlags(const Driver &D, + const Multilib::flags_list &Flags) const { + Multilib::flags_list Result; + SmallVector<StringRef> CompilationArgs; + + // Custom flag values detected in the flags list + SmallVector<const custom_flag::ValueDetail *> ClaimedCustomFlagValues; + + // Arguments to -fmultilib-flag=<arg> that don't correspond to any valid + // custom flag value. An error will be printed out for each of these. + SmallVector<StringRef> UnclaimedCustomFlagValueStrs; + + const auto ValueNameToValueDetail = custom_flag::ValueNameToDetailMap( + CustomFlagDecls.begin(), CustomFlagDecls.end()); + + for (StringRef Flag : Flags) { + if (!Flag.starts_with(custom_flag::Prefix)) { + Result.push_back(Flag.str()); + continue; + } + + StringRef CustomFlagValueStr = Flag.substr(custom_flag::Prefix.size()); + const custom_flag::ValueDetail *Detail = + ValueNameToValueDetail.get(CustomFlagValueStr); + if (Detail) + ClaimedCustomFlagValues.push_back(Detail); + else + UnclaimedCustomFlagValueStrs.push_back(CustomFlagValueStr); + } + + // Set of custom flag declarations for which a value was passed in the flags + // list. This is used to, firstly, detect multiple values for the same flag + // declaration (in this case, the last one wins), and secondly, to detect + // which declarations had no value passed in (in this case, the default value + // is selected). + llvm::SmallSet<custom_flag::DeclarationPtr, 32> TriggeredCustomFlagDecls; + + // Detect multiple values for the same flag declaration. Last one wins. + for (auto *CustomFlagValue : llvm::reverse(ClaimedCustomFlagValues)) { + if (!TriggeredCustomFlagDecls.insert(CustomFlagValue->Decl).second) + continue; + Result.push_back(std::string(custom_flag::Prefix) + CustomFlagValue->Name); + if (CustomFlagValue->DriverArgs) + CompilationArgs.append(CustomFlagValue->DriverArgs->begin(), + CustomFlagValue->DriverArgs->end()); + } + + // Detect flag declarations with no value passed in. Select default value. + for (const auto &Decl : CustomFlagDecls) { + if (TriggeredCustomFlagDecls.contains(Decl)) + continue; + custom_flag::ValueDetail &CustomFlagValue = + Decl->ValueList[*Decl->DefaultValueIdx]; + Result.push_back(std::string(custom_flag::Prefix) + CustomFlagValue.Name); + if (CustomFlagValue.DriverArgs) + CompilationArgs.append(CustomFlagValue.DriverArgs->begin(), + CustomFlagValue.DriverArgs->end()); + } + + DiagnoseUnclaimedMultilibCustomFlags(D, UnclaimedCustomFlagValueStrs, + CustomFlagDecls); + + return {Result, CompilationArgs}; +} + +bool MultilibSet::select( + const Driver &D, const Multilib::flags_list &Flags, + llvm::SmallVectorImpl<Multilib> &Selected, + llvm::SmallVector<StringRef> *CustomFlagCompilationArgs) const { + auto [FlagsWithCustom, CFCompilationArgs] = processCustomFlags(D, Flags); + llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom)); Selected.clear(); bool AnyErrors = false; + if (CustomFlagCompilationArgs) + *CustomFlagCompilationArgs = std::move(CFCompilationArgs); + // Decide which multilibs we're going to select at all. llvm::DenseSet<StringRef> ExclusiveGroupsSelected; for (const Multilib &M : llvm::reverse(Multilibs)) { diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp index eecaaa9a42930d..11282bf796e3af 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -162,9 +162,11 @@ static bool isPPCBareMetal(const llvm::Triple &Triple) { Triple.getEnvironment() == llvm::Triple::EABI; } -static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D, - StringRef MultilibPath, const ArgList &Args, - DetectedMultilibs &Result) { +static void +findMultilibsFromYAML(const ToolChain &TC, const Driver &D, + StringRef MultilibPath, const ArgList &Args, + DetectedMultilibs &Result, + SmallVector<StringRef> &CustomFlagsCompilationArgs) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = D.getVFS().getBufferForFile(MultilibPath); if (!MB) @@ -175,7 +177,8 @@ static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D, if (ErrorOrMultilibSet.getError()) return; Result.Multilibs = ErrorOrMultilibSet.get(); - if (Result.Multilibs.select(D, Flags, Result.SelectedMultilibs)) + if (Result.Multilibs.select(D, Flags, Result.SelectedMultilibs, + &CustomFlagsCompilationArgs)) return; D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " "); std::stringstream ss; @@ -234,9 +237,13 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, // If multilib.yaml is found, update sysroot so it doesn't use a target // specific suffix SysRoot = computeBaseSysRoot(D, /*IncludeTriple=*/false); - findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result); + SmallVector<StringRef> CustomFlagDriverArgs; + findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result, + CustomFlagDriverArgs); SelectedMultilibs = Result.SelectedMultilibs; Multilibs = Result.Multilibs; + MultilibDriverArgs.append(CustomFlagDriverArgs.begin(), + CustomFlagDriverArgs.end()); } else if (isRISCVBareMetal(Triple)) { if (findRISCVMultilibs(D, Triple, Args, Result)) { SelectedMultilibs = Result.SelectedMultilibs; @@ -551,3 +558,8 @@ SanitizerMask BareMetal::getSupportedSanitizers() const { } return Res; } + +SmallVector<std::string> +BareMetal::getMultilibDriverArgsStr(llvm::opt::ArgList &Args) const { + return MultilibDriverArgs; +} \ No newline at end of file diff --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h index 483b5efab5e6e2..dc61006f63c9d0 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.h +++ b/clang/lib/Driver/ToolChains/BareMetal.h @@ -70,12 +70,17 @@ class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain { std::string computeSysRoot() const override; SanitizerMask getSupportedSanitizers() const override; + SmallVector<std::string> + getMultilibDriverArgsStr(llvm::opt::ArgList &Args) const override; + private: using OrderedMultilibs = llvm::iterator_range<llvm::SmallVector<Multilib>::const_reverse_iterator>; OrderedMultilibs getOrderedMultilibs() const; std::string SysRoot; + + SmallVector<std::string> MultilibDriverArgs; }; } // namespace toolchains diff --git a/clang/test/Driver/baremetal-multilib-custom-flags.yaml b/clang/test/Driver/baremetal-multilib-custom-flags.yaml new file mode 100644 index 00000000000000..94f7838c3cd96c --- /dev/null +++ b/clang/test/Driver/baremetal-multilib-custom-flags.yaml @@ -0,0 +1,79 @@ +# RUN: %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \ +# RUN: --target=thumbv8m.main-none-eabi -mfpu=none --sysroot= \ +# RUN: | FileCheck --check-prefix=CHECK-DEFAULT %s + +# CHECK-DEFAULT: "-cc1" "-triple" "thumbv8m.main-unknown-none-eabi" +# CHECK-DEFAULT-SAME: "-internal-isystem" "[[SYSROOT:[^"]*]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/include" +# CHECK-DEFAULT-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/lib" + +# RUN: %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \ +# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -fmultilib-flag=no-multithreaded --sysroot= \ +# RUN: | FileCheck --check-prefix=CHECK-NOMULTI %s + +# CHECK-NOMULTI: "-cc1" "-triple" "thumbv8m.main-unknown-none-eabi" +# CHECK-NOMULTI-SAME: "-internal-isystem" "[[SYSROOT:[^"]*]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/include" +# CHECK-NOMULTI-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/nofp/lib" + +# RUN: %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \ +# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -fmultilib-flag=multithreaded --sysroot= \ +# RUN: | FileCheck --check-prefix=CHECK-MULTI %s + +# CHECK-MULTI: "-cc1" "-triple" "thumbv8m.main-unknown-none-eabi" +# CHECK-MULTI-SAME: "-internal-isystem" "[[SYSROOT:[^"]*]]/bin/../lib/clang-runtimes/arm-none-eabi/multithreaded/thumb/v8-m.main/nofp/include" +# CHECK-MULTI-NEXT: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/multithreaded/thumb/v8-m.main/nofp/lib" + +# RUN: not %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \ +# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -fmultilib-flag=singlethreaded -fmultilib-flag=no-io --sysroot= \ +# RUN: | FileCheck --check-prefix=CHECK-ERROR %s +# CHECK-ERROR-DAG: error: unsupported option '-fmultilib-flag=singlethreaded' +# CHECK-ERROR-DAG: error: unsupported option '-fmultilib-flag=no-io'; did you mean '-fmultilib-flag=io-none'? + +# RUN: %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \ +# RUN: --target=thumbv8m.main-none-eabi -mfpu=none -print-multi-lib --sysroot= \ +# RUN: | FileCheck --check-prefix=CHECK-PRINT-MULTI-LIB %s +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8-m.main/nofp;@-target=thumbv8m.main-unknown-none-eabi@mfpu=none@fmultilib-flag=no-multithreaded +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/multithreaded/thumb/v8-m.main/nofp;@-target=thumbv8m.main-unknown-none-eabi@mfpu=none@fmultilib-flag=multithreaded + +# RUN: %clang --target=arm-none-eabi --multi-lib-config=%s -x c %s -fmultilib-flag=no-multithreaded -### -o /dev/null 2>&1 \ +# RUN: | FileCheck --check-prefix=CHECK-DRIVERARGS-NOMULTI %s +# CHECK-DRIVERARGS-NOMULTI: "-D" "__SINGLE_THREAD__" + +# RUN: %clang --target=arm-none-eabi --multi-lib-config=%s -x c %s -fmultilib-flag=io-semihosting -### -o /dev/null 2>&1 \ +# RUN: | FileCheck --check-prefix=CHECK-DRIVERARGS-IO-SEMIHOSTING %s +# CHECK-DRIVERARGS-IO-SEMIHOSTING: "-D" "SEMIHOSTING" + +# RUN: %clang --target=arm-none-eabi --multi-lib-config=%s -x c %s -fmultilib-flag=io-linux-syscalls -### -o /dev/null 2>&1 \ +# RUN: | FileCheck --check-prefix=CHECK-DRIVERARGS-IO-LINUX %s +# CHECK-DRIVERARGS-IO-LINUX: "-U" "SEMIHOSTING" +# CHECK-DRIVERARGS-IO-LINUX-SAME: "-D" "LINUX_SYSCALLS" + +--- +MultilibVersion: 1.0 + +Groups: +- Name: stdlib + Type: Exclusive + +Variants: +- Dir: arm-none-eabi/thumb/v8-m.main/nofp + Flags: [--target=thumbv8m.main-unknown-none-eabi, -mfpu=none, -fmultilib-flag=no-multithreaded] + Group: stdlib +- Dir: arm-none-eabi/multithreaded/thumb/v8-m.main/nofp + Flags: [--target=thumbv8m.main-unknown-none-eabi, -mfpu=none, -fmultilib-flag=multithreaded] + Group: stdlib + +Flags: + - Name: multithreading + Values: + - Name: no-multithreaded + DriverArgs: [-D__SINGLE_THREAD__] + - Name: multithreaded + Default: no-multithreaded + - Name: io + Values: + - Name: io-none + - Name: io-semihosting + DriverArgs: [-DSEMIHOSTING] + - Name: io-linux-syscalls + DriverArgs: [-USEMIHOSTING, -DLINUX_SYSCALLS] + Default: io-none \ No newline at end of file >From 131a8cac8910c78df9091f8a5c5144ace013e012 Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Mon, 25 Nov 2024 13:42:47 +0000 Subject: [PATCH 03/12] Fix clang-format errors --- clang/lib/Driver/Driver.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 4463f01ee052ff..c9a0f058ed9691 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -264,7 +264,8 @@ void Driver::setDriverMode(StringRef Value) { } InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, - bool UseDriverMode, bool &ContainsError) const { + bool UseDriverMode, + bool &ContainsError) const { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); ContainsError = false; @@ -1397,7 +1398,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { bool HasConfigFileTail = !ContainsError && CfgOptionsTail; // All arguments, from both config file and command line. - auto UArgs = std::make_unique<InputArgList>(HasConfigFileHead ? std::move(*CfgOptionsHead) : std::move(*CLOptions)); + auto UArgs = std::make_unique<InputArgList>( + HasConfigFileHead ? std::move(*CfgOptionsHead) : std::move(*CLOptions)); InputArgList &Args = *UArgs; if (HasConfigFileHead) >From 403ee8c40fa4e0cda2b2edc5b4fd688ae3f7ab5f Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Mon, 25 Nov 2024 15:50:01 +0000 Subject: [PATCH 04/12] Disable test on Windows The expected output is reliant on the syntax of file hierarchy. This varies significantly between Linux and Windows. Following what other multilib tests do, I am disabling the test on Windows. --- clang/test/Driver/baremetal-multilib-custom-flags.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/test/Driver/baremetal-multilib-custom-flags.yaml b/clang/test/Driver/baremetal-multilib-custom-flags.yaml index 94f7838c3cd96c..c44096e199a560 100644 --- a/clang/test/Driver/baremetal-multilib-custom-flags.yaml +++ b/clang/test/Driver/baremetal-multilib-custom-flags.yaml @@ -1,3 +1,5 @@ +# UNSUPPORTED: system-windows + # RUN: %clang --multi-lib-config=%s -no-canonical-prefixes -x c %s -### -o /dev/null 2>&1 \ # RUN: --target=thumbv8m.main-none-eabi -mfpu=none --sysroot= \ # RUN: | FileCheck --check-prefix=CHECK-DEFAULT %s >From aa46b7b15d63f2a83dc45ccea1deb9204c94449e Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Mon, 9 Dec 2024 10:19:48 +0000 Subject: [PATCH 05/12] Repurpose DriverArgs to MacroDefines --- clang/include/clang/Driver/Multilib.h | 4 +- clang/include/clang/Driver/ToolChain.h | 4 +- clang/lib/Driver/Driver.cpp | 157 +++++++++--------- clang/lib/Driver/Multilib.cpp | 24 +-- clang/lib/Driver/ToolChains/BareMetal.cpp | 18 +- clang/lib/Driver/ToolChains/BareMetal.h | 4 +- .../baremetal-multilib-custom-flags.yaml | 20 +-- 7 files changed, 118 insertions(+), 113 deletions(-) diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h index a8cba32de84e7a..fc071ef48ca0f9 100644 --- a/clang/include/clang/Driver/Multilib.h +++ b/clang/include/clang/Driver/Multilib.h @@ -169,10 +169,10 @@ class MultilibSet { const_iterator end() const { return Multilibs.end(); } /// Process custom flags from \p Flags and returns an expanded flags list and - /// a list of extra compilation arguments. + /// a list of macro defines. /// Returns a pair where: /// - first: the new flags list including custom flags after processing. - /// - second: the extra compilation arguments to be fed to the driver. + /// - second: the extra macro defines to be fed to the driver. std::pair<Multilib::flags_list, SmallVector<StringRef>> processCustomFlags(const Driver &D, const Multilib::flags_list &Flags) const; diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 17bddf0120215b..7d1d8feebf35e3 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -686,10 +686,10 @@ class ToolChain { /// Add warning options that need to be passed to cc1 for this target. virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const; - // Get the list of extra driver arguments strings requested by the multilib + // Get the list of extra macro defines requested by the multilib // configuration. virtual SmallVector<std::string> - getMultilibDriverArgsStr(llvm::opt::ArgList &Args) const { + getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const { return {}; }; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index c9a0f058ed9691..24bc0e41f8f71c 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1398,9 +1398,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { bool HasConfigFileTail = !ContainsError && CfgOptionsTail; // All arguments, from both config file and command line. - auto UArgs = std::make_unique<InputArgList>( - HasConfigFileHead ? std::move(*CfgOptionsHead) : std::move(*CLOptions)); - InputArgList &Args = *UArgs; + InputArgList Args = HasConfigFileHead ? std::move(*CfgOptionsHead) : std::move(*CLOptions); if (HasConfigFileHead) for (auto *Opt : *CLOptions) @@ -1428,6 +1426,52 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { } } + // Check for working directory option before accessing any files + if (Arg *WD = Args.getLastArg(options::OPT_working_directory)) + if (VFS->setCurrentWorkingDirectory(WD->getValue())) + Diag(diag::err_drv_unable_to_set_working_directory) << WD->getValue(); + + // Check for missing include directories. + if (!Diags.isIgnored(diag::warn_missing_include_dirs, SourceLocation())) { + for (auto IncludeDir : Args.getAllArgValues(options::OPT_I_Group)) { + if (!VFS->exists(IncludeDir)) + Diag(diag::warn_missing_include_dirs) << IncludeDir; + } + } + + // FIXME: This stuff needs to go into the Compilation, not the driver. + bool CCCPrintPhases; + + // -canonical-prefixes, -no-canonical-prefixes are used very early in main. + Args.ClaimAllArgs(options::OPT_canonical_prefixes); + Args.ClaimAllArgs(options::OPT_no_canonical_prefixes); + + // f(no-)integated-cc1 is also used very early in main. + Args.ClaimAllArgs(options::OPT_fintegrated_cc1); + Args.ClaimAllArgs(options::OPT_fno_integrated_cc1); + + // Ignore -pipe. + Args.ClaimAllArgs(options::OPT_pipe); + + // Extract -ccc args. + // + // FIXME: We need to figure out where this behavior should live. Most of it + // should be outside in the client; the parts that aren't should have proper + // options, either by introducing new ones or by overloading gcc ones like -V + // or -b. + CCCPrintPhases = Args.hasArg(options::OPT_ccc_print_phases); + CCCPrintBindings = Args.hasArg(options::OPT_ccc_print_bindings); + if (const Arg *A = Args.getLastArg(options::OPT_ccc_gcc_name)) + CCCGenericGCCName = A->getValue(); + + // Process -fproc-stat-report options. + if (const Arg *A = Args.getLastArg(options::OPT_fproc_stat_report_EQ)) { + CCPrintProcessStats = true; + CCPrintStatReportFilename = A->getValue(); + } + if (Args.hasArg(options::OPT_fproc_stat_report)) + CCPrintProcessStats = true; + // FIXME: TargetTriple is used by the target-prefixed calls to as/ld // and getToolChain is const. if (IsCLMode()) { @@ -1485,79 +1529,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { TargetTriple = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT_ccc_install_dir)) Dir = Dir = A->getValue(); - if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) - SysRoot = A->getValue(); - if (const Arg *A = Args.getLastArg(options::OPT_resource_dir)) - ResourceDir = A->getValue(); - if (const Arg *A = Args.getLastArg(options::OPT__dyld_prefix_EQ)) - DyldPrefix = A->getValue(); - - setLTOMode(Args); - - // Owned by the host. - const ToolChain &TC = - getToolChain(Args, computeTargetTriple(*this, TargetTriple, Args)); - - SmallVector<std::string> MultilibDriverArgsStr = - TC.getMultilibDriverArgsStr(Args); - SmallVector<const char *> MLArgsChar( - llvm::map_range(MultilibDriverArgsStr, [&Args](const auto &S) { - return Args.MakeArgString(S); - })); - bool MLContainsError; - auto MultilibDriverArgList = std::make_unique<InputArgList>( - ParseArgStrings(MLArgsChar, /*UseDriverMode=*/false, MLContainsError)); - if (!MLContainsError) - for (auto *Opt : *MultilibDriverArgList) { - appendOneArg(Args, Opt, nullptr); - } - - // Check for working directory option before accessing any files - if (Arg *WD = Args.getLastArg(options::OPT_working_directory)) - if (VFS->setCurrentWorkingDirectory(WD->getValue())) - Diag(diag::err_drv_unable_to_set_working_directory) << WD->getValue(); - - // Check for missing include directories. - if (!Diags.isIgnored(diag::warn_missing_include_dirs, SourceLocation())) { - for (auto IncludeDir : Args.getAllArgValues(options::OPT_I_Group)) { - if (!VFS->exists(IncludeDir)) - Diag(diag::warn_missing_include_dirs) << IncludeDir; - } - } - - // FIXME: This stuff needs to go into the Compilation, not the driver. - bool CCCPrintPhases; - - // -canonical-prefixes, -no-canonical-prefixes are used very early in main. - Args.ClaimAllArgs(options::OPT_canonical_prefixes); - Args.ClaimAllArgs(options::OPT_no_canonical_prefixes); - - // f(no-)integated-cc1 is also used very early in main. - Args.ClaimAllArgs(options::OPT_fintegrated_cc1); - Args.ClaimAllArgs(options::OPT_fno_integrated_cc1); - - // Ignore -pipe. - Args.ClaimAllArgs(options::OPT_pipe); - - // Extract -ccc args. - // - // FIXME: We need to figure out where this behavior should live. Most of it - // should be outside in the client; the parts that aren't should have proper - // options, either by introducing new ones or by overloading gcc ones like -V - // or -b. - CCCPrintPhases = Args.hasArg(options::OPT_ccc_print_phases); - CCCPrintBindings = Args.hasArg(options::OPT_ccc_print_bindings); - if (const Arg *A = Args.getLastArg(options::OPT_ccc_gcc_name)) - CCCGenericGCCName = A->getValue(); - - // Process -fproc-stat-report options. - if (const Arg *A = Args.getLastArg(options::OPT_fproc_stat_report_EQ)) { - CCPrintProcessStats = true; - CCPrintStatReportFilename = A->getValue(); - } - if (Args.hasArg(options::OPT_fproc_stat_report)) - CCPrintProcessStats = true; - for (const Arg *A : Args.filtered(options::OPT_B)) { A->claim(); PrefixDirs.push_back(A->getValue(0)); @@ -1572,6 +1543,13 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { CompilerPath = Split.second; } } + if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) + SysRoot = A->getValue(); + if (const Arg *A = Args.getLastArg(options::OPT__dyld_prefix_EQ)) + DyldPrefix = A->getValue(); + + if (const Arg *A = Args.getLastArg(options::OPT_resource_dir)) + ResourceDir = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT_save_temps_EQ)) { SaveTemps = llvm::StringSwitch<SaveTempsMode>(A->getValue()) @@ -1591,6 +1569,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { Offload = OffloadHostDevice; } + setLTOMode(Args); + // Process -fembed-bitcode= flags. if (Arg *A = Args.getLastArg(options::OPT_fembed_bitcode_EQ)) { StringRef Name = A->getValue(); @@ -1644,6 +1624,31 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { } } + std::unique_ptr<llvm::opt::InputArgList> UArgs = + std::make_unique<InputArgList>(std::move(Args)); + + // Owned by the host. + const ToolChain &TC = + getToolChain(*UArgs, computeTargetTriple(*this, TargetTriple, *UArgs)); + + { + SmallVector<std::string> MultilibMacroDefinesStr = + TC.getMultilibMacroDefinesStr(*UArgs); + SmallVector<const char *> MLMacroDefinesChar( + llvm::map_range(MultilibMacroDefinesStr, [&UArgs](const auto &S) { + return UArgs->MakeArgString(Twine("-D") + Twine(S)); + })); + bool MLContainsError; + auto MultilibMacroDefineList = + std::make_unique<InputArgList>(ParseArgStrings( + MLMacroDefinesChar, /*UseDriverMode=*/false, MLContainsError)); + if (!MLContainsError) { + for (auto *Opt : *MultilibMacroDefineList) { + appendOneArg(*UArgs, Opt); + } + } + } + // Perform the default argument translations. DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp index d33302850b3235..53816aa46b4fb7 100644 --- a/clang/lib/Driver/Multilib.cpp +++ b/clang/lib/Driver/Multilib.cpp @@ -154,7 +154,7 @@ std::pair<Multilib::flags_list, SmallVector<StringRef>> MultilibSet::processCustomFlags(const Driver &D, const Multilib::flags_list &Flags) const { Multilib::flags_list Result; - SmallVector<StringRef> CompilationArgs; + SmallVector<StringRef> MacroDefines; // Custom flag values detected in the flags list SmallVector<const custom_flag::ValueDetail *> ClaimedCustomFlagValues; @@ -193,9 +193,9 @@ MultilibSet::processCustomFlags(const Driver &D, if (!TriggeredCustomFlagDecls.insert(CustomFlagValue->Decl).second) continue; Result.push_back(std::string(custom_flag::Prefix) + CustomFlagValue->Name); - if (CustomFlagValue->DriverArgs) - CompilationArgs.append(CustomFlagValue->DriverArgs->begin(), - CustomFlagValue->DriverArgs->end()); + if (CustomFlagValue->MacroDefines) + MacroDefines.append(CustomFlagValue->MacroDefines->begin(), + CustomFlagValue->MacroDefines->end()); } // Detect flag declarations with no value passed in. Select default value. @@ -205,28 +205,28 @@ MultilibSet::processCustomFlags(const Driver &D, custom_flag::ValueDetail &CustomFlagValue = Decl->ValueList[*Decl->DefaultValueIdx]; Result.push_back(std::string(custom_flag::Prefix) + CustomFlagValue.Name); - if (CustomFlagValue.DriverArgs) - CompilationArgs.append(CustomFlagValue.DriverArgs->begin(), - CustomFlagValue.DriverArgs->end()); + if (CustomFlagValue.MacroDefines) + MacroDefines.append(CustomFlagValue.MacroDefines->begin(), + CustomFlagValue.MacroDefines->end()); } DiagnoseUnclaimedMultilibCustomFlags(D, UnclaimedCustomFlagValueStrs, CustomFlagDecls); - return {Result, CompilationArgs}; + return {Result, MacroDefines}; } bool MultilibSet::select( const Driver &D, const Multilib::flags_list &Flags, llvm::SmallVectorImpl<Multilib> &Selected, - llvm::SmallVector<StringRef> *CustomFlagCompilationArgs) const { - auto [FlagsWithCustom, CFCompilationArgs] = processCustomFlags(D, Flags); + llvm::SmallVector<StringRef> *CustomFlagMacroDefines) const { + auto [FlagsWithCustom, CFMacroDefines] = processCustomFlags(D, Flags); llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom)); Selected.clear(); bool AnyErrors = false; - if (CustomFlagCompilationArgs) - *CustomFlagCompilationArgs = std::move(CFCompilationArgs); + if (CustomFlagMacroDefines) + *CustomFlagMacroDefines = std::move(CFMacroDefines); // Decide which multilibs we're going to select at all. llvm::DenseSet<StringRef> ExclusiveGroupsSelected; diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp index 11282bf796e3af..ffb1c6e34d6039 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -166,7 +166,7 @@ static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D, StringRef MultilibPath, const ArgList &Args, DetectedMultilibs &Result, - SmallVector<StringRef> &CustomFlagsCompilationArgs) { + SmallVector<StringRef> &CustomFlagsMacroDefines) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = D.getVFS().getBufferForFile(MultilibPath); if (!MB) @@ -178,7 +178,7 @@ findMultilibsFromYAML(const ToolChain &TC, const Driver &D, return; Result.Multilibs = ErrorOrMultilibSet.get(); if (Result.Multilibs.select(D, Flags, Result.SelectedMultilibs, - &CustomFlagsCompilationArgs)) + &CustomFlagsMacroDefines)) return; D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " "); std::stringstream ss; @@ -237,13 +237,13 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, // If multilib.yaml is found, update sysroot so it doesn't use a target // specific suffix SysRoot = computeBaseSysRoot(D, /*IncludeTriple=*/false); - SmallVector<StringRef> CustomFlagDriverArgs; + SmallVector<StringRef> CustomFlagMacroDefines; findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result, - CustomFlagDriverArgs); + CustomFlagMacroDefines); SelectedMultilibs = Result.SelectedMultilibs; Multilibs = Result.Multilibs; - MultilibDriverArgs.append(CustomFlagDriverArgs.begin(), - CustomFlagDriverArgs.end()); + MultilibMacroDefines.append(CustomFlagMacroDefines.begin(), + CustomFlagMacroDefines.end()); } else if (isRISCVBareMetal(Triple)) { if (findRISCVMultilibs(D, Triple, Args, Result)) { SelectedMultilibs = Result.SelectedMultilibs; @@ -560,6 +560,6 @@ SanitizerMask BareMetal::getSupportedSanitizers() const { } SmallVector<std::string> -BareMetal::getMultilibDriverArgsStr(llvm::opt::ArgList &Args) const { - return MultilibDriverArgs; -} \ No newline at end of file +BareMetal::getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const { + return MultilibMacroDefines; +} diff --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h index dc61006f63c9d0..f6295bda0a6a2e 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.h +++ b/clang/lib/Driver/ToolChains/BareMetal.h @@ -71,7 +71,7 @@ class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain { SanitizerMask getSupportedSanitizers() const override; SmallVector<std::string> - getMultilibDriverArgsStr(llvm::opt::ArgList &Args) const override; + getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const override; private: using OrderedMultilibs = @@ -80,7 +80,7 @@ class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain { std::string SysRoot; - SmallVector<std::string> MultilibDriverArgs; + SmallVector<std::string> MultilibMacroDefines; }; } // namespace toolchains diff --git a/clang/test/Driver/baremetal-multilib-custom-flags.yaml b/clang/test/Driver/baremetal-multilib-custom-flags.yaml index c44096e199a560..9c0320ea16117a 100644 --- a/clang/test/Driver/baremetal-multilib-custom-flags.yaml +++ b/clang/test/Driver/baremetal-multilib-custom-flags.yaml @@ -37,17 +37,17 @@ # CHECK-PRINT-MULTI-LIB: arm-none-eabi/multithreaded/thumb/v8-m.main/nofp;@-target=thumbv8m.main-unknown-none-eabi@mfpu=none@fmultilib-flag=multithreaded # RUN: %clang --target=arm-none-eabi --multi-lib-config=%s -x c %s -fmultilib-flag=no-multithreaded -### -o /dev/null 2>&1 \ -# RUN: | FileCheck --check-prefix=CHECK-DRIVERARGS-NOMULTI %s -# CHECK-DRIVERARGS-NOMULTI: "-D" "__SINGLE_THREAD__" +# RUN: | FileCheck --check-prefix=CHECK-MACRODEFINES-NOMULTI %s +# CHECK-MACRODEFINES-NOMULTI: "-D" "__SINGLE_THREAD__" # RUN: %clang --target=arm-none-eabi --multi-lib-config=%s -x c %s -fmultilib-flag=io-semihosting -### -o /dev/null 2>&1 \ -# RUN: | FileCheck --check-prefix=CHECK-DRIVERARGS-IO-SEMIHOSTING %s -# CHECK-DRIVERARGS-IO-SEMIHOSTING: "-D" "SEMIHOSTING" +# RUN: | FileCheck --check-prefix=CHECK-MACRODEFINES-IO-SEMIHOSTING %s +# CHECK-MACRODEFINES-IO-SEMIHOSTING: "-D" "SEMIHOSTING" # RUN: %clang --target=arm-none-eabi --multi-lib-config=%s -x c %s -fmultilib-flag=io-linux-syscalls -### -o /dev/null 2>&1 \ -# RUN: | FileCheck --check-prefix=CHECK-DRIVERARGS-IO-LINUX %s -# CHECK-DRIVERARGS-IO-LINUX: "-U" "SEMIHOSTING" -# CHECK-DRIVERARGS-IO-LINUX-SAME: "-D" "LINUX_SYSCALLS" +# RUN: | FileCheck --check-prefix=CHECK-MACRODEFINES-IO-LINUX %s +# CHECK-MACRODEFINES-IO-LINUX: "-D" "LINUX_SYSCALLS" +# CHECK-MACRODEFINES-IO-LINUX-SAME: "-D" "HOSTED" --- MultilibVersion: 1.0 @@ -68,14 +68,14 @@ Flags: - Name: multithreading Values: - Name: no-multithreaded - DriverArgs: [-D__SINGLE_THREAD__] + MacroDefines: [__SINGLE_THREAD__] - Name: multithreaded Default: no-multithreaded - Name: io Values: - Name: io-none - Name: io-semihosting - DriverArgs: [-DSEMIHOSTING] + MacroDefines: [SEMIHOSTING] - Name: io-linux-syscalls - DriverArgs: [-USEMIHOSTING, -DLINUX_SYSCALLS] + MacroDefines: [LINUX_SYSCALLS, HOSTED] Default: io-none \ No newline at end of file >From 46b830b732793f7b6129bec2f2612b54c66f9826 Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Thu, 9 Jan 2025 11:21:39 +0000 Subject: [PATCH 06/12] Add clarifying comment --- clang/lib/Driver/Multilib.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp index 53816aa46b4fb7..591547832112a8 100644 --- a/clang/lib/Driver/Multilib.cpp +++ b/clang/lib/Driver/Multilib.cpp @@ -225,6 +225,10 @@ bool MultilibSet::select( Selected.clear(); bool AnyErrors = false; + // Determining the list of macro defines depends only on the custom flags + // passed in. The library variants actually selected are not relevant in + // this. Therefore this assignment can take place before the selection + // happens. if (CustomFlagMacroDefines) *CustomFlagMacroDefines = std::move(CFMacroDefines); >From a92176634a398c667fcc515d546af86edc5ba14c Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Thu, 9 Jan 2025 11:52:52 +0000 Subject: [PATCH 07/12] Fix clang-format error --- clang/lib/Driver/Driver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 24bc0e41f8f71c..06eb6b945827ac 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1398,7 +1398,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { bool HasConfigFileTail = !ContainsError && CfgOptionsTail; // All arguments, from both config file and command line. - InputArgList Args = HasConfigFileHead ? std::move(*CfgOptionsHead) : std::move(*CLOptions); + InputArgList Args = + HasConfigFileHead ? std::move(*CfgOptionsHead) : std::move(*CLOptions); if (HasConfigFileHead) for (auto *Opt : *CLOptions) >From 71dd4c28c6ab995eb1458a5782c774d0e22e0fa9 Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Tue, 14 Jan 2025 14:00:02 +0000 Subject: [PATCH 08/12] Rewrite code for the removal of shared_ptr use --- clang/lib/Driver/Multilib.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp index 591547832112a8..ad1cc48ffc96ba 100644 --- a/clang/lib/Driver/Multilib.cpp +++ b/clang/lib/Driver/Multilib.cpp @@ -95,7 +95,7 @@ void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } static void DiagnoseUnclaimedMultilibCustomFlags( const Driver &D, const SmallVector<StringRef> &UnclaimedCustomFlagValues, - const SmallVector<custom_flag::DeclarationPtr> &CustomFlagDecls) { + const SmallVector<custom_flag::Declaration> &CustomFlagDecls) { struct EditDistanceInfo { StringRef FlagValue; unsigned EditDistance; @@ -105,7 +105,7 @@ static void DiagnoseUnclaimedMultilibCustomFlags( for (StringRef Unclaimed : UnclaimedCustomFlagValues) { std::optional<EditDistanceInfo> BestCandidate; for (const auto &Decl : CustomFlagDecls) { - for (const auto &Value : Decl->ValueList) { + for (const auto &Value : Decl.ValueList) { const std::string &FlagValueName = Value.Name; unsigned EditDistance = Unclaimed.edit_distance(FlagValueName, /*AllowReplacements=*/true, @@ -136,8 +136,8 @@ class ValueNameToDetailMap { template <typename It> ValueNameToDetailMap(It FlagDeclsBegin, It FlagDeclsEnd) { for (auto DeclIt = FlagDeclsBegin; DeclIt != FlagDeclsEnd; ++DeclIt) { - const DeclarationPtr &Decl = *DeclIt; - for (const auto &Value : Decl->ValueList) + const Declaration &Decl = *DeclIt; + for (const auto &Value : Decl.ValueList) Mapping.emplace_back(Value.Name, &Value); } } @@ -186,7 +186,7 @@ MultilibSet::processCustomFlags(const Driver &D, // declaration (in this case, the last one wins), and secondly, to detect // which declarations had no value passed in (in this case, the default value // is selected). - llvm::SmallSet<custom_flag::DeclarationPtr, 32> TriggeredCustomFlagDecls; + llvm::SmallPtrSet<custom_flag::Declaration *, 32> TriggeredCustomFlagDecls; // Detect multiple values for the same flag declaration. Last one wins. for (auto *CustomFlagValue : llvm::reverse(ClaimedCustomFlagValues)) { @@ -200,10 +200,10 @@ MultilibSet::processCustomFlags(const Driver &D, // Detect flag declarations with no value passed in. Select default value. for (const auto &Decl : CustomFlagDecls) { - if (TriggeredCustomFlagDecls.contains(Decl)) + if (TriggeredCustomFlagDecls.contains(&Decl)) continue; - custom_flag::ValueDetail &CustomFlagValue = - Decl->ValueList[*Decl->DefaultValueIdx]; + const custom_flag::ValueDetail &CustomFlagValue = + Decl.ValueList[*Decl.DefaultValueIdx]; Result.push_back(std::string(custom_flag::Prefix) + CustomFlagValue.Name); if (CustomFlagValue.MacroDefines) MacroDefines.append(CustomFlagValue.MacroDefines->begin(), >From 7fd397e918ba2663c7342bc1653c9ccbc5be9d96 Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Tue, 5 Nov 2024 14:22:06 +0000 Subject: [PATCH 09/12] Add documentation for Multilib custom flags --- clang/docs/Multilib.rst | 90 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/clang/docs/Multilib.rst b/clang/docs/Multilib.rst index 7637d0db9565b8..85cb789b9847ac 100644 --- a/clang/docs/Multilib.rst +++ b/clang/docs/Multilib.rst @@ -122,6 +122,78 @@ subclass and a suitable base multilib variant is present then the It is the responsibility of layered multilib authors to ensure that headers and libraries in each layer are complete enough to mask any incompatibilities. +Multilib custom flags +===================== + +Introduction +------------ + +The multilib mechanism supports library variants that correspond to target, +code generation or language command-line flags. Examples include ``--target``, +``-mcpu``, ``-mfpu``, ``-mbranch-protection``, ``-fno-rtti``. However, some library +variants are particular to features that do not correspond to any command-line +option. Multithreading and semihosting, for instance, have no associated +compiler option. + +In order to support the selection of variants for which no compiler option +exists, the multilib specification includes the concept of *custom flags*. +These flags have no impact on code generation and are only used in the multilib +processing. + +Multilib custom flags follow this format in the driver invocation: + +:: + + -fmultilib-flag=<value> + +They are fed into the multilib system alongside the remaining flags. + +Custom flag declarations +------------------------ + +Custom flags can be declared in the YAML file under the *Flags* section. + +.. code-block:: yaml + + Flags: + - Name: multithreaded + Values: + - Name: no-multithreaded + DriverArgs: [-D__SINGLE_THREAD__] + - Name: multithreaded + Default: no-multithreaded + +* Name: the name to categorize a flag. +* Values: a list of flag *Value*s (defined below). +* Default: it specifies the name of the value this flag should take if not + specified in the command-line invocation. It must be one value from the Values + field. + +A Default value is useful to save users from specifying custom flags that have a +most commonly used value. + +Each flag *Value* is defined as: + +* Name: name of the value. This is the string to be used in + ``-fmultilib-flag=<string>``. +* DriverArgs: a list of strings corresponding to the extra driver arguments + used to build a library variant that's in accordance to this specific custom + flag value. These arguments are fed back into the driver if this flag *Value* + is enabled. + +The namespace of flag values is common across all flags. This means that flag +value names must be unique. + +Usage of custom flags in the *Variants* specifications +------------------------------------------------------ + +Library variants should list their requirement on one or more custom flags like +they do for any other flag. Each requirement must be listed as +``-fmultilib-flag=<value>``. + +A variant that does not specify a requirement on one particular flag can be +matched against any value of that flag. + Stability ========= @@ -222,6 +294,24 @@ For a more comprehensive example see # Flags is a list of one or more strings. Flags: [--target=thumbv7m-none-eabi] + # Custom flag declarations. Each item is a different declaration. + Flags: + # Name of the flag + - Name: multithreaded + # List of custom flag values + Values: + # Name of the custom flag value. To be used in -fmultilib-flag=<string>. + - Name: no-multithreaded + # Extra driver arguments to be printed with -print-multi-lib. Useful for + # specifying extra arguments for building the the associated library + # variant(s). + DriverArgs: [-D__SINGLE_THREAD__] + - Name: multithreaded + # Default flag value. If no value for this flag declaration is used in the + # command-line, the multilib system will use this one. Must be equal to one + # of the flag value names from this flag declaration. + Default: no-multithreaded + Design principles ================= >From 27217d74b6be78263e2365ed74600953fc3f353c Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Mon, 25 Nov 2024 15:07:57 +0000 Subject: [PATCH 10/12] Fix doc build warning --- clang/docs/Multilib.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/Multilib.rst b/clang/docs/Multilib.rst index 85cb789b9847ac..48d84087dda01c 100644 --- a/clang/docs/Multilib.rst +++ b/clang/docs/Multilib.rst @@ -164,7 +164,7 @@ Custom flags can be declared in the YAML file under the *Flags* section. Default: no-multithreaded * Name: the name to categorize a flag. -* Values: a list of flag *Value*s (defined below). +* Values: a list of flag Values (defined below). * Default: it specifies the name of the value this flag should take if not specified in the command-line invocation. It must be one value from the Values field. >From 848184e96069618932d49311078cc44508e8631b Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Tue, 10 Dec 2024 11:05:53 +0000 Subject: [PATCH 11/12] Repurpose DriverArgs as MacroDefines --- clang/docs/Multilib.rst | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/clang/docs/Multilib.rst b/clang/docs/Multilib.rst index 48d84087dda01c..fe42a3c31e3eb8 100644 --- a/clang/docs/Multilib.rst +++ b/clang/docs/Multilib.rst @@ -159,7 +159,7 @@ Custom flags can be declared in the YAML file under the *Flags* section. - Name: multithreaded Values: - Name: no-multithreaded - DriverArgs: [-D__SINGLE_THREAD__] + MacroDefines: [__SINGLE_THREAD__] - Name: multithreaded Default: no-multithreaded @@ -176,10 +176,8 @@ Each flag *Value* is defined as: * Name: name of the value. This is the string to be used in ``-fmultilib-flag=<string>``. -* DriverArgs: a list of strings corresponding to the extra driver arguments - used to build a library variant that's in accordance to this specific custom - flag value. These arguments are fed back into the driver if this flag *Value* - is enabled. +* MacroDefines: a list of strings to be used as macro definitions. Each string + is fed into the driver as ``-D<string>``. The namespace of flag values is common across all flags. This means that flag value names must be unique. @@ -302,10 +300,9 @@ For a more comprehensive example see Values: # Name of the custom flag value. To be used in -fmultilib-flag=<string>. - Name: no-multithreaded - # Extra driver arguments to be printed with -print-multi-lib. Useful for - # specifying extra arguments for building the the associated library - # variant(s). - DriverArgs: [-D__SINGLE_THREAD__] + # Macro definitions. Useful for defining extra macros for building the + # associated library variant(s). + MacroDefines: [__SINGLE_THREAD__] - Name: multithreaded # Default flag value. If no value for this flag declaration is used in the # command-line, the multilib system will use this one. Must be equal to one >From fbe3c1cec704ee1902345ae97c252f8691415805 Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Wed, 8 Jan 2025 15:39:45 +0000 Subject: [PATCH 12/12] Remove misleading text about flag's default value --- clang/docs/Multilib.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/clang/docs/Multilib.rst b/clang/docs/Multilib.rst index fe42a3c31e3eb8..d36b73dce68cd9 100644 --- a/clang/docs/Multilib.rst +++ b/clang/docs/Multilib.rst @@ -169,9 +169,6 @@ Custom flags can be declared in the YAML file under the *Flags* section. specified in the command-line invocation. It must be one value from the Values field. -A Default value is useful to save users from specifying custom flags that have a -most commonly used value. - Each flag *Value* is defined as: * Name: name of the value. This is the string to be used in _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits