Joe created this revision.
Joe added reviewers: michaelplatings, kito-cheng.
Joe added a project: clang.
Herald added subscribers: jobnoorman, luke, shiva0217, VincentWu, vkmr, 
frasercrmck, luismarques, apazos, sameer.abuasal, s.egerton, Jim, benna, 
psnobl, abidh, jocewei, PkmX, the_o, brucehoult, MartinMosbeck, rogfer01, 
edward-jones, zzheng, jrtc27, niosHD, sabuasal, simoncook, johnrusso, rbar, 
asb, kristof.beyls, arichardson, emaste.
Herald added a project: All.
Joe requested review of this revision.
Herald added subscribers: cfe-commits, wangpc, eopXD, MaskRay.

This patch allows usage of multilib.yaml 
<https://discourse.llvm.org/t/rfc-multilib/67494> when using a riscv gnu 
toolchain

This could certainly land as three separate patches, but I wanted to put this 
up as one to gather feedback to make sure the direction makes sense.

These are the main discussion points I want to bring to attention:

1. For the RISCVMultilibFlags, the mabi flag is used in combination with all 
the march extension features (e.g +m). Notably, this doesn't align with the 
current arm/aarch64 multilib flags, which all flags corresponding to the 
command line flag. E.G `-march=`. Does this violate a particular design 
decision, or can any target decide on whatever multilib flags they want?

2. The location of multilib.yaml for a gnu toolchain is in the lib directory of 
the sysroot. E.G `riscv64-unknown-elf/lib/multilib.yaml`. This differs from the 
baremetal location of "lib/clang-runtimes".

3. Does it make more sense to implement finding multilibs using yaml for riscv 
in the baremetal toolchain first? I was planning on doing it after.

Theoretically, I think this matching of multilibs could be done without the 
need for multilib.yaml, but it is indeed much easier considering the logic is 
already there.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155294

Files:
  clang/include/clang/Driver/ToolChain.h
  clang/lib/Driver/ToolChain.cpp
  clang/lib/Driver/ToolChains/BareMetal.cpp
  clang/lib/Driver/ToolChains/Gnu.cpp
  clang/lib/Driver/ToolChains/Gnu.h
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32i/ilp32/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32i/ilp32/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32iac/ilp32/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32iac/ilp32/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32im/ilp32/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32im/ilp32/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imac/ilp32/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imac/ilp32/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imafc/ilp32f/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imafc/ilp32f/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv64imac/lp64/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv64imac/lp64/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv64imafdc/lp64d/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv64imafdc/lp64d/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/bin/ld
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/multilib.yaml
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/rv32i/ilp32/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/rv32iac/ilp32/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/rv32im/ilp32/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/rv32imac/ilp32/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/rv32imafc/ilp32f/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/rv64imac/lp64/crt0.o
  clang/test/Driver/riscv-toolchain-multilib-yaml.c

