components/llvm/patches/012-solaris-clang-libclangDriver.patch
author Shawn Walker-Salas <shawn.walker@oracle.com>
Wed, 08 Mar 2017 22:04:29 -0800
changeset 7771 46912a8a1f29
parent 6637 22d5f6c97e6f
permissions -rw-r--r--
25639599 llvm makefile cleanup and optimized build 25591626 clang on sparc fails with unhelpful "invalid gcc installation" error 22991663 llvm has unlisted build dependencies 25677424 llvm / openmp should be updated to use gcc5 25692651 some mysql test packages deliver build files

# 23701635 clang produces amd64 opcodes, but calls 32-bit assembler by default
# 23854357 clang should check for GNU ld
# 22778650 clang should support OpenMP because it can
# 24314745 clang should support PIE executables in Solaris
# 24378340 clang -fopenmp must include the path to the omp.h header file
# 24378393 clang -fopenmp must define _OPENMP to 201307
# 3.9.X for upstream.
--- tools/clang/include/clang/Driver/Options.td	2016-01-06 13:27:42.000000000 -0800
+++ tools/clang/include/clang/Driver/Options.td	2016-07-30 10:18:25.039779680 -0700
@@ -669,6 +669,9 @@
   Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)"
   " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">;
 
+def fabi_version_EQ : Joined<["-"], "fabi-version=">, Group<f_Group>,
+  Flags<[CC1Option]>, HelpText<"Use specified GNU C++ ABI version">;
+
 def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>;
 def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>;
 
@@ -959,11 +962,17 @@
 
 def fobjc_sender_dependent_dispatch : Flag<["-"], "fobjc-sender-dependent-dispatch">, Group<f_Group>;
 def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
-def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
-def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>, Flags<[NoArgumentUnused]>;
-def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>;
-def fopenmp_use_tls : Flag<["-"], "fopenmp-use-tls">, Group<f_Group>, Flags<[NoArgumentUnused]>;
-def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
+def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>,
+              Flags<[CC1Option]>, HelpText<"Enable OpenMP">;
+def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>,
+                 Flags<[CC1Option]>, HelpText<"Disable OpenMP">;
+def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>,
+                 Flags<[CC1Option]>,
+                 HelpText<"Use specified OpenMP Implementation">;
+def fopenmp_use_tls : Flag<["-"], "fopenmp-use-tls">, Group<f_Group>,
+                      Flags<[CC1Option]>, HelpText<"Use OpenMP TLS">;
+def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group<f_Group>,
+                        Flags<[CC1Option]>, HelpText<"Do not use OpenMP TLS">;
 def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
 def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;
 def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;
@@ -1312,6 +1321,12 @@
 def meabi : Separate<["-"], "meabi">, Group<m_Group>, Flags<[CC1Option]>,
   HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">;
 
+// SPARC-only options.
+def mvis : Flag<["-"], "mvis">, Group<m_Group>;
+def mvis2 : Flag<["-"], "mvis2">, Group<m_Group>;
+def mvis3 : Flag<["-"], "mvis3">, Group<m_Group>;
+def mimpure_text: Flag<["-"], "mimpure-text">, Group<m_Group>;
+
 def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>;
 def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>;
 def mno_3dnow : Flag<["-"], "mno-3dnow">, Group<m_x86_Features_Group>;
@@ -1954,6 +1969,7 @@
 
 def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group<clang_ignored_gcc_optimization_f_Group>;
 
+def fuse_as_EQ : Joined<["-"], "fuse-as=">, Group<f_Group>;
 def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>;
 
 defm align_functions : BooleanFFlag<"align-functions">, Group<clang_ignored_gcc_optimization_f_Group>;
###
--- tools/clang/lib/Driver/Multilib.cpp	2015-10-12 10:32:57.000000000 -0400
+++ tools/clang/lib/Driver/Multilib.cpp	2016-05-08 23:19:20.569431652 -0400
@@ -171,11 +171,11 @@
 }
 
 static Multilib compose(const Multilib &Base, const Multilib &New) {
-  SmallString<128> GCCSuffix;
+  SmallString<PATH_MAX> GCCSuffix;
   llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
-  SmallString<128> OSSuffix;
+  SmallString<PATH_MAX> OSSuffix;
   llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
-  SmallString<128> IncludeSuffix;
+  SmallString<PATH_MAX> IncludeSuffix;
   llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
                           New.includeSuffix());
 
###
--- tools/clang/lib/Driver/ToolChains.cpp	2016-02-16 11:56:48.000000000 -0800
+++ tools/clang/lib/Driver/ToolChains.cpp	2016-08-04 06:09:44.734198665 -0700
@@ -28,12 +28,15 @@
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/TargetParser.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cstdlib> // ::getenv
+#include <cstring>
+#include <cctype>
 #include <system_error>
 
 using namespace clang::driver;
@@ -41,6 +44,15 @@
 using namespace clang;
 using namespace llvm::opt;
 
+#if defined(LLVM_ON_UNIX)
+#include <cstring>
+#include <cctype>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#endif
+
 MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
     : ToolChain(D, Triple, Args) {
   // We expect 'as', 'ld', etc. to be adjacent to our install dir.
@@ -1347,6 +1359,11 @@
     // If we have a SysRoot, try that first.
     if (!D.SysRoot.empty()) {
       Prefixes.push_back(D.SysRoot);
+
+      // Add Solaris-specific GCC locations.
+      if (TargetTriple.getOS() == llvm::Triple::Solaris)
+        Prefixes.push_back("/usr/gcc");
+
       Prefixes.push_back(D.SysRoot + "/usr");
     }
 
@@ -1434,14 +1451,17 @@
   static const char *const ARMebHFTriples[] = {
       "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"};
 
-  static const char *const X86_64LibDirs[] = {"/lib64", "/lib"};
+  static const char *const X86_64LibDirs[] = {"/lib64", "/lib/amd64",
+                                               "/lib/64", "/lib"};
   static const char *const X86_64Triples[] = {
       "x86_64-linux-gnu",       "x86_64-unknown-linux-gnu",
       "x86_64-pc-linux-gnu",    "x86_64-redhat-linux6E",
       "x86_64-redhat-linux",    "x86_64-suse-linux",
       "x86_64-manbo-linux-gnu", "x86_64-linux-gnu",
       "x86_64-slackware-linux", "x86_64-linux-android",
-      "x86_64-unknown-linux"};
+      "x86_64-unknown-linux", "x86_64-pc-solaris2.11",
+      "x86_64-pc-solaris2.12", "x86_64-pc-solaris2.13" };
+
   static const char *const X32LibDirs[] = {"/libx32"};
   static const char *const X86LibDirs[] = {"/lib32", "/lib"};
   static const char *const X86Triples[] = {
@@ -1449,7 +1469,8 @@
       "i386-linux-gnu",       "i386-redhat-linux6E",   "i686-redhat-linux",
       "i586-redhat-linux",    "i386-redhat-linux",     "i586-suse-linux",
       "i486-slackware-linux", "i686-montavista-linux", "i686-linux-android",
-      "i586-linux-gnu"};
+      "i586-linux-gnu", "i386-pc-solaris2.11", "i386-pc-solaris2.12",
+      "i386-pc-solaris2.13" };
 
   static const char *const MIPSLibDirs[] = {"/lib"};
   static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux",
@@ -1483,30 +1504,28 @@
 
   static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"};
   static const char *const SPARCv8Triples[] = {"sparc-linux-gnu",
-                                               "sparcv8-linux-gnu"};
-  static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"};
+                                               "sparcv8-linux-gnu",
+                                               "sparc-sun-solaris2.11",
+                                               "sparc-sun-solaris2.12",
+                                               "sparc-sun-solaris2.13" };
+
+  static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib/sparcv9",
+                                                "/lib/64", "/lib" };
+
   static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu",
-                                               "sparcv9-linux-gnu"};
+                                               "sparcv9-linux-gnu",
+                                               "sparcv9-sun-solaris2.11",
+                                               "sparcv9-sun-solaris2.12",
+                                               "sparcv9-sun-solaris2.13"  };
 
   static const char *const SystemZLibDirs[] = {"/lib64", "/lib"};
   static const char *const SystemZTriples[] = {
       "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu",
       "s390x-suse-linux", "s390x-redhat-linux"};
 
-  // Solaris.
-  static const char *const SolarisSPARCLibDirs[] = {"/gcc"};
-  static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11",
-                                                    "i386-pc-solaris2.11"};
-
   using std::begin;
   using std::end;
 
-  if (TargetTriple.getOS() == llvm::Triple::Solaris) {
-    LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs));
-    TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples));
-    return;
-  }
-
   switch (TargetTriple.getArch()) {
   case llvm::Triple::aarch64:
     LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
@@ -3302,69 +3321,822 @@
 }
 
 /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
+bool Solaris::SupportsClangLibCPlusPlus = false;
 
 Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
