components/llvm/patches/014-clang-gcc-toolchain.patch
author xiao qing lu - Sun Microsystems - Beijing China <xiaoqing.lu@oracle.com>
Tue, 12 Jul 2016 19:50:03 -0700
changeset 6403 9d25dbe7eb71
parent 5434 9f55c805ce9d
permissions -rw-r--r--
23209274 Upgrade libsigsegv to 2.10

# Solaris GCC Toolchain discovery.
# https://llvm.org/bugs/show_bug.cgi?id=24606
--- lib/Support/Host.cpp	2014-12-16 19:38:04.000000000 -0800
+++ lib/Support/Host.cpp	2016-02-09 09:59:19.281147309 -0800
@@ -39,6 +39,11 @@
 #include <mach/machine.h>
 #endif
 
+#if defined(sun) || defined(__sun) || defined(__sun__)
+#include <cstring>
+#include <kstat.h>
+#endif
+
 #define DEBUG_TYPE "host-detection"
 
 //===----------------------------------------------------------------------===//
@@ -674,6 +679,43 @@
   
   return "generic";
 }
+#elif ((defined(sun) || defined(__sun) || defined(__sun__)) && \
+       (defined(sparc) || defined(__sparc) || defined(__sparc__)))
+StringRef sys::getHostCPUName() {
+  kstat_ctl_t *KC = 0;
+  kstat_t *KSP = 0;
+  kstat_named_t *KNP = 0;
+  static char Buffer[256];
+  static bool Init = false;
+  const char *Value;
+
+  if (!Init) {
+    KC = kstat_open();
+    if (KC) {
+      KSP = kstat_lookup(KC, "cpu_info", -1, "cpu_info0");
+      kstat_read(KC, KSP, NULL);
+      KNP = reinterpret_cast<kstat_named_t*>(kstat_data_lookup(KSP, "brand"));
+      Value = (const char *) KNP->value.str.addr.ptr;
+      (void) std::sprintf(Buffer, "%s (", Value);
+
+      KNP =
+        reinterpret_cast<kstat_named_t*>(kstat_data_lookup(KSP, "cpu_type"));
+      Value = (const char*) KNP->value.c;
+      (void) std::strcat(Buffer, Value);
+      (void) std::strcat(Buffer, ") ");
+
+      KNP =
+        reinterpret_cast<kstat_named_t*>(kstat_data_lookup(KSP,
+                                                           "implementation"));
+      Value = (const char*) KNP->value.str.addr.ptr;
+      (void) std::strcat(Buffer, Value);
+      Init = true;
+      kstat_close(KC);
+    }
+  }
+
+  return Buffer;
+}
 #else
 StringRef sys::getHostCPUName() {
   return "generic";
--- tools/clang/include/clang/Driver/Options.td	Sat Jul 18 11:44:46 2015
+++ tools/clang/include/clang/Driver/Options.td	Thu Aug 20 22:46:37 2015
@@ -1129,6 +1129,11 @@
 def mthread_model : Separate<["-"], "mthread-model">, Group<m_Group>, Flags<[CC1Option]>,
   HelpText<"The thread model to use, e.g. posix, single (posix by default)">;
 
+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>;
@@ -1690,6 +1695,7 @@
 defm profile_use : BooleanFFlag<"profile-use">, Group<clang_ignored_gcc_optimization_f_Group>;
 def fprofile_use_EQ : Joined<["-"], "fprofile-use=">, Group<clang_ignored_gcc_optimization_f_Group>;
 def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>;
+def fuse_as_EQ : Joined<["-"], "fuse-as=">, Group<f_Group>;
 
 defm align_functions : BooleanFFlag<"align-functions">, Group<clang_ignored_gcc_optimization_f_Group>;
 def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group<clang_ignored_gcc_optimization_f_Group>;
--- tools/clang/lib/Frontend/InitHeaderSearch.cpp	Thu Dec  4 16:22:48 2014
+++ tools/clang/lib/Frontend/InitHeaderSearch.cpp	Fri Aug 21 23:23:27 2015
@@ -122,7 +122,7 @@
   // Add the path with sysroot prepended, if desired and this is a system header
   // group.
   if (HasSysroot) {
-    SmallString<256> MappedPathStorage;
+    SmallString<PATH_MAX> MappedPathStorage;
     StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
     if (CanPrefixSysroot(MappedPathStr)) {
       AddUnmappedPath(IncludeSysroot + Path, Group, isFramework);
@@ -138,7 +138,7 @@
   assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
 
   FileManager &FM = Headers.getFileMgr();
-  SmallString<256> MappedPathStorage;
+  SmallString<PATH_MAX> MappedPathStorage;
   StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
 
   // Compute the DirectoryLookup type.
@@ -187,12 +187,16 @@
 
   // Add the multilib dirs
   llvm::Triple::ArchType arch = triple.getArch();
-  bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64;
+  bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64 ||
+    arch == llvm::Triple::sparcv9;
   if (is64bit)
     AddPath(Base + "/" + ArchDir + "/" + Dir64, CXXSystem, false);
   else
     AddPath(Base + "/" + ArchDir + "/" + Dir32, CXXSystem, false);
 
+  // Add GCC's "C" include dir
+  AddPath(Base + "/include", CXXSystem, false);
+
   // Add the backward dir
   AddPath(Base + "/backward", CXXSystem, false);
 }
@@ -442,8 +446,7 @@
                                 "", "", "", triple);
     break;
   case llvm::Triple::Solaris:
-    AddGnuCPlusPlusIncludePaths("/usr/gcc/4.5/include/c++/4.5.2/",
-                                "i386-pc-solaris2.11", "", "", triple);
+    // All of this is handled in the driver.
     break;
   default:
     break;
@@ -462,6 +465,7 @@
     break; // Everything else continues to use this routine's logic.
 
   case llvm::Triple::Linux:
+  case llvm::Triple::Solaris:
     return;
 
   case llvm::Triple::Win32:
@@ -484,7 +488,7 @@
           // Remove clang from foo/lib/clang
           StringRef Lib = llvm::sys::path::parent_path(NoVer);
           // Remove lib from foo/lib
-          SmallString<128> P = llvm::sys::path::parent_path(Lib);
+          SmallString<PATH_MAX> P = llvm::sys::path::parent_path(Lib);
 
           // Get foo/include/c++/v1
           llvm::sys::path::append(P, "include", "c++", "v1");
@@ -491,10 +495,6 @@
           AddUnmappedPath(P.str(), CXXSystem, false);
         }
       }
