Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -80,6 +80,7 @@ def m_arm_Features_Group : OptionGroup<"">, Group; def m_aarch64_Features_Group : OptionGroup<"">, Group; def m_ppc_Features_Group : OptionGroup<"">, Group; +def m_shave_Features_Group : OptionGroup<"">, Group; def m_libc_Group : OptionGroup<"">, Group; def u_Group : OptionGroup<"">; @@ -1756,6 +1757,8 @@ def mv5 : Flag<["-"], "mv5">, Group, Alias, AliasArgs<["v5"]>; +def mprog_model_EQ : Joined<["-"], "mprog-model=">, Group; + // These are legacy user-facing driver-level option spellings. They are always // aliases for options that are spelled using the more common Unix / GNU flag // style of double-dash and equals-joined flags. Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -3729,8 +3729,7 @@ } Tool *SHAVEToolChain::buildLinker() const { - // SHAVEToolChain executables can not be linked except by the vendor tools. - llvm_unreachable("SHAVEToolChain can't buildLinker"); + return new tools::SHAVE::Linker(*this); } Tool *SHAVEToolChain::buildAssembler() const { Index: lib/Driver/Tools.h =================================================================== --- lib/Driver/Tools.h +++ lib/Driver/Tools.h @@ -758,6 +758,20 @@ 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", "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; +}; + } // end namespace SHAVE } // end namespace tools Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -9091,3 +9091,175 @@ C.addCommand( llvm::make_unique(JA, *this, Args.MakeArgString(Exec), CmdArgs)); } + +void tools::SHAVE::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + // Directory structure is: + // + // mdk + // tools <-- $MV_TOOLS_DIR is this + // + // linux64 + // ... + + const char *ToolsRoot = ::getenv("MV_TOOLS_DIR"); + // The version is numbered 'n.n.n.n' for arbitrary values that are opaque + // as far as clang is concerned. + std::string ToolsVersion; + // The "Host" directory contains both host tools and target libraries + // even though target-only stuff is bitwise identical across + // the the 3 possible host toolchains {linux32 | linux64 | win32}. + std::string ToolsHostDir; + // The "Common" directory has target-only stuff in it such as "crt0.o". + std::string ToolsCommonDir; + + if (ToolsRoot) { + // Detecting which version of the tools are installed is patterned after + // GCCInstallationDetector::ScanLibDirForGCCTriple and other places. + // It is assumed that multiple versions will not co-exist side-by-side, + // or rather if they do, that picking any is ok. + SmallString<128> DirNative; + std::error_code EC; + llvm::sys::path::native(ToolsRoot, DirNative); + for (llvm::sys::fs::directory_iterator Dir(DirNative, EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + // Look for a subdirectory of ToolsDir that has within it + // a directory named 'common'. + SmallString<128> CommonDir(Dir->path()); + llvm::sys::path::append(CommonDir, "common"); + if (llvm::sys::fs::exists(CommonDir)) { + ToolsCommonDir = CommonDir.str(); + ToolsVersion = llvm::sys::path::filename(Dir->path()); + break; + } + } + } + if (ToolsCommonDir.empty()) { + ToolsRoot = "/usr/local/myriad/tools"; + ToolsVersion = "00.50.62.5"; + ToolsCommonDir = "/usr/local/mdk/tools/" + ToolsVersion + "/common"; + } + llvm::Triple HostTriple(LLVM_HOST_TRIPLE); + const char *HostSubdir = "linux64"; + if (HostTriple.isOSWindows()) + HostSubdir = "win32"; + else if (HostTriple.getArch() == llvm::Triple::x86) + HostSubdir = "linux32"; + SmallString<128> HostDir(ToolsRoot); + llvm::sys::path::append(HostDir, ToolsVersion, HostSubdir); + + SmallString<127> GnuToolsRoot(ToolsHostDir); + llvm::sys::path::append(GnuToolsRoot, "sparc-myriad-elf-4.8.2"); + + CmdArgs.push_back("-EL"); // Endianness = little + CmdArgs.push_back("-O9"); // Optimization + CmdArgs.push_back("--gc-sections"); + CmdArgs.push_back("-warn-common"); + + static const char *LibDirs[] = {"lib/gcc/sparc-myriad-elf/4.8.2/le", + "sparc-myriad-elf/lib/le"}; + for (const auto &Dir : LibDirs) { + SmallString<128> FullPath(GnuToolsRoot); + llvm::sys::path::append(FullPath, Dir); + CmdArgs.push_back("-L"); + CmdArgs.push_back(Args.MakeArgString(FullPath)); + } + + SmallString<127> CommonDir(ToolsRoot); + llvm::sys::path::append(CommonDir, "../mdk/common"); + + SmallString<128> LinkerScriptDir(CommonDir); + llvm::sys::path::append(LinkerScriptDir, "scripts/ld/myriad2collection"); + CmdArgs.push_back("-L"); + CmdArgs.push_back(Args.MakeArgString(LinkerScriptDir)); + + SmallString<128> MainLinkerScript(LinkerScriptDir); + llvm::sys::path::append(MainLinkerScript, + "myriad2_default_memory_map_elf.ldscript"); + CmdArgs.push_back("-T"); + CmdArgs.push_back(Args.MakeArgString(MainLinkerScript)); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + enum ProgrammingModel { Bare, OneLeon, BothLeons, RTEMS } ProgrammingModel; + Arg *Arg = Args.getLastArg(options::OPT_mprog_model_EQ); + if (Arg) { + std::string Value = Arg->getValue(0); + // FIXME: Instead of "Fell off the end of a string-switch" + // print something like "unsupported programming model". + ProgrammingModel = llvm::StringSwitch(Value) + .Case("bare", Bare) + .Case("oneleon", OneLeon) + .Case("bothleons", BothLeons) + .Case("rtems", RTEMS); + } + + if (ProgrammingModel != Bare) { + static const char *StartFiles[] = {"crti.o", "crtbegin.o"}; + for (const auto &File : StartFiles) { + SmallString<128> FullPath(GnuToolsRoot); + llvm::sys::path::append(FullPath, "lib/gcc/sparc-myriad-elf/4.8.2/le", + File); + CmdArgs.push_back(Args.MakeArgString(FullPath)); + } + } + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + + CmdArgs.push_back("--start-group"); + if (ProgrammingModel == Bare) { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lc"); + } else { + static const char *RTEMSStaticLibs[] = {"librtemsbsp.a", "librtemscpu.a"}; + static const char *CStaticLibs[] = {"libc.a", "libssp.a", + "libssp_nonshared.a"}; + static const char *GCCStaticLibs[] = {"libgcc.a"}; + for (const auto &File : RTEMSStaticLibs) { + SmallString<128> FullPath(ToolsCommonDir); + llvm::sys::path::append(FullPath, "rtems/prebuilt/lib", File); + CmdArgs.push_back(Args.MakeArgString(FullPath)); + } + for (const auto &File : CStaticLibs) { + SmallString<128> FullPath(ToolsHostDir); + llvm::sys::path::append( + FullPath, "sparc-myriad-elf-4.8.2/sparc-myriad-elf/lib/le", File); + CmdArgs.push_back(Args.MakeArgString(FullPath)); + } + for (const auto &File : GCCStaticLibs) { + SmallString<128> FullPath(GnuToolsRoot); + llvm::sys::path::append(FullPath, "lib/gcc/sparc-myriad-elf/4.8.2/le", + File); + CmdArgs.push_back(Args.MakeArgString(FullPath)); + } + } + + if (C.getDriver().CCCIsCXX()) { + CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back("-lsupc++"); + } + + CmdArgs.push_back("--end-group"); + + if (ProgrammingModel != Bare) { + static const char *EndFiles[] = {"crtend.o", "crtn.o"}; + for (const auto &File : EndFiles) { + SmallString<128> FullPath(GnuToolsRoot); + llvm::sys::path::append(FullPath, "lib/gcc/sparc-myriad-elf/4.8.2/le", + File); + CmdArgs.push_back(Args.MakeArgString(FullPath)); + } + } + + SmallString<128> LinkerExec(GnuToolsRoot); + llvm::sys::path::append(LinkerExec, "bin/sparc-myriad-elf-ld"); + + C.addCommand(llvm::make_unique( + JA, *this, Args.MakeArgString(LinkerExec), CmdArgs)); +} Index: test/Driver/shave-toolchain.cpp =================================================================== --- /dev/null +++ test/Driver/shave-toolchain.cpp @@ -0,0 +1,4 @@ +// RUN: %clangxx %s -### -target shave 2>&1 | FileCheck %s +// CHECK: moviCompile +// CHECK: moviAsm +// CHECK: "-lstdc++" "-lsupc++"