1 //===--- Hexagon.cpp - Hexagon 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 "Hexagon.h" 11 #include "InputInfo.h" 12 #include "CommonArgs.h" 13 #include "clang/Basic/VirtualFileSystem.h" 14 #include "clang/Config/config.h" 15 #include "clang/Driver/Compilation.h" 16 #include "clang/Driver/Driver.h" 17 #include "clang/Driver/DriverDiagnostic.h" 18 #include "clang/Driver/Options.h" 19 #include "llvm/ADT/StringExtras.h" 20 #include "llvm/Option/ArgList.h" 21 #include "llvm/Support/FileSystem.h" 22 #include "llvm/Support/Path.h" 23 24 using namespace clang::driver; 25 using namespace clang::driver::tools; 26 using namespace clang::driver::toolchains; 27 using namespace clang; 28 using namespace llvm::opt; 29 30 // Hexagon tools start. 31 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA, 32 ArgStringList &CmdArgs) const { 33 } 34 35 void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 36 const InputInfo &Output, 37 const InputInfoList &Inputs, 38 const ArgList &Args, 39 const char *LinkingOutput) const { 40 claimNoWarnArgs(Args); 41 42 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); 43 const Driver &D = HTC.getDriver(); 44 ArgStringList CmdArgs; 45 46 std::string MArchString = "-march=hexagon"; 47 CmdArgs.push_back(Args.MakeArgString(MArchString)); 48 49 RenderExtraToolArgs(JA, CmdArgs); 50 51 std::string AsName = "hexagon-llvm-mc"; 52 std::string MCpuString = "-mcpu=hexagon" + 53 toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); 54 CmdArgs.push_back("-filetype=obj"); 55 CmdArgs.push_back(Args.MakeArgString(MCpuString)); 56 57 if (Output.isFilename()) { 58 CmdArgs.push_back("-o"); 59 CmdArgs.push_back(Output.getFilename()); 60 } else { 61 assert(Output.isNothing() && "Unexpected output"); 62 CmdArgs.push_back("-fsyntax-only"); 63 } 64 65 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { 66 std::string N = llvm::utostr(G.getValue()); 67 CmdArgs.push_back(Args.MakeArgString(std::string("-gpsize=") + N)); 68 } 69 70 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 71 72 // Only pass -x if gcc will understand it; otherwise hope gcc 73 // understands the suffix correctly. The main use case this would go 74 // wrong in is for linker inputs if they happened to have an odd 75 // suffix; really the only way to get this to happen is a command 76 // like '-x foobar a.c' which will treat a.c like a linker input. 77 // 78 // FIXME: For the linker case specifically, can we safely convert 79 // inputs into '-Wl,' options? 80 for (const auto &II : Inputs) { 81 // Don't try to pass LLVM or AST inputs to a generic gcc. 82 if (types::isLLVMIR(II.getType())) 83 D.Diag(clang::diag::err_drv_no_linker_llvm_support) 84 << HTC.getTripleString(); 85 else if (II.getType() == types::TY_AST) 86 D.Diag(clang::diag::err_drv_no_ast_support) 87 << HTC.getTripleString(); 88 else if (II.getType() == types::TY_ModuleFile) 89 D.Diag(diag::err_drv_no_module_support) 90 << HTC.getTripleString(); 91 92 if (II.isFilename()) 93 CmdArgs.push_back(II.getFilename()); 94 else 95 // Don't render as input, we need gcc to do the translations. 96 // FIXME: What is this? 97 II.getInputArg().render(Args, CmdArgs); 98 } 99 100 auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str())); 101 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); 102 } 103 104 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA, 105 ArgStringList &CmdArgs) const { 106 } 107 108 static void 109 constructHexagonLinkArgs(Compilation &C, const JobAction &JA, 110 const toolchains::HexagonToolChain &HTC, 111 const InputInfo &Output, const InputInfoList &Inputs, 112 const ArgList &Args, ArgStringList &CmdArgs, 113 const char *LinkingOutput) { 114 115 const Driver &D = HTC.getDriver(); 116 117 //---------------------------------------------------------------------------- 118 // 119 //---------------------------------------------------------------------------- 120 bool IsStatic = Args.hasArg(options::OPT_static); 121 bool IsShared = Args.hasArg(options::OPT_shared); 122 bool IsPIE = Args.hasArg(options::OPT_pie); 123 bool IncStdLib = !Args.hasArg(options::OPT_nostdlib); 124 bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); 125 bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); 126 bool UseG0 = false; 127 bool UseShared = IsShared && !IsStatic; 128 129 //---------------------------------------------------------------------------- 130 // Silence warnings for various options 131 //---------------------------------------------------------------------------- 132 Args.ClaimAllArgs(options::OPT_g_Group); 133 Args.ClaimAllArgs(options::OPT_emit_llvm); 134 Args.ClaimAllArgs(options::OPT_w); // Other warning options are already 135 // handled somewhere else. 136 Args.ClaimAllArgs(options::OPT_static_libgcc); 137 138 //---------------------------------------------------------------------------- 139 // 140 //---------------------------------------------------------------------------- 141 if (Args.hasArg(options::OPT_s)) 142 CmdArgs.push_back("-s"); 143 144 if (Args.hasArg(options::OPT_r)) 145 CmdArgs.push_back("-r"); 146 147 for (const auto &Opt : HTC.ExtraOpts) 148 CmdArgs.push_back(Opt.c_str()); 149 150 CmdArgs.push_back("-march=hexagon"); 151 std::string CpuVer = 152 toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); 153 std::string MCpuString = "-mcpu=hexagon" + CpuVer; 154 CmdArgs.push_back(Args.MakeArgString(MCpuString)); 155 156 if (IsShared) { 157 CmdArgs.push_back("-shared"); 158 // The following should be the default, but doing as hexagon-gcc does. 159 CmdArgs.push_back("-call_shared"); 160 } 161 162 if (IsStatic) 163 CmdArgs.push_back("-static"); 164 165 if (IsPIE && !IsShared) 166 CmdArgs.push_back("-pie"); 167 168 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { 169 std::string N = llvm::utostr(G.getValue()); 170 CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N)); 171 UseG0 = G.getValue() == 0; 172 } 173 174 //---------------------------------------------------------------------------- 175 // 176 //---------------------------------------------------------------------------- 177 CmdArgs.push_back("-o"); 178 CmdArgs.push_back(Output.getFilename()); 179 180 //---------------------------------------------------------------------------- 181 // moslib 182 //---------------------------------------------------------------------------- 183 std::vector<std::string> OsLibs; 184 bool HasStandalone = false; 185 186 for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) { 187 A->claim(); 188 OsLibs.emplace_back(A->getValue()); 189 HasStandalone = HasStandalone || (OsLibs.back() == "standalone"); 190 } 191 if (OsLibs.empty()) { 192 OsLibs.push_back("standalone"); 193 HasStandalone = true; 194 } 195 196 //---------------------------------------------------------------------------- 197 // Start Files 198 //---------------------------------------------------------------------------- 199 const std::string MCpuSuffix = "/" + CpuVer; 200 const std::string MCpuG0Suffix = MCpuSuffix + "/G0"; 201 const std::string RootDir = 202 HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/"; 203 const std::string StartSubDir = 204 "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix); 205 206 auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir, 207 const char *Name) -> std::string { 208 std::string RelName = SubDir + Name; 209 std::string P = HTC.GetFilePath(RelName.c_str()); 210 if (llvm::sys::fs::exists(P)) 211 return P; 212 return RootDir + RelName; 213 }; 214 215 if (IncStdLib && IncStartFiles) { 216 if (!IsShared) { 217 if (HasStandalone) { 218 std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o"); 219 CmdArgs.push_back(Args.MakeArgString(Crt0SA)); 220 } 221 std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o"); 222 CmdArgs.push_back(Args.MakeArgString(Crt0)); 223 } 224 std::string Init = UseShared 225 ? Find(RootDir, StartSubDir + "/pic", "/initS.o") 226 : Find(RootDir, StartSubDir, "/init.o"); 227 CmdArgs.push_back(Args.MakeArgString(Init)); 228 } 229 230 //---------------------------------------------------------------------------- 231 // Library Search Paths 232 //---------------------------------------------------------------------------- 233 const ToolChain::path_list &LibPaths = HTC.getFilePaths(); 234 for (const auto &LibPath : LibPaths) 235 CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); 236 237 //---------------------------------------------------------------------------- 238 // 239 //---------------------------------------------------------------------------- 240 Args.AddAllArgs(CmdArgs, 241 {options::OPT_T_Group, options::OPT_e, options::OPT_s, 242 options::OPT_t, options::OPT_u_Group}); 243 244 AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); 245 246 //---------------------------------------------------------------------------- 247 // Libraries 248 //---------------------------------------------------------------------------- 249 if (IncStdLib && IncDefLibs) { 250 if (D.CCCIsCXX()) { 251 HTC.AddCXXStdlibLibArgs(Args, CmdArgs); 252 CmdArgs.push_back("-lm"); 253 } 254 255 CmdArgs.push_back("--start-group"); 256 257 if (!IsShared) { 258 for (const std::string &Lib : OsLibs) 259 CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); 260 CmdArgs.push_back("-lc"); 261 } 262 CmdArgs.push_back("-lgcc"); 263 264 CmdArgs.push_back("--end-group"); 265 } 266 267 //---------------------------------------------------------------------------- 268 // End files 269 //---------------------------------------------------------------------------- 270 if (IncStdLib && IncStartFiles) { 271 std::string Fini = UseShared 272 ? Find(RootDir, StartSubDir + "/pic", "/finiS.o") 273 : Find(RootDir, StartSubDir, "/fini.o"); 274 CmdArgs.push_back(Args.MakeArgString(Fini)); 275 } 276 } 277 278 void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA, 279 const InputInfo &Output, 280 const InputInfoList &Inputs, 281 const ArgList &Args, 282 const char *LinkingOutput) const { 283 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); 284 285 ArgStringList CmdArgs; 286 constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs, 287 LinkingOutput); 288 289 std::string Linker = HTC.GetProgramPath("hexagon-link"); 290 C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), 291 CmdArgs, Inputs)); 292 } 293 // Hexagon tools end. 294 295 /// Hexagon Toolchain 296 297 std::string HexagonToolChain::getHexagonTargetDir( 298 const std::string &InstalledDir, 299 const SmallVectorImpl<std::string> &PrefixDirs) const { 300 std::string InstallRelDir; 301 const Driver &D = getDriver(); 302 303 // Locate the rest of the toolchain ... 304 for (auto &I : PrefixDirs) 305 if (D.getVFS().exists(I)) 306 return I; 307 308 if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) 309 return InstallRelDir; 310 311 return InstalledDir; 312 } 313 314 Optional<unsigned> HexagonToolChain::getSmallDataThreshold( 315 const ArgList &Args) { 316 StringRef Gn = ""; 317 if (Arg *A = Args.getLastArg(options::OPT_G)) { 318 Gn = A->getValue(); 319 } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, 320 options::OPT_fPIC)) { 321 Gn = "0"; 322 } 323 324 unsigned G; 325 if (!Gn.getAsInteger(10, G)) 326 return G; 327 328 return None; 329 } 330 331 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, 332 ToolChain::path_list &LibPaths) const { 333 const Driver &D = getDriver(); 334 335 //---------------------------------------------------------------------------- 336 // -L Args 337 //---------------------------------------------------------------------------- 338 for (Arg *A : Args.filtered(options::OPT_L)) 339 for (const char *Value : A->getValues()) 340 LibPaths.push_back(Value); 341 342 //---------------------------------------------------------------------------- 343 // Other standard paths 344 //---------------------------------------------------------------------------- 345 std::vector<std::string> RootDirs; 346 std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(), 347 std::back_inserter(RootDirs)); 348 349 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), 350 D.PrefixDirs); 351 if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end()) 352 RootDirs.push_back(TargetDir); 353 354 bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); 355 // Assume G0 with -shared. 356 bool HasG0 = Args.hasArg(options::OPT_shared); 357 if (auto G = getSmallDataThreshold(Args)) 358 HasG0 = G.getValue() == 0; 359 360 const std::string CpuVer = GetTargetCPUVersion(Args).str(); 361 for (auto &Dir : RootDirs) { 362 std::string LibDir = Dir + "/hexagon/lib"; 363 std::string LibDirCpu = LibDir + '/' + CpuVer; 364 if (HasG0) { 365 if (HasPIC) 366 LibPaths.push_back(LibDirCpu + "/G0/pic"); 367 LibPaths.push_back(LibDirCpu + "/G0"); 368 } 369 LibPaths.push_back(LibDirCpu); 370 LibPaths.push_back(LibDir); 371 } 372 } 373 374 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, 375 const llvm::opt::ArgList &Args) 376 : Linux(D, Triple, Args) { 377 const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), 378 D.PrefixDirs); 379 380 // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to 381 // program paths 382 const std::string BinDir(TargetDir + "/bin"); 383 if (D.getVFS().exists(BinDir)) 384 getProgramPaths().push_back(BinDir); 385 386 ToolChain::path_list &LibPaths = getFilePaths(); 387 388 // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets 389 // 'elf' OS type, so the Linux paths are not appropriate. When we actually 390 // support 'linux' we'll need to fix this up 391 LibPaths.clear(); 392 getHexagonLibraryPaths(Args, LibPaths); 393 } 394 395 HexagonToolChain::~HexagonToolChain() {} 396 397 Tool *HexagonToolChain::buildAssembler() const { 398 return new tools::hexagon::Assembler(*this); 399 } 400 401 Tool *HexagonToolChain::buildLinker() const { 402 return new tools::hexagon::Linker(*this); 403 } 404 405 unsigned HexagonToolChain::getOptimizationLevel( 406 const llvm::opt::ArgList &DriverArgs) const { 407 // Copied in large part from lib/Frontend/CompilerInvocation.cpp. 408 Arg *A = DriverArgs.getLastArg(options::OPT_O_Group); 409 if (!A) 410 return 0; 411 412 if (A->getOption().matches(options::OPT_O0)) 413 return 0; 414 if (A->getOption().matches(options::OPT_Ofast) || 415 A->getOption().matches(options::OPT_O4)) 416 return 3; 417 assert(A->getNumValues() != 0); 418 StringRef S(A->getValue()); 419 if (S == "s" || S == "z" || S.empty()) 420 return 2; 421 if (S == "g") 422 return 1; 423 424 unsigned OptLevel; 425 if (S.getAsInteger(10, OptLevel)) 426 return 0; 427 return OptLevel; 428 } 429 430 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, 431 ArgStringList &CC1Args) const { 432 if (DriverArgs.hasArg(options::OPT_ffp_contract)) 433 return; 434 unsigned OptLevel = getOptimizationLevel(DriverArgs); 435 if (OptLevel >= 3) 436 CC1Args.push_back("-ffp-contract=fast"); 437 } 438 439 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 440 ArgStringList &CC1Args) const { 441 if (DriverArgs.hasArg(options::OPT_nostdinc) || 442 DriverArgs.hasArg(options::OPT_nostdlibinc)) 443 return; 444 445 const Driver &D = getDriver(); 446 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), 447 D.PrefixDirs); 448 addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); 449 } 450 451 452 void HexagonToolChain::addLibStdCxxIncludePaths( 453 const llvm::opt::ArgList &DriverArgs, 454 llvm::opt::ArgStringList &CC1Args) const { 455 const Driver &D = getDriver(); 456 std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); 457 addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "", 458 DriverArgs, CC1Args); 459 } 460 461 ToolChain::CXXStdlibType 462 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const { 463 Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); 464 if (!A) 465 return ToolChain::CST_Libstdcxx; 466 467 StringRef Value = A->getValue(); 468 if (Value != "libstdc++") 469 getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); 470 471 return ToolChain::CST_Libstdcxx; 472 } 473 474 // 475 // Returns the default CPU for Hexagon. This is the default compilation target 476 // if no Hexagon processor is selected at the command-line. 477 // 478 const StringRef HexagonToolChain::GetDefaultCPU() { 479 return "hexagonv60"; 480 } 481 482 const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { 483 Arg *CpuArg = nullptr; 484 if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ)) 485 CpuArg = A; 486 487 StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); 488 if (CPU.startswith("hexagon")) 489 return CPU.substr(sizeof("hexagon") - 1); 490 return CPU; 491 } 492