diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp index bc6d1fcd4a00..10ae76cb4161 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -1,596 +1,597 @@ //===--- AMDGPU.cpp - AMDGPU ToolChain Implementations ----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "AMDGPU.h" #include "CommonArgs.h" #include "InputInfo.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Path.h" #include "llvm/Support/VirtualFileSystem.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { assert(!Path.empty()); const StringRef Suffix(".bc"); const StringRef Suffix2(".amdgcn.bc"); std::error_code EC; for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Path, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef FilePath = LI->path(); StringRef FileName = llvm::sys::path::filename(FilePath); if (!FileName.endswith(Suffix)) continue; StringRef BaseName; if (FileName.endswith(Suffix2)) BaseName = FileName.drop_back(Suffix2.size()); else if (FileName.endswith(Suffix)) BaseName = FileName.drop_back(Suffix.size()); if (BaseName == "ocml") { OCML = FilePath; } else if (BaseName == "ockl") { OCKL = FilePath; } else if (BaseName == "opencl") { OpenCL = FilePath; } else if (BaseName == "hip") { HIP = FilePath; } else if (BaseName == "oclc_finite_only_off") { FiniteOnly.Off = FilePath; } else if (BaseName == "oclc_finite_only_on") { FiniteOnly.On = FilePath; } else if (BaseName == "oclc_daz_opt_on") { DenormalsAreZero.On = FilePath; } else if (BaseName == "oclc_daz_opt_off") { DenormalsAreZero.Off = FilePath; } else if (BaseName == "oclc_correctly_rounded_sqrt_on") { CorrectlyRoundedSqrt.On = FilePath; } else if (BaseName == "oclc_correctly_rounded_sqrt_off") { CorrectlyRoundedSqrt.Off = FilePath; } else if (BaseName == "oclc_unsafe_math_on") { UnsafeMath.On = FilePath; } else if (BaseName == "oclc_unsafe_math_off") { UnsafeMath.Off = FilePath; } else if (BaseName == "oclc_wavefrontsize64_on") { WavefrontSize64.On = FilePath; } else if (BaseName == "oclc_wavefrontsize64_off") { WavefrontSize64.Off = FilePath; } else { // Process all bitcode filenames that look like // ocl_isa_version_XXX.amdgcn.bc const StringRef DeviceLibPrefix = "oclc_isa_version_"; if (!BaseName.startswith(DeviceLibPrefix)) continue; StringRef IsaVersionNumber = BaseName.drop_front(DeviceLibPrefix.size()); llvm::Twine GfxName = Twine("gfx") + IsaVersionNumber; SmallString<8> Tmp; LibDeviceMap.insert( std::make_pair(GfxName.toStringRef(Tmp), FilePath.str())); } } } void RocmInstallationDetector::ParseHIPVersionFile(llvm::StringRef V) { SmallVector VersionParts; V.split(VersionParts, '\n'); unsigned Major; unsigned Minor; for (auto Part : VersionParts) { auto Splits = Part.split('='); if (Splits.first == "HIP_VERSION_MAJOR") Splits.second.getAsInteger(0, Major); else if (Splits.first == "HIP_VERSION_MINOR") Splits.second.getAsInteger(0, Minor); else if (Splits.first == "HIP_VERSION_PATCH") VersionPatch = Splits.second.str(); } VersionMajorMinor = llvm::VersionTuple(Major, Minor); DetectedVersion = (Twine(Major) + "." + Twine(Minor) + "." + VersionPatch).str(); } // For candidate specified by --rocm-path we do not do strict check. SmallVector RocmInstallationDetector::getInstallationPathCandidates() { SmallVector Candidates; if (!RocmPathArg.empty()) { Candidates.emplace_back(RocmPathArg.str()); return Candidates; } // Try to find relative to the compiler binary. const char *InstallDir = D.getInstalledDir(); // Check both a normal Unix prefix position of the clang binary, as well as // the Windows-esque layout the ROCm packages use with the host architecture // subdirectory of bin. // Strip off directory (usually bin) StringRef ParentDir = llvm::sys::path::parent_path(InstallDir); StringRef ParentName = llvm::sys::path::filename(ParentDir); // Some builds use bin/{host arch}, so go up again. if (ParentName == "bin") { ParentDir = llvm::sys::path::parent_path(ParentDir); ParentName = llvm::sys::path::filename(ParentDir); } // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin if (ParentName == "llvm") ParentDir = llvm::sys::path::parent_path(ParentDir); Candidates.emplace_back(ParentDir.str(), /*StrictChecking=*/true); // Device library may be installed in clang resource directory. Candidates.emplace_back(D.ResourceDir, /*StrictChecking=*/true); Candidates.emplace_back(D.SysRoot + "/opt/rocm", /*StrictChecking=*/true); return Candidates; } RocmInstallationDetector::RocmInstallationDetector( const Driver &D, const llvm::Triple &HostTriple, const llvm::opt::ArgList &Args, bool DetectHIPRuntime, bool DetectDeviceLib) : D(D) { RocmPathArg = Args.getLastArgValue(clang::driver::options::OPT_rocm_path_EQ); RocmDeviceLibPathArg = Args.getAllArgValues(clang::driver::options::OPT_rocm_device_lib_path_EQ); if (auto *A = Args.getLastArg(clang::driver::options::OPT_hip_version_EQ)) { HIPVersionArg = A->getValue(); unsigned Major = 0; unsigned Minor = 0; SmallVector Parts; HIPVersionArg.split(Parts, '.'); if (Parts.size()) Parts[0].getAsInteger(0, Major); if (Parts.size() > 1) Parts[1].getAsInteger(0, Minor); if (Parts.size() > 2) VersionPatch = Parts[2].str(); if (VersionPatch.empty()) VersionPatch = "0"; if (Major == 0 || Minor == 0) D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << HIPVersionArg; VersionMajorMinor = llvm::VersionTuple(Major, Minor); DetectedVersion = (Twine(Major) + "." + Twine(Minor) + "." + VersionPatch).str(); } else { VersionPatch = DefaultVersionPatch; VersionMajorMinor = llvm::VersionTuple(DefaultVersionMajor, DefaultVersionMinor); DetectedVersion = (Twine(DefaultVersionMajor) + "." + Twine(DefaultVersionMinor) + "." + VersionPatch) .str(); } if (DetectHIPRuntime) detectHIPRuntime(); if (DetectDeviceLib) detectDeviceLibrary(); } void RocmInstallationDetector::detectDeviceLibrary() { assert(LibDevicePath.empty()); if (!RocmDeviceLibPathArg.empty()) LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1]; else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH")) LibDevicePath = LibPathEnv; auto &FS = D.getVFS(); if (!LibDevicePath.empty()) { // Maintain compatability with HIP flag/envvar pointing directly at the // bitcode library directory. This points directly at the library path instead // of the rocm root installation. if (!FS.exists(LibDevicePath)) return; scanLibDevicePath(LibDevicePath); HasDeviceLibrary = allGenericLibsValid() && !LibDeviceMap.empty(); return; } // The install path situation in old versions of ROCm is a real mess, and // use a different install layout. Multiple copies of the device libraries // exist for each frontend project, and differ depending on which build // system produced the packages. Standalone OpenCL builds also have a // different directory structure from the ROCm OpenCL package. auto Candidates = getInstallationPathCandidates(); for (const auto &Candidate : Candidates) { auto CandidatePath = Candidate.Path; // Check device library exists at the given path. auto CheckDeviceLib = [&](StringRef Path) { bool CheckLibDevice = (!NoBuiltinLibs || Candidate.StrictChecking); if (CheckLibDevice && !FS.exists(Path)) return false; scanLibDevicePath(Path); if (!NoBuiltinLibs) { // Check that the required non-target libraries are all available. if (!allGenericLibsValid()) return false; // Check that we have found at least one libdevice that we can link in // if -nobuiltinlib hasn't been specified. if (LibDeviceMap.empty()) return false; } return true; }; // The possible structures are: // - ${ROCM_ROOT}/amdgcn/bitcode/* // - ${ROCM_ROOT}/lib/* // - ${ROCM_ROOT}/lib/bitcode/* // so try to detect these layouts. static llvm::SmallVector SubDirsList[] = { {"amdgcn", "bitcode"}, {"lib"}, {"lib", "bitcode"}, }; // Make a path by appending sub-directories to InstallPath. auto MakePath = [&](const llvm::ArrayRef &SubDirs) { auto Path = CandidatePath; for (auto SubDir : SubDirs) llvm::sys::path::append(Path, SubDir); return Path; }; for (auto SubDirs : SubDirsList) { LibDevicePath = MakePath(SubDirs); HasDeviceLibrary = CheckDeviceLib(LibDevicePath); if (HasDeviceLibrary) return; } } } void RocmInstallationDetector::detectHIPRuntime() { auto Candidates = getInstallationPathCandidates(); auto &FS = D.getVFS(); for (const auto &Candidate : Candidates) { InstallPath = Candidate.Path; if (InstallPath.empty() || !FS.exists(InstallPath)) continue; BinPath = InstallPath; llvm::sys::path::append(BinPath, "bin"); IncludePath = InstallPath; llvm::sys::path::append(IncludePath, "include"); LibPath = InstallPath; llvm::sys::path::append(LibPath, "lib"); llvm::ErrorOr> VersionFile = FS.getBufferForFile(BinPath + "/.hipVersion"); if (!VersionFile && Candidate.StrictChecking) continue; if (HIPVersionArg.empty() && VersionFile) ParseHIPVersionFile((*VersionFile)->getBuffer()); HasHIPRuntime = true; return; } HasHIPRuntime = false; } void RocmInstallationDetector::print(raw_ostream &OS) const { if (hasHIPRuntime()) OS << "Found HIP installation: " << InstallPath << ", version " << DetectedVersion << '\n'; } void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { // HIP header includes standard library wrapper headers under clang // cuda_wrappers directory. Since these wrapper headers include_next // standard C++ headers, whereas libc++ headers include_next other clang // headers. The include paths have to follow this order: // - wrapper include path // - standard C++ include path // - other clang include path // Since standard C++ and other clang include paths are added in other // places after this function, here we only need to make sure wrapper // include path is added. // // ROCm 3.5 does not fully support the wrapper headers. Therefore it needs // a workaround. SmallString<128> P(D.ResourceDir); if (UsesRuntimeWrapper) llvm::sys::path::append(P, "include", "cuda_wrappers"); CC1Args.push_back("-internal-isystem"); CC1Args.push_back(DriverArgs.MakeArgString(P)); } if (DriverArgs.hasArg(options::OPT_nogpuinc)) return; if (!hasHIPRuntime()) { D.Diag(diag::err_drv_no_hip_runtime); return; } CC1Args.push_back("-internal-isystem"); CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); if (UsesRuntimeWrapper) CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"}); } void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { std::string Linker = getToolChain().GetProgramPath(getShortName()); ArgStringList CmdArgs; + addLinkerCompressDebugSectionsOption(getToolChain(), Args, CmdArgs); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); CmdArgs.push_back("-shared"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); C.addCommand( std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker), CmdArgs, Inputs)); } void amdgpu::getAMDGPUTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, std::vector &Features) { if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args); if (Args.getLastArg(options::OPT_mwavefrontsize64)) { Features.push_back("-wavefrontsize16"); Features.push_back("-wavefrontsize32"); Features.push_back("+wavefrontsize64"); } if (Args.getLastArg(options::OPT_mno_wavefrontsize64)) { Features.push_back("-wavefrontsize16"); Features.push_back("+wavefrontsize32"); Features.push_back("-wavefrontsize64"); } handleTargetFeaturesGroup( Args, Features, options::OPT_m_amdgpu_Features_Group); } /// AMDGPU Toolchain AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args), OptionsDefault({{options::OPT_O, "3"}, {options::OPT_cl_std_EQ, "CL1.2"}}) {} Tool *AMDGPUToolChain::buildLinker() const { return new tools::amdgpu::Linker(*this); } DerivedArgList * AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const { DerivedArgList *DAL = Generic_ELF::TranslateArgs(Args, BoundArch, DeviceOffloadKind); // Do nothing if not OpenCL (-x cl) if (!Args.getLastArgValue(options::OPT_x).equals("cl")) return DAL; if (!DAL) DAL = new DerivedArgList(Args.getBaseArgs()); for (auto *A : Args) DAL->append(A); const OptTable &Opts = getDriver().getOpts(); // Phase 1 (.cl -> .bc) if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) { DAL->AddFlagArg(nullptr, Opts.getOption(getTriple().isArch64Bit() ? options::OPT_m64 : options::OPT_m32)); // Have to check OPT_O4, OPT_O0 & OPT_Ofast separately // as they defined that way in Options.td if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4, options::OPT_Ofast)) DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), getOptionDefault(options::OPT_O)); } return DAL; } bool AMDGPUToolChain::getDefaultDenormsAreZeroForTarget( llvm::AMDGPU::GPUKind Kind) { // Assume nothing without a specific target. if (Kind == llvm::AMDGPU::GK_NONE) return false; const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind); // Default to enabling f32 denormals by default on subtargets where fma is // fast with denormals const bool BothDenormAndFMAFast = (ArchAttr & llvm::AMDGPU::FEATURE_FAST_FMA_F32) && (ArchAttr & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32); return !BothDenormAndFMAFast; } llvm::DenormalMode AMDGPUToolChain::getDefaultDenormalModeForType( const llvm::opt::ArgList &DriverArgs, const JobAction &JA, const llvm::fltSemantics *FPType) const { // Denormals should always be enabled for f16 and f64. if (!FPType || FPType != &llvm::APFloat::IEEEsingle()) return llvm::DenormalMode::getIEEE(); if (JA.getOffloadingDeviceKind() == Action::OFK_HIP || JA.getOffloadingDeviceKind() == Action::OFK_Cuda) { auto Kind = llvm::AMDGPU::parseArchAMDGCN(JA.getOffloadingArch()); if (FPType && FPType == &llvm::APFloat::IEEEsingle() && DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, options::OPT_fno_cuda_flush_denormals_to_zero, getDefaultDenormsAreZeroForTarget(Kind))) return llvm::DenormalMode::getPreserveSign(); return llvm::DenormalMode::getIEEE(); } const StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ); auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); // TODO: There are way too many flags that change this. Do we need to check // them all? bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) || getDefaultDenormsAreZeroForTarget(Kind); // Outputs are flushed to zero (FTZ), preserving sign. Denormal inputs are // also implicit treated as zero (DAZ). return DAZ ? llvm::DenormalMode::getPreserveSign() : llvm::DenormalMode::getIEEE(); } bool AMDGPUToolChain::isWave64(const llvm::opt::ArgList &DriverArgs, llvm::AMDGPU::GPUKind Kind) { const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind); static bool HasWave32 = (ArchAttr & llvm::AMDGPU::FEATURE_WAVE32); return !HasWave32 || DriverArgs.hasFlag( options::OPT_mwavefrontsize64, options::OPT_mno_wavefrontsize64, false); } /// ROCM Toolchain ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : AMDGPUToolChain(D, Triple, Args) { RocmInstallation.detectDeviceLibrary(); } void AMDGPUToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { // Default to "hidden" visibility, as object level linking will not be // supported for the foreseeable future. if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, options::OPT_fvisibility_ms_compat)) { CC1Args.push_back("-fvisibility"); CC1Args.push_back("hidden"); CC1Args.push_back("-fapply-global-visibility-to-externs"); } } void ROCMToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { AMDGPUToolChain::addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); // For the OpenCL case where there is no offload target, accept -nostdlib to // disable bitcode linking. if (DeviceOffloadingKind == Action::OFK_None && DriverArgs.hasArg(options::OPT_nostdlib)) return; if (DriverArgs.hasArg(options::OPT_nogpulib)) return; if (!RocmInstallation.hasDeviceLibrary()) { getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; return; } // Get the device name and canonicalize it const StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ); auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); if (LibDeviceFile.empty()) { getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch; return; } bool Wave64 = isWave64(DriverArgs, Kind); // TODO: There are way too many flags that change this. Do we need to check // them all? bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) || getDefaultDenormsAreZeroForTarget(Kind); bool FiniteOnly = DriverArgs.hasArg(options::OPT_cl_finite_math_only); bool UnsafeMathOpt = DriverArgs.hasArg(options::OPT_cl_unsafe_math_optimizations); bool FastRelaxedMath = DriverArgs.hasArg(options::OPT_cl_fast_relaxed_math); bool CorrectSqrt = DriverArgs.hasArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt); // Add the OpenCL specific bitcode library. CC1Args.push_back("-mlink-builtin-bitcode"); CC1Args.push_back(DriverArgs.MakeArgString(RocmInstallation.getOpenCLPath())); // Add the generic set of libraries. RocmInstallation.addCommonBitcodeLibCC1Args( DriverArgs, CC1Args, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, FastRelaxedMath, CorrectSqrt); } void RocmInstallationDetector::addCommonBitcodeLibCC1Args( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, StringRef LibDeviceFile, bool Wave64, bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, bool FastRelaxedMath, bool CorrectSqrt) const { static const char LinkBitcodeFlag[] = "-mlink-builtin-bitcode"; CC1Args.push_back(LinkBitcodeFlag); CC1Args.push_back(DriverArgs.MakeArgString(getOCMLPath())); CC1Args.push_back(LinkBitcodeFlag); CC1Args.push_back(DriverArgs.MakeArgString(getOCKLPath())); CC1Args.push_back(LinkBitcodeFlag); CC1Args.push_back(DriverArgs.MakeArgString(getDenormalsAreZeroPath(DAZ))); CC1Args.push_back(LinkBitcodeFlag); CC1Args.push_back(DriverArgs.MakeArgString( getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath))); CC1Args.push_back(LinkBitcodeFlag); CC1Args.push_back(DriverArgs.MakeArgString( getFiniteOnlyPath(FiniteOnly || FastRelaxedMath))); CC1Args.push_back(LinkBitcodeFlag); CC1Args.push_back( DriverArgs.MakeArgString(getCorrectlyRoundedSqrtPath(CorrectSqrt))); CC1Args.push_back(LinkBitcodeFlag); CC1Args.push_back(DriverArgs.MakeArgString(getWavefrontSize64Path(Wave64))); CC1Args.push_back(LinkBitcodeFlag); CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp index 6b6e276b8ce7..535154e492a7 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1,1412 +1,1430 @@ //===--- CommonArgs.cpp - Args handling for multiple toolchains -*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "CommonArgs.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/SystemZ.h" #include "Arch/VE.h" #include "Arch/X86.h" #include "HIP.h" #include "Hexagon.h" #include "InputInfo.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Job.h" #include "clang/Driver/Options.h" #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" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #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" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/YAMLParser.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; void tools::addPathIfExists(const Driver &D, const Twine &Path, ToolChain::path_list &Paths) { if (D.getVFS().exists(Path)) Paths.push_back(Path.str()); } void tools::handleTargetFeaturesGroup(const ArgList &Args, std::vector &Features, OptSpecifier Group) { for (const Arg *A : Args.filtered(Group)) { StringRef Name = A->getOption().getName(); A->claim(); // Skip over "-m". assert(Name.startswith("m") && "Invalid feature name."); Name = Name.substr(1); bool IsNegative = Name.startswith("no-"); if (IsNegative) Name = Name.substr(3); Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } } std::vector tools::unifyTargetFeatures(const std::vector &Features) { std::vector UnifiedFeatures; // Find the last of each feature. llvm::StringMap LastOpt; for (unsigned I = 0, N = Features.size(); I < N; ++I) { StringRef Name = Features[I]; assert(Name[0] == '-' || Name[0] == '+'); LastOpt[Name.drop_front(1)] = I; } for (unsigned I = 0, N = Features.size(); I < N; ++I) { // If this feature was overridden, ignore it. StringRef Name = Features[I]; llvm::StringMap::iterator LastI = LastOpt.find(Name.drop_front(1)); assert(LastI != LastOpt.end()); unsigned Last = LastI->second; if (Last != I) continue; UnifiedFeatures.push_back(Name); } return UnifiedFeatures; } void tools::addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs, const char *ArgName, const char *EnvVar) { const char *DirList = ::getenv(EnvVar); bool CombinedArg = false; if (!DirList) return; // Nothing to do. StringRef Name(ArgName); if (Name.equals("-I") || Name.equals("-L") || Name.empty()) CombinedArg = true; StringRef Dirs(DirList); if (Dirs.empty()) // Empty string should not add '.'. return; StringRef::size_type Delim; while ((Delim = Dirs.find(llvm::sys::EnvPathSeparator)) != StringRef::npos) { if (Delim == 0) { // Leading colon. if (CombinedArg) { CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); } else { CmdArgs.push_back(ArgName); CmdArgs.push_back("."); } } else { if (CombinedArg) { CmdArgs.push_back( Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim))); } else { CmdArgs.push_back(ArgName); CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim))); } } Dirs = Dirs.substr(Delim + 1); } if (Dirs.empty()) { // Trailing colon. if (CombinedArg) { CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); } else { CmdArgs.push_back(ArgName); CmdArgs.push_back("."); } } else { // Add the last path. if (CombinedArg) { CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs)); } else { CmdArgs.push_back(ArgName); CmdArgs.push_back(Args.MakeArgString(Dirs)); } } } void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs, const JobAction &JA) { const Driver &D = TC.getDriver(); // Add extra linker input arguments which are not treated as inputs // (constructed via -Xarch_). Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); // LIBRARY_PATH are included before user inputs and only supported on native // toolchains. if (!TC.isCrossCompiling()) addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); 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 (auto *IA = II.getAction()) if ((JA.isHostOffloading(Action::OFK_OpenMP) && IA->isDeviceOffloading(Action::OFK_OpenMP))) continue; if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) // Don't try to pass LLVM inputs unless we have native support. D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); // Add filenames immediately. if (II.isFilename()) { CmdArgs.push_back(II.getFilename()); continue; } // Otherwise, this is a linker input argument. const Arg &A = II.getInputArg(); // Handle reserved library options. if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) TC.AddCXXStdlibLibArgs(Args, CmdArgs); else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) TC.AddCCKextLibArgs(Args, CmdArgs); else if (A.getOption().matches(options::OPT_z)) { // Pass -z prefix for gcc linker compatibility. A.claim(); A.render(Args, CmdArgs); } else { A.renderAsInput(Args, CmdArgs); } } } +void tools::addLinkerCompressDebugSectionsOption( + const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + // GNU ld supports --compress-debug-sections=none|zlib|zlib-gnu|zlib-gabi + // whereas zlib is an alias to zlib-gabi. Therefore -gz=none|zlib|zlib-gnu + // are translated to --compress-debug-sections=none|zlib|zlib-gnu. + // -gz is not translated since ld --compress-debug-sections option requires an + // argument. + if (const Arg *A = Args.getLastArg(options::OPT_gz_EQ)) { + StringRef V = A->getValue(); + if (V == "none" || V == "zlib" || V == "zlib-gnu") + CmdArgs.push_back(Args.MakeArgString("--compress-debug-sections=" + V)); + else + TC.getDriver().Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << V; + } +} + void tools::AddTargetFeature(const ArgList &Args, std::vector &Features, OptSpecifier OnOpt, OptSpecifier OffOpt, StringRef FeatureName) { if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) { if (A->getOption().matches(OnOpt)) Features.push_back(Args.MakeArgString("+" + FeatureName)); else Features.push_back(Args.MakeArgString("-" + FeatureName)); } } /// Get the (LLVM) name of the R600 gpu we are targeting. static std::string getR600TargetGPU(const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { const char *GPUName = A->getValue(); return llvm::StringSwitch(GPUName) .Cases("rv630", "rv635", "r600") .Cases("rv610", "rv620", "rs780", "rs880") .Case("rv740", "rv770") .Case("palm", "cedar") .Cases("sumo", "sumo2", "sumo") .Case("hemlock", "cypress") .Case("aruba", "cayman") .Default(GPUName); } return ""; } static std::string getLanaiTargetCPU(const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { return A->getValue(); } return ""; } /// Get the (LLVM) name of the WebAssembly cpu we are targeting. static StringRef getWebAssemblyTargetCPU(const ArgList &Args) { // If we have -mcpu=, use that. if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { StringRef CPU = A->getValue(); #ifdef __wasm__ // Handle "native" by examining the host. "native" isn't meaningful when // cross compiling, so only support this when the host is also WebAssembly. if (CPU == "native") return llvm::sys::getHostCPUName(); #endif return CPU; } return "generic"; } std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, bool FromAs) { Arg *A; switch (T.getArch()) { default: return ""; case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: return aarch64::getAArch64TargetCPU(Args, T, A); case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: { StringRef MArch, MCPU; arm::getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs); return arm::getARMTargetCPU(MCPU, MArch, T); } case llvm::Triple::avr: if (const Arg *A = Args.getLastArg(options::OPT_mmcu_EQ)) return A->getValue(); return ""; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, T, CPUName, ABIName); return std::string(CPUName); } case llvm::Triple::nvptx: case llvm::Triple::nvptx64: if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) return A->getValue(); return ""; case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: { std::string TargetCPUName = ppc::getPPCTargetCPU(Args); // LLVM may default to generating code for the native CPU, // but, like gcc, we default to a more generic option for // each architecture. (except on AIX) if (!TargetCPUName.empty()) return TargetCPUName; if (T.isOSAIX()) TargetCPUName = "pwr4"; else if (T.getArch() == llvm::Triple::ppc64le) TargetCPUName = "ppc64le"; else if (T.getArch() == llvm::Triple::ppc64) TargetCPUName = "ppc64"; else TargetCPUName = "ppc"; return TargetCPUName; } case llvm::Triple::riscv32: case llvm::Triple::riscv64: if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(); return ""; case llvm::Triple::bpfel: case llvm::Triple::bpfeb: case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(); return ""; case llvm::Triple::x86: case llvm::Triple::x86_64: return x86::getX86TargetCPU(Args, T); case llvm::Triple::hexagon: return "hexagon" + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); case llvm::Triple::lanai: return getLanaiTargetCPU(Args); case llvm::Triple::systemz: return systemz::getSystemZTargetCPU(Args); case llvm::Triple::r600: case llvm::Triple::amdgcn: return getR600TargetGPU(Args); case llvm::Triple::wasm32: case llvm::Triple::wasm64: return std::string(getWebAssemblyTargetCPU(Args)); } } llvm::StringRef tools::getLTOParallelism(const ArgList &Args, const Driver &D) { Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ); if (!LtoJobsArg) return {}; if (!llvm::get_threadpool_strategy(LtoJobsArg->getValue())) D.Diag(diag::err_drv_invalid_int_value) << LtoJobsArg->getAsString(Args) << LtoJobsArg->getValue(); return LtoJobsArg->getValue(); } // CloudABI uses -ffunction-sections and -fdata-sections by default. bool tools::isUseSeparateSections(const llvm::Triple &Triple) { return Triple.getOS() == llvm::Triple::CloudABI; } void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO) { const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath()); const Driver &D = ToolChain.getDriver(); if (llvm::sys::path::filename(Linker) != "ld.lld" && llvm::sys::path::stem(Linker) != "ld.lld") { // 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(_WIN32) const char *Suffix = ".dll"; #elif defined(__APPLE__) const char *Suffix = ".dylib"; #else const char *Suffix = ".so"; #endif SmallString<1024> Plugin; llvm::sys::path::native( Twine(D.Dir) + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + Suffix, Plugin); CmdArgs.push_back(Args.MakeArgString(Plugin)); } // Try to pass driver level flags relevant to LTO code generation down to // the plugin. // Handle flags for selecting CPU variants. std::string CPU = getCPUName(Args, ToolChain.getTriple()); if (!CPU.empty()) CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { // The optimization level matches // CompilerInvocation.cpp:getOptimizationLevel(). StringRef OOpt; if (A->getOption().matches(options::OPT_O4) || A->getOption().matches(options::OPT_Ofast)) OOpt = "3"; else if (A->getOption().matches(options::OPT_O)) { OOpt = A->getValue(); if (OOpt == "g") OOpt = "1"; else if (OOpt == "s" || OOpt == "z") OOpt = "2"; } else if (A->getOption().matches(options::OPT_O0)) OOpt = "0"; if (!OOpt.empty()) 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"); StringRef Parallelism = getLTOParallelism(Args, D); if (!Parallelism.empty()) CmdArgs.push_back( Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism))); // If an explicit debugger tuning argument appeared, pass it along. if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { if (A->getOption().matches(options::OPT_glldb)) CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb"); else if (A->getOption().matches(options::OPT_gsce)) CmdArgs.push_back("-plugin-opt=-debugger-tune=sce"); else CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb"); } bool UseSeparateSections = isUseSeparateSections(ToolChain.getEffectiveTriple()); if (Args.hasFlag(options::OPT_ffunction_sections, options::OPT_fno_function_sections, UseSeparateSections)) { CmdArgs.push_back("-plugin-opt=-function-sections"); } if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, UseSeparateSections)) { CmdArgs.push_back("-plugin-opt=-data-sections"); } if (Arg *A = getLastProfileSampleUseArg(Args)) { StringRef FName = A->getValue(); if (!llvm::sys::fs::exists(FName)) D.Diag(diag::err_drv_no_such_file) << FName; else CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); } auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate, options::OPT_fcs_profile_generate_EQ, options::OPT_fno_profile_generate); if (CSPGOGenerateArg && CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) CSPGOGenerateArg = nullptr; auto *ProfileUseArg = getLastProfileUseArg(Args); if (CSPGOGenerateArg) { CmdArgs.push_back(Args.MakeArgString("-plugin-opt=cs-profile-generate")); if (CSPGOGenerateArg->getOption().matches( options::OPT_fcs_profile_generate_EQ)) { SmallString<128> Path(CSPGOGenerateArg->getValue()); llvm::sys::path::append(Path, "default_%m.profraw"); CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + Path)); } else CmdArgs.push_back( Args.MakeArgString("-plugin-opt=cs-profile-path=default_%m.profraw")); } else if (ProfileUseArg) { SmallString<128> Path( ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); if (Path.empty() || llvm::sys::fs::is_directory(Path)) llvm::sys::path::append(Path, "default.profdata"); CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + Path)); } // 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 */ ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER)) { CmdArgs.push_back("-plugin-opt=new-pass-manager"); } // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); if (!StatsFile.empty()) CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile)); addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true); } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { // Enable -frtlib-add-rpath by default for the case of VE. const bool IsVE = TC.getTriple().isVE(); bool DefaultValue = IsVE; if (!Args.hasFlag(options::OPT_frtlib_add_rpath, options::OPT_fno_rtlib_add_rpath, DefaultValue)) return; std::string CandidateRPath = TC.getArchSpecificLibPath(); if (TC.getVFS().exists(CandidateRPath)) { CmdArgs.push_back("-rpath"); CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str())); } } bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, const ArgList &Args, bool ForceStaticHostRuntime, bool IsOffloadingHost, bool GompNeedsRT) { if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) return false; Driver::OpenMPRuntimeKind RTKind = TC.getDriver().getOpenMPRuntime(Args); if (RTKind == Driver::OMPRT_Unknown) // Already diagnosed. return false; if (ForceStaticHostRuntime) CmdArgs.push_back("-Bstatic"); switch (RTKind) { case Driver::OMPRT_OMP: CmdArgs.push_back("-lomp"); break; case Driver::OMPRT_GOMP: CmdArgs.push_back("-lgomp"); break; case Driver::OMPRT_IOMP5: CmdArgs.push_back("-liomp5"); break; case Driver::OMPRT_Unknown: break; } if (ForceStaticHostRuntime) CmdArgs.push_back("-Bdynamic"); if (RTKind == Driver::OMPRT_GOMP && GompNeedsRT) CmdArgs.push_back("-lrt"); if (IsOffloadingHost) CmdArgs.push_back("-lomptarget"); addArchSpecificRPath(TC, Args, CmdArgs); return true; } static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer, bool IsShared, bool IsWhole) { // Wrap any static runtimes that must be forced into executable in // whole-archive. if (IsWhole) CmdArgs.push_back("--whole-archive"); CmdArgs.push_back(TC.getCompilerRTArgString( Args, Sanitizer, IsShared ? ToolChain::FT_Shared : ToolChain::FT_Static)); if (IsWhole) CmdArgs.push_back("--no-whole-archive"); if (IsShared) { addArchSpecificRPath(TC, Args, CmdArgs); } } // Tries to use a file with the list of dynamic symbols that need to be exported // from the runtime library. Returns true if the file was found. 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")); return true; } return false; } void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { // Fuchsia never needs these. Any sanitizer runtimes with system // dependencies use the `.deplibs` feature instead. if (TC.getTriple().isOSFuchsia()) return; // 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 & Android. if (TC.getTriple().getOS() != llvm::Triple::RTEMS && !TC.getTriple().isAndroid()) { CmdArgs.push_back("-lpthread"); if (!TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lrt"); } CmdArgs.push_back("-lm"); // There's no libdl on all OSes. if (!TC.getTriple().isOSFreeBSD() && !TC.getTriple().isOSNetBSD() && !TC.getTriple().isOSOpenBSD() && TC.getTriple().getOS() != llvm::Triple::RTEMS) CmdArgs.push_back("-ldl"); // Required for backtrace on some OSes if (TC.getTriple().isOSFreeBSD() || TC.getTriple().isOSNetBSD()) CmdArgs.push_back("-lexecinfo"); } static void collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, SmallVectorImpl &SharedRuntimes, SmallVectorImpl &StaticRuntimes, SmallVectorImpl &NonWholeStaticRuntimes, SmallVectorImpl &HelperStaticRuntimes, SmallVectorImpl &RequiredSymbols) { const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); // Collect shared runtimes. if (SanArgs.needsSharedRt()) { if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { SharedRuntimes.push_back("asan"); if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid()) HelperStaticRuntimes.push_back("asan-preinit"); } if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { if (SanArgs.requiresMinimalRuntime()) SharedRuntimes.push_back("ubsan_minimal"); else SharedRuntimes.push_back("ubsan_standalone"); } if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) { if (SanArgs.requiresMinimalRuntime()) SharedRuntimes.push_back("scudo_minimal"); else SharedRuntimes.push_back("scudo"); } if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) SharedRuntimes.push_back("hwasan"); } // The stats_client library is also statically linked into DSOs. if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) StaticRuntimes.push_back("stats_client"); // Collect static runtimes. if (Args.hasArg(options::OPT_shared)) { // Don't link static runtimes into DSOs. return; } // Each static runtime that has a DSO counterpart above is excluded below, // but runtimes that exist only as static are not affected by needsSharedRt. if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { StaticRuntimes.push_back("asan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("asan_cxx"); } if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) { StaticRuntimes.push_back("hwasan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("hwasan_cxx"); } if (SanArgs.needsDfsanRt() && SanArgs.linkRuntimes()) StaticRuntimes.push_back("dfsan"); if (SanArgs.needsLsanRt() && SanArgs.linkRuntimes()) StaticRuntimes.push_back("lsan"); if (SanArgs.needsMsanRt() && SanArgs.linkRuntimes()) { StaticRuntimes.push_back("msan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("msan_cxx"); } if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes()) { StaticRuntimes.push_back("tsan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("tsan_cxx"); } if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { if (SanArgs.requiresMinimalRuntime()) { StaticRuntimes.push_back("ubsan_minimal"); } else { StaticRuntimes.push_back("ubsan_standalone"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("ubsan_standalone_cxx"); } } if (SanArgs.needsSafeStackRt() && SanArgs.linkRuntimes()) { NonWholeStaticRuntimes.push_back("safestack"); RequiredSymbols.push_back("__safestack_init"); } if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes())) { if (SanArgs.needsCfiRt() && SanArgs.linkRuntimes()) StaticRuntimes.push_back("cfi"); if (SanArgs.needsCfiDiagRt() && SanArgs.linkRuntimes()) { StaticRuntimes.push_back("cfi_diag"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("ubsan_standalone_cxx"); } } if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) { NonWholeStaticRuntimes.push_back("stats"); RequiredSymbols.push_back("__sanitizer_stats_register"); } if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) { 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"); } } } // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, // C runtime, etc). Returns true if sanitizer system deps need to be linked in. bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { SmallVector SharedRuntimes, StaticRuntimes, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols; collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols); const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); // Inject libfuzzer dependencies. if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() && !Args.hasArg(options::OPT_shared)) { addSanitizerRuntime(TC, Args, CmdArgs, "fuzzer", false, true); if (!Args.hasArg(clang::driver::options::OPT_nostdlibxx)) TC.AddCXXStdlibLibArgs(Args, CmdArgs); } for (auto RT : SharedRuntimes) addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false); for (auto RT : HelperStaticRuntimes) addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true); bool AddExportDynamic = false; for (auto RT : StaticRuntimes) { addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true); AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); } for (auto RT : NonWholeStaticRuntimes) { addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false); AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); } for (auto S : RequiredSymbols) { CmdArgs.push_back("-u"); CmdArgs.push_back(Args.MakeArgString(S)); } // 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"); if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) CmdArgs.push_back("--export-dynamic-symbol=__cfi_check"); 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")); for (const auto &Mode : TC.getXRayArgs().modeList()) CmdArgs.push_back(TC.getCompilerRTArgString(Args, Mode)); 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().isOSOpenBSD()) CmdArgs.push_back("-lrt"); CmdArgs.push_back("-lm"); if (!TC.getTriple().isOSFreeBSD() && !TC.getTriple().isOSNetBSD() && !TC.getTriple().isOSOpenBSD()) 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)) return !A->getOption().matches(options::OPT_O0); // Defaults to -O0. return false; } const char *tools::SplitDebugName(const ArgList &Args, const InputInfo &Input, const InputInfo &Output) { if (Arg *A = Args.getLastArg(options::OPT_gsplit_dwarf_EQ)) if (StringRef(A->getValue()) == "single") return Args.MakeArgString(Output.getFilename()); Arg *FinalOutput = Args.getLastArg(options::OPT_o); if (FinalOutput && Args.hasArg(options::OPT_c)) { SmallString<128> T(FinalOutput->getValue()); llvm::sys::path::replace_extension(T, "dwo"); return Args.MakeArgString(T); } else { // Use the compilation dir. SmallString<128> T( Args.getLastArgValue(options::OPT_fdebug_compilation_dir)); SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput())); llvm::sys::path::replace_extension(F, "dwo"); T += F; return Args.MakeArgString(F); } } void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, const JobAction &JA, const ArgList &Args, const InputInfo &Output, const char *OutFile) { ArgStringList ExtractArgs; ExtractArgs.push_back("--extract-dwo"); ArgStringList StripArgs; StripArgs.push_back("--strip-dwo"); // Grabbing the output of the earlier compile step. StripArgs.push_back(Output.getFilename()); ExtractArgs.push_back(Output.getFilename()); ExtractArgs.push_back(OutFile); const char *Exec = Args.MakeArgString(TC.GetProgramPath(CLANG_DEFAULT_OBJCOPY)); InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename()); // First extract the dwo sections. C.addCommand(std::make_unique( JA, T, ResponseFileSupport::AtFileCurCP(), Exec, ExtractArgs, II)); // Then remove them from the original .o file. C.addCommand(std::make_unique( JA, T, ResponseFileSupport::AtFileCurCP(), Exec, StripArgs, II)); } // Claim options we don't want to warn if they are unused. We do this for // options that build systems might add but are unused when assembling or only // running the preprocessor for example. void tools::claimNoWarnArgs(const ArgList &Args) { // Don't warn about unused -f(no-)?lto. This can happen when we're // preprocessing, precompiling or assembling. Args.ClaimAllArgs(options::OPT_flto_EQ); Args.ClaimAllArgs(options::OPT_flto); Args.ClaimAllArgs(options::OPT_fno_lto); } Arg *tools::getLastProfileUseArg(const ArgList &Args) { auto *ProfileUseArg = Args.getLastArg( options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, options::OPT_fprofile_use, options::OPT_fprofile_use_EQ, options::OPT_fno_profile_instr_use); if (ProfileUseArg && ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use)) ProfileUseArg = nullptr; return ProfileUseArg; } Arg *tools::getLastProfileSampleUseArg(const ArgList &Args) { auto *ProfileSampleUseArg = Args.getLastArg( options::OPT_fprofile_sample_use, options::OPT_fprofile_sample_use_EQ, options::OPT_fauto_profile, options::OPT_fauto_profile_EQ, options::OPT_fno_profile_sample_use, options::OPT_fno_auto_profile); if (ProfileSampleUseArg && (ProfileSampleUseArg->getOption().matches( options::OPT_fno_profile_sample_use) || ProfileSampleUseArg->getOption().matches(options::OPT_fno_auto_profile))) return nullptr; return Args.getLastArg(options::OPT_fprofile_sample_use_EQ, options::OPT_fauto_profile_EQ); } /// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then, /// smooshes them together with platform defaults, to decide whether /// this compile should be using PIC mode or not. Returns a tuple of /// (RelocationModel, PICLevel, IsPIE). std::tuple tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple(); const llvm::Triple &Triple = ToolChain.getTriple(); bool PIE = ToolChain.isPIEDefault(); bool PIC = PIE || ToolChain.isPICDefault(); // The Darwin/MachO default to use PIC does not apply when using -static. if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static)) PIE = PIC = false; bool IsPICLevelTwo = PIC; bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); // Android-specific defaults for PIC/PIE if (Triple.isAndroid()) { switch (Triple.getArch()) { case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::aarch64: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: PIC = true; // "-fpic" break; case llvm::Triple::x86: case llvm::Triple::x86_64: PIC = true; // "-fPIC" IsPICLevelTwo = true; break; default: break; } } // OpenBSD-specific defaults for PIE if (Triple.isOSOpenBSD()) { switch (ToolChain.getArch()) { case llvm::Triple::arm: case llvm::Triple::aarch64: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::x86: case llvm::Triple::x86_64: IsPICLevelTwo = false; // "-fpie" break; case llvm::Triple::ppc: case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: IsPICLevelTwo = true; // "-fPIE" break; default: break; } } // 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 // option implicitly enables PIC at the same level. Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, options::OPT_fpie, options::OPT_fno_pie); if (Triple.isOSWindows() && LastPICArg && LastPICArg == Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, options::OPT_fPIE, options::OPT_fpie)) { ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << LastPICArg->getSpelling() << Triple.str(); if (Triple.getArch() == llvm::Triple::x86_64) return std::make_tuple(llvm::Reloc::PIC_, 2U, false); return std::make_tuple(llvm::Reloc::Static, 0U, false); } // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness // is forced, then neither PIC nor PIE flags will have no effect. if (!ToolChain.isPICDefaultForced()) { if (LastPICArg) { Option O = LastPICArg->getOption(); if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); PIC = PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); IsPICLevelTwo = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); } else { PIE = PIC = false; if (EffectiveTriple.isPS4CPU()) { Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ); StringRef Model = ModelArg ? ModelArg->getValue() : ""; if (Model != "kernel") { PIC = true; ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic) << LastPICArg->getSpelling(); } } } } } // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the // PIC level would've been set to level 1, force it back to level 2 PIC // instead. if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU())) IsPICLevelTwo |= ToolChain.isPICDefault(); // This kernel flags are a trump-card: they will disable PIC/PIE // generation, independent of the argument order. if (KernelOrKext && ((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) && !EffectiveTriple.isWatchOS())) PIC = PIE = false; if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { // This is a very special mode. It trumps the other modes, almost no one // uses it, and it isn't even valid on any OS but Darwin. if (!Triple.isOSDarwin()) ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << A->getSpelling() << Triple.str(); // FIXME: Warn when this flag trumps some other PIC or PIE flag. // Only a forced PIC mode can cause the actual compile to have PIC defines // etc., no flags are sufficient. This behavior was selected to closely // match that of llvm-gcc and Apple GCC before that. PIC = ToolChain.isPICDefault() && ToolChain.isPICDefaultForced(); return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2U : 0U, false); } bool EmbeddedPISupported; switch (Triple.getArch()) { case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: EmbeddedPISupported = true; break; default: EmbeddedPISupported = false; break; } bool ROPI = false, RWPI = false; Arg* LastROPIArg = Args.getLastArg(options::OPT_fropi, options::OPT_fno_ropi); if (LastROPIArg && LastROPIArg->getOption().matches(options::OPT_fropi)) { if (!EmbeddedPISupported) ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << LastROPIArg->getSpelling() << Triple.str(); ROPI = true; } Arg *LastRWPIArg = Args.getLastArg(options::OPT_frwpi, options::OPT_fno_rwpi); if (LastRWPIArg && LastRWPIArg->getOption().matches(options::OPT_frwpi)) { if (!EmbeddedPISupported) ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << LastRWPIArg->getSpelling() << Triple.str(); RWPI = true; } // 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); 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); llvm::Reloc::Model RelocM = llvm::Reloc::Static; if (ROPI && RWPI) RelocM = llvm::Reloc::ROPI_RWPI; else if (ROPI) RelocM = llvm::Reloc::ROPI; else if (RWPI) RelocM = llvm::Reloc::RWPI; 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; } unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC, const ArgList &Args) { const Arg *A = Args.getLastArg(options::OPT_fdebug_default_version); if (!A) return 0; unsigned Value = 0; if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 5 || Value < 2) TC.getDriver().Diag(diag::err_drv_invalid_int_value) << A->getAsString(Args) << A->getValue(); return Value; } void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs) { llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(ToolChain, Args); if (RelocationModel != llvm::Reloc::Static) CmdArgs.push_back("-KPIC"); } /// 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); } enum class LibGccType { UnspecifiedLibGcc, StaticLibGcc, SharedLibGcc }; static LibGccType getLibGccType(const Driver &D, const ArgList &Args) { if (Args.hasArg(options::OPT_static_libgcc) || Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_pie)) return LibGccType::StaticLibGcc; if (Args.hasArg(options::OPT_shared_libgcc) || D.CCCIsCXX()) return LibGccType::SharedLibGcc; return LibGccType::UnspecifiedLibGcc; } // Gcc adds libgcc arguments in various ways: // // gcc : -lgcc --as-needed -lgcc_s --no-as-needed // g++ : -lgcc_s -lgcc // gcc shared: -lgcc_s -lgcc // g++ shared: -lgcc_s -lgcc // gcc static: -lgcc -lgcc_eh // g++ static: -lgcc -lgcc_eh // gcc static-pie: -lgcc -lgcc_eh // g++ static-pie: -lgcc -lgcc_eh // // Also, certain targets need additional adjustments. static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { ToolChain::UnwindLibType UNW = TC.GetUnwindLibType(Args); // Targets that don't use unwind libraries. if (TC.getTriple().isAndroid() || TC.getTriple().isOSIAMCU() || TC.getTriple().isOSBinFormatWasm() || UNW == ToolChain::UNW_None) return; LibGccType LGT = getLibGccType(D, Args); bool AsNeeded = LGT == LibGccType::UnspecifiedLibGcc && !TC.getTriple().isAndroid() && !TC.getTriple().isOSCygMing(); if (AsNeeded) CmdArgs.push_back("--as-needed"); switch (UNW) { case ToolChain::UNW_None: return; case ToolChain::UNW_Libgcc: { if (LGT == LibGccType::StaticLibGcc) CmdArgs.push_back("-lgcc_eh"); else CmdArgs.push_back("-lgcc_s"); break; } case ToolChain::UNW_CompilerRT: if (LGT == LibGccType::StaticLibGcc) CmdArgs.push_back("-l:libunwind.a"); else if (TC.getTriple().isOSCygMing()) { if (LGT == LibGccType::SharedLibGcc) CmdArgs.push_back("-l:libunwind.dll.a"); else // Let the linker choose between libunwind.dll.a and libunwind.a // depending on what's available, and depending on the -static flag CmdArgs.push_back("-lunwind"); } else CmdArgs.push_back("-l:libunwind.so"); break; } if (AsNeeded) CmdArgs.push_back("--no-as-needed"); } static void AddLibgcc(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { LibGccType LGT = getLibGccType(D, Args); if (LGT != LibGccType::SharedLibGcc) CmdArgs.push_back("-lgcc"); AddUnwindLibrary(TC, D, CmdArgs, Args); if (LGT == LibGccType::SharedLibGcc) CmdArgs.push_back("-lgcc"); // According to Android ABI, we have to link with libdl if we are // linking with non-static libgcc. // // NOTE: This fixes a link error on Android MIPS as well. The non-static // libgcc for MIPS relies on _Unwind_Find_FDE and dl_iterate_phdr from libdl. if (TC.getTriple().isAndroid() && LGT != LibGccType::StaticLibGcc) CmdArgs.push_back("-ldl"); } void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { // Make use of compiler-rt if --rtlib option is used ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args); switch (RLT) { case ToolChain::RLT_CompilerRT: CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); AddUnwindLibrary(TC, D, CmdArgs, Args); break; case ToolChain::RLT_Libgcc: // Make sure libgcc is not used under MSVC environment by default if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { // Issue error diagnostic if libgcc is explicitly specified // through command line as --rtlib option argument. if (Args.hasArg(options::OPT_rtlib_EQ)) { TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC"; } } else AddLibgcc(TC, D, CmdArgs, Args); break; } } 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; } void tools::addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags) { Flags.push_back(std::string(Enabled ? "+" : "-") + Flag); } void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, bool IsLTO) { auto addArg = [&, IsLTO](const Twine &Arg) { if (IsLTO) { CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg)); } else { CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString(Arg)); } }; if (Args.hasArg(options::OPT_mbranches_within_32B_boundaries)) { addArg(Twine("-x86-branches-within-32B-boundaries")); } if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_boundary_EQ)) { StringRef Value = A->getValue(); unsigned Boundary; if (Value.getAsInteger(10, Boundary) || Boundary < 16 || !llvm::isPowerOf2_64(Boundary)) { D.Diag(diag::err_drv_invalid_argument_to_option) << Value << A->getOption().getName(); } else { addArg("-x86-align-branch-boundary=" + Twine(Boundary)); } } if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_EQ)) { std::string AlignBranch; for (StringRef T : A->getValues()) { if (T != "fused" && T != "jcc" && T != "jmp" && T != "call" && T != "ret" && T != "indirect") D.Diag(diag::err_drv_invalid_malign_branch_EQ) << T << "fused, jcc, jmp, call, ret, indirect"; if (!AlignBranch.empty()) AlignBranch += '+'; AlignBranch += T; } addArg("-x86-align-branch=" + Twine(AlignBranch)); } if (const Arg *A = Args.getLastArg(options::OPT_mpad_max_prefix_size_EQ)) { StringRef Value = A->getValue(); unsigned PrefixSize; if (Value.getAsInteger(10, PrefixSize)) { D.Diag(diag::err_drv_invalid_argument_to_option) << Value << A->getOption().getName(); } else { addArg("-x86-pad-max-prefix-size=" + Twine(PrefixSize)); } } } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h index 29dedec9b09c..0028ea0ca337 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h @@ -1,140 +1,144 @@ //===--- CommonArgs.h - Args handling for multiple toolchains ---*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H #include "InputInfo.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Multilib.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include "llvm/Support/CodeGen.h" namespace clang { namespace driver { namespace tools { void addPathIfExists(const Driver &D, const Twine &Path, ToolChain::path_list &Paths); void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const JobAction &JA); +void addLinkerCompressDebugSectionsOption(const ToolChain &TC, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + void claimNoWarnArgs(const llvm::opt::ArgList &Args); bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); void linkSanitizerRuntimeDeps(const ToolChain &TC, llvm::opt::ArgStringList &CmdArgs); bool addXRayRuntime(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); void linkXRayRuntimeDeps(const ToolChain &TC, llvm::opt::ArgStringList &CmdArgs); void AddRunTimeLibs(const ToolChain &TC, const Driver &D, llvm::opt::ArgStringList &CmdArgs, const llvm::opt::ArgList &Args); const char *SplitDebugName(const llvm::opt::ArgList &Args, const InputInfo &Input, const InputInfo &Output); void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, const JobAction &JA, const llvm::opt::ArgList &Args, const InputInfo &Output, const char *OutFile); void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO); std::tuple ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args); unsigned ParseFunctionAlignment(const ToolChain &TC, const llvm::opt::ArgList &Args); unsigned ParseDebugDefaultVersion(const ToolChain &TC, const llvm::opt::ArgList &Args); void AddAssemblerKPIC(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); /// Returns true, if an OpenMP runtime has been added. bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC, const llvm::opt::ArgList &Args, bool ForceStaticHostRuntime = false, bool IsOffloadingHost = false, bool GompNeedsRT = false); llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args); llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args); bool isObjCAutoRefCount(const llvm::opt::ArgList &Args); llvm::StringRef getLTOParallelism(const llvm::opt::ArgList &Args, const Driver &D); bool areOptimizationsEnabled(const llvm::opt::ArgList &Args); bool isUseSeparateSections(const llvm::Triple &Triple); /// \p EnvVar is split by system delimiter for environment variables. /// If \p ArgName is "-I", "-L", or an empty string, each entry from \p EnvVar /// is prefixed by \p ArgName then added to \p Args. Otherwise, for each /// entry of \p EnvVar, \p ArgName is added to \p Args first, then the entry /// itself is added. void addDirectoryList(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const char *ArgName, const char *EnvVar); void AddTargetFeature(const llvm::opt::ArgList &Args, std::vector &Features, llvm::opt::OptSpecifier OnOpt, llvm::opt::OptSpecifier OffOpt, StringRef FeatureName); std::string getCPUName(const llvm::opt::ArgList &Args, const llvm::Triple &T, bool FromAs = false); /// Iterate \p Args and convert -mxxx to +xxx and -mno-xxx to -xxx and /// append it to \p Features. /// /// Note: Since \p Features may contain default values before calling /// this function, or may be appended with entries to override arguments, /// entries in \p Features are not unique. void handleTargetFeaturesGroup(const llvm::opt::ArgList &Args, std::vector &Features, llvm::opt::OptSpecifier Group); /// If there are multiple +xxx or -xxx features, keep the last one. std::vector unifyTargetFeatures(const std::vector &Features); /// Handles the -save-stats option and returns the filename to save statistics /// to. SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args, const InputInfo &Output, const InputInfo &Input, const Driver &D); /// \p Flag must be a flag accepted by the driver with its leading '-' removed, // otherwise '-print-multi-lib' will not emit them correctly. void addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags); void addX86AlignBranchArgs(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, bool IsLTO); } // end namespace tools } // end namespace driver } // end namespace clang #endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp index 909ac5e99212..6d8e25470e28 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -1,491 +1,492 @@ //===--- FreeBSD.cpp - FreeBSD ToolChain Implementations --------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "FreeBSD.h" #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/Sparc.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/VirtualFileSystem.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; const auto &D = getToolChain().getDriver(); // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. switch (getToolChain().getArch()) { default: break; case llvm::Triple::x86: CmdArgs.push_back("--32"); break; case llvm::Triple::ppc: CmdArgs.push_back("-a32"); break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); if (getToolChain().getTriple().isLittleEndian()) CmdArgs.push_back("-EL"); else CmdArgs.push_back("-EB"); if (Arg *A = Args.getLastArg(options::OPT_G)) { StringRef v = A->getValue(); CmdArgs.push_back(Args.MakeArgString("-G" + v)); A->claim(); } AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: { arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); if (ABI == arm::FloatABI::Hard) CmdArgs.push_back("-mfpu=vfp"); else CmdArgs.push_back("-mfpu=softvfp"); switch (getToolChain().getTriple().getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::GNUEABI: case llvm::Triple::EABI: CmdArgs.push_back("-meabi=5"); break; default: CmdArgs.push_back("-matpcs"); } break; } case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: { std::string CPU = getCPUName(Args, getToolChain().getTriple()); CmdArgs.push_back( sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } } for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fdebug_prefix_map_EQ)) { StringRef Map = A->getValue(); if (Map.find('=') == StringRef::npos) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else { CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map")); CmdArgs.push_back(Args.MakeArgString(Map)); } A->claim(); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const toolchains::FreeBSD &ToolChain = static_cast(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsPIE = !Args.hasArg(options::OPT_shared) && (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (IsPIE) CmdArgs.push_back("-pie"); CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-Bshareable"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld-elf.so.1"); } const llvm::Triple &T = ToolChain.getTriple(); if (T.getOSMajorVersion() >= 9) { if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || T.isX86()) CmdArgs.push_back("--hash-style=both"); } CmdArgs.push_back("--enable-new-dtags"); } // Explicitly set the linker emulation for platforms that might not // be the default emulation for the linker. switch (Arch) { case llvm::Triple::x86: CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386_fbsd"); break; case llvm::Triple::ppc: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32ppc_fbsd"); break; case llvm::Triple::mips: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32btsmip_fbsd"); break; case llvm::Triple::mipsel: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32ltsmip_fbsd"); break; case llvm::Triple::mips64: CmdArgs.push_back("-m"); if (tools::mips::hasMipsAbiArg(Args, "n32")) CmdArgs.push_back("elf32btsmipn32_fbsd"); else CmdArgs.push_back("elf64btsmip_fbsd"); break; case llvm::Triple::mips64el: CmdArgs.push_back("-m"); if (tools::mips::hasMipsAbiArg(Args, "n32")) CmdArgs.push_back("elf32ltsmipn32_fbsd"); else CmdArgs.push_back("elf64ltsmip_fbsd"); break; case llvm::Triple::riscv32: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32lriscv"); break; case llvm::Triple::riscv64: CmdArgs.push_back("-m"); CmdArgs.push_back("elf64lriscv"); break; default: break; } if (Arg *A = Args.getLastArg(options::OPT_G)) { if (ToolChain.getTriple().isMIPS()) { StringRef v = A->getValue(); CmdArgs.push_back(Args.MakeArgString("-G" + v)); A->claim(); } } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) crt1 = "gcrt1.o"; else if (IsPIE) crt1 = "Scrt1.o"; else crt1 = "crt1.o"; } if (crt1) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); const char *crtbegin = nullptr; if (Args.hasArg(options::OPT_static)) crtbegin = "crtbeginT.o"; else if (Args.hasArg(options::OPT_shared) || IsPIE) crtbegin = "crtbeginS.o"; else crtbegin = "crtbegin.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } Args.AddAllArgs(CmdArgs, options::OPT_L); ToolChain.AddFilePathLibArgs(Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); } bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); + addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Args.hasArg(options::OPT_static); addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else CmdArgs.push_back("-lm"); } if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); if (NeedsXRayDeps) linkXRayRuntimeDeps(ToolChain, CmdArgs); // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding // the default system libraries. Just mimic this for now. if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lgcc_p"); else CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else if (Args.hasArg(options::OPT_pg)) { CmdArgs.push_back("-lgcc_eh_p"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } if (Args.hasArg(options::OPT_pthread)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lpthread_p"); else CmdArgs.push_back("-lpthread"); } if (Args.hasArg(options::OPT_pg)) { if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-lc"); else CmdArgs.push_back("-lc_p"); CmdArgs.push_back("-lgcc_p"); } else { CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else if (Args.hasArg(options::OPT_pg)) { CmdArgs.push_back("-lgcc_eh_p"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || IsPIE) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); else CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } ToolChain.addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall // back to '/usr/lib' if it doesn't exist. if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() || Triple.getArch() == llvm::Triple::ppc) && D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); else getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); } ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { if (getTriple().getOSMajorVersion() >= 10) return ToolChain::CST_Libcxx; return ToolChain::CST_Libstdcxx; } unsigned FreeBSD::GetDefaultDwarfVersion() const { if (getTriple().getOSMajorVersion() < 12) return 2; return 4; } void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/usr/include/c++/v1"); } void FreeBSD::addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/4.2", "", "", "", "", DriverArgs, CC1Args); } void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); bool Profiling = Args.hasArg(options::OPT_pg); switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); break; case ToolChain::CST_Libstdcxx: CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); break; } } void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } void FreeBSD::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); } Tool *FreeBSD::buildAssembler() const { return new tools::freebsd::Assembler(*this); } Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const { // FreeBSD uses SjLj exceptions on ARM oabi. switch (getTriple().getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::GNUEABI: case llvm::Triple::EABI: return llvm::ExceptionHandling::None; default: if (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::thumb) return llvm::ExceptionHandling::SjLj; return llvm::ExceptionHandling::None; } } bool FreeBSD::HasNativeLLVMSupport() const { return true; } bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; } bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } SanitizerMask FreeBSD::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; const bool IsMIPS64 = getTriple().isMIPS64(); SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Vptr; if (IsX86_64 || IsMIPS64) { Res |= SanitizerKind::Leak; Res |= SanitizerKind::Thread; } if (IsX86 || IsX86_64) { Res |= SanitizerKind::Function; Res |= SanitizerKind::SafeStack; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; } if (IsX86_64) Res |= SanitizerKind::Memory; return Res; } void FreeBSD::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, getTriple().getOSMajorVersion() >= 12)) CC1Args.push_back("-fno-use-init-array"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp index c8a7fce07ef1..23e7a70f2fa7 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1,3057 +1,3058 @@ //===--- Gnu.cpp - Gnu Tool and ToolChain Implementations -------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "Gnu.h" #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/RISCV.h" #include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "CommonArgs.h" #include "Linux.h" #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Path.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/VirtualFileSystem.h" #include using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; using tools::addMultilibFlag; using tools::addPathIfExists; static bool forwardToGCC(const Option &O) { // Don't forward inputs from the original command line. They are added from // InputInfoList. return O.getKind() != Option::InputClass && !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); } // Switch CPU names not recognized by GNU assembler to a close CPU that it does // recognize, instead of a lower march from being picked in the absence of a cpu // flag. static void normalizeCPUNamesForAssembler(const ArgList &Args, ArgStringList &CmdArgs) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { StringRef CPUArg(A->getValue()); if (CPUArg.equals_lower("krait")) CmdArgs.push_back("-mcpu=cortex-a15"); else if(CPUArg.equals_lower("kryo")) CmdArgs.push_back("-mcpu=cortex-a57"); else Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); } } void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; for (const auto &A : Args) { if (forwardToGCC(A->getOption())) { // It is unfortunate that we have to claim here, as this means // we will basically never report anything interesting for // platforms using a generic gcc, even if we are just using gcc // to get to the assembler. A->claim(); // Don't forward any -g arguments to assembly steps. if (isa(JA) && A->getOption().matches(options::OPT_g_Group)) continue; // Don't forward any -W arguments to assembly and link steps. if ((isa(JA) || isa(JA)) && A->getOption().matches(options::OPT_W_Group)) continue; // Don't forward -mno-unaligned-access since GCC doesn't understand // it and because it doesn't affect the assembly or link steps. if ((isa(JA) || isa(JA)) && (A->getOption().matches(options::OPT_munaligned_access) || A->getOption().matches(options::OPT_mno_unaligned_access))) continue; A->render(Args, CmdArgs); } } RenderExtraToolArgs(JA, CmdArgs); // If using a driver driver, force the arch. if (getToolChain().getTriple().isOSDarwin()) { CmdArgs.push_back("-arch"); CmdArgs.push_back( Args.MakeArgString(getToolChain().getDefaultUniversalArchName())); } // Try to force gcc to match the tool chain we want, if we recognize // the arch. // // FIXME: The triple class should directly provide the information we want // here. switch (getToolChain().getArch()) { default: break; case llvm::Triple::x86: case llvm::Triple::ppc: CmdArgs.push_back("-m32"); break; case llvm::Triple::x86_64: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: CmdArgs.push_back("-m64"); break; case llvm::Triple::sparcel: CmdArgs.push_back("-EL"); break; } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Unexpected output"); CmdArgs.push_back("-fsyntax-only"); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); // Only pass -x if gcc will understand it; otherwise hope gcc // understands the suffix correctly. The main use case this would go // wrong in is for linker inputs if they happened to have an odd // suffix; really the only way to get this to happen is a command // like '-x foobar a.c' which will treat a.c like a linker input. // // FIXME: For the linker case specifically, can we safely convert // inputs into '-Wl,' options? for (const auto &II : Inputs) { // Don't try to pass LLVM or AST inputs to a generic gcc. if (types::isLLVMIR(II.getType())) D.Diag(clang::diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); else if (II.getType() == types::TY_AST) D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); else if (II.getType() == types::TY_ModuleFile) D.Diag(diag::err_drv_no_module_support) << getToolChain().getTripleString(); if (types::canTypeBeUserSpecified(II.getType())) { CmdArgs.push_back("-x"); CmdArgs.push_back(types::getTypeName(II.getType())); } if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else { const Arg &A = II.getInputArg(); // Reverse translate some rewritten options. if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) { CmdArgs.push_back("-lstdc++"); continue; } // Don't render as input, we need gcc to do the translations. A.render(Args, CmdArgs); } } const std::string &customGCCName = D.getCCCGenericGCCName(); const char *GCCName; if (!customGCCName.empty()) GCCName = customGCCName.c_str(); else if (D.CCCIsCXX()) { GCCName = "g++"; } else GCCName = "gcc"; const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void tools::gcc::Preprocessor::RenderExtraToolArgs( const JobAction &JA, ArgStringList &CmdArgs) const { CmdArgs.push_back("-E"); } void tools::gcc::Compiler::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); switch (JA.getType()) { // If -flto, etc. are present then make sure not to force assembly output. case types::TY_LLVM_IR: case types::TY_LTO_IR: case types::TY_LLVM_BC: case types::TY_LTO_BC: CmdArgs.push_back("-c"); break; // We assume we've got an "integrated" assembler in that gcc will produce an // object file itself. case types::TY_Object: CmdArgs.push_back("-c"); break; case types::TY_PP_Asm: CmdArgs.push_back("-S"); break; case types::TY_Nothing: CmdArgs.push_back("-fsyntax-only"); break; default: D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); } } void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { // The types are (hopefully) good enough. } // On Arm the endianness of the output file is determined by the target and // can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and // '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a // normalized triple so we must handle the flag here. static bool isArmBigEndian(const llvm::Triple &Triple, const ArgList &Args) { bool IsBigEndian = false; switch (Triple.getArch()) { case llvm::Triple::armeb: case llvm::Triple::thumbeb: IsBigEndian = true; LLVM_FALLTHROUGH; case llvm::Triple::arm: case llvm::Triple::thumb: if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, options::OPT_mbig_endian)) IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian); break; default: break; } return IsBigEndian; } static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { switch (T.getArch()) { case llvm::Triple::x86: if (T.isOSIAMCU()) return "elf_iamcu"; return "elf_i386"; case llvm::Triple::aarch64: return "aarch64linux"; case llvm::Triple::aarch64_be: return "aarch64linuxb"; case llvm::Triple::arm: case llvm::Triple::thumb: case llvm::Triple::armeb: case llvm::Triple::thumbeb: return isArmBigEndian(T, Args) ? "armelfb_linux_eabi" : "armelf_linux_eabi"; case llvm::Triple::ppc: return "elf32ppclinux"; case llvm::Triple::ppc64: return "elf64ppc"; case llvm::Triple::ppc64le: return "elf64lppc"; case llvm::Triple::riscv32: return "elf32lriscv"; case llvm::Triple::riscv64: return "elf64lriscv"; case llvm::Triple::sparc: case llvm::Triple::sparcel: return "elf32_sparc"; case llvm::Triple::sparcv9: return "elf64_sparc"; case llvm::Triple::mips: return "elf32btsmip"; case llvm::Triple::mipsel: return "elf32ltsmip"; case llvm::Triple::mips64: if (tools::mips::hasMipsAbiArg(Args, "n32") || T.getEnvironment() == llvm::Triple::GNUABIN32) return "elf32btsmipn32"; return "elf64btsmip"; case llvm::Triple::mips64el: if (tools::mips::hasMipsAbiArg(Args, "n32") || T.getEnvironment() == llvm::Triple::GNUABIN32) return "elf32ltsmipn32"; return "elf64ltsmip"; case llvm::Triple::systemz: return "elf64_s390"; case llvm::Triple::x86_64: if (T.getEnvironment() == llvm::Triple::GNUX32) return "elf32_x86_64"; return "elf_x86_64"; case llvm::Triple::ve: return "elf64ve"; default: return nullptr; } } static bool getPIE(const ArgList &Args, const ToolChain &TC) { if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_r) || Args.hasArg(options::OPT_static_pie)) return false; Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, options::OPT_nopie); if (!A) return TC.isPIEDefault(); return A->getOption().matches(options::OPT_pie); } static bool getStaticPIE(const ArgList &Args, const ToolChain &TC) { bool HasStaticPIE = Args.hasArg(options::OPT_static_pie); // -no-pie is an alias for -nopie. So, handling -nopie takes care of // -no-pie as well. if (HasStaticPIE && Args.hasArg(options::OPT_nopie)) { const Driver &D = TC.getDriver(); const llvm::opt::OptTable &Opts = D.getOpts(); const char *StaticPIEName = Opts.getOptionName(options::OPT_static_pie); const char *NoPIEName = Opts.getOptionName(options::OPT_nopie); D.Diag(diag::err_drv_cannot_mix_options) << StaticPIEName << NoPIEName; } return HasStaticPIE; } static bool getStatic(const ArgList &Args) { return Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_static_pie); } void tools::gnutools::StaticLibTool::ConstructJob( Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); // Silence warnings when linking C code with a C++ '-stdlib' argument. Args.ClaimAllArgs(options::OPT_stdlib_EQ); // GNU ar tool command "ar ". ArgStringList CmdArgs; // Create and insert file members with a deterministic index. CmdArgs.push_back("rcsD"); CmdArgs.push_back(Output.getFilename()); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); // Delete old output archive file if it already exists before generating a new // archive file. auto OutputFileName = Output.getFilename(); if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) { if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) { D.Diag(diag::err_drv_unable_to_remove_file) << EC.message(); return; } } const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath()); C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { // FIXME: The Linker class constructor takes a ToolChain and not a // Generic_ELF, so the static_cast might return a reference to a invalid // instance (see PR45061). Ideally, the Linker constructor needs to take a // Generic_ELF instead. const toolchains::Generic_ELF &ToolChain = static_cast(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool isAndroid = ToolChain.getTriple().isAndroid(); const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); const bool IsVE = ToolChain.getTriple().isVE(); const bool IsPIE = getPIE(Args, ToolChain); const bool IsStaticPIE = getStaticPIE(Args, ToolChain); const bool IsStatic = getStatic(Args); const bool HasCRTBeginEndFiles = ToolChain.getTriple().hasEnvironment() || (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (IsPIE) CmdArgs.push_back("-pie"); if (IsStaticPIE) { CmdArgs.push_back("-static"); CmdArgs.push_back("-pie"); CmdArgs.push_back("--no-dynamic-linker"); CmdArgs.push_back("-z"); CmdArgs.push_back("text"); } if (ToolChain.isNoExecStackDefault()) { CmdArgs.push_back("-z"); CmdArgs.push_back("noexecstack"); } if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); if (Triple.isARM() || Triple.isThumb() || Triple.isAArch64()) { bool IsBigEndian = isArmBigEndian(Triple, Args); if (IsBigEndian) arm::appendBE8LinkFlag(Args, CmdArgs, Triple); IsBigEndian = IsBigEndian || Arch == llvm::Triple::aarch64_be; CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL"); } // Most Android ARM64 targets should enable the linker fix for erratum // 843419. Only non-Cortex-A53 devices are allowed to skip this flag. if (Arch == llvm::Triple::aarch64 && isAndroid) { std::string CPU = getCPUName(Args, Triple); if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") CmdArgs.push_back("--fix-cortex-a53-843419"); } // Android does not allow shared text relocations. Emit a warning if the // user's code contains any. if (isAndroid) CmdArgs.push_back("--warn-shared-textrel"); ToolChain.addExtraOpts(CmdArgs); CmdArgs.push_back("--eh-frame-hdr"); if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) { CmdArgs.push_back("-m"); CmdArgs.push_back(LDMOption); } else { D.Diag(diag::err_target_unknown_triple) << Triple.str(); return; } if (IsStatic) { if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb) CmdArgs.push_back("-Bstatic"); else CmdArgs.push_back("-static"); } else if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } if (!IsStatic) { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back(Args.MakeArgString(Twine(D.DyldPrefix) + ToolChain.getDynamicLinker(Args))); } } CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!isAndroid && !IsIAMCU) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) crt1 = "gcrt1.o"; else if (IsPIE) crt1 = "Scrt1.o"; else if (IsStaticPIE) crt1 = "rcrt1.o"; else crt1 = "crt1.o"; } if (crt1) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); } if (IsVE) { CmdArgs.push_back("-z"); CmdArgs.push_back("max-page-size=0x4000000"); } if (IsIAMCU) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); else if (HasCRTBeginEndFiles) { std::string P; if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT && !isAndroid) { std::string crtbegin = ToolChain.getCompilerRT(Args, "crtbegin", ToolChain::FT_Object); if (ToolChain.getVFS().exists(crtbegin)) P = crtbegin; } if (P.empty()) { const char *crtbegin; if (IsStatic) crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; else if (Args.hasArg(options::OPT_shared)) crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; else if (IsPIE || IsStaticPIE) crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; else crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; P = ToolChain.GetFilePath(crtbegin); } CmdArgs.push_back(Args.MakeArgString(P)); } // Add crtfastmath.o if available and fast math is enabled. ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs); } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_u); ToolChain.AddFilePathLibArgs(Args, CmdArgs); if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); } if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); + addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (OnlyLibstdcxxStatic) CmdArgs.push_back("-Bstatic"); ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (OnlyLibstdcxxStatic) CmdArgs.push_back("-Bdynamic"); } CmdArgs.push_back("-lm"); } // Silence warnings when linking C code with a C++ '-stdlib' argument. Args.ClaimAllArgs(options::OPT_stdlib_EQ); if (!Args.hasArg(options::OPT_nostdlib)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { if (IsStatic || IsStaticPIE) CmdArgs.push_back("--start-group"); if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); if (NeedsXRayDeps) linkXRayRuntimeDeps(ToolChain, CmdArgs); bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Args.hasArg(options::OPT_static); // FIXME: Only pass GompNeedsRT = true for platforms with libgomp that // require librt. Most modern Linux platforms do, but some may not. if (addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP, JA.isHostOffloading(Action::OFK_OpenMP), /* GompNeedsRT= */ true)) // OpenMP runtimes implies pthreads when using the GNU toolchain. // FIXME: Does this really make sense for all GNU toolchains? WantPthread = true; AddRunTimeLibs(ToolChain, D, CmdArgs, Args); if (WantPthread && !isAndroid) CmdArgs.push_back("-lpthread"); if (Args.hasArg(options::OPT_fsplit_stack)) CmdArgs.push_back("--wrap=pthread_create"); if (!Args.hasArg(options::OPT_nolibc)) CmdArgs.push_back("-lc"); // Add IAMCU specific libs, if needed. if (IsIAMCU) CmdArgs.push_back("-lgloss"); if (IsStatic || IsStaticPIE) CmdArgs.push_back("--end-group"); else AddRunTimeLibs(ToolChain, D, CmdArgs, Args); // Add IAMCU specific libs (outside the group), if needed. if (IsIAMCU) { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lsoftfp"); CmdArgs.push_back("--no-as-needed"); } } if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) { if (HasCRTBeginEndFiles) { std::string P; if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT && !isAndroid) { std::string crtend = ToolChain.getCompilerRT(Args, "crtend", ToolChain::FT_Object); if (ToolChain.getVFS().exists(crtend)) P = crtend; } if (P.empty()) { const char *crtend; if (Args.hasArg(options::OPT_shared)) crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; else if (IsPIE || IsStaticPIE) crtend = isAndroid ? "crtend_android.o" : "crtendS.o"; else crtend = isAndroid ? "crtend_android.o" : "crtend.o"; P = ToolChain.GetFilePath(crtend); } CmdArgs.push_back(Args.MakeArgString(P)); } if (!isAndroid) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } } Args.AddAllArgs(CmdArgs, options::OPT_T); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void tools::gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const auto &D = getToolChain().getDriver(); claimNoWarnArgs(Args); ArgStringList CmdArgs; llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; const char *DefaultAssembler = "as"; std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(getToolChain(), Args); if (const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ)) { if (A->getOption().getID() == options::OPT_gz) { CmdArgs.push_back("--compress-debug-sections"); } else { StringRef Value = A->getValue(); if (Value == "none" || Value == "zlib" || Value == "zlib-gnu") { CmdArgs.push_back( Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } } } if (getToolChain().isNoExecStackDefault()) { CmdArgs.push_back("--noexecstack"); } switch (getToolChain().getArch()) { default: break; // Add --32/--64 to make sure we get the format we want. // This is incomplete case llvm::Triple::x86: CmdArgs.push_back("--32"); break; case llvm::Triple::x86_64: if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32) CmdArgs.push_back("--x32"); else CmdArgs.push_back("--64"); break; case llvm::Triple::ppc: { CmdArgs.push_back("-a32"); CmdArgs.push_back("-mppc"); CmdArgs.push_back( ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; } case llvm::Triple::ppc64: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); CmdArgs.push_back( ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; } case llvm::Triple::ppc64le: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); CmdArgs.push_back("-mlittle-endian"); CmdArgs.push_back( ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; } case llvm::Triple::riscv32: case llvm::Triple::riscv64: { StringRef ABIName = riscv::getRISCVABI(Args, getToolChain().getTriple()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(ABIName.data()); StringRef MArchName = riscv::getRISCVArch(Args, getToolChain().getTriple()); CmdArgs.push_back("-march"); CmdArgs.push_back(MArchName.data()); break; } case llvm::Triple::sparc: case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); std::string CPU = getCPUName(Args, getToolChain().getTriple()); CmdArgs.push_back( sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); std::string CPU = getCPUName(Args, getToolChain().getTriple()); CmdArgs.push_back( sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: { const llvm::Triple &Triple2 = getToolChain().getTriple(); CmdArgs.push_back(isArmBigEndian(Triple2, Args) ? "-EB" : "-EL"); switch (Triple2.getSubArch()) { case llvm::Triple::ARMSubArch_v7: CmdArgs.push_back("-mfpu=neon"); break; case llvm::Triple::ARMSubArch_v8: CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8"); break; default: break; } switch (arm::getARMFloatABI(getToolChain(), Args)) { case arm::FloatABI::Invalid: llvm_unreachable("must have an ABI!"); case arm::FloatABI::Soft: CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=soft")); break; case arm::FloatABI::SoftFP: CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=softfp")); break; case arm::FloatABI::Hard: CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=hard")); break; } Args.AddLastArg(CmdArgs, options::OPT_march_EQ); normalizeCPUNamesForAssembler(Args, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); break; } case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: { CmdArgs.push_back( getToolChain().getArch() == llvm::Triple::aarch64_be ? "-EB" : "-EL"); Args.AddLastArg(CmdArgs, options::OPT_march_EQ); normalizeCPUNamesForAssembler(Args, CmdArgs); break; } case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); ABIName = mips::getGnuCompatibleMipsABIName(ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(ABIName.data()); // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE, // or -mshared (not implemented) is in effect. if (RelocationModel == llvm::Reloc::Static) CmdArgs.push_back("-mno-shared"); // LLVM doesn't support -mplt yet and acts as if it is always given. // However, -mplt has no effect with the N64 ABI. if (ABIName != "64" && !Args.hasArg(options::OPT_mno_abicalls)) CmdArgs.push_back("-call_nonpic"); if (getToolChain().getTriple().isLittleEndian()) CmdArgs.push_back("-EL"); else CmdArgs.push_back("-EB"); if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { if (StringRef(A->getValue()) == "2008") CmdArgs.push_back(Args.MakeArgString("-mnan=2008")); } // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default. if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, options::OPT_mfp64)) { A->claim(); A->render(Args, CmdArgs); } else if (mips::shouldUseFPXX( Args, getToolChain().getTriple(), CPUName, ABIName, mips::getMipsFloatABI(getToolChain().getDriver(), Args, getToolChain().getTriple()))) CmdArgs.push_back("-mfpxx"); // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of // -mno-mips16 is actually -no-mips16. if (Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16)) { if (A->getOption().matches(options::OPT_mips16)) { A->claim(); A->render(Args, CmdArgs); } else { A->claim(); CmdArgs.push_back("-no-mips16"); } } Args.AddLastArg(CmdArgs, options::OPT_mmicromips, options::OPT_mno_micromips); Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp); Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2); if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) { // Do not use AddLastArg because not all versions of MIPS assembler // support -mmsa / -mno-msa options. if (A->getOption().matches(options::OPT_mmsa)) CmdArgs.push_back(Args.MakeArgString("-mmsa")); } Args.AddLastArg(CmdArgs, options::OPT_mhard_float, options::OPT_msoft_float); Args.AddLastArg(CmdArgs, options::OPT_mdouble_float, options::OPT_msingle_float); Args.AddLastArg(CmdArgs, options::OPT_modd_spreg, options::OPT_mno_odd_spreg); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } case llvm::Triple::systemz: { // Always pass an -march option, since our default of z10 is later // than the GNU assembler's default. std::string CPUName = systemz::getSystemZTargetCPU(Args); CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); break; } case llvm::Triple::ve: DefaultAssembler = "nas"; } for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fdebug_prefix_map_EQ)) { StringRef Map = A->getValue(); if (Map.find('=') == StringRef::npos) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else { CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map")); CmdArgs.push_back(Args.MakeArgString(Map)); } A->claim(); } Args.AddAllArgs(CmdArgs, options::OPT_I); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(DefaultAssembler)); C.addCommand(std::make_unique( JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); // Handle the debug info splitting at object creation time if we're // creating an object. // TODO: Currently only works on linux with newer objcopy. if (Args.hasArg(options::OPT_gsplit_dwarf) && getToolChain().getTriple().isOSLinux()) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDebugName(Args, Inputs[0], Output)); } namespace { // Filter to remove Multilibs that don't exist as a suffix to Path class FilterNonExistent { StringRef Base, File; llvm::vfs::FileSystem &VFS; public: FilterNonExistent(StringRef Base, StringRef File, llvm::vfs::FileSystem &VFS) : Base(Base), File(File), VFS(VFS) {} bool operator()(const Multilib &M) { return !VFS.exists(Base + M.gccSuffix() + File); } }; } // end anonymous namespace static bool isSoftFloatABI(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ); if (!A) return false; return A->getOption().matches(options::OPT_msoft_float) || (A->getOption().matches(options::OPT_mfloat_abi_EQ) && A->getValue() == StringRef("soft")); } static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb; } static bool isMipsEL(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el; } static bool isMips16(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16); return A && A->getOption().matches(options::OPT_mips16); } static bool isMicroMips(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); return A && A->getOption().matches(options::OPT_mmicromips); } static bool isMSP430(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::msp430; } static Multilib makeMultilib(StringRef commonSuffix) { return Multilib(commonSuffix, commonSuffix, commonSuffix); } static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // Check for Code Sourcery toolchain multilibs MultilibSet CSMipsMultilibs; { auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16"); auto MArchMicroMips = makeMultilib("/micromips").flag("+m32").flag("+mmicromips"); auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips"); auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float"); auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); auto DefaultFloat = makeMultilib("").flag("-msoft-float").flag("-mnan=2008"); auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); // Note that this one's osSuffix is "" auto MAbi64 = makeMultilib("") .gccSuffix("/64") .includeSuffix("/64") .flag("+mabi=n64") .flag("-mabi=n32") .flag("-m32"); CSMipsMultilibs = MultilibSet() .Either(MArchMips16, MArchMicroMips, MArchDefault) .Maybe(UCLibc) .Either(SoftFloat, Nan2008, DefaultFloat) .FilterOut("/micromips/nan2008") .FilterOut("/mips16/nan2008") .Either(BigEndian, LittleEndian) .Maybe(MAbi64) .FilterOut("/mips16.*/64") .FilterOut("/micromips.*/64") .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector Dirs({"/include"}); if (StringRef(M.includeSuffix()).startswith("/uclibc")) Dirs.push_back( "/../../../../mips-linux-gnu/libc/uclibc/usr/include"); else Dirs.push_back("/../../../../mips-linux-gnu/libc/usr/include"); return Dirs; }); } MultilibSet DebianMipsMultilibs; { Multilib MAbiN32 = Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32"); Multilib M64 = Multilib() .gccSuffix("/64") .includeSuffix("/64") .flag("+m64") .flag("-m32") .flag("-mabi=n32"); Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32"); DebianMipsMultilibs = MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); } // Sort candidates. Toolchain that best meets the directories tree goes first. // Then select the first toolchains matches command line flags. MultilibSet *Candidates[] = {&CSMipsMultilibs, &DebianMipsMultilibs}; if (CSMipsMultilibs.size() < DebianMipsMultilibs.size()) std::iter_swap(Candidates, Candidates + 1); for (const MultilibSet *Candidate : Candidates) { if (Candidate->select(Flags, Result.SelectedMultilib)) { if (Candidate == &DebianMipsMultilibs) Result.BiarchSibling = Multilib(); Result.Multilibs = *Candidate; return true; } } return false; } static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path, const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { MultilibSet AndroidMipsMultilibs = MultilibSet() .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) .FilterOut(NonExistent); MultilibSet AndroidMipselMultilibs = MultilibSet() .Either(Multilib().flag("+march=mips32"), Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) .FilterOut(NonExistent); MultilibSet AndroidMips64elMultilibs = MultilibSet() .Either( Multilib().flag("+march=mips64r6"), Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"), Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) .FilterOut(NonExistent); MultilibSet *MS = &AndroidMipsMultilibs; if (VFS.exists(Path + "/mips-r6")) MS = &AndroidMipselMultilibs; else if (VFS.exists(Path + "/32")) MS = &AndroidMips64elMultilibs; if (MS->select(Flags, Result.SelectedMultilib)) { Result.Multilibs = *MS; return true; } return false; } static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // Musl toolchain multilibs MultilibSet MuslMipsMultilibs; { auto MArchMipsR2 = makeMultilib("") .osSuffix("/mips-r2-hard-musl") .flag("+EB") .flag("-EL") .flag("+march=mips32r2"); auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl") .flag("-EB") .flag("+EL") .flag("+march=mips32r2"); MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2); // Specify the callback that computes the include directories. MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) { return std::vector( {"/../sysroot" + M.osSuffix() + "/usr/include"}); }); } if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) { Result.Multilibs = MuslMipsMultilibs; return true; } return false; } static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // CodeScape MTI toolchain v1.2 and early. MultilibSet MtiMipsMultilibsV1; { auto MArchMips32 = makeMultilib("/mips32") .flag("+m32") .flag("-m64") .flag("-mmicromips") .flag("+march=mips32"); auto MArchMicroMips = makeMultilib("/micromips") .flag("+m32") .flag("-m64") .flag("+mmicromips"); auto MArchMips64r2 = makeMultilib("/mips64r2") .flag("-m32") .flag("+m64") .flag("+march=mips64r2"); auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag( "-march=mips64r2"); auto MArchDefault = makeMultilib("") .flag("+m32") .flag("-m64") .flag("-mmicromips") .flag("+march=mips32r2"); auto Mips16 = makeMultilib("/mips16").flag("+mips16"); auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); auto MAbi64 = makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); auto SoftFloat = makeMultilib("/sof").flag("+msoft-float"); auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); MtiMipsMultilibsV1 = MultilibSet() .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, MArchDefault) .Maybe(UCLibc) .Maybe(Mips16) .FilterOut("/mips64/mips16") .FilterOut("/mips64r2/mips16") .FilterOut("/micromips/mips16") .Maybe(MAbi64) .FilterOut("/micromips/64") .FilterOut("/mips32/64") .FilterOut("^/64") .FilterOut("/mips16/64") .Either(BigEndian, LittleEndian) .Maybe(SoftFloat) .Maybe(Nan2008) .FilterOut(".*sof/nan2008") .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector Dirs({"/include"}); if (StringRef(M.includeSuffix()).startswith("/uclibc")) Dirs.push_back("/../../../../sysroot/uclibc/usr/include"); else Dirs.push_back("/../../../../sysroot/usr/include"); return Dirs; }); } // CodeScape IMG toolchain starting from v1.3. MultilibSet MtiMipsMultilibsV2; { auto BeHard = makeMultilib("/mips-r2-hard") .flag("+EB") .flag("-msoft-float") .flag("-mnan=2008") .flag("-muclibc"); auto BeSoft = makeMultilib("/mips-r2-soft") .flag("+EB") .flag("+msoft-float") .flag("-mnan=2008"); auto ElHard = makeMultilib("/mipsel-r2-hard") .flag("+EL") .flag("-msoft-float") .flag("-mnan=2008") .flag("-muclibc"); auto ElSoft = makeMultilib("/mipsel-r2-soft") .flag("+EL") .flag("+msoft-float") .flag("-mnan=2008") .flag("-mmicromips"); auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008") .flag("+EB") .flag("-msoft-float") .flag("+mnan=2008") .flag("-muclibc"); auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008") .flag("+EL") .flag("-msoft-float") .flag("+mnan=2008") .flag("-muclibc") .flag("-mmicromips"); auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc") .flag("+EB") .flag("-msoft-float") .flag("+mnan=2008") .flag("+muclibc"); auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc") .flag("+EL") .flag("-msoft-float") .flag("+mnan=2008") .flag("+muclibc"); auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc") .flag("+EB") .flag("-msoft-float") .flag("-mnan=2008") .flag("+muclibc"); auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc") .flag("+EL") .flag("-msoft-float") .flag("-mnan=2008") .flag("+muclibc"); auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008") .flag("+EL") .flag("-msoft-float") .flag("+mnan=2008") .flag("+mmicromips"); auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft") .flag("+EL") .flag("+msoft-float") .flag("-mnan=2008") .flag("+mmicromips"); auto O32 = makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); auto N32 = makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); auto N64 = makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); MtiMipsMultilibsV2 = MultilibSet() .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan, BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc, ElHardUclibc, ElMicroHardNan, ElMicroSoft}) .Either(O32, N32, N64) .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector({"/../../../../sysroot" + M.includeSuffix() + "/../usr/include"}); }) .setFilePathsCallback([](const Multilib &M) { return std::vector( {"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()}); }); } for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { if (Candidate->select(Flags, Result.SelectedMultilib)) { Result.Multilibs = *Candidate; return true; } } return false; } static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // CodeScape IMG toolchain v1.2 and early. MultilibSet ImgMultilibsV1; { auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32"); auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); auto MAbi64 = makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); ImgMultilibsV1 = MultilibSet() .Maybe(Mips64r6) .Maybe(MAbi64) .Maybe(LittleEndian) .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector( {"/include", "/../../../../sysroot/usr/include"}); }); } // CodeScape IMG toolchain starting from v1.3. MultilibSet ImgMultilibsV2; { auto BeHard = makeMultilib("/mips-r6-hard") .flag("+EB") .flag("-msoft-float") .flag("-mmicromips"); auto BeSoft = makeMultilib("/mips-r6-soft") .flag("+EB") .flag("+msoft-float") .flag("-mmicromips"); auto ElHard = makeMultilib("/mipsel-r6-hard") .flag("+EL") .flag("-msoft-float") .flag("-mmicromips"); auto ElSoft = makeMultilib("/mipsel-r6-soft") .flag("+EL") .flag("+msoft-float") .flag("-mmicromips"); auto BeMicroHard = makeMultilib("/micromips-r6-hard") .flag("+EB") .flag("-msoft-float") .flag("+mmicromips"); auto BeMicroSoft = makeMultilib("/micromips-r6-soft") .flag("+EB") .flag("+msoft-float") .flag("+mmicromips"); auto ElMicroHard = makeMultilib("/micromipsel-r6-hard") .flag("+EL") .flag("-msoft-float") .flag("+mmicromips"); auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft") .flag("+EL") .flag("+msoft-float") .flag("+mmicromips"); auto O32 = makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); auto N32 = makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); auto N64 = makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); ImgMultilibsV2 = MultilibSet() .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft, ElMicroHard, ElMicroSoft}) .Either(O32, N32, N64) .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector({"/../../../../sysroot" + M.includeSuffix() + "/../usr/include"}); }) .setFilePathsCallback([](const Multilib &M) { return std::vector( {"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()}); }); } for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) { if (Candidate->select(Flags, Result.SelectedMultilib)) { Result.Multilibs = *Candidate; return true; } } return false; } bool clang::driver::findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); StringRef CPUName; StringRef ABIName; tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName); llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); Multilib::flags_list Flags; addMultilibFlag(TargetTriple.isMIPS32(), "m32", Flags); addMultilibFlag(TargetTriple.isMIPS64(), "m64", Flags); addMultilibFlag(isMips16(Args), "mips16", Flags); addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || CPUName == "mips32r5" || CPUName == "p5600", "march=mips32r2", Flags); addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || CPUName == "mips64r5" || CPUName == "octeon" || CPUName == "octeon+", "march=mips64r2", Flags); addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags); addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", Flags); addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags); addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags); addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); if (TargetTriple.isAndroid()) return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent, Result); if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) return findMipsMuslMultilibs(Flags, NonExistent, Result); if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && TargetTriple.isGNUEnvironment()) return findMipsMtiMultilibs(Flags, NonExistent, Result); if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && TargetTriple.isGNUEnvironment()) return findMipsImgMultilibs(Flags, NonExistent, Result); if (findMipsCsMultilibs(Flags, NonExistent, Result)) return true; // Fallback to the regular toolchain-tree structure. Multilib Default; Result.Multilibs.push_back(Default); Result.Multilibs.FilterOut(NonExistent); if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) { Result.BiarchSibling = Multilib(); return true; } return false; } static void findAndroidArmMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb. FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); Multilib ArmV7Multilib = makeMultilib("/armv7-a") .flag("+march=armv7-a") .flag("-mthumb"); Multilib ThumbMultilib = makeMultilib("/thumb") .flag("-march=armv7-a") .flag("+mthumb"); Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb") .flag("+march=armv7-a") .flag("+mthumb"); Multilib DefaultMultilib = makeMultilib("") .flag("-march=armv7-a") .flag("-mthumb"); MultilibSet AndroidArmMultilibs = MultilibSet() .Either(ThumbMultilib, ArmV7Multilib, ArmV7ThumbMultilib, DefaultMultilib) .FilterOut(NonExistent); Multilib::flags_list Flags; llvm::StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ); bool IsArmArch = TargetTriple.getArch() == llvm::Triple::arm; bool IsThumbArch = TargetTriple.getArch() == llvm::Triple::thumb; bool IsV7SubArch = TargetTriple.getSubArch() == llvm::Triple::ARMSubArch_v7; bool IsThumbMode = IsThumbArch || Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, false) || (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::ISAKind::THUMB); bool IsArmV7Mode = (IsArmArch || IsThumbArch) && (llvm::ARM::parseArchVersion(Arch) == 7 || (IsArmArch && Arch == "" && IsV7SubArch)); addMultilibFlag(IsArmV7Mode, "march=armv7-a", Flags); addMultilibFlag(IsThumbMode, "mthumb", Flags); if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib)) Result.Multilibs = AndroidArmMultilibs; } static bool findMSP430Multilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); Multilib MSP430Multilib = makeMultilib("/430"); // FIXME: when clang starts to support msp430x ISA additional logic // to select between multilib must be implemented // Multilib MSP430xMultilib = makeMultilib("/large"); Result.Multilibs.push_back(MSP430Multilib); Result.Multilibs.FilterOut(NonExistent); Multilib::flags_list Flags; if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) return true; return false; } static void findRISCVBareMetalMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); struct RiscvMultilib { StringRef march; StringRef mabi; }; // currently only support the set of multilibs like riscv-gnu-toolchain does. // TODO: support MULTILIB_REUSE constexpr RiscvMultilib RISCVMultilibSet[] = { {"rv32i", "ilp32"}, {"rv32im", "ilp32"}, {"rv32iac", "ilp32"}, {"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"}, {"rv64imafdc", "lp64d"}}; std::vector Ms; for (auto Element : RISCVMultilibSet) { // multilib path rule is ${march}/${mabi} Ms.emplace_back( makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str()) .flag(Twine("+march=", Element.march).str()) .flag(Twine("+mabi=", Element.mabi).str())); } MultilibSet RISCVMultilibs = MultilibSet() .Either(ArrayRef(Ms)) .FilterOut(NonExistent) .setFilePathsCallback([](const Multilib &M) { return std::vector( {M.gccSuffix(), "/../../../../riscv64-unknown-elf/lib" + M.gccSuffix(), "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()}); }); Multilib::flags_list Flags; llvm::StringSet<> Added_ABIs; StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); StringRef MArch = tools::riscv::getRISCVArch(Args, TargetTriple); for (auto Element : RISCVMultilibSet) { addMultilibFlag(MArch == Element.march, Twine("march=", Element.march).str().c_str(), Flags); if (!Added_ABIs.count(Element.mabi)) { Added_ABIs.insert(Element.mabi); addMultilibFlag(ABIName == Element.mabi, Twine("mabi=", Element.mabi).str().c_str(), Flags); } } if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) Result.Multilibs = RISCVMultilibs; } static void findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { if (TargetTriple.getOS() == llvm::Triple::UnknownOS) return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result); FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32"); Multilib Ilp32f = makeMultilib("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f"); Multilib Ilp32d = makeMultilib("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d"); Multilib Lp64 = makeMultilib("lib64/lp64").flag("+m64").flag("+mabi=lp64"); Multilib Lp64f = makeMultilib("lib64/lp64f").flag("+m64").flag("+mabi=lp64f"); Multilib Lp64d = makeMultilib("lib64/lp64d").flag("+m64").flag("+mabi=lp64d"); MultilibSet RISCVMultilibs = MultilibSet() .Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d}) .FilterOut(NonExistent); Multilib::flags_list Flags; bool IsRV64 = TargetTriple.getArch() == llvm::Triple::riscv64; StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); addMultilibFlag(!IsRV64, "m32", Flags); addMultilibFlag(IsRV64, "m64", Flags); addMultilibFlag(ABIName == "ilp32", "mabi=ilp32", Flags); addMultilibFlag(ABIName == "ilp32f", "mabi=ilp32f", Flags); addMultilibFlag(ABIName == "ilp32d", "mabi=ilp32d", Flags); addMultilibFlag(ABIName == "lp64", "mabi=lp64", Flags); addMultilibFlag(ABIName == "lp64f", "mabi=lp64f", Flags); addMultilibFlag(ABIName == "lp64d", "mabi=lp64d", Flags); if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) Result.Multilibs = RISCVMultilibs; } static bool findBiarchMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, bool NeedsBiarchSuffix, DetectedMultilibs &Result) { Multilib Default; // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit // libs in a subdirectory named 64. The simple logic we follow is that // *if* there is a subdirectory of the right name with crtbegin.o in it, // we use that. If not, and if not a biarch triple alias, we look for // crtbegin.o without the subdirectory. StringRef Suff64 = "/64"; // Solaris uses platform-specific suffixes instead of /64. if (TargetTriple.getOS() == llvm::Triple::Solaris) { switch (TargetTriple.getArch()) { case llvm::Triple::x86: case llvm::Triple::x86_64: Suff64 = "/amd64"; break; case llvm::Triple::sparc: case llvm::Triple::sparcv9: Suff64 = "/sparcv9"; break; default: break; } } Multilib Alt64 = Multilib() .gccSuffix(Suff64) .includeSuffix(Suff64) .flag("-m32") .flag("+m64") .flag("-mx32"); Multilib Alt32 = Multilib() .gccSuffix("/32") .includeSuffix("/32") .flag("+m32") .flag("-m64") .flag("-mx32"); Multilib Altx32 = Multilib() .gccSuffix("/x32") .includeSuffix("/x32") .flag("-m32") .flag("-m64") .flag("+mx32"); // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a. FilterNonExistent NonExistent( Path, TargetTriple.isOSIAMCU() ? "/libgcc.a" : "/crtbegin.o", D.getVFS()); // Determine default multilib from: 32, 64, x32 // Also handle cases such as 64 on 32, 32 on 64, etc. enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN; const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32; if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) Want = WANT64; else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32)) Want = WANT64; else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64)) Want = WANT32; else { if (TargetTriple.isArch32Bit()) Want = NeedsBiarchSuffix ? WANT64 : WANT32; else if (IsX32) Want = NeedsBiarchSuffix ? WANT64 : WANTX32; else Want = NeedsBiarchSuffix ? WANT32 : WANT64; } if (Want == WANT32) Default.flag("+m32").flag("-m64").flag("-mx32"); else if (Want == WANT64) Default.flag("-m32").flag("+m64").flag("-mx32"); else if (Want == WANTX32) Default.flag("-m32").flag("-m64").flag("+mx32"); else return false; Result.Multilibs.push_back(Default); Result.Multilibs.push_back(Alt64); Result.Multilibs.push_back(Alt32); Result.Multilibs.push_back(Altx32); Result.Multilibs.FilterOut(NonExistent); Multilib::flags_list Flags; addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags); addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags); if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) return false; if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 || Result.SelectedMultilib == Altx32) Result.BiarchSibling = Default; return true; } /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. /// Less-than for GCCVersion, implementing a Strict Weak Ordering. bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, StringRef RHSPatchSuffix) const { if (Major != RHSMajor) return Major < RHSMajor; if (Minor != RHSMinor) return Minor < RHSMinor; if (Patch != RHSPatch) { // Note that versions without a specified patch sort higher than those with // a patch. if (RHSPatch == -1) return true; if (Patch == -1) return false; // Otherwise just sort on the patch itself. return Patch < RHSPatch; } if (PatchSuffix != RHSPatchSuffix) { // Sort empty suffixes higher. if (RHSPatchSuffix.empty()) return true; if (PatchSuffix.empty()) return false; // Provide a lexicographic sort to make this a total ordering. return PatchSuffix < RHSPatchSuffix; } // The versions are equal. return false; } /// Parse a GCCVersion object out of a string of text. /// /// This is the primary means of forming GCCVersion objects. /*static*/ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; std::pair First = VersionText.split('.'); std::pair Second = First.second.split('.'); GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) return BadVersion; GoodVersion.MajorStr = First.first.str(); if (First.second.empty()) return GoodVersion; StringRef MinorStr = Second.first; if (Second.second.empty()) { if (size_t EndNumber = MinorStr.find_first_not_of("0123456789")) { GoodVersion.PatchSuffix = std::string(MinorStr.substr(EndNumber)); MinorStr = MinorStr.slice(0, EndNumber); } } if (MinorStr.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) return BadVersion; GoodVersion.MinorStr = MinorStr.str(); // First look for a number prefix and parse that if present. Otherwise just // stash the entire patch string in the suffix, and leave the number // unspecified. This covers versions strings such as: // 5 (handled above) // 4.4 // 4.4-patched // 4.4.0 // 4.4.x // 4.4.2-rc4 // 4.4.x-patched // And retains any patch number it finds. StringRef PatchText = Second.second; if (!PatchText.empty()) { if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { // Try to parse the number and any suffix. if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || GoodVersion.Patch < 0) return BadVersion; GoodVersion.PatchSuffix = std::string(PatchText.substr(EndNumber)); } } return GoodVersion; } static llvm::StringRef getGCCToolchainDir(const ArgList &Args, llvm::StringRef SysRoot) { const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain); if (A) return A->getValue(); // If we have a SysRoot, ignore GCC_INSTALL_PREFIX. // GCC_INSTALL_PREFIX specifies the gcc installation for the default // sysroot and is likely not valid with a different sysroot. if (!SysRoot.empty()) return ""; return GCC_INSTALL_PREFIX; } /// Initialize a GCCInstallationDetector from the driver. /// /// This performs all of the autodetection and sets up the various paths. /// Once constructed, a GCCInstallationDetector is essentially immutable. /// /// FIXME: We shouldn't need an explicit TargetTriple parameter here, and /// should instead pull the target out of the driver. This is currently /// necessary because the driver doesn't store the final version of the target /// triple. void Generic_GCC::GCCInstallationDetector::init( const llvm::Triple &TargetTriple, const ArgList &Args, ArrayRef ExtraTripleAliases) { llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); // The library directories which may contain GCC installations. SmallVector CandidateLibDirs, CandidateBiarchLibDirs; // The compatible GCC triples for this particular architecture. SmallVector CandidateTripleAliases; SmallVector CandidateBiarchTripleAliases; CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, CandidateTripleAliases, CandidateBiarchLibDirs, CandidateBiarchTripleAliases); // Compute the set of prefixes for our search. SmallVector Prefixes(D.PrefixDirs.begin(), D.PrefixDirs.end()); StringRef GCCToolchainDir = getGCCToolchainDir(Args, D.SysRoot); if (GCCToolchainDir != "") { if (GCCToolchainDir.back() == '/') GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the / Prefixes.push_back(std::string(GCCToolchainDir)); } else { // If we have a SysRoot, try that first. if (!D.SysRoot.empty()) { Prefixes.push_back(D.SysRoot); AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot); } // Then look for gcc installed alongside clang. Prefixes.push_back(D.InstalledDir + "/.."); // Next, look for prefix(es) that correspond to distribution-supplied gcc // installations. if (D.SysRoot.empty()) { // Typically /usr. AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot); } } // Try to respect gcc-config on Gentoo. However, do that only // if --gcc-toolchain is not provided or equal to the Gentoo install // in /usr. This avoids accidentally enforcing the system GCC version // when using a custom toolchain. if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") { SmallVector GentooTestTriples; // Try to match an exact triple as target triple first. // e.g. crossdev -S x86_64-gentoo-linux-gnu will install gcc libs for // x86_64-gentoo-linux-gnu. But "clang -target x86_64-gentoo-linux-gnu" // may pick the libraries for x86_64-pc-linux-gnu even when exact matching // triple x86_64-gentoo-linux-gnu is present. GentooTestTriples.push_back(TargetTriple.str()); // Check rest of triples. GentooTestTriples.append(ExtraTripleAliases.begin(), ExtraTripleAliases.end()); GentooTestTriples.append(CandidateTripleAliases.begin(), CandidateTripleAliases.end()); if (ScanGentooConfigs(TargetTriple, Args, GentooTestTriples, CandidateBiarchTripleAliases)) return; } // Loop over the various components which exist and select the best GCC // installation available. GCC installs are ranked by version number. Version = GCCVersion::Parse("0.0.0"); for (const std::string &Prefix : Prefixes) { if (!D.getVFS().exists(Prefix)) continue; for (StringRef Suffix : CandidateLibDirs) { const std::string LibDir = Prefix + Suffix.str(); if (!D.getVFS().exists(LibDir)) continue; // Try to match the exact target triple first. ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, TargetTriple.str()); // Try rest of possible triples. for (StringRef Candidate : ExtraTripleAliases) // Try these first. ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); for (StringRef Candidate : CandidateTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); } for (StringRef Suffix : CandidateBiarchLibDirs) { const std::string LibDir = Prefix + Suffix.str(); if (!D.getVFS().exists(LibDir)) continue; for (StringRef Candidate : CandidateBiarchTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, /*NeedsBiarchSuffix=*/ true); } } } void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { for (const auto &InstallPath : CandidateGCCInstallPaths) OS << "Found candidate GCC installation: " << InstallPath << "\n"; if (!GCCInstallPath.empty()) OS << "Selected GCC installation: " << GCCInstallPath << "\n"; for (const auto &Multilib : Multilibs) OS << "Candidate multilib: " << Multilib << "\n"; if (Multilibs.size() != 0 || !SelectedMultilib.isDefault()) OS << "Selected multilib: " << SelectedMultilib << "\n"; } bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { if (BiarchSibling.hasValue()) { M = BiarchSibling.getValue(); return true; } return false; } void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( const llvm::Triple &TargetTriple, SmallVectorImpl &Prefixes, StringRef SysRoot) { if (TargetTriple.getOS() == llvm::Triple::Solaris) { // Solaris is a special case. // The GCC installation is under // /usr/gcc/./lib/gcc//../ // so we need to find those /usr/gcc/*/lib/gcc libdirs and go with // /usr/gcc/ as a prefix. std::string PrefixDir = SysRoot.str() + "/usr/gcc"; std::error_code EC; for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->path()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); // Filter out obviously bad entries. if (CandidateVersion.Major == -1 || CandidateVersion.isOlderThan(4, 1, 1)) continue; std::string CandidatePrefix = PrefixDir + "/" + VersionText.str(); std::string CandidateLibPath = CandidatePrefix + "/lib/gcc"; if (!D.getVFS().exists(CandidateLibPath)) continue; Prefixes.push_back(CandidatePrefix); } return; } // Non-Solaris is much simpler - most systems just go with "/usr". if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux) { // Yet, still look for RHEL devtoolsets. Prefixes.push_back("/opt/rh/devtoolset-9/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-8/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-7/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); } Prefixes.push_back(SysRoot.str() + "/usr"); } /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, SmallVectorImpl &LibDirs, SmallVectorImpl &TripleAliases, SmallVectorImpl &BiarchLibDirs, SmallVectorImpl &BiarchTripleAliases) { // Declare a bunch of static data sets that we'll select between below. These // are specifically designed to always refer to string literals to avoid any // lifetime or initialization issues. static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux", "aarch64-suse-linux", "aarch64-linux-android"}; static const char *const AArch64beLibDirs[] = {"/lib"}; static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", "aarch64_be-linux-gnu"}; static const char *const ARMLibDirs[] = {"/lib"}; static const char *const ARMTriples[] = {"arm-linux-gnueabi", "arm-linux-androideabi"}; static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", "armv7hl-redhat-linux-gnueabi", "armv6hl-suse-linux-gnueabi", "armv7hl-suse-linux-gnueabi"}; static const char *const ARMebLibDirs[] = {"/lib"}; static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", "armeb-linux-androideabi"}; static const char *const ARMebHFTriples[] = { "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; static const char *const AVRLibDirs[] = {"/lib"}; static const char *const AVRTriples[] = {"avr"}; static const char *const X86_64LibDirs[] = {"/lib64", "/lib"}; static const char *const X86_64Triples[] = { "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux", "x86_64-unknown-linux", "x86_64-amazon-linux", "x86_64-linux-android"}; static const char *const X32LibDirs[] = {"/libx32"}; static const char *const X86LibDirs[] = {"/lib32", "/lib"}; static const char *const X86Triples[] = { "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", "i486-slackware-linux", "i686-montavista-linux", "i586-linux-gnu", "i686-linux-android", "i386-gnu", "i486-gnu", "i586-gnu", "i686-gnu"}; static const char *const MIPSLibDirs[] = {"/lib"}; static const char *const MIPSTriples[] = { "mips-linux-gnu", "mips-mti-linux", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6-linux-gnu"}; static const char *const MIPSELLibDirs[] = {"/lib"}; static const char *const MIPSELTriples[] = { "mipsel-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6el-linux-gnu", "mipsel-linux-android"}; static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64Triples[] = { "mips64-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64-linux-gnuabi64", "mipsisa64r6-linux-gnu", "mipsisa64r6-linux-gnuabi64"}; static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64el-linux-gnuabi64", "mipsisa64r6el-linux-gnu", "mipsisa64r6el-linux-gnuabi64", "mips64el-linux-android"}; static const char *const MIPSN32LibDirs[] = {"/lib32"}; static const char *const MIPSN32Triples[] = {"mips64-linux-gnuabin32", "mipsisa64r6-linux-gnuabin32"}; static const char *const MIPSN32ELLibDirs[] = {"/lib32"}; static const char *const MIPSN32ELTriples[] = { "mips64el-linux-gnuabin32", "mipsisa64r6el-linux-gnuabin32"}; static const char *const MSP430LibDirs[] = {"/lib"}; static const char *const MSP430Triples[] = {"msp430-elf"}; static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; static const char *const PPCTriples[] = { "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", // On 32-bit PowerPC systems running SUSE Linux, gcc is configured as a // 64-bit compiler which defaults to "-m32", hence "powerpc64-suse-linux". "powerpc64-suse-linux", "powerpc-montavista-linuxspe"}; static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; static const char *const PPC64Triples[] = { "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", "powerpc64-suse-linux", "ppc64-redhat-linux"}; static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"}; static const char *const PPC64LETriples[] = { "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; static const char *const RISCV32LibDirs[] = {"/lib32", "/lib"}; static const char *const RISCV32Triples[] = {"riscv32-unknown-linux-gnu", "riscv32-linux-gnu", "riscv32-unknown-elf"}; static const char *const RISCV64LibDirs[] = {"/lib64", "/lib"}; static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu", "riscv64-linux-gnu", "riscv64-unknown-elf", "riscv64-redhat-linux", "riscv64-suse-linux"}; static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", "sparcv8-linux-gnu"}; static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"}; static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu", "sparcv9-linux-gnu"}; static const char *const SystemZLibDirs[] = {"/lib64", "/lib"}; static const char *const SystemZTriples[] = { "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", "s390x-suse-linux", "s390x-redhat-linux"}; using std::begin; using std::end; if (TargetTriple.getOS() == llvm::Triple::Solaris) { static const char *const SolarisLibDirs[] = {"/lib"}; static const char *const SolarisSparcV8Triples[] = { "sparc-sun-solaris2.11", "sparc-sun-solaris2.12"}; static const char *const SolarisSparcV9Triples[] = { "sparcv9-sun-solaris2.11", "sparcv9-sun-solaris2.12"}; static const char *const SolarisX86Triples[] = {"i386-pc-solaris2.11", "i386-pc-solaris2.12"}; static const char *const SolarisX86_64Triples[] = {"x86_64-pc-solaris2.11", "x86_64-pc-solaris2.12"}; LibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); BiarchLibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); switch (TargetTriple.getArch()) { case llvm::Triple::x86: TripleAliases.append(begin(SolarisX86Triples), end(SolarisX86Triples)); BiarchTripleAliases.append(begin(SolarisX86_64Triples), end(SolarisX86_64Triples)); break; case llvm::Triple::x86_64: TripleAliases.append(begin(SolarisX86_64Triples), end(SolarisX86_64Triples)); BiarchTripleAliases.append(begin(SolarisX86Triples), end(SolarisX86Triples)); break; case llvm::Triple::sparc: TripleAliases.append(begin(SolarisSparcV8Triples), end(SolarisSparcV8Triples)); BiarchTripleAliases.append(begin(SolarisSparcV9Triples), end(SolarisSparcV9Triples)); break; case llvm::Triple::sparcv9: TripleAliases.append(begin(SolarisSparcV9Triples), end(SolarisSparcV9Triples)); BiarchTripleAliases.append(begin(SolarisSparcV8Triples), end(SolarisSparcV8Triples)); break; default: break; } return; } // Android targets should not use GNU/Linux tools or libraries. if (TargetTriple.isAndroid()) { static const char *const AArch64AndroidTriples[] = { "aarch64-linux-android"}; static const char *const ARMAndroidTriples[] = {"arm-linux-androideabi"}; static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; static const char *const MIPS64ELAndroidTriples[] = { "mips64el-linux-android"}; static const char *const X86AndroidTriples[] = {"i686-linux-android"}; static const char *const X86_64AndroidTriples[] = {"x86_64-linux-android"}; switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); TripleAliases.append(begin(AArch64AndroidTriples), end(AArch64AndroidTriples)); break; case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); TripleAliases.append(begin(ARMAndroidTriples), end(ARMAndroidTriples)); break; case llvm::Triple::mipsel: LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); TripleAliases.append(begin(MIPSELAndroidTriples), end(MIPSELAndroidTriples)); BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), end(MIPS64ELAndroidTriples)); break; case llvm::Triple::mips64el: LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); TripleAliases.append(begin(MIPS64ELAndroidTriples), end(MIPS64ELAndroidTriples)); BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); BiarchTripleAliases.append(begin(MIPSELAndroidTriples), end(MIPSELAndroidTriples)); break; case llvm::Triple::x86_64: LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); TripleAliases.append(begin(X86_64AndroidTriples), end(X86_64AndroidTriples)); BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); BiarchTripleAliases.append(begin(X86AndroidTriples), end(X86AndroidTriples)); break; case llvm::Triple::x86: LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); TripleAliases.append(begin(X86AndroidTriples), end(X86AndroidTriples)); BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); BiarchTripleAliases.append(begin(X86_64AndroidTriples), end(X86_64AndroidTriples)); break; default: break; } return; } switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); TripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); break; case llvm::Triple::aarch64_be: LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); break; case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); } else { TripleAliases.append(begin(ARMTriples), end(ARMTriples)); } break; case llvm::Triple::armeb: case llvm::Triple::thumbeb: LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); } else { TripleAliases.append(begin(ARMebTriples), end(ARMebTriples)); } break; case llvm::Triple::avr: LibDirs.append(begin(AVRLibDirs), end(AVRLibDirs)); TripleAliases.append(begin(AVRTriples), end(AVRTriples)); break; case llvm::Triple::x86_64: LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); TripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); // x32 is always available when x86_64 is available, so adding it as // secondary arch with x86_64 triples if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) { BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs)); BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); } else { BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); BiarchTripleAliases.append(begin(X86Triples), end(X86Triples)); } break; case llvm::Triple::x86: LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); // MCU toolchain is 32 bit only and its triple alias is TargetTriple // itself, which will be appended below. if (!TargetTriple.isOSIAMCU()) { TripleAliases.append(begin(X86Triples), end(X86Triples)); BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); } break; case llvm::Triple::mips: LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); BiarchLibDirs.append(begin(MIPSN32LibDirs), end(MIPSN32LibDirs)); BiarchTripleAliases.append(begin(MIPSN32Triples), end(MIPSN32Triples)); break; case llvm::Triple::mipsel: LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); BiarchLibDirs.append(begin(MIPSN32ELLibDirs), end(MIPSN32ELLibDirs)); BiarchTripleAliases.append(begin(MIPSN32ELTriples), end(MIPSN32ELTriples)); break; case llvm::Triple::mips64: LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); BiarchLibDirs.append(begin(MIPSN32LibDirs), end(MIPSN32LibDirs)); BiarchTripleAliases.append(begin(MIPSN32Triples), end(MIPSN32Triples)); break; case llvm::Triple::mips64el: LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); BiarchLibDirs.append(begin(MIPSN32ELLibDirs), end(MIPSN32ELLibDirs)); BiarchTripleAliases.append(begin(MIPSN32ELTriples), end(MIPSN32ELTriples)); BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); break; case llvm::Triple::msp430: LibDirs.append(begin(MSP430LibDirs), end(MSP430LibDirs)); TripleAliases.append(begin(MSP430Triples), end(MSP430Triples)); break; case llvm::Triple::ppc: LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); TripleAliases.append(begin(PPCTriples), end(PPCTriples)); BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); break; case llvm::Triple::ppc64: LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); TripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples)); break; case llvm::Triple::ppc64le: LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs)); TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); break; case llvm::Triple::riscv32: LibDirs.append(begin(RISCV32LibDirs), end(RISCV32LibDirs)); TripleAliases.append(begin(RISCV32Triples), end(RISCV32Triples)); BiarchLibDirs.append(begin(RISCV64LibDirs), end(RISCV64LibDirs)); BiarchTripleAliases.append(begin(RISCV64Triples), end(RISCV64Triples)); break; case llvm::Triple::riscv64: LibDirs.append(begin(RISCV64LibDirs), end(RISCV64LibDirs)); TripleAliases.append(begin(RISCV64Triples), end(RISCV64Triples)); BiarchLibDirs.append(begin(RISCV32LibDirs), end(RISCV32LibDirs)); BiarchTripleAliases.append(begin(RISCV32Triples), end(RISCV32Triples)); break; case llvm::Triple::sparc: case llvm::Triple::sparcel: LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); break; case llvm::Triple::sparcv9: LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); break; case llvm::Triple::systemz: LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs)); TripleAliases.append(begin(SystemZTriples), end(SystemZTriples)); break; default: // By default, just rely on the standard lib directories and the original // triple. break; } // Always append the drivers target triple to the end, in case it doesn't // match any of our aliases. TripleAliases.push_back(TargetTriple.str()); // Also include the multiarch variant if it's different. if (TargetTriple.str() != BiarchTriple.str()) BiarchTripleAliases.push_back(BiarchTriple.str()); } bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( const llvm::Triple &TargetTriple, const ArgList &Args, StringRef Path, bool NeedsBiarchSuffix) { llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); DetectedMultilibs Detected; // Android standalone toolchain could have multilibs for ARM and Thumb. // Debian mips multilibs behave more like the rest of the biarch ones, // so handle them there if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { // It should also work without multilibs in a simplified toolchain. findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); } else if (TargetTriple.isMIPS()) { if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) return false; } else if (TargetTriple.isRISCV()) { findRISCVMultilibs(D, TargetTriple, Path, Args, Detected); } else if (isMSP430(TargetArch)) { findMSP430Multilibs(D, TargetTriple, Path, Args, Detected); } else if (TargetArch == llvm::Triple::avr) { // AVR has no multilibs. } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, NeedsBiarchSuffix, Detected)) { return false; } Multilibs = Detected.Multilibs; SelectedMultilib = Detected.SelectedMultilib; BiarchSibling = Detected.BiarchSibling; return true; } void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( const llvm::Triple &TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix) { llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // Locations relative to the system lib directory where GCC's triple-specific // directories might reside. struct GCCLibSuffix { // Path from system lib directory to GCC triple-specific directory. std::string LibSuffix; // Path from GCC triple-specific directory back to system lib directory. // This is one '..' component per component in LibSuffix. StringRef ReversePath; // Whether this library suffix is relevant for the triple. bool Active; } Suffixes[] = { // This is the normal place. {"gcc/" + CandidateTriple.str(), "../..", true}, // Debian puts cross-compilers in gcc-cross. {"gcc-cross/" + CandidateTriple.str(), "../..", TargetTriple.getOS() != llvm::Triple::Solaris}, // The Freescale PPC SDK has the gcc libraries in // /usr/lib//x.y.z so have a look there as well. Only do // this on Freescale triples, though, since some systems put a *lot* of // files in that location, not just GCC installation data. {CandidateTriple.str(), "..", TargetTriple.getVendor() == llvm::Triple::Freescale || TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}, // Natively multiarch systems sometimes put the GCC triple-specific // directory within their multiarch lib directory, resulting in the // triple appearing twice. {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", TargetTriple.getOS() != llvm::Triple::Solaris}, // Deal with cases (on Ubuntu) where the system architecture could be i386 // but the GCC target architecture could be (say) i686. // FIXME: It may be worthwhile to generalize this and look for a second // triple. {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", (TargetArch == llvm::Triple::x86 && TargetTriple.getOS() != llvm::Triple::Solaris)}, {"i386-gnu/gcc/" + CandidateTriple.str(), "../../..", (TargetArch == llvm::Triple::x86 && TargetTriple.getOS() != llvm::Triple::Solaris)}}; for (auto &Suffix : Suffixes) { if (!Suffix.Active) continue; StringRef LibSuffix = Suffix.LibSuffix; std::error_code EC; for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->path()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); if (CandidateVersion.Major != -1) // Filter obviously bad entries. if (!CandidateGCCInstallPaths.insert(std::string(LI->path())).second) continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; if (CandidateVersion <= Version) continue; if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(), NeedsBiarchSuffix)) continue; Version = CandidateVersion; GCCTriple.setTriple(CandidateTriple); // FIXME: We hack together the directory name here instead of // using LI to ensure stable path separators across Windows and // Linux. GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str(); GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str(); IsValid = true; } } } bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( const llvm::Triple &TargetTriple, const ArgList &Args, const SmallVectorImpl &CandidateTriples, const SmallVectorImpl &CandidateBiarchTriples) { for (StringRef CandidateTriple : CandidateTriples) { if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) return true; } for (StringRef CandidateTriple : CandidateBiarchTriples) { if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) return true; } return false; } bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( const llvm::Triple &TargetTriple, const ArgList &Args, StringRef CandidateTriple, bool NeedsBiarchSuffix) { llvm::ErrorOr> File = D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" + CandidateTriple.str()); if (File) { SmallVector Lines; File.get()->getBuffer().split(Lines, "\n"); for (StringRef Line : Lines) { Line = Line.trim(); // CURRENT=triple-version if (!Line.consume_front("CURRENT=")) continue; // Process the config file pointed to by CURRENT. llvm::ErrorOr> ConfigFile = D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/" + Line.str()); std::pair ActiveVersion = Line.rsplit('-'); // List of paths to scan for libraries. SmallVector GentooScanPaths; // Scan the Config file to find installed GCC libraries path. // Typical content of the GCC config file: // LDPATH="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x:/usr/lib/gcc/ // (continued from previous line) x86_64-pc-linux-gnu/4.9.x/32" // MANPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/man" // INFOPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/info" // STDCXX_INCDIR="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x/include/g++-v4" // We are looking for the paths listed in LDPATH=... . if (ConfigFile) { SmallVector ConfigLines; ConfigFile.get()->getBuffer().split(ConfigLines, "\n"); for (StringRef ConfLine : ConfigLines) { ConfLine = ConfLine.trim(); if (ConfLine.consume_front("LDPATH=")) { // Drop '"' from front and back if present. ConfLine.consume_back("\""); ConfLine.consume_front("\""); // Get all paths sperated by ':' ConfLine.split(GentooScanPaths, ':', -1, /*AllowEmpty*/ false); } } } // Test the path based on the version in /etc/env.d/gcc/config-{tuple}. std::string basePath = "/usr/lib/gcc/" + ActiveVersion.first.str() + "/" + ActiveVersion.second.str(); GentooScanPaths.push_back(StringRef(basePath)); // Scan all paths for GCC libraries. for (const auto &GentooScanPath : GentooScanPaths) { std::string GentooPath = D.SysRoot + std::string(GentooScanPath); if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, NeedsBiarchSuffix)) continue; Version = GCCVersion::Parse(ActiveVersion.second); GCCInstallPath = GentooPath; GCCParentLibPath = GentooPath + std::string("/../../.."); GCCTriple.setTriple(ActiveVersion.first); IsValid = true; return true; } } } } return false; } Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), GCCInstallation(D), CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); } Generic_GCC::~Generic_GCC() {} Tool *Generic_GCC::getTool(Action::ActionClass AC) const { switch (AC) { case Action::PreprocessJobClass: if (!Preprocess) Preprocess.reset(new clang::driver::tools::gcc::Preprocessor(*this)); return Preprocess.get(); case Action::CompileJobClass: if (!Compile) Compile.reset(new tools::gcc::Compiler(*this)); return Compile.get(); default: return ToolChain::getTool(AC); } } Tool *Generic_GCC::buildAssembler() const { return new tools::gnutools::Assembler(*this); } Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); } void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { // Print the information about how we detected the GCC installation. GCCInstallation.print(OS); CudaInstallation.print(OS); RocmInstallation.print(OS); } bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const { return getArch() == llvm::Triple::x86_64; } bool Generic_GCC::isPICDefault() const { switch (getArch()) { case llvm::Triple::x86_64: return getTriple().isOSWindows(); case llvm::Triple::mips64: case llvm::Triple::mips64el: return true; default: return false; } } bool Generic_GCC::isPIEDefault() const { return false; } bool Generic_GCC::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); } bool Generic_GCC::IsIntegratedAssemblerDefault() const { switch (getTriple().getArch()) { case llvm::Triple::x86: case llvm::Triple::x86_64: case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::avr: case llvm::Triple::bpfel: case llvm::Triple::bpfeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: case llvm::Triple::riscv32: case llvm::Triple::riscv64: case llvm::Triple::systemz: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::msp430: return true; case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: if (getTriple().isOSFreeBSD() || getTriple().isOSOpenBSD() || getTriple().isOSSolaris()) return true; return false; default: return false; } } static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, const Multilib &Multilib, StringRef InstallPath, ToolChain::path_list &Paths) { if (const auto &PathsCallback = Multilibs.filePathsCallback()) for (const auto &Path : PathsCallback(Multilib)) addPathIfExists(D, InstallPath + Path, Paths); } void Generic_GCC::PushPPaths(ToolChain::path_list &PPaths) { // Cross-compiling binutils and GCC installations (vanilla and openSUSE at // least) put various tools in a triple-prefixed directory off of the parent // of the GCC installation. We use the GCC triple here to ensure that we end // up with tools that support the same amount of cross compiling as the // detected GCC installation. For example, if we find a GCC installation // targeting x86_64, but it is a bi-arch GCC installation, it can also be // used to target i386. if (GCCInstallation.isValid()) { PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + GCCInstallation.getTriple().str() + "/bin") .str()); } } void Generic_GCC::AddMultilibPaths(const Driver &D, const std::string &SysRoot, const std::string &OSLibDir, const std::string &MultiarchTriple, path_list &Paths) { // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = std::string(GCCInstallation.getParentLibPath()); // Add toolchain / multilib specific file paths. addMultilibsFilePaths(D, Multilibs, SelectedMultilib, GCCInstallation.getInstallPath(), Paths); // Sourcery CodeBench MIPS toolchain holds some libraries under // a biarch-like suffix of the GCC installation. addPathIfExists( D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(), Paths); // GCC cross compiling toolchains will install target libraries which ship // as part of the toolchain under // rather than as // any part of the GCC installation in // //gcc//. This decision is somewhat // debatable, but is the reality today. We need to search this tree even // when we have a sysroot somewhere else. It is the responsibility of // whomever is doing the cross build targeting a sysroot using a GCC // installation that is *not* within the system root to ensure two things: // // 1) Any DSOs that are linked in from this tree or from the install path // above must be present on the system root and found via an // appropriate rpath. // 2) There must not be libraries installed into // // unless they should be preferred over // those within the system root. // // Note that this matches the GCC behavior. See the below comment for where // Clang diverges from GCC's behavior. addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + SelectedMultilib.osSuffix(), Paths); // If the GCC installation we found is inside of the sysroot, we want to // prefer libraries installed in the parent prefix of the GCC installation. // It is important to *not* use these paths when the GCC installation is // outside of the system root as that can pick up unintended libraries. // This usually happens when there is an external cross compiler on the // host system, and a more minimal sysroot available that is the target of // the cross. Note that GCC does include some of these directories in some // configurations but this seems somewhere between questionable and simply // a bug. if (StringRef(LibPath).startswith(SysRoot)) { addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); } } } void Generic_GCC::AddMultiarchPaths(const Driver &D, const std::string &SysRoot, const std::string &OSLibDir, path_list &Paths) { // Try walking via the GCC triple path in case of biarch or multiarch GCC // installations with strange symlinks. if (GCCInstallation.isValid()) { addPathIfExists(D, SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + "/../../" + OSLibDir, Paths); // Add the 'other' biarch variant path Multilib BiarchSibling; if (GCCInstallation.getBiarchSibling(BiarchSibling)) { addPathIfExists( D, GCCInstallation.getInstallPath() + BiarchSibling.gccSuffix(), Paths); } // See comments above on the multilib variant for details of why this is // included even from outside the sysroot. const std::string &LibPath = std::string(GCCInstallation.getParentLibPath()); const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const Multilib &Multilib = GCCInstallation.getMultilib(); addPathIfExists( D, LibPath + "/../" + GCCTriple.str() + "/lib" + Multilib.osSuffix(), Paths); // See comments above on the multilib variant for details of why this is // only included from within the sysroot. if (StringRef(LibPath).startswith(SysRoot)) addPathIfExists(D, LibPath, Paths); } } void Generic_GCC::AddMultilibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { // Add include directories specific to the selected multilib set and multilib. if (GCCInstallation.isValid()) { const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { for (const auto &Path : Callback(GCCInstallation.getMultilib())) addExternCSystemIncludeIfExists( DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); } } } void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: addLibCxxIncludePaths(DriverArgs, CC1Args); break; case ToolChain::CST_Libstdcxx: addLibStdCxxIncludePaths(DriverArgs, CC1Args); break; } } static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, StringRef base) { std::error_code EC; int MaxVersion = 0; std::string MaxVersionString; for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->path()); int Version; if (VersionText[0] == 'v' && !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { if (Version > MaxVersion) { MaxVersion = Version; MaxVersionString = std::string(VersionText); } } } return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; } void Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { auto AddIncludePath = [&](std::string Path) { std::string IncludePath = DetectLibcxxIncludePath(getVFS(), Path); if (IncludePath.empty() || !getVFS().exists(IncludePath)) return false; addSystemInclude(DriverArgs, CC1Args, IncludePath); return true; }; // Android never uses the libc++ headers installed alongside the toolchain, // which are generally incompatible with the NDK libraries anyway. if (!getTriple().isAndroid()) if (AddIncludePath(getDriver().Dir + "/../include/c++")) return; // If this is a development, non-installed, clang, libcxx will // not be found at ../include/c++ but it likely to be found at // one of the following two locations: std::string SysRoot = computeSysRoot(); if (AddIncludePath(SysRoot + "/usr/local/include/c++")) return; if (AddIncludePath(SysRoot + "/usr/include/c++")) return; } /// Helper to add the variant paths of a libstdc++ installation. bool Generic_GCC::addLibStdCXXIncludePaths( Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, Twine IncludeSuffix, const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (!getVFS().exists(Base + Suffix)) return false; addSystemInclude(DriverArgs, CC1Args, Base + Suffix); // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If // that path exists or we have neither a GCC nor target multiarch triple, use // this vanilla search path. if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/" + GCCTriple + IncludeSuffix); } else { // Otherwise try to use multiarch naming schemes which have normalized the // triples and put the triple before the suffix. // // GCC surprisingly uses *both* the GCC triple with a multilib suffix and // the target triple, so we support that here. addSystemInclude(DriverArgs, CC1Args, Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix); addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetMultiarchTriple + Suffix); } addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward"); return true; } bool Generic_GCC::addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { // Use GCCInstallation to know where libstdc++ headers are installed. if (!GCCInstallation.isValid()) return false; // By default, look for the C++ headers in an include directory adjacent to // the lib directory of the GCC installation. Note that this is expect to be // equivalent to '/usr/include/c++/X.Y' in almost all cases. StringRef LibDir = GCCInstallation.getParentLibPath(); StringRef InstallDir = GCCInstallation.getInstallPath(); StringRef TripleStr = GCCInstallation.getTriple().str(); const Multilib &Multilib = GCCInstallation.getMultilib(); const std::string GCCMultiarchTriple = getMultiarchTriple( getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); const std::string TargetMultiarchTriple = getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); const GCCVersion &Version = GCCInstallation.getVersion(); // The primary search for libstdc++ supports multiarch variants. if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", "/c++/" + Version.Text, TripleStr, GCCMultiarchTriple, TargetMultiarchTriple, Multilib.includeSuffix(), DriverArgs, CC1Args)) return true; // Otherwise, fall back on a bunch of options which don't use multiarch // layouts for simplicity. const std::string LibStdCXXIncludePathCandidates[] = { // Gentoo is weird and places its headers inside the GCC install, // so if the first attempt to find the headers fails, try these patterns. InstallDir.str() + "/include/g++-v" + Version.Text, InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + Version.MinorStr, InstallDir.str() + "/include/g++-v" + Version.MajorStr, }; for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, /*GCCMultiarchTriple*/ "", /*TargetMultiarchTriple*/ "", Multilib.includeSuffix(), DriverArgs, CC1Args)) return true; } return false; } void Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args); } llvm::opt::DerivedArgList * Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, Action::OffloadKind DeviceOffloadKind) const { // If this tool chain is used for an OpenMP offloading device we have to make // sure we always generate a shared library regardless of the commands the // user passed to the host. This is required because the runtime library // is required to load the device image dynamically at run time. if (DeviceOffloadKind == Action::OFK_OpenMP) { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); // Request the shared library. Given that these options are decided // implicitly, they do not refer to any base argument. DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_shared)); DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_fPIC)); // Filter all the arguments we don't care passing to the offloading // toolchain as they can mess up with the creation of a shared library. for (auto *A : Args) { switch ((options::ID)A->getOption().getID()) { default: DAL->append(A); break; case options::OPT_shared: case options::OPT_dynamic: case options::OPT_static: case options::OPT_fPIC: case options::OPT_fno_PIC: case options::OPT_fpic: case options::OPT_fno_pic: case options::OPT_fPIE: case options::OPT_fno_PIE: case options::OPT_fpie: case options::OPT_fno_pie: break; } } return DAL; } return nullptr; } void Generic_ELF::anchor() {} void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fno-use-init-array"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp index 7d17f809690e..228d970c4043 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp @@ -1,401 +1,403 @@ //===--- HIP.cpp - HIP Tool and ToolChain Implementations -------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "HIP.h" #include "AMDGPU.h" #include "CommonArgs.h" #include "InputInfo.h" #include "clang/Basic/Cuda.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/TargetParser.h" using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; #if defined(_WIN32) || defined(_WIN64) #define NULL_FILE "nul" #else #define NULL_FILE "/dev/null" #endif namespace { static void addBCLib(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, ArgStringList LibraryPaths, StringRef BCName) { StringRef FullName; for (std::string LibraryPath : LibraryPaths) { SmallString<128> Path(LibraryPath); llvm::sys::path::append(Path, BCName); FullName = Path; if (llvm::sys::fs::exists(FullName)) { CmdArgs.push_back("-mlink-builtin-bitcode"); CmdArgs.push_back(Args.MakeArgString(FullName)); return; } } D.Diag(diag::err_drv_no_such_file) << BCName; } } // namespace void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const InputInfo &Output, const llvm::opt::ArgList &Args) const { // Construct lld command. // The output from ld.lld is an HSA code object file. ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", "-shared", "-plugin-opt=-amdgpu-internalize-symbols"}; auto &TC = getToolChain(); auto &D = TC.getDriver(); assert(!Inputs.empty() && "Must have at least one input."); addLTOOptions(TC, Args, LldArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); // Extract all the -m options std::vector Features; amdgpu::getAMDGPUTargetFeatures(D, Args, Features); // Add features to mattr such as cumode std::string MAttrString = "-plugin-opt=-mattr="; for (auto OneFeature : unifyTargetFeatures(Features)) { MAttrString.append(Args.MakeArgString(OneFeature)); if (OneFeature != Features.back()) MAttrString.append(","); } if (!Features.empty()) LldArgs.push_back(Args.MakeArgString(MAttrString)); for (const Arg *A : Args.filtered(options::OPT_mllvm)) { LldArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0))); } if (C.getDriver().isSaveTempsEnabled()) LldArgs.push_back("-save-temps"); + addLinkerCompressDebugSectionsOption(TC, Args, LldArgs); + LldArgs.append({"-o", Output.getFilename()}); for (auto Input : Inputs) LldArgs.push_back(Input.getFilename()); const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), Lld, LldArgs, Inputs)); } // Construct a clang-offload-bundler command to bundle code objects for // different GPU's into a HIP fat binary. void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, StringRef OutputFileName, const InputInfoList &Inputs, const llvm::opt::ArgList &Args, const Tool& T) { // 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=" NULL_FILE; for (const auto &II : Inputs) { const auto* A = II.getAction(); 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)); auto BundlerOutputArg = Args.MakeArgString( std::string("-outputs=").append(std::string(OutputFileName))); BundlerArgs.push_back(BundlerOutputArg); const char *Bundler = Args.MakeArgString( T.getToolChain().GetProgramPath("clang-offload-bundler")); C.addCommand(std::make_unique(JA, T, ResponseFileSupport::None(), Bundler, BundlerArgs, Inputs)); } /// Add Generated HIP Object File which has device images embedded into the /// host to the argument list for linking. Using MC directives, embed the /// device code and also define symbols required by the code generation so that /// the image can be retrieved at runtime. void AMDGCN::Linker::constructGenerateObjFileFromHIPFatBinary( Compilation &C, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const JobAction &JA) const { const ToolChain &TC = getToolChain(); std::string Name = std::string(llvm::sys::path::stem(Output.getFilename())); // Create Temp Object File Generator, // Offload Bundled file and Bundled Object file. // Keep them if save-temps is enabled. const char *McinFile; const char *BundleFile; if (C.getDriver().isSaveTempsEnabled()) { McinFile = C.getArgs().MakeArgString(Name + ".mcin"); BundleFile = C.getArgs().MakeArgString(Name + ".hipfb"); } else { auto TmpNameMcin = C.getDriver().GetTemporaryPath(Name, "mcin"); McinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin)); auto TmpNameFb = C.getDriver().GetTemporaryPath(Name, "hipfb"); BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameFb)); } constructHIPFatbinCommand(C, JA, BundleFile, Inputs, Args, *this); // Create a buffer to write the contents of the temp obj generator. std::string ObjBuffer; llvm::raw_string_ostream ObjStream(ObjBuffer); // Add MC directives 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. ObjStream << "# HIP Object Generator\n"; ObjStream << "# *** Automatically generated by Clang ***\n"; ObjStream << " .type __hip_fatbin,@object\n"; ObjStream << " .section .hip_fatbin,\"aMS\",@progbits,1\n"; ObjStream << " .data\n"; ObjStream << " .globl __hip_fatbin\n"; ObjStream << " .p2align 3\n"; ObjStream << "__hip_fatbin:\n"; ObjStream << " .incbin \"" << BundleFile << "\"\n"; ObjStream.flush(); // Dump the contents of the temp object file gen 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() << ObjBuffer; // Open script file and write the contents. std::error_code EC; llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None); if (EC) { C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); return; } Objf << ObjBuffer; ArgStringList McArgs{"-o", Output.getFilename(), McinFile, "--filetype=obj"}; const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc")); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), Mc, McArgs, Inputs)); } // For amdgcn the inputs of the linker job are device bitcode and output is // object file. It calls llvm-link, opt, llc, then lld steps. void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { if (Inputs.size() > 0 && Inputs[0].getType() == types::TY_Image && JA.getType() == types::TY_Object) return constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, Args, JA); if (JA.getType() == types::TY_HIP_FATBIN) return constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, Args, *this); return constructLldCommand(C, JA, Inputs, Output, Args); } HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple, const ToolChain &HostTC, const ArgList &Args) : ROCMToolChain(D, Triple, Args), HostTC(HostTC) { // Lookup binaries into the driver directory, this is used to // discover the clang-offload-bundler executable. getProgramPaths().push_back(getDriver().Dir); } void HIPToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ); assert(!GpuArch.empty() && "Must have an explicit GPU arch."); (void) GpuArch; assert(DeviceOffloadingKind == Action::OFK_HIP && "Only HIP offloading kinds are supported for GPUs."); auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); CC1Args.push_back("-fcuda-is-device"); if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, options::OPT_fno_cuda_approx_transcendentals, false)) CC1Args.push_back("-fcuda-approx-transcendentals"); if (DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) CC1Args.push_back("-fgpu-rdc"); else CC1Args.append({"-mllvm", "-amdgpu-internalize-symbols"}); StringRef MaxThreadsPerBlock = DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ); if (!MaxThreadsPerBlock.empty()) { std::string ArgStr = std::string("--gpu-max-threads-per-block=") + MaxThreadsPerBlock.str(); CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr)); } if (DriverArgs.hasFlag(options::OPT_fgpu_allow_device_init, options::OPT_fno_gpu_allow_device_init, false)) CC1Args.push_back("-fgpu-allow-device-init"); CC1Args.push_back("-fcuda-allow-variadic-functions"); // Default to "hidden" visibility, as object level linking will not be // supported for the foreseeable future. if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, options::OPT_fvisibility_ms_compat)) { CC1Args.append({"-fvisibility", "hidden"}); CC1Args.push_back("-fapply-global-visibility-to-externs"); } if (DriverArgs.hasArg(options::OPT_nogpulib)) return; ArgStringList LibraryPaths; // Find in --hip-device-lib-path and HIP_LIBRARY_PATH. for (auto Path : RocmInstallation.getRocmDeviceLibPathArg()) LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH"); // Maintain compatability with --hip-device-lib. auto BCLibs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ); if (!BCLibs.empty()) { for (auto Lib : BCLibs) addBCLib(getDriver(), DriverArgs, CC1Args, LibraryPaths, Lib); } else { if (!RocmInstallation.hasDeviceLibrary()) { getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; return; } std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); if (LibDeviceFile.empty()) { getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch; return; } // If --hip-device-lib is not set, add the default bitcode libraries. // TODO: There are way too many flags that change this. Do we need to check // them all? bool DAZ = DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, options::OPT_fno_cuda_flush_denormals_to_zero, getDefaultDenormsAreZeroForTarget(Kind)); // TODO: Check standard C++ flags? bool FiniteOnly = false; bool UnsafeMathOpt = false; bool FastRelaxedMath = false; bool CorrectSqrt = true; bool Wave64 = isWave64(DriverArgs, Kind); // Add the HIP specific bitcode library. CC1Args.push_back("-mlink-builtin-bitcode"); CC1Args.push_back(DriverArgs.MakeArgString(RocmInstallation.getHIPPath())); // Add the generic set of libraries. RocmInstallation.addCommonBitcodeLibCC1Args( DriverArgs, CC1Args, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, FastRelaxedMath, CorrectSqrt); } } llvm::opt::DerivedArgList * HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const { DerivedArgList *DAL = HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); if (!DAL) DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); for (Arg *A : Args) { DAL->append(A); } if (!BoundArch.empty()) { DAL->eraseArg(options::OPT_mcpu_EQ); DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), BoundArch); } return DAL; } Tool *HIPToolChain::buildLinker() const { assert(getTriple().getArch() == llvm::Triple::amdgcn); return new tools::AMDGCN::Linker(*this); } void HIPToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { HostTC.addClangWarningOptions(CC1Args); } ToolChain::CXXStdlibType HIPToolChain::GetCXXStdlibType(const ArgList &Args) const { return HostTC.GetCXXStdlibType(Args); } void HIPToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); } void HIPToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, ArgStringList &CC1Args) const { HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); } void HIPToolChain::AddIAMCUIncludeArgs(const ArgList &Args, ArgStringList &CC1Args) const { HostTC.AddIAMCUIncludeArgs(Args, CC1Args); } void HIPToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); } SanitizerMask HIPToolChain::getSupportedSanitizers() const { // The HIPToolChain only supports sanitizers in the sense that it allows // sanitizer arguments on the command line if they are supported by the host // toolchain. The HIPToolChain will actually ignore any command line // arguments for any of these "supported" sanitizers. That means that no // sanitization of device code is actually supported at this time. // // This behavior is necessary because the host and device toolchains // invocations often share the command line, so the device toolchain must // tolerate flags meant only for the host toolchain. return HostTC.getSupportedSanitizers(); } VersionTuple HIPToolChain::computeMSVCVersion(const Driver *D, const ArgList &Args) const { return HostTC.computeMSVCVersion(D, Args); }