-      // On Solaris, include the support directory for things like xlocale and
-      // fudged system headers.
-      if (triple.getOS() == llvm::Triple::Solaris) 
-        AddPath("/usr/include/c++/v1/support/solaris", CXXSystem, false);
       
       AddPath("/usr/include/c++/v1", CXXSystem, false);
     } else {
--- tools/clang/lib/Driver/Tools.h	Wed Jan 28 15:52:21 2015
+++ tools/clang/lib/Driver/Tools.h	Thu Aug 20 22:46:37 2015
@@ -529,6 +529,9 @@
 
     bool hasIntegratedCPP() const override { return false; }
 
+    void RenderExtraToolArgs(const JobAction &JA,
+                             ArgStringList &CmdArgs) const;
+
     void ConstructJob(Compilation &C, const JobAction &JA,
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
@@ -541,6 +544,9 @@
     bool hasIntegratedCPP() const override { return false; }
     bool isLinkJob() const override { return true; }
 
+    void RenderExtraToolArgs(const JobAction &JA,
+                             ArgStringList &CmdArgs) const;
+
     void ConstructJob(Compilation &C, const JobAction &JA,
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
--- tools/clang/lib/Driver/Tools.cpp	Sat Jul 18 11:44:46 2015
+++ tools/clang/lib/Driver/Tools.cpp	Sat Aug 22 17:26:16 2015
@@ -60,6 +60,12 @@
   }
 }
 
+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) {
@@ -1360,14 +1366,30 @@
   return "";
 }
 
+static const char *getSparcTargetCPU(const ArgList &Args,
+                                     const llvm::Triple &Triple);
+
+static const char *getSparcTargetCPUFeature(const char* CPU,
+                                            const ArgList &Args,
+                                            const llvm::Triple &Triple);
+
 static void getSparcTargetFeatures(const ArgList &Args,
-                                   std::vector<const char *> &Features) {
-  bool SoftFloatABI = true;
+                                   std::vector<const char *> &Features,
+                                   const llvm::Triple &Triple) {
+  bool SoftFloatABI;
+
+  if ((Triple.getOS() == llvm::Triple::Solaris) ||
+      (Triple.getOS() == llvm::Triple::Linux))
+    SoftFloatABI = false;
+  else
+    SoftFloatABI = true;
+
   if (Arg *A =
           Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) {
     if (A->getOption().matches(options::OPT_mhard_float))
       SoftFloatABI = false;
   }
+
   if (SoftFloatABI)
     Features.push_back("+soft-float");
 }
@@ -1375,17 +1397,31 @@
 void Clang::AddSparcTargetArgs(const ArgList &Args,
                              ArgStringList &CmdArgs) const {
   const Driver &D = getToolChain().getDriver();
+  const llvm::Triple &T = getToolChain().getTriple();
 
   // Select the float ABI as determined by -msoft-float and -mhard-float.
+  // There is no support for soft-float ABI in Solaris.
   StringRef FloatABI;
   if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
                                options::OPT_mhard_float)) {
-    if (A->getOption().matches(options::OPT_msoft_float))
+    if (A->getOption().matches(options::OPT_msoft_float)) {
+      if ((T.getOS() == llvm::Triple::Solaris) ||
+          (T.getOS() == llvm::Triple::Linux)) {
+        D.Diag(diag::warn_drv_clang_unsupported) << "-msoft-float";
+        D.Diag(diag::warn_drv_overriding_flag_option) <<
+          "-msoft-float" << "-mhard-float";
+        FloatABI = "hard";
+      } else {
       FloatABI = "soft";
-    else if (A->getOption().matches(options::OPT_mhard_float))
+      }
+    } else if (A->getOption().matches(options::OPT_mhard_float))
       FloatABI = "hard";
   }
 
+  if (((T.getOS() == llvm::Triple::Solaris) ||
+       (T.getOS() == llvm::Triple::Linux)) && FloatABI.empty())
+    FloatABI = "hard";
+
   // If unspecified, choose the default based on the platform.
   if (FloatABI.empty()) {
     // Assume "soft", but warn the user we are guessing.
@@ -1400,10 +1436,93 @@
     CmdArgs.push_back("-msoft-float");
   } else {
     assert(FloatABI == "hard" && "Invalid float abi!");
-    CmdArgs.push_back("-mhard-float");
   }
+
+  std::string Feature;
+  if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+    Feature = "-march=";
+    Feature += A->getValue();
+    CmdArgs.push_back(Args.MakeArgString("-target-feature"));
+    CmdArgs.push_back(Args.MakeArgString(Feature.c_str()));
 }
 
+  if (Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
+    Feature = "-mtune=";
+    Feature += A->getValue();
+    CmdArgs.push_back(Args.MakeArgString("-target-feature"));
+    CmdArgs.push_back(Args.MakeArgString(Feature.c_str()));
+  }
+
+  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+    Feature = "-mcpu=";
+    Feature += A->getValue();
+    CmdArgs.push_back(Args.MakeArgString("-target-feature"));
+    CmdArgs.push_back(Args.MakeArgString(Feature.c_str()));
+  }
+}
+
+static const char *getSparcTargetCPU(const ArgList &Args,
+                                     const llvm::Triple &Triple) {
+    StringRef V;
+
+    if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+      V = A->getValue();
+      switch (Triple.getOS()) {
+      case llvm::Triple::Solaris:
+      case llvm::Triple::Linux:
+        if (V == "v8plus" || V == "v8plusa" ||
+            V == "v8plusb" || V == "v9" ||
+            V == "v9a" || V == "v9b" ||
+            V == "sparcmaf" || V == "sparc4" )
+          return Args.MakeArgString(V);
+        break;
+      default:
+        return Args.MakeArgString("v8plusa");
+        break;
+      }
+    }
+
+    if (Arg *AA = Args.getLastArg(options::OPT_m64))
+      return "v9a";
+
+    return "v8plusa";
+}
+
+static const char *getSparcTargetCPUFeature(const char* CPU,
+                                            const ArgList &Args,
+                                            const llvm::Triple &Triple) {
+  StringRef V;
+  if (Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
+    V = A->getValue();
+
+    if (V.empty())
+      if (Arg *AA = Args.getLastArg(options::OPT_m64))
+        return "vis";
+
+    if (V == "ultrasparc" || V == "ultrasparc2" ||
+        V == "ultrasparc3" || V == "sparcmaf" || V == "sparc4" )
+      return Args.MakeArgString(A->getValue());
+  }
+
+  if (!CPU)
+    return 0;
+
+  std::string C = CPU;
+
+  if (C == "v8plus" || C == "v9")
+    return "";
+
+  if (C == "v8plusa" || C == "v9a")
+    return "vis1";
+  else if (C == "v8plusb" || C == "v9b")
+    return "vis2";
+  else if (C == "sparcmaf" || C == "sparc4")
+    return "vis3";
+
+  return 0;
+}
+
+
 static const char *getSystemZTargetCPU(const ArgList &Args) {
   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
     return A->getValue();
@@ -1872,7 +1991,7 @@
     break;
   case llvm::Triple::sparc:
   case llvm::Triple::sparcv9:
-    getSparcTargetFeatures(Args, Features);
+    getSparcTargetFeatures(Args, Features, Triple);
     break;
   case llvm::Triple::aarch64:
   case llvm::Triple::aarch64_be:
@@ -2695,6 +2814,23 @@
     }
   }
 
