[clang] 4794bda - [Driver] Multilib YAML parsing

Michael Platings via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 13 22:47:19 PDT 2023


Author: Michael Platings
Date: 2023-06-14T06:46:40+01:00
New Revision: 4794bdab7aed92e699db29e031bfe71f4005326f

URL: https://github.com/llvm/llvm-project/commit/4794bdab7aed92e699db29e031bfe71f4005326f
DIFF: https://github.com/llvm/llvm-project/commit/4794bdab7aed92e699db29e031bfe71f4005326f.diff

LOG: [Driver] Multilib YAML parsing

The format includes a ClangMinimumVersion entry to avoid a potential
source of subtle errors if an older version of Clang were to be used
with a multilib.yaml that requires a newer Clang to work correctly.
This feature is comparable to CMake's cmake_minimum_required.

Reviewed By: peter.smith

Differential Revision: https://reviews.llvm.org/D142932

Added: 
    

Modified: 
    clang/include/clang/Driver/Multilib.h
    clang/lib/Driver/Multilib.cpp
    clang/unittests/Driver/MultilibTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h
index bf284e26f9dad..493be70cfc35b 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -13,7 +13,9 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Support/SourceMgr.h"
 #include <cassert>
 #include <functional>
 #include <string>
@@ -83,14 +85,25 @@ class MultilibSet {
       std::function<std::vector<std::string>(const Multilib &M)>;
   using FilterCallback = llvm::function_ref<bool(const Multilib &)>;
 
+  /// Uses regular expressions to simplify flags used for multilib selection.
+  /// For example, we may wish both -mfloat-abi=soft and -mfloat-abi=softfp to
+  /// be treated as -mfloat-abi=soft.
+  struct FlagMatcher {
+    std::string Match;
+    std::vector<std::string> Flags;
+  };
+
 private:
   multilib_list Multilibs;
+  std::vector<FlagMatcher> FlagMatchers;
   IncludeDirsFunc IncludeCallback;
   IncludeDirsFunc FilePathsCallback;
 
 public:
   MultilibSet() = default;
-  MultilibSet(multilib_list &&Multilibs) : Multilibs(Multilibs) {}
+  MultilibSet(multilib_list &&Multilibs,
+              std::vector<FlagMatcher> &&FlagMatchers = {})
+      : Multilibs(Multilibs), FlagMatchers(FlagMatchers) {}
 
   const multilib_list &getMultilibs() { return Multilibs; }
 
@@ -111,6 +124,11 @@ class MultilibSet {
 
   unsigned size() const { return Multilibs.size(); }
 
+  /// Get the given flags plus flags found by matching them against the
+  /// FlagMatchers and choosing the Flags of each accordingly. The select method
+  /// calls this method so in most cases it's not necessary to call it directly.
+  llvm::StringSet<> expandFlags(const Multilib::flags_list &) const;
+
   LLVM_DUMP_METHOD void dump() const;
   void print(raw_ostream &OS) const;
 
@@ -127,6 +145,10 @@ class MultilibSet {
   }
 
   const IncludeDirsFunc &filePathsCallback() const { return FilePathsCallback; }
+
+  static llvm::ErrorOr<MultilibSet>
+  parseYaml(llvm::MemoryBufferRef, llvm::SourceMgr::DiagHandlerTy = nullptr,
+            void *DiagHandlerCtxt = nullptr);
 };
 
 raw_ostream &operator<<(raw_ostream &OS, const MultilibSet &MS);

diff  --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp
index 5336c9ec57ec9..0e988d040a4e3 100644
--- a/clang/lib/Driver/Multilib.cpp
+++ b/clang/lib/Driver/Multilib.cpp
@@ -8,14 +8,18 @@
 
 #include "clang/Driver/Multilib.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/Version.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Regex.h"
+#include "llvm/Support/VersionTuple.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 #include <cassert>
@@ -91,10 +95,7 @@ void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
 
 MultilibSet::multilib_list
 MultilibSet::select(const Multilib::flags_list &Flags) const {
-  llvm::StringSet<> FlagSet;
-  for (const auto &Flag : Flags)
-    FlagSet.insert(Flag);
-
+  llvm::StringSet<> FlagSet(expandFlags(Flags));
   multilib_list Result;
   llvm::copy_if(Multilibs, std::back_inserter(Result),
                 [&FlagSet](const Multilib &M) {
@@ -115,6 +116,121 @@ bool MultilibSet::select(const Multilib::flags_list &Flags,
   return true;
 }
 
+llvm::StringSet<>
+MultilibSet::expandFlags(const Multilib::flags_list &InFlags) const {
+  llvm::StringSet<> Result;
+  for (const auto &F : InFlags)
+    Result.insert(F);
+  for (const FlagMatcher &M : FlagMatchers) {
+    std::string RegexString(M.Match);
+
+    // Make the regular expression match the whole string.
+    if (!StringRef(M.Match).starts_with("^"))
+      RegexString.insert(RegexString.begin(), '^');
+    if (!StringRef(M.Match).ends_with("$"))
+      RegexString.push_back('$');
+
+    const llvm::Regex Regex(RegexString);
+    assert(Regex.isValid());
+    if (llvm::find_if(InFlags, [&Regex](StringRef F) {
+          return Regex.match(F);
+        }) != InFlags.end()) {
+      Result.insert(M.Flags.begin(), M.Flags.end());
+    }
+  }
+  return Result;
+}
+
+namespace {
+
+// When updating this also update MULTILIB_VERSION in MultilibTest.cpp
+static const VersionTuple MultilibVersionCurrent(1, 0);
+
+struct MultilibSerialization {
+  std::string Dir;
+  std::vector<std::string> Flags;
+};
+
+struct MultilibSetSerialization {
+  llvm::VersionTuple MultilibVersion;
+  std::vector<MultilibSerialization> Multilibs;
+  std::vector<MultilibSet::FlagMatcher> FlagMatchers;
+};
+
+} // end anonymous namespace
+
+template <> struct llvm::yaml::MappingTraits<MultilibSerialization> {
+  static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) {
+    io.mapRequired("Dir", V.Dir);
+    io.mapRequired("Flags", V.Flags);
+  }
+  static std::string validate(IO &io, MultilibSerialization &V) {
+    if (StringRef(V.Dir).starts_with("/"))
+      return "paths must be relative but \"" + V.Dir + "\" starts with \"/\"";
+    return std::string{};
+  }
+};
+
+template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> {
+  static void mapping(llvm::yaml::IO &io, MultilibSet::FlagMatcher &M) {
+    io.mapRequired("Match", M.Match);
+    io.mapRequired("Flags", M.Flags);
+  }
+  static std::string validate(IO &io, MultilibSet::FlagMatcher &M) {
+    llvm::Regex Regex(M.Match);
+    std::string RegexError;
+    if (!Regex.isValid(RegexError))
+      return RegexError;
+    if (M.Flags.empty())
+      return "value required for 'Flags'";
+    return std::string{};
+  }
+};
+
+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("Mappings", M.FlagMatchers);
+  }
+  static std::string validate(IO &io, MultilibSetSerialization &M) {
+    if (M.MultilibVersion.empty())
+      return "missing required key 'MultilibVersion'";
+    if (M.MultilibVersion.getMajor() != MultilibVersionCurrent.getMajor())
+      return "multilib version " + M.MultilibVersion.getAsString() +
+             " is unsupported";
+    if (M.MultilibVersion.getMinor() > MultilibVersionCurrent.getMinor())
+      return "multilib version " + M.MultilibVersion.getAsString() +
+             " is unsupported";
+    return std::string{};
+  }
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::FlagMatcher)
+
+llvm::ErrorOr<MultilibSet>
+MultilibSet::parseYaml(llvm::MemoryBufferRef Input,
+                       llvm::SourceMgr::DiagHandlerTy DiagHandler,
+                       void *DiagHandlerCtxt) {
+  MultilibSetSerialization MS;
+  llvm::yaml::Input YamlInput(Input, nullptr, DiagHandler, DiagHandlerCtxt);
+  YamlInput >> MS;
+  if (YamlInput.error())
+    return YamlInput.error();
+
+  multilib_list Multilibs;
+  Multilibs.reserve(MS.Multilibs.size());
+  for (const auto &M : MS.Multilibs) {
+    std::string Dir;
+    if (M.Dir != ".")
+      Dir = "/" + M.Dir;
+    Multilibs.emplace_back(Dir, Dir, Dir, M.Flags);
+  }
+
+  return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers));
+}
+
 LLVM_DUMP_METHOD void MultilibSet::dump() const {
   print(llvm::errs());
 }

