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