+  // Solaris-specific defaults for PIE
+  if (getToolChain().getTriple().getOS() == llvm::Triple::Solaris) {
+    switch (getToolChain().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;
+    }
+  }
+
   // For the PIC and PIE flag options, this logic is different from the
   // legacy logic in very old versions of GCC, as that logic was just
   // a bug no one had ever fixed. This logic is both more rational and
@@ -2740,6 +2876,47 @@
   if (Args.hasArg(options::OPT_static))
     PIC = PIE = false;
 
+  if (Triple.getOS() == llvm::Triple::Solaris) {
+    if (Arg *A = Args.getLastArg(options::OPT_shared)) {
+      PIC = true;
+      PIE = false;
+      CmdArgs.push_back("-mrelocation-model");
+      CmdArgs.push_back("pic");
+      if (IsPICLevelTwo) {
+        CmdArgs.push_back("-pic-level");
+        CmdArgs.push_back("2");
+      }
+    } else if (PIC) {
+      PIC = true;
+      PIE = false;
+      CmdArgs.push_back("-mrelocation-model");
+      CmdArgs.push_back("pic");
+      if (IsPICLevelTwo) {
+        CmdArgs.push_back("-pic-level");
+        CmdArgs.push_back("2");
+      }
+    } else if (PIE) {
+      PIC = PIE = true;
+      CmdArgs.push_back("-mrelocation-model");
+      CmdArgs.push_back("pic");
+      if (IsPICLevelTwo) {
+        CmdArgs.push_back("-pie-level");
+        CmdArgs.push_back("2");
+      }
+    } else if (Args.hasArg(options::OPT_static)) {
+      // Solaris doesn't to static relocations.
+      PIC = PIE = false;
+      CmdArgs.push_back("-mrelocation-model");
+      CmdArgs.push_back("dynamic-no-pic");
+    } else {
+      // This is a Solaris non-PIE executable.
+      // Solaris doesn't to static relocations.
+      PIC = PIE = false;
+      CmdArgs.push_back("-mrelocation-model");
+      CmdArgs.push_back("dynamic-no-pic");
+    }
+  }
+
   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.
@@ -2762,6 +2939,8 @@
   } else {
     // Currently, LLVM only knows about PIC vs. static; the PIE differences are
     // handled in Clang's IRGen by the -pie-level flag.
+    // Solaris already took care of PIC/PIE/non-PIC above.
+    if (Triple.getOS() != llvm::Triple::Solaris) {
     CmdArgs.push_back("-mrelocation-model");
     CmdArgs.push_back(PIC ? "pic" : "static");
 
@@ -2774,6 +2953,7 @@
       }
     }
   }
+  }
 
   CmdArgs.push_back("-mthread-model");
   if (Arg *A = Args.getLastArg(options::OPT_mthread_model))
@@ -3180,12 +3360,13 @@
       // FIXME: we should support specifying dwarf version with
       // -gline-tables-only.
       CmdArgs.push_back("-gline-tables-only");
-      // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris.
+      // Default is dwarf-2 for Darwin, OpenBSD and FreeBSD.
       const llvm::Triple &Triple = getToolChain().getTriple();
       if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD ||
-          Triple.getOS() == llvm::Triple::FreeBSD ||
-          Triple.getOS() == llvm::Triple::Solaris)
+          Triple.getOS() == llvm::Triple::FreeBSD)
         CmdArgs.push_back("-gdwarf-2");
+      else if (Triple.getOS() == llvm::Triple::Solaris)
+        CmdArgs.push_back("-gdwarf-4");
     } else if (A->getOption().matches(options::OPT_gdwarf_2))
       CmdArgs.push_back("-gdwarf-2");
     else if (A->getOption().matches(options::OPT_gdwarf_3))
@@ -3194,12 +3375,13 @@
       CmdArgs.push_back("-gdwarf-4");
     else if (!A->getOption().matches(options::OPT_g0) &&
              !A->getOption().matches(options::OPT_ggdb0)) {
-      // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris.
+      // Default is dwarf-2 for Darwin, OpenBSD and FreeBSD.
       const llvm::Triple &Triple = getToolChain().getTriple();
       if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD ||
-          Triple.getOS() == llvm::Triple::FreeBSD ||
-          Triple.getOS() == llvm::Triple::Solaris)
+          Triple.getOS() == llvm::Triple::FreeBSD)
         CmdArgs.push_back("-gdwarf-2");
+      else if (Triple.getOS() == llvm::Triple::Solaris)
+        CmdArgs.push_back("-gdwarf-4");
       else
         CmdArgs.push_back("-g");
     }
@@ -3594,6 +3776,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 == 0) N = 72U;
     CmdArgs.push_back(Args.MakeArgString(Twine(N)));
   }
 
@@ -3735,6 +3918,7 @@
     CmdArgs.push_back("-backend-option");
     CmdArgs.push_back("-force-align-stack");
   }
+
   if (!Args.hasFlag(options::OPT_mno_stackrealign, options::OPT_mstackrealign,
                    false)) {
     CmdArgs.push_back(Args.MakeArgString("-mstackrealign"));
@@ -3743,6 +3927,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().getTriple().getArch() == llvm::Triple::sparc) ||
+        (getToolChain().getTriple().getArch() == llvm::Triple::sparcv9))
+      CmdArgs.push_back("-mstack-alignment=16");
   }
 
   if (getToolChain().getTriple().getArch() == llvm::Triple::aarch64 ||
@@ -6049,6 +6237,10 @@
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
 }
 