-                 const ArgList &Args)
-    : Generic_GCC(D, Triple, Args) {
+                 const llvm::opt::ArgList &Args)
+  : Generic_ELF(D, Triple, Args),
+  UseGnuAs(true),
+  UseGnuLd(false),
+  UseGoldLd(false),
+  UseSunLd(true),
+  UseMediatedGCCToolChainPath(false),
+  UseSpecifiedGCCToolChainPath(false),
+  IsValid(false),
+  GCCInstallDir("/usr/gcc/"),
+  GCCMajor(""),
+  GCCMajorMinorMicro(""),
+  GCCInternalLibDir(""),
+  GCCInternalMultiLibDir(""),
+  GCCIncludeDirs(),
+  Assembler("/usr/gnu/bin/as"),
+  Linker("/usr/bin/ld"),
+  mtune(""),
+  march(""),
+  mcpu(""),
+  ExtraOpts() {
+    if (Arg *A = Args.getLastArg(options::OPT_gcc_toolchain)) {
+      GCCInstallDir = A->getValue();
+      if (!llvm::sys::fs::exists(GCCInstallDir))
+        D.Diag(diag::err_drv_no_such_file) << GCCInstallDir;
+      else {
+        findSpecifiedGCCToolchain(GCCInstallDir.c_str(), Triple, Args);
+
+        if (!UseSpecifiedGCCToolChainPath) {
+          D.Diag(diag::err_drv_unsupported_rtlib_for_platform)
+            << GCCInstallDir << Triple.getTriple();
+        } else {
+          findGCCIncludeDirs(Triple, Args);
+          findGCCInternalLibDir(Triple, Args);
+        }
+      }
+    } else {
+      findGCCMajor();
+      findGCCMajorMinorMicro(Triple);
+      findGCCIncludeDirs(Triple, Args);
+      findGCCInternalLibDir(Triple, Args);
+    }
+
+    if (Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
+      Linker = A->getValue();
+      if (Linker == "bfd")
+        Linker = "/usr/gnu/bin/ld";
+      else if (Linker == "gold")
+        Linker = "/usr/gnu/bin/ld.gold";
+
+      if ((Linker == "/usr/gnu/bin/ld") || (Linker == "/usr/gnu/bin/ld.bfd") ||
+          (Linker == "/usr/bin/gld") || (Linker == "/usr/bin/gld.bfd")) {
+        UseGnuLd = true;
+        UseGoldLd = false;
+        UseSunLd = false;
+      } else if ((Linker == "/usr/gnu/bin/ld.gold") ||
+                 (Linker == "/usr/bin/gld.gold") ||
+                 (Linker == "/usr/bin/ld.gold")) {
+        UseGnuLd = false;
+        UseSunLd = false;
+        UseGoldLd = true;
+      }
+    }
 
-  GCCInstallation.init(Triple, Args);
+    if (Arg *A = Args.getLastArg(options::OPT_fuse_as_EQ)) {
+      Assembler = A->getValue();
+      if (Assembler == "llvm")
+        UseGnuAs = false;
+      else if ((Assembler == "/usr/gnu/bin/as") ||
+               (Assembler == "/usr/bin/gas"))
+        UseGnuAs = true;
+      else if (Assembler == "gas") {
+        Assembler = "/usr/gnu/bin/as";
+        UseGnuAs = true;
+      } else if ((Assembler == "/usr/bin/as") || (Assembler == "sun") ||
+                 (Assembler == "solaris"))
+        D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+    }
 
-  path_list &Paths = getFilePaths();
-  if (GCCInstallation.isValid())
-    addPathIfExists(D, GCCInstallation.getInstallPath(), Paths);
+    getProgramPaths().push_back(GCCInstallDir);
 
-  addPathIfExists(D, getDriver().getInstalledDir(), Paths);
   if (getDriver().getInstalledDir() != getDriver().Dir)
-    addPathIfExists(D, getDriver().Dir, Paths);
+      getProgramPaths().push_back(getDriver().Dir);
 
-  addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib", Paths);
+    llvm::Triple::ArchType Arch = Triple.getArch();
 
-  std::string LibPath = "/usr/lib/";
-  switch (Triple.getArch()) {
+    switch (Arch) {
   case llvm::Triple::x86:
+      getFilePaths().push_back(getDriver().Dir + "/../lib");
+      getFilePaths().push_back("/usr/lib");
+      march = mtune = "i686";
+      break;
   case llvm::Triple::sparc:
+      getFilePaths().push_back(getDriver().Dir + "/../lib");
+      getFilePaths().push_back("/usr/lib");
+      mcpu = "ultrasparc";
+      mtune = "ultrasparc";
+      march = "v8plusa";
     break;
   case llvm::Triple::x86_64:
-    LibPath += "amd64/";
+      getFilePaths().push_back(getDriver().Dir + "/../lib/amd64");
+      getFilePaths().push_back("/usr/lib/amd64");
+      march = mtune = "opteron";
     break;
   case llvm::Triple::sparcv9:
-    LibPath += "sparcv9/";
+      getFilePaths().push_back(getDriver().Dir + "/../lib/sparcv9");
+      getFilePaths().push_back("/usr/lib/sparcv9");
+      mcpu = "ultrasparc";
+      mtune = "ultrasparc";
+      march = "v9a";
     break;
   default:
-    llvm_unreachable("Unsupported architecture");
+      getFilePaths().push_back(getDriver().Dir + "/../lib");
+      getFilePaths().push_back("/usr/lib");
+      break;
   }
 
-  addPathIfExists(D, getDriver().SysRoot + LibPath, Paths);
+    validate();
+
+    if (Args.hasArg(options::OPT_v))
+      this->print(llvm::errs());
 }
 
-Tool *Solaris::buildAssembler() const {
-  return new tools::solaris::Assembler(*this);
+std::string Solaris::computeSysRoot() const {
+  if (!getDriver().SysRoot.empty())
+    return getDriver().SysRoot;
+
+  return std::string("/");
 }
 
-Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); }
+bool
+Solaris::addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
+                                  StringRef GCCTriple,
+                                  StringRef GCCMultiarchTriple,
+                                  StringRef TargetMultiarchTriple,
+                                  Twine IncludeSuffix,
+                                  const llvm::opt::ArgList &DriverArgs,
+                                  llvm::opt::ArgStringList &CC1Args) const {
+  if (!llvm::sys::fs::exists(Base + Suffix))
+    return false;
+
+  addSystemInclude(DriverArgs, CC1Args, Base);
+  addSystemInclude(DriverArgs, CC1Args, Base + Suffix);
 
-void Solaris::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
-                                           ArgStringList &CC1Args) const {
+  if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) ||
+      llvm::sys::fs::exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) {
+    addSystemInclude(DriverArgs,
+                     CC1Args, Base + Suffix + "/" + GCCTriple + IncludeSuffix);
+  } else {
+    addSystemInclude(DriverArgs, CC1Args,
+                     Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix);
+    addSystemInclude(DriverArgs, CC1Args,
+                     Base + "/" + TargetMultiarchTriple + Suffix);
+  }
+
+  if (DriverArgs.hasArg(options::OPT_fopenmp) ||
+      DriverArgs.hasArg(options::OPT_fopenmp_EQ)) {
+    addSystemInclude(DriverArgs, CC1Args, "/usr/include/iomp5");
+  }
+
+  addSystemInclude(DriverArgs, CC1Args, Base + "/backward");
+  addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward");
+  return true;
+}
+
+void
+Solaris::AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                                      llvm::opt::ArgStringList &CC1Args) const {
   if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
       DriverArgs.hasArg(options::OPT_nostdincxx))
     return;
 
-  // Include the support directory for things like xlocale and fudged system
-  // headers.
-  addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/v1/support/solaris");
+  const Driver &D = getDriver();
 
