Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ 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); 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; } @@ -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 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(); @@ -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: + llvm_unreachable("Unsupported architecture"); + 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()); } - -Tool *SHAVEToolChain::buildLinker() const { - // SHAVEToolChain executables can not be linked except by the vendor tools. - llvm_unreachable("SHAVEToolChain can't buildLinker"); +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::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; } Index: lib/Driver/Tools.h =================================================================== --- lib/Driver/Tools.h +++ 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 Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -9735,3 +9735,81 @@ C.addCommand(llvm::make_unique(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(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(JA, *this, Args.MakeArgString(Exec), + CmdArgs, Inputs)); +} Index: test/Driver/shave-toolchain.c =================================================================== --- test/Driver/shave-toolchain.c +++ test/Driver/shave-toolchain.c @@ -1,3 +1,9 @@ +// RUN: %clang -no-canonical-prefixes -### -target sparc-myriad-rtems-elf %s \ +// RUN: -B %S/Inputs/basic_myriad_tree 2>&1 | FileCheck %s -check-prefix=LINK_WITH_RTEMS +// LINK_WITH_RTEMS: crti.o +// LINK_WITH_RTEMS: crtbegin.o +// LINK_WITH_RTEMS: -lrtems + // Ensure that '-target shave' picks a different compiler. // Also check that '-I' is turned into '-i:' for the assembler. @@ -8,26 +14,26 @@ // As such, we test only for a trailing quote in its rendering. // The same goes for "moviAsm". -// RUN: %clang -target shave -c -### %s -isystem somewhere -Icommon -Wa,-yippee 2>&1 \ +// RUN: %clang -target shave-myriad -c -### %s -isystem somewhere -Icommon -Wa,-yippee 2>&1 \ // RUN: | FileCheck %s -check-prefix=MOVICOMPILE // MOVICOMPILE: moviCompile" "-DMYRIAD2" "-mcpu=myriad2" "-S" "-isystem" "somewhere" "-I" "common" // MOVICOMPILE: moviAsm" "-no6thSlotCompression" "-cv:myriad2" "-noSPrefixing" "-a" // MOVICOMPILE: "-yippee" "-i:somewhere" "-i:common" "-elf" -// RUN: %clang -target shave -c -### %s -DEFINE_ME -UNDEFINE_ME 2>&1 \ +// RUN: %clang -target shave-myriad -c -### %s -DEFINE_ME -UNDEFINE_ME 2>&1 \ // RUN: | FileCheck %s -check-prefix=DEFINES // DEFINES: "-D" "EFINE_ME" "-U" "NDEFINE_ME" -// RUN: %clang -target shave -c -### %s -Icommon -iquote quotepath -isystem syspath 2>&1 \ +// RUN: %clang -target shave-myriad -c -### %s -Icommon -iquote quotepath -isystem syspath 2>&1 \ // RUN: | FileCheck %s -check-prefix=INCLUDES // INCLUDES: "-iquote" "quotepath" "-isystem" "syspath" -// RUN: %clang -target shave -c -### %s -g -fno-inline-functions \ +// RUN: %clang -target shave-myriad -c -### %s -g -fno-inline-functions \ // RUN: -fno-inline-functions-called-once -Os -Wall -MF dep.d \ // RUN: -ffunction-sections 2>&1 | FileCheck %s -check-prefix=PASSTHRU_OPTIONS // PASSTHRU_OPTIONS: "-g" "-fno-inline-functions" "-fno-inline-functions-called-once" // PASSTHRU_OPTIONS: "-Os" "-Wall" "-MF" "dep.d" "-ffunction-sections" -// RUN: %clang -target shave -c %s -o foo.o -### -MD -MF dep.d 2>&1 \ +// RUN: %clang -target shave-myriad -c %s -o foo.o -### -MD -MF dep.d 2>&1 \ // RUN: | FileCheck %s -check-prefix=MDMF // MDMF: "-S" "-MD" "-MF" "dep.d" "-MT" "foo.o"