+void solaris::Assemble::RenderExtraToolArgs(const JobAction &JA,
+                                            ArgStringList &CmdArgs) const {
+}
+
 void solaris::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
                                       const InputInfo &Output,
                                       const InputInfoList &Inputs,
@@ -6055,61 +6247,321 @@
                                       const ArgList &Args,
                                       const char *LinkingOutput) const {
   claimNoWarnArgs(Args);
+
+  const toolchains::Solaris &TC =
+    static_cast<const toolchains::Solaris&>(getToolChain());
+
+  if (!TC.isValid()) {
+    llvm::errs() << "Invalid GCC installation!\n";
+    return;
+  }
+
+  const llvm::Triple &TT = TC.getTriple();
+  const Driver &D = TC.getDriver();
+  llvm::Triple::ArchType Arch = TT.getArch();
+  StringRef Assembler = TC.getAssembler();
+  bool m32 = true;
+
+  std::string march;
+  std::string mtune;
+  std::string mcpu;
+
   ArgStringList CmdArgs;
 
-  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
-                       options::OPT_Xassembler);
+  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 (Arg *A = Args.getLastArg(options::OPT_m64))
+    m32 = false;
+
+  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");
+      march="v8plusa";
+      mcpu="v8plusa";
+    } else {
+      CmdArgs.push_back("-64");
+      march="v9a";
+      mcpu="v9a";
+    }
+    break;
+  default:
+    D.Diag(diag::err_target_unsupported_arch) << TT.getArchName()
+      << TT.getTriple();
+    break;
+  }
+
+  std::string xarch;
+
+  switch (Arch) {
+    case llvm::Triple::sparc:
+    case llvm::Triple::sparcv9:
+      if (!march.empty()) {
+        xarch = "-xarch=";
+        xarch += march;
+        CmdArgs.push_back(Args.MakeArgString(xarch.c_str()));
+      } else if (!mtune.empty()) {
+        xarch = "-xarch=";
+        xarch += mtune;
+        CmdArgs.push_back(Args.MakeArgString(xarch.c_str()));
+      } else if (!mcpu.empty()) {
+        xarch = "-xarch=";
+        xarch += mcpu;
+        CmdArgs.push_back(Args.MakeArgString(xarch.c_str()));
+      }
+
+      addAssemblerKPIC(Args, CmdArgs);
+
+      if (Args.hasArg(options::OPT_mstrict_align))
+        CmdArgs.push_back("--enforce-aligned-data");
+      break;
+    case llvm::Triple::x86:
+    case llvm::Triple::x86_64:
+      if (!march.empty()) {
+        xarch = "-mtune=";
+        xarch += march;
+        CmdArgs.push_back(Args.MakeArgString(xarch.c_str()));
+      } else if (!mtune.empty()) {
+        xarch = "-mtune=";
+        xarch += mtune;
+        CmdArgs.push_back(Args.MakeArgString(xarch.c_str()));
+      }
+      if (!mcpu.empty()) {
+        xarch = "-march=";
+        xarch += mcpu;
+        CmdArgs.push_back(Args.MakeArgString(xarch.c_str()));
+      }
+      break;
+    default:
+      D.Diag(diag::err_target_unsupported_arch) << TT.getArchName()
+        << TT.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)
+  RenderExtraToolArgs(JA, CmdArgs);
+
+  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+                       options::OPT_Xassembler);
+
+  for (const auto &II : Inputs) {
+    if (II.getType() == types::TY_LLVM_IR ||
+        II.getType() == types::TY_LTO_IR ||
+        II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC)
+      D.Diag(clang::diag::err_drv_no_linker_llvm_support)
+        << getToolChain().getTripleString();
+    else if (II.getType() == types::TY_AST)
+      D.Diag(clang::diag::err_drv_no_ast_support)
+        << getToolChain().getTripleString();
+    else if (II.getType() == types::TY_ModuleFile)
+      D.Diag(diag::err_drv_no_module_support)
+        << getToolChain().getTripleString();
+
+    if (II.isFilename())
     CmdArgs.push_back(II.getFilename());
+    else
+      II.getInputArg().render(Args, CmdArgs);
+  }
 
-  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
-  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
+  C.addCommand(llvm::make_unique<Command>(JA, *this,
+                                          Args.MakeArgString(Assembler),
+                                          CmdArgs));
 }
 
+
+void solaris::Link::RenderExtraToolArgs(const JobAction &JA,
+                                        ArgStringList &CmdArgs) const {
+}
+
 void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
                                   const InputInfo &Output,
                                   const InputInfoList &Inputs,
                                   const ArgList &Args,
                                   const char *LinkingOutput) const {
-  // FIXME: Find a real GCC, don't hard-code versions here
-  std::string GCCLibPath = "/usr/gcc/4.5/lib/gcc/";
-  const llvm::Triple &T = getToolChain().getTriple();
-  std::string LibPath = "/usr/lib/";
+  const toolchains::Solaris& TC =
+    static_cast<const toolchains::Solaris&>(getToolChain());
+
+  if (!TC.isValid()) {
+    llvm::errs() << "Invalid GCC installation!\n";
+    return;
+  }
+
+  const llvm::Triple &T = TC.getTriple();
+  const Driver &D = TC.getDriver();
   llvm::Triple::ArchType Arch = T.getArch();
+  bool m32 = true;
+  StringRef Linker = TC.getLinker();
+
+  if (Arg *A = Args.getLastArg(options::OPT_m64))
+    m32 = false;
+
+  std::string GCCLibPath;
+  std::string YPPath;
+  GCCLibPath += "/lib/gcc/";
+  std::string LibPath = "/usr/lib/";
+  std::string ShortLibPath = "/lib/";
+  std::string ClangLibPath;
+  const char* moption;
+
   switch (Arch) {
   case llvm::Triple::x86:
-    GCCLibPath +=
-        ("i386-" + T.getVendorName() + "-" + T.getOSName()).str() + "/4.5.2/";
+    if (m32) {
+      GCCLibPath = TC.getGCCInternalLibDir().str();
+      GCCLibPath += "/";
+      moption = "-32";
+      YPPath = "/lib:/usr/lib";
+      ClangLibPath = "/usr/lib/clang/";
+    } else {
+      GCCLibPath = TC.getGCCInternalMultiLibDir().str();
+      GCCLibPath += "/";
+      LibPath += "amd64/";
+      ShortLibPath += "amd64/";
+      moption = "-64";
+      YPPath = "/lib/amd64:/usr/lib/amd64";
+      ClangLibPath = "/usr/lib/clang/amd64/";
+    }
     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.getGCCInternalMultiLibDir().str();
+      GCCLibPath += "/";
+      LibPath += "sparcv9/";
+      ShortLibPath += "sparcv9/";
+      moption = "-64";
+      YPPath = "/lib/sparcv9:/usr/lib/sparcv9";
+      ClangLibPath = "/usr/lib/clang/sparcv9/";
+    }
+    break;
   case llvm::Triple::x86_64:
-    GCCLibPath += ("i386-" + T.getVendorName() + "-" + T.getOSName()).str();
-    GCCLibPath += "/4.5.2/amd64/";
+    if (m32) {
+      GCCLibPath = TC.getGCCInternalMultiLibDir().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/clang/amd64/";
+    }
     break;
+  case llvm::Triple::sparcv9:
+    if (m32) {
+      GCCLibPath = TC.getGCCInternalMultiLibDir().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/clang/sparcv9/";
+    }
+    break;
   default:
-    llvm_unreachable("Unsupported architecture");
+    D.Diag(diag::err_target_unsupported_arch) << T.getArchName()
+      << T.getTriple();
+    break;
   }
 
   ArgStringList CmdArgs;
 