-  if (GCCInstallation.isValid()) {
-    GCCVersion Version = GCCInstallation.getVersion();
-    addSystemInclude(DriverArgs, CC1Args,
-                     getDriver().SysRoot + "/usr/gcc/" +
-                     Version.MajorStr + "." +
-                     Version.MinorStr +
-                     "/include/c++/" + Version.Text);
-    addSystemInclude(DriverArgs, CC1Args,
-                     getDriver().SysRoot + "/usr/gcc/" + Version.MajorStr +
-                     "." + Version.MinorStr + "/include/c++/" +
-                     Version.Text + "/" +
-                     GCCInstallation.getTriple().str());
+  // Check for Clang libc++
+  if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) {
+    if (!Solaris::SupportsClangLibCPlusPlus) {
+      D.Diag(diag::err_drv_invalid_stdlib_name) << "libc++";
+      return;
+    }
+
+    StringRef IncludePath = "/usr/include/libc++/v1";
+    if (!llvm::sys::fs::exists(IncludePath)) {
+      D.Diag(diag::err_drv_no_such_file) << IncludePath;
+      return;
+    }
+
+    addSystemInclude(DriverArgs, CC1Args, IncludePath);
+    return;
+  }
+
+  for (std::vector<std::string>::const_iterator B =
+       getGCCIncludeDirs().begin(), E = getGCCIncludeDirs().end();
+       B != E; ++B) {
+    llvm::Twine IncludePath((*B));
+    addSystemInclude(DriverArgs, CC1Args, IncludePath);
+  }
+}
+
+void
+Solaris::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+                                   ArgStringList &CC1Args) const {
+  const Driver &D = getDriver();
+
+  if (DriverArgs.hasArg(options::OPT_nostdinc))
+    return;
+
+  std::string SysRoot = computeSysRoot();
+
+  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+    SmallString<PATH_MAX> P(D.ResourceDir);
+    llvm::sys::path::append(P, "/include");
+    addSystemInclude(DriverArgs, CC1Args, P.str());
+  }
+
+  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+    return;
+
+  StringRef CIncludeDirs(C_INCLUDE_DIRS);
+  if (CIncludeDirs != "") {
+    SmallVector<StringRef, 5> dirs;
+    CIncludeDirs.split(dirs, ":");
+    for (SmallVectorImpl<StringRef>::iterator I = dirs.begin(), E = dirs.end();
+         I != E; ++I) {
+      StringRef Prefix =
+        llvm::sys::path::is_absolute(*I) ? StringRef(SysRoot) : "";
+      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + *I);
+    }
+  }
+
+  if (DriverArgs.hasArg(options::OPT_fopenmp) ||
+      DriverArgs.hasArg(options::OPT_fopenmp_EQ))
+    addSystemInclude(DriverArgs, CC1Args, "/usr/include/iomp5");
+
+  addExternCSystemInclude(DriverArgs, CC1Args, "/usr/include");
+}
+
+void
+Solaris::addClangTargetOptions(const ArgList &DriverArgs,
+                               ArgStringList &CC1Args) const {
+  const llvm::Triple& TT = getTriple();
+  llvm::Triple::ArchType Arch = TT.getArch();
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array))
+    DriverArgs.ClaimAllArgs(options::OPT_fuse_init_array);
+
+  // Always use .init_array/.fini_array on Solaris. The Solaris
+  // linker can't do .ctors/.dtors or .init/.fini for that matter.
+  CC1Args.push_back("-fuse-init-array");
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_fabi_version_EQ)) {
+    StringRef V = A->getValue();
+    if (!V.empty()) {
+      std::string fabi_version = "-fabi-version=";
+      fabi_version += V.str();
+      CC1Args.push_back(DriverArgs.MakeArgString(fabi_version.c_str()));
+    } else {
+      std::string fabi_version = "-fabi-version=4";
+      CC1Args.push_back(DriverArgs.MakeArgString(fabi_version.c_str()));
+    }
+  } else {
+    CC1Args.push_back(DriverArgs.MakeArgString("-fabi-version=4"));
+  }
+
+  DriverArgs.ClaimAllArgs(options::OPT_fabi_version_EQ);
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_fopenmp))
+    CC1Args.push_back(DriverArgs.MakeArgString("-fopenmp"));
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_fno_openmp))
+    CC1Args.push_back(DriverArgs.MakeArgString("-fno-openmp"));
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_fopenmp_EQ)) {
+    std::string V = A->getValue();
+    if (V != "libiomp5") {
+      const Driver &D = getDriver();
+      D.Diag(diag::err_drv_unsupported_opt) << V.c_str();
+    }
+
+    std::string fompeq="-fopenmp=";
+    fompeq += V;
+    CC1Args.push_back(DriverArgs.MakeArgString(fompeq.c_str()));
+  }
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_fopenmp_use_tls))
+    CC1Args.push_back(DriverArgs.MakeArgString("-fopenmp-use-tls"));
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_fnoopenmp_use_tls))
+    CC1Args.push_back(DriverArgs.MakeArgString("-fnoopenmp-use-tls"));
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_fopenmp_is_device)) {
+    CC1Args.push_back(DriverArgs.MakeArgString("-fopenmp-is-device"));
+  }
+
+  if (Arch == llvm::Triple::sparc || Arch == llvm::Triple::sparcv9) {
+    CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+    CC1Args.push_back(DriverArgs.MakeArgString("+hwcap"));
+  }
+
+  if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
+    if (Arg *A = DriverArgs.getLastArg(options::OPT_fomit_frame_pointer))
+      CC1Args.push_back(DriverArgs.MakeArgString("-fomit-frame-pointer"));
+
+    if (Arg *A = DriverArgs.getLastArg(options::OPT_fno_omit_frame_pointer))
+      CC1Args.push_back(DriverArgs.MakeArgString("-fno-omit-frame-pointer"));
+  }
+
+  bool SeenVIS = false;
+  bool SeenVIS2 = false;
+  bool SeenVIS3 = false;
+
+  bool DoneVIS = false;
+  bool DoneVIS2 = false;
+  bool DoneVIS3 = false;
+
+  bool DoneMTune = false;
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_mtune_EQ)) {
+    StringRef V = A->getValue();
+    if (!V.empty())
+      mtune = V.str();
+    else
+      mtune = "ultrasparc";
+
+    if (Arch == llvm::Triple::sparc || Arch == llvm::Triple::sparcv9) {
+      if ((mtune == "ultrasparc") || (mtune == "ultrasparc2") ||
+          (mtune == "vis")) {
+        SeenVIS = true;
+      } else if ((mtune == "ultrasparc3") || (mtune == "vis2")) {
+        SeenVIS = true;
+        SeenVIS2 = true;
+      } else {
+        SeenVIS = true;
+        SeenVIS2 = true;
+        SeenVIS3 = true;
+      }
+
+      if (!DoneMTune) {
+        if (SeenVIS3 && !DoneVIS3) {
+          CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+          CC1Args.push_back(DriverArgs.MakeArgString("+vis3"));
+          DoneVIS3 = true;
+          DoneVIS2 = true;
+          DoneVIS = true;
+        }
+
+        if (SeenVIS2 && !DoneVIS2) {
+          CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+          CC1Args.push_back(DriverArgs.MakeArgString("+vis2"));
+          DoneVIS2 = true;
+          DoneVIS = true;
+        }
+
+        if (SeenVIS && !DoneVIS) {
+          CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+          CC1Args.push_back(DriverArgs.MakeArgString("+vis"));
+          DoneVIS = true;
+        }
+
+        DoneMTune = true;
+      }
+    }
+  }
+
+  if (Arch == llvm::Triple::sparc || Arch == llvm::Triple::sparcv9) {
+    if (Arg *A = DriverArgs.getLastArg(options::OPT_mvis)) {
+      SeenVIS = !DoneVIS;
+      if (!DoneVIS) {
+        CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+        CC1Args.push_back(DriverArgs.MakeArgString("+vis"));
+        DoneVIS = true;
+      }
+    }
+
+    if (Arg *A = DriverArgs.getLastArg(options::OPT_mvis2)) {
+      SeenVIS2 = !DoneVIS2;
+      if (!DoneVIS2) {
+        CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+        CC1Args.push_back(DriverArgs.MakeArgString("+vis2"));
+        DoneVIS2 = true;
+        DoneVIS = true;
+      }
+    }
+
+    if (Arg *A = DriverArgs.getLastArg(options::OPT_mvis3)) {
+      SeenVIS3 = !DoneVIS3;
+      if (!DoneVIS3) {
+        CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+        CC1Args.push_back(DriverArgs.MakeArgString("+vis3"));
+        DoneVIS3 = true;
+        DoneVIS2 = true;
+        DoneVIS = true;
+      }
+    }
+  }
+}
+
+void
+Solaris::findGCCMajor() const {
+  static const char* const GCCMM[] = { "5" };
+
+  const char* P;
+  std::string Path;
+
+  Path.reserve(std::string::size_type(PATH_MAX));
+
+  for (int I = (llvm::array_lengthof(GCCMM) - 1); I >= 0; --I) {
+    if ((P = GCCMM[I]) != NULL) {
+      Path = GCCInstallDir;
+      Path.append(P);
+      Path.append("/");
+
+      if (llvm::sys::fs::exists(Path.c_str())) {
+        GCCMajor = P;
+        break;
+      }
+    }
+  }
+}
+
+void
+Solaris::findGCCMajorMinorMicro(const llvm::Triple& T) const {
+  static const char* const GCCMMM[] = { "5.4.0" };
+
+  const char* P;
+  std::string Path;
+  std::string TripleString = llvm::sys::getDefaultTargetTriple();
+  llvm::Triple::ArchType Arch = T.getArch();
+
+  // GCC4 on Solaris is multilib 32/64.
+  // GCC5+ on Solaris is multilib 64/32.
+  if (GCCMajor[0] == '5') {
+    if (TripleString.find("i386") != std::string::npos)
+      TripleString.replace(0U, 4U, std::string("x86_64"));
+    else if (TripleString.find("sparc-") != std::string::npos)
+      TripleString.replace(0U, 6U, std::string("sparcv9-"));
+  }
+
+  Path.reserve(std::string::size_type(PATH_MAX));
+
+  for (int I = (llvm::array_lengthof(GCCMMM) - 1); I >= 0; --I) {
+    if ((P = GCCMMM[I]) != NULL) {
+      if (P[0] == GCCMajor[0]) {
+        Path = GCCInstallDir;
+        Path.append("/");
+        Path.append(GCCMajor);
+        Path.append("/lib/gcc/");
+        Path.append(TripleString);
+        Path.append("/");
+        Path.append(P);
+
+        if (llvm::sys::fs::exists(Path.c_str())) {
+          std::string Test;
+          // Check if this is a real GCC installation and not just
+          // an empty directory tree
+          switch (Arch) {
+          case llvm::Triple::x86_64:
+          case llvm::Triple::sparcv9:
+            Test = Path + "/crtbegin.o";
+            break;
+          case llvm::Triple::x86:
+            Test = Path + "/32/crtbegin.o";
+            break;
+          case llvm::Triple::sparc:
+            Test = Path + "/32/crtbegin.o";
+            break;
+          default:
+            break;
+          }
+
+          if (llvm::sys::fs::exists(Test.c_str())) {
+            GCCMajorMinorMicro = P;
+            break;
+          }
+        }
+      }
+    }
+  }
+}
+
+void
+Solaris::findSpecifiedGCCToolchain(const char *StartingPath,
+                                   const llvm::Triple &Triple,
+                                   const llvm::opt::ArgList &Args) const {
+  DIR *TopLD = 0;
+  DIR *LibLD = 0;
+  DIR *GccLD = 0;
+  DIR *TripleLD = 0;
+  struct dirent *TopDE = 0;
+  struct dirent *LibDE = 0;
+  struct dirent *GccDE = 0;
+  struct dirent *TripleDE = 0;
+  std::string LibDir;
+  std::string GccDir;
+  std::string TripleDir;
+  std::string TripleVersionDir;
+  const char *DName;
+
+  assert(StartingPath && "Invalid GCC Toolchain starting search path!");
+
+  GCCMajor = "";
+  GCCMajorMinorMicro = "";
+  UseSpecifiedGCCToolChainPath = false;
+
+  LibDir.reserve(std::string::size_type(PATH_MAX));
+  GccDir.reserve(std::string::size_type(PATH_MAX));
+  TripleDir.reserve(std::string::size_type(PATH_MAX));
+  TripleVersionDir.reserve(std::string::size_type(PATH_MAX));
+
+  if (llvm::sys::fs::exists(StartingPath) &&
+      llvm::sys::fs::is_directory(StartingPath)) {
+    TopLD = opendir(StartingPath);
+    assert(TopLD && "Cannot obtain a valid toplevel DIR handle!");
+
+    while ((TopDE = readdir(TopLD)) != NULL) {
+      if (TopDE->d_name[0] == '.')
+        continue;
+
+      DName = static_cast<const char*>(&TopDE->d_name[0]);
+      if (std::strcmp(DName, "lib") == 0) {
+        LibDir = StartingPath;
+        LibDir.append("/");
+        LibDir.append(DName);
+
+        if (!llvm::sys::fs::is_directory(LibDir.c_str()))
+          continue;
+
+        LibLD = opendir(LibDir.c_str());
+        assert(LibLD && "Could not obtain a valid lib DIR handle!");
+
+        while ((LibDE = readdir(LibLD)) != NULL) {
+          if (LibDE->d_name[0] == '.')
+            continue;
+
+          DName = static_cast<const char*>(&LibDE->d_name[0]);
+          if (std::strcmp(DName, "gcc") == 0) {
+            GccDir = LibDir;
+            GccDir.append("/");
+            GccDir.append(DName);
+
+            if (!llvm::sys::fs::is_directory(GccDir.c_str()))
+              continue;
+
+            GccLD = opendir(GccDir.c_str());
+            assert(GccLD && "Could not obtain a valid gcc DIR handle!");
+
+            while ((GccDE = readdir(GccLD)) != NULL) {
+              if (GccDE->d_name[0] == '.')
+                continue;
+
+              DName = static_cast<const char*>(&GccDE->d_name[0]);
+              TripleDir = GccDir;
+              TripleDir.append("/");
+              TripleDir.append(DName);
+
+              if (!llvm::sys::fs::is_directory(TripleDir.c_str()))
+                continue;
+
+              if ((std::strncmp(DName, "sparc", 5) == 0) ||
+                  (std::strncmp(DName, "i386", 4) == 0) ||
+                  (std::strncmp(DName, "sparcv9", 7) == 0) ||
+                  (std::strncmp(DName, "x86_64", 6) == 0)) {
+                TripleLD = opendir(TripleDir.c_str());
+                assert(TripleLD &&
+                       "Could not obtain a valid Triple DIR handle!");
+
+                while ((TripleDE = readdir(TripleLD)) != NULL) {
+                  if (TripleDE->d_name[0] == '.')
+                    continue;
+
+                  DName = static_cast<const char*>(&TripleDE->d_name[0]);
+                  TripleVersionDir = TripleDir;
+                  TripleVersionDir.append("/");
+                  TripleVersionDir.append(DName);
+
+                  if (!llvm::sys::fs::is_directory(TripleVersionDir.c_str()))
+                    continue;
+
+                  if ((std::isdigit(DName[0])) && (DName[1] == '.') &&
+                      (std::isdigit(DName[2])) && (DName[3] == '.') &&
+                      (std::isdigit(DName[4])) && (DName[5] == '\0')) {
+                    GCCMajorMinorMicro = DName;
+                    GCCMajor = GCCMajorMinorMicro.substr(0, 1);
+                    UseSpecifiedGCCToolChainPath = true;
+                    goto done;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+done:
+  if (TripleLD) {
+    rewinddir(TripleLD);
+    closedir(TripleLD);
+  }
+
+  if (GccLD) {
+    rewinddir(GccLD);
+    closedir(GccLD);
+  }
+
+  if (LibLD) {
+    rewinddir(LibLD);
+    closedir(LibLD);
+  }
+
+  if (TopLD) {
+    rewinddir(TopLD);
+    closedir(TopLD);
+  }
+}
+
+void
+Solaris::findGCCIncludeDirs(const llvm::Triple &Triple,
+                            const llvm::opt::ArgList &Args) const {
+  std::string GCCInstallPath;
+  if (UseSpecifiedGCCToolChainPath)
+    GCCInstallPath = GCCInstallDir;
+  else
+    GCCInstallPath = GCCInstallDir + GCCMajor;
+
+  std::string GCCIncludeDir =
+    GCCInstallPath + "/include/c++/" + GCCMajorMinorMicro;
+  GCCIncludeDirs.push_back(GCCIncludeDir);
+
+  llvm::Triple::ArchType Arch = Triple.getArch();
+  GCCIncludeDir += "/";
+
+  switch (Arch) {
+  case llvm::Triple::x86_64:
+    GCCIncludeDir += Triple.getTriple();
+    if (Args.getLastArg(options::OPT_m32))
+      GCCIncludeDir += "/32";
+    break;
+  case llvm::Triple::sparcv9:
+    GCCIncludeDir += Triple.getTriple();
+    if (Args.getLastArg(options::OPT_m32))
+      GCCIncludeDir += "/32";
+    break;
+  case llvm::Triple::x86:
+    GCCIncludeDir += "x86_64-pc-";
+    GCCIncludeDir += Triple.getOSName();
+    if (Args.getLastArg(options::OPT_m32))
+      GCCIncludeDir += "/32";
+    break;
+  case llvm::Triple::sparc:
+    GCCIncludeDir += "sparcv9-sun-";
+    GCCIncludeDir += Triple.getOSName();
+    if (Args.getLastArg(options::OPT_m32))
+      GCCIncludeDir += "/32";
+    break;
+  default:
+    getDriver().Diag(diag::err_target_unsupported_arch)
+      << Triple.getArchName() << Triple.getTriple();
+    break;
+  }
+
+  GCCIncludeDirs.push_back(GCCIncludeDir);
+
+  GCCIncludeDir = GCCInstallPath + "/include/c++/" +
+    GCCMajorMinorMicro + "/backward";
+
+  GCCIncludeDirs.push_back(GCCIncludeDir);
+}
+
+void
+Solaris::findGCCInternalLibDir(const llvm::Triple &Triple,
+                               const llvm::opt::ArgList &Args) const {
+  std::string GCCInstallPath;
+  if (UseSpecifiedGCCToolChainPath)
+    GCCInstallPath = GCCInstallDir;
+  else
+    GCCInstallPath = GCCInstallDir + GCCMajor;
+
+  GCCInternalLibDir = GCCInstallPath + "/lib/gcc/";
+
+  llvm::Triple::ArchType Arch = Triple.getArch();
+
+  switch (Arch) {
+  case llvm::Triple::x86_64:
+    GCCInternalLibDir += Triple.getTriple();
+    GCCInternalLibDir += "/";
+    GCCInternalLibDir += GCCMajorMinorMicro;
+    if (Args.getLastArg(options::OPT_m64)) {
+      GCCInternalMultiLibDir = GCCInternalLibDir + "/32";
+    } else if (Args.getLastArg(options::OPT_m32)) {
+      GCCInternalMultiLibDir = GCCInternalLibDir;
+      GCCInternalLibDir += "/32";
+    } else {
+      GCCInternalMultiLibDir = GCCInternalLibDir + "/32";
+    }
+
+    break;
+  case llvm::Triple::sparcv9:
+    GCCInternalLibDir += Triple.getTriple();
+    GCCInternalLibDir += "/";
+    GCCInternalLibDir += GCCMajorMinorMicro;
+    if (Args.getLastArg(options::OPT_m64)) {
+      GCCInternalMultiLibDir = GCCInternalLibDir + "/32";
+    } else if (Args.getLastArg(options::OPT_m32)) {
+      GCCInternalMultiLibDir = GCCInternalLibDir;
+      GCCInternalLibDir += "/32";
+    } else {
+      GCCInternalMultiLibDir = GCCInternalLibDir + "/32";
+    }
+    break;
+  case llvm::Triple::x86:
+    GCCInternalLibDir += "x86_64-pc-";
+    GCCInternalLibDir += Triple.getOSName();
+    GCCInternalLibDir += "/";
+    GCCInternalLibDir += GCCMajorMinorMicro;
+    GCCInternalMultiLibDir = GCCInternalLibDir;
+    if (Args.getLastArg(options::OPT_m64))
+      GCCInternalMultiLibDir += "/32";
+    else if (Args.getLastArg(options::OPT_m32))
+      GCCInternalLibDir += "/32";
+    else
+      GCCInternalMultiLibDir += "/32";
+    break;
+  case llvm::Triple::sparc:
+    GCCInternalLibDir += "sparcv9-sun-";
+    GCCInternalLibDir += Triple.getOSName();
+    GCCInternalLibDir += "/";
+    GCCInternalLibDir += GCCMajorMinorMicro;
+    GCCInternalMultiLibDir = GCCInternalLibDir;
+    if (Args.getLastArg(options::OPT_m64))
+      GCCInternalMultiLibDir += "/32";
+    else if (Args.getLastArg(options::OPT_m32))
+      GCCInternalLibDir += "/32";
+    else
+      GCCInternalMultiLibDir += "/32";
+    break;
+  default:
+    getDriver().Diag(diag::err_target_unsupported_arch)
+      << Triple.getArchName() << Triple.getTriple();
+    break;
+  }
+}
+
+
+void
+Solaris::print(raw_ostream &OS) const {
+  OS << "UseGnuAs: " << (UseGnuAs ? "true" : "false") << "\n";
+  OS << "UseGnuLd: " << (UseGnuLd ? "true" : "false") << "\n";
+  OS << "UseGoldLd: " << (UseGoldLd ? "true" : "false") << "\n";
+  OS << "UseSunLd: " << (UseSunLd ? "true" : "false") << "\n";
+  OS << "UseMediatedGCCToolChainPath: "
+    << (UseMediatedGCCToolChainPath ? "true" : "false") << "\n";
+  OS << "UseSpecifiedGCCToolChainPath: "
+    << (UseSpecifiedGCCToolChainPath ? "true" : "false") << "\n";
+  OS << "GCCInstallDir: " << GCCInstallDir.c_str() << "\n";
+  OS << "GCCMajor: " << GCCMajor.c_str() << "\n";
+  OS << "GCCMajorMinorMicro: " << GCCMajorMinorMicro.c_str() << "\n";
+  OS << "GCCInternalLibDir: " << GCCInternalLibDir.c_str() << "\n";
+  OS << "GCCInternalMultiLibDir: " << GCCInternalMultiLibDir.c_str() << "\n";
+  OS << "GCCIncludeDirs: ";
+
+  if (GCCIncludeDirs.size()) {
+    std::string IncludePath;
+    for (std::vector<std::string>::const_iterator B = GCCIncludeDirs.begin(),
+         E = GCCIncludeDirs.end(); B != E; ++B) {
+      IncludePath = "-I";
+      IncludePath += (*B);
+      OS << IncludePath.c_str() << " ";
+    }
+
+    OS << "\n";
+  }
+
+  OS << "Assembler: " << Assembler.c_str() << "\n";
+  OS << "Linker: " << Linker.c_str() << "\n";
+  OS << "mtune: " << mtune.c_str() << "\n";
+  OS << "march: " << march.c_str() << "\n";
+  OS << "mcpu: " << mcpu.c_str() << "\n";
+
+  if (ExtraOpts.size()) {
+    OS << "ExtraOpts: ";
+    for (std::vector<std::string>::const_iterator B = ExtraOpts.begin(),
+         E = ExtraOpts.end(); B != E; ++B) {
+      OS << (*B).c_str() << " ";
+    }
+
+    OS << "\n";
+  }
+
+  OS << "Valid: " << (IsValid ? "true" : "false") << "\n";
+}
+
+Tool *Solaris::buildAssembler() const {
+  return new tools::solaris::Assembler(*this);
+}
+
+Tool *Solaris::buildLinker() const {
+  return new tools::solaris::Linker(*this);
+}
+
+void Solaris::validate() {
+  IsValid = llvm::sys::fs::exists(GCCInstallDir.c_str());
+  if (!IsValid) return;
+  IsValid = llvm::sys::fs::exists(GCCInternalLibDir.c_str());
+  if (!IsValid) return;
+  IsValid = llvm::sys::fs::exists(GCCInternalMultiLibDir.c_str());
+  if (!IsValid) return;
+
+  for (std::vector<std::string>::const_iterator B = GCCIncludeDirs.begin(),
+       E = GCCIncludeDirs.end(); B != E; ++B) {
+    IsValid = llvm::sys::fs::exists((*B).c_str());
+    if (!IsValid) return;
   }
 }
 
@@ -3404,6 +4182,27 @@
   UbuntuVivid,
   UbuntuWily,
   UbuntuXenial,
+  Solaris_11,
+  Solaris_11_1,
+  Solaris_11_2,
+  Solaris_11_3,
+  Solaris_11_4,
+  Solaris_11_5,
+  Solaris_11_6,
+  Solaris_11_7,
+  Solaris_11_8,
+  Solaris_11_9,
+  Solaris_12,
+  Solaris_12_1,
+  Solaris_12_2,
+  Solaris_12_3,
+  Solaris_12_4,
+  Solaris_12_5,
+  Solaris_12_6,
+  Solaris_12_7,
+  Solaris_12_8,
+  Solaris_12_9,
+  Solaris_13,
   UnknownDistro
 };
 
@@ -3421,6 +4220,10 @@
   return Distro >= UbuntuHardy && Distro <= UbuntuXenial;
 }
 
+static bool IsSolaris(enum Distro Distro) {
+  return Distro >= Solaris_11 && Distro <= Solaris_13;
+}
+
 static Distro DetectDistro(const Driver &D, llvm::Triple::ArchType Arch) {
   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
       llvm::MemoryBuffer::getFile("/etc/lsb-release");
@@ -3488,6 +4291,59 @@
     return UnknownDistro;
   }
 
+  File = llvm::MemoryBuffer::getFile("/etc/release");
+  if (File) {
+    StringRef Data = File.get()->getBuffer();
+    SmallVector<StringRef, 8> Lines;
+    Data.split(Lines, "\n");
+    for (unsigned I = 0, S = Lines.size(); I != S; ++I) {
+      if (Lines[I].find("Oracle Solaris") != std::string::npos) {
+        if (Lines[I].find("Solaris 11.0") != std::string::npos)
+          return Solaris_11;
+        else if (Lines[I].find("Solaris 11.1") != std::string::npos)
+          return Solaris_11_1;
+        else if (Lines[I].find("Solaris 11.2") != std::string::npos)
+          return Solaris_11_2;
+        else if (Lines[I].find("Solaris 11.3") != std::string::npos)
+          return Solaris_11_3;
+        else if (Lines[I].find("Solaris 11.4") != std::string::npos)
+          return Solaris_11_4;
+        else if (Lines[I].find("Solaris 11.5") != std::string::npos)
+          return Solaris_11_5;
+        else if (Lines[I].find("Solaris 11.6") != std::string::npos)
+          return Solaris_11_6;
+        else if (Lines[I].find("Solaris 11.7") != std::string::npos)
+          return Solaris_11_7;
+        else if (Lines[I].find("Solaris 11.8") != std::string::npos)
+          return Solaris_11_8;
+        else if (Lines[I].find("Solaris 11.9") != std::string::npos)
+          return Solaris_11_9;
+        else if (Lines[I].find("Solaris 12.0") != std::string::npos)
+          return Solaris_12;
+        else if (Lines[I].find("Solaris 12.1") != std::string::npos)
+          return Solaris_12_1;
+        else if (Lines[I].find("Solaris 12.2") != std::string::npos)
+          return Solaris_12_2;
+        else if (Lines[I].find("Solaris 12.3") != std::string::npos)
+          return Solaris_12_3;
+        else if (Lines[I].find("Solaris 12.4") != std::string::npos)
+          return Solaris_12_4;
+        else if (Lines[I].find("Solaris 12.5") != std::string::npos)
+          return Solaris_12_5;
+        else if (Lines[I].find("Solaris 12.6") != std::string::npos)
+          return Solaris_12_6;
+        else if (Lines[I].find("Solaris 12.7") != std::string::npos)
+          return Solaris_12_7;
+        else if (Lines[I].find("Solaris 12.8") != std::string::npos)
+          return Solaris_12_8;
+        else if (Lines[I].find("Solaris 12.9") != std::string::npos)
+          return Solaris_12_9;
+      }
+    }
+
+    return UnknownDistro;
+  }
+
   if (D.getVFS().exists("/etc/SuSE-release"))
     return OpenSUSE;
 
###
--- tools/clang/lib/Driver/ToolChains.h	2016-02-16 14:56:48.000000000 -0500
+++ tools/clang/lib/Driver/ToolChains.h	2016-05-08 23:19:20.571431701 -0400
@@ -615,24 +615,111 @@
   Tool *buildLinker() const override;
 };
 
-class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
+class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_ELF {
 public:
   Solaris(const Driver &D, const llvm::Triple &Triple,
           const llvm::opt::ArgList &Args);
 
-  bool IsIntegratedAssemblerDefault() const override { return true; }
+  bool IsIntegratedAssemblerDefault() const override { return !UseGnuAs; }
 
-  void AddClangCXXStdlibIncludeArgs(
-      const llvm::opt::ArgList &DriverArgs,
-      llvm::opt::ArgStringList &CC1Args) const override;
+  std::string computeSysRoot() const;
 
-  unsigned GetDefaultDwarfVersion() const override { return 2; }
+  bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
+                                StringRef GCCTriple,
+                                StringRef GCCMultiarchTriple,
+                                StringRef TargetMultiarchTriple,
+                                Twine IncludeSuffix,
+                                const llvm::opt::ArgList &DriverArgs,
+                                llvm::opt::ArgStringList &CC1Args) const;
+
+  void addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
+                                const llvm::opt::ArgList &DriverArgs,
+                                llvm::opt::ArgStringList &CC1Args) const;
+
+  void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                                    llvm::opt::ArgStringList &CC1Args) const override;
+
+  void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                                 llvm::opt::ArgStringList &CC1Args) const override;
+
+  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+                             llvm::opt::ArgStringList &CC1Args) const override;
+
+  void findGCCMajor() const;
+  void findGCCMajorMinorMicro(const llvm::Triple &Triple) const;
+  void findGCCIncludeDirs(const llvm::Triple &Triple,
+                          const llvm::opt::ArgList &Args) const;
+  void findGCCInternalLibDir(const llvm::Triple &Triple,
+                             const llvm::opt::ArgList &Args) const;
+  void findSpecifiedGCCToolchain(const char *StartingPath,
+                                 const llvm::Triple &Triple,
+                                 const llvm::opt::ArgList &Args) const;
+
+  StringRef getAssembler() const { return Assembler.c_str(); }
+  StringRef getLinker() const { return Linker.c_str(); }
+  StringRef getGCCInstallDir() const { return GCCInstallDir.c_str(); }
+  StringRef getGCCMajor() const { return GCCMajor.c_str(); }
+  StringRef getMArch() const { return march.c_str(); }
+  StringRef getMTune() const { return mtune.c_str(); }
+  StringRef getMCpu() const { return mcpu.c_str(); }
+  StringRef getGCCInternalLibDir() const { return GCCInternalLibDir; }
+
+  StringRef getGCCInternalMultiLibDir() const {
+    return GCCInternalMultiLibDir;
+  }
+
+  StringRef getGCCMajorMinorMicro() const {
+    return GCCMajorMinorMicro.c_str();
+  }
+
+  const std::vector<std::string> &getGCCIncludeDirs() const {
+    return GCCIncludeDirs;
+  }
+
+  const std::vector<std::string> &getExtraOpts() const {
+    return ExtraOpts;
+  }
+
+  bool isValid() const { return IsValid; }
+
+  void print(raw_ostream &OS) const;
+
+  unsigned GetDefaultDwarfVersion() const override { return 4; }
 
 protected:
   Tool *buildAssembler() const override;
   Tool *buildLinker() const override;
+  void validate();
+
+private:
+  bool UseGnuAs;
+  bool UseGnuLd;
+  bool UseGoldLd;
+  bool UseSunLd;
+  mutable bool UseMediatedGCCToolChainPath;
+  mutable bool UseSpecifiedGCCToolChainPath;
+  bool IsValid;
+
+protected:
+  mutable std::string GCCInstallDir;
+  mutable std::string GCCMajor;
+  mutable std::string GCCMajorMinorMicro;
+  mutable std::string GCCInternalLibDir;
+  mutable std::string GCCInternalMultiLibDir;
+  mutable std::vector<std::string> GCCIncludeDirs;
+
+  mutable std::string Assembler;
+  mutable std::string Linker;
+  mutable std::string mtune;
+  mutable std::string march;
+  mutable std::string mcpu;
+
+  mutable std::vector<std::string> ExtraOpts;
+  static const char *MediatedGCCToolChainPath;
+  static bool SupportsClangLibCPlusPlus;
 };
 
+
 class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain {
 public:
   MinGW(const Driver &D, const llvm::Triple &Triple,
###
--- tools/clang/lib/Driver/Tools.cpp	2016-02-12 14:51:41.000000000 -0800
+++ tools/clang/lib/Driver/Tools.cpp	2016-08-04 06:17:07.826616905 -0700
@@ -43,15 +43,22 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/TargetParser.h"
 
-#ifdef LLVM_ON_UNIX
-#include <unistd.h> // For getuid().
-#endif
-
 using namespace clang::driver;
 using namespace clang::driver::tools;
 using namespace clang;
 using namespace llvm::opt;
 
+#ifdef LLVM_ON_UNIX
+#include <unistd.h> // For getuid().
+#endif
+
+#include <cstdlib>
+#include <climits>
+
+static std::tuple<llvm::Reloc::Model, unsigned, bool>
+ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple,
+             const ArgList &Args);
+
 static void handleTargetFeaturesGroup(const ArgList &Args,
                                       std::vector<const char *> &Features,
                                       OptSpecifier Group) {
@@ -74,11 +81,15 @@
                                          const llvm::Triple &Triple) {
   if (Triple.getArch() == llvm::Triple::sparcv9) {
     return llvm::StringSwitch<const char *>(Name)
+          .Case("v9", "-Av9")
+          .Case("ultrasparc", "-Av9a")
+          .Case("ultrasparc2", "-Av9a")
+          .Case("ultrasparc3", "-Av9b")
           .Case("niagara", "-Av9b")
           .Case("niagara2", "-Av9b")
           .Case("niagara3", "-Av9d")
           .Case("niagara4", "-Av9d")
-          .Default("-Av9");
+          .Default("-Av9a");
   } else {
     return llvm::StringSwitch<const char *>(Name)
           .Case("v8", "-Av8")
@@ -89,17 +100,23 @@
           .Case("sparclite86x", "-Asparclite")
           .Case("sparclet", "-Asparclet")
           .Case("tsc701", "-Asparclet")
-          .Case("v9", "-Av8plus")
-          .Case("ultrasparc", "-Av8plus")
-          .Case("ultrasparc3", "-Av8plus")
+          .Case("ultrasparc", "-Av8plusa")
+          .Case("ultrasparc2", "-Av8plusa")
+          .Case("ultrasparc3", "-Av8plusb")
           .Case("niagara", "-Av8plusb")
           .Case("niagara2", "-Av8plusb")
           .Case("niagara3", "-Av8plusd")
           .Case("niagara4", "-Av8plusd")
-          .Default("-Av8");
+          .Default("-Av8plusa");
   }
 }
 
+static void AddLibgcc(const llvm::Triple &Triple, const Driver &D,
+                      ArgStringList &CmdArgs, const ArgList &Args);
+
+static void AddLibgcc(const Driver &D, ArgStringList &CmdArgs,
+                      const ArgList &Args, const std::string& Exec);
+
 /// CheckPreprocessingOptions - Perform some validation of preprocessing
 /// arguments that is shared with gcc.
 static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
@@ -266,6 +283,27 @@
     addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
 }
 
+static void AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args,
+                             ArgStringList &CmdArgs) {
+  llvm::Reloc::Model RelocationModel;
+  unsigned PICLevel = 1;
+  bool IsPIE = false;
+
+  std::tie(RelocationModel, PICLevel, IsPIE) =
+    ParsePICArgs(ToolChain, ToolChain.getTriple(), Args);
+
+  if (ToolChain.getTriple().getOS() == llvm::Triple::Solaris) {
+    if ((RelocationModel != llvm::Reloc::Static) &&
+        (RelocationModel != llvm::Reloc::DynamicNoPIC))
+      CmdArgs.push_back("-KPIC");
+
+    return;
+  }
+
+  if (RelocationModel != llvm::Reloc::Static)
+    CmdArgs.push_back("-KPIC");
+}
+
 /// \brief Determine whether Objective-C automated reference counting is
 /// enabled.
 static bool isObjCAutoRefCount(const ArgList &Args) {
@@ -1601,8 +1639,127 @@
   }
 }
 
