Clang toolchain driver for PNaCl

This is a toolchain driver for PNaCl which aims to replace the
pnacl-clang and pnacl-clang++ Python scripts with a native
version integrated directly into Clang.

BUG=https://bugs.chromium.org/p/nativeclient/issues/detail?id=4347
R=dschuff@chromium.org

Review URL: https://codereview.chromium.org/1547623002 .
diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake
index 5d89b1a..34958d4 100644
--- a/include/clang/Config/config.h.cmake
+++ b/include/clang/Config/config.h.cmake
@@ -26,6 +26,9 @@
 /* Define if we have libxml2 */
 #cmakedefine CLANG_HAVE_LIBXML ${CLANG_HAVE_LIBXML}
 
+/* Define to the extension used for shared libraries, say, ".so". */
+#cmakedefine LTDL_SHLIB_EXT "${LTDL_SHLIB_EXT}"
+
 /* The LLVM product name and version */
 #define BACKEND_PACKAGE_STRING "${BACKEND_PACKAGE_STRING}"
 
diff --git a/include/clang/Config/config.h.in b/include/clang/Config/config.h.in
index dba05db..40666e2 100644
--- a/include/clang/Config/config.h.in
+++ b/include/clang/Config/config.h.in
@@ -26,6 +26,9 @@
 /* Define if we have libxml2 */
 #undef CLANG_HAVE_LIBXML
 
+/* The shared library extension */
+#undef LTDL_SHLIB_EXT
+
 #undef PACKAGE_STRING
 
 /* The LLVM product name and version */
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 560df19..e800176 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -345,6 +345,10 @@
   virtual bool
   AddFastMathRuntimeIfAvailable(const llvm::opt::ArgList &Args,
                                 llvm::opt::ArgStringList &CmdArgs) const;
+
+  /// isBitcodeOnlyTarget - Whether the toolchain has a coresponding backend
+  /// target.
+  virtual bool isBitcodeOnlyTarget() const { return false; }
 };
 
 } // end namespace driver
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index fe4d533..f79e7a3 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -27,6 +27,7 @@
 #include "llvm/ADT/Triple.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h" // @LOCALMOD
 #include <algorithm>
 #include <memory>
 using namespace clang;
@@ -6490,6 +6491,12 @@
   NumAliases = 0;
 }
 
+namespace {
+llvm::Target PNaClTarget;
+llvm::RegisterTarget<llvm::Triple::le32, /*HasJIT=*/false> P(
+    PNaClTarget, "le32", "PNaCl");
+} // end anonymous namespace.
+
 // We attempt to use PNaCl (le32) frontend and Mips32EL backend.
 class NaClMips32ELTargetInfo : public Mips32ELTargetInfo {
 public:
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 07a5e42..9dd557c 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1161,7 +1161,8 @@
   Arg *FinalPhaseArg;
   phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg);
 
-  if (FinalPhase == phases::Link && Args.hasArg(options::OPT_emit_llvm)) {
+  if (FinalPhase == phases::Link && Args.hasArg(options::OPT_emit_llvm) &&
+      !TC.isBitcodeOnlyTarget()) {
     Diag(clang::diag::err_drv_emit_llvm_link);
   }
 
@@ -1266,6 +1267,10 @@
         break;
       }
 
+      // Virtual targets don't perform assembly step.
+      if (Phase == phases::Assemble && TC.isBitcodeOnlyTarget())
+        continue;
+
       // Some types skip the assembler phase (e.g., llvm-bc), but we can't
       // encode this in the steps because the intermediate type depends on
       // arguments. Just special case here.
@@ -1364,7 +1369,7 @@
         Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
       return llvm::make_unique<BackendJobAction>(std::move(Input), Output);
     }