-  // Demangle C++ names in errors
-  CmdArgs.push_back("-C");
+  CmdArgs.push_back(Args.MakeArgString("-zignore"));
 
-  if ((!Args.hasArg(options::OPT_nostdlib)) &&
-      (!Args.hasArg(options::OPT_shared))) {
-    CmdArgs.push_back("-e");
-    CmdArgs.push_back("_start");
+  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"));
+      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 warning for "-g: argument not used during compilation
+  Args.ClaimAllArgs(options::OPT_g_Group);
+
+  // 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 (Linker == "/usr/gnu/bin/ld.bfd" || Linker == "/usr/gnu/bin/ld.gold" ||
+      Linker == "/usr/gnu/bin/ld" || Linker == "/usr/bin/gld")
+    CmdArgs.push_back("--demangle");
+  else if (Linker == "/usr/bin/ld")
+    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 {
@@ -6125,41 +6577,261 @@
     assert(Output.isNothing() && "Invalid output.");
   }
 
+  const char* Values = "values-Xa.o";
+  const char* Xpg = "values-xpg4.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";
+      }
+    }
+  }
+
+  const char *gldm = 0;
+  if (Linker == "/usr/gnu/bin/ld.bfd" || Linker == "/usr/gnu/bin/ld.gold" ||
+      Linker == "/usr/gnu/bin/ld" || Linker == "/usr/bin/gld") {
+    switch (Arch) {
+    case llvm::Triple::x86:
+      if (m32)
+        gldm = "-m elf_i386";
+      else
+        gldm = "-m elf_x86_64";
+      break;
+    case llvm::Triple::x86_64:
+      if (m32)
+        gldm = "-m elf_i386";
+      else
+        gldm = "-m elf_x86_64";
+      break;
+    case llvm::Triple::sparc:
+      if (m32)
+        gldm = "-m elf32_sparc";
+      else
+        gldm = "-m elf64_sparc";
+      break;
+    case llvm::Triple::sparcv9:
+      if (m32)
+        gldm = "-m elf32_sparc";
+      else
+        gldm = "-m elf64_sparc";
+      break;
+    default:
+      break;
+    }
+
+    if (gldm)
+      CmdArgs.push_back(Args.MakeArgString(StringRef(gldm)));
+
+    if (Linker == "/usr/gnu/bin/ld.gold") {
+      if (Args.hasArg(options::OPT_O))
+        Args.AddAllArgs(CmdArgs, options::OPT_O);
+    }
+  }
+
+  if (Args.hasArg(options::OPT_v))
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-V")));
+
+  CmdArgs.push_back(Args.MakeArgString(StringRef("-Qy")));
+  if (Linker == "/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;
+
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nostartfiles)) {
     if (!Args.hasArg(options::OPT_shared)) {
-      CmdArgs.push_back(Args.MakeArgString(LibPath + "crt1.o"));
+      switch (Arch) {
+      case llvm::Triple::sparc:
+      case llvm::Triple::sparcv9:
+        crt1o = GCCLibPath;
+        break;
+      case llvm::Triple::x86:
+      case llvm::Triple::x86_64:
+        crt1o = LibPath;
+        break;
+      default:
+        D.Diag(diag::err_target_unsupported_arch) << T.getArchName()
+          << T.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-Xa.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-Xa.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"));
     }
-    if (getToolChain().getDriver().CCCIsCXX())
-      CmdArgs.push_back(Args.MakeArgString(LibPath + "cxa_finalize.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"));
+    }
+  }
 
-  CmdArgs.push_back(Args.MakeArgString("-L" + GCCLibPath));
+  // Itanium C++ ABI.
+  std::string CXAFinalize;
+  bool HasSystemCXAFinalize = false;
 
+  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);
 
-  AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+  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)) {
+      const char* zfiniarray = "-zfiniarray=__cxa_finalize";
+      CmdArgs.push_back(Args.MakeArgString(zfiniarray));
+    }
+  }
+
+  if (Linker == "/usr/gnu/bin/ld.gold" || Linker == "/usr/gnu/bin/ld" ||
+      Linker == "/usr/gnu/bin/ld.bfd") {
+    CmdArgs.push_back("-plugin");
+    std::string Plugin = D.Dir + "/../lib/LLVMgold.so";
+    CmdArgs.push_back(Args.MakeArgString(Plugin));
+  } else {
+    CmdArgs.push_back(moption);
+  }
+
+  if (Arg *A = Args.getLastArg(options::OPT_rpath)) {
+    StringRef V = A->getValue();
+    if (Linker == "/usr/gnu/bin/ld.gold" || Linker == "/usr/gnu/bin/ld" ||
+        Linker == "/usr/gnu/bin/ld.bfd") {
+      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, Linker.str());
+
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
-    if (getToolChain().getDriver().CCCIsCXX())
-      getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
-    CmdArgs.push_back("-lgcc_s");
-    if (!Args.hasArg(options::OPT_shared)) {
-      CmdArgs.push_back("-lgcc");
+    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) &&
@@ -6166,15 +6838,17 @@
       !Args.hasArg(options::OPT_nostartfiles)) {
     CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtend.o"));
   }
+
   CmdArgs.push_back(Args.MakeArgString(LibPath + "crtn.o"));
 
-  addProfileRT(getToolChain(), Args, CmdArgs);
+  addProfileRT(TC, Args, CmdArgs);
 