-static const char *getX86TargetCPU(const ArgList &Args,
-                                   const llvm::Triple &Triple) {
+const char *sparc::getSparcTargetCPU(const llvm::opt::ArgList &Args,
+                                     const llvm::Triple &Triple) {
+  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+    StringRef AV = A->getValue();
+    if (AV == "native") {
+      std::string CPU = llvm::sys::getHostCPUName().str();
+      if (CPU.find("UltraSPARC-IV") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9c" : "v8plusc";
+      else if (CPU.find("UltraSPARC-III") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+      else if (CPU.find("UltraSPARC-II") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9a" : "v8plusa";
+      else if (CPU.find("UltraSPARC-I") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9" : "v8plus";
+      else if (CPU.find("SPARC-T4") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9v" : "v8plusv";
+      else if (CPU.find("SPARC-T5") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9v" : "v8plusv";
+      else if (CPU.find("SPARC-T6") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9v" : "v8plusv";
+      else if (CPU.find("SPARC-T7") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9v" : "v8plusv";
+      else if (CPU.find("SPARC-M4") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9v" : "v8plusv";
+      else if (CPU.find("SPARC-M5") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9m" : "v8plusm";
+      else if (CPU.find("SPARC-M6") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9m" : "v8plusm";
+      else if (CPU.find("SPARC-M7") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9m" : "v8plusm";
+    } else if (AV == "ultrasparc") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9a" : "v8plusa";
+    } else if (AV == "ultrasparc2") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9a" : "v8plusa";
+    } else if (AV == "ultrasparc3") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "ultrasparc4") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9c" : "v8plusc";
+    } else if (AV == "niagara") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "niagara2") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "niagara3") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "niagara4") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "sparc4") {
+      return "sparc4";
+    } else if (AV == "sparc5") {
+      return "sparc5";
+    } else if (AV == "generic") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9a" : "v8plusa";
+    } else if (AV == "generic32") {
+      return "v8plusa";
+    } else if (AV == "generic64") {
+      return "v9a";
+    }
+  }
+
+  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+    StringRef AV = A->getValue();
+    if (AV == "native") {
+      std::string CPU = llvm::sys::getHostCPUName().str();
+      if (CPU.find("UltraSPARC-IV") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9c" : "v8plusc";
+      else if (CPU.find("UltraSPARC-III") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+      else if (CPU.find("UltraSPARC-II") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9a" : "v8plusa";
+      else if (CPU.find("UltraSPARC-I") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9" : "v8plus";
+      else if (CPU.find("SPARC-T4") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9v" : "v8plusv";
+      else if (CPU.find("SPARC-T5") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9m" : "v8plusm";
+      else if (CPU.find("SPARC-T6") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9m" : "v8plusm";
+      else if (CPU.find("SPARC-T7") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9m" : "v8plusm";
+      else if (CPU.find("SPARC-M4") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9v" : "v8plusv";
+      else if (CPU.find("SPARC-M5") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9m" : "v8plusm";
+      else if (CPU.find("SPARC-M6") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9m" : "v8plusm";
+      else if (CPU.find("SPARC-M7") != std::string::npos)
+        return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9m" : "v8plusm";
+    } else if (AV == "ultrasparc") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9a" : "v8plusa";
+    } else if (AV == "ultrasparc2") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9a" : "v8plusa";
+    } else if (AV == "ultrasparc3") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "ultrasparc4") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9c" : "v8plusc";
+    } else if (AV == "niagara") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "niagara2") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "niagara3") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "niagara4") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9b" : "v8plusb";
+    } else if (AV == "sparc4") {
+      return "sparc4";
+    } else if (AV == "sparc5") {
+      return "sparc5";
+    } else if (AV == "generic") {
+      return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9a" : "v8plusa";
+    } else if (AV == "generic32") {
+      return "v8plusa";
+    } else if (AV == "generic64") {
+      return "v9a";
+    }
+  }
+
+  return Triple.getArch() == llvm::Triple::sparcv9 ?  "v9a" : "v8plusa";
+}
+
+const char *x86::getX86TargetCPU(const llvm::opt::ArgList &Args,
+                                 const llvm::Triple &Triple) {
   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
     if (StringRef(A->getValue()) != "native") {
       if (Triple.isOSDarwin() && Triple.getArchName() == "x86_64h")
@@ -1616,7 +1773,7 @@
     //
     // FIXME: We should also incorporate the detected target features for use
     // with -native.
-    std::string CPU = llvm::sys::getHostCPUName();
+    std::string CPU = llvm::sys::getHostCPUName().str();
     if (!CPU.empty() && CPU != "generic")
       return Args.MakeArgString(CPU);
   }
@@ -1666,6 +1823,10 @@
   if (Triple.isAndroid())
     return Is64Bit ? "x86-64" : "i686";
 
+  // On Solaris return a target compatible with gas.
+  if (Triple.isOSSolaris())
+    return Is64Bit ? "opteron" : "pentium4";
+
   // Everything else goes to x86-64 in 64-bit mode.
   if (Is64Bit)
     return "x86-64";
@@ -1757,15 +1918,17 @@
   }
 
   case llvm::Triple::sparc:
-  case llvm::Triple::sparcel:
   case llvm::Triple::sparcv9:
+    return sparc::getSparcTargetCPU(Args, T);
+
+  case llvm::Triple::sparcel:
     if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
       return A->getValue();
     return "";
 
   case llvm::Triple::x86:
   case llvm::Triple::x86_64:
-    return getX86TargetCPU(Args, T);
+    return x86::getX86TargetCPU(Args, T);
 
   case llvm::Triple::hexagon:
     return "hexagon" +
@@ -3084,7 +3247,7 @@
 
 // Fallback to user id.
 #ifdef LLVM_ON_UNIX
-  std::string UID = llvm::utostr(getuid());
+  std::string UID = std::to_string(static_cast<unsigned int>(getuid()));
 #else
   // FIXME: Windows seems to have an 'SID' that might work.
   std::string UID = "9999";
@@ -3263,10 +3426,12 @@
   // ToolChain.getTriple() and Triple?
   bool PIE = ToolChain.isPIEDefault();
   bool PIC = PIE || ToolChain.isPICDefault();
+
   // The Darwin/MachO default to use PIC does not apply when using -static.
   if (ToolChain.getTriple().isOSBinFormatMachO() &&
       Args.hasArg(options::OPT_static))
     PIE = PIC = false;
+
   bool IsPICLevelTwo = PIC;
 
   bool KernelOrKext =
@@ -3320,6 +3485,24 @@
     }
   }
 
+  // Solaris-specific defaults for PIE
+  if (ToolChain.getTriple().getOS() == llvm::Triple::Solaris) {
+    switch (ToolChain.getTriple().getArch()) {
+    case llvm::Triple::x86:
+      IsPICLevelTwo = false; // "-fpie"
+      break;
+    case llvm::Triple::sparc:
+    case llvm::Triple::x86_64:
+    case llvm::Triple::sparcv9:
+      IsPICLevelTwo = true; // "-fPIE"
+      break;
+
+    default:
+      break;
+    }
+  }
+
+
   // The last argument relating to either PIC or PIE wins, and no
   // other argument is used. If the last argument is any flavor of the
   // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE
@@ -3336,8 +3519,8 @@
       if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) ||
           O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) {
         PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie);
-        PIC =
-            PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic);
+        PIC = PIE || O.matches(options::OPT_fPIC) ||
+          O.matches(options::OPT_fpic);
         IsPICLevelTwo =
             O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC);
       } else {
@@ -3367,10 +3550,37 @@
                        !Triple.isWatchOS()))
     PIC = PIE = false;
 
