diff options
Diffstat (limited to 'lib/Driver/ToolChains/CommonArgs.cpp')
-rw-r--r-- | lib/Driver/ToolChains/CommonArgs.cpp | 344 |
1 files changed, 300 insertions, 44 deletions
diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp index f26880123d8c2..1e093b25b909f 100644 --- a/lib/Driver/ToolChains/CommonArgs.cpp +++ b/lib/Driver/ToolChains/CommonArgs.cpp @@ -8,14 +8,14 @@ //===----------------------------------------------------------------------===// #include "CommonArgs.h" -#include "InputInfo.h" -#include "Hexagon.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/SystemZ.h" #include "Arch/X86.h" +#include "Hexagon.h" +#include "InputInfo.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" @@ -31,6 +31,7 @@ #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" +#include "clang/Driver/XRayArgs.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -41,6 +42,7 @@ #include "llvm/Option/Option.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -144,12 +146,14 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); for (const auto &II : Inputs) { - // If the current tool chain refers to an OpenMP offloading host, we should - // ignore inputs that refer to OpenMP offloading devices - they will be - // embedded according to a proper linker script. + // If the current tool chain refers to an OpenMP or HIP offloading host, we + // should ignore inputs that refer to OpenMP or HIP offloading devices - + // they will be embedded according to a proper linker script. if (auto *IA = II.getAction()) - if (JA.isHostOffloading(Action::OFK_OpenMP) && - IA->isDeviceOffloading(Action::OFK_OpenMP)) + if ((JA.isHostOffloading(Action::OFK_OpenMP) && + IA->isDeviceOffloading(Action::OFK_OpenMP)) || + (JA.isHostOffloading(Action::OFK_HIP) && + IA->isDeviceOffloading(Action::OFK_HIP))) continue; if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) @@ -363,23 +367,20 @@ unsigned tools::getLTOParallelism(const ArgList &Args, const Driver &D) { return Parallelism; } -// CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by -// default. +// CloudABI uses -ffunction-sections and -fdata-sections by default. bool tools::isUseSeparateSections(const llvm::Triple &Triple) { - return Triple.getOS() == llvm::Triple::CloudABI || - Triple.getArch() == llvm::Triple::wasm32 || - Triple.getArch() == llvm::Triple::wasm64; + return Triple.getOS() == llvm::Triple::CloudABI; } void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, - ArgStringList &CmdArgs, bool IsThinLTO, - const Driver &D) { + ArgStringList &CmdArgs, const InputInfo &Output, + const InputInfo &Input, bool IsThinLTO) { // Tell the linker to load the plugin. This has to come before AddLinkerInputs // as gold requires -plugin to come before any -plugin-opt that -Wl might // forward. CmdArgs.push_back("-plugin"); -#if defined(LLVM_ON_WIN32) +#if defined(_WIN32) const char *Suffix = ".dll"; #elif defined(__APPLE__) const char *Suffix = ".dylib"; @@ -415,10 +416,16 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt)); } + if (Args.hasArg(options::OPT_gsplit_dwarf)) { + CmdArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=dwo_dir=") + + Output.getFilename() + "_dwo")); + } + if (IsThinLTO) CmdArgs.push_back("-plugin-opt=thinlto"); - if (unsigned Parallelism = getLTOParallelism(Args, D)) + if (unsigned Parallelism = getLTOParallelism(Args, ToolChain.getDriver())) CmdArgs.push_back( Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism))); @@ -449,7 +456,7 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, if (Arg *A = getLastProfileSampleUseArg(Args)) { StringRef FName = A->getValue(); if (!llvm::sys::fs::exists(FName)) - D.Diag(diag::err_drv_no_such_file) << FName; + ToolChain.getDriver().Diag(diag::err_drv_no_such_file) << FName; else CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); @@ -458,14 +465,24 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, // Need this flag to turn on new pass manager via Gold plugin. if (Args.hasFlag(options::OPT_fexperimental_new_pass_manager, options::OPT_fno_experimental_new_pass_manager, - /* Default */ false)) { + /* Default */ ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER)) { CmdArgs.push_back("-plugin-opt=new-pass-manager"); } + // Setup statistics file output. + SmallString<128> StatsFile = + getStatsFileName(Args, Output, Input, ToolChain.getDriver()); + if (!StatsFile.empty()) + CmdArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile)); } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { + if (!Args.hasFlag(options::OPT_frtlib_add_rpath, + options::OPT_fno_rtlib_add_rpath, false)) + return; + std::string CandidateRPath = TC.getArchSpecificLibPath(); if (TC.getVFS().exists(CandidateRPath)) { CmdArgs.push_back("-rpath"); @@ -511,9 +528,9 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, bool IsShared, bool IsWhole) { // Wrap any static runtimes that must be forced into executable in // whole-archive. - if (IsWhole) CmdArgs.push_back("-whole-archive"); + if (IsWhole) CmdArgs.push_back("--whole-archive"); CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared)); - if (IsWhole) CmdArgs.push_back("-no-whole-archive"); + if (IsWhole) CmdArgs.push_back("--no-whole-archive"); if (IsShared) { addArchSpecificRPath(TC, Args, CmdArgs); @@ -525,6 +542,15 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer) { + // Solaris ld defaults to --export-dynamic behaviour but doesn't support + // the option, so don't try to pass it. + if (TC.getTriple().getOS() == llvm::Triple::Solaris) + return true; + // Myriad is static linking only. Furthermore, some versions of its + // linker have the bug where --export-dynamic overrides -static, so + // don't use --export-dynamic on that platform. + if (TC.getTriple().getVendor() == llvm::Triple::Myriad) + return true; SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer)); if (llvm::sys::fs::exists(SanRT + ".syms")) { CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms")); @@ -538,22 +564,23 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, // Force linking against the system libraries sanitizers depends on // (see PR15823 why this is necessary). CmdArgs.push_back("--no-as-needed"); - // There's no libpthread or librt on RTEMS. - if (TC.getTriple().getOS() != llvm::Triple::RTEMS) { + // There's no libpthread or librt on RTEMS & Android. + if (TC.getTriple().getOS() != llvm::Triple::RTEMS && + !TC.getTriple().isAndroid()) { CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lrt"); + if (TC.getTriple().getOS() != llvm::Triple::OpenBSD) + CmdArgs.push_back("-lrt"); } CmdArgs.push_back("-lm"); // There's no libdl on all OSes. if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && TC.getTriple().getOS() != llvm::Triple::NetBSD && + TC.getTriple().getOS() != llvm::Triple::OpenBSD && TC.getTriple().getOS() != llvm::Triple::RTEMS) CmdArgs.push_back("-ldl"); - // Required for forkpty on some OSes - if (TC.getTriple().getOS() == llvm::Triple::NetBSD) - CmdArgs.push_back("-lutil"); // Required for backtrace on some OSes - if (TC.getTriple().getOS() == llvm::Triple::NetBSD) + if (TC.getTriple().getOS() == llvm::Triple::NetBSD || + TC.getTriple().getOS() == llvm::Triple::FreeBSD) CmdArgs.push_back("-lexecinfo"); } @@ -573,14 +600,17 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, HelperStaticRuntimes.push_back("asan-preinit"); } if (SanArgs.needsUbsanRt()) { - if (SanArgs.requiresMinimalRuntime()) { + if (SanArgs.requiresMinimalRuntime()) SharedRuntimes.push_back("ubsan_minimal"); - } else { + else SharedRuntimes.push_back("ubsan_standalone"); - } } - if (SanArgs.needsScudoRt()) - SharedRuntimes.push_back("scudo"); + if (SanArgs.needsScudoRt()) { + if (SanArgs.requiresMinimalRuntime()) + SharedRuntimes.push_back("scudo_minimal"); + else + SharedRuntimes.push_back("scudo"); + } if (SanArgs.needsHwasanRt()) SharedRuntimes.push_back("hwasan"); } @@ -646,9 +676,15 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.needsEsanRt()) StaticRuntimes.push_back("esan"); if (SanArgs.needsScudoRt()) { - StaticRuntimes.push_back("scudo"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("scudo_cxx"); + if (SanArgs.requiresMinimalRuntime()) { + StaticRuntimes.push_back("scudo_minimal"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("scudo_cxx_minimal"); + } else { + StaticRuntimes.push_back("scudo"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("scudo_cxx"); + } } } @@ -691,7 +727,7 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, // If there is a static runtime with no dynamic list, force all the symbols // to be dynamic to be sure we export sanitizer interface functions. if (AddExportDynamic) - CmdArgs.push_back("-export-dynamic"); + CmdArgs.push_back("--export-dynamic"); const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) @@ -700,6 +736,35 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty(); } +bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args, ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_shared)) + return false; + + if (TC.getXRayArgs().needsXRayRt()) { + CmdArgs.push_back("-whole-archive"); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false)); + for (const auto &Mode : TC.getXRayArgs().modeList()) + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Mode, false)); + CmdArgs.push_back("-no-whole-archive"); + return true; + } + + return false; +} + +void tools::linkXRayRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("-lpthread"); + if (TC.getTriple().getOS() != llvm::Triple::OpenBSD) + CmdArgs.push_back("-lrt"); + CmdArgs.push_back("-lm"); + + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && + TC.getTriple().getOS() != llvm::Triple::NetBSD && + TC.getTriple().getOS() != llvm::Triple::OpenBSD) + CmdArgs.push_back("-ldl"); +} + bool tools::areOptimizationsEnabled(const ArgList &Args) { // Find the last -O arg and see if it is non-zero. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) @@ -859,6 +924,10 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { } } + // AMDGPU-specific defaults for PIC. + if (Triple.getArch() == llvm::Triple::amdgcn) + PIC = true; + // The last argument relating to either PIC or PIE wins, and no // other argument is used. If the last argument is any flavor of the // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE @@ -964,16 +1033,26 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { RWPI = true; } - // ROPI and RWPI are not comaptible with PIC or PIE. + // ROPI and RWPI are not compatible with PIC or PIE. if ((ROPI || RWPI) && (PIC || PIE)) ToolChain.getDriver().Diag(diag::err_drv_ropi_rwpi_incompatible_with_pic); - // When targettng MIPS64 with N64, the default is PIC, unless -mno-abicalls is - // used. - if ((Triple.getArch() == llvm::Triple::mips64 || - Triple.getArch() == llvm::Triple::mips64el) && - Args.hasArg(options::OPT_mno_abicalls)) - return std::make_tuple(llvm::Reloc::Static, 0U, false); + if (Triple.isMIPS()) { + StringRef CPUName; + StringRef ABIName; + mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + // When targeting the N64 ABI, PIC is the default, except in the case + // when the -mno-abicalls option is used. In that case we exit + // at next check regardless of PIC being set below. + if (ABIName == "n64") + PIC = true; + // When targettng MIPS with -mno-abicalls, it's always static. + if(Args.hasArg(options::OPT_mno_abicalls)) + return std::make_tuple(llvm::Reloc::Static, 0U, false); + // Unlike other architectures, MIPS, even with -fPIC/-mxgot/multigot, + // does not use PIC level 2 for historical reasons. + IsPICLevelTwo = false; + } if (PIC) return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2U : 1U, PIE); @@ -989,6 +1068,40 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { return std::make_tuple(RelocM, 0U, false); } +// `-falign-functions` indicates that the functions should be aligned to a +// 16-byte boundary. +// +// `-falign-functions=1` is the same as `-fno-align-functions`. +// +// The scalar `n` in `-falign-functions=n` must be an integral value between +// [0, 65536]. If the value is not a power-of-two, it will be rounded up to +// the nearest power-of-two. +// +// If we return `0`, the frontend will default to the backend's preferred +// alignment. +// +// NOTE: icc only allows values between [0, 4096]. icc uses `-falign-functions` +// to mean `-falign-functions=16`. GCC defaults to the backend's preferred +// alignment. For unaligned functions, we default to the backend's preferred +// alignment. +unsigned tools::ParseFunctionAlignment(const ToolChain &TC, + const ArgList &Args) { + const Arg *A = Args.getLastArg(options::OPT_falign_functions, + options::OPT_falign_functions_EQ, + options::OPT_fno_align_functions); + if (!A || A->getOption().matches(options::OPT_fno_align_functions)) + return 0; + + if (A->getOption().matches(options::OPT_falign_functions)) + return 0; + + unsigned Value = 0; + if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 65536) + TC.getDriver().Diag(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value; +} + void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs) { llvm::Reloc::Model RelocationModel; @@ -1000,7 +1113,7 @@ void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back("-KPIC"); } -/// \brief Determine whether Objective-C automated reference counting is +/// Determine whether Objective-C automated reference counting is /// enabled. bool tools::isObjCAutoRefCount(const ArgList &Args) { return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false); @@ -1189,3 +1302,146 @@ void tools::AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, Lksf << LksBuffer; } + +/// Add HIP linker script arguments at the end of the argument list so that +/// the fat binary is built by embedding the device images into the host. The +/// linker script also defines a symbol required by the code generation so that +/// the image can be retrieved at runtime. This should be used only in tool +/// chains that support linker scripts. +void tools::AddHIPLinkerScript(const ToolChain &TC, Compilation &C, + const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + ArgStringList &CmdArgs, const JobAction &JA, + const Tool &T) { + + // If this is not a HIP host toolchain, we don't need to do anything. + if (!JA.isHostOffloading(Action::OFK_HIP)) + return; + + // Create temporary linker script. Keep it if save-temps is enabled. + const char *LKS; + SmallString<256> Name = llvm::sys::path::filename(Output.getFilename()); + if (C.getDriver().isSaveTempsEnabled()) { + llvm::sys::path::replace_extension(Name, "lk"); + LKS = C.getArgs().MakeArgString(Name.c_str()); + } else { + llvm::sys::path::replace_extension(Name, ""); + Name = C.getDriver().GetTemporaryPath(Name, "lk"); + LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str())); + } + + // Add linker script option to the command. + CmdArgs.push_back("-T"); + CmdArgs.push_back(LKS); + + // Create a buffer to write the contents of the linker script. + std::string LksBuffer; + llvm::raw_string_ostream LksStream(LksBuffer); + + // Get the HIP offload tool chain. + auto *HIPTC = static_cast<const toolchains::CudaToolChain *>( + C.getSingleOffloadToolChain<Action::OFK_HIP>()); + assert(HIPTC->getTriple().getArch() == llvm::Triple::amdgcn && + "Wrong platform"); + (void)HIPTC; + + // Construct clang-offload-bundler command to bundle object files for + // for different GPU archs. + ArgStringList BundlerArgs; + BundlerArgs.push_back(Args.MakeArgString("-type=o")); + + // ToDo: Remove the dummy host binary entry which is required by + // clang-offload-bundler. + std::string BundlerTargetArg = "-targets=host-x86_64-unknown-linux"; + std::string BundlerInputArg = "-inputs=/dev/null"; + + for (const auto &II : Inputs) { + const Action *A = II.getAction(); + // Is this a device linking action? + if (A && isa<LinkJobAction>(A) && A->isDeviceOffloading(Action::OFK_HIP)) { + BundlerTargetArg = BundlerTargetArg + ",hip-amdgcn-amd-amdhsa-" + + StringRef(A->getOffloadingArch()).str(); + BundlerInputArg = BundlerInputArg + "," + II.getFilename(); + } + } + BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg)); + BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg)); + + std::string BundleFileName = C.getDriver().GetTemporaryPath("BUNDLE", "o"); + const char *BundleFile = + C.addTempFile(C.getArgs().MakeArgString(BundleFileName.c_str())); + auto BundlerOutputArg = + Args.MakeArgString(std::string("-outputs=").append(BundleFile)); + BundlerArgs.push_back(BundlerOutputArg); + + SmallString<128> BundlerPath(C.getDriver().Dir); + llvm::sys::path::append(BundlerPath, "clang-offload-bundler"); + const char *Bundler = Args.MakeArgString(BundlerPath); + C.addCommand(llvm::make_unique<Command>(JA, T, Bundler, BundlerArgs, Inputs)); + + // Add commands to embed target binaries. We ensure that each section and + // image is 16-byte aligned. This is not mandatory, but increases the + // likelihood of data to be aligned with a cache block in several main host + // machines. + LksStream << "/*\n"; + LksStream << " HIP Offload Linker Script\n"; + LksStream << " *** Automatically generated by Clang ***\n"; + LksStream << "*/\n"; + LksStream << "TARGET(binary)\n"; + LksStream << "INPUT(" << BundleFileName << ")\n"; + LksStream << "SECTIONS\n"; + LksStream << "{\n"; + LksStream << " .hip_fatbin :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " {\n"; + LksStream << " PROVIDE_HIDDEN(__hip_fatbin = .);\n"; + LksStream << " " << BundleFileName << "\n"; + LksStream << " }\n"; + LksStream << "}\n"; + LksStream << "INSERT BEFORE .data\n"; + LksStream.flush(); + + // Dump the contents of the linker script if the user requested that. We + // support this option to enable testing of behavior with -###. + if (C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script)) + llvm::errs() << LksBuffer; + + // If this is a dry run, do not create the linker script file. + if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) + return; + + // Open script file and write the contents. + std::error_code EC; + llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None); + + if (EC) { + C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return; + } + + Lksf << LksBuffer; +} + +SmallString<128> tools::getStatsFileName(const llvm::opt::ArgList &Args, + const InputInfo &Output, + const InputInfo &Input, + const Driver &D) { + const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ); + if (!A) + return {}; + + StringRef SaveStats = A->getValue(); + SmallString<128> StatsFile; + if (SaveStats == "obj" && Output.isFilename()) { + StatsFile.assign(Output.getFilename()); + llvm::sys::path::remove_filename(StatsFile); + } else if (SaveStats != "cwd") { + D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; + return {}; + } + + StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); + llvm::sys::path::append(StatsFile, BaseName); + llvm::sys::path::replace_extension(StatsFile, "stats"); + return StatsFile; +} |