-  const char *Exec =
-    Args.MakeArgString(getToolChain().GetLinkerPath());
-  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
+  C.addCommand(llvm::make_unique<Command>(JA, *this,
+                                          Args.MakeArgString(Linker),
+                                          CmdArgs));
 }
 
+
 void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
                                      const InputInfo &Output,
                                      const InputInfoList &Inputs,
@@ -7280,6 +7954,40 @@
   if (isAndroid && !StaticLibgcc)
     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) {
--- tools/clang/lib/Driver/ToolChains.h	2015-08-29 19:24:32.064113013 -0700
+++ tools/clang/lib/Driver/ToolChains.h	2015-08-30 12:42:03.657485673 -0700
@@ -508,16 +508,106 @@
                              llvm::opt::ArgStringList &CC1Args) 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; }
+
+  std::string computeSysRoot() const;
+
+  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 findGCCMajorMinor() 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 getGCCMajorMinor() const { return GCCMajorMinor.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;
+
 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 GCCMajorMinor;
+  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 const bool SupportsClangLibCPlusPlus;
 };
 
 
--- tools/clang/lib/Driver/ToolChains.cpp	2015-04-27 01:13:25.000000000 -0700
+++ tools/clang/lib/Driver/ToolChains.cpp	2015-08-30 13:11:52.217344511 -0700
@@ -28,8 +28,10 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/Host.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/raw_ostream.h"
+
 #include <cstdlib> // ::getenv
 #include <system_error>
 
@@ -38,6 +40,19 @@
 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
+
+/// \brief Get our best guess at the multiarch triple for a target.
+static std::string getMultiarchTriple(const llvm::Triple &TargetTriple,
+                                      StringRef SysRoot);
+
 MachO::MachO(const Driver &D, const llvm::Triple &Triple,
                        const ArgList &Args)
   : ToolChain(D, Triple, Args) {
@@ -1214,6 +1229,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");
     }
 
@@ -1303,20 +1323,24 @@
   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-linux-android", "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[] = {
     "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "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"
+    "i686-montavista-linux", "i686-linux-android", "i586-linux-gnu",
+    "i386-pc-solaris2.11", "i386-pc-solaris2.12", "i386-pc-solaris2.13"
   };
 
   static const char *const MIPSLibDirs[] = { "/lib" };
@@ -1358,10 +1382,18 @@
 
   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[] = {
@@ -2649,16 +2681,703 @@
 
 /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
 
+const char *Solaris::MediatedGCCToolChainPath =
+"/path/to/mediated/gcc/toolchain";
+const 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/"),
+  GCCMajorMinor(""),
+  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);
 
-  getProgramPaths().push_back(getDriver().getInstalledDir());
+        if (!UseSpecifiedGCCToolChainPath) {
+          D.Diag(diag::err_drv_unsupported_rtlib_for_platform)
+            << GCCInstallDir << Triple.getTriple();
+        } else {
+          findGCCIncludeDirs(Triple, Args);
+          findGCCInternalLibDir(Triple, Args);
+        }
+      }
+    } else if (llvm::sys::fs::exists(Solaris::MediatedGCCToolChainPath)) {
+      GCCInstallDir = Solaris::MediatedGCCToolChainPath;
+      UseMediatedGCCToolChainPath = true;
+    } else {
+      findGCCMajorMinor();
+      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;
+      }
+    }
+
+    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);
+    }
+
+    getProgramPaths().push_back(GCCInstallDir);
   if (getDriver().getInstalledDir() != getDriver().Dir)
     getProgramPaths().push_back(getDriver().Dir);
 
+    llvm::Triple::ArchType Arch = 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:
+      getFilePaths().push_back(getDriver().Dir + "/../lib/amd64");
+      getFilePaths().push_back("/usr/lib/amd64");
+      march = mtune = "opteron";
+      break;
+    case llvm::Triple::sparcv9:
+      getFilePaths().push_back(getDriver().Dir + "/../lib/sparcv9");
+      getFilePaths().push_back("/usr/lib/sparcv9");
+      mcpu = "ultrasparc";
+      mtune = "ultrasparc";
+      march = "v9a";
+      break;
+    default:
   getFilePaths().push_back(getDriver().Dir + "/../lib");
   getFilePaths().push_back("/usr/lib");
