kito-cheng created this revision.
Herald added subscribers: vkmr, frasercrmck, evandro, luismarques, apazos, 
sameer.abuasal, s.egerton, Jim, benna, psnobl, jocewei, PkmX, the_o, 
brucehoult, MartinMosbeck, rogfer01, edward-jones, zzheng, jrtc27, shiva0217, 
niosHD, sabuasal, simoncook, johnrusso, rbar, asb, emaste.
kito-cheng requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay.
Herald added a project: clang.

RISC-V is highly configurable architecture, so it's hard to list all
possible multi-lib here, in order to deal with that issue , GCC has support
a flexible way to configure the multi-lib[1] for bare-matel toolchain.

So I think it would be great to just leverage that from GCC, the
simplest way is asking the multi-lib configuration from GCC.

[1] 
https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=c1e6691245ca2f1f329549f323f67afe32bcb97a


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D97916

Files:
  clang/include/clang/Basic/DiagnosticDriverKinds.td
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/lib/Driver/ToolChains/Arch/RISCV.cpp
  clang/lib/Driver/ToolChains/Arch/RISCV.h
  clang/lib/Driver/ToolChains/Gnu.cpp
  clang/lib/Driver/ToolChains/Gnu.h
  clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/bin/riscv32-unknown-elf-gcc
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/lib/gcc/riscv32-unknown-elf/8.2.0/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/lib/gcc/riscv32-unknown-elf/8.2.0/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/lib/gcc/riscv32-unknown-elf/8.2.0/rv32iac/ilp32/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/lib/gcc/riscv32-unknown-elf/8.2.0/rv32iac/ilp32/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/lib/gcc/riscv32-unknown-elf/8.2.0/rv32imafc/ilp32f/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/lib/gcc/riscv32-unknown-elf/8.2.0/rv32imafc/ilp32f/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/lib/gcc/riscv32-unknown-elf/8.2.0/rv64imafdc/lp64d/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/lib/gcc/riscv32-unknown-elf/8.2.0/rv64imafdc/lp64d/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/riscv32-unknown-elf/lib/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/riscv32-unknown-elf/lib/rv32iac/ilp32/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/riscv32-unknown-elf/lib/rv32imafc/ilp32f/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/riscv32-unknown-elf/lib/rv64imac/lp64/crt0.o
  clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/bin/riscv64-unknown-elf-gcc
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/lib/gcc/riscv64-unknown-elf/8.2.0/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/lib/gcc/riscv64-unknown-elf/8.2.0/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/lib/gcc/riscv64-unknown-elf/8.2.0/rv32iac/ilp32/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/lib/gcc/riscv64-unknown-elf/8.2.0/rv32iac/ilp32/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imafc/ilp32f/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/lib/gcc/riscv64-unknown-elf/8.2.0/rv32imafc/ilp32f/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/lib/gcc/riscv64-unknown-elf/8.2.0/rv64imafdc/lp64d/crtbegin.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/lib/gcc/riscv64-unknown-elf/8.2.0/rv64imafdc/lp64d/crtend.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/riscv64-unknown-elf/lib/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/riscv64-unknown-elf/lib/rv32iac/ilp32/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/riscv64-unknown-elf/lib/rv32imafc/ilp32f/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/riscv64-unknown-elf/lib/rv64imac/lp64/crt0.o
  
clang/test/Driver/Inputs/multilib_riscv64_elf_sdk_bad/bin/riscv64-unknown-elf-gcc
  clang/test/Driver/riscv32-toolchain.c
  clang/test/Driver/riscv64-toolchain.c

Index: clang/test/Driver/riscv64-toolchain.c
===================================================================
--- clang/test/Driver/riscv64-toolchain.c
+++ clang/test/Driver/riscv64-toolchain.c
@@ -153,6 +153,24 @@
 // C-RV64-RTLIB-COMPILERRT-LP64: "--start-group" "-lc" "-lgloss" "--end-group" "{{.*}}libclang_rt.builtins-riscv64.a"
 // C-RV64-RTLIB-COMPILERRT-LP64: "{{.*}}clang_rt.crtend-riscv64.o"
 
