Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -2262,11 +2262,10 @@ case llvm::Triple::xcore: TC = new toolchains::XCoreToolChain(*this, Target, Args); break; - case llvm::Triple::shave: - TC = new toolchains::SHAVEToolChain(*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); Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ 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 ExtraTripleAliases = {}); /// \brief Check whether we detected a valid GCC install. bool isValid() const { return IsValid; } @@ -910,21 +911,29 @@ 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; virtual Tool *SelectTool(const JobAction &JA) const override; + void getCompilerSupportDir(SmallString<128> &CrtFileDir) const; + void getBuiltinLibDir(SmallString<128> &CrtFileDir) const; protected: Tool *getTool(Action::ActionClass AC) const override; Tool *buildAssembler() const override; Tool *buildLinker() const override; + bool isShaveCompilation(const llvm::Triple &T) const { + // 'sparc' is wrong, but if you accidentally leave off an -EL flag, + // it should not imply performing a SHAVE compile. + // Or looked at another way - T might be the uncanonical triple. + return !(T.getArch() == llvm::Triple::sparcel || + T.getArch() == llvm::Triple::sparc); + } private: mutable std::unique_ptr Compiler; Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ 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 ExtraTripleAliases) { llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); @@ -1220,6 +1221,8 @@ continue; for (const StringRef Candidate : CandidateTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); + for (const StringRef Candidate : ExtraTripleAliases) + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); } for (const StringRef Suffix : CandidateBiarchLibDirs) { const std::string LibDir = Prefix + Suffix.str(); @@ -3895,9 +3898,12 @@ // 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 handles several triples: +// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf +// We override SelectTool when the architecture is not sparc. +Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { + if (!isShaveCompilation(getTriple())) + return ToolChain::SelectTool(JA); switch (JA.getKind()) { case Action::CompileJobClass: if (!Compiler) @@ -3912,28 +3918,53 @@ } } -SHAVEToolChain::SHAVEToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_GCC(D, Triple, Args) {} +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 unkown "OS") as the canonical triple. + // This won't work to find gcc. Instead we hand 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. + GCCInstallation.init(D, Triple, Args, {"sparc-myriad-elf"}); +} -SHAVEToolChain::~SHAVEToolChain() {} +MyriadToolChain::~MyriadToolChain() {} -/// Following are methods necessary to avoid having moviClang be an abstract -/// class. +void MyriadToolChain::getCompilerSupportDir(SmallString<128> &Dir) const { + // This directory contains crt{i,n,begin,end}.o as well as libgcc. + // There are actually 4 choices: {le,be} x {fpu,nofpu}. + Dir = GCCInstallation.getInstallPath(); + // We pick little-endian with fpu, which is just "le/". + llvm::sys::path::append(Dir, "le"); +} +void MyriadToolChain::getBuiltinLibDir(SmallString<128> &Dir) const { + // This contains libc, libg (a superset of libc), libm, libstdc++, libssp. + // As above there are 4 choices, but we always pick "le/" + Dir = GCCInstallation.getParentLibPath(); + llvm::sys::path::append(Dir, "../sparc-myriad-elf/lib/le"); +} -Tool *SHAVEToolChain::getTool(Action::ActionClass AC) const { +Tool *MyriadToolChain::getTool(Action::ActionClass AC) const { + if (!isShaveCompilation(getTriple())) + return ToolChain::getTool(AC); // 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"); + llvm_unreachable("MyriadToolChain can't getTool"); } -Tool *SHAVEToolChain::buildLinker() const { - // SHAVEToolChain executables can not be linked except by the vendor tools. - llvm_unreachable("SHAVEToolChain can't buildLinker"); +Tool *MyriadToolChain::buildLinker() const { + // MyriadToolChain executables can not be linked except by the vendor tools. + // We run the so-called SHAVE linker even if there are no object files + // containing SHAVE executable code. + return new tools::SHAVE::Linker(*this); } -Tool *SHAVEToolChain::buildAssembler() const { +/// The Following method is necessary to avoid having moviClang be an abstract +/// class. +Tool *MyriadToolChain::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"); + llvm_unreachable("MyriadToolChain can't buildAssembler"); } Index: lib/Driver/Tools.h =================================================================== --- lib/Driver/Tools.h +++ lib/Driver/Tools.h @@ -792,6 +792,17 @@ const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + +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 SHAVE } // end namespace tools Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -9651,3 +9651,78 @@ C.addCommand(llvm::make_unique(JA, *this, Args.MakeArgString(Exec), CmdArgs, Inputs)); } + +void tools::SHAVE::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(getToolChain()); + const llvm::Triple &T = TC.getTriple(); + ArgStringList CmdArgs; + + SmallString<128> CrtObjDir; + TC.getCompilerSupportDir(CrtObjDir); + + CmdArgs.push_back("-EL"); // Endianness = little + + // 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. + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. + CmdArgs.push_back("-s"); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (T.getOS() == llvm::Triple::RTEMS) { + SmallString<128> Path1(CrtObjDir), Path2(CrtObjDir); + llvm::sys::path::append(Path1, "crti.o"); + llvm::sys::path::append(Path2, "crtbegin.o"); + CmdArgs.push_back(Args.MakeArgString(Path1)); + CmdArgs.push_back(Args.MakeArgString(Path2)); + } + + 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. + SmallString<128> LibDir; + TC.getBuiltinLibDir(LibDir); + CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibDir)); + CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + CrtObjDir)); + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + + if (T.getOS() == llvm::Triple::RTEMS) { + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lg"); + CmdArgs.push_back("-lrtemscpu"); + CmdArgs.push_back("-lrtemsbsp"); + CmdArgs.push_back("--end-group"); + } + CmdArgs.push_back("-lgcc"); + if (C.getDriver().CCCIsCXX()) + CmdArgs.push_back("-lstdc++"); + + if (T.getOS() == llvm::Triple::RTEMS) { + SmallString<128> Path1(CrtObjDir), Path2(CrtObjDir); + llvm::sys::path::append(Path1, "crtend.o"); + llvm::sys::path::append(Path2, "crtn.o"); + CmdArgs.push_back(Args.MakeArgString(Path1)); + CmdArgs.push_back(Args.MakeArgString(Path2)); + } + + std::string Exec = + Args.MakeArgString(TC.GetProgramPath("sparc-myriad-elf-ld")); + C.addCommand(llvm::make_unique(JA, *this, Args.MakeArgString(Exec), + CmdArgs, Inputs)); +}