+  if (ToolChain.getTriple().getOS() == llvm::Triple::Solaris) {
+    unsigned PICLevel = IsPICLevelTwo ? 2 : 1;
+    if (Arg *A = Args.getLastArg(options::OPT_shared)) {
+      PIC = true;
+      PIE = false;
+      return std::make_tuple(llvm::Reloc::PIC_, PICLevel, PIE);
+    } else if (PIE) {
+      PIC = PIE = true;
+      return std::make_tuple(llvm::Reloc::PIC_, PICLevel, PIE);
+    } else if (PIC) {
+      PIC = true;
+      PIE = IsPICLevelTwo;
+      return std::make_tuple(llvm::Reloc::PIC_, PICLevel, PIE);
+    } else if (Args.hasArg(options::OPT_static)) {
+      // Solaris doesn't to static relocations.
+      PIC = PIE = false;
+      return std::make_tuple(llvm::Reloc::DynamicNoPIC, PICLevel, PIE);
+    } else {
+      // This is a Solaris non-PIE executable.
+      // Solaris doesn't to static relocations.
+      PIC = PIE = false;
+      PICLevel = 0;
+      return std::make_tuple(llvm::Reloc::DynamicNoPIC, PICLevel, PIE);
+    }
+  }
+
   if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) {
     // This is a very special mode. It trumps the other modes, almost no one
     // uses it, and it isn't even valid on any OS but Darwin.
-    if (!ToolChain.getTriple().isOSDarwin())
+    if (!ToolChain.getTriple().isOSDarwin() &&
+        !ToolChain.getTriple().isOSSolaris())
       ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
           << A->getSpelling() << ToolChain.getTriple().str();
 
@@ -3404,18 +3614,6 @@
   llvm_unreachable("Unknown Reloc::Model kind");
 }
 