+// Test for multi-lib config from GCC.
+// RUN: %clang %s \
+// RUN:   -target riscv64-unknown-elf \
+// RUN:   --gcc-toolchain=%S/Inputs/multilib_riscv64_elf_sdk \
+// RUN:   --print-multi-lib \
+// RUN:   | FileCheck -check-prefix=C-RV64-GCC-MULTI-LIB %s
+// C-RV64-GCC-MULTI-LIB: rv32iac/ilp32;@march=rv32iac@mabi=ilp32
+// C-RV64-GCC-MULTI-LIB-NEXT: rv32imafc/ilp32f;@march=rv32iac@mabi=ilp32f
+// C-RV64-GCC-MULTI-LIB-NEXT: rv64imafdc/lp64d;@march=rv64imafdc@mabi=lp64d
+// C-RV64-GCC-MULTI-LIB-NOT:  {{^.+$}}
+
+// RUN: %clang %s \
+// RUN:   -target riscv64-unknown-elf \
+// RUN:   --gcc-toolchain=%S/Inputs/multilib_riscv64_elf_sdk_bad \
+// RUN:   --print-multi-lib 2>&1 \
+// RUN:   | FileCheck -check-prefix=C-RV64-GCC-MULTI-LIB-BAD %s
+// C-RV64-GCC-MULTI-LIB-BAD: warning: xxx option unrecognized in multi-lib configuration when parsing config from GCC, falling back to built-in multi-lib configuration. [-Wmultilib-fallback]
+
 // RUN: %clang -target riscv64 %s -emit-llvm -S -o - | FileCheck %s
 
 typedef __builtin_va_list va_list;
Index: clang/test/Driver/riscv32-toolchain.c
===================================================================
--- clang/test/Driver/riscv32-toolchain.c
+++ clang/test/Driver/riscv32-toolchain.c
@@ -197,6 +197,17 @@
 // C-RV32-RTLIB-COMPILERRT-ILP32: "--start-group" "-lc" "-lgloss" "--end-group" "{{.*}}libclang_rt.builtins-riscv32.a"
 // C-RV32-RTLIB-COMPILERRT-ILP32: "{{.*}}clang_rt.crtend-riscv32.o"
 
+// Test for multi-lib config from GCC.
+// RUN: %clang %s \
+// RUN:   -target riscv32-unknown-elf \
+// RUN:   --gcc-toolchain=%S/Inputs/multilib_riscv32_elf_sdk \
+// RUN:   --print-multi-lib \
+// RUN:   | FileCheck -check-prefix=C-RV32-GCC-MULTI-LIB %s
+// C-RV32-GCC-MULTI-LIB: rv32iac/ilp32;@march=rv32iac@mabi=ilp32
+// C-RV32-GCC-MULTI-LIB-NEXT: rv32imafc/ilp32f;@march=rv32iac@mabi=ilp32f
+// C-RV32-GCC-MULTI-LIB-NEXT: rv64imafdc/lp64d;@march=rv64imafdc@mabi=lp64d
+// C-RV32-GCC-MULTI-LIB-NOT:  {{^.+$}}
+
 // RUN: %clang -target riscv32 %s -emit-llvm -S -o - | FileCheck %s
 
 typedef __builtin_va_list va_list;
Index: clang/test/Driver/Inputs/multilib_riscv64_elf_sdk_bad/bin/riscv64-unknown-elf-gcc
===================================================================
--- /dev/null
+++ clang/test/Driver/Inputs/multilib_riscv64_elf_sdk_bad/bin/riscv64-unknown-elf-gcc
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+print ("rv32iac/ilp32;@march=rv32iac@mabi=ilp32")
+print ("rv32imafc/ilp32f;@march=rv32iac@mabi=ilp32f")
+print ("rv64imafdc/lp64d;@march=rv64imafdc@mabi=lp64d@xxx")
Index: clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/bin/riscv64-unknown-elf-gcc
===================================================================
--- /dev/null
+++ clang/test/Driver/Inputs/multilib_riscv64_elf_sdk/bin/riscv64-unknown-elf-gcc
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+print ("rv32iac/ilp32;@march=rv32iac@mabi=ilp32")
+print ("rv32imafc/ilp32f;@march=rv32iac@mabi=ilp32f")
+print ("rv64imafdc/lp64d;@march=rv64imafdc@mabi=lp64d")
Index: clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/bin/riscv32-unknown-elf-gcc
===================================================================
--- /dev/null
+++ clang/test/Driver/Inputs/multilib_riscv32_elf_sdk/bin/riscv32-unknown-elf-gcc
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+print ("rv32iac/ilp32;@march=rv32iac@mabi=ilp32")
+print ("rv32imafc/ilp32f;@march=rv32iac@mabi=ilp32f")
+print ("rv64imafdc/lp64d;@march=rv64imafdc@mabi=lp64d")
Index: clang/lib/Driver/ToolChains/Gnu.h
===================================================================
--- clang/lib/Driver/ToolChains/Gnu.h
+++ clang/lib/Driver/ToolChains/Gnu.h
@@ -196,6 +196,7 @@
     // FIXME: These might be better as path objects.
     std::string GCCInstallPath;
     std::string GCCParentLibPath;
+    std::string GCCPath;
 
     /// The primary multilib appropriate for the given flags.
     Multilib SelectedMultilib;
@@ -229,6 +230,9 @@
     /// Get the detected GCC installation path.
     StringRef getInstallPath() const { return GCCInstallPath; }
 
