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