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 bool UseShared = IsShared && !IsStatic; 213 214 //---------------------------------------------------------------------------- 215 // Silence warnings for various options 216 //---------------------------------------------------------------------------- 217 Args.ClaimAllArgs(options::OPT_g_Group); 218 Args.ClaimAllArgs(options::OPT_emit_llvm); 219 Args.ClaimAllArgs(options::OPT_w); // Other warning options are already 220 // handled somewhere else. 221 Args.ClaimAllArgs(options::OPT_static_libgcc); 222 223 //---------------------------------------------------------------------------- 224 // 225 //---------------------------------------------------------------------------- 226 if (Args.hasArg(options::OPT_s)) 227 CmdArgs.push_back("-s"); 228 229 if (Args.hasArg(options::OPT_r)) 230 CmdArgs.push_back("-r"); 231 232 for (const auto &Opt : HTC.ExtraOpts) 233 CmdArgs.push_back(Opt.c_str()); 234 235 CmdArgs.push_back("-march=hexagon"); 236 StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); 237 CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer)); 238 239 if (IsShared) { 240 CmdArgs.push_back("-shared"); 241 // The following should be the default, but doing as hexagon-gcc does. 242 CmdArgs.push_back("-call_shared"); 243 } 244 245 if (IsStatic) 246 CmdArgs.push_back("-static"); 247 248 if (IsPIE && !IsShared) 249 CmdArgs.push_back("-pie"); 250 251 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { 252 CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue()))); 253 UseG0 = G.getValue() == 0; 254 } 255 256 //---------------------------------------------------------------------------- 257 // 258 //---------------------------------------------------------------------------- 259 CmdArgs.push_back("-o"); 260 CmdArgs.push_back(Output.getFilename()); 261 262 //---------------------------------------------------------------------------- 263 // moslib 264 //---------------------------------------------------------------------------- 265 std::vector<std::string> OsLibs; 266 bool HasStandalone = false; 267 268 for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) { 269 A->claim(); 270 OsLibs.emplace_back(A->getValue()); 271 HasStandalone = HasStandalone || (OsLibs.back() == "standalone"); 272 } 273 if (OsLibs.empty()) { 274 OsLibs.push_back("standalone"); 275 HasStandalone = true; 276 } 277 278 //---------------------------------------------------------------------------- 279 // Start Files 280 //---------------------------------------------------------------------------- 281 const std::string MCpuSuffix = "/" + CpuVer.str(); 282 const std::string MCpuG0Suffix = MCpuSuffix + "/G0"; 283 const std::string RootDir = 284 HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/"; 285 const std::string StartSubDir = 286 "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix); 287 288 auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir, 289 const char *Name) -> std::string { 290 std::string RelName = SubDir + Name; 291 std::string P = HTC.GetFilePath(RelName.c_str()); 292 if (llvm::sys::fs::exists(P)) 293 return P; 294 return RootDir + RelName; 295 }; 296 297 if (IncStdLib && IncStartFiles) { 298 if (!IsShared) { 299 if (HasStandalone) { 300 std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o"); 301 CmdArgs.push_back(Args.MakeArgString(Crt0SA)); 302 } 303 std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o"); 304 CmdArgs.push_back(Args.MakeArgString(Crt0)); 305 } 306 std::string Init = UseShared 307 ? Find(RootDir, StartSubDir + "/pic", "/initS.o") 308 : Find(RootDir, StartSubDir, "/init.o"); 309 CmdArgs.push_back(Args.MakeArgString(Init)); 310 } 311 312 //---------------------------------------------------------------------------- 313 // Library Search Paths 314 //---------------------------------------------------------------------------- 315 const ToolChain::path_list &LibPaths = HTC.getFilePaths(); 316 for (const auto &LibPath : LibPaths) 317 CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); 318 319 //---------------------------------------------------------------------------- 320 // 321 //---------------------------------------------------------------------------- 322 Args.AddAllArgs(CmdArgs, 323 {options::OPT_T_Group, options::OPT_e, options::OPT_s, 324 options::OPT_t, options::OPT_u_Group}); 325 326 AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); 327 328 //---------------------------------------------------------------------------- 329 // Libraries 330 //---------------------------------------------------------------------------- 331 if (IncStdLib && IncDefLibs) { 332 if (D.CCCIsCXX()) { 333 if (HTC.ShouldLinkCXXStdlib(Args)) 334 HTC.AddCXXStdlibLibArgs(Args, CmdArgs); 335 CmdArgs.push_back("-lm"); 336 } 337 338 CmdArgs.push_back("--start-group"); 339 340 if (!IsShared) { 341 for (StringRef Lib : OsLibs) 342 CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); 343 CmdArgs.push_back("-lc"); 344 } 345 CmdArgs.push_back("-lgcc"); 346 347 CmdArgs.push_back("--end-group"); 348 } 349 350 //---------------------------------------------------------------------------- 351 // End files 352 //---------------------------------------------------------------------------- 353 if (IncStdLib && IncStartFiles) { 354 std::string Fini = UseShared 355 ? Find(RootDir, StartSubDir + "/pic", "/finiS.o") 356 : Find(RootDir, StartSubDir, "/fini.o"); 357 CmdArgs.push_back(Args.MakeArgString(Fini)); 358 } 359 } 360 361 void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA, 362 const InputInfo &Output, 363 const InputInfoList &Inputs, 364 const ArgList &Args, 365 const char *LinkingOutput) const { 366 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); 367 368 ArgStringList CmdArgs; 369 constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs, 370 LinkingOutput); 371 372 const char *Exec = Args.MakeArgString(HTC.GetLinkerPath()); 373 C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); 374 } 375 // Hexagon tools end. 376 377 /// Hexagon Toolchain 378 379 std::string HexagonToolChain::getHexagonTargetDir( 380 const std::string &InstalledDir, 381 const SmallVectorImpl<std::string> &PrefixDirs) const { 382 std::string InstallRelDir; 383 const Driver &D = getDriver(); 384 385 // Locate the rest of the toolchain ... 386 for (auto &I : PrefixDirs) 387 if (D.getVFS().exists(I)) 388 return I; 389 390 if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) 391 return InstallRelDir; 392 393 return InstalledDir; 394 } 395 396 Optional<unsigned> HexagonToolChain::getSmallDataThreshold( 397 const ArgList &Args) { 398 StringRef Gn = ""; 399 if (Arg *A = Args.getLastArg(options::OPT_G)) { 400 Gn = A->getValue(); 401 } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, 402 options::OPT_fPIC)) { 403 Gn = "0"; 404 } 405 406 unsigned G; 407 if (!Gn.getAsInteger(10, G)) 408 return G; 409 410 return None; 411 } 412 413 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, 414 ToolChain::path_list &LibPaths) const { 415 const Driver &D = getDriver(); 416 417 //---------------------------------------------------------------------------- 418 // -L Args 419 //---------------------------------------------------------------------------- 420 for (Arg *A : Args.filtered(options::OPT_L)) 421 for (const char *Value : A->getValues()) 422 LibPaths.push_back(Value); 423 424 //---------------------------------------------------------------------------- 425 // Other standard paths 426 //---------------------------------------------------------------------------- 427 std::vector<std::string> RootDirs; 428 std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(), 429 std::back_inserter(RootDirs)); 430 431 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), 432 D.PrefixDirs); 433 if (llvm::find(RootDirs, TargetDir) == RootDirs.end()) 434 RootDirs.push_back(TargetDir); 435 436 bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); 437 // Assume G0 with -shared. 438 bool HasG0 = Args.hasArg(options::OPT_shared); 439 if (auto G = getSmallDataThreshold(Args)) 440 HasG0 = G.getValue() == 0; 441 442 const std::string CpuVer = GetTargetCPUVersion(Args).str(); 443 for (auto &Dir : RootDirs) { 444 std::string LibDir = Dir + "/hexagon/lib"; 445 std::string LibDirCpu = LibDir + '/' + CpuVer; 446 if (HasG0) { 447 if (HasPIC) 448 LibPaths.push_back(LibDirCpu + "/G0/pic"); 449 LibPaths.push_back(LibDirCpu + "/G0"); 450 } 451 LibPaths.push_back(LibDirCpu); 452 LibPaths.push_back(LibDir); 453 } 454 } 455 456 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, 457 const llvm::opt::ArgList &Args) 458 : Linux(D, Triple, Args) { 459 const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), 460 D.PrefixDirs); 461 462 // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to 463 // program paths 464 const std::string BinDir(TargetDir + "/bin"); 465 if (D.getVFS().exists(BinDir)) 466 getProgramPaths().push_back(BinDir); 467 468 ToolChain::path_list &LibPaths = getFilePaths(); 469 470 // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets 471 // 'elf' OS type, so the Linux paths are not appropriate. When we actually 472 // support 'linux' we'll need to fix this up 473 LibPaths.clear(); 474 getHexagonLibraryPaths(Args, LibPaths); 475 } 476 477 HexagonToolChain::~HexagonToolChain() {} 478 479 Tool *HexagonToolChain::buildAssembler() const { 480 return new tools::hexagon::Assembler(*this); 481 } 482 483 Tool *HexagonToolChain::buildLinker() const { 484 return new tools::hexagon::Linker(*this); 485 } 486 487 unsigned HexagonToolChain::getOptimizationLevel( 488 const llvm::opt::ArgList &DriverArgs) const { 489 // Copied in large part from lib/Frontend/CompilerInvocation.cpp. 490 Arg *A = DriverArgs.getLastArg(options::OPT_O_Group); 491 if (!A) 492 return 0; 493 494 if (A->getOption().matches(options::OPT_O0)) 495 return 0; 496 if (A->getOption().matches(options::OPT_Ofast) || 497 A->getOption().matches(options::OPT_O4)) 498 return 3; 499 assert(A->getNumValues() != 0); 500 StringRef S(A->getValue()); 501 if (S == "s" || S == "z" || S.empty()) 502 return 2; 503 if (S == "g") 504 return 1; 505 506 unsigned OptLevel; 507 if (S.getAsInteger(10, OptLevel)) 508 return 0; 509 return OptLevel; 510 } 511 512 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, 513 ArgStringList &CC1Args, 514 Action::OffloadKind) const { 515 if (DriverArgs.hasArg(options::OPT_ffixed_r19)) { 516 CC1Args.push_back("-target-feature"); 517 CC1Args.push_back("+reserved-r19"); 518 } 519 if (isAutoHVXEnabled(DriverArgs)) { 520 CC1Args.push_back("-mllvm"); 521 CC1Args.push_back("-hexagon-autohvx"); 522 } 523 } 524 525 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 526 ArgStringList &CC1Args) const { 527 if (DriverArgs.hasArg(options::OPT_nostdinc) || 528 DriverArgs.hasArg(options::OPT_nostdlibinc)) 529 return; 530 531 const Driver &D = getDriver(); 532 std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), 533 D.PrefixDirs); 534 addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); 535 } 536 537 538 void HexagonToolChain::addLibStdCxxIncludePaths( 539 const llvm::opt::ArgList &DriverArgs, 540 llvm::opt::ArgStringList &CC1Args) const { 541 const Driver &D = getDriver(); 542 std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); 543 addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "", 544 DriverArgs, CC1Args); 545 } 546 547 ToolChain::CXXStdlibType 548 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const { 549 Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); 550 if (!A) 551 return ToolChain::CST_Libstdcxx; 552 553 StringRef Value = A->getValue(); 554 if (Value != "libstdc++") 555 getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); 556 557 return ToolChain::CST_Libstdcxx; 558 } 559 560 bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) { 561 if (Arg *A = Args.getLastArg(options::OPT_fvectorize, 562 options::OPT_fno_vectorize)) 563 return A->getOption().matches(options::OPT_fvectorize); 564 return false; 565 } 566 567 // 568 // Returns the default CPU for Hexagon. This is the default compilation target 569 // if no Hexagon processor is selected at the command-line. 570 // 571 const StringRef HexagonToolChain::GetDefaultCPU() { 572 return "hexagonv60"; 573 } 574 575 const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { 576 Arg *CpuArg = nullptr; 577 if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ)) 578 CpuArg = A; 579 580 StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); 581 if (CPU.startswith("hexagon")) 582 return CPU.substr(sizeof("hexagon") - 1); 583 return CPU; 584 } 585