-static void AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args,
-                             ArgStringList &CmdArgs) {
-  llvm::Reloc::Model RelocationModel;
-  unsigned PICLevel;
-  bool IsPIE;
-  std::tie(RelocationModel, PICLevel, IsPIE) =
-      ParsePICArgs(ToolChain, ToolChain.getTriple(), Args);
-
-  if (RelocationModel != llvm::Reloc::Static)
-    CmdArgs.push_back("-KPIC");
-}
-
 void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                          const InputInfo &Output, const InputInfoList &Inputs,
                          const ArgList &Args, const char *LinkingOutput) const {
@@ -3713,6 +3911,14 @@
     CmdArgs.push_back(A->getValue());
   }
 
+  if (Arg *A = Args.getLastArg(options::OPT_fabi_version_EQ)) {
+    StringRef V = A->getValue();
+    CmdArgs.push_back(Args.MakeArgString("-fabi-version=" + V));
+    A->claim();
+  } else {
+    CmdArgs.push_back(Args.MakeArgString("-fabi-version=4"));
+  }
+
   if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return,
                                options::OPT_freg_struct_return)) {
     if (getToolChain().getArch() != llvm::Triple::x86) {
@@ -4522,6 +4728,7 @@
     // If -fmessage-length=N was not specified, determine whether this is a
     // terminal and, if so, implicitly define -fmessage-length appropriately.
     unsigned N = llvm::sys::Process::StandardErrColumns();
+    if (N == 0U) N = 72U;
     CmdArgs.push_back(Args.MakeArgString(Twine(N)));
   }
 
@@ -4707,6 +4914,10 @@
   if (Args.hasArg(options::OPT_mstack_alignment)) {
     StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
     CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
+  } else {
+    if ((getToolChain().getArch() == llvm::Triple::sparc) ||
+        (getToolChain().getArch() == llvm::Triple::sparcv9))
+      CmdArgs.push_back("-mstack-alignment=16");
   }
 
   if (Args.hasArg(options::OPT_mstack_probe_size)) {
@@ -4963,16 +5174,16 @@
   }
 
   // -fuse-cxa-atexit is default.
-  if (!Args.hasFlag(
+  if ((!Args.hasFlag(
           options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
           !IsWindowsCygnus && !IsWindowsGNU &&
-              getToolChain().getTriple().getOS() != llvm::Triple::Solaris &&
               getToolChain().getArch() != llvm::Triple::hexagon &&
               getToolChain().getArch() != llvm::Triple::xcore &&
               ((getToolChain().getTriple().getVendor() !=
                 llvm::Triple::MipsTechnologies) ||
                getToolChain().getTriple().hasEnvironment())) ||
-      KernelOrKext)
+      KernelOrKext) &&
+      !getToolChain().getTriple().getOS() == llvm::Triple::Solaris)
     CmdArgs.push_back("-fno-use-cxa-atexit");
 
   // -fms-extensions=0 is default.
@@ -5425,8 +5636,10 @@
   // nice to enable this when doing a crashdump for modules as well.
   if (Args.hasFlag(options::OPT_frewrite_includes,
                    options::OPT_fno_rewrite_includes, false) ||
-      (C.isForDiagnostics() && !HaveModules))
+      (C.isForDiagnostics() && !HaveModules)) {
+    if (getToolChain().getTriple().getOS() != llvm::Triple::Solaris)
     CmdArgs.push_back("-frewrite-includes");
+  }
 
   // Only allow -traditional or -traditional-cpp outside in preprocessing modes.
   if (Arg *A = Args.getLastArg(options::OPT_traditional,
@@ -6155,7 +6368,10 @@
     CmdArgs.push_back("-fsyntax-only");
   }
 
-  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+                       options::OPT_Xassembler);
+  Args.ClaimAllArgs(options::OPT_Wa_COMMA);
+  Args.ClaimAllArgs(options::OPT_Xassembler);
 
   // Only pass -x if gcc will understand it; otherwise hope gcc
   // understands the suffix correctly. The main use case this would go
@@ -7383,44 +7599,362 @@
   claimNoWarnArgs(Args);
   ArgStringList CmdArgs;
 
-  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+  const toolchains::Solaris &TC =
+    static_cast<const toolchains::Solaris&>(getToolChain());
+
+  if (!TC.isValid()) {
+    llvm::errs() << "Invalid GCC installation!\n";
+    return;
+  }
 
+  std::string EffectiveTriple = TC.ComputeLLVMTriple(Args, types::ID(0));
+  llvm::Triple ET(EffectiveTriple);
+
+  const Driver &D = TC.getDriver();
+  llvm::Triple::ArchType Arch = ET.getArch();
+  StringRef AS = TC.getAssembler();
+  bool m32 = !!Args.getLastArg(options::OPT_m32);
+
+  std::string march;
+  std::string mtune;
+  std::string mcpu;
+
+  if (Arg *A = Args.getLastArg(options::OPT_march_EQ))
+    march = A->getValue();
+  else
+    march = TC.getMArch();
+
+  if (Arg *A = Args.getLastArg(options::OPT_mtune_EQ))
+    mtune = A->getValue();
+  else
+    mtune = TC.getMTune();
+
+  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+    mcpu = A->getValue();
+  else
+    mcpu = TC.getMCpu();
+
+  if (Args.hasArg(options::OPT_v))
+    CmdArgs.push_back("-V");
+
+  switch (Arch) {
+  case llvm::Triple::x86:
+  case llvm::Triple::x86_64:
+    if (m32)
+      CmdArgs.push_back("--32");
+    else
+      CmdArgs.push_back("--64");
+    break;
+  case llvm::Triple::sparc:
+  case llvm::Triple::sparcv9:
+    if (m32) {
+      CmdArgs.push_back("-32");
+      if (march.empty())
+        march="v8plusa";
+      if (mcpu.empty())
+        mcpu="v8plusa";
+    } else {
+      CmdArgs.push_back("-64");
+      if (march.empty())
+        march="v9a";
+      if (mcpu.empty())
+        mcpu="v9a";
+    }
+    break;
+  default:
+    D.Diag(diag::err_target_unsupported_arch) << ET.getArchName()
+      << ET.getTriple();
+    break;
+  }
+
+  std::string xarch;
+
+  switch (Arch) {
+  case llvm::Triple::sparc:
+  case llvm::Triple::sparcv9:
+    xarch = "-xarch=";
+    xarch += clang::driver::tools::sparc::getSparcTargetCPU(Args, ET);
+    CmdArgs.push_back(Args.MakeArgString(xarch.c_str()));
+    AddAssemblerKPIC(TC, Args, CmdArgs);
+    CmdArgs.push_back("-no-undeclared-regs");
+    if (Args.hasArg(options::OPT_mstrict_align))
+      CmdArgs.push_back("--enforce-aligned-data");
+    break;
+  case llvm::Triple::x86:
+  case llvm::Triple::x86_64:
+    xarch = "-march=";
+    xarch += clang::driver::tools::x86::getX86TargetCPU(Args, ET);
+    CmdArgs.push_back(Args.MakeArgString(xarch.c_str()));
+    break;
+  default:
+    D.Diag(diag::err_target_unsupported_arch) << ET.getArchName()
+      << ET.getTriple();
+    break;
+  }
+
+  if (Args.hasArg(options::OPT_g_Flag) || Args.hasArg(options::OPT_g0) ||
+      Args.hasArg(options::OPT_g1) || Args.hasArg(options::OPT_g2) ||
+      Args.hasArg(options::OPT_g3))
+    CmdArgs.push_back("--gen-debug");
+
+  if (Output.isFilename()) {
   CmdArgs.push_back("-o");
   CmdArgs.push_back(Output.getFilename());
+  } else {
+    D.Diag(diag::err_drv_invalid_gcc_output_type) << "<unspecified>";
+    CmdArgs.push_back("-fsyntax-only");
+  }
 
-  for (const auto &II : Inputs)
+  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+                       options::OPT_Xassembler);
+
+  for (const auto &II : Inputs) {
+    if (II.isFilename())
     CmdArgs.push_back(II.getFilename());
+    else
+      II.getInputArg().render(Args, CmdArgs);
+  }
 
-  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+  const char *Exec = AS.data();
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
 }
 
