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(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 { + // '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(); @@ -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); } @@ -1448,6 +1451,7 @@ TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); break; case llvm::Triple::sparc: + case llvm::Triple::sparcel: LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); @@ -3895,9 +3899,26 @@ // 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 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"}); +} + +MyriadToolChain::~MyriadToolChain() {} + +// 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 +3933,43 @@ } } -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. +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}. + // We pick little-endian with fpu, which is just "le/". + 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()); + // As above there are 4 choices, but we always pick "le/" + llvm::sys::path::append(Result, "../sparc-myriad-elf/lib/le"); + Dir.assign(Result.str()); +} -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,81 @@ 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; + bool UseStartfiles = !Args.hasArg(options::OPT_nostartfiles); + + std::string StartFilesDir, BuiltinLibDir; + TC.getCompilerSupportDir(StartFilesDir); + TC.getBuiltinLibDir(BuiltinLibDir); + + 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. + + // 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 (T.getOS() == llvm::Triple::RTEMS) { + CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crti.o")); + CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crtbegin.o")); + } else { + // crt0.o is apparently independent of gcc, so it's not in StartFilesDir. + CmdArgs.push_back(Args.MakeArgString(BuiltinLibDir + "/crt0.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("-lg"); + // 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,20 +14,20 @@ // As such, we test only for a trailing quote in its rendering. // The same goes for "moviAsm". -// RUN: %clang -target shave -c -### %s -Icommon 2>&1 \ +// RUN: %clang -target shave-myriad -c -### %s -Icommon 2>&1 \ // RUN: | FileCheck %s -check-prefix=MOVICOMPILE // MOVICOMPILE: moviCompile" "-DMYRIAD2" "-mcpu=myriad2" "-S" "-I" "common" // MOVICOMPILE: moviAsm" "-no6thSlotCompression" "-cv:myriad2" "-noSPrefixing" "-a" "-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 \ // RUN: -ffunction-sections 2>&1 | FileCheck %s -check-prefix=F_G_O_W_OPTIONS // F_G_O_W_OPTIONS: "-g" "-fno-inline-functions" "-fno-inline-functions-called-once"