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