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, ResponseFileSupport::None(), 81 Args.MakeArgString(Exec), CmdArgs, 82 Inputs, Output)); 83 } 84 85 void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 86 const InputInfo &Output, 87 const InputInfoList &Inputs, 88 const ArgList &Args, 89 const char *LinkingOutput) const { 90 ArgStringList CmdArgs; 91 92 assert(Inputs.size() == 1); 93 const InputInfo &II = Inputs[0]; 94 assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input. 95 assert(Output.getType() == types::TY_Object); 96 97 CmdArgs.push_back("-no6thSlotCompression"); 98 const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); 99 if (CPUArg) 100 CmdArgs.push_back( 101 Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue()))); 102 CmdArgs.push_back("-noSPrefixing"); 103 CmdArgs.push_back("-a"); // Mystery option. 104 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 105 for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) { 106 A->claim(); 107 CmdArgs.push_back( 108 Args.MakeArgString(std::string("-i:") + A->getValue(0))); 109 } 110 CmdArgs.push_back(II.getFilename()); 111 CmdArgs.push_back( 112 Args.MakeArgString(std::string("-o:") + Output.getFilename())); 113 114 std::string Exec = 115 Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); 116 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 117 Args.MakeArgString(Exec), CmdArgs, 118 Inputs, Output)); 119 } 120 121 void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, 122 const InputInfo &Output, 123 const InputInfoList &Inputs, 124 const ArgList &Args, 125 const char *LinkingOutput) const { 126 const auto &TC = 127 static_cast<const toolchains::MyriadToolChain &>(getToolChain()); 128 const llvm::Triple &T = TC.getTriple(); 129 ArgStringList CmdArgs; 130 bool UseStartfiles = 131 !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); 132 bool UseDefaultLibs = 133 !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); 134 // Silence warning if the args contain both -nostdlib and -stdlib=. 135 Args.getLastArg(options::OPT_stdlib_EQ); 136 137 if (T.getArch() == llvm::Triple::sparc) 138 CmdArgs.push_back("-EB"); 139 else // SHAVE assumes little-endian, and sparcel is expressly so. 140 CmdArgs.push_back("-EL"); 141 142 // The remaining logic is mostly like gnutools::Linker::ConstructJob, 143 // but we never pass through a --sysroot option and various other bits. 144 // For example, there are no sanitizers (yet) nor gold linker. 145 146 // Eat some arguments that may be present but have no effect. 147 Args.ClaimAllArgs(options::OPT_g_Group); 148 Args.ClaimAllArgs(options::OPT_w); 149 Args.ClaimAllArgs(options::OPT_static_libgcc); 150 151 if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. 152 CmdArgs.push_back("-s"); 153 154 CmdArgs.push_back("-o"); 155 CmdArgs.push_back(Output.getFilename()); 156 157 if (UseStartfiles) { 158 // If you want startfiles, it means you want the builtin crti and crtbegin, 159 // but not crt0. Myriad link commands provide their own crt0.o as needed. 160 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); 161 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); 162 } 163 164 Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 165 options::OPT_e, options::OPT_s, options::OPT_t, 166 options::OPT_Z_Flag, options::OPT_r}); 167 168 TC.AddFilePathLibArgs(Args, CmdArgs); 169 170 bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs); 171 AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); 172 173 if (UseDefaultLibs) { 174 if (NeedsSanitizerDeps) 175 linkSanitizerRuntimeDeps(TC, CmdArgs); 176 if (C.getDriver().CCCIsCXX()) { 177 if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { 178 CmdArgs.push_back("-lc++"); 179 CmdArgs.push_back("-lc++abi"); 180 } else 181 CmdArgs.push_back("-lstdc++"); 182 } 183 if (T.getOS() == llvm::Triple::RTEMS) { 184 CmdArgs.push_back("--start-group"); 185 CmdArgs.push_back("-lc"); 186 CmdArgs.push_back("-lgcc"); // circularly dependent on rtems 187 // You must provide your own "-L" option to enable finding these. 188 CmdArgs.push_back("-lrtemscpu"); 189 CmdArgs.push_back("-lrtemsbsp"); 190 CmdArgs.push_back("--end-group"); 191 } else { 192 CmdArgs.push_back("-lc"); 193 CmdArgs.push_back("-lgcc"); 194 } 195 } 196 if (UseStartfiles) { 197 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); 198 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); 199 } 200 201 std::string Exec = 202 Args.MakeArgString(TC.GetProgramPath("sparc-myriad-rtems-ld")); 203 C.addCommand(std::make_unique<Command>( 204 JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Exec), 205 CmdArgs, Inputs, Output)); 206 } 207 208 MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, 209 const ArgList &Args) 210 : Generic_ELF(D, Triple, Args) { 211 // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use 212 // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple. 213 // This won't work to find gcc. Instead we give the installation detector an 214 // extra triple, which is preferable to further hacks of the logic that at 215 // present is based solely on getArch(). In particular, it would be wrong to 216 // choose the myriad installation when targeting a non-myriad sparc install. 217 switch (Triple.getArch()) { 218 default: 219 D.Diag(clang::diag::err_target_unsupported_arch) 220 << Triple.getArchName() << "myriad"; 221 LLVM_FALLTHROUGH; 222 case llvm::Triple::shave: 223 return; 224 case llvm::Triple::sparc: 225 case llvm::Triple::sparcel: 226 GCCInstallation.init(Triple, Args, {"sparc-myriad-rtems"}); 227 } 228 229 if (GCCInstallation.isValid()) { 230 // This directory contains crt{i,n,begin,end}.o as well as libgcc. 231 // These files are tied to a particular version of gcc. 232 SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); 233 addPathIfExists(D, CompilerSupportDir, getFilePaths()); 234 } 235 // libstd++ and libc++ must both be found in this one place. 236 addPathIfExists(D, D.Dir + "/../sparc-myriad-rtems/lib", getFilePaths()); 237 } 238 239 MyriadToolChain::~MyriadToolChain() {} 240 241 void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 242 ArgStringList &CC1Args) const { 243 if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) 244 addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); 245 } 246 247 void MyriadToolChain::addLibCxxIncludePaths( 248 const llvm::opt::ArgList &DriverArgs, 249 llvm::opt::ArgStringList &CC1Args) const { 250 std::string Path(getDriver().getInstalledDir()); 251 addSystemInclude(DriverArgs, CC1Args, Path + "/../include/c++/v1"); 252 } 253 254 void MyriadToolChain::addLibStdCxxIncludePaths( 255 const llvm::opt::ArgList &DriverArgs, 256 llvm::opt::ArgStringList &CC1Args) const { 257 StringRef LibDir = GCCInstallation.getParentLibPath(); 258 const GCCVersion &Version = GCCInstallation.getVersion(); 259 StringRef TripleStr = GCCInstallation.getTriple().str(); 260 const Multilib &Multilib = GCCInstallation.getMultilib(); 261 addLibStdCXXIncludePaths( 262 LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, 263 TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args); 264 } 265 266 // MyriadToolChain handles several triples: 267 // {shave,sparc{,el}}-myriad-{rtems,unknown}-elf 268 Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { 269 // The inherited method works fine if not targeting the SHAVE. 270 if (!isShaveCompilation(getTriple())) 271 return ToolChain::SelectTool(JA); 272 switch (JA.getKind()) { 273 case Action::PreprocessJobClass: 274 case Action::CompileJobClass: 275 if (!Compiler) 276 Compiler.reset(new tools::SHAVE::Compiler(*this)); 277 return Compiler.get(); 278 case Action::AssembleJobClass: 279 if (!Assembler) 280 Assembler.reset(new tools::SHAVE::Assembler(*this)); 281 return Assembler.get(); 282 default: 283 return ToolChain::getTool(JA.getKind()); 284 } 285 } 286 287 Tool *MyriadToolChain::buildLinker() const { 288 return new tools::Myriad::Linker(*this); 289 } 290 291 SanitizerMask MyriadToolChain::getSupportedSanitizers() const { 292 return SanitizerKind::Address; 293 } 294