-    if (Args.hasArg(options::OPT_emit_llvm)) {
+    if (Args.hasArg(options::OPT_emit_llvm) || TC.isBitcodeOnlyTarget()) {
       types::ID Output =
         Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC;
       return llvm::make_unique<BackendJobAction>(std::move(Input), Output);
@@ -2063,7 +2068,10 @@
         TC = new toolchains::Linux(*this, Target, Args);
       break;
     case llvm::Triple::NaCl:
-      TC = new toolchains::NaCl_TC(*this, Target, Args);
+      if (Target.getArch() == llvm::Triple::le32)
+        TC = new toolchains::PNaClToolChain(*this, Target, Args);
+      else
+        TC = new toolchains::NaCl_TC(*this, Target, Args);
       break;
     case llvm::Triple::Solaris:
       TC = new toolchains::Solaris(*this, Target, Args);
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index ebd4d43..cc40bd1 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -3712,3 +3712,145 @@
                                 ArgStringList &CmdArgs) const {
   // We don't output any lib args. This is handled by xcc.
 }
+
+/// Generic_BC Toolchain
+
+Generic_BC::Generic_BC(const Driver &D, const llvm::Triple &Triple,
+                       const ArgList &Args)
+  : ToolChain(D, Triple, Args) {
+  getProgramPaths().push_back(getDriver().getInstalledDir());
+  if (getDriver().getInstalledDir() != getDriver().Dir)
+    getProgramPaths().push_back(getDriver().Dir);
+}
+
+/// PNaCl ToolChain
+
+PNaClToolChain::PNaClToolChain(const Driver &D, const llvm::Triple &Triple,
+                               const ArgList &Args)
+  : Generic_BC(D, Triple, Args) {
+  std::string SysRoot = computeSysRoot();
+
+  getFilePaths().push_back(SysRoot + "/lib");
+  getFilePaths().push_back(SysRoot + "/usr/lib");
+
+  getFilePaths().push_back(D.ResourceDir + "/lib/le32-nacl");
+}
+
+Tool *PNaClToolChain::buildLinker() const {
+  return new tools::pnacltools::Link(*this);
+}
+
+Tool *PNaClToolChain::buildAssembler() const {
+  llvm_unreachable("cannot build assembler");
+}
+
+std::string PNaClToolChain::computeSysRoot() const {
+  if (!getDriver().SysRoot.empty())
+    return getDriver().SysRoot;
+
+  return getDriver().Dir + "/../le32-nacl";
+}
+
+void PNaClToolChain::AddLinkRuntimeLibArgs(const ArgList &Args,
+                                           ArgStringList &CmdArgs) const {
+  CmdArgs.push_back("-lnacl");
+  CmdArgs.push_back("-lpnaclmm");
+}
+
+ToolChain::CXXStdlibType PNaClToolChain::GetCXXStdlibType(const ArgList &Args) const {
+  Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
+  if (!A)
+    return ToolChain::CST_Libcxx;
+
+  StringRef Value = A->getValue();
+  if (Value != "libc++") {
+    getDriver().Diag(diag::err_drv_invalid_stdlib_name)
+      << A->getAsString(Args);
+  }
+
+  return ToolChain::CST_Libcxx;
+}
+
+void PNaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+                                               ArgStringList &CC1Args) const {
+  const Driver &D = getDriver();
+  std::string SysRoot = computeSysRoot();
+
+  if (DriverArgs.hasArg(options::OPT_nostdinc))
+    return;
+
+  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+    SmallString<128> P(D.ResourceDir);
+    llvm::sys::path::append(P, "include");
+    addSystemInclude(DriverArgs, CC1Args, P.str());
+  }
+
+  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+    return;
+
+  // Check for configure-time C include directories.
+  StringRef CIncludeDirs(C_INCLUDE_DIRS);
+  if (CIncludeDirs != "") {
+    SmallVector<StringRef, 5> dirs;
+    CIncludeDirs.split(dirs, ":");
+    for (StringRef dir : dirs) {
+      StringRef Prefix =
+          llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : "";
+      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+    }
+    return;
+  }
+
+  // Add an include of '/include' directly. This isn't provided by default by
+  // system GCCs, but is often used with cross-compiling GCCs, and harmless to
+  // add even when Clang is acting as-if it were a system compiler.
+  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
+
+  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
+}
+
+void PNaClToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+                                                 ArgStringList &CC1Args) const {
+  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+      DriverArgs.hasArg(options::OPT_nostdincxx))
+    return;
+
+  // Check for -stdlib= flags. We only support libc++ but this consumes the arg
+  // if the value is libc++, and emits an error for other values.
+  GetCXXStdlibType(DriverArgs);
+
+  const std::string LibCXXIncludePathCandidates[] = {
+    // The primary location is within the Clang installation.
+    getDriver().Dir + "/../include/c++/v1",
+
+    // We also check the system as for a long time this is the only place Clang looked.
+    getDriver().SysRoot + "/usr/include/c++/v1"
+  };
+  for (const auto &IncludePath : LibCXXIncludePathCandidates) {
+    if (!llvm::sys::fs::exists(IncludePath))
+      continue;
+    // Add the first candidate that exists.
+    addSystemInclude(DriverArgs, CC1Args, IncludePath);
+    break;
+  }
+  return;
+}
+
+void PNaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
+                                         ArgStringList &CmdArgs) const {
+  switch (GetCXXStdlibType(Args)) {
+  case ToolChain::CST_Libcxx:
+    CmdArgs.push_back("-lc++");
+    break;
+  case ToolChain::CST_Libstdcxx:
+    break;
+  }
+}
+
+void PNaClToolChain::addClangTargetOptions(const ArgList &DriverArgs,
+                                       ArgStringList &CC1Args) const {
+  if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
+                         options::OPT_fno_use_init_array,
+                         getTriple().getOS() == llvm::Triple::NaCl))
+    CC1Args.push_back("-fuse-init-array");
+}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 33c97b2..11b47c1 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -757,6 +757,65 @@
   std::string NaClArmMacrosPath;
 };
 