Index: clang/test/Driver/riscv-toolchain-multilib-yaml.c
===================================================================
--- /dev/null
+++ clang/test/Driver/riscv-toolchain-multilib-yaml.c
@@ -0,0 +1,68 @@
+// UNSUPPORTED: system-windows
+// In this test, multilib resolution is resolved using a multilib.yaml
+// definition, in which multilibs are picked in accordance to matching abi /
+// marchs.
+
+// RUN: env "PATH=" %clang -### %s -fuse-ld=ld \
+// RUN:   --target=riscv32-unknown-elf --rtlib=platform --sysroot= \
+// RUN:   -march=rv32iac -mabi=ilp32\
+// RUN:   --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk_yaml 2>&1 \
+// RUN:   | FileCheck -check-prefix=C-RV32IAC-BAREMETAL-MULTI-ILP32 %s
+
+// C-RV32IAC-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv64-unknown-elf/lib/rv32iac/ilp32{{/|\\\\}}crt0.o"
+// C-RV32IAC-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32iac/ilp32{{/|\\\\}}crtbegin.o"
+// C-RV32IAC-BAREMETAL-MULTI-ILP32: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32iac/ilp32{{/|\\\\}}crtend.o"
+
+// RUN: env "PATH=" %clang -### %s -fuse-ld=ld \
+// RUN:   --target=riscv32-unknown-elf --rtlib=platform --sysroot= \
+// RUN:   -march=rv32imafc -mabi=ilp32f\
+// RUN:   --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk_yaml 2>&1 \
+// RUN:   | FileCheck -check-prefix=C-RV32IMAFC-BAREMETAL-MULTI-ILP32F %s
+
+// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv64-unknown-elf/lib/rv32imafc/ilp32f{{/|\\\\}}crt0.o"
+// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imafc/ilp32f{{/|\\\\}}crtbegin.o"
+// C-RV32IMAFC-BAREMETAL-MULTI-ILP32F: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imafc/ilp32f{{/|\\\\}}crtend.o"
+
+// Check the addition of extensions for which we don't have an exact match of multilib
+// RUN: env "PATH=" %clang -### %s -fuse-ld=ld \
+// RUN:   --target=riscv32-unknown-elf --rtlib=platform --sysroot= \
+// RUN:   -march=rv32imafc_zba -mabi=ilp32f\
+// RUN:   --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk_yaml 2>&1 \
+// RUN:   | FileCheck -check-prefix=C-RV32IMAFC-ZBA-BAREMETAL-MULTI-ILP32F %s
+
+// C-RV32IMAFC-ZBA-BAREMETAL-MULTI-ILP32F: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv64-unknown-elf/lib/rv32imafc/ilp32f{{/|\\\\}}crt0.o"
+// C-RV32IMAFC-ZBA-BAREMETAL-MULTI-ILP32F: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imafc/ilp32f{{/|\\\\}}crtbegin.o"
+// C-RV32IMAFC-ZBA-BAREMETAL-MULTI-ILP32F: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imafc/ilp32f{{/|\\\\}}crtend.o"
+
+// RUN: env "PATH=" %clang -### %s -fuse-ld=ld \
+// RUN:   --target=riscv64-unknown-elf --rtlib=platform --sysroot= \
+// RUN:   -march=rv64imac_zba -mabi=lp64\
+// RUN:   --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk_yaml 2>&1 \
+// RUN:   | FileCheck -check-prefix=C-RV64IMAC-ZBA-BAREMETAL-MULTI-LP64 %s
+
+// C-RV64IMAC-ZBA-BAREMETAL-MULTI-LP64: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv64-unknown-elf/lib/rv64imac/lp64{{/|\\\\}}crt0.o"
+// C-RV64IMAC-ZBA-BAREMETAL-MULTI-LP64: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv64imac/lp64{{/|\\\\}}crtbegin.o"
+// C-RV64IMAC-ZBA-BAREMETAL-MULTI-LP64: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/rv64imac/lp64{{/|\\\\}}crtend.o"
+
+// For this toolchain, rv64imafdc is considered the default toplevel multilib. Check this.
+// RUN: env "PATH=" %clang -### %s -fuse-ld=ld \
+// RUN:   --target=riscv64-unknown-elf --rtlib=platform --sysroot= \
+// RUN:   -march=rv64imafc -mabi=lp64d\
+// RUN:   --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk_yaml 2>&1 \
+// RUN:   | FileCheck -check-prefix=C-RV64IMAFDC-BAREMETAL-MULTI-LP64D %s
+
+// C-RV64IMAFDC-BAREMETAL-MULTI-LP64D: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0/../../..{{/|\\\\}}..{{/|\\\\}}riscv64-unknown-elf/lib{{/|\\\\}}crt0.o"
+// C-RV64IMAFDC-BAREMETAL-MULTI-LP64D: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0{{/|\\\\}}crtbegin.o"
+// C-RV64IMAFDC-BAREMETAL-MULTI-LP64D: "{{.*}}/Inputs/multilib_riscv_elf_sdk_yaml/lib/gcc/riscv64-unknown-elf/8.2.0{{/|\\\\}}crtend.o"
+
+// RUN: %clang -no-canonical-prefixes -print-multi-lib 2>&1 \
+// RUN:   --target=riscv64-unknown-elf --sysroot= \
+// RUN:   --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk_yaml 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-PRINT-MULTI-LIB %s
+// CHECK-PRINT-MULTI-LIB: rv32i/ilp32;@mabi=ilp32
+// CHECK-PRINT-MULTI-LIB: rv32iac/ilp32;@mabi=ilp32
+// CHECK-PRINT-MULTI-LIB: rv32im/ilp32;@mabi=ilp32
+// CHECK-PRINT-MULTI-LIB: rv32imac/ilp32;@mabi=ilp32
+// CHECK-PRINT-MULTI-LIB: rv32imafc/ilp32f;@mabi=ilp32f
+// CHECK-PRINT-MULTI-LIB: rv64imac/lp64;@mabi=lp64
+// CHECK-PRINT-MULTI-LIB: .;@mabi=lp64d
Index: clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/multilib.yaml
===================================================================
--- /dev/null
+++ clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/lib/multilib.yaml
@@ -0,0 +1,46 @@
+---
+# How does clang use this file?
+# 1. If the ToolChain class for the architecture supports this form of
+#    multilib it then it loads the file if present in sysroot.
+# 2. Generate flags from the user provided arguments.
+#    (Use `clang -print-multi-flags-experimental` to see which flags are
+#    generated).
+# 3. Compare the arguments against each regular expression and store
+#    associated flags if there's a match.
+# 4. Find the last library variant whose flags are a subset of the
+#    flags derived from the user provided arguments.
+# 5. Use the directory for the library variant as the sysroot.
+
+# Clang will emit an error if this number is greater than its current multilib
+# version or if its major version differs, but will accept lesser minor
+# versions.
+MultilibVersion: 1.0
+
+# A library is considered compatible if the are a subset of the flags derived
+# from the arguments provided by the user.
+# If multiple libraries are deemed compatible then the one that appears
+# last in the list wins.
+Variants:
+- Dir: rv32i/ilp32
+  Flags: [-mabi=ilp32]
+
+- Dir: rv32iac/ilp32
+  Flags: [-mabi=ilp32, +a, +c]
+
+- Dir: rv32im/ilp32
+  Flags: [-mabi=ilp32, +m]
+
+- Dir: rv32imac/ilp32
+  Flags: [-mabi=ilp32, +m, +a, +c]
+
+- Dir: rv32imafc/ilp32f
+  Flags: [-mabi=ilp32f, +m, +a, +f, +c]
+
+- Dir: rv64imac/lp64
+  Flags: [-mabi=lp64, +m, +a, +c]
+
+# GCC sysroots will have a default march/mabi sitting at the top level. Assume
+# this is rv64imafdc/lp64d for this test.
+- Dir: .
+  Flags: [-mabi=lp64d, +m, +a, +d, +c]
+...
Index: clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/bin/ld
===================================================================
--- /dev/null
+++ clang/test/Driver/Inputs/multilib_riscv_elf_sdk_yaml/riscv64-unknown-elf/bin/ld
@@ -0,0 +1 @@
+#!/bin/true
Index: clang/lib/Driver/ToolChains/Gnu.h
===================================================================
--- clang/lib/Driver/ToolChains/Gnu.h
+++ clang/lib/Driver/ToolChains/Gnu.h
@@ -193,6 +193,7 @@
     bool IsValid;
     llvm::Triple GCCTriple;
     const Driver &D;
