[llvm-branch-commits] [clang] [Multilib] Custom flags processing for library selection (PR #110659)

Victor Campos via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Jan 9 03:46:00 PST 2025


https://github.com/vhscampos updated https://github.com/llvm/llvm-project/pull/110659

>From 2fe418964fff9e03861650afb89a81ac80f1413d Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Thu, 26 Sep 2024 14:44:33 +0100
Subject: [PATCH 1/5] [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 c23d037e725bb9..80be9261ec40f7 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 1dab45c062aeec..36bdfdb6157b0b 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -163,9 +163,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 5347e29be91439..25f51b7de3e9f5 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 fb73b62cf2daed..761876b9fcc53b 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -262,7 +262,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;
 
@@ -1272,8 +1272,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)
@@ -1301,52 +1301,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()) {
@@ -1399,6 +1353,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));
@@ -1413,13 +1440,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())
@@ -1439,8 +1459,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();
@@ -1494,16 +1512,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 b4b5dbd1bdb5e3..911196eae94b1d 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 at mfpu=none at fmultilib-flag=no-multithreaded
+# CHECK-PRINT-MULTI-LIB: arm-none-eabi/multithreaded/thumb/v8-m.main/nofp;@-target=thumbv8m.main-unknown-none-eabi at mfpu=none at 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 156fa36a7683266e1e3da9600287799ba03e2fc4 Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Mon, 25 Nov 2024 13:42:47 +0000
Subject: [PATCH 2/5] 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 761876b9fcc53b..77bf036e0cdc67 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -262,7 +262,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;
 
@@ -1272,7 +1273,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 f5c6488ee60d164f5ec30ae5c2de3647908a8bef Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Mon, 25 Nov 2024 15:50:01 +0000
Subject: [PATCH 3/5] 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 414c55e0d6fd95f8f319b4fa6114adbe0165be32 Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Mon, 9 Dec 2024 10:19:48 +0000
Subject: [PATCH 4/5] 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 36bdfdb6157b0b..d9f937abd4bd1e 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -164,10 +164,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 25f51b7de3e9f5..d7e2e8c077ed97 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 77bf036e0cdc67..06fd1ff8aaeb7c 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -1273,9 +1273,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)
@@ -1303,6 +1301,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()) {
@@ -1355,79 +1399,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));
@@ -1442,6 +1413,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())
@@ -1461,6 +1439,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();
@@ -1514,6 +1494,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 911196eae94b1d..359643039e3c3c 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 at mfpu=none at 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 8a89a122d29ac7ad7370bc375a2a13e0375a929f Mon Sep 17 00:00:00 2001
From: Victor Campos <victor.campos at arm.com>
Date: Thu, 9 Jan 2025 11:21:39 +0000
Subject: [PATCH 5/5] 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 359643039e3c3c..1459d36d2b3a34 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);
 



More information about the llvm-branch-commits mailing list