+class LLVM_LIBRARY_VISIBILITY Generic_BC : public ToolChain {
+public:
+  Generic_BC(const Driver &D, const llvm::Triple &Triple,
+             const llvm::opt::ArgList &Args);
+
+  bool HasNativeLLVMSupport() const override { return true; }
+
+  bool IsIntegratedAssemblerDefault() const override {  return true; }
+
+  bool isPICDefault() const override { return false; }
+  bool isPIEDefault() const override { return false; }
+  bool isPICDefaultForced() const override { return false; }
+
+  bool isBitcodeOnlyTarget() const override { return true; }
+};
+
+class LLVM_LIBRARY_VISIBILITY PNaClToolChain : public Generic_BC {
+public:
+  PNaClToolChain(const Driver &D, const llvm::Triple &Triple,
+                 const llvm::opt::ArgList &Args);
+
+  /// Add the linker arguments to link the compiler runtime library.
+  virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
+                                     llvm::opt::ArgStringList &CmdArgs) const;
+
+  CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+
+  void
+  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                            llvm::opt::ArgStringList &CC1Args) const override;
+  void AddClangCXXStdlibIncludeArgs(
+      const llvm::opt::ArgList &DriverArgs,
+      llvm::opt::ArgStringList &CC1Args) const override;
+  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+                           llvm::opt::ArgStringList &CmdArgs) const override;
+
+  RuntimeLibType GetDefaultRuntimeLibType() const override {
+    return ToolChain::RLT_CompilerRT;
+  }
+
+  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+                             llvm::opt::ArgStringList &CC1Args) const override;
+
+protected:
+  Tool *buildLinker() const override;
+  Tool *buildAssembler() const override;
+
+private:
+  static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
+                                       StringRef GCCTriple,
+                                       StringRef GCCMultiarchTriple,
+                                       StringRef TargetMultiarchTriple,
+                                       Twine IncludeSuffix,
+                                       const llvm::opt::ArgList &DriverArgs,
+                                       llvm::opt::ArgStringList &CC1Args);
+
+  std::string computeSysRoot() const;
+};
+
 /// TCEToolChain - A tool chain using the llvm bitcode tools to perform
 /// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
 class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain {
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 05e81f5..dedeb68 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1766,6 +1766,13 @@
   CmdArgs.push_back ("-machine-sink-split=0");
 }
 
+void Clang::AddLe32TargetArgs(const ArgList &Args,
+                              ArgStringList &CmdArgs) const {
+  Args.ClaimAllArgs(options::OPT_emit_obj);
+
+  CmdArgs.push_back("-fno-gnu-inline-asm");
+}
+
 // Decode AArch64 features from string like +[no]featureA+[no]featureB+...
 static bool DecodeAArch64Features(const Driver &D, StringRef text,
                                   std::vector<const char *> &Features) {
@@ -2050,7 +2057,8 @@
 
   if (types::isCXX(InputType)) {
     bool CXXExceptionsEnabled =
-        Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU();
+        Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU() &&
+        Triple.getArch() != llvm::Triple::le32;
     Arg *ExceptionArg = Args.getLastArg(
         options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions,
         options::OPT_fexceptions, options::OPT_fno_exceptions);
@@ -3270,6 +3278,9 @@
   case llvm::Triple::hexagon:
     AddHexagonTargetArgs(Args, CmdArgs);
     break;
+
+  case llvm::Triple::le32:
+    AddLe32TargetArgs(Args, CmdArgs);
   }
 
   // Add clang-cl arguments.
@@ -4525,7 +4536,8 @@
   // Enable vectorization per default according to the optimization level
   // selected. For optimization levels that want vectorization we use the alias
   // option to simplify the hasFlag logic.
-  bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false);
+  bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false) &&
+      getToolChain().getArch() != llvm::Triple::le32;
   OptSpecifier VectorizeAliasOption = EnableVec ? options::OPT_O_Group :
     options::OPT_fvectorize;
   if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption,