+    const ToolChain &TC;
 
     // FIXME: These might be better as path objects.
     std::string GCCInstallPath;
@@ -217,7 +218,8 @@
     const std::string GentooConfigDir = "/etc/env.d/gcc";
 
   public:
-    explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
+    explicit GCCInstallationDetector(const Driver &D, const
+        ToolChain &TC) : IsValid(false), D(D), TC(TC) {}
     void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args,
               ArrayRef<std::string> ExtraTripleAliases = std::nullopt);
 
Index: clang/lib/Driver/ToolChains/Gnu.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Gnu.cpp
+++ clang/lib/Driver/ToolChains/Gnu.cpp
@@ -1750,7 +1750,37 @@
 static void findRISCVBareMetalMultilibs(const Driver &D,
                                         const llvm::Triple &TargetTriple,
                                         StringRef Path, const ArgList &Args,
-                                        DetectedMultilibs &Result) {
+                                        DetectedMultilibs &Result,
+                                        const ToolChain &TC) {
+  auto FilePathsCallback = [](const Multilib &M) {
+    return std::vector<std::string>(
+        {M.gccSuffix(), "/../../../../riscv64-unknown-elf/lib" + M.gccSuffix(),
+         "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()});
+  };
+
+  // Find multilib.yaml and use that if it exists
+  // The name of the sysroot can be either riscv32 or riscv64, so check both.
+  std::optional<SmallString<128>> ExistingMultilibYamlPath = std::nullopt;
+  SmallString<128> Toplevel(Path);
+  llvm::sys::path::append(Toplevel, "..", "..", "..", "..");
+  SmallString<128> MultilibYamlPath32(Toplevel);
+  SmallString<128> MultilibYamlPath64(Toplevel);
+
+  llvm::sys::path::append(MultilibYamlPath64, "riscv64-unknown-elf", "lib",
+                          ToolChain::MultilibFilename);
+  llvm::sys::path::append(MultilibYamlPath32, "riscv32-unknown-elf", "lib",
+                          ToolChain::MultilibFilename);
+  if (D.getVFS().exists(MultilibYamlPath64))
+    ExistingMultilibYamlPath = MultilibYamlPath64;
+  else if (D.getVFS().exists(MultilibYamlPath32))
+    ExistingMultilibYamlPath = MultilibYamlPath32;
+
+  if (ExistingMultilibYamlPath) {
+    TC.findMultilibsFromYAML(ExistingMultilibYamlPath.value(), Args, Result);
+    Result.Multilibs.setFilePathsCallback(FilePathsCallback);
+    return;
+  }
+
   FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
   struct RiscvMultilib {
     StringRef march;
@@ -1772,17 +1802,11 @@
             .flag(Twine("-march=", Element.march).str())
             .flag(Twine("-mabi=", Element.mabi).str()));
   }
-  MultilibSet RISCVMultilibs =
-      MultilibSetBuilder()
-          .Either(Ms)
-          .makeMultilibSet()
-          .FilterOut(NonExistent)
-          .setFilePathsCallback([](const Multilib &M) {
-            return std::vector<std::string>(
-                {M.gccSuffix(),
-                 "/../../../../riscv64-unknown-elf/lib" + M.gccSuffix(),
-                 "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()});
-          });
+  MultilibSet RISCVMultilibs = MultilibSetBuilder()
+                                   .Either(Ms)
+                                   .makeMultilibSet()
+                                   .FilterOut(NonExistent)
+                                   .setFilePathsCallback(FilePathsCallback);
 
   Multilib::flags_list Flags;
   llvm::StringSet<> Added_ABIs;
@@ -1804,9 +1828,10 @@
 
 static void findRISCVMultilibs(const Driver &D,
                                const llvm::Triple &TargetTriple, StringRef Path,
-                               const ArgList &Args, DetectedMultilibs &Result) {
+                               const ArgList &Args, DetectedMultilibs &Result,
+                               const ToolChain &TC) {
   if (TargetTriple.getOS() == llvm::Triple::UnknownOS)
-    return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result);
+    return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result, TC);
 
   FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
   MultilibBuilder Ilp32 =
@@ -2708,7 +2733,7 @@
     if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected))
       return false;
   } else if (TargetTriple.isRISCV()) {
-    findRISCVMultilibs(D, TargetTriple, Path, Args, Detected);
+    findRISCVMultilibs(D, TargetTriple, Path, Args, Detected, TC);
   } else if (isMSP430(TargetArch)) {
     findMSP430Multilibs(D, TargetTriple, Path, Args, Detected);
   } else if (TargetArch == llvm::Triple::avr) {
@@ -2883,7 +2908,7 @@
 
 Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple,
                          const ArgList &Args)