+      break;
+    }
+
+    validate();
+
+    if (Args.hasArg(options::OPT_v))
+      this->print(llvm::errs());
+}
+
+std::string Solaris::computeSysRoot() const {
+  if (!getDriver().SysRoot.empty())
+    return getDriver().SysRoot;
+
+  return std::string("/");
+}
+
+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);
+
+  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);
+  }
+
+  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;
+
+  const Driver &D = getDriver();
+
+  // 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);
+    }
+  }
+
+  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_mtune_EQ)) {
+    StringRef V = A->getValue();
+    if (!V.empty())
+      mtune = V.str();
+
+    // FIXME: Impplement SPARC target features.
+    CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+    if (Arch == llvm::Triple::sparc || Arch == llvm::Triple::sparcv9) {
+      std::string S = "mtune=";
+      S += mtune;
+      CC1Args.push_back(DriverArgs.MakeArgString(S.c_str()));
+    } else {
+      CC1Args.push_back(DriverArgs.MakeArgString(mtune.c_str()));
+    }
+  }
+
+  if (Arg *A = DriverArgs.getLastArg(options::OPT_march_EQ)) {
+    StringRef V = A->getValue();
+    if (!V.empty())
+      march = V.str();
+
+    CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+
+    if ((Arch == llvm::Triple::sparc) || (Arch == llvm::Triple::sparcv9)) {
+      std::string S = "march=";
+      S += mtune;
+      CC1Args.push_back(DriverArgs.MakeArgString(S.c_str()));
+    } else {
+      CC1Args.push_back(DriverArgs.MakeArgString(march.c_str()));
+    }
+  }
+
+  if (Arch == llvm::Triple::sparc || Arch == llvm::Triple::sparcv9) {
+    if (Arg *A = DriverArgs.getLastArg(options::OPT_mcpu_EQ)) {
+      StringRef V = A->getValue();
+      if (!V.empty())
+        mcpu = V.str();
+      else
+        mcpu = "ultrasparc";
+    }
+
+    CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+    std::string S = "mcpu=";
+    S += mcpu;
+    CC1Args.push_back(DriverArgs.MakeArgString(S.c_str()));
+
+    if (Arg *A = DriverArgs.getLastArg(options::OPT_mvis)) {
+      CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+      CC1Args.push_back(DriverArgs.MakeArgString("vis"));
+    } else if (Arg *A = DriverArgs.getLastArg(options::OPT_mvis2)) {
+      CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+      CC1Args.push_back(DriverArgs.MakeArgString("vis2"));
+    } else if (Arg *A = DriverArgs.getLastArg(options::OPT_mvis3)) {
+      CC1Args.push_back(DriverArgs.MakeArgString("-target-feature"));
+      CC1Args.push_back(DriverArgs.MakeArgString("vis3"));
+    }
+  }
+}
+
+void Solaris::findGCCMajorMinor() const {
+  // FIXME: Add 5.2 after testing the ABI.
+  static const char* const GCCMM[] = { "4.8", "4.9" };
+
+  const char* P;
+  std::string Path;
+
+  if (UseMediatedGCCToolChainPath) {
+    // FIXME: IMPLEMENT.
+    // Needs spec.
+  }
+
+  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())) {
+        GCCMajorMinor = P;
+        break;
+      }
+    }
+  }
+}
+
+void Solaris::findGCCMajorMinorMicro(const llvm::Triple& T) const {
+  // FIXME: Add 5.2.0 after testing the ABI.
+  static const char* const GCCMMM[] = { "4.8.2", "4.8.5", "4.9.3" };
+
+  const char* P;
+  std::string Path;
+  std::string TripleString = llvm::sys::getDefaultTargetTriple();
+  llvm::Triple::ArchType Arch = T.getArch();
+
+  if (UseMediatedGCCToolChainPath) {
+    // FIXME: IMPLEMENT.
+    // Needs spec.
+  }
+
+  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] == GCCMajorMinor[0]) && (P[2] == GCCMajorMinor[2])) {
+        Path = GCCInstallDir;
+        Path.append("/");
+        Path.append(GCCMajorMinor);
+        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:
+              case llvm::Triple::sparc:
+                Test = Path + "/crtbegin.o";
+                break;
+              case llvm::Triple::x86_64:
+                Test = Path + "/amd64/crtbegin.o";
+                break;
+              case llvm::Triple::sparcv9:
+                Test = Path + "/sparcv9/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!");
+
+  GCCMajorMinor = "";
+  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 = reinterpret_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 = reinterpret_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 = reinterpret_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 = reinterpret_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;
+                    GCCMajorMinor = GCCMajorMinorMicro.substr(0, 3);
+                    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 if (UseMediatedGCCToolChainPath)
+    GCCInstallPath = Solaris::MediatedGCCToolChainPath;
+  else
+    GCCInstallPath = GCCInstallDir + GCCMajorMinor;
+
+  std::string GCCIncludeDir =
+    GCCInstallPath + "/include/c++/" + GCCMajorMinorMicro;
+  GCCIncludeDirs.push_back(GCCIncludeDir);
+
+  llvm::Triple::ArchType Arch = Triple.getArch();
+  GCCIncludeDir += "/";
+
+  switch (Arch) {
+    case llvm::Triple::x86:
+      GCCIncludeDir += Triple.getTriple();
+      if (Arg *A = Args.getLastArg(options::OPT_m64))
+        GCCIncludeDir += "/amd64";
+      break;
+    case llvm::Triple::sparc:
+      GCCIncludeDir += Triple.getTriple();
+      if (Arg *A = Args.getLastArg(options::OPT_m64))
+        GCCIncludeDir += "/sparcv9";
+      break;
+    case llvm::Triple::x86_64:
+      GCCIncludeDir += "i386-pc-";
+      GCCIncludeDir += Triple.getOSName();
+      if (Arg *A = Args.getLastArg(options::OPT_m64))
+        GCCIncludeDir += "/amd64";
+      break;
+    case llvm::Triple::sparcv9:
+      GCCIncludeDir += "sparc-sun-";
+      GCCIncludeDir += Triple.getOSName();
+      if (Arg *A = Args.getLastArg(options::OPT_m64))
+        GCCIncludeDir += "/sparcv9";
+      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 if (UseMediatedGCCToolChainPath)
+    GCCInstallPath = Solaris::MediatedGCCToolChainPath;
+  else
+    GCCInstallPath = GCCInstallDir + GCCMajorMinor;
+
+  GCCInternalLibDir = GCCInstallPath + "/lib/gcc/";
+
+  llvm::Triple::ArchType Arch = Triple.getArch();
+
+  switch (Arch) {
+    case llvm::Triple::x86:
+      GCCInternalLibDir += Triple.getTriple();
+      GCCInternalLibDir += "/";
+      GCCInternalLibDir += GCCMajorMinorMicro;
+      if (Arg *A = Args.getLastArg(options::OPT_m64)) {
+        GCCInternalMultiLibDir = GCCInternalLibDir;
+        GCCInternalLibDir += "/amd64";
+      } else if (Arg *A = Args.getLastArg(options::OPT_m32)) {
+        GCCInternalMultiLibDir = GCCInternalLibDir;
+        GCCInternalMultiLibDir += "/amd64";
+      } else {
+        GCCInternalMultiLibDir = GCCInternalLibDir;
+        GCCInternalMultiLibDir += "/amd64";
+      }
+
+      break;
+    case llvm::Triple::sparc:
+      GCCInternalLibDir += Triple.getTriple();
+      GCCInternalLibDir += "/";
+      GCCInternalLibDir += GCCMajorMinorMicro;
+      if (Arg *A = Args.getLastArg(options::OPT_m64)) {
+        GCCInternalMultiLibDir = GCCInternalLibDir;
+        GCCInternalLibDir += "/sparcv9";
+      } else if (Arg *A = Args.getLastArg(options::OPT_m32)) {
+        GCCInternalMultiLibDir = GCCInternalLibDir;
+        GCCInternalMultiLibDir += "/sparcv9";
+      } else {
+        GCCInternalMultiLibDir = GCCInternalLibDir;
+        GCCInternalMultiLibDir += "/sparcv9";
+      }
+      break;
+    case llvm::Triple::x86_64:
+      GCCInternalLibDir += "i386-pc-";
+      GCCInternalLibDir += Triple.getOSName();
+      GCCInternalLibDir += "/";
+      GCCInternalLibDir += GCCMajorMinorMicro;
+      GCCInternalMultiLibDir = GCCInternalLibDir;
+      if (Arg *A = Args.getLastArg(options::OPT_m64))
+        GCCInternalLibDir += "/amd64";
+      else if (Arg *A = Args.getLastArg(options::OPT_m32))
+        GCCInternalMultiLibDir += "/amd64";
+      else
+        GCCInternalLibDir += "/amd64";
+      break;
+    case llvm::Triple::sparcv9:
+      GCCInternalLibDir += "sparc-sun-";
+      GCCInternalLibDir += Triple.getOSName();
+      GCCInternalLibDir += "/";
+      GCCInternalLibDir += GCCMajorMinorMicro;
+      GCCInternalMultiLibDir = GCCInternalLibDir;
+      if (Arg *A = Args.getLastArg(options::OPT_m64))
+        GCCInternalLibDir += "/sparcv9";
+      else if (Arg *A = Args.getLastArg(options::OPT_m32))
+        GCCInternalMultiLibDir += "/sparcv9";
+      else
+        GCCInternalLibDir += "/sparcv9";
+      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 << "GCCMajorMinor: " << GCCMajorMinor.c_str() << "\n";
+  OS << "GCCMajorMinorMicro: " << GCCMajorMinorMicro.c_str() << "\n";
+  OS << "GCCInternalLibDir: " << GCCInternalLibDir.c_str() << "\n";
+  OS << "GCCInternalMultiLibDir: " << GCCInternalMultiLibDir.c_str() << "\n";
+  OS << "MediatedGCCToolChainPath: " << MediatedGCCToolChainPath << "\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 {
@@ -2669,6 +3388,21 @@
   return new tools::solaris::Link(*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;
+  }
+}
+
 /// Distribution (very bare-bones at the moment).
 
 enum Distro {
@@ -2696,6 +3430,27 @@
   UbuntuRaring,
   UbuntuSaucy,
   UbuntuTrusty,
+  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
 };
 
@@ -2715,6 +3470,10 @@
   return Distro >= UbuntuHardy && Distro <= UbuntuTrusty;
 }
 