+void
+solaris::Assembler::RenderExtraToolArgs(const JobAction &JA,
+                                        llvm::opt::ArgStringList &CmdArgs) const {
+  // FIXME: IMPLEMENT
+}
+
+bool solaris::Linker::checkGnuLd(StringRef Path) const {
+  if (Path.empty()) return false;
+
+  char Buf[_POSIX_PATH_MAX+1];
+  std::string CMD = Path.str();
+  CMD += " -v 2>&1";
+
+  std::FILE *FP = ::popen(CMD.c_str(), "r");
+  if (!FP) return false;
+
+  (void) std::memset(Buf, 0, sizeof(Buf));
+  (void) std::fgets(Buf, _POSIX_PATH_MAX, FP);
+  ::pclose(FP);
+
+  return !!std::strstr(Buf, "GNU");
+}
+
 void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
                                    const InputInfo &Output,
                                    const InputInfoList &Inputs,
                                    const ArgList &Args,
                                    const char *LinkingOutput) const {
+  const toolchains::Solaris& TC =
+    static_cast<const toolchains::Solaris&>(getToolChain());
+
+  if (!TC.isValid()) {
+    llvm::errs() << "Invalid GCC installation!\n";
+    return;
+  }
+
+  llvm::Triple TT = TC.getTriple();
+  std::string EffectiveTriple = TC.ComputeLLVMTriple(Args, types::ID(0));
+  llvm::Triple ET(EffectiveTriple);
+
+  const Driver &D = TC.getDriver();
+  llvm::Triple::ArchType Arch = TT.getArch();
+  bool m32 = !!Args.getLastArg(options::OPT_m32);
+
+  StringRef LD = TC.getLinker();
+  bool UseGnuLd = checkGnuLd(LD);
+
+  std::string GCCLibPath;
+  std::string YPPath;
+  GCCLibPath += "/lib/gcc/";
+  std::string LibPath = "/usr/lib/";
+  std::string ShortLibPath = "/lib/";
+  std::string ClangLibPath;
+  const char* moption;
+  std::string gldm;
+
+  if (UseGnuLd) {
+    switch (Arch) {
+    case llvm::Triple::x86:
+      if (m32)
+        gldm = "elf_i386_sol2";
+      else
+        gldm = "elf_x86_64_sol2";
+      break;
+    case llvm::Triple::x86_64:
+      if (m32)
+        gldm = "elf_i386_sol2";
+      else
+        gldm = "elf_x86_64_sol2";
+      break;
+    case llvm::Triple::sparc:
+      if (m32)
+        gldm = "elf32_sparc_sol2";
+      else
+        gldm = "elf64_sparc_sol2";
+      break;
+    case llvm::Triple::sparcv9:
+      if (m32)
+        gldm = "elf32_sparc_sol2";
+      else
+        gldm = "elf64_sparc_sol2";
+      break;
+    default:
+      break;
+    }
+  }
+
+  switch (Arch) {
+  case llvm::Triple::x86:
+    if (m32) {
+      GCCLibPath = TC.getGCCInternalLibDir().str();
+      GCCLibPath += "/";
+      moption = "-32";
+      YPPath = "/lib:/usr/lib";
+      ClangLibPath = "/usr/lib/clang/";
+    } else {
+      GCCLibPath = TC.getGCCInternalLibDir().str();
+      GCCLibPath += "/";
+      LibPath += "amd64/";
+      ShortLibPath += "amd64/";
+      moption = "-64";
+      YPPath = "/lib/amd64:/usr/lib/amd64";
+      ClangLibPath = "/usr/lib/amd64/clang/";
+    }
+    break;
+  case llvm::Triple::sparc:
+    if (m32) {
+      GCCLibPath = TC.getGCCInternalLibDir().str();
+      GCCLibPath += "/";
+      moption = "-32";
+      YPPath = "/lib:/usr/lib";
+      ClangLibPath = "/usr/lib/clang/";
+    } else {
+      GCCLibPath = TC.getGCCInternalLibDir().str();
+      GCCLibPath += "/";
+      LibPath += "sparcv9/";
+      ShortLibPath += "sparcv9/";
+      moption = "-64";
+      YPPath = "/lib/sparcv9:/usr/lib/sparcv9";
+      ClangLibPath = "/usr/lib/sparcv9/clang/";
+    }
+    break;
+  case llvm::Triple::x86_64:
+    if (m32) {
+      GCCLibPath = TC.getGCCInternalLibDir().str();
+      GCCLibPath += "/";
+      moption = "-32";
+      YPPath = "/lib:/usr/lib";
+      ClangLibPath = "/usr/lib/clang/";
+    } else {
+      GCCLibPath = TC.getGCCInternalLibDir().str();
+      GCCLibPath += "/";
+      LibPath += "amd64/";
+      ShortLibPath += "amd64/";
+      moption = "-64";
+      YPPath = "/lib/amd64:/usr/lib/amd64";
+      ClangLibPath = "/usr/lib/amd64/clang/";
+    }
+    break;
+  case llvm::Triple::sparcv9:
+    if (m32) {
+      GCCLibPath = TC.getGCCInternalLibDir().str();
+      GCCLibPath += "/";
+      moption = "-32";
+      YPPath = "/lib:/usr/lib";
+      ClangLibPath = "/usr/lib/clang/";
+    } else {
+      GCCLibPath = TC.getGCCInternalLibDir().str();
+      GCCLibPath += "/";
+      LibPath += "sparcv9/";
+      ShortLibPath += "sparcv9/";
+      moption = "-64";
+      YPPath = "/lib/sparcv9:/usr/lib/sparcv9";
+      ClangLibPath = "/usr/lib/sparcv9/clang/";
+    }
+    break;
+  default:
+    D.Diag(diag::err_target_unsupported_arch) << ET.getArchName()
+      << ET.getTriple();
+    break;
+  }
+
   ArgStringList CmdArgs;
 
-  // Demangle C++ names in errors
-  CmdArgs.push_back("-C");
+  // THe -m flag to GNU ld is positional dependent.
+  // Do not change this ordering of options for the GNU ld.
+  if (!gldm.empty()) {
+    CmdArgs.push_back(Args.MakeArgString("-m"));
+    CmdArgs.push_back(Args.MakeArgString(gldm.c_str()));
+  }
 
-  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
-    CmdArgs.push_back("-e");
-    CmdArgs.push_back("_start");
+  if (UseGnuLd) {
+    if (Args.hasArg(options::OPT_v))
+      CmdArgs.push_back(Args.MakeArgString("-v"));
+    CmdArgs.push_back(Args.MakeArgString("--as-needed"));
+  } else {
+    if (D.CCCIsCXX())
+      CmdArgs.push_back(Args.MakeArgString("-zrelax=comdat"));
   }
 
+  Arg *PIEArg = Args.getLastArg(options::OPT_fPIE, options::OPT_fpie);
+  if (PIEArg) {
+    if (PIEArg->getOption().matches(options::OPT_fPIE) ||
+        PIEArg->getOption().matches(options::OPT_fpie)) {
+      CmdArgs.push_back(Args.MakeArgString("-Qy"));
+
+      if (UseGnuLd) {
+        CmdArgs.push_back(Args.MakeArgString("--pic-executable"));
+      } else {
+        CmdArgs.push_back(Args.MakeArgString("-zdirect"));
+        CmdArgs.push_back(Args.MakeArgString("-ztextwarn"));
+        CmdArgs.push_back(Args.MakeArgString("-ztype=pie"));
+        CmdArgs.push_back(Args.MakeArgString("-zaslr=enable"));
+      }
+    }
+  }
+
+  // Silence 'argument not used during compilation: -g' warning.
+  Args.ClaimAllArgs(options::OPT_g_Group);
+
+  // Silence 'argument unused during compilation: -pthread' warning.
+  Args.ClaimAllArgs(options::OPT_pthread);
+
+  // Language options
+  Args.ClaimAllArgs(options::OPT_emit_llvm);
+  Args.ClaimAllArgs(options::OPT_w);
+
+  if (Args.hasArg(options::OPT_s))
+    CmdArgs.push_back("-s");
+
+  const std::vector<std::string> &ExtraOpts = TC.getExtraOpts();
+
+  // Handle extra options
+  if (ExtraOpts.size()) {
+    for (std::vector<std::string>::const_iterator I = ExtraOpts.begin(),
+         E = ExtraOpts.end(); I != E; ++I)
+      CmdArgs.push_back((*I).c_str());
+  }
+
+  // Demangle C++ names
+  if (UseGnuLd)
+    CmdArgs.push_back("--demangle");
+  else
+    CmdArgs.push_back("-C");
+
   if (Args.hasArg(options::OPT_static)) {
     CmdArgs.push_back("-Bstatic");
     CmdArgs.push_back("-dn");
   } else {
     CmdArgs.push_back("-Bdynamic");
+    CmdArgs.push_back("-dy");
     if (Args.hasArg(options::OPT_shared)) {
       CmdArgs.push_back("-shared");
     } else {
       CmdArgs.push_back("--dynamic-linker");
-      CmdArgs.push_back(
-          Args.MakeArgString(getToolChain().GetFilePath("ld.so.1")));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + "ld.so.1"));
     }
   }
 
@@ -7431,48 +7965,268 @@
     assert(Output.isNothing() && "Invalid output.");
   }
 
-  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
-    if (!Args.hasArg(options::OPT_shared))
-      CmdArgs.push_back(
-          Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
+  const char* Values = "values-Xa.o";
+  const char* Xpg = "values-xpg4.o";
 
-    CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
-    CmdArgs.push_back(
-        Args.MakeArgString(getToolChain().GetFilePath("values-Xa.o")));
-    CmdArgs.push_back(
-        Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+  Arg *STDArg = Args.getLastArg(options::OPT_std_EQ);
+  if (STDArg) {
+    if (STDArg->getOption().matches(options::OPT_std_EQ)) {
+      std::string Lang = STDArg->getValue();
+      if ((Lang == "c99") || (Lang == "c11") ||
+          (Lang == "c++11") || (Lang == "c++14")) {
+        Values = "values-Xc.o";
+        Xpg = "values-xpg6.o";
+      }
+    }
   }
 
-  getToolChain().AddFilePathLibArgs(Args, CmdArgs);
+  if (UseGnuLd) {
+    if (LD == "/usr/gnu/bin/ld.gold") {
+      if (Args.hasArg(options::OPT_O))
+        Args.AddAllArgs(CmdArgs, options::OPT_O);
+    } else
+      CmdArgs.push_back(Args.MakeArgString("-O"));
+  }
 
-  Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
-                            options::OPT_e, options::OPT_r});
+  if (Args.hasArg(options::OPT_v))
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-V")));
 
-  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+  CmdArgs.push_back(Args.MakeArgString(StringRef("-Qy")));
 
