diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Driver/ToolChain.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Driver/ToolChain.cpp | 574 |
1 files changed, 477 insertions, 97 deletions
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp index 6c1b88141c45..20a555afb809 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp @@ -7,10 +7,12 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/ToolChain.h" +#include "ToolChains/Arch/AArch64.h" #include "ToolChains/Arch/ARM.h" #include "ToolChains/Clang.h" -#include "ToolChains/InterfaceStubs.h" +#include "ToolChains/CommonArgs.h" #include "ToolChains/Flang.h" +#include "ToolChains/InterfaceStubs.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" #include "clang/Config/config.h" @@ -24,22 +26,25 @@ #include "clang/Driver/XRayArgs.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/llvm-config.h" #include "llvm/MC/MCTargetOptions.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" #include "llvm/Support/Path.h" -#include "llvm/Support/TargetParser.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/VersionTuple.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/AArch64TargetParser.h" +#include "llvm/TargetParser/TargetParser.h" +#include "llvm/TargetParser/Triple.h" #include <cassert> #include <cstddef> #include <cstring> @@ -67,25 +72,62 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args, return ToolChain::RM_Disabled; } - // -frtti is default, except for the PS4 CPU. - return (Triple.isPS4CPU()) ? ToolChain::RM_Disabled : ToolChain::RM_Enabled; + // -frtti is default, except for the PS4/PS5 and DriverKit. + bool NoRTTI = Triple.isPS() || Triple.isDriverKit(); + return NoRTTI ? ToolChain::RM_Disabled : ToolChain::RM_Enabled; +} + +static ToolChain::ExceptionsMode CalculateExceptionsMode(const ArgList &Args) { + if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, + true)) { + return ToolChain::EM_Enabled; + } + return ToolChain::EM_Disabled; } ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, const ArgList &Args) : D(D), Triple(T), Args(Args), CachedRTTIArg(GetRTTIArgument(Args)), - CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)) { - std::string RuntimePath = getRuntimePath(); - if (getVFS().exists(RuntimePath)) - getLibraryPaths().push_back(RuntimePath); + CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)), + CachedExceptionsMode(CalculateExceptionsMode(Args)) { + auto addIfExists = [this](path_list &List, const std::string &Path) { + if (getVFS().exists(Path)) + List.push_back(Path); + }; + + if (std::optional<std::string> Path = getRuntimePath()) + getLibraryPaths().push_back(*Path); + if (std::optional<std::string> Path = getStdlibPath()) + getFilePaths().push_back(*Path); + for (const auto &Path : getArchSpecificLibPaths()) + addIfExists(getFilePaths(), Path); +} + +llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> +ToolChain::executeToolChainProgram(StringRef Executable, + unsigned SecondsToWait) const { + llvm::SmallString<64> OutputFile; + llvm::sys::fs::createTemporaryFile("toolchain-program", "txt", OutputFile); + llvm::FileRemover OutputRemover(OutputFile.c_str()); + std::optional<llvm::StringRef> Redirects[] = { + {""}, + OutputFile.str(), + {""}, + }; - std::string StdlibPath = getStdlibPath(); - if (getVFS().exists(StdlibPath)) - getFilePaths().push_back(StdlibPath); + std::string ErrorMessage; + if (llvm::sys::ExecuteAndWait(Executable, {}, {}, Redirects, SecondsToWait, + /*MemoryLimit=*/0, &ErrorMessage)) + return llvm::createStringError(std::error_code(), + Executable + ": " + ErrorMessage); - std::string CandidateLibPath = getArchSpecificLibPath(); - if (getVFS().exists(CandidateLibPath)) - getFilePaths().push_back(CandidateLibPath); + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf = + llvm::MemoryBuffer::getFile(OutputFile.c_str()); + if (!OutputBuf) + return llvm::createStringError(OutputBuf.getError(), + "Failed to read stdout of " + Executable + + ": " + OutputBuf.getError().message()); + return std::move(*OutputBuf); } void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) { @@ -106,24 +148,169 @@ bool ToolChain::useIntegratedAs() const { IsIntegratedAssemblerDefault()); } +bool ToolChain::useIntegratedBackend() const { + assert( + ((IsIntegratedBackendDefault() && IsIntegratedBackendSupported()) || + (!IsIntegratedBackendDefault() || IsNonIntegratedBackendSupported())) && + "(Non-)integrated backend set incorrectly!"); + + bool IBackend = Args.hasFlag(options::OPT_fintegrated_objemitter, + options::OPT_fno_integrated_objemitter, + IsIntegratedBackendDefault()); + + // Diagnose when integrated-objemitter options are not supported by this + // toolchain. + unsigned DiagID; + if ((IBackend && !IsIntegratedBackendSupported()) || + (!IBackend && !IsNonIntegratedBackendSupported())) + DiagID = clang::diag::err_drv_unsupported_opt_for_target; + else + DiagID = clang::diag::warn_drv_unsupported_opt_for_target; + Arg *A = Args.getLastArg(options::OPT_fno_integrated_objemitter); + if (A && !IsNonIntegratedBackendSupported()) + D.Diag(DiagID) << A->getAsString(Args) << Triple.getTriple(); + A = Args.getLastArg(options::OPT_fintegrated_objemitter); + if (A && !IsIntegratedBackendSupported()) + D.Diag(DiagID) << A->getAsString(Args) << Triple.getTriple(); + + return IBackend; +} + bool ToolChain::useRelaxRelocations() const { return ENABLE_X86_RELAX_RELOCATIONS; } -bool ToolChain::isNoExecStackDefault() const { - return false; +bool ToolChain::defaultToIEEELongDouble() const { + return PPC_LINUX_DEFAULT_IEEELONGDOUBLE && getTriple().isOSLinux(); +} + +static void getAArch64MultilibFlags(const Driver &D, + const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + Multilib::flags_list &Result) { + std::vector<StringRef> Features; + tools::aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, false); + const auto UnifiedFeatures = tools::unifyTargetFeatures(Features); + llvm::DenseSet<StringRef> FeatureSet(UnifiedFeatures.begin(), + UnifiedFeatures.end()); + std::vector<std::string> MArch; + for (const auto &Ext : AArch64::Extensions) + if (!Ext.UserVisibleName.empty()) + if (FeatureSet.contains(Ext.PosTargetFeature)) + MArch.push_back(Ext.UserVisibleName.str()); + for (const auto &Ext : AArch64::Extensions) + if (!Ext.UserVisibleName.empty()) + if (FeatureSet.contains(Ext.NegTargetFeature)) + MArch.push_back(("no" + Ext.UserVisibleName).str()); + StringRef ArchName; + for (const auto &ArchInfo : AArch64::ArchInfos) + if (FeatureSet.contains(ArchInfo->ArchFeature)) + ArchName = ArchInfo->Name; + assert(!ArchName.empty() && "at least one architecture should be found"); + MArch.insert(MArch.begin(), ("-march=" + ArchName).str()); + Result.push_back(llvm::join(MArch, "+")); +} + +static void getARMMultilibFlags(const Driver &D, + const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + Multilib::flags_list &Result) { + std::vector<StringRef> Features; + llvm::ARM::FPUKind FPUKind = tools::arm::getARMTargetFeatures( + D, Triple, Args, Features, false /*ForAs*/, true /*ForMultilib*/); + const auto UnifiedFeatures = tools::unifyTargetFeatures(Features); + llvm::DenseSet<StringRef> FeatureSet(UnifiedFeatures.begin(), + UnifiedFeatures.end()); + std::vector<std::string> MArch; + for (const auto &Ext : ARM::ARCHExtNames) + if (!Ext.Name.empty()) + if (FeatureSet.contains(Ext.Feature)) + MArch.push_back(Ext.Name.str()); + for (const auto &Ext : ARM::ARCHExtNames) + if (!Ext.Name.empty()) + if (FeatureSet.contains(Ext.NegFeature)) + MArch.push_back(("no" + Ext.Name).str()); + MArch.insert(MArch.begin(), ("-march=" + Triple.getArchName()).str()); + Result.push_back(llvm::join(MArch, "+")); + + switch (FPUKind) { +#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) \ + case llvm::ARM::KIND: \ + Result.push_back("-mfpu=" NAME); \ + break; +#include "llvm/TargetParser/ARMTargetParser.def" + default: + llvm_unreachable("Invalid FPUKind"); + } + + switch (arm::getARMFloatABI(D, Triple, Args)) { + case arm::FloatABI::Soft: + Result.push_back("-mfloat-abi=soft"); + break; + case arm::FloatABI::SoftFP: + Result.push_back("-mfloat-abi=softfp"); + break; + case arm::FloatABI::Hard: + Result.push_back("-mfloat-abi=hard"); + break; + case arm::FloatABI::Invalid: + llvm_unreachable("Invalid float ABI"); + } } -const SanitizerArgs& ToolChain::getSanitizerArgs() const { - if (!SanitizerArguments.get()) - SanitizerArguments.reset(new SanitizerArgs(*this, Args)); - return *SanitizerArguments.get(); +Multilib::flags_list +ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const { + using namespace clang::driver::options; + + std::vector<std::string> Result; + const llvm::Triple Triple(ComputeEffectiveClangTriple(Args)); + Result.push_back("--target=" + Triple.str()); + + switch (Triple.getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: + case llvm::Triple::aarch64_be: + getAArch64MultilibFlags(D, Triple, Args, Result); + break; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + getARMMultilibFlags(D, Triple, Args, Result); + break; + default: + break; + } + + // Include fno-exceptions and fno-rtti + // to improve multilib selection + if (getRTTIMode() == ToolChain::RTTIMode::RM_Disabled) + Result.push_back("-fno-rtti"); + else + Result.push_back("-frtti"); + + if (getExceptionsMode() == ToolChain::ExceptionsMode::EM_Disabled) + Result.push_back("-fno-exceptions"); + else + Result.push_back("-fexceptions"); + + // Sort and remove duplicates. + std::sort(Result.begin(), Result.end()); + Result.erase(std::unique(Result.begin(), Result.end()), Result.end()); + return Result; +} + +SanitizerArgs +ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const { + SanitizerArgs SanArgs(*this, JobArgs, !SanitizerArgsChecked); + SanitizerArgsChecked = true; + return SanArgs; } const XRayArgs& ToolChain::getXRayArgs() const { - if (!XRayArguments.get()) + if (!XRayArguments) XRayArguments.reset(new XRayArgs(*this, Args)); - return *XRayArguments.get(); + return *XRayArguments; } namespace { @@ -153,13 +340,14 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { {"cl", "--driver-mode=cl"}, {"++", "--driver-mode=g++"}, {"flang", "--driver-mode=flang"}, + {"clang-dxc", "--driver-mode=dxc"}, }; - for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) { - StringRef Suffix(DriverSuffixes[i].Suffix); - if (ProgName.endswith(Suffix)) { + for (const auto &DS : DriverSuffixes) { + StringRef Suffix(DS.Suffix); + if (ProgName.ends_with(Suffix)) { Pos = ProgName.size() - Suffix.size(); - return &DriverSuffixes[i]; + return &DS; } } return nullptr; @@ -168,11 +356,12 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { /// Normalize the program name from argv[0] by stripping the file extension if /// present and lower-casing the string on Windows. static std::string normalizeProgramName(llvm::StringRef Argv0) { - std::string ProgName = std::string(llvm::sys::path::stem(Argv0)); -#ifdef _WIN32 - // Transform to lowercase for case insensitive file systems. - std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), ::tolower); -#endif + std::string ProgName = std::string(llvm::sys::path::filename(Argv0)); + if (is_style_windows(llvm::sys::path::Style::native)) { + // Transform to lowercase for case insensitive file systems. + std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), + ::tolower); + } return ProgName; } @@ -186,6 +375,13 @@ static const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) { // added via -target as implicit first argument. const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos); + if (!DS && ProgName.ends_with(".exe")) { + // Try again after stripping the executable suffix: + // clang++.exe -> clang++ + ProgName = ProgName.drop_back(StringRef(".exe").size()); + DS = FindDriverSuffix(ProgName, Pos); + } + if (!DS) { // Try again after stripping any trailing version number: // clang++3.5 -> clang++ @@ -256,13 +452,14 @@ std::string ToolChain::getInputFilename(const InputInfo &Input) const { return Input.getFilename(); } -bool ToolChain::IsUnwindTablesDefault(const ArgList &Args) const { - return false; +ToolChain::UnwindTableLevel +ToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const { + return UnwindTableLevel::None; } Tool *ToolChain::getClang() const { if (!Clang) - Clang.reset(new tools::Clang(*this)); + Clang.reset(new tools::Clang(*this, useIntegratedBackend())); return Clang.get(); } @@ -320,10 +517,16 @@ Tool *ToolChain::getOffloadBundler() const { return OffloadBundler.get(); } -Tool *ToolChain::getOffloadWrapper() const { - if (!OffloadWrapper) - OffloadWrapper.reset(new tools::OffloadWrapper(*this)); - return OffloadWrapper.get(); +Tool *ToolChain::getOffloadPackager() const { + if (!OffloadPackager) + OffloadPackager.reset(new tools::OffloadPackager(*this)); + return OffloadPackager.get(); +} + +Tool *ToolChain::getLinkerWrapper() const { + if (!LinkerWrapper) + LinkerWrapper.reset(new tools::LinkerWrapper(*this, getLink())); + return LinkerWrapper.get(); } Tool *ToolChain::getTool(Action::ActionClass AC) const { @@ -346,12 +549,13 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::LipoJobClass: case Action::DsymutilJobClass: case Action::VerifyDebugInfoJobClass: + case Action::BinaryAnalyzeJobClass: llvm_unreachable("Invalid tool kind."); case Action::CompileJobClass: case Action::PrecompileJobClass: - case Action::HeaderModulePrecompileJobClass: case Action::PreprocessJobClass: + case Action::ExtractAPIJobClass: case Action::AnalyzeJobClass: case Action::MigrateJobClass: case Action::VerifyPCHJobClass: @@ -362,8 +566,10 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::OffloadUnbundlingJobClass: return getOffloadBundler(); - case Action::OffloadWrapperJobClass: - return getOffloadWrapper(); + case Action::OffloadPackagerJobClass: + return getOffloadPackager(); + case Action::LinkerWrapperJobClass: + return getLinkerWrapper(); } llvm_unreachable("Invalid tool kind."); @@ -374,6 +580,9 @@ static StringRef getArchNameForCompilerRTLib(const ToolChain &TC, const llvm::Triple &Triple = TC.getTriple(); bool IsWindows = Triple.isOSWindows(); + if (TC.isBareMetal()) + return Triple.getArchName(); + if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows) ? "armhf" @@ -411,12 +620,17 @@ StringRef ToolChain::getOSLibName() const { std::string ToolChain::getCompilerRTPath() const { SmallString<128> Path(getDriver().ResourceDir); - if (Triple.isOSUnknown()) { + if (isBareMetal()) { + llvm::sys::path::append(Path, "lib", getOSLibName()); + if (!SelectedMultilibs.empty()) { + Path += SelectedMultilibs.back().gccSuffix(); + } + } else if (Triple.isOSUnknown()) { llvm::sys::path::append(Path, "lib"); } else { llvm::sys::path::append(Path, "lib", getOSLibName()); } - return std::string(Path.str()); + return std::string(Path); } std::string ToolChain::getCompilerRTBasename(const ArgList &Args, @@ -465,20 +679,30 @@ std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component, // Check for runtime files in the new layout without the architecture first. std::string CRTBasename = buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false); + SmallString<128> Path; for (const auto &LibPath : getLibraryPaths()) { SmallString<128> P(LibPath); llvm::sys::path::append(P, CRTBasename); if (getVFS().exists(P)) - return std::string(P.str()); + return std::string(P); + if (Path.empty()) + Path = P; } + if (getTriple().isOSAIX()) + Path.clear(); - // Fall back to the old expected compiler-rt name if the new one does not - // exist. + // Check the filename for the old layout if the new one does not exist. CRTBasename = buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/true); - SmallString<128> Path(getCompilerRTPath()); - llvm::sys::path::append(Path, CRTBasename); - return std::string(Path.str()); + SmallString<128> OldPath(getCompilerRTPath()); + llvm::sys::path::append(OldPath, CRTBasename); + if (Path.empty() || getVFS().exists(OldPath)) + return std::string(OldPath); + + // If none is found, use a file name from the new layout, which may get + // printed in an error message, aiding users in knowing what Clang is + // looking for. + return std::string(Path); } const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, @@ -487,23 +711,130 @@ const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, return Args.MakeArgString(getCompilerRT(Args, Component, Type)); } -std::string ToolChain::getRuntimePath() const { +// Android target triples contain a target version. If we don't have libraries +// for the exact target version, we should fall back to the next newest version +// or a versionless path, if any. +std::optional<std::string> +ToolChain::getFallbackAndroidTargetPath(StringRef BaseDir) const { + llvm::Triple TripleWithoutLevel(getTriple()); + TripleWithoutLevel.setEnvironmentName("android"); // remove any version number + const std::string &TripleWithoutLevelStr = TripleWithoutLevel.str(); + unsigned TripleVersion = getTriple().getEnvironmentVersion().getMajor(); + unsigned BestVersion = 0; + + SmallString<32> TripleDir; + bool UsingUnversionedDir = false; + std::error_code EC; + for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(BaseDir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef DirName = llvm::sys::path::filename(LI->path()); + StringRef DirNameSuffix = DirName; + if (DirNameSuffix.consume_front(TripleWithoutLevelStr)) { + if (DirNameSuffix.empty() && TripleDir.empty()) { + TripleDir = DirName; + UsingUnversionedDir = true; + } else { + unsigned Version; + if (!DirNameSuffix.getAsInteger(10, Version) && Version > BestVersion && + Version < TripleVersion) { + BestVersion = Version; + TripleDir = DirName; + UsingUnversionedDir = false; + } + } + } + } + + if (TripleDir.empty()) + return {}; + + SmallString<128> P(BaseDir); + llvm::sys::path::append(P, TripleDir); + if (UsingUnversionedDir) + D.Diag(diag::warn_android_unversioned_fallback) << P << getTripleString(); + return std::string(P); +} + +std::optional<std::string> +ToolChain::getTargetSubDirPath(StringRef BaseDir) const { + auto getPathForTriple = + [&](const llvm::Triple &Triple) -> std::optional<std::string> { + SmallString<128> P(BaseDir); + llvm::sys::path::append(P, Triple.str()); + if (getVFS().exists(P)) + return std::string(P); + return {}; + }; + + if (auto Path = getPathForTriple(getTriple())) + return *Path; + + // When building with per target runtime directories, various ways of naming + // the Arm architecture may have been normalised to simply "arm". + // For example "armv8l" (Armv8 AArch32 little endian) is replaced with "arm". + // Since an armv8l system can use libraries built for earlier architecture + // versions assuming endian and float ABI match. + // + // Original triple: armv8l-unknown-linux-gnueabihf + // Runtime triple: arm-unknown-linux-gnueabihf + // + // We do not do this for armeb (big endian) because doing so could make us + // select little endian libraries. In addition, all known armeb triples only + // use the "armeb" architecture name. + // + // M profile Arm is bare metal and we know they will not be using the per + // target runtime directory layout. + if (getTriple().getArch() == Triple::arm && !getTriple().isArmMClass()) { + llvm::Triple ArmTriple = getTriple(); + ArmTriple.setArch(Triple::arm); + if (auto Path = getPathForTriple(ArmTriple)) + return *Path; + } + + if (getTriple().isAndroid()) + return getFallbackAndroidTargetPath(BaseDir); + + return {}; +} + +std::optional<std::string> ToolChain::getRuntimePath() const { SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "lib", getTripleString()); - return std::string(P.str()); + llvm::sys::path::append(P, "lib"); + if (auto Ret = getTargetSubDirPath(P)) + return Ret; + // Darwin does not use per-target runtime directory. + if (Triple.isOSDarwin()) + return {}; + llvm::sys::path::append(P, Triple.str()); + return std::string(P); } -std::string ToolChain::getStdlibPath() const { +std::optional<std::string> ToolChain::getStdlibPath() const { SmallString<128> P(D.Dir); - llvm::sys::path::append(P, "..", "lib", getTripleString()); - return std::string(P.str()); + llvm::sys::path::append(P, "..", "lib"); + return getTargetSubDirPath(P); } -std::string ToolChain::getArchSpecificLibPath() const { - SmallString<128> Path(getDriver().ResourceDir); - llvm::sys::path::append(Path, "lib", getOSLibName(), - llvm::Triple::getArchTypeName(getArch())); - return std::string(Path.str()); +std::optional<std::string> ToolChain::getStdlibIncludePath() const { + SmallString<128> P(D.Dir); + llvm::sys::path::append(P, "..", "include"); + return getTargetSubDirPath(P); +} + +ToolChain::path_list ToolChain::getArchSpecificLibPaths() const { + path_list Paths; + + auto AddPath = [&](const ArrayRef<StringRef> &SS) { + SmallString<128> Path(getDriver().ResourceDir); + llvm::sys::path::append(Path, "lib"); + for (auto &S : SS) + llvm::sys::path::append(Path, S); + Paths.push_back(std::string(Path)); + }; + + AddPath({getTriple().str()}); + AddPath({getOSLibName(), llvm::Triple::getArchTypeName(getArch())}); + return Paths; } bool ToolChain::needsProfileRT(const ArgList &Args) { @@ -530,7 +861,8 @@ Tool *ToolChain::SelectTool(const JobAction &JA) const { if (D.IsFlangMode() && getDriver().ShouldUseFlangCompiler(JA)) return getFlang(); if (getDriver().ShouldUseClangCompiler(JA)) return getClang(); Action::ActionClass AC = JA.getKind(); - if (AC == Action::AssembleJobClass && useIntegratedAs()) + if (AC == Action::AssembleJobClass && useIntegratedAs() && + !getTriple().isOSAIX()) return getClangAs(); return getTool(AC); } @@ -543,12 +875,9 @@ std::string ToolChain::GetProgramPath(const char *Name) const { return D.GetProgramPath(Name, *this); } -std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD, - bool *LinkerIsLLDDarwinNew) const { +std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const { if (LinkerIsLLD) *LinkerIsLLD = false; - if (LinkerIsLLDDarwinNew) - *LinkerIsLLDDarwinNew = false; // Get -fuse-ld= first to prevent -Wunused-command-line-argument. -fuse-ld= is // considered as the linker flavor, e.g. "bfd", "gold", or "lld". @@ -558,13 +887,18 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD, // --ld-path= takes precedence over -fuse-ld= and specifies the executable // name. -B, COMPILER_PATH and PATH and consulted if the value does not // contain a path component separator. + // -fuse-ld=lld can be used with --ld-path= to inform clang that the binary + // that --ld-path= points to is lld. if (const Arg *A = Args.getLastArg(options::OPT_ld_path_EQ)) { std::string Path(A->getValue()); if (!Path.empty()) { if (llvm::sys::path::parent_path(Path).empty()) Path = GetProgramPath(A->getValue()); - if (llvm::sys::fs::can_execute(Path)) + if (llvm::sys::fs::can_execute(Path)) { + if (LinkerIsLLD) + *LinkerIsLLD = UseLinker == "lld"; return std::string(Path); + } } getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args); return GetProgramPath(getDefaultLinker()); @@ -583,7 +917,7 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD, // for the linker flavor is brittle. In addition, prepending "ld." or "ld64." // to a relative path is surprising. This is more complex due to priorities // among -B, COMPILER_PATH and PATH. --ld-path= should be used instead. - if (UseLinker.find('/') != StringRef::npos) + if (UseLinker.contains('/')) getDriver().Diag(diag::warn_drv_fuse_ld_path); if (llvm::sys::path::is_absolute(UseLinker)) { @@ -601,11 +935,8 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD, std::string LinkerPath(GetProgramPath(LinkerName.c_str())); if (llvm::sys::fs::can_execute(LinkerPath)) { - // FIXME: Remove LinkerIsLLDDarwinNew once there's only one MachO lld. if (LinkerIsLLD) - *LinkerIsLLD = UseLinker == "lld" || UseLinker == "lld.darwinold"; - if (LinkerIsLLDDarwinNew) - *LinkerIsLLDDarwinNew = UseLinker == "lld"; + *LinkerIsLLD = UseLinker == "lld"; return LinkerPath; } } @@ -618,6 +949,8 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD, std::string ToolChain::GetStaticLibToolPath() const { // TODO: Add support for static lib archiving on Windows + if (Triple.isOSDarwin()) + return GetProgramPath("libtool"); return GetProgramPath("llvm-ar"); } @@ -698,11 +1031,12 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, } case llvm::Triple::aarch64: { llvm::Triple Triple = getTriple(); + tools::aarch64::setPAuthABIInTriple(getDriver(), Args, Triple); if (!Triple.isOSBinFormatMachO()) - return getTripleString(); + return Triple.getTriple(); if (Triple.isArm64e()) - return getTripleString(); + return Triple.getTriple(); // FIXME: older versions of ld64 expect the "arm64" component in the actual // triple string and query it to determine whether an LTO file can be @@ -742,6 +1076,9 @@ void ToolChain::addClangTargetOptions( const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const {} +void ToolChain::addClangCC1ASTargetOptions(const ArgList &Args, + ArgStringList &CC1ASArgs) const {} + void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {} void ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args, @@ -879,6 +1216,14 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, } } +/*static*/ std::string ToolChain::concat(StringRef Path, const Twine &A, + const Twine &B, const Twine &C, + const Twine &D) { + SmallString<128> Result(Path); + llvm::sys::path::append(Result, llvm::sys::path::Style::posix, A, B, C, D); + return std::string(Result); +} + std::string ToolChain::detectLibcxxVersion(StringRef IncludePath) const { std::error_code EC; int MaxVersion = 0; @@ -920,8 +1265,15 @@ void ToolChain::AddClangCXXStdlibIsystemArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { DriverArgs.ClaimAllArgs(options::OPT_stdlibxx_isystem); - if (!DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdincxx, - options::OPT_nostdlibinc)) + // This intentionally only looks at -nostdinc++, and not -nostdinc or + // -nostdlibinc. The purpose of -stdlib++-isystem is to support toolchain + // setups with non-standard search logic for the C++ headers, while still + // allowing users of the toolchain to bring their own C++ headers. Such a + // toolchain likely also has non-standard search logic for the C headers and + // uses -nostdinc to suppress the default logic, but -stdlib++-isystem should + // still work in that case and only be suppressed by an explicit -nostdinc++ + // in a project using the toolchain. + if (!DriverArgs.hasArg(options::OPT_nostdincxx)) for (const auto &P : DriverArgs.getAllArgValues(options::OPT_stdlibxx_isystem)) addSystemInclude(DriverArgs, CC1Args, P); @@ -942,6 +1294,8 @@ void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args, switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); break; case ToolChain::CST_Libstdcxx: @@ -964,19 +1318,35 @@ void ToolChain::AddCCKextLibArgs(const ArgList &Args, bool ToolChain::isFastMathRuntimeAvailable(const ArgList &Args, std::string &Path) const { + // Don't implicitly link in mode-changing libraries in a shared library, since + // this can have very deleterious effects. See the various links from + // https://github.com/llvm/llvm-project/issues/57589 for more information. + bool Default = !Args.hasArgNoClaim(options::OPT_shared); + // Do not check for -fno-fast-math or -fno-unsafe-math when -Ofast passed // (to keep the linker options consistent with gcc and clang itself). - if (!isOptimizationLevelFast(Args)) { + if (Default && !isOptimizationLevelFast(Args)) { // Check if -ffast-math or -funsafe-math. - Arg *A = - Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math, - options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations); + Arg *A = Args.getLastArg( + options::OPT_ffast_math, options::OPT_fno_fast_math, + options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, options::OPT_ffp_model_EQ); if (!A || A->getOption().getID() == options::OPT_fno_fast_math || A->getOption().getID() == options::OPT_fno_unsafe_math_optimizations) - return false; + Default = false; + if (A && A->getOption().getID() == options::OPT_ffp_model_EQ) { + StringRef Model = A->getValue(); + if (Model != "fast") + Default = false; + } } + + // Whatever decision came as a result of the above implicit settings, either + // -mdaz-ftz or -mno-daz-ftz is capable of overriding it. + if (!Args.hasFlag(options::OPT_mdaz_ftz, options::OPT_mno_daz_ftz, Default)) + return false; + // If crtfastmath.o exists add it to the arguments. Path = GetFilePath("crtfastmath.o"); return (Path != "crtfastmath.o"); // Not found. @@ -993,22 +1363,27 @@ bool ToolChain::addFastMathRuntimeIfAvailable(const ArgList &Args, return false; } +Expected<SmallVector<std::string>> +ToolChain::getSystemGPUArchs(const llvm::opt::ArgList &Args) const { + return SmallVector<std::string>(); +} + SanitizerMask ToolChain::getSupportedSanitizers() const { // Return sanitizers which don't require runtime support and are not // platform dependent. SanitizerMask Res = - (SanitizerKind::Undefined & ~SanitizerKind::Vptr & - ~SanitizerKind::Function) | + (SanitizerKind::Undefined & ~SanitizerKind::Vptr) | (SanitizerKind::CFI & ~SanitizerKind::CFIICall) | SanitizerKind::CFICastStrict | SanitizerKind::FloatDivideByZero | - SanitizerKind::UnsignedIntegerOverflow | + SanitizerKind::KCFI | SanitizerKind::UnsignedIntegerOverflow | SanitizerKind::UnsignedShiftBase | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::LocalBounds; if (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64 || getTriple().getArch() == llvm::Triple::arm || getTriple().isWasm() || - getTriple().isAArch64()) + getTriple().isAArch64() || getTriple().isRISCV() || + getTriple().isLoongArch64()) Res |= SanitizerKind::CFIICall; if (getTriple().getArch() == llvm::Triple::x86_64 || getTriple().isAArch64(64) || getTriple().isRISCV()) @@ -1024,8 +1399,8 @@ void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, void ToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const {} -llvm::SmallVector<std::string, 12> -ToolChain::getHIPDeviceLibs(const ArgList &DriverArgs) const { +llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> +ToolChain::getDeviceLibs(const ArgList &DriverArgs) const { return {}; } @@ -1100,7 +1475,10 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( // matches the current toolchain triple. If it is not present // at all, target and host share a toolchain. if (A->getOption().matches(options::OPT_m_Group)) { - if (SameTripleAsHost) + // Pass code object version to device toolchain + // to correctly set metadata in intermediate files. + if (SameTripleAsHost || + A->getOption().matches(options::OPT_mcode_object_version_EQ)) DAL->append(A); else Modified = true; @@ -1113,8 +1491,10 @@ llvm::opt::DerivedArgList *ToolChain::TranslateOpenMPTargetArgs( A->getOption().matches(options::OPT_Xopenmp_target); if (A->getOption().matches(options::OPT_Xopenmp_target_EQ)) { + llvm::Triple TT(getOpenMPTriple(A->getValue(0))); + // Passing device args: -Xopenmp-target=<triple> -opt=val. - if (A->getValue(0) == getTripleString()) + if (TT.getTriple() == getTripleString()) Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); else continue; @@ -1205,17 +1585,17 @@ llvm::opt::DerivedArgList *ToolChain::TranslateXarchArgs( DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); bool Modified = false; - bool IsGPU = OFK == Action::OFK_Cuda || OFK == Action::OFK_HIP; + bool IsDevice = OFK != Action::OFK_None && OFK != Action::OFK_Host; for (Arg *A : Args) { bool NeedTrans = false; bool Skip = false; if (A->getOption().matches(options::OPT_Xarch_device)) { - NeedTrans = IsGPU; - Skip = !IsGPU; + NeedTrans = IsDevice; + Skip = !IsDevice; } else if (A->getOption().matches(options::OPT_Xarch_host)) { - NeedTrans = !IsGPU; - Skip = IsGPU; - } else if (A->getOption().matches(options::OPT_Xarch__) && IsGPU) { + NeedTrans = !IsDevice; + Skip = IsDevice; + } else if (A->getOption().matches(options::OPT_Xarch__) && IsDevice) { // Do not translate -Xarch_ options for non CUDA/HIP toolchain since // they may need special translation. // Skip this argument unless the architecture matches BoundArch |