-    : ToolChain(D, Triple, Args), GCCInstallation(D),
+    : ToolChain(D, Triple, Args), GCCInstallation(D, *this),
       CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) {
   getProgramPaths().push_back(getDriver().getInstalledDir());
   if (getDriver().getInstalledDir() != getDriver().Dir)
Index: clang/lib/Driver/ToolChains/BareMetal.cpp
===================================================================
--- clang/lib/Driver/ToolChains/BareMetal.cpp
+++ clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -161,30 +161,6 @@
   return Triple.getEnvironmentName() == "elf";
 }
 
-static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D,
-                                  StringRef MultilibPath, const ArgList &Args,
-                                  DetectedMultilibs &Result) {
-  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB =
-      D.getVFS().getBufferForFile(MultilibPath);
-  if (!MB)
-    return;
-  Multilib::flags_list Flags = TC.getMultilibFlags(Args);
-  llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet =
-      MultilibSet::parseYaml(*MB.get());
-  if (ErrorOrMultilibSet.getError())
-    return;
-  Result.Multilibs = ErrorOrMultilibSet.get();
-  if (Result.Multilibs.select(Flags, Result.SelectedMultilibs))
-    return;
-  D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " ");
-  std::stringstream ss;
-  for (const Multilib &Multilib : Result.Multilibs)
-    ss << "\n" << llvm::join(Multilib.flags(), " ");
-  D.Diag(clang::diag::note_drv_available_multilibs) << ss.str();
-}
-
-static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
-
 // Get the sysroot, before multilib takes effect.
 static std::string computeBaseSysRoot(const Driver &D,
                                       const llvm::Triple &Triple) {
@@ -195,7 +171,7 @@
   llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes");
 
   SmallString<128> MultilibPath(SysRootDir);
-  llvm::sys::path::append(MultilibPath, MultilibFilename);
+  llvm::sys::path::append(MultilibPath, ToolChain::MultilibFilename);
 
   // New behaviour: if multilib.yaml is found then use clang-runtimes as the
   // sysroot.
@@ -217,8 +193,8 @@
     }
   } else {
     llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple));