+    /// Get the detected GCC executable path.
+    StringRef getGCCPath() const { return GCCPath; }
+
     /// Get the detected GCC parent lib path.
     StringRef getParentLibPath() const { return GCCParentLibPath; }
 
Index: clang/lib/Driver/ToolChains/Gnu.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Gnu.cpp
+++ clang/lib/Driver/ToolChains/Gnu.cpp
@@ -25,6 +25,7 @@
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/TargetParser.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include <system_error>
@@ -1583,10 +1584,187 @@
   return false;
 }
 
+static std::string findGCCPath(const Driver &D,
+                               llvm::StringRef BasePath)
+{
+  SmallString<128> GCCPath;
+  llvm::sys::path::append(GCCPath, BasePath, "bin",
+                          D.getTargetTriple() + "-gcc");
+  if (llvm::sys::fs::exists(GCCPath))
+    return GCCPath.str().str();
+  else
+    return "";
+}
+
+static std::string getGCCPath(const Driver &D,
+                              const ArgList &Args)
+{
+  llvm::StringRef GCCBasePath;
+  std::string GCCPath;
+
+  // Find GCC from -gcc-toolchain if given.
+  const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain);
+  if (A) {
+    GCCPath = findGCCPath(D, A->getValue());
+  } else {
+    // Try to find GCC from GCC_INSTALL_PREFIX if define.
+    llvm::StringRef GCCInstallPrefix = GCC_INSTALL_PREFIX;
+    if (!GCCInstallPrefix.empty())
+      GCCPath = findGCCPath(D, GCCInstallPrefix);
+    else {
+      // Try to find GCC from the same folder as driver.
+      SmallString<128> GCCBasePath;
+      llvm::sys::path::append(GCCBasePath, D.Dir, "..");
+      GCCPath = findGCCPath(D, GCCBasePath);
+    }
+  }
+
+  return GCCPath;
+}
+
+bool ScanGCCMultilibConfig(
+    const Driver &D,
+    const llvm::Triple &TargetTriple,
+    StringRef Path,
+    const ArgList &Args,
+    const std::string &MultilibOutput,
+    DetectedMultilibs &Result) {
+  llvm::StringSet<> AllABI;
+  llvm::StringSet<> AllArch;
+  llvm::StringSet<> AllMCmodel;
+  Multilib::flags_list Flags;
+
+  FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
+
+  // Get current ABI, Arch, and code model.
+  StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple);
+  StringRef MArch = tools::riscv::getRISCVArch(Args, TargetTriple);
+  StringRef CodeModel = tools::riscv::getRISCVCodeModel(Args);
+
+  // Turns it into option style, to make it able to compare
+  // to multi-lib option list.
+  std::string CurrentABIOpt = Twine("mabi=", ABIName).str();
+  std::string CurrentArchOpt = Twine("march=", MArch).str();
+  std::string CurrentMCmodelOpt =
+    llvm::StringSwitch<const char *>(CodeModel)
+          .Case("medium", "mcmodel=medany")
+          .Default("mcmodel=medlow");
+
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+      D.getVFS().getBufferForFile(MultilibOutput);
+  std::vector<Multilib> Ms;
+
+  if (File) {
+    SmallVector<StringRef, 128> Lines;
+    File.get()->getBuffer().split(Lines, "\n");
+    for (StringRef Line : Lines) {
+      if (Line.empty())
+        continue;
+      // Format for multi-lib:
+      // <path>;@opt1@opt2
+      // For example:
+      // rv32ec/ilp32e;@march=rv32ec@mabi=ilp32e
+      // -march=rv32ec and -mabi=ilp32e using rv32ec/ilp32e.
+      auto MultilibInfo = Line.split(';');
+      StringRef Path = MultilibInfo.first;
+
+      // Skip default multi-lib path.
+      // Clang has implied a default multi-lib rule there,
+      // so we don't need to add it manually.
+      if (Path == ".")
+        continue;
+
+      StringRef Options = MultilibInfo.second.substr(1);
+      SmallVector<StringRef, 2> OptionList;
+      Options.split(OptionList, '@');
+      // multilib path rule is ${march}/${mabi}
+      auto Multilib = makeMultilib(Path);
+      for (StringRef Option : OptionList) {
+        Multilib.flag(Twine("+", Option).str());
+
+        // Gather all used option from multi-lib config.
+        if (Option.startswith("march=")) {
+          if (!AllArch.contains(Option)) {
+            // Make sure every option we only process once
+            AllArch.insert(Option);
+            addMultilibFlag(CurrentArchOpt == Option,
+                            Option.str().c_str(), Flags);
+          }
+        } else if (Option.startswith("mabi=")) {
+          if (!AllABI.contains(Option)) {
+            AllABI.insert(Option);
+            addMultilibFlag(CurrentABIOpt == Option,
+                            Option.str().c_str(), Flags);
+          }
+        } else if (Option.startswith("mcmodel=")) {
+          if (!AllMCmodel.contains(Option)) {
+            AllMCmodel.insert(Option);
+            addMultilibFlag(CurrentMCmodelOpt == Option,
+                            Option.str().c_str(), Flags);
+          }
+        } else {
+          // Got unrecognized option in multi-lib config, fallback.
+          D.Diag(diag::warn_drv_multilib_fallback) << Option;
+          return false;
+        }
+      }
+      Ms.emplace_back(Multilib);
+    }
+  } else {
+    // Ooops, some thing wrong during open file, let's fallback.
+    return false;
+  }
+
+  MultilibSet RISCVMultilibs =
+      MultilibSet()
+          .FilterOut(NonExistent)
+          .Either(ArrayRef<Multilib>(Ms));
+
+  RISCVMultilibs.select(Flags, Result.SelectedMultilib);
+
+  Result.Multilibs = RISCVMultilibs;
+
+  return true;
+}
+
+
+static bool getMultilibFromGCC(const Driver &D,
+                               const llvm::Triple &TargetTriple,
+                               StringRef Path,
+                               const ArgList &Args,
+                               DetectedMultilibs &Result) {
+  // Try to find where is GCC.
+  std::string GCCPath = getGCCPath(D, Args);
+
+  // Not found? fallback to built-in multi-lib.
+  if (GCCPath.empty ())
+    return false;
+
+  // Ask GCC's multi-lib config via --print-multi-lib.
+  StringRef GCCArgs[] = {{GCCPath}, {"--print-multi-lib"}};
+  std::string MultilibOutput = D.GetTemporaryPath("gcc-output-", "");
+  Optional<StringRef> Redirects[] = {None, {MultilibOutput}, {""}};
+
+  int rc = llvm::sys::ExecuteAndWait(GCCPath, GCCArgs, None, Redirects);
+
+  // Any failed happen? let fallback to built-in multi-lib.
+  if (rc != 0)
+    return false;
+
+  // Parsing output of --print-multi-lib, and use that info to determine
+  // which multi-lib should be used.
+  return ScanGCCMultilibConfig(D, TargetTriple,
+                               Path, Args, MultilibOutput, Result);
+}
+
 static void findRISCVBareMetalMultilibs(const Driver &D,
                                         const llvm::Triple &TargetTriple,
                                         StringRef Path, const ArgList &Args,
                                         DetectedMultilibs &Result) {
+  // Try to get multilib from GCC first.
+  if (getMultilibFromGCC(D, TargetTriple, Path, Args, Result))
+    return;
+
   FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
   struct RiscvMultilib {
     StringRef march;
Index: clang/lib/Driver/ToolChains/Arch/RISCV.h
===================================================================
--- clang/lib/Driver/ToolChains/Arch/RISCV.h
+++ clang/lib/Driver/ToolChains/Arch/RISCV.h
@@ -26,6 +26,7 @@
                       const llvm::Triple &Triple);
 StringRef getRISCVArch(const llvm::opt::ArgList &Args,
                        const llvm::Triple &Triple);
+StringRef getRISCVCodeModel(const llvm::opt::ArgList &Args);
 } // end namespace riscv
 } // namespace tools
 } // end namespace driver
