1 //===--- Myriad.cpp - Myriad ToolChain Implementations ----------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "Myriad.h" 10 #include "CommonArgs.h" 11 #include "clang/Driver/Compilation.h" 12 #include "clang/Driver/Driver.h" 13 #include "clang/Driver/DriverDiagnostic.h" 14 #include "clang/Driver/Options.h" 15 #include "llvm/Option/ArgList.h" 16 17 using namespace clang::driver; 18 using namespace clang::driver::toolchains; 19 using namespace clang; 20 using namespace llvm::opt; 21 22 using tools::addPathIfExists; 23 24 void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, 25 const InputInfo &Output, 26 const InputInfoList &Inputs, 27 const ArgList &Args, 28 const char *LinkingOutput) const { 29 ArgStringList CmdArgs; 30 assert(Inputs.size() == 1); 31 const InputInfo &II = Inputs[0]; 32 assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX || 33 II.getType() == types::TY_PP_CXX); 34 35 if (JA.getKind() == Action::PreprocessJobClass) { 36 Args.ClaimAllArgs(); 37 CmdArgs.push_back("-E"); 38 } else { 39 assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. 40 CmdArgs.push_back("-S"); 41 CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. 42 } 43 CmdArgs.push_back("-DMYRIAD2"); 44 45 // Append all -I, -iquote, -isystem paths, defines/undefines, 'f' 46 // flags, 'g' flags, 'M' flags, optimize flags, warning options, 47 // mcpu flags, mllvm flags, and Xclang flags. 48 // These are spelled the same way in clang and moviCompile. 49 Args.AddAllArgsExcept( 50 CmdArgs, 51 {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ, 52 options::OPT_D, options::OPT_U, options::OPT_f_Group, 53 options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group, 54 options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ, 55 options::OPT_mllvm, options::OPT_Xclang}, 56 {options::OPT_fno_split_dwarf_inlining}); 57 Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. 58 59 // If we're producing a dependency file, and assembly is the final action, 60 // then the name of the target in the dependency file should be the '.o' 61 // file, not the '.s' file produced by this step. For example, instead of 62 // /tmp/mumble.s: mumble.c .../someheader.h 63 // the filename on the lefthand side should be "mumble.o" 64 if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && 65 C.getActions().size() == 1 && 66 C.getActions()[0]->getKind() == Action::AssembleJobClass) { 67 Arg *A = Args.getLastArg(options::OPT_o); 68 if (A) { 69 CmdArgs.push_back("-MT"); 70 CmdArgs.push_back(Args.MakeArgString(A->getValue())); 71 } 72 } 73 74 CmdArgs.push_back(II.getFilename()); 75 CmdArgs.push_back("-o"); 76 CmdArgs.push_back(Output.getFilename()); 77 78 std::string Exec = 79 Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); 80 C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), 81 CmdArgs, Inputs)); 82 } 83 84 void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 85 const InputInfo &Output, 86 const InputInfoList &Inputs, 87 const ArgList &Args, 88 const char *LinkingOutput) const { 89 ArgStringList CmdArgs; 90 91 assert(Inputs.size() == 1); 92 const InputInfo &II = Inputs[0]; 93 assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input. 94 assert(Output.getType() == types::TY_Object); 95 96 CmdArgs.push_back("-no6thSlotCompression"); 97 const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); 98 if (CPUArg) 99 CmdArgs.push_back( 100 Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue()))); 101 CmdArgs.push_back("-noSPrefixing"); 102 CmdArgs.push_back("-a"); // Mystery option. 103 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 104 for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) { 105 A->claim(); 106 CmdArgs.push_back( 107 Args.MakeArgString(std::string("-i:") + A->getValue(0))); 108 } 109 CmdArgs.push_back(II.getFilename()); 110 CmdArgs.push_back( 111 Args.MakeArgString(std::string("-o:") + Output.getFilename())); 112 113 std::string Exec = 114 Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); 115 C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), 116 CmdArgs, Inputs)); 117 } 118 119 void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, 120 const InputInfo &Output, 121 const InputInfoList &Inputs, 122 const ArgList &Args, 123 const char *LinkingOutput) const { 124 const auto &TC = 125 static_cast<const toolchains::MyriadToolChain &>(getToolChain()); 126 const llvm::Triple &T = TC.getTriple(); 127 ArgStringList CmdArgs; 128 bool UseStartfiles = 129 !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); 130 bool UseDefaultLibs = 131 !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); 132 // Silence warning if the args contain both -nostdlib and -stdlib=. 133 Args.getLastArg(options::OPT_stdlib_EQ); 134 135 if (T.getArch() == llvm::Triple::sparc) 136 CmdArgs.push_back("-EB"); 137 else // SHAVE assumes little-endian, and sparcel is expressly so. 138 CmdArgs.push_back("-EL"); 139 140 // The remaining logic is mostly like gnutools::Linker::ConstructJob, 141 // but we never pass through a --sysroot option and various other bits. 142 // For example, there are no sanitizers (yet) nor gold linker. 143 144 // Eat some arguments that may be present but have no effect. 145 Args.ClaimAllArgs(options::OPT_g_Group); 146 Args.ClaimAllArgs(options::OPT_w); 147 Args.ClaimAllArgs(options::OPT_static_libgcc); 148 149 if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. 150 CmdArgs.push_back("-s"); 151 152 CmdArgs.push_back("-o"); 153 CmdArgs.push_back(Output.getFilename()); 154 155 if (UseStartfiles) { 156 // If you want startfiles, it means you want the builtin crti and crtbegin, 157 // but not crt0. Myriad link commands provide their own crt0.o as needed. 158 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); 159 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); 160 } 161 162 Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 163 options::OPT_e, options::OPT_s, options::OPT_t, 164 options::OPT_Z_Flag, options::OPT_r}); 165 166 TC.AddFilePathLibArgs(Args, CmdArgs); 167 168 bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs); 169 AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); 170 171 if (UseDefaultLibs) { 172 if (NeedsSanitizerDeps) 173 linkSanitizerRuntimeDeps(TC, CmdArgs); 174 if (C.getDriver().CCCIsCXX()) { 175 if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { 176 CmdArgs.push_back("-lc++"); 177 CmdArgs.push_back("-lc++abi"); 178 } else 179 CmdArgs.push_back("-lstdc++"); 180 } 181 if (T.getOS() == llvm::Triple::RTEMS) { 182 CmdArgs.push_back("--start-group"); 183 CmdArgs.push_back("-lc"); 184 CmdArgs.push_back("-lgcc"); // circularly dependent on rtems 185 // You must provide your own "-L" option to enable finding these. 186 CmdArgs.push_back("-lrtemscpu"); 187 CmdArgs.push_back("-lrtemsbsp"); 188 CmdArgs.push_back("--end-group"); 189 } else { 190 CmdArgs.push_back("-lc"); 191 CmdArgs.push_back("-lgcc"); 192 } 193 } 194 if (UseStartfiles) { 195 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); 196 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); 197 } 198 199 std::string Exec = 200 Args.MakeArgString(TC.GetProgramPath("sparc-myriad-rtems-ld")); 201 C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), 202 CmdArgs, Inputs)); 203 } 204 205 MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, 206 const ArgList &Args) 207 : Generic_ELF(D, Triple, Args) { 208 // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use 209 // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple. 210 // This won't work to find gcc. Instead we give the installation detector an 211 // extra triple, which is preferable to further hacks of the logic that at 212 // present is based solely on getArch(). In particular, it would be wrong to 213 // choose the myriad installation when targeting a non-myriad sparc install. 214 switch (Triple.getArch()) { 215 default: 216 D.Diag(clang::diag::err_target_unsupported_arch) 217 << Triple.getArchName() << "myriad"; 218 LLVM_FALLTHROUGH; 219 case llvm::Triple::shave: 220 return; 221 case llvm::Triple::sparc: 222 case llvm::Triple::sparcel: 223 GCCInstallation.init(Triple, Args, {"sparc-myriad-rtems"}); 224 } 225 226 if (GCCInstallation.isValid()) { 227 // This directory contains crt{i,n,begin,end}.o as well as libgcc. 228 // These files are tied to a particular version of gcc. 229 SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); 230 addPathIfExists(D, CompilerSupportDir, getFilePaths()); 231 } 232 // libstd++ and libc++ must both be found in this one place. 233 addPathIfExists(D, D.Dir + "/../sparc-myriad-rtems/lib", getFilePaths()); 234 } 235 236 MyriadToolChain::~MyriadToolChain() {} 237 238 void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 239 ArgStringList &CC1Args) const { 240 if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) 241 addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); 242 } 243 244 void MyriadToolChain::addLibCxxIncludePaths( 245 const llvm::opt::ArgList &DriverArgs, 246 llvm::opt::ArgStringList &CC1Args) const { 247 std::string Path(getDriver().getInstalledDir()); 248 addSystemInclude(DriverArgs, CC1Args, Path + "/../include/c++/v1"); 249 } 250 251 void MyriadToolChain::addLibStdCxxIncludePaths( 252 const llvm::opt::ArgList &DriverArgs, 253 llvm::opt::ArgStringList &CC1Args) const { 254 StringRef LibDir = GCCInstallation.getParentLibPath(); 255 const GCCVersion &Version = GCCInstallation.getVersion(); 256 StringRef TripleStr = GCCInstallation.getTriple().str(); 257 const Multilib &Multilib = GCCInstallation.getMultilib(); 258 addLibStdCXXIncludePaths( 259 LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, 260 "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args); 261 } 262 263 // MyriadToolChain handles several triples: 264 // {shave,sparc{,el}}-myriad-{rtems,unknown}-elf 265 Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { 266 // The inherited method works fine if not targeting the SHAVE. 267 if (!isShaveCompilation(getTriple())) 268 return ToolChain::SelectTool(JA); 269 switch (JA.getKind()) { 270 case Action::PreprocessJobClass: 271 case Action::CompileJobClass: 272 if (!Compiler) 273 Compiler.reset(new tools::SHAVE::Compiler(*this)); 274 return Compiler.get(); 275 case Action::AssembleJobClass: 276 if (!Assembler) 277 Assembler.reset(new tools::SHAVE::Assembler(*this)); 278 return Assembler.get(); 279 default: 280 return ToolChain::getTool(JA.getKind()); 281 } 282 } 283 284 Tool *MyriadToolChain::buildLinker() const { 285 return new tools::Myriad::Linker(*this); 286 } 287 288 SanitizerMask MyriadToolChain::getSupportedSanitizers() const { 289 return SanitizerKind::Address; 290 } 291