-    llvm::sys::path::append(MultilibPath, MultilibFilename);
-    findMultilibsFromYAML(*this, D, MultilibPath, Args, Result);
+    llvm::sys::path::append(MultilibPath, ToolChain::MultilibFilename);
+    findMultilibsFromYAML(MultilibPath, Args, Result);
     SelectedMultilibs = Result.SelectedMultilibs;
     Multilibs = Result.Multilibs;
   }
Index: clang/lib/Driver/ToolChain.cpp
===================================================================
--- clang/lib/Driver/ToolChain.cpp
+++ clang/lib/Driver/ToolChain.cpp
@@ -9,9 +9,11 @@
 #include "clang/Driver/ToolChain.h"
 #include "ToolChains/Arch/AArch64.h"
 #include "ToolChains/Arch/ARM.h"
+#include "ToolChains/Arch/RISCV.h"
 #include "ToolChains/Clang.h"
 #include "ToolChains/CommonArgs.h"
 #include "ToolChains/Flang.h"
+#include "ToolChains/Gnu.h"
 #include "ToolChains/InterfaceStubs.h"
 #include "clang/Basic/ObjCRuntime.h"
 #include "clang/Basic/Sanitizers.h"
@@ -40,6 +42,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/RISCVISAInfo.h"
 #include "llvm/Support/VersionTuple.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/TargetParser/AArch64TargetParser.h"
@@ -48,6 +51,7 @@
 #include <cassert>
 #include <cstddef>
 #include <cstring>
+#include <sstream>
 #include <string>
 
 using namespace clang;
@@ -240,26 +244,53 @@
   }
 }
 