+static bool IsSolaris(enum Distro Distro) {
+  return Distro >= Solaris_11 && Distro <= Solaris_13;
+}
+
 static Distro DetectDistro(llvm::Triple::ArchType Arch) {
   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
       llvm::MemoryBuffer::getFile("/etc/lsb-release");
@@ -2774,6 +3533,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 (llvm::sys::fs::exists("/etc/SuSE-release"))
     return OpenSUSE;
 
--- tools/llvm-shlib/Makefile	Sat Jul 18 11:44:45 2015
+++ tools/llvm-shlib/Makefile	Thu Aug 20 23:40:28 2015
@@ -74,6 +74,7 @@
     LLVMLibsOptions := -Wl,-z -Wl,rescan -Wl,-z -Wl,allextract $(LLVMLibsOptions)
     LLVMLibsOptions += -Wl,-h -Wl,lib$(LIBRARYNAME)$(SHLIBEXT)
     LLVMLibsOptions += -Wl,-z -Wl,defaultextract -Wl,-z -Wl,defs
+    LLVMLibsOptions += -lkstat
 endif
 
 ifeq ($(HOST_OS), $(filter $(HOST_OS), Cygwin MingW))
--- tools/clang/lib/Basic/Targets.cpp	2015-08-26 11:44:48.659904739 -0700
+++ tools/clang/lib/Basic/Targets.cpp	2015-08-26 11:47:36.318310023 -0700
@@ -530,28 +530,60 @@
 template<typename Target>
 class SolarisTargetInfo : public OSTargetInfo<Target> {
 protected:
-  void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+  virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
                     MacroBuilder &Builder) const override {
     DefineStd(Builder, "sun", Opts);
     DefineStd(Builder, "unix", Opts);
     Builder.defineMacro("__ELF__");
     Builder.defineMacro("__svr4__");
     Builder.defineMacro("__SVR4");
-    // Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and
-    // newer, but to 500 for everything else.  feature_test.h has a check to
-    // ensure that you are not using C99 with an old version of X/Open or C89
-    // with a new version.
-    if (Opts.C99)
+
+    if (Opts.C99 || Opts.CPlusPlus11) {
+      if (Opts.C99) {
       Builder.defineMacro("_XOPEN_SOURCE", "600");
-    else
+        Builder.defineMacro("_XPG6", "1");
+      }
+
+      Builder.defineMacro("__STDC_VERSION__", "199901L");
+      Builder.defineMacro("_STDC_C99", "1");
+      Builder.defineMacro("__C99FEATURES__", "1");
+    }
+
+    if (Opts.CPlusPlus11)
+      Builder.defineMacro("__cplusplus", "201103L");
+    else if (Opts.CPlusPlus14)
+      Builder.defineMacro("__cplusplus", "201402L");
+
+    if (Opts.CPlusPlus11) {
+      Builder.defineMacro("_STDC_C11", "1");
+      Builder.defineMacro("_STDC_C11_BCI", "1");
+      Builder.defineMacro("__XPG7_THREAD_MODEL__", "1");
+      Builder.defineMacro("_XPG7", "1");
+      Builder.defineMacro("_XOPEN_SOURCE", "700");
+    } else if (Opts.C11 || Opts.CPlusPlus14) {
+      Builder.defineMacro("__STDC_VERSION__", "201112L");
+      Builder.defineMacro("_STDC_C11", "1");
+      Builder.defineMacro("_STDC_C11_BCI", "1");
+      Builder.defineMacro("__XPG7_THREAD_MODEL__", "1");
+      Builder.defineMacro("_XPG7", "1");
+      Builder.defineMacro("_XOPEN_SOURCE", "700");
+    } else {
       Builder.defineMacro("_XOPEN_SOURCE", "500");
-    if (Opts.CPlusPlus)
-      Builder.defineMacro("__C99FEATURES__");
+      Builder.defineMacro("__STDC_VERSION__", "199409L");
+      if (Opts.CPlusPlus && !Opts.CPlusPlus11 && !Opts.CPlusPlus14)
+        Builder.defineMacro("__cplusplus", "199711L");
+    }
+
+    if ((Triple.getArchName() == "i386") || (Triple.getArchName() == "sparc"))
     Builder.defineMacro("_LARGEFILE_SOURCE");
+    else if ((Triple.getArchName() == "x86_64") ||
+             (Triple.getArchName() == "sparcv9"))
     Builder.defineMacro("_LARGEFILE64_SOURCE");
-    Builder.defineMacro("__EXTENSIONS__");
+
+    Builder.defineMacro("__EXTENSIONS__", "1");
     Builder.defineMacro("_REENTRANT");
   }
+
 public:
   SolarisTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
     this->UserLabelPrefix = "";