@@ -4533,7 +4545,8 @@
     CmdArgs.push_back("-vectorize-loops");
 
   // -fslp-vectorize is enabled based on the optimization level selected.
-  bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true);
+  bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true) &&
+      getToolChain().getArch() != llvm::Triple::le32;
   OptSpecifier SLPVectAliasOption = EnableSLPVec ? options::OPT_O_Group :
     options::OPT_fslp_vectorize;
   if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption,
@@ -8181,6 +8194,186 @@
                                           ToolChain.Linker.c_str(), CmdArgs));
 }
 
+void pnacltools::Link::ConstructJob(Compilation &C, const JobAction &JA,
+                                    const InputInfo &Output,
+                                    const InputInfoList &Inputs,
+                                    const ArgList &Args,
+                                    const char *LinkingOutput) const {
+  const toolchains::PNaClToolChain& ToolChain =
+    static_cast<const toolchains::PNaClToolChain&>(getToolChain());
+  const Driver &D = ToolChain.getDriver();
+
+  ArgStringList CmdArgs;
+
+  // Silence warning for "clang -g foo.o -o foo"
+  Args.ClaimAllArgs(options::OPT_g_Group);
+  // and "clang -emit-llvm foo.o -o foo"
+  Args.ClaimAllArgs(options::OPT_emit_llvm);
+  // and for "clang -w foo.o -o foo". Other warning options are already
+  // handled somewhere else.
+  Args.ClaimAllArgs(options::OPT_w);
+  // Silence warning for libgcc since we only support compiler-rt.
+  Args.ClaimAllArgs(options::OPT_shared_libgcc);
+  Args.ClaimAllArgs(options::OPT_static_libgcc);
+
+  if (!D.SysRoot.empty())
+    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+  if (Arg *A = Args.getLastArg(options::OPT_shared,
+                               options::OPT_dynamic,
+                               options::OPT_rdynamic))
+    D.Diag(diag::err_drv_unsupported_opt) << A->getOption().getName();
+
+  std::string TripleStr = ToolChain.ComputeEffectiveClangTriple(Args);
+  if (ToolChain.getArch() != llvm::Triple::le32)
+    D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName()
+                                              << TripleStr;
+
+  Args.AddAllArgs(CmdArgs, options::OPT_static);
+  if (!Args.hasArg(options::OPT_static))
+    CmdArgs.push_back("-static");
+
+  bool EH = exceptionSettings(Args, ToolChain.getTriple());
+
+  bool IsRelocatable = false;
+  if (Args.hasArg(options::OPT_Wl_COMMA)) {
+    for (arg_iterator
+          it = Args.filtered_begin(options::OPT_Wl_COMMA),
+          ie = Args.filtered_end();
+         it != ie;
+         ++it) {
+      for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i) {
+        if (StringRef((*it)->getValue(i)) == "-r")
+          IsRelocatable = true;
+      }
+    }
+  }
+
+  if (!IsRelocatable) {
+    // The following functions are implemented in the native support library.
+    // Before a .pexe is produced, they get rewritten to intrinsic calls.
+    // However, this rewriting happens after bitcode linking - so gold has to
+    // be told that these are allowed to remain unresolved.
+    const StringRef AllowUnresolvedSymbols[] = {
+      "memcpy",
+      "memset",
+      "memmove",
+      "setjmp",
+      "longjmp"
+    };
+    CmdArgs.push_back("--undef-sym-check");
+    for (StringRef Symbol : AllowUnresolvedSymbols)
+      CmdArgs.push_back(Args.MakeArgString(Twine("--allow-unresolved=") + Symbol));
+
+    // These TLS layout functions are either defined by the ExpandTls pass or
+    // (for non-ABI-stable code only) by PNaCl's native support code.
+    const StringRef AllowUnresolvedSymbols1[] = {
+      "__nacl_tp_tls_offset",
+      "__nacl_tp_tdb_offset",
+      "__nacl_get_arch",
+    };
+    for (StringRef Symbol : AllowUnresolvedSymbols1)
+      CmdArgs.push_back(Args.MakeArgString(Twine("--allow-unresolved=") + Symbol));
+
+    if (EH) {
+      // These symbols are defined by libsupc++ and the PNaClSjLjEH pass
+      // generates references to them.
+      const StringRef UndefinedSymbols[] = {
+        "__pnacl_eh_stack",
+        "__pnacl_eh_resume",
+      };
+      for (StringRef Symbol : UndefinedSymbols)
+        CmdArgs.push_back(Args.MakeArgString(Twine("--undefined=") + Symbol));
+      // These symbols are defined by the PNaClSjLjEH pass and libsupc++ refers
+      // to them.
+      const StringRef AllowUnresolvedSymbols[] = {
+        "__pnacl_eh_type_table",
+        "__pnacl_eh_action_table",
+        "__pnacl_eh_filter_table",
+      };
+      for (StringRef Symbol : AllowUnresolvedSymbols)
+        CmdArgs.push_back(Args.MakeArgString(Twine("--allow-unresolved=") + Symbol));
+    }
+  }
+
+  CmdArgs.push_back("-o");
+  CmdArgs.push_back(Output.getFilename());
+
+  if (!Args.hasArg(options::OPT_nostdlib) &&
+      !Args.hasArg(options::OPT_nostartfiles)) {
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.x")));
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.bc")));
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.bc")));
+
+    const char *unwind = nullptr;
+    if (EH)
+      unwind = "sjlj_eh_redirect.bc";
+    else
+      unwind = "unwind_stubs.bc";
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(unwind)));
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_L);
+  Args.AddAllArgs(CmdArgs, options::OPT_u);
+
+  const ToolChain::path_list &Paths = ToolChain.getFilePaths();
+
+  for (const auto &Path : Paths)
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+
+  // Tell the linker to load the plugin. This has to come before AddLinkerInputs
+  // as gold requires -plugin to come before any -plugin-opt that -Wl might
+  // forward.
+  CmdArgs.push_back("-plugin");
+  std::string Plugin = ToolChain.getDriver().Dir +
+      "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" LTDL_SHLIB_EXT;
+
+  CmdArgs.push_back(Args.MakeArgString(Plugin));
+
+  CmdArgs.push_back("-plugin-opt=emit-llvm");
+  if (!IsRelocatable)
+    CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mtriple=") +
+                                         ToolChain.getTriple().str()));
+
+  if (EH)
+    CmdArgs.push_back("-plugin-opt=-enable-pnacl-sjlj-eh");
+
+  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+    CmdArgs.push_back("--no-demangle");
+
+  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+
+  if (D.CCCIsCXX() &&
+      !Args.hasArg(options::OPT_nostdlib) &&
+      !Args.hasArg(options::OPT_nodefaultlibs)) {
+    ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+    CmdArgs.push_back("-lpthread");
+    CmdArgs.push_back("-lm");
+  }
+  // Silence warnings when linking C code with a C++ '-stdlib' argument.
+  Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+  if (!Args.hasArg(options::OPT_nostdlib)) {
+    if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+      CmdArgs.push_back("--start-group");
+
+      if ((Args.hasArg(options::OPT_pthread) ||
+           Args.hasArg(options::OPT_pthreads)))
+        CmdArgs.push_back("-lpthread");
+
+      CmdArgs.push_back("-lc");
+      CmdArgs.push_back("-lgcc");
+      CmdArgs.push_back("-lm");
+      ToolChain.AddLinkRuntimeLibArgs(Args, CmdArgs);
+
+      CmdArgs.push_back("--end-group");
+    }
+  }
+
+  std::string Linker = ToolChain.GetProgramPath("le32-nacl-ld.gold");
+  C.addCommand(
+      llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), CmdArgs));
+}
 
 void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
                                    const InputInfo &Output,
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index aa292bf..4f7590e 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -75,6 +75,8 @@
                           llvm::opt::ArgStringList &CmdArgs) const;
     void AddHexagonTargetArgs(const llvm::opt::ArgList &Args,
                               llvm::opt::ArgStringList &CmdArgs) const;