diff  --git a/clang/unittests/Driver/MultilibTest.cpp b/clang/unittests/Driver/MultilibTest.cpp
index 6a066f6b0f5a6..087ec35e48149 100644
--- a/clang/unittests/Driver/MultilibTest.cpp
+++ b/clang/unittests/Driver/MultilibTest.cpp
@@ -13,6 +13,7 @@
 #include "clang/Driver/Multilib.h"
 #include "../../lib/Driver/ToolChains/CommonArgs.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/Version.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -187,3 +188,350 @@ TEST(MultilibTest, SelectMultiple) {
   EXPECT_EQ("/a", Selection[0].gccSuffix());
   EXPECT_EQ("/b", Selection[1].gccSuffix());
 }
+
+static void diagnosticCallback(const llvm::SMDiagnostic &D, void *Out) {
+  *reinterpret_cast<std::string *>(Out) = D.getMessage();
+}
+
+static bool parseYaml(MultilibSet &MS, std::string &Diagnostic,
+                      const char *Data) {
+  auto ErrorOrMS = MultilibSet::parseYaml(llvm::MemoryBufferRef(Data, "TEST"),
+                                          diagnosticCallback, &Diagnostic);
+  if (ErrorOrMS.getError())
+    return false;
+  MS = std::move(ErrorOrMS.get());
+  return true;
+}
+
+static bool parseYaml(MultilibSet &MS, const char *Data) {
+  auto ErrorOrMS = MultilibSet::parseYaml(llvm::MemoryBufferRef(Data, "TEST"));
+  if (ErrorOrMS.getError())
+    return false;
+  MS = std::move(ErrorOrMS.get());
+  return true;
+}
+
+// When updating this version also update MultilibVersionCurrent in Multilib.cpp
+#define YAML_PREAMBLE "MultilibVersion: 1.0\n"
+
+TEST(MultilibTest, ParseInvalid) {
+  std::string Diagnostic;
+
+  MultilibSet MS;
+
+  EXPECT_FALSE(parseYaml(MS, Diagnostic, R"(
+Variants: []
+)"));
+  EXPECT_TRUE(
+      StringRef(Diagnostic).contains("missing required key 'MultilibVersion'"))
+      << Diagnostic;
+
+  // Reject files with a 
diff erent major version
+  EXPECT_FALSE(parseYaml(MS, Diagnostic,
+                         R"(
+MultilibVersion: 2.0
+Variants: []
+)"));
+  EXPECT_TRUE(
+      StringRef(Diagnostic).contains("multilib version 2.0 is unsupported"))
+      << Diagnostic;
+  EXPECT_FALSE(parseYaml(MS, Diagnostic,
+                         R"(
+MultilibVersion: 0.1
+Variants: []
+)"));
+  EXPECT_TRUE(
+      StringRef(Diagnostic).contains("multilib version 0.1 is unsupported"))
+      << Diagnostic;
+
+  // Reject files with a later minor version
+  EXPECT_FALSE(parseYaml(MS, Diagnostic,
+                         R"(
+MultilibVersion: 1.9
+Variants: []
+)"));
+  EXPECT_TRUE(
+      StringRef(Diagnostic).contains("multilib version 1.9 is unsupported"))
+      << Diagnostic;
+
+  // Accept files with the same major version and the same or earlier minor
+  // version
+  EXPECT_TRUE(parseYaml(MS, Diagnostic, R"(
+MultilibVersion: 1.0
+Variants: []
+)")) << Diagnostic;
+
+  EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE));
+  EXPECT_TRUE(StringRef(Diagnostic).contains("missing required key 'Variants'"))
+      << Diagnostic;
+
+  EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants:
+- Dir: /abc
+  Flags: []
+)"));
+  EXPECT_TRUE(StringRef(Diagnostic).contains("paths must be relative"))
+      << Diagnostic;
+
+  EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants:
+- Flags: []
+)"));
+  EXPECT_TRUE(StringRef(Diagnostic).contains("missing required key 'Dir'"))
+      << Diagnostic;
+
+  EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants:
+- Dir: .
+)"));
+  EXPECT_TRUE(StringRef(Diagnostic).contains("missing required key 'Flags'"))
+      << Diagnostic;
+
+  EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants: []
+Mappings:
+- Match: abc
+)"));
+  EXPECT_TRUE(StringRef(Diagnostic).contains("value required for 'Flags'"))
+      << Diagnostic;
+
+  EXPECT_FALSE(parseYaml(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants: []
+Mappings:
+- Dir: .
+  Match: '('
+  Flags: []
+)"));
+  EXPECT_TRUE(StringRef(Diagnostic).contains("parentheses not balanced"))
+      << Diagnostic;
+}
+
+TEST(MultilibTest, Parse) {
+  MultilibSet MS;
+  EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: .
+  Flags: []
+)"));
+  EXPECT_EQ(1U, MS.size());
+  EXPECT_EQ("", MS.begin()->gccSuffix());
+
+  EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: abc
+  Flags: []
+)"));
+  EXPECT_EQ(1U, MS.size());
+  EXPECT_EQ("/abc", MS.begin()->gccSuffix());
+
+  EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: pqr
+  Flags: [-mfloat-abi=soft]
+)"));
+  EXPECT_EQ(1U, MS.size());
+  EXPECT_EQ("/pqr", MS.begin()->gccSuffix());
+  EXPECT_EQ(std::vector<std::string>({"-mfloat-abi=soft"}),
+            MS.begin()->flags());
+
+  EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: pqr
+  Flags: [-mfloat-abi=soft, -fno-exceptions]
+)"));
+  EXPECT_EQ(1U, MS.size());
+  EXPECT_EQ(std::vector<std::string>({"-mfloat-abi=soft", "-fno-exceptions"}),
+            MS.begin()->flags());
+
+  EXPECT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: a
+  Flags: []
+- Dir: b
+  Flags: []
+)"));
+  EXPECT_EQ(2U, MS.size());
+}
+
+TEST(MultilibTest, SelectSoft) {
+  MultilibSet MS;
+  Multilib Selected;
+  ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: s
+  Flags: [-mfloat-abi=soft]
+Mappings:
+- Match: -mfloat-abi=softfp
+  Flags: [-mfloat-abi=soft]
+)"));
+  EXPECT_TRUE(MS.select({"-mfloat-abi=soft"}, Selected));
+  EXPECT_TRUE(MS.select({"-mfloat-abi=softfp"}, Selected));
+  EXPECT_FALSE(MS.select({"-mfloat-abi=hard"}, Selected));
+}
+
+TEST(MultilibTest, SelectSoftFP) {
+  MultilibSet MS;
+  Multilib Selected;
+  ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: f
+  Flags: [-mfloat-abi=softfp]
+)"));
+  EXPECT_FALSE(MS.select({"-mfloat-abi=soft"}, Selected));
+  EXPECT_TRUE(MS.select({"-mfloat-abi=softfp"}, Selected));
+  EXPECT_FALSE(MS.select({"-mfloat-abi=hard"}, Selected));
+}
+
+TEST(MultilibTest, SelectHard) {
+  // If hard float is all that's available then select that only if compiling
+  // with hard float.
+  MultilibSet MS;
+  Multilib Selected;
+  ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: h
+  Flags: [-mfloat-abi=hard]
+)"));
+  EXPECT_FALSE(MS.select({"-mfloat-abi=soft"}, Selected));
+  EXPECT_FALSE(MS.select({"-mfloat-abi=softfp"}, Selected));
+  EXPECT_TRUE(MS.select({"-mfloat-abi=hard"}, Selected));
+}
+
+TEST(MultilibTest, SelectFloatABI) {
+  MultilibSet MS;
+  Multilib Selected;
+  ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: s
+  Flags: [-mfloat-abi=soft]
+- Dir: f
+  Flags: [-mfloat-abi=softfp]
+- Dir: h
+  Flags: [-mfloat-abi=hard]
+Mappings:
+- Match: -mfloat-abi=softfp
+  Flags: [-mfloat-abi=soft]
+)"));
+  MS.select({"-mfloat-abi=soft"}, Selected);
+  EXPECT_EQ("/s", Selected.gccSuffix());
+  MS.select({"-mfloat-abi=softfp"}, Selected);
+  EXPECT_EQ("/f", Selected.gccSuffix());
+  MS.select({"-mfloat-abi=hard"}, Selected);
+  EXPECT_EQ("/h", Selected.gccSuffix());
+}
+
+TEST(MultilibTest, SelectFloatABIReversed) {
+  // If soft is specified after softfp then softfp will never be
+  // selected because soft is compatible with softfp and last wins.
+  MultilibSet MS;
+  Multilib Selected;
+  ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: h
+  Flags: [-mfloat-abi=hard]
+- Dir: f
+  Flags: [-mfloat-abi=softfp]
+- Dir: s
+  Flags: [-mfloat-abi=soft]
+Mappings:
+- Match: -mfloat-abi=softfp
+  Flags: [-mfloat-abi=soft]
+)"));
+  MS.select({"-mfloat-abi=soft"}, Selected);
+  EXPECT_EQ("/s", Selected.gccSuffix());
+  MS.select({"-mfloat-abi=softfp"}, Selected);
+  EXPECT_EQ("/s", Selected.gccSuffix());
+  MS.select({"-mfloat-abi=hard"}, Selected);
+  EXPECT_EQ("/h", Selected.gccSuffix());
+}
+
+TEST(MultilibTest, SelectMClass) {
+  const char *MultilibSpec = YAML_PREAMBLE R"(
+Variants:
+- Dir: thumb/v6-m/nofp
+  Flags: [--target=thumbv6m-none-unknown-eabi, -mfpu=none]
+
+- Dir: thumb/v7-m/nofp
+  Flags: [--target=thumbv7m-none-unknown-eabi, -mfpu=none]
+
+- Dir: thumb/v7e-m/nofp
+  Flags: [--target=thumbv7em-none-unknown-eabi, -mfpu=none]
+
+- Dir: thumb/v8-m.main/nofp
+  Flags: [--target=thumbv8m.main-none-unknown-eabi, -mfpu=none]
+
+- Dir: thumb/v8.1-m.main/nofp/nomve
+  Flags: [--target=thumbv8.1m.main-none-unknown-eabi, -mfpu=none]
+
+- Dir: thumb/v7e-m/fpv4_sp_d16
+  Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv4-sp-d16]
+
+- Dir: thumb/v7e-m/fpv5_d16
+  Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv5-d16]
+
+- Dir: thumb/v8-m.main/fp
+  Flags: [--target=thumbv8m.main-none-unknown-eabihf]
+
+- Dir: thumb/v8.1-m.main/fp
+  Flags: [--target=thumbv8.1m.main-none-unknown-eabihf]
+
+- Dir: thumb/v8.1-m.main/nofp/mve
+  Flags: [--target=thumbv8.1m.main-none-unknown-eabihf, -march=thumbv8.1m.main+mve]
+
+Mappings:
+- Match: --target=thumbv8(\.[0-9]+)?m\.base-none-unknown-eabi
+  Flags: [--target=thumbv6m-none-unknown-eabi]
+- Match: -target=thumbv8\.[1-9]m\.main-none-unknown-eabi
+  Flags: [--target=thumbv8.1m.main-none-unknown-eabi]
+- Match: -target=thumbv8\.[1-9]m\.main-none-unknown-eabihf
+  Flags: [--target=thumbv8.1m.main-none-unknown-eabihf]
+- Match: -march=thumbv8\.[1-9]m\.main.*\+mve($|\+).*
+  Flags: [-march=thumbv8.1m.main+mve]
+)";
+
+  MultilibSet MS;
+  Multilib Selected;
+  ASSERT_TRUE(parseYaml(MS, MultilibSpec));
+
+  ASSERT_TRUE(MS.select({"--target=thumbv6m-none-unknown-eabi", "-mfpu=none"},
+                        Selected));
+  EXPECT_EQ("/thumb/v6-m/nofp", Selected.gccSuffix());
+
+  ASSERT_TRUE(MS.select({"--target=thumbv7m-none-unknown-eabi", "-mfpu=none"},
+                        Selected));
+  EXPECT_EQ("/thumb/v7-m/nofp", Selected.gccSuffix());
+
+  ASSERT_TRUE(MS.select({"--target=thumbv7em-none-unknown-eabi", "-mfpu=none"},
+                        Selected));
+  EXPECT_EQ("/thumb/v7e-m/nofp", Selected.gccSuffix());
+
+  ASSERT_TRUE(MS.select(
+      {"--target=thumbv8m.main-none-unknown-eabi", "-mfpu=none"}, Selected));
+  EXPECT_EQ("/thumb/v8-m.main/nofp", Selected.gccSuffix());
+
+  ASSERT_TRUE(MS.select(
+      {"--target=thumbv8.1m.main-none-unknown-eabi", "-mfpu=none"}, Selected));
+  EXPECT_EQ("/thumb/v8.1-m.main/nofp/nomve", Selected.gccSuffix());
+
+  ASSERT_TRUE(
+      MS.select({"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv4-sp-d16"},
+                Selected));
+  EXPECT_EQ("/thumb/v7e-m/fpv4_sp_d16", Selected.gccSuffix());
+
+  ASSERT_TRUE(MS.select(
+      {"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv5-d16"}, Selected));
+  EXPECT_EQ("/thumb/v7e-m/fpv5_d16", Selected.gccSuffix());
+
+  ASSERT_TRUE(
+      MS.select({"--target=thumbv8m.main-none-unknown-eabihf"}, Selected));
+  EXPECT_EQ("/thumb/v8-m.main/fp", Selected.gccSuffix());
+
+  ASSERT_TRUE(
+      MS.select({"--target=thumbv8.1m.main-none-unknown-eabihf"}, Selected));
+  EXPECT_EQ("/thumb/v8.1-m.main/fp", Selected.gccSuffix());
+
+  ASSERT_TRUE(MS.select({"--target=thumbv8.1m.main-none-unknown-eabihf",
+                         "-mfpu=none", "-march=thumbv8.1m.main+dsp+mve"},
+                        Selected));
+  EXPECT_EQ("/thumb/v8.1-m.main/nofp/mve", Selected.gccSuffix());
+}


        


More information about the cfe-commits mailing list