-  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
-    if (getToolChain().getDriver().CCCIsCXX())
-      getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
-    CmdArgs.push_back("-lgcc_s");
-    CmdArgs.push_back("-lc");
+  if (LD == "/usr/bin/ld") {
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-Y")));
+    CmdArgs.push_back(Args.MakeArgString(StringRef("P," + YPPath)));
+  } else {
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-Y")));
+    CmdArgs.push_back(Args.MakeArgString(StringRef(YPPath)));
+  }
+
+  CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
+
+  std::string P = GCCLibPath;
+  P += "../../..";
+  CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + P));
+
+  std::string crt1o;
+  bool S12OrHigher = false;
+
+  // We're not backporting this to S10. Until we do, that is.
+  if (EffectiveTriple.find("solaris2.11") == std::string::npos)
+    S12OrHigher = true;
+
+  if (!Args.hasArg(options::OPT_nostdlib) &&
+      !Args.hasArg(options::OPT_nostartfiles)) {
     if (!Args.hasArg(options::OPT_shared)) {
-      CmdArgs.push_back("-lgcc");
+      switch (Arch) {
+      case llvm::Triple::sparc:
+      case llvm::Triple::sparcv9:
+        if (S12OrHigher)
+          crt1o = LibPath;
+        else
+          crt1o = GCCLibPath;
+      case llvm::Triple::x86:
+      case llvm::Triple::x86_64:
+        crt1o = LibPath;
+        break;
+      default:
+        D.Diag(diag::err_target_unsupported_arch) << ET.getArchName()
+          << ET.getTriple();
+        break;
+      }
+
+      crt1o += "/crt1.o";
+
+      CmdArgs.push_back(Args.MakeArgString(crt1o.c_str()));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o"));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + Values));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + Xpg));
+      CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + GCCLibPath));
+      CmdArgs.push_back(Args.MakeArgString("-L" + P));
+      CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o"));
+    } else {
+      CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o"));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + Values));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + Xpg));
+      CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + GCCLibPath));
+      CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + P));
+      CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o"));
+    }
+  } else if (Args.hasArg(options::OPT_nostdlib) &&
+             !Args.hasArg(options::OPT_nostartfiles)) {
+    if (Args.hasArg(options::OPT_shared)) {
+      CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o"));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + Values));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + Xpg));
+      CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + GCCLibPath));
+      CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + P));
+      CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o"));
+    } else {
+      CmdArgs.push_back(Args.MakeArgString(crt1o.c_str()));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o"));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + Values));
+      CmdArgs.push_back(Args.MakeArgString(LibPath + Xpg));
+      CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + GCCLibPath));
+      CmdArgs.push_back(Args.MakeArgString("-L" + P));
+    }
+  } else if (!Args.hasArg(options::OPT_nostdlib) &&
+             Args.hasArg(options::OPT_nostartfiles)) {
+    if (Args.hasArg(options::OPT_shared)) {
+      CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtend.o"));
+    }
+  }
+
+  // Itanium C++ ABI.
+  std::string CXAFinalize;
+  bool HasSystemCXAFinalize = !S12OrHigher;
+
+  if (!Args.hasArg(options::OPT_shared)) {
+    if (PIEArg) {
+      if (PIEArg->getOption().matches(options::OPT_fPIE) ||
+          PIEArg->getOption().matches(options::OPT_fpie)) {
+        CXAFinalize = ClangLibPath + "cxa_finalize_pic.o";
+      }
+    } else {
+      CXAFinalize = ClangLibPath + "cxa_finalize.o";
+    }
+
+    HasSystemCXAFinalize = llvm::sys::fs::exists(CXAFinalize.c_str());
+
+    if (D.CCCIsCXX() && HasSystemCXAFinalize)
+      CmdArgs.push_back(Args.MakeArgString(CXAFinalize.c_str()));
+  }
+
+  CmdArgs.push_back(Args.MakeArgString(StringRef("-L" + GCCLibPath)));
+  CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
+  CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + ShortLibPath));
+
+  Args.AddAllArgs(CmdArgs, options::OPT_L);
+  const ToolChain::path_list Paths = TC.getFilePaths();
+  for (ToolChain::path_list::const_iterator B = Paths.begin(), E = Paths.end();
+       B != E; ++B) {
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *B));
+
+    // Itanium C++ ABI.
+    if (!Args.hasArg(options::OPT_shared)) {
+      if (D.CCCIsCXX() && !HasSystemCXAFinalize) {
+        if (PIEArg) {
+          if (PIEArg->getOption().matches(options::OPT_fPIE) ||
+              PIEArg->getOption().matches(options::OPT_fpie)) {
+            CXAFinalize = *B + "/cxa_finalize_pic.o";
+          }
+        } else {
+          CXAFinalize = *B + "/cxa_finalize.o";
+        }
+
+        if (llvm::sys::fs::exists(CXAFinalize.c_str()))
+          CmdArgs.push_back(Args.MakeArgString(CXAFinalize.c_str()));
+      }
+    }
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+  Args.AddAllArgs(CmdArgs, options::OPT_e);
+  Args.AddAllArgs(CmdArgs, options::OPT_s);
+  Args.AddAllArgs(CmdArgs, options::OPT_t);
+  Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+  std::vector<std::string>  zoptions = Args.getAllArgValues(options::OPT_z);
+  std::string zoption;
+
+  for (std::vector<std::string>::const_iterator B = zoptions.begin(),
+       E = zoptions.end(); B != E; ++B) {
+    zoption = "-z";
+    zoption += *B;
+    CmdArgs.push_back(Args.MakeArgString(StringRef(zoption)));
+  }
+
+  if (!Args.hasArg(options::OPT_mimpure_text) &&
+      !Args.hasArg(options::OPT_fpie) &&
+      !Args.hasArg(options::OPT_fPIE))
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-ztext")));
+
+  // Itanium C++ ABI.
+  if (D.CCCIsCXX()) {
+    if (!Args.hasArg(options::OPT_shared)) {
+      if (HasSystemCXAFinalize) {
+        const char* zfiniarray = "-zfiniarray=__cxa_finalize";
+        CmdArgs.push_back(Args.MakeArgString(zfiniarray));
+      }
+    }
+  }
+
+  if (LD == "/usr/gnu/bin/ld.gold") {
+    CmdArgs.push_back("-plugin");
+    std::string Plugin = D.Dir + "/../lib/LLVMgold.so";
+    CmdArgs.push_back(Args.MakeArgString(Plugin));
+  }
+
+  if (!UseGnuLd) {
+    CmdArgs.push_back(moption);
+  }
+
+  if (Arg *A = Args.getLastArg(options::OPT_rpath)) {
+    StringRef V = A->getValue();
+    if (UseGnuLd) {
+      CmdArgs.push_back(Args.MakeArgString("-rpath"));
+      CmdArgs.push_back(Args.MakeArgString(V));
+    } else {
+      CmdArgs.push_back(Args.MakeArgString("-R"));
+      CmdArgs.push_back(Args.MakeArgString(V));
+    }
+  }
+
+  AddLinkerInputs(TC, Inputs, Args, CmdArgs);
+  AddLibgcc(D, CmdArgs, Args, LD.str());
+
+  if (!Args.hasArg(options::OPT_nostdlib) &&
+      !Args.hasArg(options::OPT_nodefaultlibs)) {
+    if (Args.hasArg(options::OPT_fopenmp) ||
+        Args.hasArg(options::OPT_fopenmp_EQ)) {
+      addOpenMPRuntime(CmdArgs, TC, Args);
+      CmdArgs.push_back("-latomic");
+    }
+
+    if (D.CCCIsCXX())
+      TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+
+    CmdArgs.push_back("-lc");
       CmdArgs.push_back("-lm");
+    CmdArgs.push_back("-lgcc_s");
+
+    if (Args.hasArg(options::OPT_static)) {
+      CmdArgs.push_back("-lgcc");
+      CmdArgs.push_back("-lgcc_eh");
     }
+  } else if (Args.hasArg(options::OPT_nostdlib) &&
+             (!Args.hasArg(options::OPT_nodefaultlibs))) {
+    CmdArgs.push_back("-lgcc_s");
+
+    if (Args.hasArg(options::OPT_static))
+      CmdArgs.push_back("-lgcc_eh");
   }
 
-  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
-    CmdArgs.push_back(
-        Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+  if (!Args.hasArg(options::OPT_nostdlib) &&
+      !Args.hasArg(options::OPT_nostartfiles)) {
+    CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtend.o"));
   }
-  CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
 
-  getToolChain().addProfileRTLibs(Args, CmdArgs);
+  CmdArgs.push_back(Args.MakeArgString(LibPath + "crtn.o"));
 
-  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+  TC.addProfileRTLibs(Args, CmdArgs);
+
+  Args.ClaimAllArgs(options::OPT_Wl_COMMA);
+  Args.ClaimAllArgs(options::OPT_Xlinker);
+
+  const char *Exec = LD.data();
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
 }
 
+void
+solaris::Linker::RenderExtraToolArgs(const JobAction &JA,
+                                     llvm::opt::ArgStringList &CmdArgs) const {
+  // FIXME: IMPLEMENT
+}
+
 void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
                                       const InputInfo &Output,
                                       const InputInfoList &Inputs,
@@ -8623,6 +9377,41 @@
     CmdArgs.push_back("-ldl");
 }
 
+static void AddLibgcc(const Driver &D, ArgStringList &CmdArgs,
+                      const ArgList &Args, const std::string& Exec) {
+  bool StaticLibgcc = Args.hasArg(options::OPT_static) ||
+    Args.hasArg(options::OPT_static_libgcc);
+  if (!D.CCCIsCXX())
+    CmdArgs.push_back("-lgcc");
+
+  if (StaticLibgcc) {
+    if (D.CCCIsCXX())
+      CmdArgs.push_back("-lgcc");
+  } else {
+    if ((!D.CCCIsCXX()) && ((Exec == "/usr/bin/gld") ||
+                            (Exec == "/usr/gnu/bin/ld") ||
+                            (Exec == "/usr/gnu/bin/ld.bfd") ||
+                            (Exec == "/usr/gnu/bin/ld.gold")))
+      CmdArgs.push_back("--as-needed");
+
+    CmdArgs.push_back("-lgcc_s");
+    if ((!D.CCCIsCXX()) && ((Exec == "/usr/bin/gld") ||
+                            (Exec == "/usr/gnu/bin/ld") ||
+                            (Exec == "/usr/gnu/bin/ld.bfd") ||
+                            (Exec == "/usr/gnu/bin/ld.gold")))
+      CmdArgs.push_back("--no-as-needed");
+  }
+
+  if (StaticLibgcc)
+    CmdArgs.push_back("-lgcc_eh");
+  else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX())
+    CmdArgs.push_back("-lgcc");
+
+  if (!StaticLibgcc)
+    CmdArgs.push_back("-ldl");
+}
+
+
 static std::string getLinuxDynamicLinker(const ArgList &Args,
                                          const toolchains::Linux &ToolChain) {
   const llvm::Triple::ArchType Arch = ToolChain.getArch();
###
--- tools/clang/lib/Driver/Tools.h	2016-01-08 06:14:31.000000000 -0900
+++ tools/clang/lib/Driver/Tools.h	2016-07-04 11:21:03.646553390 -0800
@@ -17,6 +17,8 @@
 #include "clang/Frontend/CodeGenOptions.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Option/Option.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
 #include "llvm/Support/Compiler.h"
 
 namespace clang {
@@ -38,9 +40,10 @@
 
 using llvm::opt::ArgStringList;
 
-SmallString<128> getCompilerRT(const ToolChain &TC,
+SmallString<PATH_MAX> getCompilerRT(const ToolChain &TC,
                                const llvm::opt::ArgList &Args,
-                               StringRef Component, bool Shared = false);
+                                    StringRef Component,
+                                    bool Shared = false);
 
 /// \brief Clang compiler tool.
 class LLVM_LIBRARY_VISIBILITY Clang : public Tool {
@@ -308,6 +311,16 @@
 bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value);
 } // end namespace ppc
 
+namespace sparc {
+  const char *getSparcTargetCPU(const llvm::opt::ArgList &Args,
+                                const llvm::Triple &Triple);
+} // end namespace sparc
+
+namespace x86 {
+  const char *getX86TargetCPU(const llvm::opt::ArgList &Args,
+                              const llvm::Triple &Triple);
+} // end namespace x86
+
 /// cloudabi -- Directly call GNU Binutils linker
 namespace cloudabi {
 class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
@@ -622,25 +635,32 @@
 
 /// solaris -- Directly call Solaris assembler and linker
 namespace solaris {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
 public:
   Assembler(const ToolChain &TC)
-      : Tool("solaris::Assembler", "assembler", TC) {}
+    : GnuTool("solaris::Assembler", "assembler", TC) {}
 
   bool hasIntegratedCPP() const override { return false; }
 
+  virtual void RenderExtraToolArgs(const JobAction &JA,
+                                   llvm::opt::ArgStringList &CmdArgs) const;
+
   void ConstructJob(Compilation &C, const JobAction &JA,
                     const InputInfo &Output, const InputInfoList &Inputs,
                     const llvm::opt::ArgList &TCArgs,
                     const char *LinkingOutput) const override;
 };
 
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
 public:
-  Linker(const ToolChain &TC) : Tool("solaris::Linker", "linker", TC) {}
+  Linker(const ToolChain &TC)
+    : GnuTool("solaris::Linker", "linker", TC) {}
 
   bool hasIntegratedCPP() const override { return false; }
   bool isLinkJob() const override { return true; }
+  bool checkGnuLd(StringRef Path) const;
+  virtual void RenderExtraToolArgs(const JobAction &JA,
+                                   llvm::opt::ArgStringList &CmdArgs) const;
 
   void ConstructJob(Compilation &C, const JobAction &JA,
                     const InputInfo &Output, const InputInfoList &Inputs,
###
--- tools/clang/lib/Driver/ToolChain.cpp	2015-11-25 16:02:07.000000000 -0900
+++ tools/clang/lib/Driver/ToolChain.cpp	2016-06-30 20:26:09.406980255 -0800
@@ -408,6 +408,34 @@
 
 std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
                                          types::ID InputType) const {
+  llvm::Triple T = getTriple();
+  if (T.isOSSolaris()) {
+    if ((!Args.getLastArg(options::OPT_m32)) &&
+        (!Args.getLastArg(options::OPT_m64))) {
+      StringRef ArchName;
+
+      switch (T.getArch()) {
+      case llvm::Triple::x86_64:
+      case llvm::Triple::sparcv9:
+        return getTripleString();
+        break;
+      case llvm::Triple::sparc:
+        ArchName = "sparcv9";
+        T.setArchName(ArchName);
+        return T.getTriple();
+        break;
+      case llvm::Triple::x86:
+        ArchName = "x86_64";
+        T.setArchName(ArchName);
+        return T.getTriple();
+        break;
+      default:
+        llvm_unreachable("Unknonwn Solaris Target Triple!");
+        break;
+      }
+    }
+  }
+
   switch (getTriple().getArch()) {
   default:
     return getTripleString();
###