[Shave]: Drive sparc-myriad-elf-ld directly rather than via gcc.
Differential Revision: http://reviews.llvm.org/D12541
llvm-svn: 247924
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 2edb6ce..384d027 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -2262,15 +2262,14 @@
case llvm::Triple::xcore:
TC = new toolchains::XCoreToolChain(*this, Target, Args);
break;
- case llvm::Triple::shave:
- TC = new toolchains::SHAVEToolChain(*this, Target, Args);
- break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
TC = new toolchains::WebAssembly(*this, Target, Args);
break;
default:
- if (Target.isOSBinFormatELF())
+ if (Target.getVendor() == llvm::Triple::Myriad)
+ TC = new toolchains::MyriadToolChain(*this, Target, Args);
+ else if (Target.isOSBinFormatELF())
TC = new toolchains::Generic_ELF(*this, Target, Args);
else if (Target.isOSBinFormatMachO())
TC = new toolchains::MachO(*this, Target, Args);
diff --git a/clang/lib/Driver/ToolChains.cpp b/clang/lib/Driver/ToolChains.cpp
index 1569872..592542d 100644
--- a/clang/lib/Driver/ToolChains.cpp
+++ b/clang/lib/Driver/ToolChains.cpp
@@ -1170,7 +1170,8 @@
/// necessary because the driver doesn't store the final version of the target
/// triple.
void Generic_GCC::GCCInstallationDetector::init(
- const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args) {
+ const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args,
+ const ArrayRef<std::string> ExtraTripleAliases) {
llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit()
? TargetTriple.get64BitArchVariant()
: TargetTriple.get32BitArchVariant();
@@ -1218,6 +1219,8 @@
const std::string LibDir = Prefix + Suffix.str();
if (!llvm::sys::fs::exists(LibDir))
continue;
+ for (const StringRef Candidate : ExtraTripleAliases) // Try these first.
+ ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate);
for (const StringRef Candidate : CandidateTripleAliases)
ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate);
}
@@ -3920,9 +3923,33 @@
// We don't output any lib args. This is handled by xcc.
}
-// SHAVEToolChain does not call Clang's C compiler.
-// We override SelectTool to avoid testing ShouldUseClangCompiler().
-Tool *SHAVEToolChain::SelectTool(const JobAction &JA) const {
+MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_GCC(D, Triple, Args) {
+ // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use
+ // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple.
+ // This won't work to find gcc. Instead we give the installation detector an
+ // extra triple, which is preferable to further hacks of the logic that at
+ // present is based solely on getArch(). In particular, it would be wrong to
+ // choose the myriad installation when targeting a non-myriad sparc install.
+ switch (Triple.getArch()) {
+ default:
+ D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() << "myriad";
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::shave:
+ GCCInstallation.init(D, Triple, Args, {"sparc-myriad-elf"});
+ }
+}
+
+MyriadToolChain::~MyriadToolChain() {}
+
+// MyriadToolChain handles several triples:
+// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf
+Tool *MyriadToolChain::SelectTool(const JobAction &JA) const {
+ // The inherited method works fine if not targeting the SHAVE.
+ if (!isShaveCompilation(getTriple()))
+ return ToolChain::SelectTool(JA);
switch (JA.getKind()) {
case Action::CompileJobClass:
if (!Compiler)
@@ -3937,30 +3964,29 @@
}
}
-SHAVEToolChain::SHAVEToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_GCC(D, Triple, Args) {}
-
-SHAVEToolChain::~SHAVEToolChain() {}
-
-/// Following are methods necessary to avoid having moviClang be an abstract
-/// class.
-
-Tool *SHAVEToolChain::getTool(Action::ActionClass AC) const {
- // SelectTool() must find a tool using the method in the superclass.
- // There's nothing we can do if that fails.
- llvm_unreachable("SHAVEToolChain can't getTool");
+void MyriadToolChain::getCompilerSupportDir(std::string &Dir) const {
+ // This directory contains crt{i,n,begin,end}.o as well as libgcc.
+ // These files are tied to a particular version of gcc.
+ SmallString<128> Result(GCCInstallation.getInstallPath());
+ // There are actually 4 choices: {le,be} x {fpu,nofpu}
+ // but as this toolchain is for LEON sparc, it can assume FPU.
+ if (this->getTriple().getArch() == llvm::Triple::sparcel)
+ llvm::sys::path::append(Result, "le");
+ Dir.assign(Result.str());
+}
+void MyriadToolChain::getBuiltinLibDir(std::string &Dir) const {
+ // The contents of LibDir are independent of the version of gcc.
+ // This contains libc, libg (a superset of libc), libm, libstdc++, libssp.
+ SmallString<128> Result(GCCInstallation.getParentLibPath());
+ if (this->getTriple().getArch() == llvm::Triple::sparcel)
+ llvm::sys::path::append(Result, "../sparc-myriad-elf/lib/le");
+ else
+ llvm::sys::path::append(Result, "../sparc-myriad-elf/lib");
+ Dir.assign(Result.str());
}
-Tool *SHAVEToolChain::buildLinker() const {
- // SHAVEToolChain executables can not be linked except by the vendor tools.
- llvm_unreachable("SHAVEToolChain can't buildLinker");
-}
-
-Tool *SHAVEToolChain::buildAssembler() const {
- // This one you'd think should be reachable since we expose an
- // assembler to the driver, except not the way it expects.
- llvm_unreachable("SHAVEToolChain can't buildAssembler");
+Tool *MyriadToolChain::buildLinker() const {
+ return new tools::Myriad::Linker(*this);
}
bool WebAssembly::IsMathErrnoDefault() const { return false; }
diff --git a/clang/lib/Driver/ToolChains.h b/clang/lib/Driver/ToolChains.h
index f68e84c..c3d729c 100644
--- a/clang/lib/Driver/ToolChains.h
+++ b/clang/lib/Driver/ToolChains.h
@@ -101,7 +101,8 @@
public:
GCCInstallationDetector() : IsValid(false) {}
void init(const Driver &D, const llvm::Triple &TargetTriple,
- const llvm::opt::ArgList &Args);
+ const llvm::opt::ArgList &Args,
+ const ArrayRef<std::string> ExtraTripleAliases = {});
/// \brief Check whether we detected a valid GCC install.
bool isValid() const { return IsValid; }
@@ -918,21 +919,23 @@
llvm::opt::ArgStringList &CmdArgs) const override;
};
-/// SHAVEToolChain - A tool chain using the compiler installed by the
-/// Movidius SDK into MV_TOOLS_DIR (which we assume will be copied to llvm's
-/// installation dir) to perform all subcommands.
-class LLVM_LIBRARY_VISIBILITY SHAVEToolChain : public Generic_GCC {
+/// MyriadToolChain - A tool chain using either clang or the external compiler
+/// installed by the Movidius SDK to perform all subcommands.
+class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_GCC {
public:
- SHAVEToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- ~SHAVEToolChain() override;
+ MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~MyriadToolChain() override;
Tool *SelectTool(const JobAction &JA) const override;
+ void getCompilerSupportDir(std::string &Dir) const;
+ void getBuiltinLibDir(std::string &Dir) const;
protected:
- Tool *getTool(Action::ActionClass AC) const override;
- Tool *buildAssembler() const override;
Tool *buildLinker() const override;
+ bool isShaveCompilation(const llvm::Triple &T) const {
+ return T.getArch() == llvm::Triple::shave;
+ }
private:
mutable std::unique_ptr<Tool> Compiler;
diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp
index 755ea1b..f8358cd 100644
--- a/clang/lib/Driver/Tools.cpp
+++ b/clang/lib/Driver/Tools.cpp
@@ -9736,3 +9736,81 @@
C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
CmdArgs, Inputs));
}
+
+void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &TC =
+ static_cast<const toolchains::MyriadToolChain &>(getToolChain());
+ const llvm::Triple &T = TC.getTriple();
+ ArgStringList CmdArgs;
+ bool UseStartfiles = !Args.hasArg(options::OPT_nostartfiles);
+
+ std::string StartFilesDir, BuiltinLibDir;
+ TC.getCompilerSupportDir(StartFilesDir);
+ TC.getBuiltinLibDir(BuiltinLibDir);
+
+ if (T.getArch() == llvm::Triple::sparc)
+ CmdArgs.push_back("-EB");
+ else // SHAVE assumes little-endian, and sparcel is expressly so.
+ CmdArgs.push_back("-EL");
+
+ // The remaining logic is mostly like gnutools::Linker::ConstructJob,
+ // but we never pass through a --sysroot option and various other bits.
+ // For example, there are no sanitizers (yet) nor gold linker.
+
+ // Eat some arguments that may be present but have no effect.
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ Args.ClaimAllArgs(options::OPT_w);
+ Args.ClaimAllArgs(options::OPT_static_libgcc);
+
+ if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option.
+ CmdArgs.push_back("-s");
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (UseStartfiles) {
+ // If you want startfiles, it means you want the builtin crti and crtbegin,
+ // but not crt0. Myriad link commands provide their own crt0.o as needed.
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crti.o"));
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crtbegin.o"));
+ }
+
+ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_e, options::OPT_s, options::OPT_t,
+ options::OPT_Z_Flag, options::OPT_r});
+
+ // The linker doesn't use these builtin paths unless directed to,
+ // because it was not compiled for support with sysroots, nor does
+ // it have a default of little-endian with FPU.
+ CmdArgs.push_back(Args.MakeArgString("-L" + BuiltinLibDir));
+ CmdArgs.push_back(Args.MakeArgString("-L" + StartFilesDir));
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
+
+ if (T.getOS() == llvm::Triple::RTEMS) {
+ CmdArgs.push_back("--start-group");
+ CmdArgs.push_back("-lc");
+ // You must provide your own "-L" option to enable finding these.
+ CmdArgs.push_back("-lrtemscpu");
+ CmdArgs.push_back("-lrtemsbsp");
+ CmdArgs.push_back("--end-group");
+ } else {
+ CmdArgs.push_back("-lc");
+ }
+ if (C.getDriver().CCCIsCXX())
+ CmdArgs.push_back("-lstdc++");
+ CmdArgs.push_back("-lgcc");
+ if (UseStartfiles) {
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crtend.o"));
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crtn.o"));
+ }
+
+ std::string Exec =
+ Args.MakeArgString(TC.GetProgramPath("sparc-myriad-elf-ld"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ CmdArgs, Inputs));
+}
diff --git a/clang/lib/Driver/Tools.h b/clang/lib/Driver/Tools.h
index 010bac0..80f0d49 100644
--- a/clang/lib/Driver/Tools.h
+++ b/clang/lib/Driver/Tools.h
@@ -794,6 +794,23 @@
};
} // end namespace SHAVE
+/// The Myriad toolchain uses tools that are in two different namespaces.
+/// The Compiler and Assembler as defined above are in the SHAVE namespace,
+/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE,
+/// is in the Myriad namespace.
+namespace Myriad {
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("shave::Linker", "ld", 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;
+};
+} // end namespace Myriad
+
} // end namespace tools
} // end namespace driver
} // end namespace clang