+static void getRISCVMultilibFlags(const Driver &D, const llvm::Triple &Triple,
+                                  const llvm::opt::ArgList &Args,
+                                  Multilib::flags_list &Result) {
+  std::vector<StringRef> Features;
+  riscv::getRISCVTargetFeatures(D, Triple, Args, Features);
+  const auto UnifiedFeatures = tools::unifyTargetFeatures(Features);
+  llvm::DenseSet<StringRef> FeatureSet(UnifiedFeatures.begin(),
+                                       UnifiedFeatures.end());
+  // Add all Extenstion features
+  for (StringRef Feature : Features) {
+    std::string FeatureStr = Feature.str();
+    if (FeatureStr.front() != '+')
+      continue;
+    // get rid of +/- on Feature
+    if (RISCVISAInfo::isSupportedExtensionFeature(FeatureStr.substr(1)))
+      Result.push_back(FeatureStr);
+  }
+
+  if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+    Result.push_back(std::string("-mabi=") + A->getValue());
+  }
+}
+
 Multilib::flags_list
 ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const {
   using namespace clang::driver::options;
 
   std::vector<std::string> Result;
   const llvm::Triple Triple(ComputeEffectiveClangTriple(Args));
-  Result.push_back("--target=" + Triple.str());
 
   switch (Triple.getArch()) {
   case llvm::Triple::aarch64:
   case llvm::Triple::aarch64_32:
   case llvm::Triple::aarch64_be:
+    Result.push_back("--target=" + Triple.str());
     getAArch64MultilibFlags(D, Triple, Args, Result);
     break;
   case llvm::Triple::arm:
   case llvm::Triple::armeb:
   case llvm::Triple::thumb:
   case llvm::Triple::thumbeb:
+    Result.push_back("--target=" + Triple.str());
     getARMMultilibFlags(D, Triple, Args, Result);
     break;
+  case llvm::Triple::riscv32:
+  case llvm::Triple::riscv64:
+    getRISCVMultilibFlags(D, Triple, Args, Result);
   default:
     break;
   }
@@ -1499,3 +1530,24 @@
   delete DAL;
   return nullptr;
 }
+
+void ToolChain::findMultilibsFromYAML(StringRef MultilibPath,
+    const llvm::opt::ArgList &Args, DetectedMultilibs &Result) const {
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB =
+      getDriver().getVFS().getBufferForFile(MultilibPath);
+  if (!MB)
+    return;
+  Multilib::flags_list Flags = getMultilibFlags(Args);
+  llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet =
+      MultilibSet::parseYaml(*MB.get());
+  if (ErrorOrMultilibSet.getError())
+    return;
+  Result.Multilibs = ErrorOrMultilibSet.get();
+  if (Result.Multilibs.select(Flags, Result.SelectedMultilibs))
+    return;
+  getDriver().Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " ");
+  std::stringstream ss;
+  for (const Multilib &Multilib : Result.Multilibs)
+    ss << "\n" << llvm::join(Multilib.flags(), " ");
+  getDriver().Diag(clang::diag::note_drv_available_multilibs) << ss.str();
+}
Index: clang/include/clang/Driver/ToolChain.h
===================================================================
--- clang/include/clang/Driver/ToolChain.h
+++ clang/include/clang/Driver/ToolChain.h
@@ -13,7 +13,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/Sanitizers.h"
 #include "clang/Driver/Action.h"
-#include "clang/Driver/Multilib.h"
+#include "clang/Driver/MultilibBuilder.h"
 #include "clang/Driver/Types.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -58,6 +58,7 @@
 class SanitizerArgs;
 class Tool;
 class XRayArgs;
+struct DetectedMultilibs;
 
 /// Helper structure used to pass information extracted from clang executable
 /// name such as `i686-linux-android-g++`.
@@ -237,6 +238,8 @@
   llvm::vfs::FileSystem &getVFS() const;
   const llvm::Triple &getTriple() const { return Triple; }
 
+  static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
+
   /// Get the toolchain's aux triple, if it has one.
   ///
   /// Exactly what the aux triple represents depends on the toolchain, but for
@@ -793,6 +796,11 @@
     }
     return TT;
   }
+
+  void findMultilibsFromYAML(StringRef MultilibPath,
+                             const llvm::opt::ArgList &Args,
+                             DetectedMultilibs &Result) const;
+
 };
 
 /// Set a ToolChain's effective triple. Reset it when the registration object
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to