+    void AddLe32TargetArgs(const llvm::opt::ArgList &Args,
+                           llvm::opt::ArgStringList &CmdArgs) const;
 
     enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile };
 
@@ -536,6 +538,22 @@
   };
 }
 
+namespace pnacltools {
+  class LLVM_LIBRARY_VISIBILITY Link : public Tool  {
+  public:
+    Link(const ToolChain &TC) : Tool("PNaCl::Link", "linker", TC) {}
+
+    bool hasIntegratedCPP() const override { return false; }
+    bool isLinkJob() const override { return true; }
+
+    void ConstructJob(Compilation &C, const JobAction &JA,
+                              const InputInfo &Output,
+                              const InputInfoList &Inputs,
+                              const llvm::opt::ArgList &TCArgs,
+                              const char *LinkingOutput) const override;
+  };
+}
+
   /// minix -- Directly call GNU Binutils assembler and linker
 namespace minix {
   class LLVM_LIBRARY_VISIBILITY Assemble : public GnuTool  {
diff --git a/test/CodeGen/pr18235.c b/test/CodeGen/pr18235.c
index d3f12ee..ae059d2 100644
--- a/test/CodeGen/pr18235.c
+++ b/test/CodeGen/pr18235.c
@@ -1,3 +1,3 @@
-// RUN: not %clang_cc1 -triple le32-unknown-nacl %s -S -o - 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple spir-unknown-unknown %s -S -o - 2>&1 | FileCheck %s
 
 // CHECK: error: unable to create target: 'No available targets are compatible with this triple, see -version for the available targets.'
diff --git a/test/Driver/le32-unknown-nacl.cpp b/test/Driver/le32-unknown-nacl.cpp
index 379ddb6..d836674 100644
--- a/test/Driver/le32-unknown-nacl.cpp
+++ b/test/Driver/le32-unknown-nacl.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang -target le32-unknown-nacl -### %s -emit-llvm-only -c 2>&1 | FileCheck %s -check-prefix=ECHO
-// RUN: %clang -target le32-unknown-nacl %s -emit-llvm -S -c -o - | FileCheck %s
-// RUN: %clang -target le32-unknown-nacl %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
+// RUN: %clang -target le32-unknown-nacl -### %s -c 2>&1 | FileCheck %s -check-prefix=ECHO
+// RUN: %clang -target le32-unknown-nacl %s -S -c -o - | FileCheck %s
+// RUN: %clang -target le32-unknown-nacl %s -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
 
 // ECHO: {{.*}} "-cc1" {{.*}}le32-unknown-nacl.c
 
diff --git a/test/Driver/pnacl-direct.c b/test/Driver/pnacl-direct.c
new file mode 100644
index 0000000..375c454
--- /dev/null
+++ b/test/Driver/pnacl-direct.c
@@ -0,0 +1,74 @@
+// Test clang changes for PNaCl Support including:
+//    include paths, library paths, emulation, default static
+
+// RUN: %clang -no-canonical-prefixes -### -o %t.o %s \
+// RUN:     -target le32-unknown-nacl -resource-dir foo 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-LE32 %s
+// CHECK-LE32: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-LE32: "-triple" "le32-unknown-nacl"
+// CHECK-LE32: "-emit-llvm-bc"
+// CHECK-LE32: "-fuse-init-array"
+// CHECK-LE32: "-fno-gnu-inline-asm"
+// CHECK-LE32: "-resource-dir" "foo"
+// CHECK-LE32: "-internal-isystem" "foo{{/|\\\\}}include"
+// CHECK-LE32: "-internal-externc-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}le32-nacl{{/|\\\\}}include"
+// CHECK-LE32: "-internal-externc-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}le32-nacl{{/|\\\\}}usr{{/|\\\\}}include"
+// CHECK-LE32: le32-nacl-ld.gold{{(.exe)?}}"
+// CHECK-LE32: "-static"
+// CHECK-LE32: "--undef-sym-check"
+// CHECK-LE32: "--allow-unresolved=memcpy"
+// CHECK-LE32: "--allow-unresolved=memset"
+// CHECK-LE32: "--allow-unresolved=memmove"
+// CHECK-LE32: "--allow-unresolved=setjmp"
+// CHECK-LE32: "--allow-unresolved=longjmp"
+// CHECK-LE32: "--allow-unresolved=__nacl_tp_tls_offset"
+// CHECK-LE32: "--allow-unresolved=__nacl_tp_tdb_offset"
+// CHECK-LE32: "crt1.x"
+// CHECK-LE32: "crti.bc"
+// CHECK-LE32: "crtbegin.bc"
+// CHECK-LE32: "unwind_stubs.bc"
+// CHECK-LE32: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}le32-nacl{{/|\\\\}}lib"
+// CHECK-LE32: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}le32-nacl{{/|\\\\}}usr{{/|\\\\}}lib"
+// CHECK-LE32: "-Lfoo{{/|\\\\}}lib{{/|\\\\}}le32-nacl"
+// CHECK-LE32: "-plugin" "{{.*}}{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}LLVMgold.so"
+// CHECK-LE32: "-plugin-opt=emit-llvm"
+// CHECK-LE32: "-plugin-opt=mtriple=le32-unknown-nacl"
+// CHECK-LE32-NOT: -lpthread
+
+// RUN: %clangxx -no-canonical-prefixes -### -o %t.o %s \
+// RUN:     -target le32-unknown-nacl -fexceptions -resource-dir foo 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-LE32-CXX %s
+// CHECK-LE32-CXX: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-LE32-CXX: "-triple" "le32-unknown-nacl"
+// CHECK-LE32-CXX: "-emit-llvm-bc"
+// CHECK-LE32-CXX: "-fuse-init-array"
+// CHECK-LE32-CXX: "-fno-gnu-inline-asm"
+// CHECK-LE32-CXX: "-resource-dir" "foo"
+// CHECK-LE32-CXX: "-internal-isystem" "foo{{/|\\\\}}include"
+// CHECK-LE32-CXX: "-internal-externc-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}le32-nacl{{/|\\\\}}include"
+// CHECK-LE32-CXX: "-internal-externc-isystem" "{{.*}}{{/|\\\\}}..{{/|\\\\}}le32-nacl{{/|\\\\}}usr{{/|\\\\}}include"
+// CHECK-LE32-CXX: le32-nacl-ld.gold{{(.exe)?}}"
+// CHECK-LE32-CXX: "-static"
+// CHECK-LE32-CXX: "--undef-sym-check"
+// CHECK-LE32-CXX: "--allow-unresolved=memcpy"
+// CHECK-LE32-CXX: "--allow-unresolved=memset"
+// CHECK-LE32-CXX: "--allow-unresolved=memmove"
+// CHECK-LE32-CXX: "--allow-unresolved=setjmp"
+// CHECK-LE32-CXX: "--allow-unresolved=longjmp"
+// CHECK-LE32-CXX: "--allow-unresolved=__nacl_tp_tls_offset"
+// CHECK-LE32-CXX: "--allow-unresolved=__nacl_tp_tdb_offset"
+// CHECK-LE32-CXX: "--undefined=__pnacl_eh_stack"
+// CHECK-LE32-CXX: "--undefined=__pnacl_eh_resume"
+// CHECK-LE32-CXX: "--allow-unresolved=__pnacl_eh_type_table"
+// CHECK-LE32-CXX: "--allow-unresolved=__pnacl_eh_action_table"
+// CHECK-LE32-CXX: "crt1.x"
+// CHECK-LE32-CXX: "crti.bc"
+// CHECK-LE32-CXX: "crtbegin.bc"
+// CHECK-LE32-CXX: "sjlj_eh_redirect.bc"
+// CHECK-LE32-CXX: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}le32-nacl{{/|\\\\}}lib"
+// CHECK-LE32-CXX: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}le32-nacl{{/|\\\\}}usr{{/|\\\\}}lib"
+// CHECK-LE32-CXX: "-plugin" "{{.*}}{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}LLVMgold.so"
+// CHECK-LE32-CXX: "-plugin-opt=emit-llvm"
+// CHECK-LE32-CXX: "-plugin-opt=mtriple=le32-unknown-nacl"
+// CHECK-LE32-CXX: "-plugin-opt=-enable-pnacl-sjlj-eh"
+// CHECK-LE32-CXX: -lpthread