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