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, 47 // 'f' flags, optimize flags, and warning options. 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_fno_split_dwarf_inlining}); 56 Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. 57 58 // If we're producing a dependency file, and assembly is the final action, 59 // then the name of the target in the dependency file should be the '.o' 60 // file, not the '.s' file produced by this step. For example, instead of 61 // /tmp/mumble.s: mumble.c .../someheader.h 62 // the filename on the lefthand side should be "mumble.o" 63 if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && 64 C.getActions().size() == 1 && 65 C.getActions()[0]->getKind() == Action::AssembleJobClass) { 66 Arg *A = Args.getLastArg(options::OPT_o); 67 if (A) { 68 CmdArgs.push_back("-MT"); 69 CmdArgs.push_back(Args.MakeArgString(A->getValue())); 70 } 71 } 72 73 CmdArgs.push_back(II.getFilename()); 74 CmdArgs.push_back("-o"); 75 CmdArgs.push_back(Output.getFilename()); 76 77 std::string Exec = 78 Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); 79 C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), 80 CmdArgs, Inputs)); 81 } 82 83 void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 84 const InputInfo &Output, 85 const InputInfoList &Inputs, 86 const ArgList &Args, 87 const char *LinkingOutput) const { 88 ArgStringList CmdArgs; 89 90 assert(Inputs.size() == 1); 91 const InputInfo &II = Inputs[0]; 92 assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input. 93 assert(Output.getType() == types::TY_Object); 94 95 CmdArgs.push_back("-no6thSlotCompression"); 96 const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); 97 if (CPUArg) 98 CmdArgs.push_back( 99 Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue()))); 100 CmdArgs.push_back("-noSPrefixing"); 101 CmdArgs.push_back("-a"); // Mystery option. 102 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 103 for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) { 104 A->claim(); 105 CmdArgs.push_back( 106 Args.MakeArgString(std::string("-i:") + A->getValue(0))); 107 } 108 CmdArgs.push_back("-elf"); // Output format. 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(llvm::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-elf-ld")); 201 C.addCommand(llvm::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 case llvm::Triple::sparc: 219 case llvm::Triple::sparcel: 220 case llvm::Triple::shave: 221 GCCInstallation.init(Triple, Args, {"sparc-myriad-elf"}); 222 } 223 224 if (GCCInstallation.isValid()) { 225 // This directory contains crt{i,n,begin,end}.o as well as libgcc. 226 // These files are tied to a particular version of gcc. 227 SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); 228 addPathIfExists(D, CompilerSupportDir, getFilePaths()); 229 } 230 // libstd++ and libc++ must both be found in this one place. 231 addPathIfExists(D, D.Dir + "/../sparc-myriad-elf/lib", getFilePaths()); 232 } 233 234 MyriadToolChain::~MyriadToolChain() {} 235 236 void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 237 ArgStringList &CC1Args) const { 238 if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) 239 addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); 240 } 241 242 std::string MyriadToolChain::findLibCxxIncludePath() const { 243 std::string Path(getDriver().getInstalledDir()); 244 return Path + "/../include/c++/v1"; 245 } 246 247 void MyriadToolChain::addLibStdCxxIncludePaths( 248 const llvm::opt::ArgList &DriverArgs, 249 llvm::opt::ArgStringList &CC1Args) const { 250 StringRef LibDir = GCCInstallation.getParentLibPath(); 251 const GCCVersion &Version = GCCInstallation.getVersion(); 252 StringRef TripleStr = GCCInstallation.getTriple().str(); 253 const Multilib &Multilib = GCCInstallation.getMultilib(); 254 addLibStdCXXIncludePaths( 255 LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, 256 "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args); 257 } 258 259 // MyriadToolChain handles several triples: 260 // {shave,sparc{,el}}-myriad-{rtems,unknown}-elf 261 Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { 262 // The inherited method works fine if not targeting the SHAVE. 263 if (!isShaveCompilation(getTriple())) 264 return ToolChain::SelectTool(JA); 265 switch (JA.getKind()) { 266 case Action::PreprocessJobClass: 267 case Action::CompileJobClass: 268 if (!Compiler) 269 Compiler.reset(new tools::SHAVE::Compiler(*this)); 270 return Compiler.get(); 271 case Action::AssembleJobClass: 272 if (!Assembler) 273 Assembler.reset(new tools::SHAVE::Assembler(*this)); 274 return Assembler.get(); 275 default: 276 return ToolChain::getTool(JA.getKind()); 277 } 278 } 279 280 Tool *MyriadToolChain::buildLinker() const { 281 return new tools::Myriad::Linker(*this); 282 } 283 284 SanitizerMask MyriadToolChain::getSupportedSanitizers() const { 285 return SanitizerKind::Address; 286 } 287