Index: clang/lib/Driver/ToolChains/Arch/RISCV.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -721,3 +721,15 @@
       return "rv64imafdc";
   }
 }
+
+StringRef riscv::getRISCVCodeModel(const llvm::opt::ArgList &Args)
+{
+  /* Default code model is small(medlow).  */
+  StringRef CodeModel;
+  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+    CodeModel = A->getValue();
+  else
+    CodeModel = "small";
+
+  return CodeModel;
+}
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -767,6 +767,7 @@
 def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
 def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">;
 def MisleadingIndentation : DiagGroup<"misleading-indentation">;
+def MultilibFallback : DiagGroup<"multilib-fallback">;
 
 // This covers both the deprecated case (in C++98)
 // and the extension case (in C++11 onwards).
Index: clang/include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -390,6 +390,11 @@
   "-ftest-module-file-extension argument '%0' is not of the required form "
   "'blockname:major:minor:hashed:user info'">;
 
+def warn_drv_multilib_fallback : Warning<
+  "%0 option unrecognized in multi-lib configuration when parsing config "
+  "from GCC, falling back to built-in multi-lib configuration.">,
+  InGroup<MultilibFallback>;
+
 def warn_slash_u_filename : Warning<"'/U%0' treated as the '/U' option">,
   InGroup<DiagGroup<"slash-u-filename">>;
 def note_use_dashdash : Note<"Use '--' to treat subsequent arguments as filenames">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to