diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Driver')
129 files changed, 17365 insertions, 9240 deletions
diff --git a/contrib/llvm-project/clang/lib/Driver/Action.cpp b/contrib/llvm-project/clang/lib/Driver/Action.cpp index eb08bfe9cde5..849bf6035ebd 100644 --- a/contrib/llvm-project/clang/lib/Driver/Action.cpp +++ b/contrib/llvm-project/clang/lib/Driver/Action.cpp @@ -25,7 +25,8 @@ const char *Action::getClassName(ActionClass AC) { return "offload"; case PreprocessJobClass: return "preprocessor"; case PrecompileJobClass: return "precompiler"; - case HeaderModulePrecompileJobClass: return "header-module-precompiler"; + case ExtractAPIJobClass: + return "api-extractor"; case AnalyzeJobClass: return "analyzer"; case MigrateJobClass: return "migrator"; case CompileJobClass: return "compiler"; @@ -41,18 +42,21 @@ const char *Action::getClassName(ActionClass AC) { return "clang-offload-bundler"; case OffloadUnbundlingJobClass: return "clang-offload-unbundler"; - case OffloadWrapperJobClass: - return "clang-offload-wrapper"; + case OffloadPackagerJobClass: + return "clang-offload-packager"; case LinkerWrapperJobClass: return "clang-linker-wrapper"; case StaticLibJobClass: return "static-lib-linker"; + case BinaryAnalyzeJobClass: + return "binary-analyzer"; } llvm_unreachable("invalid class"); } -void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) { +void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch, + const ToolChain *OToolChain) { // Offload action set its own kinds on their dependences. if (Kind == OffloadClass) return; @@ -65,9 +69,10 @@ void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) { assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??"); OffloadingDeviceKind = OKind; OffloadingArch = OArch; + OffloadingToolChain = OToolChain; for (auto *A : Inputs) - A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch); + A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch, OToolChain); } void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) { @@ -89,7 +94,8 @@ void Action::propagateOffloadInfo(const Action *A) { propagateHostOffloadInfo(HK, A->getOffloadingArch()); else propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(), - A->getOffloadingArch()); + A->getOffloadingArch(), + A->getOffloadingToolChain()); } std::string Action::getOffloadingKindPrefix() const { @@ -190,9 +196,10 @@ OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty) DevToolChains(DDeps.getToolChains()) { auto &OKinds = DDeps.getOffloadKinds(); auto &BArchs = DDeps.getBoundArchs(); + auto &OTCs = DDeps.getToolChains(); // If all inputs agree on the same kind, use it also for this action. - if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); })) + if (llvm::all_equal(OKinds)) OffloadingDeviceKind = OKinds.front(); // If we have a single dependency, inherit the architecture from it. @@ -201,7 +208,7 @@ OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty) // Propagate info to the dependencies. for (unsigned i = 0, e = getInputs().size(); i != e; ++i) - getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i]); + getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i], OTCs[i]); } OffloadAction::OffloadAction(const HostDependence &HDep, @@ -216,12 +223,17 @@ OffloadAction::OffloadAction(const HostDependence &HDep, // Add device inputs and propagate info to the device actions. Do work only if // we have dependencies. - for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i) + for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i) { if (auto *A = DDeps.getActions()[i]) { getInputs().push_back(A); A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i], - DDeps.getBoundArchs()[i]); + DDeps.getBoundArchs()[i], + DDeps.getToolChains()[i]); + // If this action is used to forward single dependency, set the toolchain. + if (DDeps.getActions().size() == 1) + OffloadingToolChain = DDeps.getToolChains()[i]; } + } } void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const { @@ -300,6 +312,19 @@ void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC, DeviceOffloadKinds.push_back(OKind); } +void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC, + const char *BoundArch, + unsigned OffloadKindMask) { + DeviceActions.push_back(&A); + DeviceToolChains.push_back(&TC); + DeviceBoundArchs.push_back(BoundArch); + + // Add each active offloading kind from a mask. + for (OffloadKind OKind : {OFK_OpenMP, OFK_Cuda, OFK_HIP}) + if (OKind & OffloadKindMask) + DeviceOffloadKinds.push_back(OKind); +} + OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC, const char *BoundArch, const DeviceDependences &DDeps) @@ -332,12 +357,10 @@ PrecompileJobAction::PrecompileJobAction(ActionClass Kind, Action *Input, assert(isa<PrecompileJobAction>((Action*)this) && "invalid action kind"); } -void HeaderModulePrecompileJobAction::anchor() {} +void ExtractAPIJobAction::anchor() {} -HeaderModulePrecompileJobAction::HeaderModulePrecompileJobAction( - Action *Input, types::ID OutputType, const char *ModuleName) - : PrecompileJobAction(HeaderModulePrecompileJobClass, Input, OutputType), - ModuleName(ModuleName) {} +ExtractAPIJobAction::ExtractAPIJobAction(Action *Inputs, types::ID OutputType) + : JobAction(ExtractAPIJobClass, Inputs, OutputType) {} void AnalyzeJobAction::anchor() {} @@ -414,11 +437,11 @@ void OffloadUnbundlingJobAction::anchor() {} OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input) : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {} -void OffloadWrapperJobAction::anchor() {} +void OffloadPackagerJobAction::anchor() {} -OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs, - types::ID Type) - : JobAction(OffloadWrapperJobClass, Inputs, Type) {} +OffloadPackagerJobAction::OffloadPackagerJobAction(ActionList &Inputs, + types::ID Type) + : JobAction(OffloadPackagerJobClass, Inputs, Type) {} void LinkerWrapperJobAction::anchor() {} @@ -430,3 +453,8 @@ void StaticLibJobAction::anchor() {} StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type) : JobAction(StaticLibJobClass, Inputs, Type) {} + +void BinaryAnalyzeJobAction::anchor() {} + +BinaryAnalyzeJobAction::BinaryAnalyzeJobAction(Action *Input, types::ID Type) + : JobAction(BinaryAnalyzeJobClass, Input, Type) {} diff --git a/contrib/llvm-project/clang/lib/Driver/Compilation.cpp b/contrib/llvm-project/clang/lib/Driver/Compilation.cpp index 67d941c6c2ab..ad077d5bbfa6 100644 --- a/contrib/llvm-project/clang/lib/Driver/Compilation.cpp +++ b/contrib/llvm-project/clang/lib/Driver/Compilation.cpp @@ -15,15 +15,14 @@ #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" -#include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Triple.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptSpecifier.h" #include "llvm/Option/Option.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" #include <cassert> #include <string> #include <system_error> @@ -102,7 +101,7 @@ Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch, } // Add allocated arguments to the final DAL. - for (auto ArgPtr : AllocatedArgs) + for (auto *ArgPtr : AllocatedArgs) Entry->AddSynthesizedArg(ArgPtr); } @@ -162,7 +161,8 @@ bool Compilation::CleanupFileMap(const ArgStringMap &Files, } int Compilation::ExecuteCommand(const Command &C, - const Command *&FailingCommand) const { + const Command *&FailingCommand, + bool LogOnly) const { if ((getDriver().CCPrintOptions || getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) { raw_ostream *OS = &llvm::errs(); @@ -191,6 +191,9 @@ int Compilation::ExecuteCommand(const Command &C, C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions); } + if (LogOnly) + return 0; + std::string Error; bool ExecutionFailed; int Res = C.Execute(Redirects, &Error, &ExecutionFailed); @@ -237,7 +240,8 @@ static bool InputsOk(const Command &C, } void Compilation::ExecuteJobs(const JobList &Jobs, - FailingCommandList &FailingCommands) const { + FailingCommandList &FailingCommands, + bool LogOnly) const { // According to UNIX standard, driver need to continue compiling all the // inputs on the command line even one of them failed. // In all but CLMode, execute all the jobs unless the necessary inputs for the @@ -246,7 +250,7 @@ void Compilation::ExecuteJobs(const JobList &Jobs, if (!InputsOk(Job, FailingCommands)) continue; const Command *FailingCommand = nullptr; - if (int Res = ExecuteCommand(Job, FailingCommand)) { + if (int Res = ExecuteCommand(Job, FailingCommand, LogOnly)) { FailingCommands.push_back(std::make_pair(Res, FailingCommand)); // Bail as soon as one command fails in cl driver mode. if (TheDriver.IsCLMode()) @@ -278,9 +282,9 @@ void Compilation::initCompilationForDiagnostics() { options::OPT_o, options::OPT_MD, options::OPT_MMD, options::OPT_M, options::OPT_MM, options::OPT_MF, options::OPT_MG, options::OPT_MJ, options::OPT_MQ, options::OPT_MT, options::OPT_MV}; - for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) { - if (TranslatedArgs->hasArg(OutputOpts[i])) - TranslatedArgs->eraseArg(OutputOpts[i]); + for (const auto &Opt : OutputOpts) { + if (TranslatedArgs->hasArg(Opt)) + TranslatedArgs->eraseArg(Opt); } TranslatedArgs->ClaimAllArgs(); @@ -292,7 +296,7 @@ void Compilation::initCompilationForDiagnostics() { TCArgs.clear(); // Redirect stdout/stderr to /dev/null. - Redirects = {None, {""}, {""}}; + Redirects = {std::nullopt, {""}, {""}}; // Temporary files added by diagnostics should be kept. ForceKeepTempFiles = true; @@ -302,6 +306,6 @@ StringRef Compilation::getSysRoot() const { return getDriver().SysRoot; } -void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) { +void Compilation::Redirect(ArrayRef<std::optional<StringRef>> Redirects) { this->Redirects = Redirects; } diff --git a/contrib/llvm-project/clang/lib/Driver/Distro.cpp b/contrib/llvm-project/clang/lib/Driver/Distro.cpp index 5ac38c34d112..a7e7f169dc14 100644 --- a/contrib/llvm-project/clang/lib/Driver/Distro.cpp +++ b/contrib/llvm-project/clang/lib/Driver/Distro.cpp @@ -11,11 +11,11 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Triple.h" #include "llvm/Support/ErrorOr.h" -#include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Threading.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" using namespace clang::driver; using namespace clang; @@ -34,7 +34,7 @@ static Distro::DistroType DetectOsRelease(llvm::vfs::FileSystem &VFS) { // Obviously this can be improved a lot. for (StringRef Line : Lines) - if (Version == Distro::UnknownDistro && Line.startswith("ID=")) + if (Version == Distro::UnknownDistro && Line.starts_with("ID=")) Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(3)) .Case("alpine", Distro::AlpineLinux) .Case("fedora", Distro::Fedora) @@ -60,7 +60,7 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) { for (StringRef Line : Lines) if (Version == Distro::UnknownDistro && - Line.startswith("DISTRIB_CODENAME=")) + Line.starts_with("DISTRIB_CODENAME=")) Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17)) .Case("hardy", Distro::UbuntuHardy) .Case("intrepid", Distro::UbuntuIntrepid) @@ -91,6 +91,10 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) { .Case("hirsute", Distro::UbuntuHirsute) .Case("impish", Distro::UbuntuImpish) .Case("jammy", Distro::UbuntuJammy) + .Case("kinetic", Distro::UbuntuKinetic) + .Case("lunar", Distro::UbuntuLunar) + .Case("mantic", Distro::UbuntuMantic) + .Case("noble", Distro::UbuntuNoble) .Default(Distro::UnknownDistro); return Version; } @@ -109,16 +113,16 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { if (Version != Distro::UnknownDistro) return Version; - // Otherwise try some distro-specific quirks for RedHat... + // Otherwise try some distro-specific quirks for Red Hat... llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = VFS.getBufferForFile("/etc/redhat-release"); if (File) { StringRef Data = File.get()->getBuffer(); - if (Data.startswith("Fedora release")) + if (Data.starts_with("Fedora release")) return Distro::Fedora; - if (Data.startswith("Red Hat Enterprise Linux") || - Data.startswith("CentOS") || Data.startswith("Scientific Linux")) { + if (Data.starts_with("Red Hat Enterprise Linux") || + Data.starts_with("CentOS") || Data.starts_with("Scientific Linux")) { if (Data.contains("release 7")) return Distro::RHEL7; else if (Data.contains("release 6")) @@ -153,6 +157,8 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { return Distro::DebianBullseye; case 12: return Distro::DebianBookworm; + case 13: + return Distro::DebianTrixie; default: return Distro::UnknownDistro; } @@ -165,6 +171,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { .Case("buster/sid", Distro::DebianBuster) .Case("bullseye/sid", Distro::DebianBullseye) .Case("bookworm/sid", Distro::DebianBookworm) + .Case("trixie/sid", Distro::DebianTrixie) .Default(Distro::UnknownDistro); } @@ -175,7 +182,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { SmallVector<StringRef, 8> Lines; Data.split(Lines, "\n"); for (const StringRef &Line : Lines) { - if (!Line.trim().startswith("VERSION")) + if (!Line.trim().starts_with("VERSION")) continue; std::pair<StringRef, StringRef> SplitLine = Line.split('='); // Old versions have split VERSION and PATCHLEVEL diff --git a/contrib/llvm-project/clang/lib/Driver/Driver.cpp b/contrib/llvm-project/clang/lib/Driver/Driver.cpp index 3bfddeefc7b2..93cddf742d52 100644 --- a/contrib/llvm-project/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm-project/clang/lib/Driver/Driver.cpp @@ -11,11 +11,10 @@ #include "ToolChains/AMDGPU.h" #include "ToolChains/AMDGPUOpenMP.h" #include "ToolChains/AVR.h" -#include "ToolChains/Ananas.h" +#include "ToolChains/Arch/RISCV.h" #include "ToolChains/BareMetal.h" +#include "ToolChains/CSKYToolChain.h" #include "ToolChains/Clang.h" -#include "ToolChains/CloudABI.h" -#include "ToolChains/Contiki.h" #include "ToolChains/CrossWindows.h" #include "ToolChains/Cuda.h" #include "ToolChains/Darwin.h" @@ -25,6 +24,7 @@ #include "ToolChains/Gnu.h" #include "ToolChains/HIPAMD.h" #include "ToolChains/HIPSPV.h" +#include "ToolChains/HLSL.h" #include "ToolChains/Haiku.h" #include "ToolChains/Hexagon.h" #include "ToolChains/Hurd.h" @@ -33,11 +33,10 @@ #include "ToolChains/MSP430.h" #include "ToolChains/MSVC.h" #include "ToolChains/MinGW.h" -#include "ToolChains/Minix.h" #include "ToolChains/MipsLinux.h" -#include "ToolChains/Myriad.h" #include "ToolChains/NaCl.h" #include "ToolChains/NetBSD.h" +#include "ToolChains/OHOS.h" #include "ToolChains/OpenBSD.h" #include "ToolChains/PPCFreeBSD.h" #include "ToolChains/PPCLinux.h" @@ -59,13 +58,13 @@ #include "clang/Driver/InputInfo.h" #include "clang/Driver/Job.h" #include "clang/Driver/Options.h" +#include "clang/Driver/Phases.h" #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" @@ -82,17 +81,21 @@ #include "llvm/Support/ExitCodes.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/Host.h" #include "llvm/Support/MD5.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" +#include <cstdlib> // ::getenv #include <map> #include <memory> +#include <optional> +#include <set> #include <utility> #if LLVM_ON_UNIX #include <unistd.h> // getpid @@ -102,8 +105,8 @@ using namespace clang::driver; using namespace clang; using namespace llvm::opt; -static llvm::Optional<llvm::Triple> -getOffloadTargetTriple(const Driver &D, const ArgList &Args) { +static std::optional<llvm::Triple> getOffloadTargetTriple(const Driver &D, + const ArgList &Args) { auto OffloadTargets = Args.getAllArgValues(options::OPT_offload_EQ); // Offload compilation flow does not support multiple targets for now. We // need the HIPActionBuilder (and possibly the CudaActionBuilder{,Base}too) @@ -111,17 +114,17 @@ getOffloadTargetTriple(const Driver &D, const ArgList &Args) { switch (OffloadTargets.size()) { default: D.Diag(diag::err_drv_only_one_offload_target_supported); - return llvm::None; + return std::nullopt; case 0: D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << ""; - return llvm::None; + return std::nullopt; case 1: break; } return llvm::Triple(OffloadTargets[0]); } -static llvm::Optional<llvm::Triple> +static std::optional<llvm::Triple> getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args, const llvm::Triple &HostTriple) { if (!Args.hasArg(options::OPT_offload_EQ)) { @@ -134,19 +137,19 @@ getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args, if (Args.hasArg(options::OPT_emit_llvm)) return TT; D.Diag(diag::err_drv_cuda_offload_only_emit_bc); - return llvm::None; + return std::nullopt; } D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str(); - return llvm::None; + return std::nullopt; } -static llvm::Optional<llvm::Triple> +static std::optional<llvm::Triple> getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) { if (!Args.hasArg(options::OPT_offload_EQ)) { return llvm::Triple("amdgcn-amd-amdhsa"); // Default HIP triple. } auto TT = getOffloadTargetTriple(D, Args); if (!TT) - return llvm::None; + return std::nullopt; if (TT->getArch() == llvm::Triple::amdgcn && TT->getVendor() == llvm::Triple::AMD && TT->getOS() == llvm::Triple::AMDHSA) @@ -154,7 +157,7 @@ getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) { if (TT->getArch() == llvm::Triple::spirv64) return TT; D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str(); - return llvm::None; + return std::nullopt; } // static @@ -177,23 +180,28 @@ std::string Driver::GetResourcesPath(StringRef BinaryPath, // path of the embedding binary, which for LLVM binaries will be in bin/. // ../lib gets us to lib/ in both cases. P = llvm::sys::path::parent_path(Dir); - llvm::sys::path::append(P, Twine("lib") + CLANG_LIBDIR_SUFFIX, "clang", - CLANG_VERSION_STRING); + // This search path is also created in the COFF driver of lld, so any + // changes here also needs to happen in lld/COFF/Driver.cpp + llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", + CLANG_VERSION_MAJOR_STRING); } - return std::string(P.str()); + return std::string(P); } Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, DiagnosticsEngine &Diags, std::string Title, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) : Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode), - SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None), + SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), + Offload(OffloadHostDevice), CXX20HeaderType(HeaderMode_None), + ModulesModeCXX20(false), LTOMode(LTOK_None), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false), - CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), - CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc), - CheckInputsExist(true), GenReproducer(false), + CCLogDiagnostics(false), CCGenDiagnostics(false), + CCPrintProcessStats(false), CCPrintInternalStats(false), + TargetTriple(TargetTriple), Saver(Alloc), PrependArg(nullptr), + CheckInputsExist(true), ProbePrecompiled(true), SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. if (!this->VFS) @@ -214,7 +222,11 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, SystemConfigDir = CLANG_CONFIG_FILE_SYSTEM_DIR; #endif #if defined(CLANG_CONFIG_FILE_USER_DIR) - UserConfigDir = CLANG_CONFIG_FILE_USER_DIR; + { + SmallString<128> P; + llvm::sys::fs::expand_tilde(CLANG_CONFIG_FILE_USER_DIR, P); + UserConfigDir = static_cast<std::string>(P); + } #endif // Compute the path to the resource directory. @@ -222,40 +234,30 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, } void Driver::setDriverMode(StringRef Value) { - static const std::string OptName = + static StringRef OptName = getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); - if (auto M = llvm::StringSwitch<llvm::Optional<DriverMode>>(Value) + if (auto M = llvm::StringSwitch<std::optional<DriverMode>>(Value) .Case("gcc", GCCMode) .Case("g++", GXXMode) .Case("cpp", CPPMode) .Case("cl", CLMode) .Case("flang", FlangMode) - .Default(None)) + .Case("dxc", DXCMode) + .Default(std::nullopt)) Mode = *M; else Diag(diag::err_drv_unsupported_option_argument) << OptName << Value; } InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, - bool IsClCompatMode, - bool &ContainsError) { + bool UseDriverMode, bool &ContainsError) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); ContainsError = false; - unsigned IncludedFlagsBitmask; - unsigned ExcludedFlagsBitmask; - std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = - getIncludeExcludeOptionFlagMasks(IsClCompatMode); - - // Make sure that Flang-only options don't pollute the Clang output - // TODO: Make sure that Clang-only options don't pollute Flang output - if (!IsFlangMode()) - ExcludedFlagsBitmask |= options::FlangOnlyOption; - + llvm::opt::Visibility VisibilityMask = getOptionVisibilityMask(UseDriverMode); unsigned MissingArgIndex, MissingArgCount; - InputArgList Args = - getOpts().ParseArgs(ArgStrings, MissingArgIndex, MissingArgCount, - IncludedFlagsBitmask, ExcludedFlagsBitmask); + InputArgList Args = getOpts().ParseArgs(ArgStrings, MissingArgIndex, + MissingArgCount, VisibilityMask); // Check for missing argument error. if (MissingArgCount) { @@ -269,19 +271,9 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, // Check for unsupported options. for (const Arg *A : Args) { if (A->getOption().hasFlag(options::Unsupported)) { - unsigned DiagID; - auto ArgString = A->getAsString(Args); - std::string Nearest; - if (getOpts().findNearest( - ArgString, Nearest, IncludedFlagsBitmask, - ExcludedFlagsBitmask | options::Unsupported) > 1) { - DiagID = diag::err_drv_unsupported_opt; - Diag(DiagID) << ArgString; - } else { - DiagID = diag::err_drv_unsupported_opt_with_suggestion; - Diag(DiagID) << ArgString << Nearest; - } - ContainsError |= Diags.getDiagnosticLevel(DiagID, SourceLocation()) > + Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args); + ContainsError |= Diags.getDiagnosticLevel(diag::err_drv_unsupported_opt, + SourceLocation()) > DiagnosticsEngine::Warning; continue; } @@ -299,11 +291,17 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, unsigned DiagID; auto ArgString = A->getAsString(Args); std::string Nearest; - if (getOpts().findNearest( - ArgString, Nearest, IncludedFlagsBitmask, ExcludedFlagsBitmask) > 1) { - DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl - : diag::err_drv_unknown_argument; - Diags.Report(DiagID) << ArgString; + if (getOpts().findNearest(ArgString, Nearest, VisibilityMask) > 1) { + if (!IsCLMode() && + getOpts().findExact(ArgString, Nearest, + llvm::opt::Visibility(options::CC1Option))) { + DiagID = diag::err_drv_unknown_argument_with_suggestion; + Diags.Report(DiagID) << ArgString << "-Xclang " + Nearest; + } else { + DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl + : diag::err_drv_unknown_argument; + Diags.Report(DiagID) << ArgString; + } } else { DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl_with_suggestion @@ -314,6 +312,18 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings, DiagnosticsEngine::Warning; } + for (const Arg *A : Args.filtered(options::OPT_o)) { + if (ArgStrings[A->getIndex()] == A->getSpelling()) + continue; + + // Warn on joined arguments that are similar to a long argument. + std::string ArgString = ArgStrings[A->getIndex()]; + std::string Nearest; + if (getOpts().findExact("-" + ArgString, Nearest, VisibilityMask)) + Diags.Report(diag::warn_drv_potentially_misspelled_joined_argument) + << A->getAsString(Args) << Nearest; + } + return Args; } @@ -333,11 +343,15 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, CCGenDiagnostics) { FinalPhase = phases::Preprocess; - // --precompile only runs up to precompilation. - } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) { + // --precompile only runs up to precompilation. + // Options that cause the output of C++20 compiled module interfaces or + // header units have the same effect. + } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile)) || + (PhaseArg = DAL.getLastArg(options::OPT_extract_api)) || + (PhaseArg = DAL.getLastArg(options::OPT_fmodule_header, + options::OPT_fmodule_header_EQ))) { FinalPhase = phases::Precompile; - - // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. + // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || (PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) || (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || @@ -346,8 +360,7 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || (PhaseArg = DAL.getLastArg(options::OPT__analyze)) || - (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) || - (PhaseArg = DAL.getLastArg(options::OPT_extract_api))) { + (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { FinalPhase = phases::Compile; // -S only runs up to the backend. @@ -467,6 +480,10 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { DAL->append(A); } + // DXC mode quits before assembly if an output object file isn't specified. + if (IsDXCMode() && !Args.hasArg(options::OPT_dxc_Fo)) + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S)); + // Enforce -static if -miamcu is present. if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_static)); @@ -509,40 +526,38 @@ static llvm::Triple computeTargetTriple(const Driver &D, if (Target.isOSBinFormatMachO()) { // If an explicit Darwin arch name is given, that trumps all. if (!DarwinArchName.empty()) { - tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName); + tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName, + Args); return Target; } // Handle the Darwin '-arch' flag. if (Arg *A = Args.getLastArg(options::OPT_arch)) { StringRef ArchName = A->getValue(); - tools::darwin::setTripleTypeForMachOArchName(Target, ArchName); + tools::darwin::setTripleTypeForMachOArchName(Target, ArchName, Args); } } // Handle pseudo-target flags '-mlittle-endian'/'-EL' and // '-mbig-endian'/'-EB'. - if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, - options::OPT_mbig_endian)) { - if (A->getOption().matches(options::OPT_mlittle_endian)) { - llvm::Triple LE = Target.getLittleEndianArchVariant(); - if (LE.getArch() != llvm::Triple::UnknownArch) - Target = std::move(LE); - } else { - llvm::Triple BE = Target.getBigEndianArchVariant(); - if (BE.getArch() != llvm::Triple::UnknownArch) - Target = std::move(BE); + if (Arg *A = Args.getLastArgNoClaim(options::OPT_mlittle_endian, + options::OPT_mbig_endian)) { + llvm::Triple T = A->getOption().matches(options::OPT_mlittle_endian) + ? Target.getLittleEndianArchVariant() + : Target.getBigEndianArchVariant(); + if (T.getArch() != llvm::Triple::UnknownArch) { + Target = std::move(T); + Args.claimAllArgs(options::OPT_mlittle_endian, options::OPT_mbig_endian); } } // Skip further flag support on OSes which don't support '-m32' or '-m64'. - if (Target.getArch() == llvm::Triple::tce || - Target.getOS() == llvm::Triple::Minix) + if (Target.getArch() == llvm::Triple::tce) return Target; // On AIX, the env OBJECT_MODE may affect the resulting arch variant. if (Target.isOSAIX()) { - if (Optional<std::string> ObjectModeValue = + if (std::optional<std::string> ObjectModeValue = llvm::sys::Process::GetEnv("OBJECT_MODE")) { StringRef ObjectMode = *ObjectModeValue; llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; @@ -560,13 +575,21 @@ static llvm::Triple computeTargetTriple(const Driver &D, } } + // The `-maix[32|64]` flags are only valid for AIX targets. + if (Arg *A = Args.getLastArgNoClaim(options::OPT_maix32, options::OPT_maix64); + A && !Target.isOSAIX()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << Target.str(); + // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, - options::OPT_m32, options::OPT_m16); + options::OPT_m32, options::OPT_m16, + options::OPT_maix32, options::OPT_maix64); if (A) { llvm::Triple::ArchType AT = llvm::Triple::UnknownArch; - if (A->getOption().matches(options::OPT_m64)) { + if (A->getOption().matches(options::OPT_m64) || + A->getOption().matches(options::OPT_maix64)) { AT = Target.get64BitArchVariant().getArch(); if (Target.getEnvironment() == llvm::Triple::GNUX32) Target.setEnvironment(llvm::Triple::GNU); @@ -579,7 +602,8 @@ static llvm::Triple computeTargetTriple(const Driver &D, Target.setEnvironment(llvm::Triple::MuslX32); else Target.setEnvironment(llvm::Triple::GNUX32); - } else if (A->getOption().matches(options::OPT_m32)) { + } else if (A->getOption().matches(options::OPT_m32) || + A->getOption().matches(options::OPT_maix32)) { AT = Target.get32BitArchVariant().getArch(); if (Target.getEnvironment() == llvm::Triple::GNUX32) Target.setEnvironment(llvm::Triple::GNU); @@ -619,36 +643,44 @@ static llvm::Triple computeTargetTriple(const Driver &D, // If target is MIPS adjust the target triple // accordingly to provided ABI name. - A = Args.getLastArg(options::OPT_mabi_EQ); - if (A && Target.isMIPS()) { - StringRef ABIName = A->getValue(); - if (ABIName == "32") { - Target = Target.get32BitArchVariant(); - if (Target.getEnvironment() == llvm::Triple::GNUABI64 || - Target.getEnvironment() == llvm::Triple::GNUABIN32) - Target.setEnvironment(llvm::Triple::GNU); - } else if (ABIName == "n32") { - Target = Target.get64BitArchVariant(); - if (Target.getEnvironment() == llvm::Triple::GNU || - Target.getEnvironment() == llvm::Triple::GNUABI64) - Target.setEnvironment(llvm::Triple::GNUABIN32); - } else if (ABIName == "64") { - Target = Target.get64BitArchVariant(); - if (Target.getEnvironment() == llvm::Triple::GNU || - Target.getEnvironment() == llvm::Triple::GNUABIN32) - Target.setEnvironment(llvm::Triple::GNUABI64); + if (Target.isMIPS()) { + if ((A = Args.getLastArg(options::OPT_mabi_EQ))) { + StringRef ABIName = A->getValue(); + if (ABIName == "32") { + Target = Target.get32BitArchVariant(); + if (Target.getEnvironment() == llvm::Triple::GNUABI64 || + Target.getEnvironment() == llvm::Triple::GNUABIN32) + Target.setEnvironment(llvm::Triple::GNU); + } else if (ABIName == "n32") { + Target = Target.get64BitArchVariant(); + if (Target.getEnvironment() == llvm::Triple::GNU || + Target.getEnvironment() == llvm::Triple::GNUABI64) + Target.setEnvironment(llvm::Triple::GNUABIN32); + } else if (ABIName == "64") { + Target = Target.get64BitArchVariant(); + if (Target.getEnvironment() == llvm::Triple::GNU || + Target.getEnvironment() == llvm::Triple::GNUABIN32) + Target.setEnvironment(llvm::Triple::GNUABI64); + } } } // If target is RISC-V adjust the target triple according to // provided architecture name - A = Args.getLastArg(options::OPT_march_EQ); - if (A && Target.isRISCV()) { - StringRef ArchName = A->getValue(); - if (ArchName.startswith_insensitive("rv32")) - Target.setArch(llvm::Triple::riscv32); - else if (ArchName.startswith_insensitive("rv64")) - Target.setArch(llvm::Triple::riscv64); + if (Target.isRISCV()) { + if (Args.hasArg(options::OPT_march_EQ) || + Args.hasArg(options::OPT_mcpu_EQ)) { + StringRef ArchName = tools::riscv::getRISCVArch(Args, Target); + auto ISAInfo = llvm::RISCVISAInfo::parseArchString( + ArchName, /*EnableExperimentalExtensions=*/true); + if (!llvm::errorToBool(ISAInfo.takeError())) { + unsigned XLen = (*ISAInfo)->getXLen(); + if (XLen == 32) + Target.setArch(llvm::Triple::riscv32); + else if (XLen == 64) + Target.setArch(llvm::Triple::riscv64); + } + } } return Target; @@ -672,7 +704,7 @@ static driver::LTOKind parseLTOMode(Driver &D, const llvm::opt::ArgList &Args, if (LTOMode == LTOK_Unknown) { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << A->getValue(); + << A->getSpelling() << A->getValue(); return LTOK_None; } return LTOMode; @@ -685,6 +717,17 @@ void Driver::setLTOMode(const llvm::opt::ArgList &Args) { OffloadLTOMode = parseLTOMode(*this, Args, options::OPT_foffload_lto_EQ, options::OPT_fno_offload_lto); + + // Try to enable `-foffload-lto=full` if `-fopenmp-target-jit` is on. + if (Args.hasFlag(options::OPT_fopenmp_target_jit, + options::OPT_fno_openmp_target_jit, false)) { + if (Arg *A = Args.getLastArg(options::OPT_foffload_lto_EQ, + options::OPT_fno_offload_lto)) + if (OffloadLTOMode != LTOK_Full) + Diag(diag::err_drv_incompatible_options) + << A->getSpelling() << "-fopenmp-target-jit"; + OffloadLTOMode = LTOK_Full; + } } /// Compute the desired OpenMP runtime from the flags provided. @@ -704,7 +747,7 @@ Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const { if (RT == OMPRT_Unknown) { if (A) Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << A->getValue(); + << A->getSpelling() << A->getValue(); else // FIXME: We could use a nicer diagnostic here. Diag(diag::err_drv_unsupported_opt) << "-fopenmp"; @@ -730,7 +773,8 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, [](std::pair<types::ID, const llvm::opt::Arg *> &I) { return types::isHIP(I.first); }) || - C.getInputArgs().hasArg(options::OPT_hip_link); + C.getInputArgs().hasArg(options::OPT_hip_link) || + C.getInputArgs().hasArg(options::OPT_hipstdpar); if (IsCuda && IsHIP) { Diag(clang::diag::err_drv_mix_cuda_hip); return; @@ -748,7 +792,13 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, auto &CudaTC = ToolChains[CudaTriple->str() + "/" + HostTriple.str()]; if (!CudaTC) { CudaTC = std::make_unique<toolchains::CudaToolChain>( - *this, *CudaTriple, *HostTC, C.getInputArgs(), OFK); + *this, *CudaTriple, *HostTC, C.getInputArgs()); + + // Emit a warning if the detected CUDA version is too new. + CudaInstallationDetector &CudaInstallation = + static_cast<toolchains::CudaToolChain &>(*CudaTC).CudaInstallation; + if (CudaInstallation.isValid()) + CudaInstallation.WarnIfUnsupportedVersion(); } C.addOffloadDeviceToolChain(CudaTC.get(), OFK); } else if (IsHIP) { @@ -773,76 +823,146 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, // OpenMP // // We need to generate an OpenMP toolchain if the user specified targets with - // the -fopenmp-targets option. - if (Arg *OpenMPTargets = - C.getInputArgs().getLastArg(options::OPT_fopenmp_targets_EQ)) { - if (OpenMPTargets->getNumValues()) { - // We expect that -fopenmp-targets is always used in conjunction with the - // option -fopenmp specifying a valid runtime with offloading support, - // i.e. libomp or libiomp. - bool HasValidOpenMPRuntime = C.getInputArgs().hasFlag( - options::OPT_fopenmp, options::OPT_fopenmp_EQ, - options::OPT_fno_openmp, false); - if (HasValidOpenMPRuntime) { - OpenMPRuntimeKind OpenMPKind = getOpenMPRuntime(C.getInputArgs()); - HasValidOpenMPRuntime = - OpenMPKind == OMPRT_OMP || OpenMPKind == OMPRT_IOMP5; + // the -fopenmp-targets option or used --offload-arch with OpenMP enabled. + bool IsOpenMPOffloading = + C.getInputArgs().hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false) && + (C.getInputArgs().hasArg(options::OPT_fopenmp_targets_EQ) || + C.getInputArgs().hasArg(options::OPT_offload_arch_EQ)); + if (IsOpenMPOffloading) { + // We expect that -fopenmp-targets is always used in conjunction with the + // option -fopenmp specifying a valid runtime with offloading support, i.e. + // libomp or libiomp. + OpenMPRuntimeKind RuntimeKind = getOpenMPRuntime(C.getInputArgs()); + if (RuntimeKind != OMPRT_OMP && RuntimeKind != OMPRT_IOMP5) { + Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets); + return; + } + + llvm::StringMap<llvm::DenseSet<StringRef>> DerivedArchs; + llvm::StringMap<StringRef> FoundNormalizedTriples; + std::multiset<StringRef> OpenMPTriples; + + // If the user specified -fopenmp-targets= we create a toolchain for each + // valid triple. Otherwise, if only --offload-arch= was specified we instead + // attempt to derive the appropriate toolchains from the arguments. + if (Arg *OpenMPTargets = + C.getInputArgs().getLastArg(options::OPT_fopenmp_targets_EQ)) { + if (OpenMPTargets && !OpenMPTargets->getNumValues()) { + Diag(clang::diag::warn_drv_empty_joined_argument) + << OpenMPTargets->getAsString(C.getInputArgs()); + return; + } + for (StringRef T : OpenMPTargets->getValues()) + OpenMPTriples.insert(T); + } else if (C.getInputArgs().hasArg(options::OPT_offload_arch_EQ) && + !IsHIP && !IsCuda) { + const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); + auto AMDTriple = getHIPOffloadTargetTriple(*this, C.getInputArgs()); + auto NVPTXTriple = getNVIDIAOffloadTargetTriple(*this, C.getInputArgs(), + HostTC->getTriple()); + + // Attempt to deduce the offloading triple from the set of architectures. + // We can only correctly deduce NVPTX / AMDGPU triples currently. We need + // to temporarily create these toolchains so that we can access tools for + // inferring architectures. + llvm::DenseSet<StringRef> Archs; + if (NVPTXTriple) { + auto TempTC = std::make_unique<toolchains::CudaToolChain>( + *this, *NVPTXTriple, *HostTC, C.getInputArgs()); + for (StringRef Arch : getOffloadArchs( + C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true)) + Archs.insert(Arch); + } + if (AMDTriple) { + auto TempTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>( + *this, *AMDTriple, *HostTC, C.getInputArgs()); + for (StringRef Arch : getOffloadArchs( + C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true)) + Archs.insert(Arch); + } + if (!AMDTriple && !NVPTXTriple) { + for (StringRef Arch : + getOffloadArchs(C, C.getArgs(), Action::OFK_OpenMP, nullptr, true)) + Archs.insert(Arch); } - if (HasValidOpenMPRuntime) { - llvm::StringMap<const char *> FoundNormalizedTriples; - for (const char *Val : OpenMPTargets->getValues()) { - llvm::Triple TT(ToolChain::getOpenMPTriple(Val)); - std::string NormalizedName = TT.normalize(); - - // Make sure we don't have a duplicate triple. - auto Duplicate = FoundNormalizedTriples.find(NormalizedName); - if (Duplicate != FoundNormalizedTriples.end()) { - Diag(clang::diag::warn_drv_omp_offload_target_duplicate) - << Val << Duplicate->second; - continue; - } + for (StringRef Arch : Archs) { + if (NVPTXTriple && IsNVIDIAGpuArch(StringToCudaArch( + getProcessorFromTargetID(*NVPTXTriple, Arch)))) { + DerivedArchs[NVPTXTriple->getTriple()].insert(Arch); + } else if (AMDTriple && + IsAMDGpuArch(StringToCudaArch( + getProcessorFromTargetID(*AMDTriple, Arch)))) { + DerivedArchs[AMDTriple->getTriple()].insert(Arch); + } else { + Diag(clang::diag::err_drv_failed_to_deduce_target_from_arch) << Arch; + return; + } + } - // Store the current triple so that we can check for duplicates in the - // following iterations. - FoundNormalizedTriples[NormalizedName] = Val; - - // If the specified target is invalid, emit a diagnostic. - if (TT.getArch() == llvm::Triple::UnknownArch) - Diag(clang::diag::err_drv_invalid_omp_target) << Val; - else { - const ToolChain *TC; - // Device toolchains have to be selected differently. They pair host - // and device in their implementation. - if (TT.isNVPTX() || TT.isAMDGCN()) { - const ToolChain *HostTC = - C.getSingleOffloadToolChain<Action::OFK_Host>(); - assert(HostTC && "Host toolchain should be always defined."); - auto &DeviceTC = - ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()]; - if (!DeviceTC) { - if (TT.isNVPTX()) - DeviceTC = std::make_unique<toolchains::CudaToolChain>( - *this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP); - else if (TT.isAMDGCN()) - DeviceTC = - std::make_unique<toolchains::AMDGPUOpenMPToolChain>( - *this, TT, *HostTC, C.getInputArgs()); - else - assert(DeviceTC && "Device toolchain not defined."); - } - - TC = DeviceTC.get(); - } else - TC = &getToolChain(C.getInputArgs(), TT); - C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP); + // If the set is empty then we failed to find a native architecture. + if (Archs.empty()) { + Diag(clang::diag::err_drv_failed_to_deduce_target_from_arch) + << "native"; + return; + } + + for (const auto &TripleAndArchs : DerivedArchs) + OpenMPTriples.insert(TripleAndArchs.first()); + } + + for (StringRef Val : OpenMPTriples) { + llvm::Triple TT(ToolChain::getOpenMPTriple(Val)); + std::string NormalizedName = TT.normalize(); + + // Make sure we don't have a duplicate triple. + auto Duplicate = FoundNormalizedTriples.find(NormalizedName); + if (Duplicate != FoundNormalizedTriples.end()) { + Diag(clang::diag::warn_drv_omp_offload_target_duplicate) + << Val << Duplicate->second; + continue; + } + + // Store the current triple so that we can check for duplicates in the + // following iterations. + FoundNormalizedTriples[NormalizedName] = Val; + + // If the specified target is invalid, emit a diagnostic. + if (TT.getArch() == llvm::Triple::UnknownArch) + Diag(clang::diag::err_drv_invalid_omp_target) << Val; + else { + const ToolChain *TC; + // Device toolchains have to be selected differently. They pair host + // and device in their implementation. + if (TT.isNVPTX() || TT.isAMDGCN()) { + const ToolChain *HostTC = + C.getSingleOffloadToolChain<Action::OFK_Host>(); + assert(HostTC && "Host toolchain should be always defined."); + auto &DeviceTC = + ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()]; + if (!DeviceTC) { + if (TT.isNVPTX()) + DeviceTC = std::make_unique<toolchains::CudaToolChain>( + *this, TT, *HostTC, C.getInputArgs()); + else if (TT.isAMDGCN()) + DeviceTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>( + *this, TT, *HostTC, C.getInputArgs()); + else + assert(DeviceTC && "Device toolchain not defined."); } - } - } else - Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets); - } else - Diag(clang::diag::warn_drv_empty_joined_argument) - << OpenMPTargets->getAsString(C.getInputArgs()); + + TC = DeviceTC.get(); + } else + TC = &getToolChain(C.getInputArgs(), TT); + C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP); + if (DerivedArchs.contains(TT.getTriple())) + KnownArchs[TC] = DerivedArchs[TT.getTriple()]; + } + } + } else if (C.getInputArgs().hasArg(options::OPT_fopenmp_targets_EQ)) { + Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets); + return; } // @@ -850,69 +970,78 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, // } -/// Looks the given directories for the specified file. -/// -/// \param[out] FilePath File path, if the file was found. -/// \param[in] Dirs Directories used for the search. -/// \param[in] FileName Name of the file to search for. -/// \return True if file was found. -/// -/// Looks for file specified by FileName sequentially in directories specified -/// by Dirs. -/// -static bool searchForFile(SmallVectorImpl<char> &FilePath, - ArrayRef<StringRef> Dirs, StringRef FileName) { - SmallString<128> WPath; - for (const StringRef &Dir : Dirs) { - if (Dir.empty()) - continue; - WPath.clear(); - llvm::sys::path::append(WPath, Dir, FileName); - llvm::sys::path::native(WPath); - if (llvm::sys::fs::is_regular_file(WPath)) { - FilePath = std::move(WPath); - return true; - } - } - return false; +static void appendOneArg(InputArgList &Args, const Arg *Opt, + const Arg *BaseArg) { + // The args for config files or /clang: flags belong to different InputArgList + // objects than Args. This copies an Arg from one of those other InputArgLists + // to the ownership of Args. + unsigned Index = Args.MakeIndex(Opt->getSpelling()); + Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index), + Index, BaseArg); + Copy->getValues() = Opt->getValues(); + if (Opt->isClaimed()) + Copy->claim(); + Copy->setOwnsValues(Opt->getOwnsValues()); + Opt->setOwnsValues(false); + Args.append(Copy); } -bool Driver::readConfigFile(StringRef FileName) { +bool Driver::readConfigFile(StringRef FileName, + llvm::cl::ExpansionContext &ExpCtx) { + // Try opening the given file. + auto Status = getVFS().status(FileName); + if (!Status) { + Diag(diag::err_drv_cannot_open_config_file) + << FileName << Status.getError().message(); + return true; + } + if (Status->getType() != llvm::sys::fs::file_type::regular_file) { + Diag(diag::err_drv_cannot_open_config_file) + << FileName << "not a regular file"; + return true; + } + // Try reading the given file. SmallVector<const char *, 32> NewCfgArgs; - if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs)) { - Diag(diag::err_drv_cannot_read_config_file) << FileName; + if (llvm::Error Err = ExpCtx.readConfigFile(FileName, NewCfgArgs)) { + Diag(diag::err_drv_cannot_read_config_file) + << FileName << toString(std::move(Err)); return true; } // Read options from config file. llvm::SmallString<128> CfgFileName(FileName); llvm::sys::path::native(CfgFileName); - ConfigFile = std::string(CfgFileName); bool ContainErrors; - CfgOptions = std::make_unique<InputArgList>( - ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors)); - if (ContainErrors) { - CfgOptions.reset(); + std::unique_ptr<InputArgList> NewOptions = std::make_unique<InputArgList>( + ParseArgStrings(NewCfgArgs, /*UseDriverMode=*/true, ContainErrors)); + if (ContainErrors) return true; - } - - if (CfgOptions->hasArg(options::OPT_config)) { - CfgOptions.reset(); - Diag(diag::err_drv_nested_config_file); - return true; - } // Claim all arguments that come from a configuration file so that the driver // does not warn on any that is unused. - for (Arg *A : *CfgOptions) + for (Arg *A : *NewOptions) A->claim(); + + if (!CfgOptions) + CfgOptions = std::move(NewOptions); + else { + // If this is a subsequent config file, append options to the previous one. + for (auto *Opt : *NewOptions) { + const Arg *BaseArg = &Opt->getBaseArg(); + if (BaseArg == Opt) + BaseArg = nullptr; + appendOneArg(*CfgOptions, Opt, BaseArg); + } + } + ConfigFiles.push_back(std::string(CfgFileName)); return false; } -bool Driver::loadConfigFile() { - std::string CfgFileName; - bool FileSpecifiedExplicitly = false; +bool Driver::loadConfigFiles() { + llvm::cl::ExpansionContext ExpCtx(Saver.getAllocator(), + llvm::cl::tokenizeConfigFile); + ExpCtx.setVFS(&getVFS()); // Process options that change search path for config files. if (CLOptions) { @@ -920,143 +1049,141 @@ bool Driver::loadConfigFile() { SmallString<128> CfgDir; CfgDir.append( CLOptions->getLastArgValue(options::OPT_config_system_dir_EQ)); - if (!CfgDir.empty()) { - if (llvm::sys::fs::make_absolute(CfgDir).value() != 0) - SystemConfigDir.clear(); - else - SystemConfigDir = std::string(CfgDir.begin(), CfgDir.end()); - } + if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir)) + SystemConfigDir.clear(); + else + SystemConfigDir = static_cast<std::string>(CfgDir); } if (CLOptions->hasArg(options::OPT_config_user_dir_EQ)) { SmallString<128> CfgDir; - CfgDir.append( - CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ)); - if (!CfgDir.empty()) { - if (llvm::sys::fs::make_absolute(CfgDir).value() != 0) - UserConfigDir.clear(); - else - UserConfigDir = std::string(CfgDir.begin(), CfgDir.end()); - } + llvm::sys::fs::expand_tilde( + CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ), CfgDir); + if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir)) + UserConfigDir.clear(); + else + UserConfigDir = static_cast<std::string>(CfgDir); } } - // First try to find config file specified in command line. - if (CLOptions) { - std::vector<std::string> ConfigFiles = - CLOptions->getAllArgValues(options::OPT_config); - if (ConfigFiles.size() > 1) { - if (!llvm::all_of(ConfigFiles, [ConfigFiles](const std::string &s) { - return s == ConfigFiles[0]; - })) { - Diag(diag::err_drv_duplicate_config); - return true; - } - } + // Prepare list of directories where config file is searched for. + StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir}; + ExpCtx.setSearchDirs(CfgFileSearchDirs); - if (!ConfigFiles.empty()) { - CfgFileName = ConfigFiles.front(); - assert(!CfgFileName.empty()); + // First try to load configuration from the default files, return on error. + if (loadDefaultConfigFiles(ExpCtx)) + return true; + // Then load configuration files specified explicitly. + SmallString<128> CfgFilePath; + if (CLOptions) { + for (auto CfgFileName : CLOptions->getAllArgValues(options::OPT_config)) { // If argument contains directory separator, treat it as a path to // configuration file. if (llvm::sys::path::has_parent_path(CfgFileName)) { - SmallString<128> CfgFilePath; - if (llvm::sys::path::is_relative(CfgFileName)) - llvm::sys::fs::current_path(CfgFilePath); - llvm::sys::path::append(CfgFilePath, CfgFileName); - if (!llvm::sys::fs::is_regular_file(CfgFilePath)) { - Diag(diag::err_drv_config_file_not_exist) << CfgFilePath; - return true; + CfgFilePath.assign(CfgFileName); + if (llvm::sys::path::is_relative(CfgFilePath)) { + if (getVFS().makeAbsolute(CfgFilePath)) { + Diag(diag::err_drv_cannot_open_config_file) + << CfgFilePath << "cannot get absolute path"; + return true; + } } - return readConfigFile(CfgFilePath); + } else if (!ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) { + // Report an error that the config file could not be found. + Diag(diag::err_drv_config_file_not_found) << CfgFileName; + for (const StringRef &SearchDir : CfgFileSearchDirs) + if (!SearchDir.empty()) + Diag(diag::note_drv_config_file_searched_in) << SearchDir; + return true; } - FileSpecifiedExplicitly = true; + // Try to read the config file, return on error. + if (readConfigFile(CfgFilePath, ExpCtx)) + return true; } } - // If config file is not specified explicitly, try to deduce configuration - // from executable name. For instance, an executable 'armv7l-clang' will - // search for config file 'armv7l-clang.cfg'. - if (CfgFileName.empty() && !ClangNameParts.TargetPrefix.empty()) - CfgFileName = ClangNameParts.TargetPrefix + '-' + ClangNameParts.ModeSuffix; + // No error occurred. + return false; +} - if (CfgFileName.empty()) +bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) { + // Disable default config if CLANG_NO_DEFAULT_CONFIG is set to a non-empty + // value. + if (const char *NoConfigEnv = ::getenv("CLANG_NO_DEFAULT_CONFIG")) { + if (*NoConfigEnv) + return false; + } + if (CLOptions && CLOptions->hasArg(options::OPT_no_default_config)) return false; - // Determine architecture part of the file name, if it is present. - StringRef CfgFileArch = CfgFileName; - size_t ArchPrefixLen = CfgFileArch.find('-'); - if (ArchPrefixLen == StringRef::npos) - ArchPrefixLen = CfgFileArch.size(); - llvm::Triple CfgTriple; - CfgFileArch = CfgFileArch.take_front(ArchPrefixLen); - CfgTriple = llvm::Triple(llvm::Triple::normalize(CfgFileArch)); - if (CfgTriple.getArch() == llvm::Triple::ArchType::UnknownArch) - ArchPrefixLen = 0; - - if (!StringRef(CfgFileName).endswith(".cfg")) - CfgFileName += ".cfg"; - - // If config file starts with architecture name and command line options - // redefine architecture (with options like -m32 -LE etc), try finding new - // config file with that architecture. - SmallString<128> FixedConfigFile; - size_t FixedArchPrefixLen = 0; - if (ArchPrefixLen) { - // Get architecture name from config file name like 'i386.cfg' or - // 'armv7l-clang.cfg'. - // Check if command line options changes effective triple. - llvm::Triple EffectiveTriple = computeTargetTriple(*this, - CfgTriple.getTriple(), *CLOptions); - if (CfgTriple.getArch() != EffectiveTriple.getArch()) { - FixedConfigFile = EffectiveTriple.getArchName(); - FixedArchPrefixLen = FixedConfigFile.size(); - // Append the rest of original file name so that file name transforms - // like: i386-clang.cfg -> x86_64-clang.cfg. - if (ArchPrefixLen < CfgFileName.size()) - FixedConfigFile += CfgFileName.substr(ArchPrefixLen); - } + std::string RealMode = getExecutableForDriverMode(Mode); + std::string Triple; + + // If name prefix is present, no --target= override was passed via CLOptions + // and the name prefix is not a valid triple, force it for backwards + // compatibility. + if (!ClangNameParts.TargetPrefix.empty() && + computeTargetTriple(*this, "/invalid/", *CLOptions).str() == + "/invalid/") { + llvm::Triple PrefixTriple{ClangNameParts.TargetPrefix}; + if (PrefixTriple.getArch() == llvm::Triple::UnknownArch || + PrefixTriple.isOSUnknown()) + Triple = PrefixTriple.str(); + } + + // Otherwise, use the real triple as used by the driver. + if (Triple.empty()) { + llvm::Triple RealTriple = + computeTargetTriple(*this, TargetTriple, *CLOptions); + Triple = RealTriple.str(); + assert(!Triple.empty()); + } + + // Search for config files in the following order: + // 1. <triple>-<mode>.cfg using real driver mode + // (e.g. i386-pc-linux-gnu-clang++.cfg). + // 2. <triple>-<mode>.cfg using executable suffix + // (e.g. i386-pc-linux-gnu-clang-g++.cfg for *clang-g++). + // 3. <triple>.cfg + <mode>.cfg using real driver mode + // (e.g. i386-pc-linux-gnu.cfg + clang++.cfg). + // 4. <triple>.cfg + <mode>.cfg using executable suffix + // (e.g. i386-pc-linux-gnu.cfg + clang-g++.cfg for *clang-g++). + + // Try loading <triple>-<mode>.cfg, and return if we find a match. + SmallString<128> CfgFilePath; + std::string CfgFileName = Triple + '-' + RealMode + ".cfg"; + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) + return readConfigFile(CfgFilePath, ExpCtx); + + bool TryModeSuffix = !ClangNameParts.ModeSuffix.empty() && + ClangNameParts.ModeSuffix != RealMode; + if (TryModeSuffix) { + CfgFileName = Triple + '-' + ClangNameParts.ModeSuffix + ".cfg"; + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) + return readConfigFile(CfgFilePath, ExpCtx); + } + + // Try loading <mode>.cfg, and return if loading failed. If a matching file + // was not found, still proceed on to try <triple>.cfg. + CfgFileName = RealMode + ".cfg"; + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) { + if (readConfigFile(CfgFilePath, ExpCtx)) + return true; + } else if (TryModeSuffix) { + CfgFileName = ClangNameParts.ModeSuffix + ".cfg"; + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath) && + readConfigFile(CfgFilePath, ExpCtx)) + return true; } - // Prepare list of directories where config file is searched for. - StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir}; - - // Try to find config file. First try file with corrected architecture. - llvm::SmallString<128> CfgFilePath; - if (!FixedConfigFile.empty()) { - if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile)) - return readConfigFile(CfgFilePath); - // If 'x86_64-clang.cfg' was not found, try 'x86_64.cfg'. - FixedConfigFile.resize(FixedArchPrefixLen); - FixedConfigFile.append(".cfg"); - if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile)) - return readConfigFile(CfgFilePath); - } - - // Then try original file name. - if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName)) - return readConfigFile(CfgFilePath); - - // Finally try removing driver mode part: 'x86_64-clang.cfg' -> 'x86_64.cfg'. - if (!ClangNameParts.ModeSuffix.empty() && - !ClangNameParts.TargetPrefix.empty()) { - CfgFileName.assign(ClangNameParts.TargetPrefix); - CfgFileName.append(".cfg"); - if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName)) - return readConfigFile(CfgFilePath); - } - - // Report error but only if config file was specified explicitly, by option - // --config. If it was deduced from executable name, it is not an error. - if (FileSpecifiedExplicitly) { - Diag(diag::err_drv_config_file_not_found) << CfgFileName; - for (const StringRef &SearchDir : CfgFileSearchDirs) - if (!SearchDir.empty()) - Diag(diag::note_drv_config_file_searched_in) << SearchDir; - return true; - } + // Try loading <triple>.cfg and return if we find a match. + CfgFileName = Triple + ".cfg"; + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) + return readConfigFile(CfgFilePath, ExpCtx); + // If we were unable to find a config file deduced from executable name, + // that is not an error. return false; } @@ -1078,32 +1205,17 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // Arguments specified in command line. bool ContainsError; CLOptions = std::make_unique<InputArgList>( - ParseArgStrings(ArgList.slice(1), IsCLMode(), ContainsError)); + ParseArgStrings(ArgList.slice(1), /*UseDriverMode=*/true, ContainsError)); // Try parsing configuration file. if (!ContainsError) - ContainsError = loadConfigFile(); + ContainsError = loadConfigFiles(); bool HasConfigFile = !ContainsError && (CfgOptions.get() != nullptr); // All arguments, from both config file and command line. InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions) : std::move(*CLOptions)); - // The args for config files or /clang: flags belong to different InputArgList - // objects than Args. This copies an Arg from one of those other InputArgLists - // to the ownership of Args. - auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) { - unsigned Index = Args.MakeIndex(Opt->getSpelling()); - Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index), - Index, BaseArg); - Copy->getValues() = Opt->getValues(); - if (Opt->isClaimed()) - Copy->claim(); - Copy->setOwnsValues(Opt->getOwnsValues()); - Opt->setOwnsValues(false); - Args.append(Copy); - }; - if (HasConfigFile) for (auto *Opt : *CLOptions) { if (Opt->getOption().matches(options::OPT_config)) @@ -1111,7 +1223,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { const Arg *BaseArg = &Opt->getBaseArg(); if (BaseArg == Opt) BaseArg = nullptr; - appendOneArg(Opt, BaseArg); + appendOneArg(Args, Opt, BaseArg); } // In CL mode, look for any pass-through arguments @@ -1126,11 +1238,12 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // Parse any pass through args using default clang processing rather // than clang-cl processing. auto CLModePassThroughOptions = std::make_unique<InputArgList>( - ParseArgStrings(CLModePassThroughArgList, false, ContainsError)); + ParseArgStrings(CLModePassThroughArgList, /*UseDriverMode=*/false, + ContainsError)); if (!ContainsError) for (auto *Opt : *CLModePassThroughOptions) { - appendOneArg(Opt, nullptr); + appendOneArg(Args, Opt, nullptr); } } } @@ -1143,9 +1256,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // FIXME: This stuff needs to go into the Compilation, not the driver. bool CCCPrintPhases; - // Silence driver warnings if requested - Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w)); - // -canonical-prefixes, -no-canonical-prefixes are used very early in main. Args.ClaimAllArgs(options::OPT_canonical_prefixes); Args.ClaimAllArgs(options::OPT_no_canonical_prefixes); @@ -1167,9 +1277,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { CCCPrintBindings = Args.hasArg(options::OPT_ccc_print_bindings); if (const Arg *A = Args.getLastArg(options::OPT_ccc_gcc_name)) CCCGenericGCCName = A->getValue(); - GenReproducer = Args.hasFlag(options::OPT_gen_reproducer, - options::OPT_fno_crash_diagnostics, - !!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")); // Process -fproc-stat-report options. if (const Arg *A = Args.getLastArg(options::OPT_fproc_stat_report_EQ)) { @@ -1188,8 +1295,45 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { T.setVendor(llvm::Triple::PC); T.setEnvironment(llvm::Triple::MSVC); T.setObjectFormat(llvm::Triple::COFF); + if (Args.hasArg(options::OPT__SLASH_arm64EC)) + T.setArch(llvm::Triple::aarch64, llvm::Triple::AArch64SubArch_arm64ec); TargetTriple = T.str(); + } else if (IsDXCMode()) { + // Build TargetTriple from target_profile option for clang-dxc. + if (const Arg *A = Args.getLastArg(options::OPT_target_profile)) { + StringRef TargetProfile = A->getValue(); + if (auto Triple = + toolchains::HLSLToolChain::parseTargetProfile(TargetProfile)) + TargetTriple = *Triple; + else + Diag(diag::err_drv_invalid_directx_shader_module) << TargetProfile; + + A->claim(); + + if (Args.hasArg(options::OPT_spirv)) { + llvm::Triple T(TargetTriple); + T.setArch(llvm::Triple::spirv); + T.setOS(llvm::Triple::Vulkan); + + // Set specific Vulkan version if applicable. + if (const Arg *A = Args.getLastArg(options::OPT_fspv_target_env_EQ)) { + const llvm::StringSet<> ValidValues = {"vulkan1.2", "vulkan1.3"}; + if (ValidValues.contains(A->getValue())) { + T.setOSName(A->getValue()); + } else { + Diag(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + } + A->claim(); + } + + TargetTriple = T.str(); + } + } else { + Diag(diag::err_drv_dxc_missing_target_profile); + } } + if (const Arg *A = Args.getLastArg(options::OPT_target)) TargetTriple = A->getValue(); if (const Arg *A = Args.getLastArg(options::OPT_ccc_install_dir)) @@ -1198,7 +1342,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { A->claim(); PrefixDirs.push_back(A->getValue(0)); } - if (Optional<std::string> CompilerPathValue = + if (std::optional<std::string> CompilerPathValue = llvm::sys::Process::GetEnv("COMPILER_PATH")) { StringRef CompilerPath = *CompilerPathValue; while (!CompilerPath.empty()) { @@ -1223,6 +1367,17 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { .Default(SaveTempsCwd); } + if (const Arg *A = Args.getLastArg(options::OPT_offload_host_only, + options::OPT_offload_device_only, + options::OPT_offload_host_device)) { + if (A->getOption().matches(options::OPT_offload_host_only)) + Offload = OffloadHost; + else if (A->getOption().matches(options::OPT_offload_device_only)) + Offload = OffloadDevice; + else + Offload = OffloadHostDevice; + } + setLTOMode(Args); // Process -fembed-bitcode= flags. @@ -1241,6 +1396,43 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { BitcodeEmbed = static_cast<BitcodeEmbedMode>(Model); } + // Remove existing compilation database so that each job can append to it. + if (Arg *A = Args.getLastArg(options::OPT_MJ)) + llvm::sys::fs::remove(A->getValue()); + + // Setting up the jobs for some precompile cases depends on whether we are + // treating them as PCH, implicit modules or C++20 ones. + // TODO: inferring the mode like this seems fragile (it meets the objective + // of not requiring anything new for operation, however). + const Arg *Std = Args.getLastArg(options::OPT_std_EQ); + ModulesModeCXX20 = + !Args.hasArg(options::OPT_fmodules) && Std && + (Std->containsValue("c++20") || Std->containsValue("c++2a") || + Std->containsValue("c++23") || Std->containsValue("c++2b") || + Std->containsValue("c++26") || Std->containsValue("c++2c") || + Std->containsValue("c++latest")); + + // Process -fmodule-header{=} flags. + if (Arg *A = Args.getLastArg(options::OPT_fmodule_header_EQ, + options::OPT_fmodule_header)) { + // These flags force C++20 handling of headers. + ModulesModeCXX20 = true; + if (A->getOption().matches(options::OPT_fmodule_header)) + CXX20HeaderType = HeaderMode_Default; + else { + StringRef ArgName = A->getValue(); + unsigned Kind = llvm::StringSwitch<unsigned>(ArgName) + .Case("user", HeaderMode_User) + .Case("system", HeaderMode_System) + .Default(~0U); + if (Kind == ~0U) { + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << ArgName; + } else + CXX20HeaderType = static_cast<ModuleHeaderMode>(Kind); + } + } + std::unique_ptr<llvm::opt::InputArgList> UArgs = std::make_unique<InputArgList>(std::move(Args)); @@ -1251,6 +1443,55 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { const ToolChain &TC = getToolChain( *UArgs, computeTargetTriple(*this, TargetTriple, *UArgs)); + if (TC.getTriple().isAndroid()) { + llvm::Triple Triple = TC.getTriple(); + StringRef TripleVersionName = Triple.getEnvironmentVersionString(); + + if (Triple.getEnvironmentVersion().empty() && TripleVersionName != "") { + Diags.Report(diag::err_drv_triple_version_invalid) + << TripleVersionName << TC.getTripleString(); + ContainsError = true; + } + } + + // Report warning when arm64EC option is overridden by specified target + if ((TC.getTriple().getArch() != llvm::Triple::aarch64 || + TC.getTriple().getSubArch() != llvm::Triple::AArch64SubArch_arm64ec) && + UArgs->hasArg(options::OPT__SLASH_arm64EC)) { + getDiags().Report(clang::diag::warn_target_override_arm64ec) + << TC.getTriple().str(); + } + + // A common user mistake is specifying a target of aarch64-none-eabi or + // arm-none-elf whereas the correct names are aarch64-none-elf & + // arm-none-eabi. Detect these cases and issue a warning. + if (TC.getTriple().getOS() == llvm::Triple::UnknownOS && + TC.getTriple().getVendor() == llvm::Triple::UnknownVendor) { + switch (TC.getTriple().getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + if (TC.getTriple().getEnvironmentName() == "elf") { + Diag(diag::warn_target_unrecognized_env) + << TargetTriple + << (TC.getTriple().getArchName().str() + "-none-eabi"); + } + break; + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::aarch64_32: + if (TC.getTriple().getEnvironmentName().starts_with("eabi")) { + Diag(diag::warn_target_unrecognized_env) + << TargetTriple + << (TC.getTriple().getArchName().str() + "-none-elf"); + } + break; + default: + break; + } + } + // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs, ContainsError); @@ -1311,7 +1552,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename, // (or /Library/Logs/DiagnosticReports for root) and has the filename pattern // clang-<VERSION>_<YYYY-MM-DD-HHMMSS>_<hostname>.crash. path::home_directory(CrashDiagDir); - if (CrashDiagDir.startswith("/var/root")) + if (CrashDiagDir.starts_with("/var/root")) CrashDiagDir = "/"; path::append(CrashDiagDir, "Library/Logs/DiagnosticReports"); int PID = @@ -1329,7 +1570,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename, for (fs::directory_iterator File(CrashDiagDir, EC), FileEnd; File != FileEnd && !EC; File.increment(EC)) { StringRef FileName = path::filename(File->path()); - if (!FileName.startswith(Name)) + if (!FileName.starts_with(Name)) continue; if (fs::status(File->path(), FileStatus)) continue; @@ -1340,7 +1581,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename, // The first line should start with "Process:", otherwise this isn't a real // .crash file. StringRef Data = CrashFile.get()->getBuffer(); - if (!Data.startswith("Process:")) + if (!Data.starts_with("Process:")) continue; // Parse parent process pid line, e.g: "Parent Process: clang-4.0 [79141]" size_t ParentProcPos = Data.find("Parent Process:"); @@ -1390,6 +1631,11 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename, return false; } +static const char BugReporMsg[] = + "\n********************\n\n" + "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n" + "Preprocessed source(s) and associated run script(s) are located at:"; + // When clang crashes, produce diagnostic information including the fully // preprocessed source file(s). Request that the developer attach the // diagnostic information to a bug report. @@ -1399,11 +1645,36 @@ void Driver::generateCompilationDiagnostics( if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics)) return; - // Don't try to generate diagnostics for link or dsymutil jobs. - if (FailingCommand.getCreator().isLinkJob() || - FailingCommand.getCreator().isDsymutilJob()) + unsigned Level = 1; + if (Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_EQ)) { + Level = llvm::StringSwitch<unsigned>(A->getValue()) + .Case("off", 0) + .Case("compiler", 1) + .Case("all", 2) + .Default(1); + } + if (!Level) + return; + + // Don't try to generate diagnostics for dsymutil jobs. + if (FailingCommand.getCreator().isDsymutilJob()) return; + bool IsLLD = false; + ArgStringList SavedTemps; + if (FailingCommand.getCreator().isLinkJob()) { + C.getDefaultToolChain().GetLinkerPath(&IsLLD); + if (!IsLLD || Level < 2) + return; + + // If lld crashed, we will re-run the same command with the input it used + // to have. In that case we should not remove temp files in + // initCompilationForDiagnostics yet. They will be added back and removed + // later. + SavedTemps = std::move(C.getTempFiles()); + assert(!C.getTempFiles().size()); + } + // Print the version of the compiler. PrintVersion(C, llvm::errs()); @@ -1420,6 +1691,29 @@ void Driver::generateCompilationDiagnostics( // Suppress tool output. C.initCompilationForDiagnostics(); + // If lld failed, rerun it again with --reproduce. + if (IsLLD) { + const char *TmpName = CreateTempFile(C, "linker-crash", "tar"); + Command NewLLDInvocation = Cmd; + llvm::opt::ArgStringList ArgList = NewLLDInvocation.getArguments(); + StringRef ReproduceOption = + C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment() + ? "/reproduce:" + : "--reproduce="; + ArgList.push_back(Saver.save(Twine(ReproduceOption) + TmpName).data()); + NewLLDInvocation.replaceArguments(std::move(ArgList)); + + // Redirect stdout/stderr to /dev/null. + NewLLDInvocation.Execute({std::nullopt, {""}, {""}}, nullptr, nullptr); + Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg; + Diag(clang::diag::note_drv_command_failed_diag_msg) << TmpName; + Diag(clang::diag::note_drv_command_failed_diag_msg) + << "\n\n********************"; + if (Report) + Report->TemporaryFiles.push_back(TmpName); + return; + } + // Construct the list of inputs. InputList Inputs; BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs); @@ -1504,10 +1798,7 @@ void Driver::generateCompilationDiagnostics( return; } - Diag(clang::diag::note_drv_command_failed_diag_msg) - << "\n********************\n\n" - "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n" - "Preprocessed source(s) and associated run script(s) are located at:"; + Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg; SmallString<128> VFS; SmallString<128> ReproCrashFilename; @@ -1519,7 +1810,7 @@ void Driver::generateCompilationDiagnostics( ReproCrashFilename = TempFile; llvm::sys::path::replace_extension(ReproCrashFilename, ".crash"); } - if (StringRef(TempFile).endswith(".cache")) { + if (StringRef(TempFile).ends_with(".cache")) { // In some cases (modules) we'll dump extra data to help with reproducing // the crash into a directory next to the output. VFS = llvm::sys::path::filename(TempFile); @@ -1527,6 +1818,9 @@ void Driver::generateCompilationDiagnostics( } } + for (const char *TempFile : SavedTemps) + C.addTempFile(TempFile); + // Assume associated files are based off of the first temporary file. CrashReportInfo CrashInfo(TempFiles[0], VFS); @@ -1550,7 +1844,7 @@ void Driver::generateCompilationDiagnostics( ScriptOS << "\n# Additional information: " << AdditionalInformation << "\n"; if (Report) - Report->TemporaryFiles.push_back(std::string(Script.str())); + Report->TemporaryFiles.push_back(std::string(Script)); Diag(clang::diag::note_drv_command_failed_diag_msg) << Script; } @@ -1572,9 +1866,6 @@ void Driver::generateCompilationDiagnostics( } } - for (const auto &A : C.getArgs().filtered(options::OPT_frewrite_map_file_EQ)) - Diag(clang::diag::note_drv_command_failed_diag_msg) << A->getValue(); - Diag(clang::diag::note_drv_command_failed_diag_msg) << "\n\n********************"; } @@ -1597,10 +1888,23 @@ void Driver::setUpResponseFiles(Compilation &C, Command &Cmd) { int Driver::ExecuteCompilation( Compilation &C, SmallVectorImpl<std::pair<int, const Command *>> &FailingCommands) { + if (C.getArgs().hasArg(options::OPT_fdriver_only)) { + if (C.getArgs().hasArg(options::OPT_v)) + C.getJobs().Print(llvm::errs(), "\n", true); + + C.ExecuteJobs(C.getJobs(), FailingCommands, /*LogOnly=*/true); + + // If there were errors building the compilation, quit now. + if (!FailingCommands.empty() || Diags.hasErrorOccurred()) + return 1; + + return 0; + } + // Just print if -### was present. if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { C.getJobs().Print(llvm::errs(), "\n", true); - return 0; + return Diags.hasErrorOccurred() ? 1 : 0; } // If there were errors building the compilation, quit now. @@ -1634,14 +1938,12 @@ int Driver::ExecuteCompilation( C.CleanupFileMap(C.getFailureResultFiles(), JA, true); } -#if LLVM_ON_UNIX - // llvm/lib/Support/Unix/Signals.inc will exit with a special return code + // llvm/lib/Support/*/Signals.inc will exit with a special return code // for SIGPIPE. Do not print diagnostics for this case. if (CommandRes == EX_IOERR) { Res = CommandRes; continue; } -#endif // Print extra information about abnormal failures, if possible. // @@ -1666,24 +1968,12 @@ int Driver::ExecuteCompilation( } void Driver::PrintHelp(bool ShowHidden) const { - unsigned IncludedFlagsBitmask; - unsigned ExcludedFlagsBitmask; - std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = - getIncludeExcludeOptionFlagMasks(IsCLMode()); - - ExcludedFlagsBitmask |= options::NoDriverOption; - if (!ShowHidden) - ExcludedFlagsBitmask |= HelpHidden; - - if (IsFlangMode()) - IncludedFlagsBitmask |= options::FlangOption; - else - ExcludedFlagsBitmask |= options::FlangOnlyOption; + llvm::opt::Visibility VisibilityMask = getOptionVisibilityMask(); std::string Usage = llvm::formatv("{0} [options] file...", Name).str(); getOpts().printHelp(llvm::outs(), Usage.c_str(), DriverTitle.c_str(), - IncludedFlagsBitmask, ExcludedFlagsBitmask, - /*ShowAllAliases=*/false); + ShowHidden, /*ShowAllAliases=*/false, + VisibilityMask); } void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { @@ -1709,8 +1999,8 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { // Print out the install directory. OS << "InstalledDir: " << InstalledDir << '\n'; - // If configuration file was used, print its path. - if (!ConfigFile.empty()) + // If configuration files were used, print their paths. + for (auto ConfigFile : ConfigFiles) OS << "Configuration file: " << ConfigFile << '\n'; } @@ -1731,18 +2021,17 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { std::vector<std::string> SuggestedCompletions; std::vector<std::string> Flags; - unsigned int DisableFlags = - options::NoDriverOption | options::Unsupported | options::Ignored; + llvm::opt::Visibility VisibilityMask(options::ClangOption); // Make sure that Flang-only options don't pollute the Clang output // TODO: Make sure that Clang-only options don't pollute Flang output - if (!IsFlangMode()) - DisableFlags |= options::FlangOnlyOption; + if (IsFlangMode()) + VisibilityMask = llvm::opt::Visibility(options::FlangOption); // Distinguish "--autocomplete=-someflag" and "--autocomplete=-someflag," // because the latter indicates that the user put space before pushing tab // which should end up in a file completion. - const bool HasSpace = PassedFlags.endswith(","); + const bool HasSpace = PassedFlags.ends_with(","); // Parse PassedFlags by "," as all the command-line flags are passed to this // function separated by "," @@ -1756,7 +2045,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { // We want to show cc1-only options only when clang is invoked with -cc1 or // -Xclang. if (llvm::is_contained(Flags, "-Xclang") || llvm::is_contained(Flags, "-cc1")) - DisableFlags &= ~options::NoDriverOption; + VisibilityMask = llvm::opt::Visibility(options::CC1Option); const llvm::opt::OptTable &Opts = getOpts(); StringRef Cur; @@ -1782,17 +2071,19 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const { // When flag ends with '=' and there was no value completion, return empty // string and fall back to the file autocompletion. - if (SuggestedCompletions.empty() && !Cur.endswith("=")) { + if (SuggestedCompletions.empty() && !Cur.ends_with("=")) { // If the flag is in the form of "--autocomplete=-foo", // we were requested to print out all option names that start with "-foo". // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". - SuggestedCompletions = Opts.findByPrefix(Cur, DisableFlags); + SuggestedCompletions = Opts.findByPrefix( + Cur, VisibilityMask, + /*DisableFlags=*/options::Unsupported | options::Ignored); // We have to query the -W flags manually as they're not in the OptTable. // TODO: Find a good way to add them to OptTable instead and them remove // this code. for (StringRef S : DiagnosticIDs::getDiagnosticFlags()) - if (S.startswith(Cur)) + if (S.starts_with(Cur)) SuggestedCompletions.push_back(std::string(S)); } @@ -1844,7 +2135,8 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { if (C.getArgs().hasArg(options::OPT_v) || C.getArgs().hasArg(options::OPT__HASH_HASH_HASH) || - C.getArgs().hasArg(options::OPT_print_supported_cpus)) { + C.getArgs().hasArg(options::OPT_print_supported_cpus) || + C.getArgs().hasArg(options::OPT_print_supported_extensions)) { PrintVersion(C, llvm::errs()); SuppressMissingInputWarning = true; } @@ -1903,21 +2195,20 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } if (C.getArgs().hasArg(options::OPT_print_runtime_dir)) { - std::string RuntimePath; - // Get the first existing path, if any. - for (auto Path : TC.getRuntimePaths()) { - if (getVFS().exists(Path)) { - RuntimePath = Path; - break; - } - } - if (!RuntimePath.empty()) - llvm::outs() << RuntimePath << '\n'; + if (std::optional<std::string> RuntimePath = TC.getRuntimePath()) + llvm::outs() << *RuntimePath << '\n'; else llvm::outs() << TC.getCompilerRTPath() << '\n'; return false; } + if (C.getArgs().hasArg(options::OPT_print_diagnostic_options)) { + std::vector<std::string> Flags = DiagnosticIDs::getDiagnosticFlags(); + for (std::size_t I = 0; I != Flags.size(); I += 2) + llvm::outs() << " " << Flags[I] << "\n " << Flags[I + 1] << "\n\n"; + return false; + } + // FIXME: The following handlers should use a callback mechanism, we don't // know what the client would like to do. if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) { @@ -1963,14 +2254,26 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { return false; } + if (C.getArgs().hasArg(options::OPT_print_multi_flags)) { + Multilib::flags_list ArgFlags = TC.getMultilibFlags(C.getArgs()); + llvm::StringSet<> ExpandedFlags = TC.getMultilibs().expandFlags(ArgFlags); + std::set<llvm::StringRef> SortedFlags; + for (const auto &FlagEntry : ExpandedFlags) + SortedFlags.insert(FlagEntry.getKey()); + for (auto Flag : SortedFlags) + llvm::outs() << Flag << '\n'; + return false; + } + if (C.getArgs().hasArg(options::OPT_print_multi_directory)) { - const Multilib &Multilib = TC.getMultilib(); - if (Multilib.gccSuffix().empty()) - llvm::outs() << ".\n"; - else { - StringRef Suffix(Multilib.gccSuffix()); - assert(Suffix.front() == '/'); - llvm::outs() << Suffix.substr(1) << "\n"; + for (const Multilib &Multilib : TC.getSelectedMultilibs()) { + if (Multilib.gccSuffix().empty()) + llvm::outs() << ".\n"; + else { + StringRef Suffix(Multilib.gccSuffix()); + assert(Suffix.front() == '/'); + llvm::outs() << Suffix.substr(1) << "\n"; + } } return false; } @@ -1986,12 +2289,6 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { return false; } - if (C.getArgs().hasArg(options::OPT_print_multiarch)) { - llvm::outs() << TC.getMultiarchTriple(*this, TC.getTriple(), SysRoot) - << "\n"; - return false; - } - if (C.getArgs().hasArg(options::OPT_print_targets)) { llvm::TargetRegistry::printRegisteredTargetsForVersion(llvm::outs()); return false; @@ -2209,6 +2506,14 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, if (Value == "-") return true; + // If it's a header to be found in the system or user search path, then defer + // complaints about its absence until those searches can be done. When we + // are definitely processing headers for C++20 header units, extend this to + // allow the user to put "-fmodule-header -xc++-header vector" for example. + if (Ty == types::TY_CXXSHeader || Ty == types::TY_CXXUHeader || + (ModulesModeCXX20 && Ty == types::TY_CXXHeader)) + return true; + if (getVFS().exists(Value)) return true; @@ -2218,13 +2523,8 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, // filenames, but e.g. `/diagnostic:caret` is more likely a typo for // the option `/diagnostics:caret` than a reference to a file in the root // directory. - unsigned IncludedFlagsBitmask; - unsigned ExcludedFlagsBitmask; - std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = - getIncludeExcludeOptionFlagMasks(IsCLMode()); std::string Nearest; - if (getOpts().findNearest(Value, Nearest, IncludedFlagsBitmask, - ExcludedFlagsBitmask) <= 1) { + if (getOpts().findNearest(Value, Nearest, getOptionVisibilityMask()) <= 1) { Diag(clang::diag::err_drv_no_such_file_with_suggestion) << Value << Nearest; return false; @@ -2235,7 +2535,7 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, // they can be influenced by linker flags the clang driver might not // understand. // Examples: - // - `clang-cl main.cc ole32.lib` in a a non-MSVC shell will make the driver + // - `clang-cl main.cc ole32.lib` in a non-MSVC shell will make the driver // module look for an MSVC installation in the registry. (We could ask // the MSVCToolChain object if it can find `ole32.lib`, but the logic to // look in the registry might move into lld-link in the future so that @@ -2265,13 +2565,28 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, // so we can't downgrade diagnostics for `/GR-` from an error to a warning // in cc mode. (We can in cl mode because cl.exe itself only warns on // unknown flags.) - if (IsCLMode() && Ty == types::TY_Object && !Value.startswith("/")) + if (IsCLMode() && Ty == types::TY_Object && !Value.starts_with("/")) return true; Diag(clang::diag::err_drv_no_such_file) << Value; return false; } +// Get the C++20 Header Unit type corresponding to the input type. +static types::ID CXXHeaderUnitType(ModuleHeaderMode HM) { + switch (HM) { + case HeaderMode_User: + return types::TY_CXXUHeader; + case HeaderMode_System: + return types::TY_CXXSHeader; + case HeaderMode_Default: + break; + case HeaderMode_None: + llvm_unreachable("should not be called in this case"); + } + return types::TY_CXXHUHeader; +} + // Construct a the list of inputs and their types. void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, InputList &Inputs) const { @@ -2295,17 +2610,32 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, for (Arg *A : Args.filtered(options::OPT__SLASH_TC, options::OPT__SLASH_TP)) { if (Previous) { - Diag(clang::diag::warn_drv_overriding_flag_option) - << Previous->getSpelling() << A->getSpelling(); + Diag(clang::diag::warn_drv_overriding_option) + << Previous->getSpelling() << A->getSpelling(); ShowNote = true; } Previous = A; } if (ShowNote) Diag(clang::diag::note_drv_t_option_is_global); + } - // No driver mode exposes -x and /TC or /TP; we don't support mixing them. - assert(!Args.hasArg(options::OPT_x) && "-x and /TC or /TP is not allowed"); + // CUDA/HIP and their preprocessor expansions can be accepted by CL mode. + // Warn -x after last input file has no effect + auto LastXArg = Args.getLastArgValue(options::OPT_x); + const llvm::StringSet<> ValidXArgs = {"cuda", "hip", "cui", "hipi"}; + if (!IsCLMode() || ValidXArgs.contains(LastXArg)) { + Arg *LastXArg = Args.getLastArgNoClaim(options::OPT_x); + Arg *LastInputArg = Args.getLastArgNoClaim(options::OPT_INPUT); + if (LastXArg && LastInputArg && + LastInputArg->getIndex() < LastXArg->getIndex()) + Diag(clang::diag::warn_drv_unused_x) << LastXArg->getValue(); + } else { + // In CL mode suggest /TC or /TP since -x doesn't make sense if passed via + // /clang:. + if (auto *A = Args.getLastArg(options::OPT_x)) + Diag(diag::err_drv_unsupported_opt_with_suggestion) + << A->getAsString(Args) << "/TC' or '/TP"; } for (Arg *A : Args) { @@ -2323,6 +2653,8 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, if (memcmp(Value, "-", 2) == 0) { if (IsFlangMode()) { Ty = types::TY_Fortran; + } else if (IsDXCMode()) { + Ty = types::TY_HLSL; } else { // If running with -E, treat as a C input (this changes the // builtin macros, for example). This may be overridden by -ObjC @@ -2360,7 +2692,9 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, types::ID OldTy = Ty; Ty = types::lookupCXXTypeForCType(Ty); - if (Ty != OldTy) + // Do not complain about foo.h, when we are known to be processing + // it as a C++20 header unit. + if (Ty != OldTy && !(OldTy == types::TY_CHeader && hasHeaderMode())) Diag(clang::diag::warn_drv_treating_input_as_cxx) << getTypeName(OldTy) << getTypeName(Ty); } @@ -2383,6 +2717,14 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, else if (Args.hasArg(options::OPT_ObjCXX)) Ty = types::TY_ObjCXX; } + + // Disambiguate headers that are meant to be header units from those + // intended to be PCH. Avoid missing '.h' cases that are counted as + // C headers by default - we know we are in C++ mode and we do not + // want to issue a complaint about compiling things in the wrong mode. + if ((Ty == types::TY_CXXHeader || Ty == types::TY_CHeader) && + hasHeaderMode()) + Ty = CXXHeaderUnitType(CXX20HeaderType); } else { assert(InputTypeArg && "InputType set w/o InputTypeArg"); if (!InputTypeArg->getOption().matches(options::OPT_x)) { @@ -2398,6 +2740,10 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, } } + if ((Ty == types::TY_C || Ty == types::TY_CXX) && + Args.hasArgNoClaim(options::OPT_hipstdpar)) + Ty = types::TY_HIP; + if (DiagnoseInputExistence(Args, Value, Ty, /*TypoCorrect=*/true)) Inputs.push_back(std::make_pair(Ty, A)); @@ -2434,6 +2780,11 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Diag(clang::diag::err_drv_unknown_language) << A->getValue(); InputType = types::TY_Object; } + + // If the user has put -fmodule-header{,=} then we treat C++ headers as + // header unit inputs. So we 'promote' -xc++-header appropriately. + if (InputType == types::TY_CXXHeader && hasHeaderMode()) + InputType = CXXHeaderUnitType(CXX20HeaderType); } else if (A->getOption().getID() == options::OPT_U) { assert(A->getNumValues() == 1 && "The /U option has one value."); StringRef Val = A->getValue(0); @@ -2465,6 +2816,9 @@ class OffloadingActionBuilder final { /// Map between an input argument and the offload kinds used to process it. std::map<const Arg *, unsigned> InputArgToOffloadKindMap; + /// Map between a host action and its originating input argument. + std::map<Action *, const Arg *> HostActionToInputArgMap; + /// Builder interface. It doesn't build anything or keep any state. class DeviceActionBuilder { public: @@ -2517,7 +2871,7 @@ class OffloadingActionBuilder final { /// Update the state to include the provided host action \a HostAction as a /// dependency of the current device action. By default it is inactive. - virtual ActionBuilderReturnCode addDeviceDepences(Action *HostAction) { + virtual ActionBuilderReturnCode addDeviceDependences(Action *HostAction) { return ABRT_Inactive; } @@ -2603,9 +2957,14 @@ class OffloadingActionBuilder final { CudaActionBuilderBase(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs, Action::OffloadKind OFKind) - : DeviceActionBuilder(C, Args, Inputs, OFKind) {} + : DeviceActionBuilder(C, Args, Inputs, OFKind) { - ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override { + CompileDeviceOnly = C.getDriver().offloadDeviceOnly(); + Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, + options::OPT_fno_gpu_rdc, /*Default=*/false); + } + + ActionBuilderReturnCode addDeviceDependences(Action *HostAction) override { // While generating code for CUDA, we only depend on the host input action // to trigger the creation of all the CUDA device actions. @@ -2679,12 +3038,16 @@ class OffloadingActionBuilder final { std::string FileName = IA->getInputArg().getAsString(Args); // Check if the type of the file is the same as the action. Do not // unbundle it if it is not. Do not unbundle .so files, for example, - // which are not object files. + // which are not object files. Files with extension ".lib" is classified + // as TY_Object but they are actually archives, therefore should not be + // unbundled here as objects. They will be handled at other places. + const StringRef LibFileExt = ".lib"; if (IA->getType() == types::TY_Object && (!llvm::sys::path::has_extension(FileName) || types::lookupTypeForExtension( llvm::sys::path::extension(FileName).drop_front()) != - types::TY_Object)) + types::TY_Object || + llvm::sys::path::extension(FileName) == LibFileExt)) return ABRT_Inactive; for (auto Arch : GpuArchList) { @@ -2692,6 +3055,7 @@ class OffloadingActionBuilder final { UA->registerDependentActionInfo(ToolChains[0], Arch, AssociatedOffloadKind); } + IsActive = true; return ABRT_Success; } @@ -2734,7 +3098,7 @@ class OffloadingActionBuilder final { /// option is invalid. virtual StringRef getCanonicalOffloadArch(StringRef Arch) = 0; - virtual llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> + virtual std::optional<std::pair<llvm::StringRef, llvm::StringRef>> getConflictOffloadArchCombination(const std::set<StringRef> &GpuArchs) = 0; bool initialize() override { @@ -2751,9 +3115,6 @@ class OffloadingActionBuilder final { !C.hasOffloadToolChain<Action::OFK_HIP>()) return false; - Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, - options::OPT_fno_gpu_rdc, /*Default=*/false); - const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>(); assert(HostTC && "No toolchain for host compilation."); if (HostTC->getTriple().isNVPTX() || @@ -2771,15 +3132,7 @@ class OffloadingActionBuilder final { ? C.getSingleOffloadToolChain<Action::OFK_Cuda>() : C.getSingleOffloadToolChain<Action::OFK_HIP>()); - Arg *PartialCompilationArg = Args.getLastArg( - options::OPT_cuda_host_only, options::OPT_cuda_device_only, - options::OPT_cuda_compile_host_device); - CompileHostOnly = PartialCompilationArg && - PartialCompilationArg->getOption().matches( - options::OPT_cuda_host_only); - CompileDeviceOnly = PartialCompilationArg && - PartialCompilationArg->getOption().matches( - options::OPT_cuda_device_only); + CompileHostOnly = C.getDriver().offloadHostOnly(); EmitLLVM = Args.getLastArg(options::OPT_emit_llvm); EmitAsm = Args.getLastArg(options::OPT_S); FixedCUID = Args.getLastArgValue(options::OPT_cuid_EQ); @@ -2806,7 +3159,7 @@ class OffloadingActionBuilder final { << "--offload"; } - // Collect all cuda_gpu_arch parameters, removing duplicates. + // Collect all offload arch parameters, removing duplicates. std::set<StringRef> GpuArchs; bool Error = false; for (Arg *A : Args) { @@ -2815,28 +3168,41 @@ class OffloadingActionBuilder final { continue; A->claim(); - StringRef ArchStr = A->getValue(); - if (A->getOption().matches(options::OPT_no_offload_arch_EQ) && - ArchStr == "all") { - GpuArchs.clear(); - continue; + for (StringRef ArchStr : llvm::split(A->getValue(), ",")) { + if (A->getOption().matches(options::OPT_no_offload_arch_EQ) && + ArchStr == "all") { + GpuArchs.clear(); + } else if (ArchStr == "native") { + const ToolChain &TC = *ToolChains.front(); + auto GPUsOrErr = ToolChains.front()->getSystemGPUArchs(Args); + if (!GPUsOrErr) { + TC.getDriver().Diag(diag::err_drv_undetermined_gpu_arch) + << llvm::Triple::getArchTypeName(TC.getArch()) + << llvm::toString(GPUsOrErr.takeError()) << "--offload-arch"; + continue; + } + + for (auto GPU : *GPUsOrErr) { + GpuArchs.insert(Args.MakeArgString(GPU)); + } + } else { + ArchStr = getCanonicalOffloadArch(ArchStr); + if (ArchStr.empty()) { + Error = true; + } else if (A->getOption().matches(options::OPT_offload_arch_EQ)) + GpuArchs.insert(ArchStr); + else if (A->getOption().matches(options::OPT_no_offload_arch_EQ)) + GpuArchs.erase(ArchStr); + else + llvm_unreachable("Unexpected option."); + } } - ArchStr = getCanonicalOffloadArch(ArchStr); - if (ArchStr.empty()) { - Error = true; - } else if (A->getOption().matches(options::OPT_offload_arch_EQ)) - GpuArchs.insert(ArchStr); - else if (A->getOption().matches(options::OPT_no_offload_arch_EQ)) - GpuArchs.erase(ArchStr); - else - llvm_unreachable("Unexpected option."); } auto &&ConflictingArchs = getConflictOffloadArchCombination(GpuArchs); if (ConflictingArchs) { C.getDriver().Diag(clang::diag::err_drv_bad_offload_arch_combo) - << ConflictingArchs.getValue().first - << ConflictingArchs.getValue().second; + << ConflictingArchs->first << ConflictingArchs->second; C.setContainsError(); return true; } @@ -2878,10 +3244,10 @@ class OffloadingActionBuilder final { return CudaArchToString(Arch); } - llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> + std::optional<std::pair<llvm::StringRef, llvm::StringRef>> getConflictOffloadArchCombination( const std::set<StringRef> &GpuArchs) override { - return llvm::None; + return std::nullopt; } ActionBuilderReturnCode @@ -2997,17 +3363,41 @@ class OffloadingActionBuilder final { // Bundle code objects except --no-gpu-output is specified for device // only compilation. Bundle other type of output files only if // --gpu-bundle-output is specified for device only compilation. - Optional<bool> BundleOutput; + std::optional<bool> BundleOutput; + std::optional<bool> EmitReloc; public: HIPActionBuilder(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs) : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) { - DefaultCudaArch = CudaArch::GFX803; + + DefaultCudaArch = CudaArch::GFX906; + + if (Args.hasArg(options::OPT_fhip_emit_relocatable, + options::OPT_fno_hip_emit_relocatable)) { + EmitReloc = Args.hasFlag(options::OPT_fhip_emit_relocatable, + options::OPT_fno_hip_emit_relocatable, false); + + if (*EmitReloc) { + if (Relocatable) { + C.getDriver().Diag(diag::err_opt_not_valid_with_opt) + << "-fhip-emit-relocatable" + << "-fgpu-rdc"; + } + + if (!CompileDeviceOnly) { + C.getDriver().Diag(diag::err_opt_not_valid_without_opt) + << "-fhip-emit-relocatable" + << "--cuda-device-only"; + } + } + } + if (Args.hasArg(options::OPT_gpu_bundle_output, options::OPT_no_gpu_bundle_output)) BundleOutput = Args.hasFlag(options::OPT_gpu_bundle_output, - options::OPT_no_gpu_bundle_output); + options::OPT_no_gpu_bundle_output, true) && + (!EmitReloc || !*EmitReloc); } bool canUseBundlerUnbundler() const override { return true; } @@ -3024,11 +3414,11 @@ class OffloadingActionBuilder final { C.setContainsError(); return StringRef(); } - auto CanId = getCanonicalTargetID(ArchStr.getValue(), Features); + auto CanId = getCanonicalTargetID(*ArchStr, Features); return Args.MakeArgStringRef(CanId); }; - llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> + std::optional<std::pair<llvm::StringRef, llvm::StringRef>> getConflictOffloadArchCombination( const std::set<StringRef> &GpuArchs) override { return getConflictTargetIDCombination(GpuArchs); @@ -3038,9 +3428,12 @@ class OffloadingActionBuilder final { getDeviceDependences(OffloadAction::DeviceDependences &DA, phases::ID CurPhase, phases::ID FinalPhase, PhasesTy &Phases) override { + if (!IsActive) + return ABRT_Inactive; + // amdgcn does not support linking of object files, therefore we skip // backend and assemble phases to output LLVM IR. Except for generating - // non-relocatable device coee, where we generate fat binary for device + // non-relocatable device code, where we generate fat binary for device // code and pass to host in Backend phase. if (CudaDeviceActions.empty()) return ABRT_Success; @@ -3049,10 +3442,12 @@ class OffloadingActionBuilder final { CudaDeviceActions.size() == GpuArchList.size()) && "Expecting one action per GPU architecture."); assert(!CompileHostOnly && - "Not expecting CUDA actions in host-only compilation."); + "Not expecting HIP actions in host-only compilation."); + + bool ShouldLink = !EmitReloc || !*EmitReloc; if (!Relocatable && CurPhase == phases::Backend && !EmitLLVM && - !EmitAsm) { + !EmitAsm && ShouldLink) { // If we are in backend phase, we attempt to generate the fat binary. // We compile each arch to IR and use a link action to generate code // object containing ISA. Then we use a special "link" action to create @@ -3108,8 +3503,7 @@ class OffloadingActionBuilder final { DDep, CudaDeviceActions[I]->getType()); } - if (!CompileDeviceOnly || !BundleOutput.hasValue() || - BundleOutput.getValue()) { + if (!CompileDeviceOnly || !BundleOutput || *BundleOutput) { // Create HIP fat binary with a special "link" action. CudaFatBinary = C.MakeAction<LinkJobAction>(CudaDeviceActions, types::TY_HIP_FATBIN); @@ -3129,6 +3523,8 @@ class OffloadingActionBuilder final { return CompileDeviceOnly ? ABRT_Ignore_Host : ABRT_Success; } else if (CurPhase == phases::Link) { + if (!ShouldLink) + return ABRT_Success; // Save CudaDeviceActions to DeviceLinkerInputs for each GPU subarch. // This happens to each device action originated from each input file. // Later on, device actions in DeviceLinkerInputs are used to create @@ -3152,8 +3548,8 @@ class OffloadingActionBuilder final { A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A, AssociatedOffloadKind); - if (CompileDeviceOnly && CurPhase == FinalPhase && - BundleOutput.hasValue() && BundleOutput.getValue()) { + if (CompileDeviceOnly && CurPhase == FinalPhase && BundleOutput && + *BundleOutput) { for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { OffloadAction::DeviceDependences DDep; DDep.add(*CudaDeviceActions[I], *ToolChains.front(), GpuArchList[I], @@ -3166,8 +3562,11 @@ class OffloadingActionBuilder final { CudaDeviceActions.clear(); } - return (CompileDeviceOnly && CurPhase == FinalPhase) ? ABRT_Ignore_Host - : ABRT_Success; + return (CompileDeviceOnly && + (CurPhase == FinalPhase || + (!ShouldLink && CurPhase == phases::Assemble))) + ? ABRT_Ignore_Host + : ABRT_Success; } void appendLinkDeviceActions(ActionList &AL) override { @@ -3178,12 +3577,16 @@ class OffloadingActionBuilder final { "Linker inputs and GPU arch list sizes do not match."); ActionList Actions; - // Append a new link action for each device. unsigned I = 0; + // Append a new link action for each device. + // Each entry in DeviceLinkerInputs corresponds to a GPU arch. for (auto &LI : DeviceLinkerInputs) { - // Each entry in DeviceLinkerInputs corresponds to a GPU arch. - auto *DeviceLinkAction = - C.MakeAction<LinkJobAction>(LI, types::TY_Image); + + types::ID Output = Args.hasArg(options::OPT_emit_llvm) + ? types::TY_LLVM_BC + : types::TY_Image; + + auto *DeviceLinkAction = C.MakeAction<LinkJobAction>(LI, Output); // Linking all inputs for the current GPU arch. // LI contains all the inputs for the linker. OffloadAction::DeviceDependences DeviceLinkDeps; @@ -3195,12 +3598,17 @@ class OffloadingActionBuilder final { } DeviceLinkerInputs.clear(); + // If emitting LLVM, do not generate final host/device compilation action + if (Args.hasArg(options::OPT_emit_llvm)) { + AL.append(Actions); + return; + } + // Create a host object from all the device images by embedding them // in a fat binary for mixed host-device compilation. For device-only // compilation, creates a fat binary. OffloadAction::DeviceDependences DDeps; - if (!CompileDeviceOnly || !BundleOutput.hasValue() || - BundleOutput.getValue()) { + if (!CompileDeviceOnly || !BundleOutput || *BundleOutput) { auto *TopDeviceLinkAction = C.MakeAction<LinkJobAction>( Actions, CompileDeviceOnly ? types::TY_HIP_FATBIN : types::TY_Object); @@ -3219,178 +3627,6 @@ class OffloadingActionBuilder final { void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {} }; - /// OpenMP action builder. The host bitcode is passed to the device frontend - /// and all the device linked images are passed to the host link phase. - class OpenMPActionBuilder final : public DeviceActionBuilder { - /// The OpenMP actions for the current input. - ActionList OpenMPDeviceActions; - - /// The linker inputs obtained for each toolchain. - SmallVector<ActionList, 8> DeviceLinkerInputs; - - public: - OpenMPActionBuilder(Compilation &C, DerivedArgList &Args, - const Driver::InputList &Inputs) - : DeviceActionBuilder(C, Args, Inputs, Action::OFK_OpenMP) {} - - ActionBuilderReturnCode - getDeviceDependences(OffloadAction::DeviceDependences &DA, - phases::ID CurPhase, phases::ID FinalPhase, - PhasesTy &Phases) override { - if (OpenMPDeviceActions.empty()) - return ABRT_Inactive; - - // We should always have an action for each input. - assert(OpenMPDeviceActions.size() == ToolChains.size() && - "Number of OpenMP actions and toolchains do not match."); - - // The host only depends on device action in the linking phase, when all - // the device images have to be embedded in the host image. - if (CurPhase == phases::Link) { - assert(ToolChains.size() == DeviceLinkerInputs.size() && - "Toolchains and linker inputs sizes do not match."); - auto LI = DeviceLinkerInputs.begin(); - for (auto *A : OpenMPDeviceActions) { - LI->push_back(A); - ++LI; - } - - // We passed the device action as a host dependence, so we don't need to - // do anything else with them. - OpenMPDeviceActions.clear(); - return ABRT_Success; - } - - // By default, we produce an action for each device arch. - for (Action *&A : OpenMPDeviceActions) - A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A); - - return ABRT_Success; - } - - ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override { - - // If this is an input action replicate it for each OpenMP toolchain. - if (auto *IA = dyn_cast<InputAction>(HostAction)) { - OpenMPDeviceActions.clear(); - for (unsigned I = 0; I < ToolChains.size(); ++I) - OpenMPDeviceActions.push_back( - C.MakeAction<InputAction>(IA->getInputArg(), IA->getType())); - return ABRT_Success; - } - - // If this is an unbundling action use it as is for each OpenMP toolchain. - if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) { - OpenMPDeviceActions.clear(); - auto *IA = cast<InputAction>(UA->getInputs().back()); - std::string FileName = IA->getInputArg().getAsString(Args); - // Check if the type of the file is the same as the action. Do not - // unbundle it if it is not. Do not unbundle .so files, for example, - // which are not object files. - if (IA->getType() == types::TY_Object && - (!llvm::sys::path::has_extension(FileName) || - types::lookupTypeForExtension( - llvm::sys::path::extension(FileName).drop_front()) != - types::TY_Object)) - return ABRT_Inactive; - for (unsigned I = 0; I < ToolChains.size(); ++I) { - OpenMPDeviceActions.push_back(UA); - UA->registerDependentActionInfo( - ToolChains[I], /*BoundArch=*/StringRef(), Action::OFK_OpenMP); - } - return ABRT_Success; - } - - // When generating code for OpenMP we use the host compile phase result as - // a dependence to the device compile phase so that it can learn what - // declarations should be emitted. However, this is not the only use for - // the host action, so we prevent it from being collapsed. - if (isa<CompileJobAction>(HostAction)) { - HostAction->setCannotBeCollapsedWithNextDependentAction(); - assert(ToolChains.size() == OpenMPDeviceActions.size() && - "Toolchains and device action sizes do not match."); - OffloadAction::HostDependence HDep( - *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), - /*BoundArch=*/nullptr, Action::OFK_OpenMP); - auto TC = ToolChains.begin(); - for (Action *&A : OpenMPDeviceActions) { - assert(isa<CompileJobAction>(A)); - OffloadAction::DeviceDependences DDep; - DDep.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP); - A = C.MakeAction<OffloadAction>(HDep, DDep); - ++TC; - } - } - return ABRT_Success; - } - - void appendTopLevelActions(ActionList &AL) override { - if (OpenMPDeviceActions.empty()) - return; - - // We should always have an action for each input. - assert(OpenMPDeviceActions.size() == ToolChains.size() && - "Number of OpenMP actions and toolchains do not match."); - - // Append all device actions followed by the proper offload action. - auto TI = ToolChains.begin(); - for (auto *A : OpenMPDeviceActions) { - OffloadAction::DeviceDependences Dep; - Dep.add(*A, **TI, /*BoundArch=*/nullptr, Action::OFK_OpenMP); - AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType())); - ++TI; - } - // We no longer need the action stored in this builder. - OpenMPDeviceActions.clear(); - } - - void appendLinkDeviceActions(ActionList &AL) override { - assert(ToolChains.size() == DeviceLinkerInputs.size() && - "Toolchains and linker inputs sizes do not match."); - - // Append a new link action for each device. - auto TC = ToolChains.begin(); - for (auto &LI : DeviceLinkerInputs) { - auto *DeviceLinkAction = - C.MakeAction<LinkJobAction>(LI, types::TY_Image); - OffloadAction::DeviceDependences DeviceLinkDeps; - DeviceLinkDeps.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr, - Action::OFK_OpenMP); - AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps, - DeviceLinkAction->getType())); - ++TC; - } - DeviceLinkerInputs.clear(); - } - - Action* appendLinkHostActions(ActionList &AL) override { - // Create wrapper bitcode from the result of device link actions and compile - // it to an object which will be added to the host link command. - auto *BC = C.MakeAction<OffloadWrapperJobAction>(AL, types::TY_LLVM_BC); - auto *ASM = C.MakeAction<BackendJobAction>(BC, types::TY_PP_Asm); - return C.MakeAction<AssembleJobAction>(ASM, types::TY_Object); - } - - void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {} - - bool initialize() override { - // Get the OpenMP toolchains. If we don't get any, the action builder will - // know there is nothing to do related to OpenMP offloading. - auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); - for (auto TI = OpenMPTCRange.first, TE = OpenMPTCRange.second; TI != TE; - ++TI) - ToolChains.push_back(TI->second); - - DeviceLinkerInputs.resize(ToolChains.size()); - return false; - } - - bool canUseBundlerUnbundler() const override { - // OpenMP should use bundled files whenever possible. - return true; - } - }; - /// /// TODO: Add the implementation for other specialized builders here. /// @@ -3415,9 +3651,6 @@ public: // Create a specialized builder for HIP. SpecializedBuilders.push_back(new HIPActionBuilder(C, Args, Inputs)); - // Create a specialized builder for OpenMP. - SpecializedBuilders.push_back(new OpenMPActionBuilder(C, Args, Inputs)); - // // TODO: Build other specialized builders here. // @@ -3445,6 +3678,17 @@ public: delete SB; } + /// Record a host action and its originating input argument. + void recordHostAction(Action *HostAction, const Arg *InputArg) { + assert(HostAction && "Invalid host action"); + assert(InputArg && "Invalid input argument"); + auto Loc = HostActionToInputArgMap.find(HostAction); + if (Loc == HostActionToInputArgMap.end()) + HostActionToInputArgMap[HostAction] = InputArg; + assert(HostActionToInputArgMap[HostAction] == InputArg && + "host action mapped to multiple input arguments"); + } + /// Generate an action that adds device dependences (if any) to a host action. /// If no device dependence actions exist, just return the host action \a /// HostAction. If an error is found or if no builder requires the host action @@ -3460,6 +3704,7 @@ public: return HostAction; assert(HostAction && "Invalid host action!"); + recordHostAction(HostAction, InputArg); OffloadAction::DeviceDependences DDeps; // Check if all the programming models agree we should not emit the host @@ -3472,7 +3717,6 @@ public: ++InactiveBuilders; continue; } - auto RetCode = SB->getDeviceDependences(DDeps, CurPhase, FinalPhase, Phases); @@ -3513,6 +3757,8 @@ public: if (!IsValid) return true; + recordHostAction(HostAction, InputArg); + // If we are supporting bundling/unbundling and the current action is an // input action of non-source file, we replace the host action by the // unbundling action. The bundler tool has the logic to detect if an input @@ -3529,6 +3775,7 @@ public: C.getSingleOffloadToolChain<Action::OFK_Host>(), /*BoundArch=*/StringRef(), Action::OFK_Host); HostAction = UnbundlingHostAction; + recordHostAction(HostAction, InputArg); } assert(HostAction && "Invalid host action!"); @@ -3539,7 +3786,7 @@ public: if (!SB->isValid()) continue; - auto RetCode = SB->addDeviceDepences(HostAction); + auto RetCode = SB->addDeviceDependences(HostAction); // Host dependences for device actions are not compatible with that same // action being ignored. @@ -3565,6 +3812,9 @@ public: /// programming models allow it. bool appendTopLevelActions(ActionList &AL, Action *HostAction, const Arg *InputArg) { + if (HostAction) + recordHostAction(HostAction, InputArg); + // Get the device actions to be appended. ActionList OffloadAL; for (auto *SB : SpecializedBuilders) { @@ -3586,6 +3836,7 @@ public: // before this method was called. assert(HostAction == AL.back() && "Host action not in the list??"); HostAction = C.MakeAction<OffloadBundlingJobAction>(OffloadAL); + recordHostAction(HostAction, InputArg); AL.back() = HostAction; } else AL.append(OffloadAL.begin(), OffloadAL.end()); @@ -3619,6 +3870,11 @@ public: if (!SB->isValid()) continue; HA = SB->appendLinkHostActions(DeviceAL); + // This created host action has no originating input argument, therefore + // needs to set its offloading kind directly. + if (HA) + HA->propagateHostOffloadInfo(SB->getAssociatedOffloadKind(), + /*BoundArch=*/nullptr); } return HA; } @@ -3645,10 +3901,22 @@ public: // If we don't have device dependencies, we don't have to create an offload // action. if (DDeps.getActions().empty()) { - // Propagate all the active kinds to host action. Given that it is a link - // action it is assumed to depend on all actions generated so far. - HostAction->propagateHostOffloadInfo(ActiveOffloadKinds, - /*BoundArch=*/nullptr); + // Set all the active offloading kinds to the link action. Given that it + // is a link action it is assumed to depend on all actions generated so + // far. + HostAction->setHostOffloadInfo(ActiveOffloadKinds, + /*BoundArch=*/nullptr); + // Propagate active offloading kinds for each input to the link action. + // Each input may have different active offloading kind. + for (auto *A : HostAction->inputs()) { + auto ArgLoc = HostActionToInputArgMap.find(A); + if (ArgLoc == HostActionToInputArgMap.end()) + continue; + auto OFKLoc = InputArgToOffloadKindMap.find(ArgLoc->second); + if (OFKLoc == InputArgToOffloadKindMap.end()) + continue; + A->propagateHostOffloadInfo(OFKLoc->second, /*BoundArch=*/nullptr); + } return HostAction; } @@ -3686,12 +3954,34 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg); if (FinalPhase == phases::Link) { - if (Args.hasArg(options::OPT_emit_llvm)) + if (Args.hasArgNoClaim(options::OPT_hipstdpar)) { + Args.AddFlagArg(nullptr, getOpts().getOption(options::OPT_hip_link)); + Args.AddFlagArg(nullptr, + getOpts().getOption(options::OPT_frtlib_add_rpath)); + } + // Emitting LLVM while linking disabled except in HIPAMD Toolchain + if (Args.hasArg(options::OPT_emit_llvm) && !Args.hasArg(options::OPT_hip_link)) Diag(clang::diag::err_drv_emit_llvm_link); if (IsCLMode() && LTOMode != LTOK_None && !Args.getLastArgValue(options::OPT_fuse_ld_EQ) .equals_insensitive("lld")) Diag(clang::diag::err_drv_lto_without_lld); + + // If -dumpdir is not specified, give a default prefix derived from the link + // output filename. For example, `clang -g -gsplit-dwarf a.c -o x` passes + // `-dumpdir x-` to cc1. If -o is unspecified, use + // stem(getDefaultImageName()) (usually stem("a.out") = "a"). + if (!Args.hasArg(options::OPT_dumpdir)) { + Arg *FinalOutput = Args.getLastArg(options::OPT_o, options::OPT__SLASH_o); + Arg *Arg = Args.MakeSeparateArg( + nullptr, getOpts().getOption(options::OPT_dumpdir), + Args.MakeArgString( + (FinalOutput ? FinalOutput->getValue() + : llvm::sys::path::stem(getDefaultImageName())) + + "-")); + Arg->claim(); + Args.append(Arg); + } } if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) { @@ -3787,11 +4077,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, return; } - // Reject -Z* at the top level, these options should never have been exposed - // by gcc. - if (Arg *A = Args.getLastArg(options::OPT_Z_Joined)) - Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args); - // Diagnose misuse of /Fo. if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) { StringRef V = A->getValue(); @@ -3827,16 +4112,19 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, handleArguments(C, Args, Inputs, Actions); - // Builder to be used to build offloading actions. - OffloadingActionBuilder OffloadBuilder(C, Args, Inputs); + bool UseNewOffloadingDriver = + C.isOffloadingHostKind(Action::OFK_OpenMP) || + Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false); - // Offload kinds active for this compilation. - unsigned OffloadKinds = Action::OFK_None; - if (C.hasOffloadToolChain<Action::OFK_OpenMP>()) - OffloadKinds |= Action::OFK_OpenMP; + // Builder to be used to build offloading actions. + std::unique_ptr<OffloadingActionBuilder> OffloadBuilder = + !UseNewOffloadingDriver + ? std::make_unique<OffloadingActionBuilder>(C, Args, Inputs) + : nullptr; // Construct the actions to perform. - HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr; + ExtractAPIJobAction *ExtractAPIAction = nullptr; ActionList LinkerInputs; ActionList MergerInputs; @@ -3855,15 +4143,15 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // Use the current host action in any of the offloading actions, if // required. - if (!Args.hasArg(options::OPT_fopenmp_new_driver)) - if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg)) + if (!UseNewOffloadingDriver) + if (OffloadBuilder->addHostDependenceToDeviceActions(Current, InputArg)) break; for (phases::ID Phase : PL) { // Add any offload action the host action depends on. - if (!Args.hasArg(options::OPT_fopenmp_new_driver)) - Current = OffloadBuilder.addDeviceDependencesToHostAction( + if (!UseNewOffloadingDriver) + Current = OffloadBuilder->addDeviceDependencesToHostAction( Current, InputArg, Phase, PL.back(), FullPL); if (!Current) break; @@ -3871,7 +4159,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // Queue linker inputs. if (Phase == phases::Link) { assert(Phase == PL.back() && "linking must be final compilation step."); - LinkerInputs.push_back(Current); + // We don't need to generate additional link commands if emitting AMD + // bitcode or compiling only for the offload device + if (!(C.getInputArgs().hasArg(options::OPT_hip_link) && + (C.getInputArgs().hasArg(options::OPT_emit_llvm))) && + !offloadDeviceOnly()) + LinkerInputs.push_back(Current); Current = nullptr; break; } @@ -3887,21 +4180,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, break; } - // Each precompiled header file after a module file action is a module - // header of that same module file, rather than being compiled to a - // separate PCH. - if (Phase == phases::Precompile && HeaderModuleAction && - getPrecompiledType(InputType) == types::TY_PCH) { - HeaderModuleAction->addModuleHeaderInput(Current); + if (Phase == phases::Precompile && ExtractAPIAction) { + ExtractAPIAction->addHeaderInput(Current); Current = nullptr; break; } - // Try to build the offloading actions and add the result as a dependency - // to the host. - if (Args.hasArg(options::OPT_fopenmp_new_driver)) - Current = BuildOffloadingActions(C, Args, I, Current); - // FIXME: Should we include any prior module file outputs as inputs of // later actions in the same command line? @@ -3912,16 +4196,20 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, if (NewCurrent == Current) continue; - if (auto *HMA = dyn_cast<HeaderModulePrecompileJobAction>(NewCurrent)) - HeaderModuleAction = HMA; + if (auto *EAA = dyn_cast<ExtractAPIJobAction>(NewCurrent)) + ExtractAPIAction = EAA; Current = NewCurrent; + // Try to build the offloading actions and add the result as a dependency + // to the host. + if (UseNewOffloadingDriver) + Current = BuildOffloadingActions(C, Args, I, Current); // Use the current host action in any of the offloading actions, if // required. - if (!Args.hasArg(options::OPT_fopenmp_new_driver)) - if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg)) - break; + else if (OffloadBuilder->addHostDependenceToDeviceActions(Current, + InputArg)) + break; if (Current->getType() == types::TY_Nothing) break; @@ -3932,10 +4220,10 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Actions.push_back(Current); // Add any top level actions generated for offloading. - if (!Args.hasArg(options::OPT_fopenmp_new_driver)) - OffloadBuilder.appendTopLevelActions(Actions, Current, InputArg); + if (!UseNewOffloadingDriver) + OffloadBuilder->appendTopLevelActions(Actions, Current, InputArg); else if (Current) - Current->propagateHostOffloadInfo(OffloadKinds, + Current->propagateHostOffloadInfo(C.getActiveOffloadKinds(), /*BoundArch=*/nullptr); } @@ -3944,27 +4232,28 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, if (LinkerInputs.empty()) { Arg *FinalPhaseArg; if (getFinalPhase(Args, &FinalPhaseArg) == phases::Link) - OffloadBuilder.appendDeviceLinkActions(Actions); + if (!UseNewOffloadingDriver) + OffloadBuilder->appendDeviceLinkActions(Actions); } if (!LinkerInputs.empty()) { - if (!Args.hasArg(options::OPT_fopenmp_new_driver)) - if (Action *Wrapper = OffloadBuilder.makeHostLinkAction()) + if (!UseNewOffloadingDriver) + if (Action *Wrapper = OffloadBuilder->makeHostLinkAction()) LinkerInputs.push_back(Wrapper); Action *LA; // Check if this Linker Job should emit a static library. if (ShouldEmitStaticLibrary(Args)) { LA = C.MakeAction<StaticLibJobAction>(LinkerInputs, types::TY_Image); - } else if (Args.hasArg(options::OPT_fopenmp_new_driver) && - OffloadKinds != Action::OFK_None) { + } else if (UseNewOffloadingDriver || + Args.hasArg(options::OPT_offload_link)) { LA = C.MakeAction<LinkerWrapperJobAction>(LinkerInputs, types::TY_Image); - LA->propagateHostOffloadInfo(OffloadKinds, + LA->propagateHostOffloadInfo(C.getActiveOffloadKinds(), /*BoundArch=*/nullptr); } else { LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image); } - if (!Args.hasArg(options::OPT_fopenmp_new_driver)) - LA = OffloadBuilder.processHostLinkAction(LA); + if (!UseNewOffloadingDriver) + LA = OffloadBuilder->processHostLinkAction(LA); Actions.push_back(LA); } @@ -4029,87 +4318,358 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image)); } - // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom - // Compile phase that prints out supported cpu models and quits. - if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) { - // Use the -mcpu=? flag as the dummy input to cc1. - Actions.clear(); - Action *InputAc = C.MakeAction<InputAction>(*A, types::TY_C); - Actions.push_back( - C.MakeAction<PrecompileJobAction>(InputAc, types::TY_Nothing)); - for (auto &I : Inputs) - I.second->claim(); + for (auto Opt : {options::OPT_print_supported_cpus, + options::OPT_print_supported_extensions}) { + // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a + // custom Compile phase that prints out supported cpu models and quits. + // + // If --print-supported-extensions is specified, call the helper function + // RISCVMarchHelp in RISCVISAInfo.cpp that prints out supported extensions + // and quits. + if (Arg *A = Args.getLastArg(Opt)) { + if (Opt == options::OPT_print_supported_extensions && + !C.getDefaultToolChain().getTriple().isRISCV() && + !C.getDefaultToolChain().getTriple().isAArch64() && + !C.getDefaultToolChain().getTriple().isARM()) { + C.getDriver().Diag(diag::err_opt_not_valid_on_target) + << "--print-supported-extensions"; + return; + } + + // Use the -mcpu=? flag as the dummy input to cc1. + Actions.clear(); + Action *InputAc = C.MakeAction<InputAction>(*A, types::TY_C); + Actions.push_back( + C.MakeAction<PrecompileJobAction>(InputAc, types::TY_Nothing)); + for (auto &I : Inputs) + I.second->claim(); + } + } + + // Call validator for dxil when -Vd not in Args. + if (C.getDefaultToolChain().getTriple().isDXIL()) { + // Only add action when needValidation. + const auto &TC = + static_cast<const toolchains::HLSLToolChain &>(C.getDefaultToolChain()); + if (TC.requiresValidation(Args)) { + Action *LastAction = Actions.back(); + Actions.push_back(C.MakeAction<BinaryAnalyzeJobAction>( + LastAction, types::TY_DX_CONTAINER)); + } } // Claim ignored clang-cl options. Args.ClaimAllArgs(options::OPT_cl_ignored_Group); +} + +/// Returns the canonical name for the offloading architecture when using a HIP +/// or CUDA architecture. +static StringRef getCanonicalArchString(Compilation &C, + const llvm::opt::DerivedArgList &Args, + StringRef ArchStr, + const llvm::Triple &Triple, + bool SuppressError = false) { + // Lookup the CUDA / HIP architecture string. Only report an error if we were + // expecting the triple to be only NVPTX / AMDGPU. + CudaArch Arch = StringToCudaArch(getProcessorFromTargetID(Triple, ArchStr)); + if (!SuppressError && Triple.isNVPTX() && + (Arch == CudaArch::UNKNOWN || !IsNVIDIAGpuArch(Arch))) { + C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch) + << "CUDA" << ArchStr; + return StringRef(); + } else if (!SuppressError && Triple.isAMDGPU() && + (Arch == CudaArch::UNKNOWN || !IsAMDGpuArch(Arch))) { + C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch) + << "HIP" << ArchStr; + return StringRef(); + } + + if (IsNVIDIAGpuArch(Arch)) + return Args.MakeArgStringRef(CudaArchToString(Arch)); + + if (IsAMDGpuArch(Arch)) { + llvm::StringMap<bool> Features; + auto HIPTriple = getHIPOffloadTargetTriple(C.getDriver(), C.getInputArgs()); + if (!HIPTriple) + return StringRef(); + auto Arch = parseTargetID(*HIPTriple, ArchStr, &Features); + if (!Arch) { + C.getDriver().Diag(clang::diag::err_drv_bad_target_id) << ArchStr; + C.setContainsError(); + return StringRef(); + } + return Args.MakeArgStringRef(getCanonicalTargetID(*Arch, Features)); + } + + // If the input isn't CUDA or HIP just return the architecture. + return ArchStr; +} + +/// Checks if the set offloading architectures does not conflict. Returns the +/// incompatible pair if a conflict occurs. +static std::optional<std::pair<llvm::StringRef, llvm::StringRef>> +getConflictOffloadArchCombination(const llvm::DenseSet<StringRef> &Archs, + llvm::Triple Triple) { + if (!Triple.isAMDGPU()) + return std::nullopt; + + std::set<StringRef> ArchSet; + llvm::copy(Archs, std::inserter(ArchSet, ArchSet.begin())); + return getConflictTargetIDCombination(ArchSet); +} + +llvm::DenseSet<StringRef> +Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args, + Action::OffloadKind Kind, const ToolChain *TC, + bool SuppressError) const { + if (!TC) + TC = &C.getDefaultToolChain(); + + // --offload and --offload-arch options are mutually exclusive. + if (Args.hasArgNoClaim(options::OPT_offload_EQ) && + Args.hasArgNoClaim(options::OPT_offload_arch_EQ, + options::OPT_no_offload_arch_EQ)) { + C.getDriver().Diag(diag::err_opt_not_valid_with_opt) + << "--offload" + << (Args.hasArgNoClaim(options::OPT_offload_arch_EQ) + ? "--offload-arch" + : "--no-offload-arch"); + } + + if (KnownArchs.contains(TC)) + return KnownArchs.lookup(TC); + + llvm::DenseSet<StringRef> Archs; + for (auto *Arg : Args) { + // Extract any '--[no-]offload-arch' arguments intended for this toolchain. + std::unique_ptr<llvm::opt::Arg> ExtractedArg = nullptr; + if (Arg->getOption().matches(options::OPT_Xopenmp_target_EQ) && + ToolChain::getOpenMPTriple(Arg->getValue(0)) == TC->getTriple()) { + Arg->claim(); + unsigned Index = Args.getBaseArgs().MakeIndex(Arg->getValue(1)); + ExtractedArg = getOpts().ParseOneArg(Args, Index); + Arg = ExtractedArg.get(); + } + + // Add or remove the seen architectures in order of appearance. If an + // invalid architecture is given we simply exit. + if (Arg->getOption().matches(options::OPT_offload_arch_EQ)) { + for (StringRef Arch : llvm::split(Arg->getValue(), ",")) { + if (Arch == "native" || Arch.empty()) { + auto GPUsOrErr = TC->getSystemGPUArchs(Args); + if (!GPUsOrErr) { + if (SuppressError) + llvm::consumeError(GPUsOrErr.takeError()); + else + TC->getDriver().Diag(diag::err_drv_undetermined_gpu_arch) + << llvm::Triple::getArchTypeName(TC->getArch()) + << llvm::toString(GPUsOrErr.takeError()) << "--offload-arch"; + continue; + } + + for (auto ArchStr : *GPUsOrErr) { + Archs.insert( + getCanonicalArchString(C, Args, Args.MakeArgString(ArchStr), + TC->getTriple(), SuppressError)); + } + } else { + StringRef ArchStr = getCanonicalArchString( + C, Args, Arch, TC->getTriple(), SuppressError); + if (ArchStr.empty()) + return Archs; + Archs.insert(ArchStr); + } + } + } else if (Arg->getOption().matches(options::OPT_no_offload_arch_EQ)) { + for (StringRef Arch : llvm::split(Arg->getValue(), ",")) { + if (Arch == "all") { + Archs.clear(); + } else { + StringRef ArchStr = getCanonicalArchString( + C, Args, Arch, TC->getTriple(), SuppressError); + if (ArchStr.empty()) + return Archs; + Archs.erase(ArchStr); + } + } + } + } + + if (auto ConflictingArchs = + getConflictOffloadArchCombination(Archs, TC->getTriple())) { + C.getDriver().Diag(clang::diag::err_drv_bad_offload_arch_combo) + << ConflictingArchs->first << ConflictingArchs->second; + C.setContainsError(); + } + + // Skip filling defaults if we're just querying what is availible. + if (SuppressError) + return Archs; + + if (Archs.empty()) { + if (Kind == Action::OFK_Cuda) + Archs.insert(CudaArchToString(CudaArch::CudaDefault)); + else if (Kind == Action::OFK_HIP) + Archs.insert(CudaArchToString(CudaArch::HIPDefault)); + else if (Kind == Action::OFK_OpenMP) + Archs.insert(StringRef()); + } else { + Args.ClaimAllArgs(options::OPT_offload_arch_EQ); + Args.ClaimAllArgs(options::OPT_no_offload_arch_EQ); + } - // Claim --cuda-host-only and --cuda-compile-host-device, which may be passed - // to non-CUDA compilations and should not trigger warnings there. - Args.ClaimAllArgs(options::OPT_cuda_host_only); - Args.ClaimAllArgs(options::OPT_cuda_compile_host_device); + return Archs; } Action *Driver::BuildOffloadingActions(Compilation &C, llvm::opt::DerivedArgList &Args, const InputTy &Input, Action *HostAction) const { - if (!isa<CompileJobAction>(HostAction)) + // Don't build offloading actions if explicitly disabled or we do not have a + // valid source input and compile action to embed it in. If preprocessing only + // ignore embedding. + if (offloadHostOnly() || !types::isSrcFile(Input.first) || + !(isa<CompileJobAction>(HostAction) || + getFinalPhase(Args) == phases::Preprocess)) return HostAction; - SmallVector<const ToolChain *, 2> ToolChains; - ActionList DeviceActions; + ActionList OffloadActions; + OffloadAction::DeviceDependences DDeps; - types::ID InputType = Input.first; - const Arg *InputArg = Input.second; + const Action::OffloadKind OffloadKinds[] = { + Action::OFK_OpenMP, Action::OFK_Cuda, Action::OFK_HIP}; - auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); - for (auto TI = OpenMPTCRange.first, TE = OpenMPTCRange.second; TI != TE; ++TI) - ToolChains.push_back(TI->second); + for (Action::OffloadKind Kind : OffloadKinds) { + SmallVector<const ToolChain *, 2> ToolChains; + ActionList DeviceActions; - for (unsigned I = 0; I < ToolChains.size(); ++I) - DeviceActions.push_back(C.MakeAction<InputAction>(*InputArg, InputType)); + auto TCRange = C.getOffloadToolChains(Kind); + for (auto TI = TCRange.first, TE = TCRange.second; TI != TE; ++TI) + ToolChains.push_back(TI->second); - if (DeviceActions.empty()) - return HostAction; + if (ToolChains.empty()) + continue; - auto PL = types::getCompilationPhases(*this, Args, InputType); + types::ID InputType = Input.first; + const Arg *InputArg = Input.second; - for (phases::ID Phase : PL) { - if (Phase == phases::Link) { - assert(Phase == PL.back() && "linking must be final compilation step."); - break; + // The toolchain can be active for unsupported file types. + if ((Kind == Action::OFK_Cuda && !types::isCuda(InputType)) || + (Kind == Action::OFK_HIP && !types::isHIP(InputType))) + continue; + + // Get the product of all bound architectures and toolchains. + SmallVector<std::pair<const ToolChain *, StringRef>> TCAndArchs; + for (const ToolChain *TC : ToolChains) + for (StringRef Arch : getOffloadArchs(C, Args, Kind, TC)) + TCAndArchs.push_back(std::make_pair(TC, Arch)); + + for (unsigned I = 0, E = TCAndArchs.size(); I != E; ++I) + DeviceActions.push_back(C.MakeAction<InputAction>(*InputArg, InputType)); + + if (DeviceActions.empty()) + return HostAction; + + auto PL = types::getCompilationPhases(*this, Args, InputType); + + for (phases::ID Phase : PL) { + if (Phase == phases::Link) { + assert(Phase == PL.back() && "linking must be final compilation step."); + break; + } + + auto TCAndArch = TCAndArchs.begin(); + for (Action *&A : DeviceActions) { + if (A->getType() == types::TY_Nothing) + continue; + + // Propagate the ToolChain so we can use it in ConstructPhaseAction. + A->propagateDeviceOffloadInfo(Kind, TCAndArch->second.data(), + TCAndArch->first); + A = ConstructPhaseAction(C, Args, Phase, A, Kind); + + if (isa<CompileJobAction>(A) && isa<CompileJobAction>(HostAction) && + Kind == Action::OFK_OpenMP && + HostAction->getType() != types::TY_Nothing) { + // OpenMP offloading has a dependency on the host compile action to + // identify which declarations need to be emitted. This shouldn't be + // collapsed with any other actions so we can use it in the device. + HostAction->setCannotBeCollapsedWithNextDependentAction(); + OffloadAction::HostDependence HDep( + *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + TCAndArch->second.data(), Kind); + OffloadAction::DeviceDependences DDep; + DDep.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind); + A = C.MakeAction<OffloadAction>(HDep, DDep); + } + + ++TCAndArch; + } } - auto TC = ToolChains.begin(); + // Compiling HIP in non-RDC mode requires linking each action individually. for (Action *&A : DeviceActions) { - A = ConstructPhaseAction(C, Args, Phase, A, Action::OFK_OpenMP); - - if (isa<CompileJobAction>(A)) { - HostAction->setCannotBeCollapsedWithNextDependentAction(); - OffloadAction::HostDependence HDep( - *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), - /*BourdArch=*/nullptr, Action::OFK_OpenMP); - OffloadAction::DeviceDependences DDep; - DDep.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP); - A = C.MakeAction<OffloadAction>(HDep, DDep); - } - ++TC; + if ((A->getType() != types::TY_Object && + A->getType() != types::TY_LTO_BC) || + Kind != Action::OFK_HIP || + Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) + continue; + ActionList LinkerInput = {A}; + A = C.MakeAction<LinkJobAction>(LinkerInput, types::TY_Image); + } + + auto TCAndArch = TCAndArchs.begin(); + for (Action *A : DeviceActions) { + DDeps.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind); + OffloadAction::DeviceDependences DDep; + DDep.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind); + OffloadActions.push_back(C.MakeAction<OffloadAction>(DDep, A->getType())); + ++TCAndArch; } } - OffloadAction::DeviceDependences DDeps; + if (offloadDeviceOnly()) + return C.MakeAction<OffloadAction>(DDeps, types::TY_Nothing); - auto TC = ToolChains.begin(); - for (Action *A : DeviceActions) { - DDeps.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP); - TC++; - } + if (OffloadActions.empty()) + return HostAction; + OffloadAction::DeviceDependences DDep; + if (C.isOffloadingHostKind(Action::OFK_Cuda) && + !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) { + // If we are not in RDC-mode we just emit the final CUDA fatbinary for + // each translation unit without requiring any linking. + Action *FatbinAction = + C.MakeAction<LinkJobAction>(OffloadActions, types::TY_CUDA_FATBIN); + DDep.add(*FatbinAction, *C.getSingleOffloadToolChain<Action::OFK_Cuda>(), + nullptr, Action::OFK_Cuda); + } else if (C.isOffloadingHostKind(Action::OFK_HIP) && + !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + false)) { + // If we are not in RDC-mode we just emit the final HIP fatbinary for each + // translation unit, linking each input individually. + Action *FatbinAction = + C.MakeAction<LinkJobAction>(OffloadActions, types::TY_HIP_FATBIN); + DDep.add(*FatbinAction, *C.getSingleOffloadToolChain<Action::OFK_HIP>(), + nullptr, Action::OFK_HIP); + } else { + // Package all the offloading actions into a single output that can be + // embedded in the host and linked. + Action *PackagerAction = + C.MakeAction<OffloadPackagerJobAction>(OffloadActions, types::TY_Image); + DDep.add(*PackagerAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + nullptr, C.getActiveOffloadKinds()); + } + + // If we are unable to embed a single device output into the host, we need to + // add each device output as a host dependency to ensure they are still built. + bool SingleDeviceOutput = !llvm::any_of(OffloadActions, [](Action *A) { + return A->getType() == types::TY_Nothing; + }) && isa<CompileJobAction>(HostAction); OffloadAction::HostDependence HDep( *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), - /*BoundArch=*/nullptr, DDeps); - return C.MakeAction<OffloadAction>(HDep, DDeps); + /*BoundArch=*/nullptr, SingleDeviceOutput ? DDep : DDeps); + return C.MakeAction<OffloadAction>(HDep, SingleDeviceOutput ? DDep : DDeps); } Action *Driver::ConstructPhaseAction( @@ -4138,10 +4698,14 @@ Action *Driver::ConstructPhaseAction( OutputTy = types::TY_Dependencies; } else { OutputTy = Input->getType(); + // For these cases, the preprocessor is only translating forms, the Output + // still needs preprocessing. if (!Args.hasFlag(options::OPT_frewrite_includes, options::OPT_fno_rewrite_includes, false) && !Args.hasFlag(options::OPT_frewrite_imports, options::OPT_fno_rewrite_imports, false) && + !Args.hasFlag(options::OPT_fdirectives_only, + options::OPT_fno_directives_only, false) && !CCGenDiagnostics) OutputTy = types::getPreprocessedType(OutputTy); assert(OutputTy != types::TY_INVALID && @@ -4150,6 +4714,10 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction<PreprocessJobAction>(Input, OutputTy); } case phases::Precompile: { + // API extraction should not generate an actual precompilation action. + if (Args.hasArg(options::OPT_extract_api)) + return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO); + types::ID OutputTy = getPrecompiledType(Input->getType()); assert(OutputTy != types::TY_INVALID && "Cannot precompile this input type!"); @@ -4164,15 +4732,11 @@ Action *Driver::ConstructPhaseAction( OutputTy = types::TY_ModuleFile; } - if (Args.hasArg(options::OPT_fsyntax_only) || - Args.hasArg(options::OPT_extract_api)) { + if (Args.hasArg(options::OPT_fsyntax_only)) { // Syntax checks should not emit a PCH file OutputTy = types::TY_Nothing; } - if (ModName) - return C.MakeAction<HeaderModulePrecompileJobAction>(Input, OutputTy, - ModName); return C.MakeAction<PrecompileJobAction>(Input, OutputTy); } case phases::Compile: { @@ -4194,27 +4758,43 @@ Action *Driver::ConstructPhaseAction( if (Args.hasArg(options::OPT_verify_pch)) return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing); if (Args.hasArg(options::OPT_extract_api)) - return C.MakeAction<CompileJobAction>(Input, types::TY_API_INFO); + return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO); return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC); } case phases::Backend: { if (isUsingLTO() && TargetDeviceOffloadKind == Action::OFK_None) { - types::ID Output = - Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; + types::ID Output; + if (Args.hasArg(options::OPT_ffat_lto_objects) && + !Args.hasArg(options::OPT_emit_llvm)) + Output = types::TY_PP_Asm; + else if (Args.hasArg(options::OPT_S)) + Output = types::TY_LTO_IR; + else + Output = types::TY_LTO_BC; return C.MakeAction<BackendJobAction>(Input, Output); } if (isUsingLTO(/* IsOffload */ true) && - TargetDeviceOffloadKind == Action::OFK_OpenMP) { + TargetDeviceOffloadKind != Action::OFK_None) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; return C.MakeAction<BackendJobAction>(Input, Output); } if (Args.hasArg(options::OPT_emit_llvm) || - (TargetDeviceOffloadKind == Action::OFK_HIP && - Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, - false))) { + (((Input->getOffloadingToolChain() && + Input->getOffloadingToolChain()->getTriple().isAMDGPU()) || + TargetDeviceOffloadKind == Action::OFK_HIP) && + (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + false) || + TargetDeviceOffloadKind == Action::OFK_OpenMP))) { types::ID Output = - Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC; + Args.hasArg(options::OPT_S) && + (TargetDeviceOffloadKind == Action::OFK_None || + offloadDeviceOnly() || + (TargetDeviceOffloadKind == Action::OFK_HIP && + !Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false))) + ? types::TY_LLVM_IR + : types::TY_LLVM_BC; return C.MakeAction<BackendJobAction>(Input, Output); } return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm); @@ -4244,11 +4824,16 @@ void Driver::BuildJobs(Compilation &C) const { // we are also generating .o files. So we allow more than one output file in // this case as well. // + // OffloadClass of type TY_Nothing: device-only output will place many outputs + // into a single offloading action. We should count all inputs to the action + // as outputs. Also ignore device-only outputs if we're compiling with + // -fsyntax-only. if (FinalOutput) { unsigned NumOutputs = 0; unsigned NumIfsOutputs = 0; - for (const Action *A : C.getActions()) + for (const Action *A : C.getActions()) { if (A->getType() != types::TY_Nothing && + A->getType() != types::TY_DX_CONTAINER && !(A->getKind() == Action::IfsMergeJobClass || (A->getType() == clang::driver::types::TY_IFS_CPP && A->getKind() == clang::driver::Action::CompileJobClass && @@ -4256,6 +4841,11 @@ void Driver::BuildJobs(Compilation &C) const { (A->getKind() == Action::BindArchClass && A->getInputs().size() && A->getInputs().front()->getKind() == Action::IfsMergeJobClass))) ++NumOutputs; + else if (A->getKind() == Action::OffloadClass && + A->getType() == types::TY_Nothing && + !C.getArgs().hasArg(options::OPT_fsyntax_only)) + NumOutputs += A->size(); + } if (NumOutputs > 1) { Diag(clang::diag::err_drv_output_argument_with_multiple_files); @@ -4264,13 +4854,6 @@ void Driver::BuildJobs(Compilation &C) const { } const llvm::Triple &RawTriple = C.getDefaultToolChain().getTriple(); - if (RawTriple.isOSAIX()) { - if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) - Diag(diag::err_drv_unsupported_opt_for_target) - << A->getSpelling() << RawTriple.str(); - if (LTOMode == LTOK_Thin) - Diag(diag::err_drv_clang_unsupported) << "thinLTO on AIX"; - } // Collect the list of architectures. llvm::StringSet<> ArchNames; @@ -4312,7 +4895,7 @@ void Driver::BuildJobs(Compilation &C) const { if (CCPrintProcessStats) { C.setPostCallback([=](const Command &Cmd, int Res) { - Optional<llvm::sys::ProcessStatistics> ProcStat = + std::optional<llvm::sys::ProcessStatistics> ProcStat = Cmd.getProcessStatistics(); if (!ProcStat) return; @@ -4372,6 +4955,8 @@ void Driver::BuildJobs(Compilation &C) const { C.getArgs().hasArg(options::OPT_Qunused_arguments)) return; + // Claim -fdriver-only here. + (void)C.getArgs().hasArg(options::OPT_fdriver_only); // Claim -### here. (void)C.getArgs().hasArg(options::OPT__HASH_HASH_HASH); @@ -4379,6 +4964,12 @@ void Driver::BuildJobs(Compilation &C) const { (void)C.getArgs().hasArg(options::OPT_driver_mode); (void)C.getArgs().hasArg(options::OPT_rsp_quoting); + bool HasAssembleJob = llvm::any_of(C.getJobs(), [](auto &J) { + // Match ClangAs and other derived assemblers of Tool. ClangAs uses a + // longer ShortName "clang integrated assembler" while other assemblers just + // use "assembler". + return strstr(J.getCreator().getShortName(), "assembler"); + }); for (Arg *A : C.getArgs()) { // FIXME: It would be nice to be able to send the argument to the // DiagnosticsEngine, so that extra values, position, and so on could be @@ -4406,9 +4997,21 @@ void Driver::BuildJobs(Compilation &C) const { // In clang-cl, don't mention unknown arguments here since they have // already been warned about. - if (!IsCLMode() || !A->getOption().matches(options::OPT_UNKNOWN)) - Diag(clang::diag::warn_drv_unused_argument) - << A->getAsString(C.getArgs()); + if (!IsCLMode() || !A->getOption().matches(options::OPT_UNKNOWN)) { + if (A->getOption().hasFlag(options::TargetSpecific) && + !A->isIgnoredTargetSpecific() && !HasAssembleJob && + // When for example -### or -v is used + // without a file, target specific options are not + // consumed/validated. + // Instead emitting an error emit a warning instead. + !C.getActions().empty()) { + Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << getTargetTriple(); + } else { + Diag(clang::diag::warn_drv_unused_argument) + << A->getAsString(C.getArgs()); + } + } } } } @@ -4483,7 +5086,8 @@ class ToolSelector final { return TC.useIntegratedAs() && !SaveTemps && !C.getArgs().hasArg(options::OPT_via_file_asm) && !C.getArgs().hasArg(options::OPT__SLASH_FA) && - !C.getArgs().hasArg(options::OPT__SLASH_Fa); + !C.getArgs().hasArg(options::OPT__SLASH_Fa) && + !C.getArgs().hasArg(options::OPT_dxc_Fc); } /// Return true if a preprocessor action can be collapsed. @@ -4756,6 +5360,37 @@ InputInfoList Driver::BuildJobsForAction( return Result; } +static void handleTimeTrace(Compilation &C, const ArgList &Args, + const JobAction *JA, const char *BaseInput, + const InputInfo &Result) { + Arg *A = + Args.getLastArg(options::OPT_ftime_trace, options::OPT_ftime_trace_EQ); + if (!A) + return; + SmallString<128> Path; + if (A->getOption().matches(options::OPT_ftime_trace_EQ)) { + Path = A->getValue(); + if (llvm::sys::fs::is_directory(Path)) { + SmallString<128> Tmp(Result.getFilename()); + llvm::sys::path::replace_extension(Tmp, "json"); + llvm::sys::path::append(Path, llvm::sys::path::filename(Tmp)); + } + } else { + if (Arg *DumpDir = Args.getLastArgNoClaim(options::OPT_dumpdir)) { + // The trace file is ${dumpdir}${basename}.json. Note that dumpdir may not + // end with a path separator. + Path = DumpDir->getValue(); + Path += llvm::sys::path::filename(BaseInput); + } else { + Path = Result.getFilename(); + } + llvm::sys::path::replace_extension(Path, "json"); + } + const char *ResultFile = C.getArgs().MakeArgString(Path); + C.addTimeTraceFile(ResultFile, JA); + C.addResultFile(ResultFile, JA); +} + InputInfoList Driver::BuildJobsForActionNoCache( Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, @@ -4791,20 +5426,21 @@ InputInfoList Driver::BuildJobsForActionNoCache( // \ // Device Action 1 ---> OffloadAction -> Device Action 2 // - // For a) and b), we just return the job generated for the dependence. For + // For a) and b), we just return the job generated for the dependences. For // c) and d) we override the current action with the host/device dependence // if the current toolchain is host/device and set the offload dependences // info with the jobs obtained from the device/host dependence(s). - // If there is a single device option, just generate the job for it. - if (OA->hasSingleDeviceDependence()) { + // If there is a single device option or has no host action, just generate + // the job for it. + if (OA->hasSingleDeviceDependence() || !OA->hasHostDependence()) { InputInfoList DevA; OA->doOnEachDeviceDependence([&](Action *DepA, const ToolChain *DepTC, const char *DepBoundArch) { - DevA = - BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel, - /*MultipleArchs*/ !!DepBoundArch, LinkingOutput, - CachedResults, DepA->getOffloadingDeviceKind()); + DevA.append(BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel, + /*MultipleArchs*/ !!DepBoundArch, + LinkingOutput, CachedResults, + DepA->getOffloadingDeviceKind())); }); return DevA; } @@ -4879,25 +5515,6 @@ InputInfoList Driver::BuildJobsForActionNoCache( if (!T) return {InputInfo()}; - if (BuildingForOffloadDevice && - A->getOffloadingDeviceKind() == Action::OFK_OpenMP) { - if (TC->getTriple().isAMDGCN()) { - // AMDGCN treats backend and assemble actions as no-op because - // linker does not support object files. - if (const BackendJobAction *BA = dyn_cast<BackendJobAction>(A)) { - return BuildJobsForAction(C, *BA->input_begin(), TC, BoundArch, - AtTopLevel, MultipleArchs, LinkingOutput, - CachedResults, TargetDeviceOffloadKind); - } - - if (const AssembleJobAction *AA = dyn_cast<AssembleJobAction>(A)) { - return BuildJobsForAction(C, *AA->input_begin(), TC, BoundArch, - AtTopLevel, MultipleArchs, LinkingOutput, - CachedResults, TargetDeviceOffloadKind); - } - } - } - // If we've collapsed action list that contained OffloadAction we // need to build jobs for host/device-side inputs it may have held. for (const auto *OA : CollapsedOffloadActions) @@ -4937,10 +5554,6 @@ InputInfoList Driver::BuildJobsForActionNoCache( if (JA->getType() == types::TY_dSYM) BaseInput = InputInfos[0].getFilename(); - // ... and in header module compilations, which use the module name. - if (auto *ModuleJA = dyn_cast<HeaderModulePrecompileJobAction>(JA)) - BaseInput = ModuleJA->getModuleName(); - // Append outputs of offload device jobs to the input list if (!OffloadDependencesInputInfo.empty()) InputInfos.append(OffloadDependencesInputInfo.begin(), @@ -5020,20 +5633,15 @@ InputInfoList Driver::BuildJobsForActionNoCache( // action. std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( A->getOffloadingDeviceKind(), TC->getTriple().normalize(), - /*CreatePrefixForHost=*/!!A->getOffloadingHostActiveKinds() && - !AtTopLevel); - if (isa<OffloadWrapperJobAction>(JA)) { - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) - BaseInput = FinalOutput->getValue(); - else - BaseInput = getDefaultImageName(); - BaseInput = - C.getArgs().MakeArgString(std::string(BaseInput) + "-wrapper"); - } + /*CreatePrefixForHost=*/isa<OffloadPackagerJobAction>(A) || + !(A->getOffloadingHostActiveKinds() == Action::OFK_None || + AtTopLevel)); Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch, AtTopLevel, MultipleArchs, OffloadingPrefix), BaseInput); + if (T->canEmitIR() && OffloadingPrefix.empty()) + handleTimeTrace(C, Args, JA, BaseInput, Result); } if (CCCPrintBindings && !CCGenDiagnostics) { @@ -5119,6 +5727,78 @@ static bool HasPreprocessOutput(const Action &JA) { return false; } +const char *Driver::CreateTempFile(Compilation &C, StringRef Prefix, + StringRef Suffix, bool MultipleArchs, + StringRef BoundArch, + bool NeedUniqueDirectory) const { + SmallString<128> TmpName; + Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir); + std::optional<std::string> CrashDirectory = + CCGenDiagnostics && A + ? std::string(A->getValue()) + : llvm::sys::Process::GetEnv("CLANG_CRASH_DIAGNOSTICS_DIR"); + if (CrashDirectory) { + if (!getVFS().exists(*CrashDirectory)) + llvm::sys::fs::create_directories(*CrashDirectory); + SmallString<128> Path(*CrashDirectory); + llvm::sys::path::append(Path, Prefix); + const char *Middle = !Suffix.empty() ? "-%%%%%%." : "-%%%%%%"; + if (std::error_code EC = + llvm::sys::fs::createUniqueFile(Path + Middle + Suffix, TmpName)) { + Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return ""; + } + } else { + if (MultipleArchs && !BoundArch.empty()) { + if (NeedUniqueDirectory) { + TmpName = GetTemporaryDirectory(Prefix); + llvm::sys::path::append(TmpName, + Twine(Prefix) + "-" + BoundArch + "." + Suffix); + } else { + TmpName = + GetTemporaryPath((Twine(Prefix) + "-" + BoundArch).str(), Suffix); + } + + } else { + TmpName = GetTemporaryPath(Prefix, Suffix); + } + } + return C.addTempFile(C.getArgs().MakeArgString(TmpName)); +} + +// Calculate the output path of the module file when compiling a module unit +// with the `-fmodule-output` option or `-fmodule-output=` option specified. +// The behavior is: +// - If `-fmodule-output=` is specfied, then the module file is +// writing to the value. +// - Otherwise if the output object file of the module unit is specified, the +// output path +// of the module file should be the same with the output object file except +// the corresponding suffix. This requires both `-o` and `-c` are specified. +// - Otherwise, the output path of the module file will be the same with the +// input with the corresponding suffix. +static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA, + const char *BaseInput) { + assert(isa<PrecompileJobAction>(JA) && JA.getType() == types::TY_ModuleFile && + (C.getArgs().hasArg(options::OPT_fmodule_output) || + C.getArgs().hasArg(options::OPT_fmodule_output_EQ))); + + if (Arg *ModuleOutputEQ = + C.getArgs().getLastArg(options::OPT_fmodule_output_EQ)) + return C.addResultFile(ModuleOutputEQ->getValue(), &JA); + + SmallString<64> OutputPath; + Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); + if (FinalOutput && C.getArgs().hasArg(options::OPT_c)) + OutputPath = FinalOutput->getValue(); + else + OutputPath = BaseInput; + + const char *Extension = types::getTypeTempSuffix(JA.getType()); + llvm::sys::path::replace_extension(OutputPath, Extension); + return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA); +} + const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, StringRef OrigBoundArch, bool AtTopLevel, @@ -5160,6 +5840,22 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, return "-"; } + if (JA.getType() == types::TY_PP_Asm && + C.getArgs().hasArg(options::OPT_dxc_Fc)) { + StringRef FcValue = C.getArgs().getLastArgValue(options::OPT_dxc_Fc); + // TODO: Should we use `MakeCLOutputFilename` here? If so, we can probably + // handle this as part of the SLASH_Fa handling below. + return C.addResultFile(C.getArgs().MakeArgString(FcValue.str()), &JA); + } + + if (JA.getType() == types::TY_Object && + C.getArgs().hasArg(options::OPT_dxc_Fo)) { + StringRef FoValue = C.getArgs().getLastArgValue(options::OPT_dxc_Fo); + // TODO: Should we use `MakeCLOutputFilename` here? If so, we can probably + // handle this as part of the SLASH_Fo handling below. + return C.addResultFile(C.getArgs().MakeArgString(FoValue.str()), &JA); + } + // Is this the assembly listing for /FA? if (JA.getType() == types::TY_PP_Asm && (C.getArgs().hasArg(options::OPT__SLASH_FA) || @@ -5172,37 +5868,41 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, &JA); } + // DXC defaults to standard out when generating assembly. We check this after + // any DXC flags that might specify a file. + if (AtTopLevel && JA.getType() == types::TY_PP_Asm && IsDXCMode()) + return "-"; + + bool SpecifiedModuleOutput = + C.getArgs().hasArg(options::OPT_fmodule_output) || + C.getArgs().hasArg(options::OPT_fmodule_output_EQ); + if (MultipleArchs && SpecifiedModuleOutput) + Diag(clang::diag::err_drv_module_output_with_multiple_arch); + + // If we're emitting a module output with the specified option + // `-fmodule-output`. + if (!AtTopLevel && isa<PrecompileJobAction>(JA) && + JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) + return GetModuleOutputPath(C, JA, BaseInput); + // Output to a temporary file? if ((!AtTopLevel && !isSaveTempsEnabled() && !C.getArgs().hasArg(options::OPT__SLASH_Fo)) || CCGenDiagnostics) { StringRef Name = llvm::sys::path::filename(BaseInput); std::pair<StringRef, StringRef> Split = Name.split('.'); - SmallString<128> TmpName; - const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode()); - Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir); - if (CCGenDiagnostics && A) { - SmallString<128> CrashDirectory(A->getValue()); - if (!getVFS().exists(CrashDirectory)) - llvm::sys::fs::create_directories(CrashDirectory); - llvm::sys::path::append(CrashDirectory, Split.first); - const char *Middle = Suffix ? "-%%%%%%." : "-%%%%%%"; - std::error_code EC = llvm::sys::fs::createUniqueFile( - CrashDirectory + Middle + Suffix, TmpName); - if (EC) { - Diag(clang::diag::err_unable_to_make_temp) << EC.message(); - return ""; - } - } else { - if (MultipleArchs && !BoundArch.empty()) { - TmpName = GetTemporaryDirectory(Split.first); - llvm::sys::path::append(TmpName, - Split.first + "-" + BoundArch + "." + Suffix); - } else { - TmpName = GetTemporaryPath(Split.first, Suffix); - } - } - return C.addTempFile(C.getArgs().MakeArgString(TmpName)); + const char *Suffix = + types::getTypeTempSuffix(JA.getType(), IsCLMode() || IsDXCMode()); + // The non-offloading toolchain on Darwin requires deterministic input + // file name for binaries to be deterministic, therefore it needs unique + // directory. + llvm::Triple Triple(C.getDriver().getTargetTriple()); + bool NeedUniqueDirectory = + (JA.getOffloadingDeviceKind() == Action::OFK_None || + JA.getOffloadingDeviceKind() == Action::OFK_Host) && + Triple.isOSDarwin(); + return CreateTempFile(C, Split.first, Suffix, MultipleArchs, BoundArch, + NeedUniqueDirectory); } SmallString<128> BasePath(BaseInput); @@ -5258,7 +5958,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, bool IsHIPNoRDC = JA.getOffloadingDeviceKind() == Action::OFK_HIP && !C.getArgs().hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false); - if (IsHIPNoRDC) { + bool UseOutExtension = IsHIPNoRDC || isa<OffloadPackagerJobAction>(JA); + if (UseOutExtension) { Output = BaseName; llvm::sys::path::replace_extension(Output, ""); } @@ -5267,14 +5968,23 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, Output += "-"; Output.append(BoundArch); } - if (IsHIPNoRDC) + if (UseOutExtension) Output += ".out"; NamedOutput = C.getArgs().MakeArgString(Output.c_str()); } } else if (JA.getType() == types::TY_PCH && IsCLMode()) { NamedOutput = C.getArgs().MakeArgString(GetClPchPath(C, BaseName)); + } else if ((JA.getType() == types::TY_Plist || JA.getType() == types::TY_AST) && + C.getArgs().hasArg(options::OPT__SLASH_o)) { + StringRef Val = + C.getArgs() + .getLastArg(options::OPT__SLASH_o) + ->getValue(); + NamedOutput = + MakeCLOutputFilename(C.getArgs(), Val, BaseName, types::TY_Object); } else { - const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode()); + const char *Suffix = + types::getTypeTempSuffix(JA.getType(), IsCLMode() || IsDXCMode()); assert(Suffix && "All types used for output should have a suffix."); std::string::size_type End = std::string::npos; @@ -5289,19 +5999,22 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, // When using both -save-temps and -emit-llvm, use a ".tmp.bc" suffix for // the unoptimized bitcode so that it does not get overwritten by the ".bc" // optimized bitcode output. - auto IsHIPRDCInCompilePhase = [](const JobAction &JA, + auto IsAMDRDCInCompilePhase = [](const JobAction &JA, const llvm::opt::DerivedArgList &Args) { - // The relocatable compilation in HIP implies -emit-llvm. Similarly, use a - // ".tmp.bc" suffix for the unoptimized bitcode (generated in the compile - // phase.) + // The relocatable compilation in HIP and OpenMP implies -emit-llvm. + // Similarly, use a ".tmp.bc" suffix for the unoptimized bitcode + // (generated in the compile phase.) + const ToolChain *TC = JA.getOffloadingToolChain(); return isa<CompileJobAction>(JA) && - JA.getOffloadingDeviceKind() == Action::OFK_HIP && - Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, - false); + ((JA.getOffloadingDeviceKind() == Action::OFK_HIP && + Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + false)) || + (JA.getOffloadingDeviceKind() == Action::OFK_OpenMP && TC && + TC->getTriple().isAMDGPU())); }; if (!AtTopLevel && JA.getType() == types::TY_LLVM_BC && (C.getArgs().hasArg(options::OPT_emit_llvm) || - IsHIPRDCInCompilePhase(JA, C.getArgs()))) + IsAMDRDCInCompilePhase(JA, C.getArgs()))) Suffixed += ".tmp"; Suffixed += '.'; Suffixed += Suffix; @@ -5332,7 +6045,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, StringRef Name = llvm::sys::path::filename(BaseInput); std::pair<StringRef, StringRef> Split = Name.split('.'); std::string TmpName = GetTemporaryPath( - Split.first, types::getTypeTempSuffix(JA.getType(), IsCLMode())); + Split.first, + types::getTypeTempSuffix(JA.getType(), IsCLMode() || IsDXCMode())); return C.addTempFile(C.getArgs().MakeArgString(TmpName)); } } @@ -5345,15 +6059,15 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, else llvm::sys::path::append(BasePath, NamedOutput); return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA); - } else { - return C.addResultFile(NamedOutput, &JA); } + + return C.addResultFile(NamedOutput, &JA); } std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { // Search for Name in a list of paths. auto SearchPaths = [&](const llvm::SmallVectorImpl<std::string> &P) - -> llvm::Optional<std::string> { + -> std::optional<std::string> { // Respect a limited subset of the '-Bprefix' functionality in GCC by // attempting to use this prefix when looking for file paths. for (const auto &Dir : P) { @@ -5364,7 +6078,7 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { if (llvm::sys::fs::exists(Twine(P))) return std::string(P); } - return None; + return std::nullopt; }; if (auto P = SearchPaths(PrefixDirs)) @@ -5373,17 +6087,17 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const { SmallString<128> R(ResourceDir); llvm::sys::path::append(R, Name); if (llvm::sys::fs::exists(Twine(R))) - return std::string(R.str()); + return std::string(R); SmallString<128> P(TC.getCompilerRTPath()); llvm::sys::path::append(P, Name); if (llvm::sys::fs::exists(Twine(P))) - return std::string(P.str()); + return std::string(P); SmallString<128> D(Dir); llvm::sys::path::append(D, "..", Name); if (llvm::sys::fs::exists(Twine(D))) - return std::string(D.str()); + return std::string(D); if (auto P = SearchPaths(TC.getLibraryPaths())) return *P; @@ -5420,11 +6134,11 @@ std::string Driver::GetProgramPath(StringRef Name, const ToolChain &TC) const { if (llvm::sys::fs::is_directory(PrefixDir)) { SmallString<128> P(PrefixDir); if (ScanDirForExecutable(P, Name)) - return std::string(P.str()); + return std::string(P); } else { SmallString<128> P((PrefixDir + Name).str()); if (llvm::sys::fs::can_execute(Twine(P))) - return std::string(P.str()); + return std::string(P); } } @@ -5440,7 +6154,7 @@ std::string Driver::GetProgramPath(StringRef Name, const ToolChain &TC) const { for (const auto &Path : List) { SmallString<128> P(Path); if (ScanDirForExecutable(P, TargetSpecificExecutable)) - return std::string(P.str()); + return std::string(P); } // Fall back to the path @@ -5460,7 +6174,7 @@ std::string Driver::GetTemporaryPath(StringRef Prefix, StringRef Suffix) const { return ""; } - return std::string(Path.str()); + return std::string(Path); } std::string Driver::GetTemporaryDirectory(StringRef Prefix) const { @@ -5471,7 +6185,7 @@ std::string Driver::GetTemporaryDirectory(StringRef Prefix) const { return ""; } - return std::string(Path.str()); + return std::string(Path); } std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { @@ -5493,7 +6207,7 @@ std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const { Output = BaseName; llvm::sys::path::replace_extension(Output, ".pch"); } - return std::string(Output.str()); + return std::string(Output); } const ToolChain &Driver::getToolChain(const ArgList &Args, @@ -5508,17 +6222,13 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Haiku: TC = std::make_unique<toolchains::Haiku>(*this, Target, Args); break; - case llvm::Triple::Ananas: - TC = std::make_unique<toolchains::Ananas>(*this, Target, Args); - break; - case llvm::Triple::CloudABI: - TC = std::make_unique<toolchains::CloudABI>(*this, Target, Args); - break; case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: case llvm::Triple::TvOS: case llvm::Triple::WatchOS: + case llvm::Triple::XROS: + case llvm::Triple::DriverKit: TC = std::make_unique<toolchains::DarwinClang>(*this, Target, Args); break; case llvm::Triple::DragonFly: @@ -5537,9 +6247,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, else TC = std::make_unique<toolchains::FreeBSD>(*this, Target, Args); break; - case llvm::Triple::Minix: - TC = std::make_unique<toolchains::Minix>(*this, Target, Args); - break; case llvm::Triple::Linux: case llvm::Triple::ELFIAMCU: if (Target.getArch() == llvm::Triple::hexagon) @@ -5554,7 +6261,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, Args); else if (Target.getArch() == llvm::Triple::ve) TC = std::make_unique<toolchains::VEToolChain>(*this, Target, Args); - + else if (Target.isOHOSFamily()) + TC = std::make_unique<toolchains::OHOS>(*this, Target, Args); else TC = std::make_unique<toolchains::Linux>(*this, Target, Args); break; @@ -5567,6 +6275,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Solaris: TC = std::make_unique<toolchains::Solaris>(*this, Target, Args); break; + case llvm::Triple::CUDA: + TC = std::make_unique<toolchains::NVPTXToolChain>(*this, Target, Args); + break; case llvm::Triple::AMDHSA: TC = std::make_unique<toolchains::ROCMToolChain>(*this, Target, Args); break; @@ -5594,7 +6305,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::MSVC: case llvm::Triple::UnknownEnvironment: if (Args.getLastArgValue(options::OPT_fuse_ld_EQ) - .startswith_insensitive("bfd")) + .starts_with_insensitive("bfd")) TC = std::make_unique<toolchains::CrossWindowsToolChain>( *this, Target, Args); else @@ -5606,15 +6317,21 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::PS4: TC = std::make_unique<toolchains::PS4CPU>(*this, Target, Args); break; - case llvm::Triple::Contiki: - TC = std::make_unique<toolchains::Contiki>(*this, Target, Args); + case llvm::Triple::PS5: + TC = std::make_unique<toolchains::PS5CPU>(*this, Target, Args); break; case llvm::Triple::Hurd: TC = std::make_unique<toolchains::Hurd>(*this, Target, Args); break; + case llvm::Triple::LiteOS: + TC = std::make_unique<toolchains::OHOS>(*this, Target, Args); + break; case llvm::Triple::ZOS: TC = std::make_unique<toolchains::ZOS>(*this, Target, Args); break; + case llvm::Triple::ShaderModel: + TC = std::make_unique<toolchains::HLSLToolChain>(*this, Target, Args); + break; default: // Of these targets, Hexagon is the only one that might have // an OS of Linux, in which case it got handled above already. @@ -5661,11 +6378,11 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::spirv64: TC = std::make_unique<toolchains::SPIRVToolChain>(*this, Target, Args); break; + case llvm::Triple::csky: + TC = std::make_unique<toolchains::CSKYToolChain>(*this, Target, Args); + break; default: - if (Target.getVendor() == llvm::Triple::Myriad) - TC = std::make_unique<toolchains::MyriadToolChain>(*this, Target, - Args); - else if (toolchains::BareMetal::handlesTarget(Target)) + if (toolchains::BareMetal::handlesTarget(Target)) TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args); else if (Target.isOSBinFormatELF()) TC = std::make_unique<toolchains::Generic_ELF>(*this, Target, Args); @@ -5677,11 +6394,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, } } - // Intentionally omitted from the switch above: llvm::Triple::CUDA. CUDA - // compiles always need two toolchains, the CUDA toolchain and the host - // toolchain. So the only valid way to create a CUDA toolchain is via - // CreateOffloadingDeviceToolChains. - return *TC; } @@ -5725,7 +6437,8 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { // And say "no" if this is not a kind of action clang understands. if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) && - !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA)) + !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA) && + !isa<ExtractAPIJobAction>(JA)) return false; return true; @@ -5734,11 +6447,12 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { bool Driver::ShouldUseFlangCompiler(const JobAction &JA) const { // Say "no" if there is not exactly one input of a type flang understands. if (JA.size() != 1 || - !types::isFortran((*JA.input_begin())->getType())) + !types::isAcceptedByFlang((*JA.input_begin())->getType())) return false; // And say "no" if this is not a kind of action flang understands. - if (!isa<PreprocessJobAction>(JA) && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA)) + if (!isa<PreprocessJobAction>(JA) && !isa<CompileJobAction>(JA) && + !isa<BackendJobAction>(JA)) return false; return true; @@ -5817,20 +6531,37 @@ bool Driver::GetReleaseVersion(StringRef Str, return false; } -std::pair<unsigned, unsigned> -Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { - unsigned IncludedFlagsBitmask = 0; - unsigned ExcludedFlagsBitmask = options::NoDriverOption; - - if (IsClCompatMode) { - // Include CL and Core options. - IncludedFlagsBitmask |= options::CLOption; - IncludedFlagsBitmask |= options::CoreOption; - } else { - ExcludedFlagsBitmask |= options::CLOption; - } +llvm::opt::Visibility +Driver::getOptionVisibilityMask(bool UseDriverMode) const { + if (!UseDriverMode) + return llvm::opt::Visibility(options::ClangOption); + if (IsCLMode()) + return llvm::opt::Visibility(options::CLOption); + if (IsDXCMode()) + return llvm::opt::Visibility(options::DXCOption); + if (IsFlangMode()) { + return llvm::opt::Visibility(options::FlangOption); + } + return llvm::opt::Visibility(options::ClangOption); +} - return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask); +const char *Driver::getExecutableForDriverMode(DriverMode Mode) { + switch (Mode) { + case GCCMode: + return "clang"; + case GXXMode: + return "clang++"; + case CPPMode: + return "clang-cpp"; + case CLMode: + return "clang-cl"; + case FlangMode: + return "flang"; + case DXCMode: + return "clang-dxc"; + } + + llvm_unreachable("Unhandled Mode"); } bool clang::driver::isOptimizationLevelFast(const ArgList &Args) { @@ -5862,11 +6593,11 @@ bool clang::driver::willEmitRemarks(const ArgList &Args) { llvm::StringRef clang::driver::getDriverMode(StringRef ProgName, ArrayRef<const char *> Args) { - static const std::string OptName = + static StringRef OptName = getDriverOptTable().getOption(options::OPT_driver_mode).getPrefixedName(); llvm::StringRef Opt; for (StringRef Arg : Args) { - if (!Arg.startswith(OptName)) + if (!Arg.starts_with(OptName)) continue; Opt = Arg; } @@ -5876,3 +6607,58 @@ llvm::StringRef clang::driver::getDriverMode(StringRef ProgName, } bool driver::IsClangCL(StringRef DriverMode) { return DriverMode.equals("cl"); } + +llvm::Error driver::expandResponseFiles(SmallVectorImpl<const char *> &Args, + bool ClangCLMode, + llvm::BumpPtrAllocator &Alloc, + llvm::vfs::FileSystem *FS) { + // Parse response files using the GNU syntax, unless we're in CL mode. There + // are two ways to put clang in CL compatibility mode: ProgName is either + // clang-cl or cl, or --driver-mode=cl is on the command line. The normal + // command line parsing can't happen until after response file parsing, so we + // have to manually search for a --driver-mode=cl argument the hard way. + // Finally, our -cc1 tools don't care which tokenization mode we use because + // response files written by clang will tokenize the same way in either mode. + enum { Default, POSIX, Windows } RSPQuoting = Default; + for (const char *F : Args) { + if (strcmp(F, "--rsp-quoting=posix") == 0) + RSPQuoting = POSIX; + else if (strcmp(F, "--rsp-quoting=windows") == 0) + RSPQuoting = Windows; + } + + // Determines whether we want nullptr markers in Args to indicate response + // files end-of-lines. We only use this for the /LINK driver argument with + // clang-cl.exe on Windows. + bool MarkEOLs = ClangCLMode; + + llvm::cl::TokenizerCallback Tokenizer; + if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode)) + Tokenizer = &llvm::cl::TokenizeWindowsCommandLine; + else + Tokenizer = &llvm::cl::TokenizeGNUCommandLine; + + if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).starts_with("-cc1")) + MarkEOLs = false; + + llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer); + ECtx.setMarkEOLs(MarkEOLs); + if (FS) + ECtx.setVFS(FS); + + if (llvm::Error Err = ECtx.expandResponseFiles(Args)) + return Err; + + // If -cc1 came from a response file, remove the EOL sentinels. + auto FirstArg = llvm::find_if(llvm::drop_begin(Args), + [](const char *A) { return A != nullptr; }); + if (FirstArg != Args.end() && StringRef(*FirstArg).starts_with("-cc1")) { + // If -cc1 came from a response file, remove the EOL sentinels. + if (MarkEOLs) { + auto newEnd = std::remove(Args.begin(), Args.end(), nullptr); + Args.resize(newEnd - Args.begin()); + } + } + + return llvm::Error::success(); +} diff --git a/contrib/llvm-project/clang/lib/Driver/DriverOptions.cpp b/contrib/llvm-project/clang/lib/Driver/DriverOptions.cpp index 67d4198d222a..b25801a8f3f4 100644 --- a/contrib/llvm-project/clang/lib/Driver/DriverOptions.cpp +++ b/contrib/llvm-project/clang/lib/Driver/DriverOptions.cpp @@ -16,40 +16,40 @@ using namespace clang::driver; using namespace clang::driver::options; using namespace llvm::opt; -#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE; +#define OPTTABLE_VALUES_CODE +#include "clang/Driver/Options.inc" +#undef OPTTABLE_VALUES_CODE + +#define PREFIX(NAME, VALUE) \ + static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \ + static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \ + NAME##_init, std::size(NAME##_init) - 1); #include "clang/Driver/Options.inc" #undef PREFIX -static const OptTable::Info InfoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES) \ - {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES}, +static constexpr const llvm::StringLiteral PrefixTable_init[] = +#define PREFIX_UNION(VALUES) VALUES +#include "clang/Driver/Options.inc" +#undef PREFIX_UNION + ; +static constexpr const llvm::ArrayRef<llvm::StringLiteral> + PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1); + +static constexpr OptTable::Info InfoTable[] = { +#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), #include "clang/Driver/Options.inc" #undef OPTION }; namespace { -class DriverOptTable : public OptTable { +class DriverOptTable : public PrecomputedOptTable { public: - DriverOptTable() - : OptTable(InfoTable) {} + DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {} }; - } const llvm::opt::OptTable &clang::driver::getDriverOptTable() { - static const DriverOptTable *Table = []() { - auto Result = std::make_unique<DriverOptTable>(); - // Options.inc is included in DriverOptions.cpp, and calls OptTable's - // addValues function. - // Opt is a variable used in the code fragment in Options.inc. - OptTable &Opt = *Result; -#define OPTTABLE_ARG_INIT -#include "clang/Driver/Options.inc" -#undef OPTTABLE_ARG_INIT - return Result.release(); - }(); - return *Table; + static DriverOptTable Table; + return Table; } diff --git a/contrib/llvm-project/clang/lib/Driver/Job.cpp b/contrib/llvm-project/clang/lib/Driver/Job.cpp index f63763effaff..a6c1581be796 100644 --- a/contrib/llvm-project/clang/lib/Driver/Job.cpp +++ b/contrib/llvm-project/clang/lib/Driver/Job.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" @@ -38,9 +39,10 @@ using namespace driver; Command::Command(const Action &Source, const Tool &Creator, ResponseFileSupport ResponseSupport, const char *Executable, const llvm::opt::ArgStringList &Arguments, - ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs) + ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs, + const char *PrependArg) : Source(Source), Creator(Creator), ResponseSupport(ResponseSupport), - Executable(Executable), Arguments(Arguments) { + Executable(Executable), PrependArg(PrependArg), Arguments(Arguments) { for (const auto &II : Inputs) if (II.isFilename()) InputInfoList.push_back(II); @@ -93,10 +95,10 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum, // These flags are treated as a single argument (e.g., -F<Dir>). StringRef FlagRef(Flag); - IsInclude = FlagRef.startswith("-F") || FlagRef.startswith("-I"); + IsInclude = FlagRef.starts_with("-F") || FlagRef.starts_with("-I"); if (IsInclude) return !HaveCrashVFS; - if (FlagRef.startswith("-fmodules-cache-path=")) + if (FlagRef.starts_with("-fmodules-cache-path=")) return true; SkipNum = 0; @@ -144,6 +146,10 @@ void Command::buildArgvForResponseFile( for (const auto *InputName : InputFileList) Inputs.insert(InputName); Out.push_back(Executable); + + if (PrependArg) + Out.push_back(PrependArg); + // In a file list, build args vector ignoring parameters that will go in the // response file (elements of the InputFileList vector) bool FirstInput = true; @@ -179,8 +185,8 @@ rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx, SmallString<128> NewInc; if (NumArgs == 1) { StringRef FlagRef(Args[Idx + NumArgs - 1]); - assert((FlagRef.startswith("-F") || FlagRef.startswith("-I")) && - "Expecting -I or -F"); + assert((FlagRef.starts_with("-F") || FlagRef.starts_with("-I")) && + "Expecting -I or -F"); StringRef Inc = FlagRef.slice(2, StringRef::npos); if (getAbsPath(Inc, NewInc)) { SmallString<128> NewArg(FlagRef.slice(0, 2)); @@ -209,6 +215,9 @@ void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, if (ResponseFile != nullptr) { buildArgvForResponseFile(ArgsRespFile); Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name + } else if (PrependArg) { + OS << ' '; + llvm::sys::printArg(OS, PrependArg, /*Quote=*/true); } bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty(); @@ -301,6 +310,11 @@ void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { Environment.push_back(nullptr); } +void Command::setRedirectFiles( + const std::vector<std::optional<std::string>> &Redirects) { + RedirectFiles = Redirects; +} + void Command::PrintFileNames() const { if (PrintInputFilenames) { for (const auto &Arg : InputInfoList) @@ -309,13 +323,15 @@ void Command::PrintFileNames() const { } } -int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, +int Command::Execute(ArrayRef<std::optional<StringRef>> Redirects, std::string *ErrMsg, bool *ExecutionFailed) const { PrintFileNames(); SmallVector<const char *, 128> Argv; if (ResponseFile == nullptr) { Argv.push_back(Executable); + if (PrependArg) + Argv.push_back(PrependArg); Argv.append(Arguments.begin(), Arguments.end()); Argv.push_back(nullptr); } else { @@ -342,16 +358,32 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, } } - Optional<ArrayRef<StringRef>> Env; + std::optional<ArrayRef<StringRef>> Env; std::vector<StringRef> ArgvVectorStorage; if (!Environment.empty()) { assert(Environment.back() == nullptr && "Environment vector should be null-terminated by now"); ArgvVectorStorage = llvm::toStringRefArray(Environment.data()); - Env = makeArrayRef(ArgvVectorStorage); + Env = ArrayRef(ArgvVectorStorage); } auto Args = llvm::toStringRefArray(Argv.data()); + + // Use Job-specific redirect files if they are present. + if (!RedirectFiles.empty()) { + std::vector<std::optional<StringRef>> RedirectFilesOptional; + for (const auto &Ele : RedirectFiles) + if (Ele) + RedirectFilesOptional.push_back(std::optional<StringRef>(*Ele)); + else + RedirectFilesOptional.push_back(std::nullopt); + + return llvm::sys::ExecuteAndWait(Executable, Args, Env, + ArrayRef(RedirectFilesOptional), + /*secondsToWait=*/0, /*memoryLimit=*/0, + ErrMsg, ExecutionFailed, &ProcStat); + } + return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects, /*secondsToWait*/ 0, /*memoryLimit*/ 0, ErrMsg, ExecutionFailed, &ProcStat); @@ -361,9 +393,10 @@ CC1Command::CC1Command(const Action &Source, const Tool &Creator, ResponseFileSupport ResponseSupport, const char *Executable, const llvm::opt::ArgStringList &Arguments, - ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs) + ArrayRef<InputInfo> Inputs, ArrayRef<InputInfo> Outputs, + const char *PrependArg) : Command(Source, Creator, ResponseSupport, Executable, Arguments, Inputs, - Outputs) { + Outputs, PrependArg) { InProcess = true; } @@ -374,7 +407,7 @@ void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, Command::Print(OS, Terminator, Quote, CrashInfo); } -int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, +int CC1Command::Execute(ArrayRef<std::optional<StringRef>> Redirects, std::string *ErrMsg, bool *ExecutionFailed) const { // FIXME: Currently, if there're more than one job, we disable // -fintegrate-cc1. If we're no longer a integrated-cc1 job, fallback to @@ -417,30 +450,6 @@ void CC1Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { "The CC1Command doesn't support changing the environment vars!"); } -ForceSuccessCommand::ForceSuccessCommand( - const Action &Source_, const Tool &Creator_, - ResponseFileSupport ResponseSupport, const char *Executable_, - const llvm::opt::ArgStringList &Arguments_, ArrayRef<InputInfo> Inputs, - ArrayRef<InputInfo> Outputs) - : Command(Source_, Creator_, ResponseSupport, Executable_, Arguments_, - Inputs, Outputs) {} - -void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator, - bool Quote, CrashReportInfo *CrashInfo) const { - Command::Print(OS, "", Quote, CrashInfo); - OS << " || (exit 0)" << Terminator; -} - -int ForceSuccessCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, - std::string *ErrMsg, - bool *ExecutionFailed) const { - int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed); - (void)Status; - if (ExecutionFailed) - *ExecutionFailed = false; - return 0; -} - void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo) const { for (const auto &Job : *this) diff --git a/contrib/llvm-project/clang/lib/Driver/Multilib.cpp b/contrib/llvm-project/clang/lib/Driver/Multilib.cpp index ab44ba50b5d5..9c091bbfdaba 100644 --- a/contrib/llvm-project/clang/lib/Driver/Multilib.cpp +++ b/contrib/llvm-project/clang/lib/Driver/Multilib.cpp @@ -8,14 +8,18 @@ #include "clang/Driver/Multilib.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSet.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/Support/YAMLParser.h" +#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -25,56 +29,17 @@ using namespace clang; using namespace driver; using namespace llvm::sys; -/// normalize Segment to "/foo/bar" or "". -static void normalizePathSegment(std::string &Segment) { - StringRef seg = Segment; - - // Prune trailing "/" or "./" - while (true) { - StringRef last = path::filename(seg); - if (last != ".") - break; - seg = path::parent_path(seg); - } - - if (seg.empty() || seg == "/") { - Segment.clear(); - return; - } - - // Add leading '/' - if (seg.front() != '/') { - Segment = "/" + seg.str(); - } else { - Segment = std::string(seg); - } -} - Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, - StringRef IncludeSuffix, int Priority) + StringRef IncludeSuffix, const flags_list &Flags, + StringRef ExclusiveGroup) : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix), - Priority(Priority) { - normalizePathSegment(this->GCCSuffix); - normalizePathSegment(this->OSSuffix); - normalizePathSegment(this->IncludeSuffix); -} - -Multilib &Multilib::gccSuffix(StringRef S) { - GCCSuffix = std::string(S); - normalizePathSegment(GCCSuffix); - return *this; -} - -Multilib &Multilib::osSuffix(StringRef S) { - OSSuffix = std::string(S); - normalizePathSegment(OSSuffix); - return *this; -} - -Multilib &Multilib::includeSuffix(StringRef S) { - IncludeSuffix = std::string(S); - normalizePathSegment(IncludeSuffix); - return *this; + Flags(Flags), ExclusiveGroup(ExclusiveGroup) { + assert(GCCSuffix.empty() || + (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); + assert(OSSuffix.empty() || + (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1)); + assert(IncludeSuffix.empty() || + (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1)); } LLVM_DUMP_METHOD void Multilib::dump() const { @@ -82,7 +47,6 @@ LLVM_DUMP_METHOD void Multilib::dump() const { } void Multilib::print(raw_ostream &OS) const { - assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/')); if (GCCSuffix.empty()) OS << "."; else { @@ -90,27 +54,11 @@ void Multilib::print(raw_ostream &OS) const { } OS << ";"; for (StringRef Flag : Flags) { - if (Flag.front() == '+') + if (Flag.front() == '-') OS << "@" << Flag.substr(1); } } -bool Multilib::isValid() const { - llvm::StringMap<int> FlagSet; - for (unsigned I = 0, N = Flags.size(); I != N; ++I) { - StringRef Flag(Flags[I]); - llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1)); - - assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-'); - - if (SI == FlagSet.end()) - FlagSet[Flag.substr(1)] = I; - else if (Flags[I] != Flags[SI->getValue()]) - return false; - } - return true; -} - bool Multilib::operator==(const Multilib &Other) const { // Check whether the flags sets match // allowing for the match to be order invariant @@ -119,7 +67,7 @@ bool Multilib::operator==(const Multilib &Other) const { MyFlags.insert(Flag); for (const auto &Flag : Other.Flags) - if (MyFlags.find(Flag) == MyFlags.end()) + if (!MyFlags.contains(Flag)) return false; if (osSuffix() != Other.osSuffix()) @@ -139,147 +87,225 @@ raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) { return OS; } -MultilibSet &MultilibSet::Maybe(const Multilib &M) { - Multilib Opposite; - // Negate any '+' flags - for (StringRef Flag : M.flags()) { - if (Flag.front() == '+') - Opposite.flags().push_back(("-" + Flag.substr(1)).str()); - } - return Either(M, Opposite); -} - -MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) { - return Either({M1, M2}); -} - -MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, - const Multilib &M3) { - return Either({M1, M2, M3}); -} - -MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, - const Multilib &M3, const Multilib &M4) { - return Either({M1, M2, M3, M4}); -} - -MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, - const Multilib &M3, const Multilib &M4, - const Multilib &M5) { - return Either({M1, M2, M3, M4, M5}); -} - -static Multilib compose(const Multilib &Base, const Multilib &New) { - SmallString<128> GCCSuffix; - llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); - SmallString<128> OSSuffix; - llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); - SmallString<128> IncludeSuffix; - llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), - New.includeSuffix()); - - Multilib Composed(GCCSuffix, OSSuffix, IncludeSuffix); - - Multilib::flags_list &Flags = Composed.flags(); - - Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); - Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); - - return Composed; +MultilibSet &MultilibSet::FilterOut(FilterCallback F) { + llvm::erase_if(Multilibs, F); + return *this; } -MultilibSet &MultilibSet::Either(ArrayRef<Multilib> MultilibSegments) { - multilib_list Composed; +void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } - if (Multilibs.empty()) - Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), - MultilibSegments.end()); - else { - for (const auto &New : MultilibSegments) { - for (const auto &Base : *this) { - Multilib MO = compose(Base, New); - if (MO.isValid()) - Composed.push_back(MO); - } +bool MultilibSet::select(const Multilib::flags_list &Flags, + llvm::SmallVectorImpl<Multilib> &Selected) const { + llvm::StringSet<> FlagSet(expandFlags(Flags)); + Selected.clear(); + + // Decide which multilibs we're going to select at all. + llvm::DenseSet<StringRef> ExclusiveGroupsSelected; + for (const Multilib &M : llvm::reverse(Multilibs)) { + // If this multilib doesn't match all our flags, don't select it. + if (!llvm::all_of(M.flags(), [&FlagSet](const std::string &F) { + return FlagSet.contains(F); + })) + continue; + + const std::string &group = M.exclusiveGroup(); + if (!group.empty()) { + // If this multilib has the same ExclusiveGroup as one we've already + // selected, skip it. We're iterating in reverse order, so the group + // member we've selected already is preferred. + // + // Otherwise, add the group name to the set of groups we've already + // selected a member of. + auto [It, Inserted] = ExclusiveGroupsSelected.insert(group); + if (!Inserted) + continue; } - Multilibs = Composed; + // Select this multilib. + Selected.push_back(M); } - return *this; -} + // We iterated in reverse order, so now put Selected back the right way + // round. + std::reverse(Selected.begin(), Selected.end()); -MultilibSet &MultilibSet::FilterOut(FilterCallback F) { - filterInPlace(F, Multilibs); - return *this; + return !Selected.empty(); } -MultilibSet &MultilibSet::FilterOut(const char *Regex) { - llvm::Regex R(Regex); -#ifndef NDEBUG - std::string Error; - if (!R.isValid(Error)) { - llvm::errs() << Error; - llvm_unreachable("Invalid regex!"); +llvm::StringSet<> +MultilibSet::expandFlags(const Multilib::flags_list &InFlags) const { + llvm::StringSet<> Result; + for (const auto &F : InFlags) + Result.insert(F); + for (const FlagMatcher &M : FlagMatchers) { + std::string RegexString(M.Match); + + // Make the regular expression match the whole string. + if (!StringRef(M.Match).starts_with("^")) + RegexString.insert(RegexString.begin(), '^'); + if (!StringRef(M.Match).ends_with("$")) + RegexString.push_back('$'); + + const llvm::Regex Regex(RegexString); + assert(Regex.isValid()); + if (llvm::any_of(InFlags, + [&Regex](StringRef F) { return Regex.match(F); })) { + Result.insert(M.Flags.begin(), M.Flags.end()); + } } -#endif - - filterInPlace([&R](const Multilib &M) { return R.match(M.gccSuffix()); }, - Multilibs); - return *this; -} - -void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } - -void MultilibSet::combineWith(const MultilibSet &Other) { - Multilibs.insert(Multilibs.end(), Other.begin(), Other.end()); + return Result; } -static bool isFlagEnabled(StringRef Flag) { - char Indicator = Flag.front(); - assert(Indicator == '+' || Indicator == '-'); - return Indicator == '+'; -} +namespace { + +// When updating this also update MULTILIB_VERSION in MultilibTest.cpp +static const VersionTuple MultilibVersionCurrent(1, 0); + +struct MultilibSerialization { + std::string Dir; + std::vector<std::string> Flags; + std::string Group; +}; + +enum class MultilibGroupType { + /* + * The only group type currently supported is 'Exclusive', which indicates a + * group of multilibs of which at most one may be selected. + */ + Exclusive, + + /* + * Future possibility: a second group type indicating a set of library + * directories that are mutually _dependent_ rather than mutually exclusive: + * if you include one you must include them all. + * + * It might also be useful to allow groups to be members of other groups, so + * that a mutually exclusive group could contain a mutually dependent set of + * library directories, or vice versa. + * + * These additional features would need changes in the implementation, but + * the YAML schema is set up so they can be added without requiring changes + * in existing users' multilib.yaml files. + */ +}; + +struct MultilibGroupSerialization { + std::string Name; + MultilibGroupType Type; +}; + +struct MultilibSetSerialization { + llvm::VersionTuple MultilibVersion; + std::vector<MultilibGroupSerialization> Groups; + std::vector<MultilibSerialization> Multilibs; + std::vector<MultilibSet::FlagMatcher> FlagMatchers; +}; + +} // end anonymous namespace + +template <> struct llvm::yaml::MappingTraits<MultilibSerialization> { + static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) { + io.mapRequired("Dir", V.Dir); + io.mapRequired("Flags", V.Flags); + io.mapOptional("Group", V.Group); + } + static std::string validate(IO &io, MultilibSerialization &V) { + if (StringRef(V.Dir).starts_with("/")) + return "paths must be relative but \"" + V.Dir + "\" starts with \"/\""; + return std::string{}; + } +}; -bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const { - llvm::StringMap<bool> FlagSet; +template <> struct llvm::yaml::ScalarEnumerationTraits<MultilibGroupType> { + static void enumeration(IO &io, MultilibGroupType &Val) { + io.enumCase(Val, "Exclusive", MultilibGroupType::Exclusive); + } +}; - // Stuff all of the flags into the FlagSet such that a true mappend indicates - // the flag was enabled, and a false mappend indicates the flag was disabled. - for (StringRef Flag : Flags) - FlagSet[Flag.substr(1)] = isFlagEnabled(Flag); +template <> struct llvm::yaml::MappingTraits<MultilibGroupSerialization> { + static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &V) { + io.mapRequired("Name", V.Name); + io.mapRequired("Type", V.Type); + } +}; - multilib_list Filtered = filterCopy([&FlagSet](const Multilib &M) { - for (StringRef Flag : M.flags()) { - llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1)); - if (SI != FlagSet.end()) - if (SI->getValue() != isFlagEnabled(Flag)) - return true; +template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> { + static void mapping(llvm::yaml::IO &io, MultilibSet::FlagMatcher &M) { + io.mapRequired("Match", M.Match); + io.mapRequired("Flags", M.Flags); + } + static std::string validate(IO &io, MultilibSet::FlagMatcher &M) { + llvm::Regex Regex(M.Match); + std::string RegexError; + if (!Regex.isValid(RegexError)) + return RegexError; + if (M.Flags.empty()) + return "value required for 'Flags'"; + return std::string{}; + } +}; + +template <> struct llvm::yaml::MappingTraits<MultilibSetSerialization> { + static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) { + io.mapRequired("MultilibVersion", M.MultilibVersion); + io.mapRequired("Variants", M.Multilibs); + io.mapOptional("Groups", M.Groups); + io.mapOptional("Mappings", M.FlagMatchers); + } + static std::string validate(IO &io, MultilibSetSerialization &M) { + if (M.MultilibVersion.empty()) + return "missing required key 'MultilibVersion'"; + if (M.MultilibVersion.getMajor() != MultilibVersionCurrent.getMajor()) + return "multilib version " + M.MultilibVersion.getAsString() + + " is unsupported"; + if (M.MultilibVersion.getMinor() > MultilibVersionCurrent.getMinor()) + return "multilib version " + M.MultilibVersion.getAsString() + + " is unsupported"; + for (const MultilibSerialization &Lib : M.Multilibs) { + if (!Lib.Group.empty()) { + bool Found = false; + for (const MultilibGroupSerialization &Group : M.Groups) + if (Group.Name == Lib.Group) { + Found = true; + break; + } + if (!Found) + return "multilib \"" + Lib.Dir + + "\" specifies undefined group name \"" + Lib.Group + "\""; + } } - return false; - }, Multilibs); - - if (Filtered.empty()) - return false; - if (Filtered.size() == 1) { - M = Filtered[0]; - return true; + return std::string{}; } - - // Sort multilibs by priority and select the one with the highest priority. - llvm::sort(Filtered.begin(), Filtered.end(), - [](const Multilib &a, const Multilib &b) -> bool { - return a.priority() > b.priority(); - }); - - if (Filtered[0].priority() > Filtered[1].priority()) { - M = Filtered[0]; - return true; +}; + +LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization) +LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization) +LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::FlagMatcher) + +llvm::ErrorOr<MultilibSet> +MultilibSet::parseYaml(llvm::MemoryBufferRef Input, + llvm::SourceMgr::DiagHandlerTy DiagHandler, + void *DiagHandlerCtxt) { + MultilibSetSerialization MS; + llvm::yaml::Input YamlInput(Input, nullptr, DiagHandler, DiagHandlerCtxt); + YamlInput >> MS; + if (YamlInput.error()) + return YamlInput.error(); + + multilib_list Multilibs; + Multilibs.reserve(MS.Multilibs.size()); + for (const auto &M : MS.Multilibs) { + std::string Dir; + if (M.Dir != ".") + Dir = "/" + M.Dir; + // We transfer M.Group straight into the ExclusiveGroup parameter for the + // Multilib constructor. If we later support more than one type of group, + // we'll have to look up the group name in MS.Groups, check its type, and + // decide what to do here. + Multilibs.emplace_back(Dir, Dir, Dir, M.Flags, M.Group); } - // TODO: We should consider returning llvm::Error rather than aborting. - assert(false && "More than one multilib with the same priority"); - return false; + return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers)); } LLVM_DUMP_METHOD void MultilibSet::dump() const { @@ -291,17 +317,6 @@ void MultilibSet::print(raw_ostream &OS) const { OS << M << "\n"; } -MultilibSet::multilib_list MultilibSet::filterCopy(FilterCallback F, - const multilib_list &Ms) { - multilib_list Copy(Ms); - filterInPlace(F, Copy); - return Copy; -} - -void MultilibSet::filterInPlace(FilterCallback F, multilib_list &Ms) { - llvm::erase_if(Ms, F); -} - raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) { MS.print(OS); return OS; diff --git a/contrib/llvm-project/clang/lib/Driver/MultilibBuilder.cpp b/contrib/llvm-project/clang/lib/Driver/MultilibBuilder.cpp new file mode 100644 index 000000000000..15adf5017780 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/MultilibBuilder.cpp @@ -0,0 +1,197 @@ +//===- MultilibBuilder.cpp - MultilibBuilder Implementation -===// +// +// 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 "clang/Driver/MultilibBuilder.h" +#include "ToolChains/CommonArgs.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace driver; + +/// normalize Segment to "/foo/bar" or "". +static void normalizePathSegment(std::string &Segment) { + StringRef seg = Segment; + + // Prune trailing "/" or "./" + while (true) { + StringRef last = llvm::sys::path::filename(seg); + if (last != ".") + break; + seg = llvm::sys::path::parent_path(seg); + } + + if (seg.empty() || seg == "/") { + Segment.clear(); + return; + } + + // Add leading '/' + if (seg.front() != '/') { + Segment = "/" + seg.str(); + } else { + Segment = std::string(seg); + } +} + +MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include) + : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include) { + normalizePathSegment(GCCSuffix); + normalizePathSegment(OSSuffix); + normalizePathSegment(IncludeSuffix); +} + +MultilibBuilder::MultilibBuilder(StringRef Suffix) + : MultilibBuilder(Suffix, Suffix, Suffix) {} + +MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) { + GCCSuffix = std::string(S); + normalizePathSegment(GCCSuffix); + return *this; +} + +MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) { + OSSuffix = std::string(S); + normalizePathSegment(OSSuffix); + return *this; +} + +MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) { + IncludeSuffix = std::string(S); + normalizePathSegment(IncludeSuffix); + return *this; +} + +bool MultilibBuilder::isValid() const { + llvm::StringMap<int> FlagSet; + for (unsigned I = 0, N = Flags.size(); I != N; ++I) { + StringRef Flag(Flags[I]); + llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1)); + + assert(StringRef(Flag).front() == '-' || StringRef(Flag).front() == '!'); + + if (SI == FlagSet.end()) + FlagSet[Flag.substr(1)] = I; + else if (Flags[I] != Flags[SI->getValue()]) + return false; + } + return true; +} + +MultilibBuilder &MultilibBuilder::flag(StringRef Flag, bool Disallow) { + tools::addMultilibFlag(!Disallow, Flag, Flags); + return *this; +} + +Multilib MultilibBuilder::makeMultilib() const { + return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags); +} + +MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) { + MultilibBuilder Opposite; + // Negate positive flags + for (StringRef Flag : M.flags()) { + if (Flag.front() == '-') + Opposite.flag(Flag, /*Disallow=*/true); + } + return Either(M, Opposite); +} + +MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, + const MultilibBuilder &M2) { + return Either({M1, M2}); +} + +MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, + const MultilibBuilder &M2, + const MultilibBuilder &M3) { + return Either({M1, M2, M3}); +} + +MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, + const MultilibBuilder &M2, + const MultilibBuilder &M3, + const MultilibBuilder &M4) { + return Either({M1, M2, M3, M4}); +} + +MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, + const MultilibBuilder &M2, + const MultilibBuilder &M3, + const MultilibBuilder &M4, + const MultilibBuilder &M5) { + return Either({M1, M2, M3, M4, M5}); +} + +static MultilibBuilder compose(const MultilibBuilder &Base, + const MultilibBuilder &New) { + SmallString<128> GCCSuffix; + llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); + SmallString<128> OSSuffix; + llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); + SmallString<128> IncludeSuffix; + llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), + New.includeSuffix()); + + MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix); + + MultilibBuilder::flags_list &Flags = Composed.flags(); + + Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); + Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); + + return Composed; +} + +MultilibSetBuilder & +MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) { + multilib_list Composed; + + if (Multilibs.empty()) + Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), + MultilibSegments.end()); + else { + for (const auto &New : MultilibSegments) { + for (const auto &Base : Multilibs) { + MultilibBuilder MO = compose(Base, New); + if (MO.isValid()) + Composed.push_back(MO); + } + } + + Multilibs = Composed; + } + + return *this; +} + +MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) { + llvm::Regex R(Regex); +#ifndef NDEBUG + std::string Error; + if (!R.isValid(Error)) { + llvm::errs() << Error; + llvm_unreachable("Invalid regex!"); + } +#endif + llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) { + return R.match(M.gccSuffix()); + }); + return *this; +} + +MultilibSet MultilibSetBuilder::makeMultilibSet() const { + MultilibSet Result; + for (const auto &M : Multilibs) { + Result.push_back(M.makeMultilib()); + } + return Result; +} diff --git a/contrib/llvm-project/clang/lib/Driver/OffloadBundler.cpp b/contrib/llvm-project/clang/lib/Driver/OffloadBundler.cpp new file mode 100644 index 000000000000..b1091aca5616 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/OffloadBundler.cpp @@ -0,0 +1,1684 @@ +//===- OffloadBundler.cpp - File Bundling and Unbundling ------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements an offload bundling API that bundles different files +/// that relate with the same source code but different targets into a single +/// one. Also the implements the opposite functionality, i.e. unbundle files +/// previous created by this API. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/OffloadBundler.h" +#include "clang/Basic/Cuda.h" +#include "clang/Basic/TargetID.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MD5.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <forward_list> +#include <llvm/Support/Process.h> +#include <memory> +#include <set> +#include <string> +#include <system_error> +#include <utility> + +using namespace llvm; +using namespace llvm::object; +using namespace clang; + +static llvm::TimerGroup + ClangOffloadBundlerTimerGroup("Clang Offload Bundler Timer Group", + "Timer group for clang offload bundler"); + +/// Magic string that marks the existence of offloading data. +#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__" + +OffloadTargetInfo::OffloadTargetInfo(const StringRef Target, + const OffloadBundlerConfig &BC) + : BundlerConfig(BC) { + + // TODO: Add error checking from ClangOffloadBundler.cpp + auto TargetFeatures = Target.split(':'); + auto TripleOrGPU = TargetFeatures.first.rsplit('-'); + + if (clang::StringToCudaArch(TripleOrGPU.second) != clang::CudaArch::UNKNOWN) { + auto KindTriple = TripleOrGPU.first.split('-'); + this->OffloadKind = KindTriple.first; + + // Enforce optional env field to standardize bundles + llvm::Triple t = llvm::Triple(KindTriple.second); + this->Triple = llvm::Triple(t.getArchName(), t.getVendorName(), + t.getOSName(), t.getEnvironmentName()); + + this->TargetID = Target.substr(Target.find(TripleOrGPU.second)); + } else { + auto KindTriple = TargetFeatures.first.split('-'); + this->OffloadKind = KindTriple.first; + + // Enforce optional env field to standardize bundles + llvm::Triple t = llvm::Triple(KindTriple.second); + this->Triple = llvm::Triple(t.getArchName(), t.getVendorName(), + t.getOSName(), t.getEnvironmentName()); + + this->TargetID = ""; + } +} + +bool OffloadTargetInfo::hasHostKind() const { + return this->OffloadKind == "host"; +} + +bool OffloadTargetInfo::isOffloadKindValid() const { + return OffloadKind == "host" || OffloadKind == "openmp" || + OffloadKind == "hip" || OffloadKind == "hipv4"; +} + +bool OffloadTargetInfo::isOffloadKindCompatible( + const StringRef TargetOffloadKind) const { + if (OffloadKind == TargetOffloadKind) + return true; + if (BundlerConfig.HipOpenmpCompatible) { + bool HIPCompatibleWithOpenMP = OffloadKind.starts_with_insensitive("hip") && + TargetOffloadKind == "openmp"; + bool OpenMPCompatibleWithHIP = + OffloadKind == "openmp" && + TargetOffloadKind.starts_with_insensitive("hip"); + return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP; + } + return false; +} + +bool OffloadTargetInfo::isTripleValid() const { + return !Triple.str().empty() && Triple.getArch() != Triple::UnknownArch; +} + +bool OffloadTargetInfo::operator==(const OffloadTargetInfo &Target) const { + return OffloadKind == Target.OffloadKind && + Triple.isCompatibleWith(Target.Triple) && TargetID == Target.TargetID; +} + +std::string OffloadTargetInfo::str() const { + return Twine(OffloadKind + "-" + Triple.str() + "-" + TargetID).str(); +} + +static StringRef getDeviceFileExtension(StringRef Device, + StringRef BundleFileName) { + if (Device.contains("gfx")) + return ".bc"; + if (Device.contains("sm_")) + return ".cubin"; + return sys::path::extension(BundleFileName); +} + +static std::string getDeviceLibraryFileName(StringRef BundleFileName, + StringRef Device) { + StringRef LibName = sys::path::stem(BundleFileName); + StringRef Extension = getDeviceFileExtension(Device, BundleFileName); + + std::string Result; + Result += LibName; + Result += Extension; + return Result; +} + +namespace { +/// Generic file handler interface. +class FileHandler { +public: + struct BundleInfo { + StringRef BundleID; + }; + + FileHandler() {} + + virtual ~FileHandler() {} + + /// Update the file handler with information from the header of the bundled + /// file. + virtual Error ReadHeader(MemoryBuffer &Input) = 0; + + /// Read the marker of the next bundled to be read in the file. The bundle + /// name is returned if there is one in the file, or `std::nullopt` if there + /// are no more bundles to be read. + virtual Expected<std::optional<StringRef>> + ReadBundleStart(MemoryBuffer &Input) = 0; + + /// Read the marker that closes the current bundle. + virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0; + + /// Read the current bundle and write the result into the stream \a OS. + virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0; + + /// Write the header of the bundled file to \a OS based on the information + /// gathered from \a Inputs. + virtual Error WriteHeader(raw_ostream &OS, + ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0; + + /// Write the marker that initiates a bundle for the triple \a TargetTriple to + /// \a OS. + virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0; + + /// Write the marker that closes a bundle for the triple \a TargetTriple to \a + /// OS. + virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0; + + /// Write the bundle from \a Input into \a OS. + virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0; + + /// Finalize output file. + virtual Error finalizeOutputFile() { return Error::success(); } + + /// List bundle IDs in \a Input. + virtual Error listBundleIDs(MemoryBuffer &Input) { + if (Error Err = ReadHeader(Input)) + return Err; + return forEachBundle(Input, [&](const BundleInfo &Info) -> Error { + llvm::outs() << Info.BundleID << '\n'; + Error Err = listBundleIDsCallback(Input, Info); + if (Err) + return Err; + return Error::success(); + }); + } + + /// Get bundle IDs in \a Input in \a BundleIds. + virtual Error getBundleIDs(MemoryBuffer &Input, + std::set<StringRef> &BundleIds) { + if (Error Err = ReadHeader(Input)) + return Err; + return forEachBundle(Input, [&](const BundleInfo &Info) -> Error { + BundleIds.insert(Info.BundleID); + Error Err = listBundleIDsCallback(Input, Info); + if (Err) + return Err; + return Error::success(); + }); + } + + /// For each bundle in \a Input, do \a Func. + Error forEachBundle(MemoryBuffer &Input, + std::function<Error(const BundleInfo &)> Func) { + while (true) { + Expected<std::optional<StringRef>> CurTripleOrErr = + ReadBundleStart(Input); + if (!CurTripleOrErr) + return CurTripleOrErr.takeError(); + + // No more bundles. + if (!*CurTripleOrErr) + break; + + StringRef CurTriple = **CurTripleOrErr; + assert(!CurTriple.empty()); + + BundleInfo Info{CurTriple}; + if (Error Err = Func(Info)) + return Err; + } + return Error::success(); + } + +protected: + virtual Error listBundleIDsCallback(MemoryBuffer &Input, + const BundleInfo &Info) { + return Error::success(); + } +}; + +/// Handler for binary files. The bundled file will have the following format +/// (all integers are stored in little-endian format): +/// +/// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string) +/// +/// NumberOfOffloadBundles (8-byte integer) +/// +/// OffsetOfBundle1 (8-byte integer) +/// SizeOfBundle1 (8-byte integer) +/// NumberOfBytesInTripleOfBundle1 (8-byte integer) +/// TripleOfBundle1 (byte length defined before) +/// +/// ... +/// +/// OffsetOfBundleN (8-byte integer) +/// SizeOfBundleN (8-byte integer) +/// NumberOfBytesInTripleOfBundleN (8-byte integer) +/// TripleOfBundleN (byte length defined before) +/// +/// Bundle1 +/// ... +/// BundleN + +/// Read 8-byte integers from a buffer in little-endian format. +static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) { + return llvm::support::endian::read64le(Buffer.data() + pos); +} + +/// Write 8-byte integers to a buffer in little-endian format. +static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) { + llvm::support::endian::write(OS, Val, llvm::endianness::little); +} + +class BinaryFileHandler final : public FileHandler { + /// Information about the bundles extracted from the header. + struct BinaryBundleInfo final : public BundleInfo { + /// Size of the bundle. + uint64_t Size = 0u; + /// Offset at which the bundle starts in the bundled file. + uint64_t Offset = 0u; + + BinaryBundleInfo() {} + BinaryBundleInfo(uint64_t Size, uint64_t Offset) + : Size(Size), Offset(Offset) {} + }; + + /// Map between a triple and the corresponding bundle information. + StringMap<BinaryBundleInfo> BundlesInfo; + + /// Iterator for the bundle information that is being read. + StringMap<BinaryBundleInfo>::iterator CurBundleInfo; + StringMap<BinaryBundleInfo>::iterator NextBundleInfo; + + /// Current bundle target to be written. + std::string CurWriteBundleTarget; + + /// Configuration options and arrays for this bundler job + const OffloadBundlerConfig &BundlerConfig; + +public: + // TODO: Add error checking from ClangOffloadBundler.cpp + BinaryFileHandler(const OffloadBundlerConfig &BC) : BundlerConfig(BC) {} + + ~BinaryFileHandler() final {} + + Error ReadHeader(MemoryBuffer &Input) final { + StringRef FC = Input.getBuffer(); + + // Initialize the current bundle with the end of the container. + CurBundleInfo = BundlesInfo.end(); + + // Check if buffer is smaller than magic string. + size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1; + if (ReadChars > FC.size()) + return Error::success(); + + // Check if no magic was found. + if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle) + return Error::success(); + + // Read number of bundles. + if (ReadChars + 8 > FC.size()) + return Error::success(); + + uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars); + ReadChars += 8; + + // Read bundle offsets, sizes and triples. + for (uint64_t i = 0; i < NumberOfBundles; ++i) { + + // Read offset. + if (ReadChars + 8 > FC.size()) + return Error::success(); + + uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars); + ReadChars += 8; + + // Read size. + if (ReadChars + 8 > FC.size()) + return Error::success(); + + uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars); + ReadChars += 8; + + // Read triple size. + if (ReadChars + 8 > FC.size()) + return Error::success(); + + uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars); + ReadChars += 8; + + // Read triple. + if (ReadChars + TripleSize > FC.size()) + return Error::success(); + + StringRef Triple(&FC.data()[ReadChars], TripleSize); + ReadChars += TripleSize; + + // Check if the offset and size make sense. + if (!Offset || Offset + Size > FC.size()) + return Error::success(); + + assert(!BundlesInfo.contains(Triple) && "Triple is duplicated??"); + BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset); + } + // Set the iterator to where we will start to read. + CurBundleInfo = BundlesInfo.end(); + NextBundleInfo = BundlesInfo.begin(); + return Error::success(); + } + + Expected<std::optional<StringRef>> + ReadBundleStart(MemoryBuffer &Input) final { + if (NextBundleInfo == BundlesInfo.end()) + return std::nullopt; + CurBundleInfo = NextBundleInfo++; + return CurBundleInfo->first(); + } + + Error ReadBundleEnd(MemoryBuffer &Input) final { + assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!"); + return Error::success(); + } + + Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final { + assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!"); + StringRef FC = Input.getBuffer(); + OS.write(FC.data() + CurBundleInfo->second.Offset, + CurBundleInfo->second.Size); + return Error::success(); + } + + Error WriteHeader(raw_ostream &OS, + ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final { + + // Compute size of the header. + uint64_t HeaderSize = 0; + + HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1; + HeaderSize += 8; // Number of Bundles + + for (auto &T : BundlerConfig.TargetNames) { + HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple. + HeaderSize += T.size(); // The triple. + } + + // Write to the buffer the header. + OS << OFFLOAD_BUNDLER_MAGIC_STR; + + Write8byteIntegerToBuffer(OS, BundlerConfig.TargetNames.size()); + + unsigned Idx = 0; + for (auto &T : BundlerConfig.TargetNames) { + MemoryBuffer &MB = *Inputs[Idx++]; + HeaderSize = alignTo(HeaderSize, BundlerConfig.BundleAlignment); + // Bundle offset. + Write8byteIntegerToBuffer(OS, HeaderSize); + // Size of the bundle (adds to the next bundle's offset) + Write8byteIntegerToBuffer(OS, MB.getBufferSize()); + BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize); + HeaderSize += MB.getBufferSize(); + // Size of the triple + Write8byteIntegerToBuffer(OS, T.size()); + // Triple + OS << T; + } + return Error::success(); + } + + Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final { + CurWriteBundleTarget = TargetTriple.str(); + return Error::success(); + } + + Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final { + return Error::success(); + } + + Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final { + auto BI = BundlesInfo[CurWriteBundleTarget]; + + // Pad with 0 to reach specified offset. + size_t CurrentPos = OS.tell(); + size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0; + for (size_t I = 0; I < PaddingSize; ++I) + OS.write('\0'); + assert(OS.tell() == BI.Offset); + + OS.write(Input.getBufferStart(), Input.getBufferSize()); + + return Error::success(); + } +}; + +// This class implements a list of temporary files that are removed upon +// object destruction. +class TempFileHandlerRAII { +public: + ~TempFileHandlerRAII() { + for (const auto &File : Files) + sys::fs::remove(File); + } + + // Creates temporary file with given contents. + Expected<StringRef> Create(std::optional<ArrayRef<char>> Contents) { + SmallString<128u> File; + if (std::error_code EC = + sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File)) + return createFileError(File, EC); + Files.push_front(File); + + if (Contents) { + std::error_code EC; + raw_fd_ostream OS(File, EC); + if (EC) + return createFileError(File, EC); + OS.write(Contents->data(), Contents->size()); + } + return Files.front().str(); + } + +private: + std::forward_list<SmallString<128u>> Files; +}; + +/// Handler for object files. The bundles are organized by sections with a +/// designated name. +/// +/// To unbundle, we just copy the contents of the designated section. +class ObjectFileHandler final : public FileHandler { + + /// The object file we are currently dealing with. + std::unique_ptr<ObjectFile> Obj; + + /// Return the input file contents. + StringRef getInputFileContents() const { return Obj->getData(); } + + /// Return bundle name (<kind>-<triple>) if the provided section is an offload + /// section. + static Expected<std::optional<StringRef>> + IsOffloadSection(SectionRef CurSection) { + Expected<StringRef> NameOrErr = CurSection.getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + + // If it does not start with the reserved suffix, just skip this section. + if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle) + return std::nullopt; + + // Return the triple that is right after the reserved prefix. + return NameOrErr->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1); + } + + /// Total number of inputs. + unsigned NumberOfInputs = 0; + + /// Total number of processed inputs, i.e, inputs that were already + /// read from the buffers. + unsigned NumberOfProcessedInputs = 0; + + /// Iterator of the current and next section. + section_iterator CurrentSection; + section_iterator NextSection; + + /// Configuration options and arrays for this bundler job + const OffloadBundlerConfig &BundlerConfig; + +public: + // TODO: Add error checking from ClangOffloadBundler.cpp + ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn, + const OffloadBundlerConfig &BC) + : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()), + NextSection(Obj->section_begin()), BundlerConfig(BC) {} + + ~ObjectFileHandler() final {} + + Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); } + + Expected<std::optional<StringRef>> + ReadBundleStart(MemoryBuffer &Input) final { + while (NextSection != Obj->section_end()) { + CurrentSection = NextSection; + ++NextSection; + + // Check if the current section name starts with the reserved prefix. If + // so, return the triple. + Expected<std::optional<StringRef>> TripleOrErr = + IsOffloadSection(*CurrentSection); + if (!TripleOrErr) + return TripleOrErr.takeError(); + if (*TripleOrErr) + return **TripleOrErr; + } + return std::nullopt; + } + + Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); } + + Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final { + Expected<StringRef> ContentOrErr = CurrentSection->getContents(); + if (!ContentOrErr) + return ContentOrErr.takeError(); + StringRef Content = *ContentOrErr; + + // Copy fat object contents to the output when extracting host bundle. + if (Content.size() == 1u && Content.front() == 0) + Content = StringRef(Input.getBufferStart(), Input.getBufferSize()); + + OS.write(Content.data(), Content.size()); + return Error::success(); + } + + Error WriteHeader(raw_ostream &OS, + ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final { + assert(BundlerConfig.HostInputIndex != ~0u && + "Host input index not defined."); + + // Record number of inputs. + NumberOfInputs = Inputs.size(); + return Error::success(); + } + + Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final { + ++NumberOfProcessedInputs; + return Error::success(); + } + + Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final { + return Error::success(); + } + + Error finalizeOutputFile() final { + assert(NumberOfProcessedInputs <= NumberOfInputs && + "Processing more inputs that actually exist!"); + assert(BundlerConfig.HostInputIndex != ~0u && + "Host input index not defined."); + + // If this is not the last output, we don't have to do anything. + if (NumberOfProcessedInputs != NumberOfInputs) + return Error::success(); + + // We will use llvm-objcopy to add target objects sections to the output + // fat object. These sections should have 'exclude' flag set which tells + // link editor to remove them from linker inputs when linking executable or + // shared library. + + assert(BundlerConfig.ObjcopyPath != "" && + "llvm-objcopy path not specified"); + + // Temporary files that need to be removed. + TempFileHandlerRAII TempFiles; + + // Compose llvm-objcopy command line for add target objects' sections with + // appropriate flags. + BumpPtrAllocator Alloc; + StringSaver SS{Alloc}; + SmallVector<StringRef, 8u> ObjcopyArgs{"llvm-objcopy"}; + + for (unsigned I = 0; I < NumberOfInputs; ++I) { + StringRef InputFile = BundlerConfig.InputFileNames[I]; + if (I == BundlerConfig.HostInputIndex) { + // Special handling for the host bundle. We do not need to add a + // standard bundle for the host object since we are going to use fat + // object as a host object. Therefore use dummy contents (one zero byte) + // when creating section for the host bundle. + Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0)); + if (!TempFileOrErr) + return TempFileOrErr.takeError(); + InputFile = *TempFileOrErr; + } + + ObjcopyArgs.push_back( + SS.save(Twine("--add-section=") + OFFLOAD_BUNDLER_MAGIC_STR + + BundlerConfig.TargetNames[I] + "=" + InputFile)); + ObjcopyArgs.push_back( + SS.save(Twine("--set-section-flags=") + OFFLOAD_BUNDLER_MAGIC_STR + + BundlerConfig.TargetNames[I] + "=readonly,exclude")); + } + ObjcopyArgs.push_back("--"); + ObjcopyArgs.push_back( + BundlerConfig.InputFileNames[BundlerConfig.HostInputIndex]); + ObjcopyArgs.push_back(BundlerConfig.OutputFileNames.front()); + + if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs)) + return Err; + + return Error::success(); + } + + Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final { + return Error::success(); + } + +private: + Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) { + // If the user asked for the commands to be printed out, we do that + // instead of executing it. + if (BundlerConfig.PrintExternalCommands) { + errs() << "\"" << Objcopy << "\""; + for (StringRef Arg : drop_begin(Args, 1)) + errs() << " \"" << Arg << "\""; + errs() << "\n"; + } else { + if (sys::ExecuteAndWait(Objcopy, Args)) + return createStringError(inconvertibleErrorCode(), + "'llvm-objcopy' tool failed"); + } + return Error::success(); + } +}; + +/// Handler for text files. The bundled file will have the following format. +/// +/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple" +/// Bundle 1 +/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple" +/// ... +/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple" +/// Bundle N +/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple" +class TextFileHandler final : public FileHandler { + /// String that begins a line comment. + StringRef Comment; + + /// String that initiates a bundle. + std::string BundleStartString; + + /// String that closes a bundle. + std::string BundleEndString; + + /// Number of chars read from input. + size_t ReadChars = 0u; + +protected: + Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); } + + Expected<std::optional<StringRef>> + ReadBundleStart(MemoryBuffer &Input) final { + StringRef FC = Input.getBuffer(); + + // Find start of the bundle. + ReadChars = FC.find(BundleStartString, ReadChars); + if (ReadChars == FC.npos) + return std::nullopt; + + // Get position of the triple. + size_t TripleStart = ReadChars = ReadChars + BundleStartString.size(); + + // Get position that closes the triple. + size_t TripleEnd = ReadChars = FC.find("\n", ReadChars); + if (TripleEnd == FC.npos) + return std::nullopt; + + // Next time we read after the new line. + ++ReadChars; + + return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart); + } + + Error ReadBundleEnd(MemoryBuffer &Input) final { + StringRef FC = Input.getBuffer(); + + // Read up to the next new line. + assert(FC[ReadChars] == '\n' && "The bundle should end with a new line."); + + size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1); + if (TripleEnd != FC.npos) + // Next time we read after the new line. + ++ReadChars; + + return Error::success(); + } + + Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final { + StringRef FC = Input.getBuffer(); + size_t BundleStart = ReadChars; + + // Find end of the bundle. + size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars); + + StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart); + OS << Bundle; + + return Error::success(); + } + + Error WriteHeader(raw_ostream &OS, + ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final { + return Error::success(); + } + + Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final { + OS << BundleStartString << TargetTriple << "\n"; + return Error::success(); + } + + Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final { + OS << BundleEndString << TargetTriple << "\n"; + return Error::success(); + } + + Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final { + OS << Input.getBuffer(); + return Error::success(); + } + +public: + TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) { + BundleStartString = + "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ "; + BundleEndString = + "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ "; + } + + Error listBundleIDsCallback(MemoryBuffer &Input, + const BundleInfo &Info) final { + // TODO: To list bundle IDs in a bundled text file we need to go through + // all bundles. The format of bundled text file may need to include a + // header if the performance of listing bundle IDs of bundled text file is + // important. + ReadChars = Input.getBuffer().find(BundleEndString, ReadChars); + if (Error Err = ReadBundleEnd(Input)) + return Err; + return Error::success(); + } +}; +} // namespace + +/// Return an appropriate object file handler. We use the specific object +/// handler if we know how to deal with that format, otherwise we use a default +/// binary file handler. +static std::unique_ptr<FileHandler> +CreateObjectFileHandler(MemoryBuffer &FirstInput, + const OffloadBundlerConfig &BundlerConfig) { + // Check if the input file format is one that we know how to deal with. + Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput); + + // We only support regular object files. If failed to open the input as a + // known binary or this is not an object file use the default binary handler. + if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr)) + return std::make_unique<BinaryFileHandler>(BundlerConfig); + + // Otherwise create an object file handler. The handler will be owned by the + // client of this function. + return std::make_unique<ObjectFileHandler>( + std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())), + BundlerConfig); +} + +/// Return an appropriate handler given the input files and options. +static Expected<std::unique_ptr<FileHandler>> +CreateFileHandler(MemoryBuffer &FirstInput, + const OffloadBundlerConfig &BundlerConfig) { + std::string FilesType = BundlerConfig.FilesType; + + if (FilesType == "i") + return std::make_unique<TextFileHandler>(/*Comment=*/"//"); + if (FilesType == "ii") + return std::make_unique<TextFileHandler>(/*Comment=*/"//"); + if (FilesType == "cui") + return std::make_unique<TextFileHandler>(/*Comment=*/"//"); + if (FilesType == "hipi") + return std::make_unique<TextFileHandler>(/*Comment=*/"//"); + // TODO: `.d` should be eventually removed once `-M` and its variants are + // handled properly in offload compilation. + if (FilesType == "d") + return std::make_unique<TextFileHandler>(/*Comment=*/"#"); + if (FilesType == "ll") + return std::make_unique<TextFileHandler>(/*Comment=*/";"); + if (FilesType == "bc") + return std::make_unique<BinaryFileHandler>(BundlerConfig); + if (FilesType == "s") + return std::make_unique<TextFileHandler>(/*Comment=*/"#"); + if (FilesType == "o") + return CreateObjectFileHandler(FirstInput, BundlerConfig); + if (FilesType == "a") + return CreateObjectFileHandler(FirstInput, BundlerConfig); + if (FilesType == "gch") + return std::make_unique<BinaryFileHandler>(BundlerConfig); + if (FilesType == "ast") + return std::make_unique<BinaryFileHandler>(BundlerConfig); + + return createStringError(errc::invalid_argument, + "'" + FilesType + "': invalid file type specified"); +} + +OffloadBundlerConfig::OffloadBundlerConfig() { + auto IgnoreEnvVarOpt = + llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_IGNORE_ENV_VAR"); + if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() == "1") + return; + + auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_VERBOSE"); + if (VerboseEnvVarOpt.has_value()) + Verbose = VerboseEnvVarOpt.value() == "1"; + + auto CompressEnvVarOpt = + llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_COMPRESS"); + if (CompressEnvVarOpt.has_value()) + Compress = CompressEnvVarOpt.value() == "1"; +} + +llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> +CompressedOffloadBundle::compress(const llvm::MemoryBuffer &Input, + bool Verbose) { + llvm::Timer HashTimer("Hash Calculation Timer", "Hash calculation time", + ClangOffloadBundlerTimerGroup); + if (Verbose) + HashTimer.startTimer(); + llvm::MD5 Hash; + llvm::MD5::MD5Result Result; + Hash.update(Input.getBuffer()); + Hash.final(Result); + uint64_t TruncatedHash = Result.low(); + if (Verbose) + HashTimer.stopTimer(); + + SmallVector<uint8_t, 0> CompressedBuffer; + auto BufferUint8 = llvm::ArrayRef<uint8_t>( + reinterpret_cast<const uint8_t *>(Input.getBuffer().data()), + Input.getBuffer().size()); + + llvm::compression::Format CompressionFormat; + + if (llvm::compression::zstd::isAvailable()) + CompressionFormat = llvm::compression::Format::Zstd; + else if (llvm::compression::zlib::isAvailable()) + CompressionFormat = llvm::compression::Format::Zlib; + else + return createStringError(llvm::inconvertibleErrorCode(), + "Compression not supported"); + + llvm::Timer CompressTimer("Compression Timer", "Compression time", + ClangOffloadBundlerTimerGroup); + if (Verbose) + CompressTimer.startTimer(); + llvm::compression::compress(CompressionFormat, BufferUint8, CompressedBuffer); + if (Verbose) + CompressTimer.stopTimer(); + + uint16_t CompressionMethod = static_cast<uint16_t>(CompressionFormat); + uint32_t UncompressedSize = Input.getBuffer().size(); + + SmallVector<char, 0> FinalBuffer; + llvm::raw_svector_ostream OS(FinalBuffer); + OS << MagicNumber; + OS.write(reinterpret_cast<const char *>(&Version), sizeof(Version)); + OS.write(reinterpret_cast<const char *>(&CompressionMethod), + sizeof(CompressionMethod)); + OS.write(reinterpret_cast<const char *>(&UncompressedSize), + sizeof(UncompressedSize)); + OS.write(reinterpret_cast<const char *>(&TruncatedHash), + sizeof(TruncatedHash)); + OS.write(reinterpret_cast<const char *>(CompressedBuffer.data()), + CompressedBuffer.size()); + + if (Verbose) { + auto MethodUsed = + CompressionFormat == llvm::compression::Format::Zstd ? "zstd" : "zlib"; + llvm::errs() << "Compressed bundle format version: " << Version << "\n" + << "Compression method used: " << MethodUsed << "\n" + << "Binary size before compression: " << UncompressedSize + << " bytes\n" + << "Binary size after compression: " << CompressedBuffer.size() + << " bytes\n" + << "Truncated MD5 hash: " + << llvm::format_hex(TruncatedHash, 16) << "\n"; + } + + return llvm::MemoryBuffer::getMemBufferCopy( + llvm::StringRef(FinalBuffer.data(), FinalBuffer.size())); +} + +llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> +CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input, + bool Verbose) { + + StringRef Blob = Input.getBuffer(); + + if (Blob.size() < HeaderSize) { + return llvm::MemoryBuffer::getMemBufferCopy(Blob); + } + if (llvm::identify_magic(Blob) != + llvm::file_magic::offload_bundle_compressed) { + if (Verbose) + llvm::errs() << "Uncompressed bundle.\n"; + return llvm::MemoryBuffer::getMemBufferCopy(Blob); + } + + uint16_t ThisVersion; + uint16_t CompressionMethod; + uint32_t UncompressedSize; + uint64_t StoredHash; + memcpy(&ThisVersion, Input.getBuffer().data() + MagicNumber.size(), + sizeof(uint16_t)); + memcpy(&CompressionMethod, Blob.data() + MagicSize + VersionFieldSize, + sizeof(uint16_t)); + memcpy(&UncompressedSize, + Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize, + sizeof(uint32_t)); + memcpy(&StoredHash, + Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize + + SizeFieldSize, + sizeof(uint64_t)); + + llvm::compression::Format CompressionFormat; + if (CompressionMethod == + static_cast<uint16_t>(llvm::compression::Format::Zlib)) + CompressionFormat = llvm::compression::Format::Zlib; + else if (CompressionMethod == + static_cast<uint16_t>(llvm::compression::Format::Zstd)) + CompressionFormat = llvm::compression::Format::Zstd; + else + return createStringError(inconvertibleErrorCode(), + "Unknown compressing method"); + + llvm::Timer DecompressTimer("Decompression Timer", "Decompression time", + ClangOffloadBundlerTimerGroup); + if (Verbose) + DecompressTimer.startTimer(); + + SmallVector<uint8_t, 0> DecompressedData; + StringRef CompressedData = Blob.substr(HeaderSize); + if (llvm::Error DecompressionError = llvm::compression::decompress( + CompressionFormat, llvm::arrayRefFromStringRef(CompressedData), + DecompressedData, UncompressedSize)) + return createStringError(inconvertibleErrorCode(), + "Could not decompress embedded file contents: " + + llvm::toString(std::move(DecompressionError))); + + if (Verbose) { + DecompressTimer.stopTimer(); + + // Recalculate MD5 hash + llvm::Timer HashRecalcTimer("Hash Recalculation Timer", + "Hash recalculation time", + ClangOffloadBundlerTimerGroup); + HashRecalcTimer.startTimer(); + llvm::MD5 Hash; + llvm::MD5::MD5Result Result; + Hash.update(llvm::ArrayRef<uint8_t>(DecompressedData.data(), + DecompressedData.size())); + Hash.final(Result); + uint64_t RecalculatedHash = Result.low(); + HashRecalcTimer.stopTimer(); + bool HashMatch = (StoredHash == RecalculatedHash); + + llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n" + << "Decompression method: " + << (CompressionFormat == llvm::compression::Format::Zlib + ? "zlib" + : "zstd") + << "\n" + << "Size before decompression: " << CompressedData.size() + << " bytes\n" + << "Size after decompression: " << UncompressedSize + << " bytes\n" + << "Stored hash: " << llvm::format_hex(StoredHash, 16) << "\n" + << "Recalculated hash: " + << llvm::format_hex(RecalculatedHash, 16) << "\n" + << "Hashes match: " << (HashMatch ? "Yes" : "No") << "\n"; + } + + return llvm::MemoryBuffer::getMemBufferCopy( + llvm::toStringRef(DecompressedData)); +} + +// List bundle IDs. Return true if an error was found. +Error OffloadBundler::ListBundleIDsInFile( + StringRef InputFileName, const OffloadBundlerConfig &BundlerConfig) { + // Open Input file. + ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = + MemoryBuffer::getFileOrSTDIN(InputFileName); + if (std::error_code EC = CodeOrErr.getError()) + return createFileError(InputFileName, EC); + + // Decompress the input if necessary. + Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr = + CompressedOffloadBundle::decompress(**CodeOrErr, BundlerConfig.Verbose); + if (!DecompressedBufferOrErr) + return createStringError( + inconvertibleErrorCode(), + "Failed to decompress input: " + + llvm::toString(DecompressedBufferOrErr.takeError())); + + MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr; + + // Select the right files handler. + Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr = + CreateFileHandler(DecompressedInput, BundlerConfig); + if (!FileHandlerOrErr) + return FileHandlerOrErr.takeError(); + + std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr; + assert(FH); + return FH->listBundleIDs(DecompressedInput); +} + +/// @brief Checks if a code object \p CodeObjectInfo is compatible with a given +/// target \p TargetInfo. +/// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id +bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo, + const OffloadTargetInfo &TargetInfo) { + + // Compatible in case of exact match. + if (CodeObjectInfo == TargetInfo) { + DEBUG_WITH_TYPE("CodeObjectCompatibility", + dbgs() << "Compatible: Exact match: \t[CodeObject: " + << CodeObjectInfo.str() + << "]\t:\t[Target: " << TargetInfo.str() << "]\n"); + return true; + } + + // Incompatible if Kinds or Triples mismatch. + if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) || + !CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) { + DEBUG_WITH_TYPE( + "CodeObjectCompatibility", + dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: " + << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str() + << "]\n"); + return false; + } + + // Incompatible if Processors mismatch. + llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap; + std::optional<StringRef> CodeObjectProc = clang::parseTargetID( + CodeObjectInfo.Triple, CodeObjectInfo.TargetID, &CodeObjectFeatureMap); + std::optional<StringRef> TargetProc = clang::parseTargetID( + TargetInfo.Triple, TargetInfo.TargetID, &TargetFeatureMap); + + // Both TargetProc and CodeObjectProc can't be empty here. + if (!TargetProc || !CodeObjectProc || + CodeObjectProc.value() != TargetProc.value()) { + DEBUG_WITH_TYPE("CodeObjectCompatibility", + dbgs() << "Incompatible: Processor mismatch \t[CodeObject: " + << CodeObjectInfo.str() + << "]\t:\t[Target: " << TargetInfo.str() << "]\n"); + return false; + } + + // Incompatible if CodeObject has more features than Target, irrespective of + // type or sign of features. + if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) { + DEBUG_WITH_TYPE("CodeObjectCompatibility", + dbgs() << "Incompatible: CodeObject has more features " + "than target \t[CodeObject: " + << CodeObjectInfo.str() + << "]\t:\t[Target: " << TargetInfo.str() << "]\n"); + return false; + } + + // Compatible if each target feature specified by target is compatible with + // target feature of code object. The target feature is compatible if the + // code object does not specify it (meaning Any), or if it specifies it + // with the same value (meaning On or Off). + for (const auto &CodeObjectFeature : CodeObjectFeatureMap) { + auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey()); + if (TargetFeature == TargetFeatureMap.end()) { + DEBUG_WITH_TYPE( + "CodeObjectCompatibility", + dbgs() + << "Incompatible: Value of CodeObject's non-ANY feature is " + "not matching with Target feature's ANY value \t[CodeObject: " + << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str() + << "]\n"); + return false; + } else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) { + DEBUG_WITH_TYPE( + "CodeObjectCompatibility", + dbgs() << "Incompatible: Value of CodeObject's non-ANY feature is " + "not matching with Target feature's non-ANY value " + "\t[CodeObject: " + << CodeObjectInfo.str() + << "]\t:\t[Target: " << TargetInfo.str() << "]\n"); + return false; + } + } + + // CodeObject is compatible if all features of Target are: + // - either, present in the Code Object's features map with the same sign, + // - or, the feature is missing from CodeObjects's features map i.e. it is + // set to ANY + DEBUG_WITH_TYPE( + "CodeObjectCompatibility", + dbgs() << "Compatible: Target IDs are compatible \t[CodeObject: " + << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str() + << "]\n"); + return true; +} + +/// Bundle the files. Return true if an error was found. +Error OffloadBundler::BundleFiles() { + std::error_code EC; + + // Create a buffer to hold the content before compressing. + SmallVector<char, 0> Buffer; + llvm::raw_svector_ostream BufferStream(Buffer); + + // Open input files. + SmallVector<std::unique_ptr<MemoryBuffer>, 8u> InputBuffers; + InputBuffers.reserve(BundlerConfig.InputFileNames.size()); + for (auto &I : BundlerConfig.InputFileNames) { + ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = + MemoryBuffer::getFileOrSTDIN(I); + if (std::error_code EC = CodeOrErr.getError()) + return createFileError(I, EC); + InputBuffers.emplace_back(std::move(*CodeOrErr)); + } + + // Get the file handler. We use the host buffer as reference. + assert((BundlerConfig.HostInputIndex != ~0u || BundlerConfig.AllowNoHost) && + "Host input index undefined??"); + Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr = CreateFileHandler( + *InputBuffers[BundlerConfig.AllowNoHost ? 0 + : BundlerConfig.HostInputIndex], + BundlerConfig); + if (!FileHandlerOrErr) + return FileHandlerOrErr.takeError(); + + std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr; + assert(FH); + + // Write header. + if (Error Err = FH->WriteHeader(BufferStream, InputBuffers)) + return Err; + + // Write all bundles along with the start/end markers. If an error was found + // writing the end of the bundle component, abort the bundle writing. + auto Input = InputBuffers.begin(); + for (auto &Triple : BundlerConfig.TargetNames) { + if (Error Err = FH->WriteBundleStart(BufferStream, Triple)) + return Err; + if (Error Err = FH->WriteBundle(BufferStream, **Input)) + return Err; + if (Error Err = FH->WriteBundleEnd(BufferStream, Triple)) + return Err; + ++Input; + } + + raw_fd_ostream OutputFile(BundlerConfig.OutputFileNames.front(), EC, + sys::fs::OF_None); + if (EC) + return createFileError(BundlerConfig.OutputFileNames.front(), EC); + + SmallVector<char, 0> CompressedBuffer; + if (BundlerConfig.Compress) { + std::unique_ptr<llvm::MemoryBuffer> BufferMemory = + llvm::MemoryBuffer::getMemBufferCopy( + llvm::StringRef(Buffer.data(), Buffer.size())); + auto CompressionResult = + CompressedOffloadBundle::compress(*BufferMemory, BundlerConfig.Verbose); + if (auto Error = CompressionResult.takeError()) + return Error; + + auto CompressedMemBuffer = std::move(CompressionResult.get()); + CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(), + CompressedMemBuffer->getBufferEnd()); + } else + CompressedBuffer = Buffer; + + OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size()); + + return FH->finalizeOutputFile(); +} + +// Unbundle the files. Return true if an error was found. +Error OffloadBundler::UnbundleFiles() { + // Open Input file. + ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = + MemoryBuffer::getFileOrSTDIN(BundlerConfig.InputFileNames.front()); + if (std::error_code EC = CodeOrErr.getError()) + return createFileError(BundlerConfig.InputFileNames.front(), EC); + + // Decompress the input if necessary. + Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr = + CompressedOffloadBundle::decompress(**CodeOrErr, BundlerConfig.Verbose); + if (!DecompressedBufferOrErr) + return createStringError( + inconvertibleErrorCode(), + "Failed to decompress input: " + + llvm::toString(DecompressedBufferOrErr.takeError())); + + MemoryBuffer &Input = **DecompressedBufferOrErr; + + // Select the right files handler. + Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr = + CreateFileHandler(Input, BundlerConfig); + if (!FileHandlerOrErr) + return FileHandlerOrErr.takeError(); + + std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr; + assert(FH); + + // Read the header of the bundled file. + if (Error Err = FH->ReadHeader(Input)) + return Err; + + // Create a work list that consist of the map triple/output file. + StringMap<StringRef> Worklist; + auto Output = BundlerConfig.OutputFileNames.begin(); + for (auto &Triple : BundlerConfig.TargetNames) { + Worklist[Triple] = *Output; + ++Output; + } + + // Read all the bundles that are in the work list. If we find no bundles we + // assume the file is meant for the host target. + bool FoundHostBundle = false; + while (!Worklist.empty()) { + Expected<std::optional<StringRef>> CurTripleOrErr = + FH->ReadBundleStart(Input); + if (!CurTripleOrErr) + return CurTripleOrErr.takeError(); + + // We don't have more bundles. + if (!*CurTripleOrErr) + break; + + StringRef CurTriple = **CurTripleOrErr; + assert(!CurTriple.empty()); + + auto Output = Worklist.begin(); + for (auto E = Worklist.end(); Output != E; Output++) { + if (isCodeObjectCompatible( + OffloadTargetInfo(CurTriple, BundlerConfig), + OffloadTargetInfo((*Output).first(), BundlerConfig))) { + break; + } + } + + if (Output == Worklist.end()) + continue; + // Check if the output file can be opened and copy the bundle to it. + std::error_code EC; + raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None); + if (EC) + return createFileError((*Output).second, EC); + if (Error Err = FH->ReadBundle(OutputFile, Input)) + return Err; + if (Error Err = FH->ReadBundleEnd(Input)) + return Err; + Worklist.erase(Output); + + // Record if we found the host bundle. + auto OffloadInfo = OffloadTargetInfo(CurTriple, BundlerConfig); + if (OffloadInfo.hasHostKind()) + FoundHostBundle = true; + } + + if (!BundlerConfig.AllowMissingBundles && !Worklist.empty()) { + std::string ErrMsg = "Can't find bundles for"; + std::set<StringRef> Sorted; + for (auto &E : Worklist) + Sorted.insert(E.first()); + unsigned I = 0; + unsigned Last = Sorted.size() - 1; + for (auto &E : Sorted) { + if (I != 0 && Last > 1) + ErrMsg += ","; + ErrMsg += " "; + if (I == Last && I != 0) + ErrMsg += "and "; + ErrMsg += E.str(); + ++I; + } + return createStringError(inconvertibleErrorCode(), ErrMsg); + } + + // If no bundles were found, assume the input file is the host bundle and + // create empty files for the remaining targets. + if (Worklist.size() == BundlerConfig.TargetNames.size()) { + for (auto &E : Worklist) { + std::error_code EC; + raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None); + if (EC) + return createFileError(E.second, EC); + + // If this entry has a host kind, copy the input file to the output file. + auto OffloadInfo = OffloadTargetInfo(E.getKey(), BundlerConfig); + if (OffloadInfo.hasHostKind()) + OutputFile.write(Input.getBufferStart(), Input.getBufferSize()); + } + return Error::success(); + } + + // If we found elements, we emit an error if none of those were for the host + // in case host bundle name was provided in command line. + if (!(FoundHostBundle || BundlerConfig.HostInputIndex == ~0u || + BundlerConfig.AllowMissingBundles)) + return createStringError(inconvertibleErrorCode(), + "Can't find bundle for the host target"); + + // If we still have any elements in the worklist, create empty files for them. + for (auto &E : Worklist) { + std::error_code EC; + raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None); + if (EC) + return createFileError(E.second, EC); + } + + return Error::success(); +} + +static Archive::Kind getDefaultArchiveKindForHost() { + return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN + : Archive::K_GNU; +} + +/// @brief Computes a list of targets among all given targets which are +/// compatible with this code object +/// @param [in] CodeObjectInfo Code Object +/// @param [out] CompatibleTargets List of all compatible targets among all +/// given targets +/// @return false, if no compatible target is found. +static bool +getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo, + SmallVectorImpl<StringRef> &CompatibleTargets, + const OffloadBundlerConfig &BundlerConfig) { + if (!CompatibleTargets.empty()) { + DEBUG_WITH_TYPE("CodeObjectCompatibility", + dbgs() << "CompatibleTargets list should be empty\n"); + return false; + } + for (auto &Target : BundlerConfig.TargetNames) { + auto TargetInfo = OffloadTargetInfo(Target, BundlerConfig); + if (isCodeObjectCompatible(CodeObjectInfo, TargetInfo)) + CompatibleTargets.push_back(Target); + } + return !CompatibleTargets.empty(); +} + +// Check that each code object file in the input archive conforms to following +// rule: for a specific processor, a feature either shows up in all target IDs, +// or does not show up in any target IDs. Otherwise the target ID combination is +// invalid. +static Error +CheckHeterogeneousArchive(StringRef ArchiveName, + const OffloadBundlerConfig &BundlerConfig) { + std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers; + ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = + MemoryBuffer::getFileOrSTDIN(ArchiveName, true, false); + if (std::error_code EC = BufOrErr.getError()) + return createFileError(ArchiveName, EC); + + ArchiveBuffers.push_back(std::move(*BufOrErr)); + Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr = + Archive::create(ArchiveBuffers.back()->getMemBufferRef()); + if (!LibOrErr) + return LibOrErr.takeError(); + + auto Archive = std::move(*LibOrErr); + + Error ArchiveErr = Error::success(); + auto ChildEnd = Archive->child_end(); + + /// Iterate over all bundled code object files in the input archive. + for (auto ArchiveIter = Archive->child_begin(ArchiveErr); + ArchiveIter != ChildEnd; ++ArchiveIter) { + if (ArchiveErr) + return ArchiveErr; + auto ArchiveChildNameOrErr = (*ArchiveIter).getName(); + if (!ArchiveChildNameOrErr) + return ArchiveChildNameOrErr.takeError(); + + auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef(); + if (!CodeObjectBufferRefOrErr) + return CodeObjectBufferRefOrErr.takeError(); + + auto CodeObjectBuffer = + MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false); + + Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr = + CreateFileHandler(*CodeObjectBuffer, BundlerConfig); + if (!FileHandlerOrErr) + return FileHandlerOrErr.takeError(); + + std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr; + assert(FileHandler); + + std::set<StringRef> BundleIds; + auto CodeObjectFileError = + FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds); + if (CodeObjectFileError) + return CodeObjectFileError; + + auto &&ConflictingArchs = clang::getConflictTargetIDCombination(BundleIds); + if (ConflictingArchs) { + std::string ErrMsg = + Twine("conflicting TargetIDs [" + ConflictingArchs.value().first + + ", " + ConflictingArchs.value().second + "] found in " + + ArchiveChildNameOrErr.get() + " of " + ArchiveName) + .str(); + return createStringError(inconvertibleErrorCode(), ErrMsg); + } + } + + return ArchiveErr; +} + +/// UnbundleArchive takes an archive file (".a") as input containing bundled +/// code object files, and a list of offload targets (not host), and extracts +/// the code objects into a new archive file for each offload target. Each +/// resulting archive file contains all code object files corresponding to that +/// particular offload target. The created archive file does not +/// contain an index of the symbols and code object files are named as +/// <<Parent Bundle Name>-<CodeObject's TargetID>>, with ':' replaced with '_'. +Error OffloadBundler::UnbundleArchive() { + std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers; + + /// Map of target names with list of object files that will form the device + /// specific archive for that target + StringMap<std::vector<NewArchiveMember>> OutputArchivesMap; + + // Map of target names and output archive filenames + StringMap<StringRef> TargetOutputFileNameMap; + + auto Output = BundlerConfig.OutputFileNames.begin(); + for (auto &Target : BundlerConfig.TargetNames) { + TargetOutputFileNameMap[Target] = *Output; + ++Output; + } + + StringRef IFName = BundlerConfig.InputFileNames.front(); + + if (BundlerConfig.CheckInputArchive) { + // For a specific processor, a feature either shows up in all target IDs, or + // does not show up in any target IDs. Otherwise the target ID combination + // is invalid. + auto ArchiveError = CheckHeterogeneousArchive(IFName, BundlerConfig); + if (ArchiveError) { + return ArchiveError; + } + } + + ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = + MemoryBuffer::getFileOrSTDIN(IFName, true, false); + if (std::error_code EC = BufOrErr.getError()) + return createFileError(BundlerConfig.InputFileNames.front(), EC); + + ArchiveBuffers.push_back(std::move(*BufOrErr)); + Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr = + Archive::create(ArchiveBuffers.back()->getMemBufferRef()); + if (!LibOrErr) + return LibOrErr.takeError(); + + auto Archive = std::move(*LibOrErr); + + Error ArchiveErr = Error::success(); + auto ChildEnd = Archive->child_end(); + + /// Iterate over all bundled code object files in the input archive. + for (auto ArchiveIter = Archive->child_begin(ArchiveErr); + ArchiveIter != ChildEnd; ++ArchiveIter) { + if (ArchiveErr) + return ArchiveErr; + auto ArchiveChildNameOrErr = (*ArchiveIter).getName(); + if (!ArchiveChildNameOrErr) + return ArchiveChildNameOrErr.takeError(); + + StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr); + + auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef(); + if (!CodeObjectBufferRefOrErr) + return CodeObjectBufferRefOrErr.takeError(); + + auto TempCodeObjectBuffer = + MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false); + + // Decompress the buffer if necessary. + Expected<std::unique_ptr<MemoryBuffer>> DecompressedBufferOrErr = + CompressedOffloadBundle::decompress(*TempCodeObjectBuffer, + BundlerConfig.Verbose); + if (!DecompressedBufferOrErr) + return createStringError( + inconvertibleErrorCode(), + "Failed to decompress code object: " + + llvm::toString(DecompressedBufferOrErr.takeError())); + + MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr; + + Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr = + CreateFileHandler(CodeObjectBuffer, BundlerConfig); + if (!FileHandlerOrErr) + return FileHandlerOrErr.takeError(); + + std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr; + assert(FileHandler && + "FileHandle creation failed for file in the archive!"); + + if (Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer)) + return ReadErr; + + Expected<std::optional<StringRef>> CurBundleIDOrErr = + FileHandler->ReadBundleStart(CodeObjectBuffer); + if (!CurBundleIDOrErr) + return CurBundleIDOrErr.takeError(); + + std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr; + // No device code in this child, skip. + if (!OptionalCurBundleID) + continue; + StringRef CodeObject = *OptionalCurBundleID; + + // Process all bundle entries (CodeObjects) found in this child of input + // archive. + while (!CodeObject.empty()) { + SmallVector<StringRef> CompatibleTargets; + auto CodeObjectInfo = OffloadTargetInfo(CodeObject, BundlerConfig); + if (CodeObjectInfo.hasHostKind()) { + // Do nothing, we don't extract host code yet. + } else if (getCompatibleOffloadTargets(CodeObjectInfo, CompatibleTargets, + BundlerConfig)) { + std::string BundleData; + raw_string_ostream DataStream(BundleData); + if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer)) + return Err; + + for (auto &CompatibleTarget : CompatibleTargets) { + SmallString<128> BundledObjectFileName; + BundledObjectFileName.assign(BundledObjectFile); + auto OutputBundleName = + Twine(llvm::sys::path::stem(BundledObjectFileName) + "-" + + CodeObject + + getDeviceLibraryFileName(BundledObjectFileName, + CodeObjectInfo.TargetID)) + .str(); + // Replace ':' in optional target feature list with '_' to ensure + // cross-platform validity. + std::replace(OutputBundleName.begin(), OutputBundleName.end(), ':', + '_'); + + std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy( + DataStream.str(), OutputBundleName); + ArchiveBuffers.push_back(std::move(MemBuf)); + llvm::MemoryBufferRef MemBufRef = + MemoryBufferRef(*(ArchiveBuffers.back())); + + // For inserting <CompatibleTarget, list<CodeObject>> entry in + // OutputArchivesMap. + if (!OutputArchivesMap.contains(CompatibleTarget)) { + + std::vector<NewArchiveMember> ArchiveMembers; + ArchiveMembers.push_back(NewArchiveMember(MemBufRef)); + OutputArchivesMap.insert_or_assign(CompatibleTarget, + std::move(ArchiveMembers)); + } else { + OutputArchivesMap[CompatibleTarget].push_back( + NewArchiveMember(MemBufRef)); + } + } + } + + if (Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer)) + return Err; + + Expected<std::optional<StringRef>> NextTripleOrErr = + FileHandler->ReadBundleStart(CodeObjectBuffer); + if (!NextTripleOrErr) + return NextTripleOrErr.takeError(); + + CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr : ""; + } // End of processing of all bundle entries of this child of input archive. + } // End of while over children of input archive. + + assert(!ArchiveErr && "Error occurred while reading archive!"); + + /// Write out an archive for each target + for (auto &Target : BundlerConfig.TargetNames) { + StringRef FileName = TargetOutputFileNameMap[Target]; + StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers = + OutputArchivesMap.find(Target); + if (CurArchiveMembers != OutputArchivesMap.end()) { + if (Error WriteErr = writeArchive(FileName, CurArchiveMembers->getValue(), + SymtabWritingMode::NormalSymtab, + getDefaultArchiveKindForHost(), true, + false, nullptr)) + return WriteErr; + } else if (!BundlerConfig.AllowMissingBundles) { + std::string ErrMsg = + Twine("no compatible code object found for the target '" + Target + + "' in heterogeneous archive library: " + IFName) + .str(); + return createStringError(inconvertibleErrorCode(), ErrMsg); + } else { // Create an empty archive file if no compatible code object is + // found and "allow-missing-bundles" is enabled. It ensures that + // the linker using output of this step doesn't complain about + // the missing input file. + std::vector<llvm::NewArchiveMember> EmptyArchive; + EmptyArchive.clear(); + if (Error WriteErr = writeArchive( + FileName, EmptyArchive, SymtabWritingMode::NormalSymtab, + getDefaultArchiveKindForHost(), true, false, nullptr)) + return WriteErr; + } + } + + return Error::success(); +} diff --git a/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp index 403fac76f060..56d497eb4c32 100644 --- a/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp +++ b/contrib/llvm-project/clang/lib/Driver/SanitizerArgs.cpp @@ -13,12 +13,14 @@ #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Path.h" #include "llvm/Support/SpecialCaseList.h" -#include "llvm/Support/AArch64TargetParser.h" -#include "llvm/Support/TargetParser.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/AArch64TargetParser.h" +#include "llvm/TargetParser/RISCVTargetParser.h" +#include "llvm/TargetParser/TargetParser.h" #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h" #include <memory> @@ -34,32 +36,33 @@ static const SanitizerMask NeedsUbsanRt = static const SanitizerMask NeedsUbsanCxxRt = SanitizerKind::Vptr | SanitizerKind::CFI; static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr; -static const SanitizerMask NotAllowedWithMinimalRuntime = - SanitizerKind::Function | SanitizerKind::Vptr; -static const SanitizerMask RequiresPIE = - SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo; +static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr; +static const SanitizerMask NotAllowedWithExecuteOnly = + SanitizerKind::Function | SanitizerKind::KCFI; static const SanitizerMask NeedsUnwindTables = SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::DataFlow; static const SanitizerMask SupportsCoverage = SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress | - SanitizerKind::MemTag | SanitizerKind::Memory | + SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap | + SanitizerKind::MemtagGlobals | SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak | SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::DataFlow | SanitizerKind::Fuzzer | SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero | SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack | - SanitizerKind::Thread | SanitizerKind::ObjCCast; + SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI; static const SanitizerMask RecoverableByDefault = SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast; static const SanitizerMask Unrecoverable = SanitizerKind::Unreachable | SanitizerKind::Return; -static const SanitizerMask AlwaysRecoverable = - SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress; +static const SanitizerMask AlwaysRecoverable = SanitizerKind::KernelAddress | + SanitizerKind::KernelHWAddress | + SanitizerKind::KCFI; static const SanitizerMask NeedsLTO = SanitizerKind::CFI; static const SanitizerMask TrappingSupported = (SanitizerKind::Undefined & ~SanitizerKind::Vptr) | SanitizerKind::Integer | @@ -73,7 +76,8 @@ static const SanitizerMask CFIClasses = SanitizerKind::CFIUnrelatedCast; static const SanitizerMask CompatibleWithMinimalRuntime = TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack | - SanitizerKind::MemTag; + SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap | + SanitizerKind::MemtagGlobals | SanitizerKind::KCFI; enum CoverageFeature { CoverageFunc = 1 << 0, @@ -94,6 +98,13 @@ enum CoverageFeature { CoverageInlineBoolFlag = 1 << 15, CoverageTraceLoads = 1 << 16, CoverageTraceStores = 1 << 17, + CoverageControlFlow = 1 << 18, +}; + +enum BinaryMetadataFeature { + BinaryMetadataCovered = 1 << 0, + BinaryMetadataAtomics = 1 << 1, + BinaryMetadataUAR = 1 << 2, }; /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any @@ -106,6 +117,11 @@ static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A, bool DiagnoseErrors); +/// Parse -f(no-)?sanitize-metadata= flag values, diagnosing any invalid +/// components. Returns OR of members of \c BinaryMetadataFeature enumeration. +static int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors); + /// Produce an argument string from ArgList \p Args, which shows how it /// provides some sanitizer kind from \p Mask. For example, the argument list /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt @@ -125,6 +141,16 @@ static std::string describeSanitizeArg(const llvm::opt::Arg *A, /// Sanitizers set. static std::string toString(const clang::SanitizerSet &Sanitizers); +/// Return true if an execute-only target disallows data access to code +/// sections. +static bool isExecuteOnlyTarget(const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) { + if (Triple.isPS5()) + return true; + return Args.hasFlagNoClaim(options::OPT_mexecute_only, + options::OPT_mno_execute_only, false); +} + static void validateSpecialCaseListFormat(const Driver &D, std::vector<std::string> &SCLFiles, unsigned MalformedSCLErrorDiagID, @@ -164,18 +190,18 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds, clang::SmallString<64> Path(D.ResourceDir); llvm::sys::path::append(Path, "share", BL.File); if (D.getVFS().exists(Path)) - IgnorelistFiles.push_back(std::string(Path.str())); + IgnorelistFiles.push_back(std::string(Path)); else if (BL.Mask == SanitizerKind::CFI && DiagnoseErrors) // If cfi_ignorelist.txt cannot be found in the resource dir, driver // should fail. - D.Diag(clang::diag::err_drv_no_such_file) << Path; + D.Diag(clang::diag::err_drv_missing_sanitizer_ignorelist) << Path; } validateSpecialCaseListFormat( D, IgnorelistFiles, clang::diag::err_drv_malformed_sanitizer_ignorelist, DiagnoseErrors); } -/// Parse -f(no-)?sanitize-(coverage-)?(white|ignore)list argument's values, +/// Parse -f(no-)?sanitize-(coverage-)?(allow|ignore)list argument's values, /// diagnosing any invalid file paths and validating special case list format. static void parseSpecialCaseListArg(const Driver &D, const llvm::opt::ArgList &Args, @@ -185,7 +211,7 @@ static void parseSpecialCaseListArg(const Driver &D, unsigned MalformedSCLErrorDiagID, bool DiagnoseErrors) { for (const auto *Arg : Args) { - // Match -fsanitize-(coverage-)?(white|ignore)list. + // Match -fsanitize-(coverage-)?(allow|ignore)list. if (Arg->getOption().matches(SCLOptionID)) { Arg->claim(); std::string SCLPath = Arg->getValue(); @@ -218,9 +244,9 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) { static SanitizerMask parseSanitizeTrapArgs(const Driver &D, const llvm::opt::ArgList &Args, bool DiagnoseErrors) { - SanitizerMask TrapRemove; // During the loop below, the accumulated set of - // sanitizers disabled by the current sanitizer - // argument or any argument after it. + SanitizerMask TrapRemove; // During the loop below, the accumulated set of + // sanitizers disabled by the current sanitizer + // argument or any argument after it. SanitizerMask TrappingKinds; SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported); @@ -233,8 +259,8 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D, if (InvalidValues && DiagnoseErrors) { SanitizerSet S; S.Mask = InvalidValues; - D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap" - << toString(S); + D.Diag(diag::err_drv_unsupported_option_argument) + << Arg->getSpelling() << toString(S); } TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) { @@ -275,9 +301,7 @@ bool SanitizerArgs::needsCfiDiagRt() const { CfiCrossDso && !ImplicitCfiRuntime; } -bool SanitizerArgs::requiresPIE() const { - return NeedPIE || (Sanitizers.Mask & RequiresPIE); -} +bool SanitizerArgs::requiresPIE() const { return NeedPIE; } bool SanitizerArgs::needsUnwindTables() const { return static_cast<bool>(Sanitizers.Mask & NeedsUnwindTables); @@ -293,13 +317,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SanitizerMask AllRemove; // During the loop below, the accumulated set of // sanitizers disabled by the current sanitizer // argument or any argument after it. - SanitizerMask AllAddedKinds; // Mask of all sanitizers ever enabled by - // -fsanitize= flags (directly or via group - // expansion), some of which may be disabled - // later. Used to carefully prune - // unused-argument diagnostics. - SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now. - // Used to deduplicate diagnostics. + SanitizerMask AllAddedKinds; // Mask of all sanitizers ever enabled by + // -fsanitize= flags (directly or via group + // expansion), some of which may be disabled + // later. Used to carefully prune + // unused-argument diagnostics. + SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now. + // Used to deduplicate diagnostics. SanitizerMask Kinds; const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers()); @@ -367,6 +391,35 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Add &= ~NotAllowedWithMinimalRuntime; } + if (llvm::opt::Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { + StringRef CM = A->getValue(); + if (CM != "small" && + (Add & SanitizerKind::Function & ~DiagnosedKinds)) { + if (DiagnoseErrors) + D.Diag(diag::err_drv_argument_only_allowed_with) + << "-fsanitize=function" + << "-mcmodel=small"; + Add &= ~SanitizerKind::Function; + DiagnosedKinds |= SanitizerKind::Function; + } + } + // -fsanitize=function and -fsanitize=kcfi instrument indirect function + // calls to load a type hash before the function label. Therefore, an + // execute-only target doesn't support the function and kcfi sanitizers. + const llvm::Triple &Triple = TC.getTriple(); + if (isExecuteOnlyTarget(Triple, Args)) { + if (SanitizerMask KindsToDiagnose = + Add & NotAllowedWithExecuteOnly & ~DiagnosedKinds) { + if (DiagnoseErrors) { + std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose); + D.Diag(diag::err_drv_argument_not_allowed_with) + << Desc << Triple.str(); + } + DiagnosedKinds |= KindsToDiagnose; + } + Add &= ~NotAllowedWithExecuteOnly; + } + // FIXME: Make CFI on member function calls compatible with cross-DSO CFI. // There are currently two problems: // - Virtual function call checks need to pass a pointer to the function @@ -402,7 +455,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if ((Add & SanitizerKind::Vptr) && (RTTIMode == ToolChain::RM_Disabled)) { if (const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg()) { assert(NoRTTIArg->getOption().matches(options::OPT_fno_rtti) && - "RTTI disabled without -fno-rtti option?"); + "RTTI disabled without -fno-rtti option?"); // The user explicitly passed -fno-rtti with -fsanitize=vptr, but // the vptr sanitizer requires RTTI, so this is a user error. if (DiagnoseErrors) @@ -428,6 +481,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (MinimalRuntime) { Add &= ~NotAllowedWithMinimalRuntime; } + // NotAllowedWithExecuteOnly is silently discarded on an execute-only + // target if implicitly enabled through group expansion. + if (isExecuteOnlyTarget(Triple, Args)) + Add &= ~NotAllowedWithExecuteOnly; if (CfiCrossDso) Add &= ~SanitizerKind::CFIMFCall; Add &= Supported; @@ -487,7 +544,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, std::make_pair(SanitizerKind::MemTag, SanitizerKind::Address | SanitizerKind::KernelAddress | SanitizerKind::HWAddress | - SanitizerKind::KernelHWAddress)}; + SanitizerKind::KernelHWAddress), + std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function)}; // Enable toolchain specific default sanitizers if not explicitly disabled. SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove; @@ -513,10 +571,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } - if ((Kinds & SanitizerKind::ShadowCallStack) && - ((TC.getTriple().isAArch64() && - !llvm::AArch64::isX18ReservedByDefault(TC.getTriple())) || - TC.getTriple().isRISCV()) && + if ((Kinds & SanitizerKind::ShadowCallStack) && TC.getTriple().isAArch64() && + !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) && !Args.hasArg(options::OPT_ffixed_x18) && DiagnoseErrors) { D.Diag(diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack) @@ -576,7 +632,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SetToDiagnose.Mask |= KindsToDiagnose; if (DiagnoseErrors) D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << toString(SetToDiagnose); + << Arg->getSpelling() << toString(SetToDiagnose); DiagnosedUnrecoverableKinds |= KindsToDiagnose; } RecoverableKinds |= expandSanitizerGroups(Add); @@ -591,7 +647,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SetToDiagnose.Mask |= KindsToDiagnose; if (DiagnoseErrors) D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << toString(SetToDiagnose); + << Arg->getSpelling() << toString(SetToDiagnose); DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose; } RecoverableKinds &= ~expandSanitizerGroups(Remove); @@ -621,14 +677,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (AllAddedKinds & SanitizerKind::Memory) { if (Arg *A = Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, - options::OPT_fsanitize_memory_track_origins, options::OPT_fno_sanitize_memory_track_origins)) { - if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { - MsanTrackOrigins = 2; - } else if (A->getOption().matches( - options::OPT_fno_sanitize_memory_track_origins)) { - MsanTrackOrigins = 0; - } else { + if (!A->getOption().matches( + options::OPT_fno_sanitize_memory_track_origins)) { StringRef S = A->getValue(); if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || MsanTrackOrigins > 2) { @@ -638,20 +689,34 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } } - MsanUseAfterDtor = - Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor, - options::OPT_fno_sanitize_memory_use_after_dtor, - MsanUseAfterDtor); + MsanUseAfterDtor = Args.hasFlag( + options::OPT_fsanitize_memory_use_after_dtor, + options::OPT_fno_sanitize_memory_use_after_dtor, MsanUseAfterDtor); + MsanParamRetval = Args.hasFlag( + options::OPT_fsanitize_memory_param_retval, + options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval); + } else if (AllAddedKinds & SanitizerKind::KernelMemory) { + MsanUseAfterDtor = false; MsanParamRetval = Args.hasFlag( options::OPT_fsanitize_memory_param_retval, options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval); - NeedPIE |= !(TC.getTriple().isOSLinux() && - TC.getTriple().getArch() == llvm::Triple::x86_64); } else { MsanUseAfterDtor = false; MsanParamRetval = false; } + if (AllAddedKinds & SanitizerKind::MemTag) { + StringRef S = + Args.getLastArgValue(options::OPT_fsanitize_memtag_mode_EQ, "sync"); + if (S == "async" || S == "sync") { + MemtagMode = S.str(); + } else { + D.Diag(clang::diag::err_drv_invalid_value_with_suggestion) + << "-fsanitize-memtag-mode=" << S << "{async, sync}"; + MemtagMode = "sync"; + } + } + if (AllAddedKinds & SanitizerKind::Thread) { TsanMemoryAccess = Args.hasFlag( options::OPT_fsanitize_thread_memory_access, @@ -671,6 +736,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, CfiICallGeneralizePointers = Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers); + CfiICallNormalizeIntegers = + Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers); + if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fsanitize-cfi-cross-dso" @@ -681,6 +749,16 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, options::OPT_fno_sanitize_cfi_canonical_jump_tables, true); } + if (AllAddedKinds & SanitizerKind::KCFI) { + CfiICallNormalizeIntegers = + Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers); + + if (AllAddedKinds & SanitizerKind::CFI && DiagnoseErrors) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fsanitize=kcfi" + << lastArgumentForMask(D, Args, SanitizerKind::CFI); + } + Stats = Args.hasFlag(options::OPT_fsanitize_stats, options::OPT_fno_sanitize_stats, false); @@ -758,26 +836,28 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters | CoverageTraceLoads | - CoverageTraceStores | CoverageInlineBoolFlag; + CoverageTraceStores | CoverageInlineBoolFlag | + CoverageControlFlow; if ((CoverageFeatures & InsertionPointTypes) && !(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) { D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=[func|bb|edge]" - << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; + << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],[" + "control-flow]"; } // trace-pc w/o func/bb/edge implies edge. if (!(CoverageFeatures & InsertionPointTypes)) { if (CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters | - CoverageInlineBoolFlag)) + CoverageInlineBoolFlag | CoverageControlFlow)) CoverageFeatures |= CoverageEdge; if (CoverageFeatures & CoverageStackDepth) CoverageFeatures |= CoverageFunc; } - // Parse -fsanitize-coverage-(ignore|white)list options if coverage enabled. + // Parse -fsanitize-coverage-(allow|ignore)list options if coverage enabled. // This also validates special case lists format. // Here, OptSpecifier() acts as a never-matching command-line argument. // So, there is no way to clear coverage lists but you can append to them. @@ -794,6 +874,32 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, DiagnoseErrors); } + // Parse -f(no-)?sanitize-metadata. + for (const auto *Arg : + Args.filtered(options::OPT_fexperimental_sanitize_metadata_EQ, + options::OPT_fno_experimental_sanitize_metadata_EQ)) { + if (Arg->getOption().matches( + options::OPT_fexperimental_sanitize_metadata_EQ)) { + Arg->claim(); + BinaryMetadataFeatures |= + parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors); + } else { + Arg->claim(); + BinaryMetadataFeatures &= + ~parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors); + } + } + + // Parse -fsanitize-metadata-ignorelist option if enabled. + if (BinaryMetadataFeatures) { + parseSpecialCaseListArg( + D, Args, BinaryMetadataIgnorelistFiles, + options::OPT_fexperimental_sanitize_metadata_ignorelist_EQ, + OptSpecifier(), // Cannot clear ignore list, only append. + clang::diag::err_drv_malformed_sanitizer_metadata_ignorelist, + DiagnoseErrors); + } + SharedRuntime = Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan, TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() || @@ -805,13 +911,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, NeedPIE |= TC.getTriple().isOSFuchsia(); if (Arg *A = Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { - StringRef S = A->getValue(); - // Legal values are 0 and 1, 2, but in future we may add more levels. - if ((S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || - AsanFieldPadding > 2) && - DiagnoseErrors) { - D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; - } + StringRef S = A->getValue(); + // Legal values are 0 and 1, 2, but in future we may add more levels. + if ((S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || + AsanFieldPadding > 2) && + DiagnoseErrors) { + D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; + } } if (Arg *WindowsDebugRTArg = @@ -831,6 +937,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } + StableABI = Args.hasFlag(options::OPT_fsanitize_stable_abi, + options::OPT_fno_sanitize_stable_abi, false); + AsanUseAfterScope = Args.hasFlag( options::OPT_fsanitize_address_use_after_scope, options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope); @@ -845,18 +954,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, options::OPT_fno_sanitize_address_outline_instrumentation, AsanOutlineInstrumentation); - // As a workaround for a bug in gold 2.26 and earlier, dead stripping of - // globals in ASan is disabled by default on ELF targets. - // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002 - AsanGlobalsDeadStripping = - !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() || - TC.getTriple().isPS4() || - Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping); + AsanGlobalsDeadStripping = Args.hasFlag( + options::OPT_fsanitize_address_globals_dead_stripping, + options::OPT_fno_sanitize_address_globals_dead_stripping, true); + // Enable ODR indicators which allow better handling of mixed instrumented + // and uninstrumented globals. Disable them for Windows where weak odr + // indicators (.weak.__odr_asan_gen*) may cause multiple definition linker + // errors in the absence of -lldmingw. AsanUseOdrIndicator = Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator, options::OPT_fno_sanitize_address_use_odr_indicator, - AsanUseOdrIndicator); + !TC.getTriple().isOSWindows()); if (AllAddedKinds & SanitizerKind::PointerCompare & ~AllRemove) { AsanInvalidPointerCmp = true; @@ -877,7 +986,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, auto parsedAsanDtorKind = AsanDtorKindFromString(Arg->getValue()); if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid && DiagnoseErrors) { TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << Arg->getValue(); + << Arg->getSpelling() << Arg->getValue(); } AsanDtorKind = parsedAsanDtorKind; } @@ -890,7 +999,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, llvm::AsanDetectStackUseAfterReturnMode::Invalid && DiagnoseErrors) { TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << Arg->getValue(); + << Arg->getSpelling() << Arg->getValue(); } AsanUseAfterReturn = parsedAsanUseAfterReturn; } @@ -994,7 +1103,8 @@ static void addIncludeLinkerOption(const ToolChain &TC, } static bool hasTargetFeatureMTE(const llvm::opt::ArgStringList &CmdArgs) { - for (auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End; ++Start) { + for (auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End; + ++Start) { auto It = std::find(Start, End, StringRef("+mte")); if (It == End) break; @@ -1011,13 +1121,16 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, // NVPTX doesn't currently support sanitizers. Bailing out here means // that e.g. -fsanitize=address applies only to host code, which is what we // want for now. - // - // AMDGPU sanitizer support is experimental and controlled by -fgpu-sanitize. - if (TC.getTriple().isNVPTX() || - (TC.getTriple().isAMDGPU() && - !Args.hasFlag(options::OPT_fgpu_sanitize, - options::OPT_fno_gpu_sanitize))) + if (TC.getTriple().isNVPTX()) return; + // AMDGPU sanitizer support is experimental and controlled by -fgpu-sanitize. + bool GPUSanitize = false; + if (TC.getTriple().isAMDGPU()) { + if (!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize, + true)) + return; + GPUSanitize = true; + } // Translate available CoverageFeatures to corresponding clang-cc1 flags. // Do it even if Sanitizers.empty() since some forms of coverage don't require @@ -1043,7 +1156,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"), std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth"), std::make_pair(CoverageTraceLoads, "-fsanitize-coverage-trace-loads"), - std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores")}; + std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores"), + std::make_pair(CoverageControlFlow, "-fsanitize-coverage-control-flow")}; for (auto F : CoverageFlags) { if (CoverageFeatures & F.first) CmdArgs.push_back(F.second); @@ -1053,6 +1167,23 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-coverage-ignorelist=", CoverageIgnorelistFiles); + if (!GPUSanitize) { + // Translate available BinaryMetadataFeatures to corresponding clang-cc1 + // flags. Does not depend on any other sanitizers. Unsupported on GPUs. + const std::pair<int, std::string> BinaryMetadataFlags[] = { + std::make_pair(BinaryMetadataCovered, "covered"), + std::make_pair(BinaryMetadataAtomics, "atomics"), + std::make_pair(BinaryMetadataUAR, "uar")}; + for (const auto &F : BinaryMetadataFlags) { + if (BinaryMetadataFeatures & F.first) + CmdArgs.push_back( + Args.MakeArgString("-fexperimental-sanitize-metadata=" + F.second)); + } + addSpecialCaseListOpt(Args, CmdArgs, + "-fexperimental-sanitize-metadata-ignorelist=", + BinaryMetadataIgnorelistFiles); + } + if (TC.getTriple().isOSWindows() && needsUbsanRt()) { // Instruct the code generator to embed linker directives in the object file // that cause the required runtime libraries to be linked. @@ -1101,8 +1232,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (MsanUseAfterDtor) CmdArgs.push_back("-fsanitize-memory-use-after-dtor"); - if (MsanParamRetval) - CmdArgs.push_back("-fsanitize-memory-param-retval"); + if (!MsanParamRetval) + CmdArgs.push_back("-fno-sanitize-memory-param-retval"); // FIXME: Pass these parameters as function attributes, not as -llvm flags. if (!TsanMemoryAccess) { @@ -1131,6 +1262,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (CfiICallGeneralizePointers) CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers"); + if (CfiICallNormalizeIntegers) + CmdArgs.push_back("-fsanitize-cfi-icall-experimental-normalize-integers"); + if (CfiCanonicalJumpTables) CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables"); @@ -1153,8 +1287,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (AsanGlobalsDeadStripping) CmdArgs.push_back("-fsanitize-address-globals-dead-stripping"); - if (AsanUseOdrIndicator) - CmdArgs.push_back("-fsanitize-address-use-odr-indicator"); + if (!AsanUseOdrIndicator) + CmdArgs.push_back("-fno-sanitize-address-use-odr-indicator"); if (AsanInvalidPointerCmp) { CmdArgs.push_back("-mllvm"); @@ -1171,6 +1305,18 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, CmdArgs.push_back("-asan-instrumentation-with-call-threshold=0"); } + // When emitting Stable ABI instrumentation, force outlining calls and avoid + // inlining shadow memory poisoning. While this is a big performance burden + // for now it allows full abstraction from implementation details. + if (StableABI) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-asan-instrumentation-with-call-threshold=0"); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-asan-max-inline-poisoning-size=0"); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-asan-guard-against-version-mismatch=0"); + } + // Only pass the option to the frontend if the user requested, // otherwise the frontend will just use the codegen default. if (AsanDtorKind != llvm::AsanDtorKind::Invalid) { @@ -1230,7 +1376,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, << "-fvisibility="; } - if (Sanitizers.has(SanitizerKind::MemTag) && !hasTargetFeatureMTE(CmdArgs)) + if (Sanitizers.has(SanitizerKind::MemtagStack) && + !hasTargetFeatureMTE(CmdArgs)) TC.getDriver().Diag(diag::err_stack_tagging_requires_hardware_feature); } @@ -1258,7 +1405,7 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, Kinds |= Kind; else if (DiagnoseErrors) D.Diag(clang::diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } return Kinds; } @@ -1289,10 +1436,34 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A, .Case("stack-depth", CoverageStackDepth) .Case("trace-loads", CoverageTraceLoads) .Case("trace-stores", CoverageTraceStores) + .Case("control-flow", CoverageControlFlow) + .Default(0); + if (F == 0 && DiagnoseErrors) + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Value; + Features |= F; + } + return Features; +} + +int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors) { + assert( + A->getOption().matches(options::OPT_fexperimental_sanitize_metadata_EQ) || + A->getOption().matches( + options::OPT_fno_experimental_sanitize_metadata_EQ)); + int Features = 0; + for (int i = 0, n = A->getNumValues(); i != n; ++i) { + const char *Value = A->getValue(i); + int F = llvm::StringSwitch<int>(Value) + .Case("covered", BinaryMetadataCovered) + .Case("atomics", BinaryMetadataAtomics) + .Case("uar", BinaryMetadataUAR) + .Case("all", ~0) .Default(0); if (F == 0 && DiagnoseErrors) D.Diag(clang::diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; Features |= F; } return Features; @@ -1319,8 +1490,8 @@ std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args, } std::string describeSanitizeArg(const llvm::opt::Arg *A, SanitizerMask Mask) { - assert(A->getOption().matches(options::OPT_fsanitize_EQ) - && "Invalid argument in describeSanitizerArg!"); + assert(A->getOption().matches(options::OPT_fsanitize_EQ) && + "Invalid argument in describeSanitizerArg!"); std::string Sanitizers; for (int i = 0, n = A->getNumValues(); i != n; ++i) { diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp index d657d21bfcdb..388030592b48 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp @@ -7,8 +7,10 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/ToolChain.h" +#include "ToolChains/Arch/AArch64.h" #include "ToolChains/Arch/ARM.h" #include "ToolChains/Clang.h" +#include "ToolChains/CommonArgs.h" #include "ToolChains/Flang.h" #include "ToolChains/InterfaceStubs.h" #include "clang/Basic/ObjCRuntime.h" @@ -24,8 +26,8 @@ #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" @@ -36,10 +38,13 @@ #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/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,8 +72,9 @@ 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; } ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, @@ -80,11 +86,39 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, List.push_back(Path); }; - for (const auto &Path : getRuntimePaths()) - addIfExists(getLibraryPaths(), Path); - for (const auto &Path : getStdlibPaths()) + 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); - addIfExists(getFilePaths(), getArchSpecificLibPath()); +} + +llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> +ToolChain::executeToolChainProgram(StringRef Executable) 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 ErrorMessage; + if (llvm::sys::ExecuteAndWait(Executable, {}, {}, Redirects, + /* SecondsToWait */ 0, + /*MemoryLimit*/ 0, &ErrorMessage)) + return llvm::createStringError(std::error_code(), + Executable + ": " + ErrorMessage); + + 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) { @@ -105,6 +139,34 @@ 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; } @@ -113,6 +175,101 @@ 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 (FeatureSet.contains(Ext.Feature)) + MArch.push_back(Ext.Name.str()); + for (const auto &Ext : AArch64::Extensions) + 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, "+")); +} + +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 (FeatureSet.contains(Ext.Feature)) + MArch.push_back(Ext.Name.str()); + for (const auto &Ext : ARM::ARCHExtNames) + 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"); + } +} + +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; + } + + // 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); @@ -121,9 +278,9 @@ ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const { } const XRayArgs& ToolChain::getXRayArgs() const { - if (!XRayArguments.get()) + if (!XRayArguments) XRayArguments.reset(new XRayArgs(*this, Args)); - return *XRayArguments.get(); + return *XRayArguments; } namespace { @@ -153,13 +310,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,7 +326,7 @@ 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)); + 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(), @@ -187,6 +345,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++ @@ -257,8 +422,15 @@ 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; +} + +unsigned ToolChain::GetDefaultDwarfVersion() const { + // TODO: Remove the RISC-V special case when R_RISCV_SET_ULEB128 linker + // support becomes more widely available. + return getTriple().isRISCV() ? 4 : 5; } Tool *ToolChain::getClang() const { @@ -321,10 +493,10 @@ 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 { @@ -353,12 +525,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: @@ -369,8 +542,8 @@ 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(); } @@ -383,6 +556,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" @@ -420,12 +596,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, @@ -478,7 +659,7 @@ std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component, SmallString<128> P(LibPath); llvm::sys::path::append(P, CRTBasename); if (getVFS().exists(P)) - return std::string(P.str()); + return std::string(P); } // Fall back to the old expected compiler-rt name if the new one does not @@ -487,7 +668,7 @@ std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component, buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/true); SmallString<128> Path(getCompilerRTPath()); llvm::sys::path::append(Path, CRTBasename); - return std::string(Path.str()); + return std::string(Path); } const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, @@ -496,42 +677,118 @@ const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args, return Args.MakeArgString(getCompilerRT(Args, Component, Type)); } -ToolChain::path_list ToolChain::getRuntimePaths() const { - path_list Paths; - auto addPathForTriple = [this, &Paths](const llvm::Triple &Triple) { - SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "lib", Triple.str()); - Paths.push_back(std::string(P.str())); +// 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 {}; }; - addPathForTriple(getTriple()); + if (auto Path = getPathForTriple(getTriple())) + return *Path; - // Android targets may include an API level at the end. We still want to fall - // back on a path without the API level. - if (getTriple().isAndroid() && - getTriple().getEnvironmentName() != "android") { - llvm::Triple TripleWithoutLevel = getTriple(); - TripleWithoutLevel.setEnvironmentName("android"); - addPathForTriple(TripleWithoutLevel); + // 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; } - return Paths; + if (getTriple().isAndroid()) + return getFallbackAndroidTargetPath(BaseDir); + + return {}; } -ToolChain::path_list ToolChain::getStdlibPaths() const { - path_list Paths; - SmallString<128> P(D.Dir); - llvm::sys::path::append(P, "..", "lib", getTripleString()); - Paths.push_back(std::string(P.str())); +std::optional<std::string> ToolChain::getRuntimePath() const { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "lib"); + return getTargetSubDirPath(P); +} - return Paths; +std::optional<std::string> ToolChain::getStdlibPath() const { + SmallString<128> P(D.Dir); + 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()); +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) { @@ -558,7 +815,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); } @@ -583,13 +841,18 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const { // --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()); @@ -766,6 +1029,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, @@ -903,6 +1169,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; @@ -944,8 +1218,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); @@ -966,6 +1247,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: @@ -1017,22 +1300,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()) @@ -1049,7 +1337,7 @@ void ToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const {} llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> -ToolChain::getHIPDeviceLibs(const ArgList &DriverArgs) const { +ToolChain::getDeviceLibs(const ArgList &DriverArgs) const { return {}; } @@ -1124,7 +1412,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; @@ -1231,17 +1522,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 diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp index e4bbf498b9cd..e6126ff62db3 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp @@ -12,7 +12,9 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Path.h" using AIX = clang::driver::toolchains::AIX; @@ -28,6 +30,7 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit(); @@ -36,6 +39,11 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, if (!IsArch32Bit && !IsArch64Bit) llvm_unreachable("Unsupported bit width value."); + if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << D.getTargetTriple(); + } + // Specify the mode in which the as(1) command operates. if (IsArch32Bit) { CmdArgs.push_back("-a32"); @@ -74,6 +82,29 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, Exec, CmdArgs, Inputs, Output)); } +// Determine whether there are any linker options that supply an export list +// (or equivalent information about what to export) being sent to the linker. +static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) { + for (size_t i = 0, Size = CmdArgs.size(); i < Size; ++i) { + llvm::StringRef ArgString(CmdArgs[i]); + + if (ArgString.starts_with("-bE:") || ArgString.starts_with("-bexport:") || + ArgString == "-bexpall" || ArgString == "-bexpfull") + return true; + + // If we split -b option, check the next opt. + if (ArgString == "-b" && i + 1 < Size) { + ++i; + llvm::StringRef ArgNextString(CmdArgs[i]); + if (ArgNextString.starts_with("E:") || + ArgNextString.starts_with("export:") || ArgNextString == "expall" || + ArgNextString == "expfull") + return true; + } + } + return false; +} + void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, @@ -88,6 +119,11 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!(IsArch32Bit || IsArch64Bit)) llvm_unreachable("Unsupported bit width value."); + if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << D.getTargetTriple(); + } + // Force static linking when "-static" is present. if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-bnso"); @@ -98,9 +134,21 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-bnoentry"); } - // Specify PGO linker option without LTO - if (!D.isUsingLTO() && - (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + if (Args.hasFlag(options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr, + false)) { + if (Args.hasArg(options::OPT_shared)) + D.Diag(diag::err_roptr_cannot_build_shared); + + // The `-mxcoff-roptr` option places constants in RO sections as much as + // possible. Then `-bforceimprw` changes such sections to RW if they contain + // imported symbols that need to be resolved. + CmdArgs.push_back("-bforceimprw"); + } + + // PGO instrumentation generates symbols belonging to special sections, and + // the linker needs to place all symbols in a particular section together in + // memory; the AIX linker does that under an option. + if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasFlag(options::OPT_fprofile_generate, options::OPT_fno_profile_generate, false) || @@ -115,8 +163,24 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.hasFlag(options::OPT_fcs_profile_generate_EQ, options::OPT_fno_profile_generate, false) || Args.hasArg(options::OPT_fcreate_profile) || - Args.hasArg(options::OPT_coverage))) - CmdArgs.push_back("-bdbg:namedsects"); + Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back("-bdbg:namedsects:ss"); + + if (Arg *A = + Args.getLastArg(clang::driver::options::OPT_mxcoff_build_id_EQ)) { + StringRef BuildId = A->getValue(); + if (BuildId[0] != '0' || BuildId[1] != 'x' || + BuildId.find_if_not(llvm::isHexDigit, 2) != StringRef::npos) + ToolChain.getDriver().Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << BuildId; + else { + std::string LinkerFlag = "-bdbg:ldrinfo:xcoff_binary_id:0x"; + if (BuildId.size() % 2) // Prepend a 0 if odd number of digits. + LinkerFlag += "0"; + LinkerFlag += BuildId.drop_front(2).lower(); + CmdArgs.push_back(Args.MakeArgString(LinkerFlag)); + } + } // Specify linker output file. assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); @@ -138,19 +202,19 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-bpD:0x110000000"); } - auto getCrt0Basename = [&Args, IsArch32Bit] { - // Enable gprofiling when "-pg" is specified. - if (Args.hasArg(options::OPT_pg)) - return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o"; - // Enable profiling when "-p" is specified. - else if (Args.hasArg(options::OPT_p)) - return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o"; - else + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_shared, options::OPT_r)) { + auto getCrt0Basename = [&Args, IsArch32Bit] { + if (Arg *A = Args.getLastArgNoClaim(options::OPT_p, options::OPT_pg)) { + // Enable gprofiling when "-pg" is specified. + if (A->getOption().matches(options::OPT_pg)) + return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o"; + // Enable profiling when "-p" is specified. + return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o"; + } return IsArch32Bit ? "crt0.o" : "crt0_64.o"; - }; + }; - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, - options::OPT_shared)) { CmdArgs.push_back( Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename()))); @@ -167,27 +231,109 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Specify linker input file(s). AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - // Add directory to library search path. - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - ToolChain.addProfileRTLibs(Args, CmdArgs); - - if (getToolChain().ShouldLinkCXXStdlib(Args)) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - AddRunTimeLibs(ToolChain, D, CmdArgs, Args); - - // Support POSIX threads if "-pthreads" or "-pthread" is present. - if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread)) - CmdArgs.push_back("-lpthreads"); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, + D.getLTOMode() == LTOK_Thin); + } - if (D.CCCIsCXX()) - CmdArgs.push_back("-lm"); + if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) { + + const char *CreateExportListExec = Args.MakeArgString( + path::parent_path(ToolChain.getDriver().ClangExecutable) + + "/llvm-nm"); + ArgStringList CreateExportCmdArgs; + + std::string CreateExportListPath = + C.getDriver().GetTemporaryPath("CreateExportList", "exp"); + const char *ExportList = + C.addTempFile(C.getArgs().MakeArgString(CreateExportListPath)); + + for (const auto &II : Inputs) + if (II.isFilename()) + CreateExportCmdArgs.push_back(II.getFilename()); + + CreateExportCmdArgs.push_back("--export-symbols"); + CreateExportCmdArgs.push_back("-X"); + if (IsArch32Bit) { + CreateExportCmdArgs.push_back("32"); + } else { + // Must be 64-bit, otherwise asserted already. + CreateExportCmdArgs.push_back("64"); + } + + auto ExpCommand = std::make_unique<Command>( + JA, *this, ResponseFileSupport::None(), CreateExportListExec, + CreateExportCmdArgs, Inputs, Output); + ExpCommand->setRedirectFiles( + {std::nullopt, std::string(ExportList), std::nullopt}); + C.addCommand(std::move(ExpCommand)); + CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-bE:") + ExportList)); + } - CmdArgs.push_back("-lc"); + // Add directory to library search path. + Args.AddAllArgs(CmdArgs, options::OPT_L); + if (!Args.hasArg(options::OPT_r)) { + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + ToolChain.addProfileRTLibs(Args, CmdArgs); + + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + + // Add OpenMP runtime if -fopenmp is specified. + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) { + switch (ToolChain.getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: + CmdArgs.push_back("-lomp"); + break; + case Driver::OMPRT_IOMP5: + CmdArgs.push_back("-liomp5"); + break; + case Driver::OMPRT_GOMP: + CmdArgs.push_back("-lgomp"); + break; + case Driver::OMPRT_Unknown: + // Already diagnosed. + break; + } + } + + // Support POSIX threads if "-pthreads" or "-pthread" is present. + if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread)) + CmdArgs.push_back("-lpthreads"); + + if (D.CCCIsCXX()) + CmdArgs.push_back("-lm"); + + CmdArgs.push_back("-lc"); + + if (Args.hasArgNoClaim(options::OPT_p, options::OPT_pg)) { + CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) + + "/lib/profiled")); + CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) + + "/usr/lib/profiled")); + } + } } + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + CmdArgs.push_back("-lm"); + CmdArgs.push_back("-lpthread"); + } const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, Inputs, Output)); @@ -196,6 +342,10 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, /// AIX - AIX tool chain which can call as(1) and ld(1) directly. AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); + ParseInlineAsmUsingAsmParser = Args.hasFlag( options::OPT_fintegrated_as, options::OPT_fno_integrated_as, true); getLibraryPaths().push_back(getDriver().SysRoot + "/usr/lib"); @@ -221,11 +371,13 @@ void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs, llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); const Driver &D = getDriver(); - // Add the Clang builtin headers (<resource>/include). if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { SmallString<128> P(D.ResourceDir); - path::append(P, "/include"); - addSystemInclude(DriverArgs, CC1Args, P.str()); + // Add the PowerPC intrinsic headers (<resource>/include/ppc_wrappers) + path::append(P, "include", "ppc_wrappers"); + addSystemInclude(DriverArgs, CC1Args, P); + // Add the Clang builtin headers (<resource>/include) + addSystemInclude(DriverArgs, CC1Args, path::parent_path(P.str())); } // Return if -nostdlibinc is specified as a driver option. @@ -274,6 +426,8 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::report_fatal_error("linking libstdc++ unimplemented on AIX"); case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); return; } @@ -281,6 +435,37 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm_unreachable("Unexpected C++ library type; only libc++ is supported."); } +void AIX::addClangTargetOptions( + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + Args.AddLastArg(CC1Args, options::OPT_mignore_xcoff_visibility); + Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ); + Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr); + + if (Args.hasFlag(options::OPT_fxl_pragma_pack, + options::OPT_fno_xl_pragma_pack, true)) + CC1Args.push_back("-fxl-pragma-pack"); +} + +void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + if (needsProfileRT(Args)) { + // Add linker option -u__llvm_profile_runtime to cause runtime + // initialization to occur. + CmdArgs.push_back(Args.MakeArgString( + Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); + + if (const auto *A = + Args.getLastArgNoClaim(options::OPT_fprofile_update_EQ)) { + StringRef Val = A->getValue(); + if (Val == "atomic" || Val == "prefer-atomic") + CmdArgs.push_back("-latomic"); + } + } + + ToolChain::addProfileRTLibs(Args, CmdArgs); +} + ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const { return ToolChain::CST_Libcxx; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h index e7ec3a5ece4d..755d87e07ec5 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h @@ -16,10 +16,10 @@ namespace clang { namespace driver { namespace tools { -/// aix -- Directly call system default assembler and linker. +/// Directly call system default assembler and linker. namespace aix { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("aix::Assembler", "assembler", TC) {} @@ -31,7 +31,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("aix::Linker", "linker", TC) {} @@ -67,6 +67,7 @@ public: return false; } bool isPICDefaultForced() const override { return true; } + bool HasNativeLLVMSupport() const override { return true; } void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, @@ -79,6 +80,13 @@ public: void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + void addClangTargetOptions( + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const override; + + void addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + CXXStdlibType GetDefaultCXXStdlibType() const override; RuntimeLibType GetDefaultRuntimeLibType() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp index 43ce33750eba..b3c9d5908654 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -9,20 +9,22 @@ #include "AMDGPU.h" #include "CommonArgs.h" #include "clang/Basic/TargetID.h" +#include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Error.h" -#include "llvm/Support/FileUtilities.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Host.h" +#include <optional> #include <system_error> -#define AMDGPU_ARCH_PROGRAM_NAME "amdgpu-arch" - using namespace clang::driver; using namespace clang::driver::tools; using namespace clang::driver::toolchains; @@ -47,7 +49,7 @@ RocmInstallationDetector::findSPACKPackage(const Candidate &Cand, FileEnd; File != FileEnd && !EC; File.increment(EC)) { llvm::StringRef FileName = llvm::sys::path::filename(File->path()); - if (FileName.startswith(Prefix)) { + if (FileName.starts_with(Prefix)) { SubDirs.push_back(FileName); if (SubDirs.size() > 1) break; @@ -82,15 +84,16 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { !EC && LI != LE; LI = LI.increment(EC)) { StringRef FilePath = LI->path(); StringRef FileName = llvm::sys::path::filename(FilePath); - if (!FileName.endswith(Suffix)) + if (!FileName.ends_with(Suffix)) continue; StringRef BaseName; - if (FileName.endswith(Suffix2)) + if (FileName.ends_with(Suffix2)) BaseName = FileName.drop_back(Suffix2.size()); - else if (FileName.endswith(Suffix)) + else if (FileName.ends_with(Suffix)) BaseName = FileName.drop_back(Suffix.size()); + const StringRef ABIVersionPrefix = "oclc_abi_version_"; if (BaseName == "ocml") { OCML = FilePath; } else if (BaseName == "ockl") { @@ -121,11 +124,17 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { WavefrontSize64.On = FilePath; } else if (BaseName == "oclc_wavefrontsize64_off") { WavefrontSize64.Off = FilePath; + } else if (BaseName.starts_with(ABIVersionPrefix)) { + unsigned ABIVersionNumber; + if (BaseName.drop_front(ABIVersionPrefix.size()) + .getAsInteger(/*Redex=*/0, ABIVersionNumber)) + continue; + ABIVersionMap[ABIVersionNumber] = FilePath.str(); } else { // Process all bitcode filenames that look like // ocl_isa_version_XXX.amdgcn.bc const StringRef DeviceLibPrefix = "oclc_isa_version_"; - if (!BaseName.startswith(DeviceLibPrefix)) + if (!BaseName.starts_with(DeviceLibPrefix)) continue; StringRef IsaVersionNumber = @@ -190,9 +199,10 @@ RocmInstallationDetector::getInstallationPathCandidates() { ROCmSearchDirs.emplace_back(RocmPathArg.str()); DoPrintROCmSearchDirs(); return ROCmSearchDirs; - } else if (const char *RocmPathEnv = ::getenv("ROCM_PATH")) { - if (!StringRef(RocmPathEnv).empty()) { - ROCmSearchDirs.emplace_back(RocmPathEnv); + } else if (std::optional<std::string> RocmPathEnv = + llvm::sys::Process::GetEnv("ROCM_PATH")) { + if (!RocmPathEnv->empty()) { + ROCmSearchDirs.emplace_back(std::move(*RocmPathEnv)); DoPrintROCmSearchDirs(); return ROCmSearchDirs; } @@ -220,7 +230,7 @@ RocmInstallationDetector::getInstallationPathCandidates() { // <rocm_root>/llvm-amdgpu-<rocm_release_string>-<hash>/bin directory. // We only consider the parent directory of llvm-amdgpu package as ROCm // installation candidate for SPACK. - if (ParentName.startswith("llvm-amdgpu-")) { + if (ParentName.starts_with("llvm-amdgpu-")) { auto SPACKPostfix = ParentName.drop_front(strlen("llvm-amdgpu-")).split('-'); auto SPACKReleaseStr = SPACKPostfix.first; @@ -233,7 +243,7 @@ RocmInstallationDetector::getInstallationPathCandidates() { // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin // Some versions of the aomp package install to /opt/rocm/aomp/bin - if (ParentName == "llvm" || ParentName.startswith("aomp")) + if (ParentName == "llvm" || ParentName.starts_with("aomp")) ParentDir = llvm::sys::path::parent_path(ParentDir); return Candidate(ParentDir.str(), /*StrictChecking=*/true); @@ -282,7 +292,7 @@ RocmInstallationDetector::getInstallationPathCandidates() { FileEnd; File != FileEnd && !EC; File.increment(EC)) { llvm::StringRef FileName = llvm::sys::path::filename(File->path()); - if (!FileName.startswith("rocm-")) + if (!FileName.starts_with("rocm-")) continue; if (LatestROCm.empty()) { LatestROCm = FileName.str(); @@ -299,6 +309,11 @@ RocmInstallationDetector::getInstallationPathCandidates() { ROCmSearchDirs.emplace_back(D.SysRoot + "/opt/" + LatestROCm, /*StrictChecking=*/true); + ROCmSearchDirs.emplace_back(D.SysRoot + "/usr/local", + /*StrictChecking=*/true); + ROCmSearchDirs.emplace_back(D.SysRoot + "/usr", + /*StrictChecking=*/true); + DoPrintROCmSearchDirs(); return ROCmSearchDirs; } @@ -314,6 +329,20 @@ RocmInstallationDetector::RocmInstallationDetector( RocmDeviceLibPathArg = Args.getAllArgValues(clang::driver::options::OPT_rocm_device_lib_path_EQ); HIPPathArg = Args.getLastArgValue(clang::driver::options::OPT_hip_path_EQ); + HIPStdParPathArg = + Args.getLastArgValue(clang::driver::options::OPT_hipstdpar_path_EQ); + HasHIPStdParLibrary = + !HIPStdParPathArg.empty() && D.getVFS().exists(HIPStdParPathArg + + "/hipstdpar_lib.hpp"); + HIPRocThrustPathArg = + Args.getLastArgValue(clang::driver::options::OPT_hipstdpar_thrust_path_EQ); + HasRocThrustLibrary = !HIPRocThrustPathArg.empty() && + D.getVFS().exists(HIPRocThrustPathArg + "/thrust"); + HIPRocPrimPathArg = + Args.getLastArgValue(clang::driver::options::OPT_hipstdpar_prim_path_EQ); + HasRocPrimLibrary = !HIPRocPrimPathArg.empty() && + D.getVFS().exists(HIPRocPrimPathArg + "/rocprim"); + if (auto *A = Args.getLastArg(clang::driver::options::OPT_hip_version_EQ)) { HIPVersionArg = A->getValue(); unsigned Major = ~0U; @@ -357,8 +386,9 @@ void RocmInstallationDetector::detectDeviceLibrary() { if (!RocmDeviceLibPathArg.empty()) LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1]; - else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH")) - LibDevicePath = LibPathEnv; + else if (std::optional<std::string> LibPathEnv = + llvm::sys::Process::GetEnv("HIP_DEVICE_LIB_PATH")) + LibDevicePath = std::move(*LibPathEnv); auto &FS = D.getVFS(); if (!LibDevicePath.empty()) { @@ -373,69 +403,57 @@ void RocmInstallationDetector::detectDeviceLibrary() { 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 &ROCmDirs = getInstallationPathCandidates(); - for (const auto &Candidate : ROCmDirs) { - 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); + // Check device library exists at the given path. + auto CheckDeviceLib = [&](StringRef Path, bool StrictChecking) { + bool CheckLibDevice = (!NoBuiltinLibs || StrictChecking); + if (CheckLibDevice && !FS.exists(Path)) + return false; - if (!NoBuiltinLibs) { - // Check that the required non-target libraries are all available. - if (!allGenericLibsValid()) - return false; + scanLibDevicePath(Path); - // 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; - }; + if (!NoBuiltinLibs) { + // Check that the required non-target libraries are all available. + if (!allGenericLibsValid()) + return false; - // The possible structures are: - // - ${ROCM_ROOT}/amdgcn/bitcode/* - // - ${ROCM_ROOT}/lib/* - // - ${ROCM_ROOT}/lib/bitcode/* - // so try to detect these layouts. - static constexpr std::array<const char *, 2> SubDirsList[] = { - {"amdgcn", "bitcode"}, - {"lib", ""}, - {"lib", "bitcode"}, - }; + // 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; + }; - // Make a path by appending sub-directories to InstallPath. - auto MakePath = [&](const llvm::ArrayRef<const char *> &SubDirs) { - auto Path = CandidatePath; - for (auto SubDir : SubDirs) - llvm::sys::path::append(Path, SubDir); - return Path; - }; + // Find device libraries in <LLVM_DIR>/lib/clang/<ver>/lib/amdgcn/bitcode + LibDevicePath = D.ResourceDir; + llvm::sys::path::append(LibDevicePath, CLANG_INSTALL_LIBDIR_BASENAME, + "amdgcn", "bitcode"); + HasDeviceLibrary = CheckDeviceLib(LibDevicePath, true); + if (HasDeviceLibrary) + return; - for (auto SubDirs : SubDirsList) { - LibDevicePath = MakePath(SubDirs); - HasDeviceLibrary = CheckDeviceLib(LibDevicePath); - if (HasDeviceLibrary) - return; - } + // Find device libraries in a legacy ROCm directory structure + // ${ROCM_ROOT}/amdgcn/bitcode/* + auto &ROCmDirs = getInstallationPathCandidates(); + for (const auto &Candidate : ROCmDirs) { + LibDevicePath = Candidate.Path; + llvm::sys::path::append(LibDevicePath, "amdgcn", "bitcode"); + HasDeviceLibrary = CheckDeviceLib(LibDevicePath, Candidate.StrictChecking); + if (HasDeviceLibrary) + return; } } void RocmInstallationDetector::detectHIPRuntime() { SmallVector<Candidate, 4> HIPSearchDirs; if (!HIPPathArg.empty()) - HIPSearchDirs.emplace_back(HIPPathArg.str(), /*StrictChecking=*/true); - else + HIPSearchDirs.emplace_back(HIPPathArg.str()); + else if (std::optional<std::string> HIPPathEnv = + llvm::sys::Process::GetEnv("HIP_PATH")) { + if (!HIPPathEnv->empty()) + HIPSearchDirs.emplace_back(std::move(*HIPPathEnv)); + } + if (HIPSearchDirs.empty()) HIPSearchDirs.append(getInstallationPathCandidates()); auto &FS = D.getVFS(); @@ -454,18 +472,41 @@ void RocmInstallationDetector::detectHIPRuntime() { llvm::sys::path::append(IncludePath, "include"); LibPath = InstallPath; llvm::sys::path::append(LibPath, "lib"); - - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = - FS.getBufferForFile(BinPath + "/.hipVersion"); - if (!VersionFile && Candidate.StrictChecking) - continue; - - if (HIPVersionArg.empty() && VersionFile) - if (parseHIPVersionFile((*VersionFile)->getBuffer())) + SharePath = InstallPath; + llvm::sys::path::append(SharePath, "share"); + + // Get parent of InstallPath and append "share" + SmallString<0> ParentSharePath = llvm::sys::path::parent_path(InstallPath); + llvm::sys::path::append(ParentSharePath, "share"); + + auto Append = [](SmallString<0> &path, const Twine &a, const Twine &b = "", + const Twine &c = "", const Twine &d = "") { + SmallString<0> newpath = path; + llvm::sys::path::append(newpath, a, b, c, d); + return newpath; + }; + // If HIP version file can be found and parsed, use HIP version from there. + for (const auto &VersionFilePath : + {Append(SharePath, "hip", "version"), + Append(ParentSharePath, "hip", "version"), + Append(BinPath, ".hipVersion")}) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = + FS.getBufferForFile(VersionFilePath); + if (!VersionFile) continue; + if (HIPVersionArg.empty() && VersionFile) + if (parseHIPVersionFile((*VersionFile)->getBuffer())) + continue; - HasHIPRuntime = true; - return; + HasHIPRuntime = true; + return; + } + // Otherwise, if -rocm-path is specified (no strict checking), use the + // default HIP version or specified by --hip-version. + if (!Candidate.StrictChecking) { + HasHIPRuntime = true; + return; + } } HasHIPRuntime = false; } @@ -480,6 +521,7 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5) && !DriverArgs.hasArg(options::OPT_nohipwrapperinc); + bool HasHipStdPar = DriverArgs.hasArg(options::OPT_hipstdpar); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { // HIP header includes standard library wrapper headers under clang @@ -502,18 +544,66 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, CC1Args.push_back(DriverArgs.MakeArgString(P)); } - if (DriverArgs.hasArg(options::OPT_nogpuinc)) + const auto HandleHipStdPar = [=, &DriverArgs, &CC1Args]() { + StringRef Inc = getIncludePath(); + auto &FS = D.getVFS(); + + if (!hasHIPStdParLibrary()) + if (!HIPStdParPathArg.empty() || + !FS.exists(Inc + "/thrust/system/hip/hipstdpar/hipstdpar_lib.hpp")) { + D.Diag(diag::err_drv_no_hipstdpar_lib); + return; + } + if (!HasRocThrustLibrary && !FS.exists(Inc + "/thrust")) { + D.Diag(diag::err_drv_no_hipstdpar_thrust_lib); + return; + } + if (!HasRocPrimLibrary && !FS.exists(Inc + "/rocprim")) { + D.Diag(diag::err_drv_no_hipstdpar_prim_lib); + return; + } + const char *ThrustPath; + if (HasRocThrustLibrary) + ThrustPath = DriverArgs.MakeArgString(HIPRocThrustPathArg); + else + ThrustPath = DriverArgs.MakeArgString(Inc + "/thrust"); + + const char *HIPStdParPath; + if (hasHIPStdParLibrary()) + HIPStdParPath = DriverArgs.MakeArgString(HIPStdParPathArg); + else + HIPStdParPath = DriverArgs.MakeArgString(StringRef(ThrustPath) + + "/system/hip/hipstdpar"); + + const char *PrimPath; + if (HasRocPrimLibrary) + PrimPath = DriverArgs.MakeArgString(HIPRocPrimPathArg); + else + PrimPath = DriverArgs.MakeArgString(getIncludePath() + "/rocprim"); + + CC1Args.append({"-idirafter", ThrustPath, "-idirafter", PrimPath, + "-idirafter", HIPStdParPath, "-include", + "hipstdpar_lib.hpp"}); + }; + + if (DriverArgs.hasArg(options::OPT_nogpuinc)) { + if (HasHipStdPar) + HandleHipStdPar(); + return; + } if (!hasHIPRuntime()) { D.Diag(diag::err_drv_no_hip_runtime); return; } - CC1Args.push_back("-internal-isystem"); + CC1Args.push_back("-idirafter"); CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); if (UsesRuntimeWrapper) CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"}); + if (HasHipStdPar) + HandleHipStdPar(); } void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -524,9 +614,18 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, std::string Linker = getToolChain().GetProgramPath(getShortName()); ArgStringList CmdArgs; + CmdArgs.push_back("--no-undefined"); + CmdArgs.push_back("-shared"); + addLinkerCompressDebugSectionsOption(getToolChain(), Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_L); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - CmdArgs.push_back("-shared"); + if (C.getDriver().isUsingLTO()) + addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0], + C.getDriver().getLTOMode() == LTOK_Thin); + else if (Args.hasArg(options::OPT_mcpu_EQ)) + CmdArgs.push_back(Args.MakeArgString( + "-plugin-opt=mcpu=" + Args.getLastArgValue(options::OPT_mcpu_EQ))); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); C.addCommand(std::make_unique<Command>( @@ -545,7 +644,7 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D, llvm::StringMap<bool> FeatureMap; auto OptionalGpuArch = parseTargetID(Triple, TargetID, &FeatureMap); if (OptionalGpuArch) { - StringRef GpuArch = OptionalGpuArch.getValue(); + StringRef GpuArch = *OptionalGpuArch; // Iterate through all possible target ID features for the given GPU. // If it is mapped to true, add +feature. // If it is mapped to false, add -feature. @@ -564,8 +663,8 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D, options::OPT_mno_wavefrontsize64, false)) Features.push_back("+wavefrontsize64"); - handleTargetFeaturesGroup( - Args, Features, options::OPT_m_amdgpu_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_amdgpu_Features_Group); } /// AMDGPU Toolchain @@ -597,9 +696,28 @@ AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, if (!DAL) DAL = new DerivedArgList(Args.getBaseArgs()); - for (Arg *A : Args) { - if (!shouldSkipArgument(A)) - DAL->append(A); + for (Arg *A : Args) + DAL->append(A); + + // Replace -mcpu=native with detected GPU. + Arg *LastMCPUArg = DAL->getLastArg(options::OPT_mcpu_EQ); + if (LastMCPUArg && StringRef(LastMCPUArg->getValue()) == "native") { + DAL->eraseArg(options::OPT_mcpu_EQ); + auto GPUsOrErr = getSystemGPUArchs(Args); + if (!GPUsOrErr) { + getDriver().Diag(diag::err_drv_undetermined_gpu_arch) + << llvm::Triple::getArchTypeName(getArch()) + << llvm::toString(GPUsOrErr.takeError()) << "-mcpu"; + } else { + auto &GPUs = *GPUsOrErr; + if (GPUs.size() > 1) { + getDriver().Diag(diag::warn_drv_multi_gpu_arch) + << llvm::Triple::getArchTypeName(getArch()) + << llvm::join(GPUs, ", ") << "-mcpu"; + } + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), + Args.MakeArgString(GPUs.front())); + } } checkTargetID(*DAL); @@ -689,7 +807,7 @@ bool AMDGPUToolChain::isWave64(const llvm::opt::ArgList &DriverArgs, ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : AMDGPUToolChain(D, Triple, Args) { - RocmInstallation.detectDeviceLibrary(); + RocmInstallation->detectDeviceLibrary(); } void AMDGPUToolChain::addClangTargetOptions( @@ -700,8 +818,7 @@ void AMDGPUToolChain::addClangTargetOptions( // 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("-fvisibility=hidden"); CC1Args.push_back("-fapply-global-visibility-to-externs"); } } @@ -716,14 +833,14 @@ AMDGPUToolChain::ParsedTargetIDType AMDGPUToolChain::getParsedTargetID(const llvm::opt::ArgList &DriverArgs) const { StringRef TargetID = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ); if (TargetID.empty()) - return {None, None, None}; + return {std::nullopt, std::nullopt, std::nullopt}; llvm::StringMap<bool> FeatureMap; auto OptionalGpuArch = parseTargetID(getTriple(), TargetID, &FeatureMap); if (!OptionalGpuArch) - return {TargetID.str(), None, None}; + return {TargetID.str(), std::nullopt, std::nullopt}; - return {TargetID.str(), OptionalGpuArch.getValue().str(), FeatureMap}; + return {TargetID.str(), OptionalGpuArch->str(), FeatureMap}; } void AMDGPUToolChain::checkTargetID( @@ -731,80 +848,33 @@ void AMDGPUToolChain::checkTargetID( auto PTID = getParsedTargetID(DriverArgs); if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) { getDriver().Diag(clang::diag::err_drv_bad_target_id) - << PTID.OptionalTargetID.getValue(); + << *PTID.OptionalTargetID; } } -llvm::Error -AMDGPUToolChain::detectSystemGPUs(const ArgList &Args, - SmallVector<std::string, 1> &GPUArchs) const { +Expected<SmallVector<std::string>> +AMDGPUToolChain::getSystemGPUArchs(const ArgList &Args) const { + // Detect AMD GPUs availible on the system. std::string Program; if (Arg *A = Args.getLastArg(options::OPT_amdgpu_arch_tool_EQ)) Program = A->getValue(); else - Program = GetProgramPath(AMDGPU_ARCH_PROGRAM_NAME); - llvm::SmallString<64> OutputFile; - llvm::sys::fs::createTemporaryFile("print-system-gpus", "" /* No Suffix */, - OutputFile); - llvm::FileRemover OutputRemover(OutputFile.c_str()); - llvm::Optional<llvm::StringRef> Redirects[] = { - {""}, - OutputFile.str(), - {""}, - }; + Program = GetProgramPath("amdgpu-arch"); - std::string ErrorMessage; - if (int Result = llvm::sys::ExecuteAndWait( - Program, {}, {}, Redirects, /* SecondsToWait */ 0, - /*MemoryLimit*/ 0, &ErrorMessage)) { - if (Result > 0) { - ErrorMessage = "Exited with error code " + std::to_string(Result); - } else if (Result == -1) { - ErrorMessage = "Execute failed: " + ErrorMessage; - } else { - ErrorMessage = "Crashed: " + ErrorMessage; - } + auto StdoutOrErr = executeToolChainProgram(Program); + if (!StdoutOrErr) + return StdoutOrErr.takeError(); - return llvm::createStringError(std::error_code(), - Program + ": " + ErrorMessage); - } - - 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 " + Program + - ": " + OutputBuf.getError().message()); - } - - for (llvm::line_iterator LineIt(**OutputBuf); !LineIt.is_at_end(); ++LineIt) { - GPUArchs.push_back(LineIt->str()); - } - return llvm::Error::success(); -} - -llvm::Error AMDGPUToolChain::getSystemGPUArch(const ArgList &Args, - std::string &GPUArch) const { - // detect the AMDGPU installed in system SmallVector<std::string, 1> GPUArchs; - auto Err = detectSystemGPUs(Args, GPUArchs); - if (Err) { - return Err; - } - if (GPUArchs.empty()) { + for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n")) + if (!Arch.empty()) + GPUArchs.push_back(Arch.str()); + + if (GPUArchs.empty()) return llvm::createStringError(std::error_code(), "No AMD GPU detected in the system"); - } - GPUArch = GPUArchs[0]; - if (GPUArchs.size() > 1) { - bool AllSame = llvm::all_of(GPUArchs, [&](const StringRef &GPUArch) { - return GPUArch == GPUArchs.front(); - }); - if (!AllSame) - return llvm::createStringError( - std::error_code(), "Multiple AMD GPUs found with different archs"); - } - return llvm::Error::success(); + + return std::move(GPUArchs); } void ROCMToolChain::addClangTargetOptions( @@ -822,20 +892,16 @@ void ROCMToolChain::addClangTargetOptions( 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 = getGPUArch(DriverArgs); 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; + StringRef LibDeviceFile = RocmInstallation->getLibDeviceFile(CanonArch); + auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion( + getAMDGPUCodeObjectVersion(getDriver(), DriverArgs)); + if (!RocmInstallation->checkCommonBitcodeLibs(CanonArch, LibDeviceFile, + ABIVer)) return; - } bool Wave64 = isWave64(DriverArgs, Kind); @@ -853,59 +919,75 @@ void ROCMToolChain::addClangTargetOptions( // Add the OpenCL specific bitcode library. llvm::SmallVector<std::string, 12> BCLibs; - BCLibs.push_back(RocmInstallation.getOpenCLPath().str()); + BCLibs.push_back(RocmInstallation->getOpenCLPath().str()); // Add the generic set of libraries. - BCLibs.append(RocmInstallation.getCommonBitcodeLibs( + BCLibs.append(RocmInstallation->getCommonBitcodeLibs( DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, - FastRelaxedMath, CorrectSqrt)); + FastRelaxedMath, CorrectSqrt, ABIVer, false)); - llvm::for_each(BCLibs, [&](StringRef BCFile) { + for (StringRef BCFile : BCLibs) { CC1Args.push_back("-mlink-builtin-bitcode"); CC1Args.push_back(DriverArgs.MakeArgString(BCFile)); - }); + } +} + +bool RocmInstallationDetector::checkCommonBitcodeLibs( + StringRef GPUArch, StringRef LibDeviceFile, + DeviceLibABIVersion ABIVer) const { + if (!hasDeviceLibrary()) { + D.Diag(diag::err_drv_no_rocm_device_lib) << 0; + return false; + } + if (LibDeviceFile.empty()) { + D.Diag(diag::err_drv_no_rocm_device_lib) << 1 << GPUArch; + return false; + } + if (ABIVer.requiresLibrary() && getABIVersionPath(ABIVer).empty()) { + D.Diag(diag::err_drv_no_rocm_device_lib) << 2 << ABIVer.toString(); + return false; + } + return true; } llvm::SmallVector<std::string, 12> RocmInstallationDetector::getCommonBitcodeLibs( const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile, bool Wave64, bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, bool FastRelaxedMath, - bool CorrectSqrt) const { - + bool CorrectSqrt, DeviceLibABIVersion ABIVer, bool isOpenMP = false) const { llvm::SmallVector<std::string, 12> BCLibs; auto AddBCLib = [&](StringRef BCFile) { BCLibs.push_back(BCFile.str()); }; AddBCLib(getOCMLPath()); - AddBCLib(getOCKLPath()); + if (!isOpenMP) + AddBCLib(getOCKLPath()); AddBCLib(getDenormalsAreZeroPath(DAZ)); AddBCLib(getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath)); AddBCLib(getFiniteOnlyPath(FiniteOnly || FastRelaxedMath)); AddBCLib(getCorrectlyRoundedSqrtPath(CorrectSqrt)); AddBCLib(getWavefrontSize64Path(Wave64)); AddBCLib(LibDeviceFile); + auto ABIVerPath = getABIVersionPath(ABIVer); + if (!ABIVerPath.empty()) + AddBCLib(ABIVerPath); return BCLibs; } -bool AMDGPUToolChain::shouldSkipArgument(const llvm::opt::Arg *A) const { - Option O = A->getOption(); - if (O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) - return true; - return false; -} - llvm::SmallVector<std::string, 12> ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, - const std::string &GPUArch) const { + const std::string &GPUArch, + bool isOpenMP) const { 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; + StringRef LibDeviceFile = RocmInstallation->getLibDeviceFile(CanonArch); + auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion( + getAMDGPUCodeObjectVersion(getDriver(), DriverArgs)); + if (!RocmInstallation->checkCommonBitcodeLibs(CanonArch, LibDeviceFile, + ABIVer)) 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 @@ -922,10 +1004,10 @@ ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, options::OPT_fno_fast_math, false); bool CorrectSqrt = DriverArgs.hasFlag( options::OPT_fhip_fp32_correctly_rounded_divide_sqrt, - options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt); + options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt, true); bool Wave64 = isWave64(DriverArgs, Kind); - return RocmInstallation.getCommonBitcodeLibs( + return RocmInstallation->getCommonBitcodeLibs( DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, - FastRelaxedMath, CorrectSqrt); + FastRelaxedMath, CorrectSqrt, ABIVer, isOpenMP); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h index 156bfd1fbdb2..b3361b1e3607 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h @@ -16,7 +16,7 @@ #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/TargetParser/TargetParser.h" #include <map> @@ -26,7 +26,7 @@ namespace driver { namespace tools { namespace amdgpu { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("amdgpu::Linker", "ld.lld", TC) {} bool isLinkJob() const override { return true; } @@ -61,16 +61,14 @@ public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); unsigned GetDefaultDwarfVersion() const override { return 5; } - bool IsIntegratedAssemblerDefault() const override { return true; } - bool IsMathErrnoDefault() const override { return false; } - bool useIntegratedAs() const override { return true; } + bool IsMathErrnoDefault() const override { return false; } bool isCrossCompiling() const override { return true; } - bool isPICDefault() const override { return false; } + bool isPICDefault() const override { return true; } bool isPIEDefault(const llvm::opt::ArgList &Args) const override { return false; } - bool isPICDefaultForced() const override { return false; } + bool isPICDefaultForced() const override { return true; } bool SupportsProfiling() const override { return false; } llvm::opt::DerivedArgList * @@ -99,13 +97,10 @@ public: /// Needed for translating LTO options. const char *getDefaultLinker() const override { return "ld.lld"; } - /// Should skip argument. - bool shouldSkipArgument(const llvm::opt::Arg *Arg) const; - - /// Uses amdgpu_arch tool to get arch of the system GPU. Will return error + /// Uses amdgpu-arch tool to get arch of the system GPU. Will return error /// if unable to find one. - llvm::Error getSystemGPUArch(const llvm::opt::ArgList &Args, - std::string &GPUArch) const; + virtual Expected<SmallVector<std::string>> + getSystemGPUArchs(const llvm::opt::ArgList &Args) const override; protected: /// Check and diagnose invalid target ID specified by -mcpu. @@ -113,9 +108,9 @@ protected: /// The struct type returned by getParsedTargetID. struct ParsedTargetIDType { - Optional<std::string> OptionalTargetID; - Optional<std::string> OptionalGPUArch; - Optional<llvm::StringMap<bool>> OptionalFeatures; + std::optional<std::string> OptionalTargetID; + std::optional<std::string> OptionalGPUArch; + std::optional<llvm::StringMap<bool>> OptionalFeatures; }; /// Get target ID, GPU arch, and target ID features if the target ID is @@ -126,8 +121,6 @@ protected: /// Get GPU arch from -mcpu without checking. StringRef getGPUArch(const llvm::opt::ArgList &DriverArgs) const; - llvm::Error detectSystemGPUs(const llvm::opt::ArgList &Args, - SmallVector<std::string, 1> &GPUArchs) const; }; class LLVM_LIBRARY_VISIBILITY ROCMToolChain : public AMDGPUToolChain { @@ -142,7 +135,8 @@ public: // Returns a list of device library names shared by different languages llvm::SmallVector<std::string, 12> getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, - const std::string &GPUArch) const; + const std::string &GPUArch, + bool isOpenMP = false) const; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp index d7cf41e4b660..b012b7cb7293 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp @@ -29,238 +29,13 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -namespace { - -static const char *getOutputFileName(Compilation &C, StringRef Base, - const char *Postfix, - const char *Extension) { - const char *OutputFileName; - if (C.getDriver().isSaveTempsEnabled()) { - OutputFileName = - C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension); - } else { - std::string TmpName = - C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension); - OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName)); - } - return OutputFileName; -} - -static void addLLCOptArg(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) { - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - StringRef OOpt = "0"; - if (A->getOption().matches(options::OPT_O4) || - A->getOption().matches(options::OPT_Ofast)) - OOpt = "3"; - else if (A->getOption().matches(options::OPT_O0)) - OOpt = "0"; - else if (A->getOption().matches(options::OPT_O)) { - // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3 - // so we map -Os/-Oz to -O2. - // Only clang supports -Og, and maps it to -O1. - // We map anything else to -O2. - OOpt = llvm::StringSwitch<const char *>(A->getValue()) - .Case("1", "1") - .Case("2", "2") - .Case("3", "3") - .Case("s", "2") - .Case("z", "2") - .Case("g", "1") - .Default("0"); - } - CmdArgs.push_back(Args.MakeArgString("-O" + OOpt)); - } -} - -static bool checkSystemForAMDGPU(const ArgList &Args, const AMDGPUToolChain &TC, - std::string &GPUArch) { - if (auto Err = TC.getSystemGPUArch(Args, GPUArch)) { - std::string ErrMsg = - llvm::formatv("{0}", llvm::fmt_consume(std::move(Err))); - TC.getDriver().Diag(diag::err_drv_undetermined_amdgpu_arch) << ErrMsg; - return false; - } - - return true; -} -} // namespace - -const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( - const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C, - const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, - StringRef SubArchName, StringRef OutputFilePrefix) const { - ArgStringList CmdArgs; - - for (const auto &II : Inputs) - if (II.isFilename()) - CmdArgs.push_back(II.getFilename()); - - bool HasLibm = false; - if (Args.hasArg(options::OPT_l)) { - auto Lm = Args.getAllArgValues(options::OPT_l); - for (auto &Lib : Lm) { - if (Lib == "m") { - HasLibm = true; - break; - } - } - - if (HasLibm) { - // This is not certain to work. The device libs added here, and passed to - // llvm-link, are missing attributes that they expect to be inserted when - // passed to mlink-builtin-bitcode. The amdgpu backend does not generate - // conservatively correct code when attributes are missing, so this may - // be the root cause of miscompilations. Passing via mlink-builtin-bitcode - // ultimately hits CodeGenModule::addDefaultFunctionDefinitionAttributes - // on each function, see D28538 for context. - // Potential workarounds: - // - unconditionally link all of the device libs to every translation - // unit in clang via mlink-builtin-bitcode - // - build a libm bitcode file as part of the DeviceRTL and explictly - // mlink-builtin-bitcode the rocm device libs components at build time - // - drop this llvm-link fork in favour or some calls into LLVM, chosen - // to do basically the same work as llvm-link but with that call first - // - write an opt pass that sets that on every function it sees and pipe - // the device-libs bitcode through that on the way to this llvm-link - SmallVector<std::string, 12> BCLibs = - AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str()); - llvm::for_each(BCLibs, [&](StringRef BCFile) { - CmdArgs.push_back(Args.MakeArgString(BCFile)); - }); - } - } - - AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn", - SubArchName, /*isBitCodeSDL=*/true, - /*postClangLink=*/false); - // Add an intermediate output file. - CmdArgs.push_back("-o"); - const char *OutputFileName = - getOutputFileName(C, OutputFilePrefix, "-linked", "bc"); - CmdArgs.push_back(OutputFileName); - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, - InputInfo(&JA, Args.MakeArgString(OutputFileName)))); - - // If we linked in libm definitions late we run another round of optimizations - // to inline the definitions and fold what is foldable. - if (HasLibm) { - ArgStringList OptCmdArgs; - const char *OptOutputFileName = - getOutputFileName(C, OutputFilePrefix, "-linked-opt", "bc"); - addLLCOptArg(Args, OptCmdArgs); - OptCmdArgs.push_back(OutputFileName); - OptCmdArgs.push_back("-o"); - OptCmdArgs.push_back(OptOutputFileName); - const char *OptExec = - Args.MakeArgString(getToolChain().GetProgramPath("opt")); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), OptExec, OptCmdArgs, - InputInfo(&JA, Args.MakeArgString(OutputFileName)), - InputInfo(&JA, Args.MakeArgString(OptOutputFileName)))); - OutputFileName = OptOutputFileName; - } - - return OutputFileName; -} - -const char *AMDGCN::OpenMPLinker::constructLlcCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix, const char *InputFileName, - bool OutputIsAsm) const { - // Construct llc command. - ArgStringList LlcArgs; - // The input to llc is the output from opt. - LlcArgs.push_back(InputFileName); - // Pass optimization arg to llc. - addLLCOptArg(Args, LlcArgs); - LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); - LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); - LlcArgs.push_back( - Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj"))); - - for (const Arg *A : Args.filtered(options::OPT_mllvm)) { - LlcArgs.push_back(A->getValue(0)); - } - - // Add output filename - LlcArgs.push_back("-o"); - const char *LlcOutputFile = - getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o"); - LlcArgs.push_back(LlcOutputFile); - const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc")); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), Llc, LlcArgs, Inputs, - InputInfo(&JA, Args.MakeArgString(LlcOutputFile)))); - return LlcOutputFile; -} - -void AMDGCN::OpenMPLinker::constructLldCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const InputInfo &Output, const llvm::opt::ArgList &Args, - const char *InputFileName) const { - // Construct lld command. - // The output from ld.lld is an HSA code object file. - ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", - "-shared", "-o", Output.getFilename(), - InputFileName}; - - const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), Lld, LldArgs, Inputs, - InputInfo(&JA, Args.MakeArgString(Output.getFilename())))); -} - -// 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::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const ToolChain &TC = getToolChain(); - assert(getToolChain().getTriple().isAMDGCN() && "Unsupported target"); - - const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC = - static_cast<const toolchains::AMDGPUOpenMPToolChain &>(TC); - - std::string GPUArch = Args.getLastArgValue(options::OPT_march_EQ).str(); - if (GPUArch.empty()) { - if (!checkSystemForAMDGPU(Args, AMDGPUOpenMPTC, GPUArch)) - return; - } - - // Prefix for temporary file name. - std::string Prefix; - for (const auto &II : Inputs) - if (II.isFilename()) - Prefix = llvm::sys::path::stem(II.getFilename()).str() + "-" + GPUArch; - assert(Prefix.length() && "no linker inputs are files "); - - // Each command outputs different files. - const char *LLVMLinkCommand = constructLLVMLinkCommand( - AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix); - - // Produce readable assembly if save-temps is enabled. - if (C.getDriver().isSaveTempsEnabled()) - constructLlcCommand(C, JA, Inputs, Args, GPUArch, Prefix, LLVMLinkCommand, - /*OutputIsAsm=*/true); - const char *LlcCommand = constructLlcCommand(C, JA, Inputs, Args, GPUArch, - Prefix, LLVMLinkCommand); - constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand); -} - AMDGPUOpenMPToolChain::AMDGPUOpenMPToolChain(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. + // discover the 'amdgpu-arch' executable. getProgramPaths().push_back(getDriver().Dir); } @@ -269,11 +44,8 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions( Action::OffloadKind DeviceOffloadingKind) const { HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); - std::string GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ).str(); - if (GPUArch.empty()) { - if (!checkSystemForAMDGPU(DriverArgs, *this, GPUArch)) - return; - } + StringRef GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + assert(!GPUArch.empty() && "Must have an explicit GPU arch."); assert(DeviceOffloadingKind == Action::OFK_OpenMP && "Only OpenMP offloading kinds are supported."); @@ -285,19 +57,15 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions( if (DriverArgs.hasArg(options::OPT_nogpulib)) return; + for (auto BCFile : getDeviceLibs(DriverArgs)) { + CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" + : "-mlink-bitcode-file"); + CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path)); + } + // Link the bitcode library late if we're using device LTO. if (getDriver().isUsingLTO(/* IsOffload */ true)) return; - - std::string BitcodeSuffix; - if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime, - options::OPT_fno_openmp_target_new_runtime, true)) - BitcodeSuffix = "new-amdgpu-" + GPUArch; - else - BitcodeSuffix = "amdgcn-" + GPUArch; - - addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, - getTriple()); } llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( @@ -315,9 +83,20 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( if (!llvm::is_contained(*DAL, A)) DAL->append(A); - std::string Arch = DAL->getLastArgValue(options::OPT_march_EQ).str(); - if (Arch.empty()) { - checkSystemForAMDGPU(Args, *this, Arch); + if (!DAL->hasArg(options::OPT_march_EQ)) { + StringRef Arch = BoundArch; + if (Arch.empty()) { + auto ArchsOrErr = getSystemGPUArchs(Args); + if (!ArchsOrErr) { + std::string ErrMsg = + llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError())); + getDriver().Diag(diag::err_drv_undetermined_gpu_arch) + << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march"; + Arch = CudaArchToString(CudaArch::HIPDefault); + } else { + Arch = Args.MakeArgString(ArchsOrErr->front()); + } + } DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch); } @@ -337,11 +116,6 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( return DAL; } -Tool *AMDGPUOpenMPToolChain::buildLinker() const { - assert(getTriple().isAMDGCN()); - return new tools::AMDGCN::OpenMPLinker(*this); -} - void AMDGPUOpenMPToolChain::addClangWarningOptions( ArgStringList &CC1Args) const { HostTC.addClangWarningOptions(CC1Args); @@ -380,3 +154,24 @@ AMDGPUOpenMPToolChain::computeMSVCVersion(const Driver *D, const ArgList &Args) const { return HostTC.computeMSVCVersion(D, Args); } + +llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> +AMDGPUOpenMPToolChain::getDeviceLibs(const llvm::opt::ArgList &Args) const { + if (Args.hasArg(options::OPT_nogpulib)) + return {}; + + if (!RocmInstallation->hasDeviceLibrary()) { + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; + return {}; + } + + StringRef GpuArch = getProcessorFromTargetID( + getTriple(), Args.getLastArgValue(options::OPT_march_EQ)); + + SmallVector<BitCodeLibraryInfo, 12> BCLibs; + for (auto BCLib : getCommonDeviceLibNames(Args, GpuArch.str(), + /*IsOpenMP=*/true)) + BCLibs.emplace_back(BCLib); + + return BCLibs; +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h index 233256bf7378..2be444a42c55 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h @@ -20,49 +20,6 @@ namespace toolchains { class AMDGPUOpenMPToolChain; } -namespace tools { - -namespace AMDGCN { -// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with -// device library, then compiles it to ISA in a shared object. -class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool { -public: - OpenMPLinker(const ToolChain &TC) - : Tool("AMDGCN::OpenMPLinker", "amdgcn-link", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - -private: - /// \return llvm-link output file name. - const char *constructLLVMLinkCommand( - const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C, - const JobAction &JA, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix) const; - - /// \return llc output file name. - const char *constructLlcCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix, - const char *InputFileName, - bool OutputIsAsm = false) const; - - void constructLldCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, const InputInfo &Output, - const llvm::opt::ArgList &Args, - const char *InputFileName) const; -}; - -} // end namespace AMDGCN -} // end namespace tools - namespace toolchains { class LLVM_LIBRARY_VISIBILITY AMDGPUOpenMPToolChain final @@ -97,10 +54,10 @@ public: computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override; - const ToolChain &HostTC; + llvm::SmallVector<BitCodeLibraryInfo, 12> + getDeviceLibs(const llvm::opt::ArgList &Args) const override; -protected: - Tool *buildLinker() const override; + const ToolChain &HostTC; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp index 2cf16cf9fdb4..bb5c0e6db997 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp @@ -12,13 +12,12 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/SubtargetFeature.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/TargetParser/SubtargetFeature.h" using namespace clang::driver; using namespace clang::driver::toolchains; @@ -28,6 +27,7 @@ using namespace llvm::opt; namespace { +// NOTE: This list has been synchronized with gcc-avr 7.3.0 and avr-libc 2.0.0. constexpr struct { StringRef Name; StringRef SubPath; @@ -62,6 +62,7 @@ constexpr struct { {"attiny261a", "avr25/tiny-stack", "avr25", 0x800060}, {"at86rf401", "avr25", "avr25", 0x800060}, {"ata5272", "avr25", "avr25", 0x800100}, + {"ata6616c", "avr25", "avr25", 0x800100}, {"attiny4313", "avr25", "avr25", 0x800060}, {"attiny44", "avr25", "avr25", 0x800060}, {"attiny44a", "avr25", "avr25", 0x800060}, @@ -88,6 +89,8 @@ constexpr struct { {"at90usb82", "avr35", "avr35", 0x800100}, {"at90usb162", "avr35", "avr35", 0x800100}, {"ata5505", "avr35", "avr35", 0x800100}, + {"ata6617c", "avr35", "avr35", 0x800100}, + {"ata664251", "avr35", "avr35", 0x800100}, {"atmega8u2", "avr35", "avr35", 0x800100}, {"atmega16u2", "avr35", "avr35", 0x800100}, {"atmega32u2", "avr35", "avr35", 0x800100}, @@ -97,6 +100,7 @@ constexpr struct { {"atmega8a", "avr4", "avr4", 0x800060}, {"ata6285", "avr4", "avr4", 0x800100}, {"ata6286", "avr4", "avr4", 0x800100}, + {"ata6612c", "avr4", "avr4", 0x800100}, {"atmega48", "avr4", "avr4", 0x800100}, {"atmega48a", "avr4", "avr4", 0x800100}, {"atmega48pa", "avr4", "avr4", 0x800100}, @@ -116,8 +120,17 @@ constexpr struct { {"at90pwm3", "avr4", "avr4", 0x800100}, {"at90pwm3b", "avr4", "avr4", 0x800100}, {"at90pwm81", "avr4", "avr4", 0x800100}, + {"ata5702m322", "avr5", "avr5", 0x800200}, + {"ata5782", "avr5", "avr5", 0x800200}, {"ata5790", "avr5", "avr5", 0x800100}, + {"ata5790n", "avr5", "avr5", 0x800100}, + {"ata5791", "avr5", "avr5", 0x800100}, {"ata5795", "avr5", "avr5", 0x800100}, + {"ata5831", "avr5", "avr5", 0x800200}, + {"ata6613c", "avr5", "avr5", 0x800100}, + {"ata6614q", "avr5", "avr5", 0x800100}, + {"ata8210", "avr5", "avr5", 0x800200}, + {"ata8510", "avr5", "avr5", 0x800200}, {"atmega16", "avr5", "avr5", 0x800060}, {"atmega16a", "avr5", "avr5", 0x800060}, {"atmega161", "avr5", "avr5", 0x800060}, @@ -145,6 +158,7 @@ constexpr struct { {"atmega324a", "avr5", "avr5", 0x800100}, {"atmega324p", "avr5", "avr5", 0x800100}, {"atmega324pa", "avr5", "avr5", 0x800100}, + {"atmega324pb", "avr5", "avr5", 0x800100}, {"atmega325", "avr5", "avr5", 0x800100}, {"atmega325a", "avr5", "avr5", 0x800100}, {"atmega325p", "avr5", "avr5", 0x800100}, @@ -155,6 +169,7 @@ constexpr struct { {"atmega3250pa", "avr5", "avr5", 0x800100}, {"atmega328", "avr5", "avr5", 0x800100}, {"atmega328p", "avr5", "avr5", 0x800100}, + {"atmega328pb", "avr5", "avr5", 0x800100}, {"atmega329", "avr5", "avr5", 0x800100}, {"atmega329a", "avr5", "avr5", 0x800100}, {"atmega329p", "avr5", "avr5", 0x800100}, @@ -192,6 +207,7 @@ constexpr struct { {"atmega32hvb", "avr5", "avr5", 0x800100}, {"atmega32hvbrevb", "avr5", "avr5", 0x800100}, {"atmega64hve", "avr5", "avr5", 0x800100}, + {"atmega64hve2", "avr5", "avr5", 0x800100}, {"at90can32", "avr5", "avr5", 0x800100}, {"at90can64", "avr5", "avr5", 0x800100}, {"at90pwm161", "avr5", "avr5", 0x800100}, @@ -232,17 +248,22 @@ constexpr struct { {"attiny10", "avrtiny", "avrtiny", 0x800040}, {"attiny20", "avrtiny", "avrtiny", 0x800040}, {"attiny40", "avrtiny", "avrtiny", 0x800040}, + {"attiny102", "avrtiny", "avrtiny", 0x800040}, + {"attiny104", "avrtiny", "avrtiny", 0x800040}, {"atxmega16a4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega16a4u", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega16c4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega16d4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32a4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32a4u", "avrxmega2", "avrxmega2", 0x802000}, + {"atxmega32c3", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32c4", "avrxmega2", "avrxmega2", 0x802000}, + {"atxmega32d3", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32d4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32e5", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega16e5", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega8e5", "avrxmega2", "avrxmega2", 0x802000}, + {"atxmega64a3", "avrxmega4", "avrxmega4", 0x802000}, {"atxmega64a3u", "avrxmega4", "avrxmega4", 0x802000}, {"atxmega64a4u", "avrxmega4", "avrxmega4", 0x802000}, {"atxmega64b1", "avrxmega4", "avrxmega4", 0x802000}, @@ -274,6 +295,42 @@ constexpr struct { {"atxmega128a1", "avrxmega7", "avrxmega7", 0x802000}, {"atxmega128a1u", "avrxmega7", "avrxmega7", 0x802000}, {"atxmega128a4u", "avrxmega7", "avrxmega7", 0x802000}, + {"attiny202", "avrxmega3/short-calls", "avrxmega3", 0x803F80}, + {"attiny204", "avrxmega3/short-calls", "avrxmega3", 0x803F80}, + {"attiny212", "avrxmega3/short-calls", "avrxmega3", 0x803F80}, + {"attiny214", "avrxmega3/short-calls", "avrxmega3", 0x803F80}, + {"attiny402", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny404", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny406", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny412", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny414", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny416", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny417", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny804", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny806", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny807", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny814", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny816", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny817", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"atmega808", "avrxmega3/short-calls", "avrxmega3", 0x803C00}, + {"atmega809", "avrxmega3/short-calls", "avrxmega3", 0x803C00}, + {"atmega1608", "avrxmega3", "avrxmega3", 0x803800}, + {"atmega1609", "avrxmega3", "avrxmega3", 0x803800}, + {"atmega3208", "avrxmega3", "avrxmega3", 0x803000}, + {"atmega3209", "avrxmega3", "avrxmega3", 0x803000}, + {"atmega4808", "avrxmega3", "avrxmega3", 0x802800}, + {"atmega4809", "avrxmega3", "avrxmega3", 0x802800}, + {"attiny1604", "avrxmega3", "avrxmega3", 0x803C00}, + {"attiny1606", "avrxmega3", "avrxmega3", 0x803C00}, + {"attiny1607", "avrxmega3", "avrxmega3", 0x803C00}, + {"attiny1614", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1616", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1617", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1624", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1626", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1627", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny3216", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny3217", "avrxmega3", "avrxmega3", 0x803800}, }; std::string GetMCUSubPath(StringRef MCUName) { @@ -283,18 +340,18 @@ std::string GetMCUSubPath(StringRef MCUName) { return ""; } -llvm::Optional<StringRef> GetMCUFamilyName(StringRef MCUName) { +std::optional<StringRef> GetMCUFamilyName(StringRef MCUName) { for (const auto &MCU : MCUInfo) if (MCU.Name == MCUName) - return Optional<StringRef>(MCU.Family); - return Optional<StringRef>(); + return std::optional<StringRef>(MCU.Family); + return std::nullopt; } -llvm::Optional<unsigned> GetMCUSectionAddressData(StringRef MCUName) { +std::optional<unsigned> GetMCUSectionAddressData(StringRef MCUName) { for (const auto &MCU : MCUInfo) if (MCU.Name == MCUName && MCU.DataAddr > 0) - return Optional<unsigned>(MCU.DataAddr); - return Optional<unsigned>(); + return std::optional<unsigned>(MCU.DataAddr); + return std::nullopt; } const StringRef PossibleAVRLibcLocations[] = { @@ -308,49 +365,18 @@ const StringRef PossibleAVRLibcLocations[] = { /// AVR Toolchain AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args), LinkStdlib(false) { + : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); + if (getCPUName(D, Args, Triple).empty()) + D.Diag(diag::warn_drv_avr_mcu_not_specified); + // Only add default libraries if the user hasn't explicitly opted out. if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs) && - !Args.hasArg(options::OPT_c /* does not apply when not linking */)) { - std::string CPU = getCPUName(D, Args, Triple); - - if (CPU.empty()) { - // We cannot link any standard libraries without an MCU specified. - D.Diag(diag::warn_drv_avr_mcu_not_specified); - } else { - Optional<StringRef> FamilyName = GetMCUFamilyName(CPU); - Optional<std::string> AVRLibcRoot = findAVRLibcInstallation(); - - if (!FamilyName.hasValue()) { - // We do not have an entry for this CPU in the family - // mapping table yet. - D.Diag(diag::warn_drv_avr_family_linking_stdlibs_not_implemented) - << CPU; - } else if (!GCCInstallation.isValid()) { - // No avr-gcc found and so no runtime linked. - D.Diag(diag::warn_drv_avr_gcc_not_found); - } else if (!AVRLibcRoot.hasValue()) { - // No avr-libc found and so no runtime linked. - D.Diag(diag::warn_drv_avr_libc_not_found); - } else { // We have enough information to link stdlibs - std::string GCCRoot(GCCInstallation.getInstallPath()); - std::string GCCParentPath(GCCInstallation.getParentLibPath()); - std::string LibcRoot = AVRLibcRoot.getValue(); - std::string SubPath = GetMCUSubPath(CPU); - - getProgramPaths().push_back(GCCParentPath + "/../bin"); - getFilePaths().push_back(LibcRoot + std::string("/lib/") + SubPath); - getFilePaths().push_back(GCCRoot + std::string("/") + SubPath); - - LinkStdlib = true; - } - } - - if (!LinkStdlib) - D.Diag(diag::warn_drv_avr_stdlib_not_linked); + !Args.hasArg(options::OPT_nodefaultlibs) && GCCInstallation.isValid()) { + GCCInstallPath = GCCInstallation.getInstallPath(); + std::string GCCParentPath(GCCInstallation.getParentLibPath()); + getProgramPaths().push_back(GCCParentPath + "/../bin"); } } @@ -361,12 +387,12 @@ void AVRToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; // Omit if there is no avr-libc installed. - Optional<std::string> AVRLibcRoot = findAVRLibcInstallation(); - if (!AVRLibcRoot.hasValue()) + std::optional<std::string> AVRLibcRoot = findAVRLibcInstallation(); + if (!AVRLibcRoot) return; // Add 'avr-libc/include' to clang system include paths if applicable. - std::string AVRInc = AVRLibcRoot.getValue() + "/include"; + std::string AVRInc = *AVRLibcRoot + "/include"; if (llvm::sys::fs::is_directory(AVRInc)) addSystemInclude(DriverArgs, CC1Args, AVRInc); } @@ -387,41 +413,116 @@ void AVRToolChain::addClangTargetOptions( } Tool *AVRToolChain::buildLinker() const { - return new tools::AVR::Linker(getTriple(), *this, LinkStdlib); + return new tools::AVR::Linker(getTriple(), *this); +} + +std::string +AVRToolChain::getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, + FileType Type = ToolChain::FT_Static) const { + assert(Type == ToolChain::FT_Static && "AVR only supports static libraries"); + // Since AVR can never be a host environment, its compiler-rt library files + // should always have ".a" suffix, even on windows. + SmallString<32> File("/libclang_rt."); + File += Component.str(); + File += ".a"; + // Return the default compiler-rt path appended with + // "avr/libclang_rt.$COMPONENT.a". + SmallString<256> Path(ToolChain::getCompilerRTPath()); + llvm::sys::path::append(Path, "avr"); + llvm::sys::path::append(Path, File.str()); + return std::string(Path); } void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const auto &TC = static_cast<const AVRToolChain &>(getToolChain()); const Driver &D = getToolChain().getDriver(); // Compute information about the target AVR. std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); - llvm::Optional<StringRef> FamilyName = GetMCUFamilyName(CPU); - llvm::Optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU); + std::optional<StringRef> FamilyName = GetMCUFamilyName(CPU); + std::optional<std::string> AVRLibcRoot = TC.findAVRLibcInstallation(); + std::optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU); + + // Compute the linker program path, and use GNU "avr-ld" as default. + const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ); + std::string Linker = A ? getToolChain().GetLinkerPath(nullptr) + : getToolChain().GetProgramPath(getShortName()); - std::string Linker = getToolChain().GetProgramPath(getShortName()); ArgStringList CmdArgs; - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); // Enable garbage collection of unused sections. - CmdArgs.push_back("--gc-sections"); + if (!Args.hasArg(options::OPT_r)) + CmdArgs.push_back("--gc-sections"); // Add library search paths before we specify libraries. Args.AddAllArgs(CmdArgs, options::OPT_L); getToolChain().AddFilePathLibArgs(Args, CmdArgs); - if (SectionAddressData.hasValue()) { - std::string DataSectionArg = std::string("-Tdata=0x") + - llvm::utohexstr(SectionAddressData.getValue()); - CmdArgs.push_back(Args.MakeArgString(DataSectionArg)); - } else { - // We do not have an entry for this CPU in the address mapping table yet. - D.Diag(diag::warn_drv_avr_linker_section_addresses_not_implemented) << CPU; + // Currently we only support libgcc and compiler-rt. + auto RtLib = TC.GetRuntimeLibType(Args); + assert( + (RtLib == ToolChain::RLT_Libgcc || RtLib == ToolChain::RLT_CompilerRT) && + "unknown runtime library"); + + // Only add default libraries if the user hasn't explicitly opted out. + bool LinkStdlib = false; + if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_r) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!CPU.empty()) { + if (!FamilyName) { + // We do not have an entry for this CPU in the family + // mapping table yet. + D.Diag(diag::warn_drv_avr_family_linking_stdlibs_not_implemented) + << CPU; + } else if (!AVRLibcRoot) { + // No avr-libc found and so no runtime linked. + D.Diag(diag::warn_drv_avr_libc_not_found); + } else { + std::string SubPath = GetMCUSubPath(CPU); + // Add path of avr-libc. + CmdArgs.push_back( + Args.MakeArgString(Twine("-L") + *AVRLibcRoot + "/lib/" + SubPath)); + if (RtLib == ToolChain::RLT_Libgcc) + CmdArgs.push_back(Args.MakeArgString("-L" + TC.getGCCInstallPath() + + "/" + SubPath)); + LinkStdlib = true; + } + } + if (!LinkStdlib) + D.Diag(diag::warn_drv_avr_stdlib_not_linked); + } + + if (!Args.hasArg(options::OPT_r)) { + if (SectionAddressData) { + CmdArgs.push_back( + Args.MakeArgString("--defsym=__DATA_REGION_ORIGIN__=0x" + + Twine::utohexstr(*SectionAddressData))); + } else { + // We do not have an entry for this CPU in the address mapping table + // yet. + D.Diag(diag::warn_drv_avr_linker_section_addresses_not_implemented) + << CPU; + } + } + + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(TC, Args, CmdArgs, Output, *Input, + D.getLTOMode() == LTOK_Thin); } // If the family name is known, we can link with the device-specific libgcc. @@ -436,28 +537,63 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o"); CmdArgs.push_back(Args.MakeArgString(CrtFileName)); - CmdArgs.push_back("-lgcc"); + // Link to libgcc. + if (RtLib == ToolChain::RLT_Libgcc) + CmdArgs.push_back("-lgcc"); + + // Link to generic libraries of avr-libc. CmdArgs.push_back("-lm"); CmdArgs.push_back("-lc"); // Add the link library specific to the MCU. CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU)); + // Add the relocatable inputs. + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + // We directly use libclang_rt.builtins.a as input file, instead of using + // '-lclang_rt.builtins'. + if (RtLib == ToolChain::RLT_CompilerRT) { + std::string RtLib = + getToolChain().getCompilerRT(Args, "builtins", ToolChain::FT_Static); + if (llvm::sys::fs::exists(RtLib)) + CmdArgs.push_back(Args.MakeArgString(RtLib)); + } + CmdArgs.push_back("--end-group"); - // Specify the family name as the emulation mode to use. - // This is almost always required because otherwise avr-ld - // will assume 'avr2' and warn about the program being larger - // than the bare minimum supports. - CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName)); + // Add avr-libc's linker script to lld by default, if it exists. + if (!Args.hasArg(options::OPT_T) && + Linker.find("avr-ld") == std::string::npos) { + std::string Path(*AVRLibcRoot + "/lib/ldscripts/"); + Path += *FamilyName; + Path += ".x"; + if (llvm::sys::fs::exists(Path)) + CmdArgs.push_back(Args.MakeArgString("-T" + Path)); + } + // Otherwise add user specified linker script to either avr-ld or lld. + else + Args.AddAllArgs(CmdArgs, options::OPT_T); + + if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) + CmdArgs.push_back("--relax"); + } else { + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); } + // Specify the family name as the emulation mode to use. + // This is almost always required because otherwise avr-ld + // will assume 'avr2' and warn about the program being larger + // than the bare minimum supports. + if (Linker.find("avr-ld") != std::string::npos && FamilyName) + CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName)); + C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker), CmdArgs, Inputs, Output)); } -llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const { +std::optional<std::string> AVRToolChain::findAVRLibcInstallation() const { // Search avr-libc installation according to avr-gcc installation. std::string GCCParent(GCCInstallation.getParentLibPath()); std::string Path(GCCParent + "/avr"); @@ -475,5 +611,5 @@ llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const { return Path; } - return llvm::None; + return std::nullopt; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h index 2d027957ed76..247188b7eaad 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h @@ -31,28 +31,28 @@ public: llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + std::optional<std::string> findAVRLibcInstallation() const; + StringRef getGCCInstallPath() const { return GCCInstallPath; } + std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, + FileType Type) const override; + + bool HasNativeLLVMSupport() const override { return true; } + protected: Tool *buildLinker() const override; private: - /// Whether libgcc, libct, and friends should be linked. - /// - /// This is not done if the user does not specify a - /// microcontroller on the command line. - bool LinkStdlib; - - llvm::Optional<std::string> findAVRLibcInstallation() const; + StringRef GCCInstallPath; }; } // end namespace toolchains namespace tools { namespace AVR { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: - Linker(const llvm::Triple &Triple, const ToolChain &TC, bool LinkStdlib) - : Tool("AVR::Linker", "avr-ld", TC), Triple(Triple), - LinkStdlib(LinkStdlib) {} + Linker(const llvm::Triple &Triple, const ToolChain &TC) + : Tool("AVR::Linker", "avr-ld", TC), Triple(Triple) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } @@ -63,7 +63,6 @@ public: protected: const llvm::Triple &Triple; - bool LinkStdlib; }; } // end namespace AVR } // end namespace tools diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp deleted file mode 100644 index be1476a7636c..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp +++ /dev/null @@ -1,144 +0,0 @@ -//===--- Ananas.cpp - Ananas 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 "Ananas.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/InputInfo.h" -#include "clang/Driver/Options.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Support/Path.h" - -using namespace clang::driver; -using namespace clang::driver::tools; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - 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<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const ToolChain &ToolChain = getToolChain(); - const Driver &D = ToolChain.getDriver(); - 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 (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 { - Args.AddAllArgs(CmdArgs, options::OPT_pie); - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back("/lib/ld-ananas.so"); - } - } - - 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)) { - if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - } - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o"))); - } else { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); - } - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_Z_Flag, 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); - } - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (ToolChain.ShouldLinkCXXStdlib(Args)) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - CmdArgs.push_back("-lc"); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - 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"))); - } - - const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -// Ananas - Ananas tool chain which can call as(1) and ld(1) directly. - -Ananas::Ananas(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); -} - -Tool *Ananas::buildAssembler() const { - return new tools::ananas::Assembler(*this); -} - -Tool *Ananas::buildLinker() const { return new tools::ananas::Linker(*this); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h deleted file mode 100644 index 72ad3edcf056..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h +++ /dev/null @@ -1,65 +0,0 @@ -//===--- Ananas.h - Ananas 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H - -#include "Gnu.h" -#include "clang/Driver/Tool.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { - -/// ananas -- Directly call GNU Binutils assembler and linker -namespace ananas { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("ananas::Assembler", "assembler", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { -public: - Linker(const ToolChain &TC) : Tool("ananas::Linker", "linker", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace ananas -} // end namespace tools - -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY Ananas : public Generic_ELF { -public: - Ananas(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 53610f0909a2..0cf96bb5c9cb 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -7,13 +7,13 @@ //===----------------------------------------------------------------------===// #include "AArch64.h" +#include "../CommonArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/AArch64TargetParser.h" -#include "llvm/Support/TargetParser.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/AArch64TargetParser.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -38,6 +38,8 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, CPU = Mcpu.split("+").first.lower(); } + CPU = llvm::AArch64::resolveCPUAlias(CPU); + // Handle CPU name is 'native'. if (CPU == "native") return std::string(llvm::sys::getHostCPUName()); @@ -51,13 +53,17 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, return "apple-m1"; } + if (Triple.isXROS()) { + // The xrOS simulator runs on M1 as well, it should have been covered above. + assert(!Triple.isSimulatorEnvironment() && "xrossim should be mac-like"); + return "apple-a12"; + } // arm64e requires v8.3a and only runs on apple-a12 and later CPUs. if (Triple.isArm64e()) return "apple-a12"; - // Make sure we pick the appropriate Apple CPU if -arch is used or when - // targetting a Darwin OS. - if (Args.getLastArg(options::OPT_arch) || Triple.isOSDarwin()) + // Make sure we pick the appropriate Apple CPU when targetting a Darwin OS. + if (Triple.isOSDarwin()) return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4" : "apple-a7"; @@ -66,107 +72,68 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, // Decode AArch64 features from string like +[no]featureA+[no]featureB+... static bool DecodeAArch64Features(const Driver &D, StringRef text, - std::vector<StringRef> &Features, - llvm::AArch64::ArchKind ArchKind) { + llvm::AArch64::ExtensionSet &Extensions) { SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); for (StringRef Feature : Split) { - StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature); - if (!FeatureName.empty()) - Features.push_back(FeatureName); - else if (Feature == "neon" || Feature == "noneon") + if (Feature == "neon" || Feature == "noneon") { D.Diag(clang::diag::err_drv_no_neon_modifier); - else - return false; - - if (Feature == "sve2") - Features.push_back("+sve"); - else if (Feature == "sve2-bitperm" || Feature == "sve2-sha3" || - Feature == "sve2-aes" || Feature == "sve2-sm4") { - Features.push_back("+sve"); - Features.push_back("+sve2"); - } else if (Feature == "nosve") { - Features.push_back("-sve2"); - Features.push_back("-sve2-bitperm"); - Features.push_back("-sve2-sha3"); - Features.push_back("-sve2-aes"); - Features.push_back("-sve2-sm4"); - } else if (Feature == "nosve2") { - Features.push_back("-sve2-bitperm"); - Features.push_back("-sve2-sha3"); - Features.push_back("-sve2-aes"); - Features.push_back("-sve2-sm4"); + continue; } - - // +sve implies +f32mm if the base architecture is >= v8.6A (except v9A) - // It isn't the case in general that sve implies both f64mm and f32mm - if ((ArchKind == llvm::AArch64::ArchKind::ARMV8_6A || - ArchKind == llvm::AArch64::ArchKind::ARMV8_7A || - ArchKind == llvm::AArch64::ArchKind::ARMV8_8A || - ArchKind == llvm::AArch64::ArchKind::ARMV9_1A || - ArchKind == llvm::AArch64::ArchKind::ARMV9_2A || - ArchKind == llvm::AArch64::ArchKind::ARMV9_3A) && - Feature == "sve") - Features.push_back("+f32mm"); + if (!Extensions.parseModifier(Feature)) + return false; } + return true; } // Check if the CPU name and feature modifiers in -mcpu are legal. If yes, // decode CPU and feature. static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, - std::vector<StringRef> &Features) { + llvm::AArch64::ExtensionSet &Extensions) { std::pair<StringRef, StringRef> Split = Mcpu.split("+"); CPU = Split.first; - llvm::AArch64::ArchKind ArchKind = llvm::AArch64::ArchKind::ARMV8A; if (CPU == "native") CPU = llvm::sys::getHostCPUName(); if (CPU == "generic") { - Features.push_back("+neon"); + Extensions.enable(llvm::AArch64::AEK_SIMD); } else { - ArchKind = llvm::AArch64::parseCPUArch(CPU); - if (!llvm::AArch64::getArchFeatures(ArchKind, Features)) + const std::optional<llvm::AArch64::CpuInfo> CpuInfo = + llvm::AArch64::parseCpu(CPU); + if (!CpuInfo) return false; - uint64_t Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind); - if (!llvm::AArch64::getExtensionFeatures(Extension, Features)) - return false; - } + Extensions.addCPUDefaults(*CpuInfo); + } - if (Split.second.size() && - !DecodeAArch64Features(D, Split.second, Features, ArchKind)) - return false; + if (Split.second.size() && + !DecodeAArch64Features(D, Split.second, Extensions)) + return false; - return true; + return true; } static bool getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, const ArgList &Args, - std::vector<StringRef> &Features) { + llvm::AArch64::ExtensionSet &Extensions) { std::string MarchLowerCase = March.lower(); std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+"); - llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first); - if (ArchKind == llvm::AArch64::ArchKind::INVALID || - !llvm::AArch64::getArchFeatures(ArchKind, Features)) + const llvm::AArch64::ArchInfo *ArchInfo = + llvm::AArch64::parseArch(Split.first); + if (Split.first == "native") + ArchInfo = llvm::AArch64::getArchForCpu(llvm::sys::getHostCPUName().str()); + if (!ArchInfo) return false; - // Enable SVE2 by default on Armv9-A. - // It can still be disabled if +nosve2 is present. - // We must do this early so that DecodeAArch64Features has the correct state - if ((ArchKind == llvm::AArch64::ArchKind::ARMV9A || - ArchKind == llvm::AArch64::ArchKind::ARMV9_1A || - ArchKind == llvm::AArch64::ArchKind::ARMV9_2A)) { - Features.push_back("+sve"); - Features.push_back("+sve2"); - } + Extensions.addArchDefaults(*ArchInfo); if ((Split.second.size() && - !DecodeAArch64Features(D, Split.second, Features, ArchKind))) + !DecodeAArch64Features(D, Split.second, Extensions))) return false; return true; @@ -175,10 +142,10 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, static bool getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, - std::vector<StringRef> &Features) { + llvm::AArch64::ExtensionSet &Extensions) { StringRef CPU; std::string McpuLowerCase = Mcpu.lower(); - if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features)) + if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Extensions)) return false; return true; @@ -189,17 +156,17 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, const ArgList &Args, std::vector<StringRef> &Features) { std::string MtuneLowerCase = Mtune.lower(); - // Check CPU name is valid - std::vector<StringRef> MtuneFeatures; + // Check CPU name is valid, but ignore any extensions on it. + llvm::AArch64::ExtensionSet Extensions; StringRef Tune; - if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures)) + if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, Extensions)) return false; // Handle CPU name is 'native'. if (MtuneLowerCase == "native") MtuneLowerCase = std::string(llvm::sys::getHostCPUName()); if (MtuneLowerCase == "cyclone" || - StringRef(MtuneLowerCase).startswith("apple")) { + StringRef(MtuneLowerCase).starts_with("apple")) { Features.push_back("+zcm"); Features.push_back("+zcz"); } @@ -211,7 +178,8 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, std::vector<StringRef> &Features) { StringRef CPU; - std::vector<StringRef> DecodedFeature; + // Check CPU name is valid, but ignore any extensions on it. + llvm::AArch64::ExtensionSet DecodedFeature; std::string McpuLowerCase = Mcpu.lower(); if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature)) return false; @@ -222,35 +190,35 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, void aarch64::getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, std::vector<StringRef> &Features, bool ForAS) { Arg *A; bool success = true; - // Enable NEON by default. - Features.push_back("+neon"); llvm::StringRef WaMArch; + llvm::AArch64::ExtensionSet Extensions; if (ForAS) for (const auto *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) for (StringRef Value : A->getValues()) - if (Value.startswith("-march=")) + if (Value.starts_with("-march=")) WaMArch = Value.substr(7); // Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or // "-Xassembler -march" is detected. Otherwise it may return false // and causes Clang to error out. if (!WaMArch.empty()) - success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Features); + success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Extensions); else if ((A = Args.getLastArg(options::OPT_march_EQ))) - success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features); + success = + getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Extensions); else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) - success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features); - else if (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple)) + success = + getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Extensions); + else if (isCPUDeterminedByTriple(Triple)) success = getAArch64ArchFeaturesFromMcpu( - D, getAArch64TargetCPU(Args, Triple, A), Args, Features); + D, getAArch64TargetCPU(Args, Triple, A), Args, Extensions); else // Default to 'A' profile if the architecture is not specified. - success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Features); + success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Extensions); if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) success = @@ -258,36 +226,48 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ))) success = getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features); - else if (success && - (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple))) + else if (success && isCPUDeterminedByTriple(Triple)) success = getAArch64MicroArchFeaturesFromMcpu( D, getAArch64TargetCPU(Args, Triple, A), Args, Features); if (!success) { - auto Diag = D.Diag(diag::err_drv_clang_unsupported); + auto Diag = D.Diag(diag::err_drv_unsupported_option_argument); // If "-Wa,-march=" is used, 'WaMArch' will contain the argument's value, // while 'A' is uninitialized. Only dereference 'A' in the other case. if (!WaMArch.empty()) - Diag << "-march=" + WaMArch.str(); + Diag << "-march=" << WaMArch; else - Diag << A->getAsString(Args); + Diag << A->getSpelling() << A->getValue(); } + // -mgeneral-regs-only disables all floating-point features. if (Args.getLastArg(options::OPT_mgeneral_regs_only)) { - Features.push_back("-fp-armv8"); - Features.push_back("-crypto"); - Features.push_back("-neon"); + Extensions.disable(llvm::AArch64::AEK_FP); + } + + // En/disable crc + if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { + if (A->getOption().matches(options::OPT_mcrc)) + Extensions.enable(llvm::AArch64::AEK_CRC); + else + Extensions.disable(llvm::AArch64::AEK_CRC); } + // At this point all hardware features are decided, so convert the extensions + // set to a feature list. + Extensions.toLLVMFeatureList(Features); + if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { StringRef Mtp = A->getValue(); - if (Mtp == "el3") + if (Mtp == "el3" || Mtp == "tpidr_el3") Features.push_back("+tpidr-el3"); - else if (Mtp == "el2") + else if (Mtp == "el2" || Mtp == "tpidr_el2") Features.push_back("+tpidr-el2"); - else if (Mtp == "el1") + else if (Mtp == "el1" || Mtp == "tpidr_el1") Features.push_back("+tpidr-el1"); - else if (Mtp != "el0") + else if (Mtp == "tpidrro_el0") + Features.push_back("+tpidrro-el0"); + else if (Mtp != "el0" && Mtp != "tpidr_el0") D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args); } @@ -323,8 +303,8 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, DisableComdat = true; continue; } - D.Diag(diag::err_invalid_sls_hardening) - << Scope << A->getAsString(Args); + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Scope; break; } } @@ -338,144 +318,12 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, } } - // En/disable crc - if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { - if (A->getOption().matches(options::OPT_mcrc)) - Features.push_back("+crc"); - else - Features.push_back("-crc"); - } - - // Handle (arch-dependent) fp16fml/fullfp16 relationship. - // FIXME: this fp16fml option handling will be reimplemented after the - // TargetParser rewrite. - const auto ItRNoFullFP16 = std::find(Features.rbegin(), Features.rend(), "-fullfp16"); - const auto ItRFP16FML = std::find(Features.rbegin(), Features.rend(), "+fp16fml"); - if (llvm::is_contained(Features, "+v8.4a")) { - const auto ItRFullFP16 = std::find(Features.rbegin(), Features.rend(), "+fullfp16"); - if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) { - // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml. - // Only append the +fp16fml if there is no -fp16fml after the +fullfp16. - if (std::find(Features.rbegin(), ItRFullFP16, "-fp16fml") == ItRFullFP16) - Features.push_back("+fp16fml"); - } - else - goto fp16_fml_fallthrough; - } else { -fp16_fml_fallthrough: - // In both of these cases, putting the 'other' feature on the end of the vector will - // result in the same effect as placing it immediately after the current feature. - if (ItRNoFullFP16 < ItRFP16FML) - Features.push_back("-fp16fml"); - else if (ItRNoFullFP16 > ItRFP16FML) - Features.push_back("+fullfp16"); - } - - // FIXME: this needs reimplementation too after the TargetParser rewrite - // - // Context sensitive meaning of Crypto: - // 1) For Arch >= ARMv8.4a: crypto = sm4 + sha3 + sha2 + aes - // 2) For Arch <= ARMv8.3a: crypto = sha2 + aes - const auto ItBegin = Features.begin(); - const auto ItEnd = Features.end(); - const auto ItRBegin = Features.rbegin(); - const auto ItREnd = Features.rend(); - const auto ItRCrypto = std::find(ItRBegin, ItREnd, "+crypto"); - const auto ItRNoCrypto = std::find(ItRBegin, ItREnd, "-crypto"); - const auto HasCrypto = ItRCrypto != ItREnd; - const auto HasNoCrypto = ItRNoCrypto != ItREnd; - const ptrdiff_t PosCrypto = ItRCrypto - ItRBegin; - const ptrdiff_t PosNoCrypto = ItRNoCrypto - ItRBegin; - - bool NoCrypto = false; - if (HasCrypto && HasNoCrypto) { - if (PosNoCrypto < PosCrypto) - NoCrypto = true; - } - - if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd || - std::find(ItBegin, ItEnd, "+v8.8a") != ItEnd || - std::find(ItBegin, ItEnd, "+v9a") != ItEnd || - std::find(ItBegin, ItEnd, "+v9.1a") != ItEnd || - std::find(ItBegin, ItEnd, "+v9.2a") != ItEnd || - std::find(ItBegin, ItEnd, "+v9.3a") != ItEnd) { - if (HasCrypto && !NoCrypto) { - // Check if we have NOT disabled an algorithm with something like: - // +crypto, -algorithm - // And if "-algorithm" does not occur, we enable that crypto algorithm. - const bool HasSM4 = (std::find(ItBegin, ItEnd, "-sm4") == ItEnd); - const bool HasSHA3 = (std::find(ItBegin, ItEnd, "-sha3") == ItEnd); - const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd); - const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd); - if (HasSM4) - Features.push_back("+sm4"); - if (HasSHA3) - Features.push_back("+sha3"); - if (HasSHA2) - Features.push_back("+sha2"); - if (HasAES) - Features.push_back("+aes"); - } else if (HasNoCrypto) { - // Check if we have NOT enabled a crypto algorithm with something like: - // -crypto, +algorithm - // And if "+algorithm" does not occur, we disable that crypto algorithm. - const bool HasSM4 = (std::find(ItBegin, ItEnd, "+sm4") != ItEnd); - const bool HasSHA3 = (std::find(ItBegin, ItEnd, "+sha3") != ItEnd); - const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd); - const bool HasAES = (std::find(ItBegin, ItEnd, "+aes") != ItEnd); - if (!HasSM4) - Features.push_back("-sm4"); - if (!HasSHA3) - Features.push_back("-sha3"); - if (!HasSHA2) - Features.push_back("-sha2"); - if (!HasAES) - Features.push_back("-aes"); - } - } else { - if (HasCrypto && !NoCrypto) { - const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd); - const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd); - if (HasSHA2) - Features.push_back("+sha2"); - if (HasAES) - Features.push_back("+aes"); - } else if (HasNoCrypto) { - const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd); - const bool HasAES = (std::find(ItBegin, ItEnd, "+aes") != ItEnd); - const bool HasV82a = (std::find(ItBegin, ItEnd, "+v8.2a") != ItEnd); - const bool HasV83a = (std::find(ItBegin, ItEnd, "+v8.3a") != ItEnd); - const bool HasV84a = (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd); - if (!HasSHA2) - Features.push_back("-sha2"); - if (!HasAES) - Features.push_back("-aes"); - if (HasV82a || HasV83a || HasV84a) { - Features.push_back("-sm4"); - Features.push_back("-sha3"); - } - } - } - - const char *Archs[] = {"+v8.6a", "+v8.7a", "+v8.8a", - "+v9.1a", "+v9.2a", "+v9.3a"}; - auto Pos = std::find_first_of(Features.begin(), Features.end(), - std::begin(Archs), std::end(Archs)); - if (Pos != std::end(Features)) - Pos = Features.insert(std::next(Pos), {"+i8mm", "+bf16"}); - if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { - if (A->getOption().matches(options::OPT_mno_unaligned_access)) { + if (A->getOption().matches(options::OPT_mno_unaligned_access)) Features.push_back("+strict-align"); - if (!ForAS) - CmdArgs.push_back("-Wunaligned-access"); - } - } else if (Triple.isOSOpenBSD()) { + } else if (Triple.isOSOpenBSD()) Features.push_back("+strict-align"); - if (!ForAS) - CmdArgs.push_back("-Wunaligned-access"); - } if (Args.hasArg(options::OPT_ffixed_x1)) Features.push_back("+reserve-x1"); @@ -588,9 +436,13 @@ fp16_fml_fallthrough: Features.push_back("+fix-cortex-a53-835769"); else Features.push_back("-fix-cortex-a53-835769"); - } else if (Triple.isAndroid()) { + } else if (Triple.isAndroid() || Triple.isOHOSFamily()) { // Enabled A53 errata (835769) workaround by default on android Features.push_back("+fix-cortex-a53-835769"); + } else if (Triple.isOSFuchsia()) { + std::string CPU = getCPUName(D, Args, Triple); + if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") + Features.push_back("+fix-cortex-a53-835769"); } if (Args.getLastArg(options::OPT_mno_bti_at_return_twice)) diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.h index 0cdc2ec725e0..d47c402d4a42 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.h @@ -22,7 +22,6 @@ namespace aarch64 { void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, std::vector<llvm::StringRef> &Features, bool ForAS); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 16af9f6d7129..e6ee2f88a84e 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -12,9 +12,8 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/ARMTargetParser.h" -#include "llvm/Support/TargetParser.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/ARMTargetParser.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -33,6 +32,20 @@ bool arm::isARMMProfile(const llvm::Triple &Triple) { return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M; } +// 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. +bool arm::isARMBigEndian(const llvm::Triple &Triple, const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, + options::OPT_mbig_endian)) { + return !A->getOption().matches(options::OPT_mlittle_endian); + } + + return Triple.getArch() == llvm::Triple::armeb || + Triple.getArch() == llvm::Triple::thumbeb; +} + // True if A-profile. bool arm::isARMAProfile(const llvm::Triple &Triple) { llvm::StringRef Arch = Triple.getArchName(); @@ -54,9 +67,9 @@ void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, // Use getValues because -Wa can have multiple arguments // e.g. -Wa,-mcpu=foo,-mcpu=bar for (StringRef Value : A->getValues()) { - if (Value.startswith("-mcpu=")) + if (Value.starts_with("-mcpu=")) CPU = Value.substr(6); - if (Value.startswith("-march=")) + if (Value.starts_with("-march=")) Arch = Value.substr(7); } } @@ -73,25 +86,25 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A, } // Handle -mfpu=. -static unsigned getARMFPUFeatures(const Driver &D, const Arg *A, - const ArgList &Args, StringRef FPU, - std::vector<StringRef> &Features) { - unsigned FPUID = llvm::ARM::parseFPU(FPU); - if (!llvm::ARM::getFPUFeatures(FPUID, Features)) +static llvm::ARM::FPUKind getARMFPUFeatures(const Driver &D, const Arg *A, + const ArgList &Args, StringRef FPU, + std::vector<StringRef> &Features) { + llvm::ARM::FPUKind FPUKind = llvm::ARM::parseFPU(FPU); + if (!llvm::ARM::getFPUFeatures(FPUKind, Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); - return FPUID; + return FPUKind; } // Decode ARM features from string like +[no]featureA+[no]featureB+... static bool DecodeARMFeatures(const Driver &D, StringRef text, StringRef CPU, llvm::ARM::ArchKind ArchKind, std::vector<StringRef> &Features, - unsigned &ArgFPUID) { + llvm::ARM::FPUKind &ArgFPUKind) { SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); for (StringRef Feature : Split) { - if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features, ArgFPUID)) + if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features, ArgFPUKind)) return false; } return true; @@ -113,31 +126,52 @@ static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef ArchName, llvm::StringRef CPUName, std::vector<StringRef> &Features, - const llvm::Triple &Triple, unsigned &ArgFPUID) { + const llvm::Triple &Triple, + llvm::ARM::FPUKind &ArgFPUKind) { std::pair<StringRef, StringRef> Split = ArchName.split("+"); std::string MArch = arm::getARMArch(ArchName, Triple); llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch); if (ArchKind == llvm::ARM::ArchKind::INVALID || - (Split.second.size() && !DecodeARMFeatures(D, Split.second, CPUName, - ArchKind, Features, ArgFPUID))) - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + (Split.second.size() && + !DecodeARMFeatures(D, Split.second, CPUName, ArchKind, Features, + ArgFPUKind))) + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << A->getValue(); } // Check -mcpu=. Needs ArchName to handle -mcpu=generic. static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef CPUName, llvm::StringRef ArchName, std::vector<StringRef> &Features, - const llvm::Triple &Triple, unsigned &ArgFPUID) { + const llvm::Triple &Triple, + llvm::ARM::FPUKind &ArgFPUKind) { std::pair<StringRef, StringRef> Split = CPUName.split("+"); std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); llvm::ARM::ArchKind ArchKind = arm::getLLVMArchKindForARM(CPU, ArchName, Triple); if (ArchKind == llvm::ARM::ArchKind::INVALID || - (Split.second.size() && - !DecodeARMFeatures(D, Split.second, CPU, ArchKind, Features, ArgFPUID))) - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + (Split.second.size() && !DecodeARMFeatures(D, Split.second, CPU, ArchKind, + Features, ArgFPUKind))) + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << A->getValue(); +} + +// If -mfloat-abi=hard or -mhard-float are specified explicitly then check that +// floating point registers are available on the target CPU. +static void checkARMFloatABI(const Driver &D, const ArgList &Args, + bool HasFPRegs) { + if (HasFPRegs) + return; + const Arg *A = + Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ); + if (A && (A->getOption().matches(options::OPT_mhard_float) || + (A->getOption().matches(options::OPT_mfloat_abi_EQ) && + A->getValue() == StringRef("hard")))) + D.Diag(clang::diag::warn_drv_no_floating_point_registers) + << A->getAsString(Args); } bool arm::useAAPCSForMachO(const llvm::Triple &T) { @@ -164,11 +198,16 @@ arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { arm::ReadTPMode ThreadPointer = llvm::StringSwitch<arm::ReadTPMode>(A->getValue()) - .Case("cp15", ReadTPMode::Cp15) + .Case("cp15", ReadTPMode::TPIDRURO) + .Case("tpidrurw", ReadTPMode::TPIDRURW) + .Case("tpidruro", ReadTPMode::TPIDRURO) + .Case("tpidrprw", ReadTPMode::TPIDRPRW) .Case("soft", ReadTPMode::Soft) .Default(ReadTPMode::Invalid); - if (ThreadPointer == ReadTPMode::Cp15 && !isHardTPSupported(Triple) && - !ForAS) { + if ((ThreadPointer == ReadTPMode::TPIDRURW || + ThreadPointer == ReadTPMode::TPIDRURO || + ThreadPointer == ReadTPMode::TPIDRPRW) && + !isHardTPSupported(Triple) && !ForAS) { D.Diag(diag::err_target_unsupported_tp_hard) << Triple.getArchName(); return ReadTPMode::Invalid; } @@ -246,9 +285,9 @@ void arm::setArchNameInTriple(const Driver &D, const ArgList &Args, // There is no assembler equivalent of -mno-thumb, -marm, or -mno-arm. if (Value == "-mthumb") IsThumb = true; - else if (Value.startswith("-march=")) + else if (Value.starts_with("-march=")) WaMArch = Value.substr(7); - else if (Value.startswith("-mcpu=")) + else if (Value.starts_with("-mcpu=")) WaMCPU = Value.substr(6); } } @@ -274,6 +313,11 @@ void arm::setArchNameInTriple(const Driver &D, const ArgList &Args, void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args, llvm::Triple &Triple) { + if (Triple.isOSLiteOS()) { + Triple.setEnvironment(llvm::Triple::OpenHOS); + return; + } + bool isHardFloat = (arm::getARMFloatABI(D, Triple, Args) == arm::FloatABI::Hard); @@ -293,6 +337,8 @@ void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args, Triple.setEnvironment(isHardFloat ? llvm::Triple::MuslEABIHF : llvm::Triple::MuslEABI); break; + case llvm::Triple::OpenHOS: + break; default: { arm::FloatABI DefaultABI = arm::getDefaultFloatABI(Triple); if (DefaultABI != arm::FloatABI::Invalid && @@ -320,6 +366,8 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { case llvm::Triple::MacOSX: case llvm::Triple::IOS: case llvm::Triple::TvOS: + case llvm::Triple::DriverKit: + case llvm::Triple::XROS: // Darwin defaults to "softfp" for v6 and v7. if (Triple.isWatchABI()) return FloatABI::Hard; @@ -357,10 +405,13 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { } break; + case llvm::Triple::Haiku: case llvm::Triple::OpenBSD: return FloatABI::SoftFP; default: + if (Triple.isOHOSFamily()) + return FloatABI::Soft; switch (Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::MuslEABIHF: @@ -433,14 +484,15 @@ static bool hasIntegerMVE(const std::vector<StringRef> &F) { (NoMVE == F.rend() || std::distance(MVE, NoMVE) > 0); } -void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args, ArgStringList &CmdArgs, - std::vector<StringRef> &Features, bool ForAS) { +llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, + std::vector<StringRef> &Features, + bool ForAS, bool ForMultilib) { bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args); - llvm::Optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv, - WaArch; + std::optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv, WaArch; // This vector will accumulate features from the architecture // extension suffixes on -mcpu and -march (e.g. the 'bar' in @@ -477,28 +529,38 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, // We use getValues here because you can have many options per -Wa // We will keep the last one we find for each of these for (StringRef Value : A->getValues()) { - if (Value.startswith("-mfpu=")) { + if (Value.starts_with("-mfpu=")) { WaFPU = std::make_pair(A, Value.substr(6)); - } else if (Value.startswith("-mcpu=")) { + } else if (Value.starts_with("-mcpu=")) { WaCPU = std::make_pair(A, Value.substr(6)); - } else if (Value.startswith("-mhwdiv=")) { + } else if (Value.starts_with("-mhwdiv=")) { WaHDiv = std::make_pair(A, Value.substr(8)); - } else if (Value.startswith("-march=")) { + } else if (Value.starts_with("-march=")) { WaArch = std::make_pair(A, Value.substr(7)); } } } + + // The integrated assembler doesn't implement e_flags setting behavior for + // -meabi=gnu (gcc -mabi={apcs-gnu,atpcs} passes -meabi=gnu to gas). For + // compatibility we accept but warn. + if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) + A->ignoreTargetSpecific(); } - if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::Cp15) - Features.push_back("+read-tp-hard"); + if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRURW) + Features.push_back("+read-tp-tpidrurw"); + if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRURO) + Features.push_back("+read-tp-tpidruro"); + if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRPRW) + Features.push_back("+read-tp-tpidrprw"); const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); StringRef ArchName; StringRef CPUName; - unsigned ArchArgFPUID = llvm::ARM::FK_INVALID; - unsigned CPUArgFPUID = llvm::ARM::FK_INVALID; + llvm::ARM::FPUKind ArchArgFPUKind = llvm::ARM::FK_INVALID; + llvm::ARM::FPUKind CPUArgFPUKind = llvm::ARM::FK_INVALID; // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. if (WaCPU) { @@ -518,13 +580,13 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, ArchName = WaArch->second; // This will set any features after the base architecture. checkARMArchName(D, WaArch->first, Args, ArchName, CPUName, - ExtensionFeatures, Triple, ArchArgFPUID); + ExtensionFeatures, Triple, ArchArgFPUKind); // The base architecture was handled in ToolChain::ComputeLLVMTriple because // triple is read only by this point. } else if (ArchArg) { ArchName = ArchArg->getValue(); checkARMArchName(D, ArchArg, Args, ArchName, CPUName, ExtensionFeatures, - Triple, ArchArgFPUID); + Triple, ArchArgFPUKind); } // Add CPU features for generic CPUs @@ -544,9 +606,14 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (CPUArg) checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures, - Triple, CPUArgFPUID); + Triple, CPUArgFPUKind); + + // TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a + // longstanding behavior. + (void)Args.getLastArg(options::OPT_mtune_EQ); + // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. - unsigned FPUID = llvm::ARM::FK_INVALID; + llvm::ARM::FPUKind FPUKind = llvm::ARM::FK_INVALID; const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); if (WaFPU) { if (FPUArg) @@ -554,20 +621,25 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, << FPUArg->getAsString(Args); (void)getARMFPUFeatures(D, WaFPU->first, Args, WaFPU->second, Features); } else if (FPUArg) { - FPUID = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); + FPUKind = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); } else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) { const char *AndroidFPU = "neon"; - FPUID = llvm::ARM::parseFPU(AndroidFPU); - if (!llvm::ARM::getFPUFeatures(FPUID, Features)) + FPUKind = llvm::ARM::parseFPU(AndroidFPU); + if (!llvm::ARM::getFPUFeatures(FPUKind, Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << std::string("-mfpu=") + AndroidFPU; + } else if (ArchArgFPUKind != llvm::ARM::FK_INVALID || + CPUArgFPUKind != llvm::ARM::FK_INVALID) { + FPUKind = + CPUArgFPUKind != llvm::ARM::FK_INVALID ? CPUArgFPUKind : ArchArgFPUKind; + (void)llvm::ARM::getFPUFeatures(FPUKind, Features); } else { if (!ForAS) { std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); llvm::ARM::ArchKind ArchKind = arm::getLLVMArchKindForARM(CPU, ArchName, Triple); - FPUID = llvm::ARM::getDefaultFPU(CPU, ArchKind); - (void)llvm::ARM::getFPUFeatures(FPUID, Features); + FPUKind = llvm::ARM::getDefaultFPU(CPU, ArchKind); + (void)llvm::ARM::getFPUFeatures(FPUKind, Features); } } @@ -618,25 +690,30 @@ fp16_fml_fallthrough: // -march/-mcpu effectively disables the FPU (GCC ignores the -mfpu options in // this case). Note that the ABI can also be set implicitly by the target // selected. + bool HasFPRegs = true; if (ABI == arm::FloatABI::Soft) { llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); // Disable all features relating to hardware FP, not already disabled by the // above call. - Features.insert(Features.end(), {"-dotprod", "-fp16fml", "-bf16", "-mve", - "-mve.fp", "-fpregs"}); - } else if (FPUID == llvm::ARM::FK_NONE || - ArchArgFPUID == llvm::ARM::FK_NONE || - CPUArgFPUID == llvm::ARM::FK_NONE) { + Features.insert(Features.end(), + {"-dotprod", "-fp16fml", "-bf16", "-mve", "-mve.fp"}); + HasFPRegs = false; + FPUKind = llvm::ARM::FK_NONE; + } else if (FPUKind == llvm::ARM::FK_NONE || + ArchArgFPUKind == llvm::ARM::FK_NONE || + CPUArgFPUKind == llvm::ARM::FK_NONE) { // -mfpu=none, -march=armvX+nofp or -mcpu=X+nofp is *very* similar to // -mfloat-abi=soft, only that it should not disable MVE-I. They disable the // FPU, but not the FPU registers, thus MVE-I, which depends only on the // latter, is still supported. Features.insert(Features.end(), {"-dotprod", "-fp16fml", "-bf16", "-mve.fp"}); - if (!hasIntegerMVE(Features)) - Features.emplace_back("-fpregs"); + HasFPRegs = hasIntegerMVE(Features); + FPUKind = llvm::ARM::FK_NONE; } + if (!HasFPRegs) + Features.emplace_back("-fpregs"); // En/disable crc code generation. if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { @@ -717,6 +794,15 @@ fp16_fml_fallthrough: } } + // Propagate frame-chain model selection + if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) { + StringRef FrameChainOption = A->getValue(); + if (FrameChainOption.starts_with("aapcs")) + Features.push_back("+aapcs-frame-chain"); + if (FrameChainOption == "aapcs+leaf") + Features.push_back("+aapcs-frame-chain-leaf"); + } + // CMSE: Check for target 8M (for -mcmse to be applicable) is performed later. if (Args.getLastArg(options::OPT_mcmse)) Features.push_back("+8msecext"); @@ -733,6 +819,16 @@ fp16_fml_fallthrough: Features.push_back("-fix-cmse-cve-2021-35465"); } + // This also handles the -m(no-)fix-cortex-a72-1655431 arguments via aliases. + if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a57_aes_1742098, + options::OPT_mno_fix_cortex_a57_aes_1742098)) { + if (A->getOption().matches(options::OPT_mfix_cortex_a57_aes_1742098)) { + Features.push_back("+fix-cortex-a57-aes-1742098"); + } else { + Features.push_back("-fix-cortex-a57-aes-1742098"); + } + } + // Look for the last occurrence of -mlong-calls or -mno-long-calls. If // neither options are specified, see if we are compiling for kernel/kext and // decide whether to pass "+long-calls" based on the OS and its version. @@ -741,29 +837,32 @@ fp16_fml_fallthrough: if (A->getOption().matches(options::OPT_mlong_calls)) Features.push_back("+long-calls"); } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) && - !Triple.isWatchOS()) { - Features.push_back("+long-calls"); + !Triple.isWatchOS() && !Triple.isXROS()) { + Features.push_back("+long-calls"); } // Generate execute-only output (no data access to code sections). // This only makes sense for the compiler, not for the assembler. - if (!ForAS) { + // It's not needed for multilib selection and may hide an unused + // argument diagnostic if the code is always run. + if (!ForAS && !ForMultilib) { // Supported only on ARMv6T2 and ARMv7 and above. - // Cannot be combined with -mno-movt or -mlong-calls + // Cannot be combined with -mno-movt. if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { if (A->getOption().matches(options::OPT_mexecute_only)) { if (getARMSubArchVersionNumber(Triple) < 7 && - llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2) + llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2 && + llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6M) D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); - else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) - D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); - // Long calls create constant pool entries and have not yet been fixed up - // to play nicely with execute-only. Hence, they cannot be used in - // execute-only code for now - else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) { - if (B->getOption().matches(options::OPT_mlong_calls)) - D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); - } + else if (llvm::ARM::parseArch(Triple.getArchName()) == llvm::ARM::ArchKind::ARMV6M) { + if (Arg *PIArg = Args.getLastArg(options::OPT_fropi, options::OPT_frwpi, + options::OPT_fpic, options::OPT_fpie, + options::OPT_fPIC, options::OPT_fPIE)) + D.Diag(diag::err_opt_not_valid_with_opt_on_target) + << A->getAsString(Args) << PIArg->getAsString(Args) << Triple.getArchName(); + } else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) + D.Diag(diag::err_opt_not_valid_with_opt) + << A->getAsString(Args) << B->getAsString(Args); Features.push_back("+execute-only"); } } @@ -772,8 +871,6 @@ fp16_fml_fallthrough: // Kernel code has more strict alignment requirements. if (KernelOrKext) { Features.push_back("+strict-align"); - if (!ForAS) - CmdArgs.push_back("-Wunaligned-access"); } else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { if (A->getOption().matches(options::OPT_munaligned_access)) { @@ -784,11 +881,8 @@ fp16_fml_fallthrough: // access either. else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline) D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base"; - } else { + } else Features.push_back("+strict-align"); - if (!ForAS) - CmdArgs.push_back("-Wunaligned-access"); - } } else { // Assume pre-ARMv6 doesn't support unaligned accesses. // @@ -807,23 +901,14 @@ fp16_fml_fallthrough: int VersionNum = getARMSubArchVersionNumber(Triple); if (Triple.isOSDarwin() || Triple.isOSNetBSD()) { if (VersionNum < 6 || - Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) { + Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) Features.push_back("+strict-align"); - if (!ForAS) - CmdArgs.push_back("-Wunaligned-access"); - } } else if (Triple.isOSLinux() || Triple.isOSNaCl() || Triple.isOSWindows()) { - if (VersionNum < 7) { + if (VersionNum < 7) Features.push_back("+strict-align"); - if (!ForAS) - CmdArgs.push_back("-Wunaligned-access"); - } - } else { + } else Features.push_back("+strict-align"); - if (!ForAS) - CmdArgs.push_back("-Wunaligned-access"); - } } // llvm does not support reserving registers in general. There is support @@ -871,8 +956,8 @@ fp16_fml_fallthrough: DisableComdat = true; continue; } - D.Diag(diag::err_invalid_sls_hardening) - << Scope << A->getAsString(Args); + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Scope; break; } } @@ -893,6 +978,10 @@ fp16_fml_fallthrough: if (Args.getLastArg(options::OPT_mno_bti_at_return_twice)) Features.push_back("+no-bti-at-return-twice"); + + checkARMFloatABI(D, Args, HasFPRegs); + + return FPUKind; } std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { @@ -931,7 +1020,7 @@ StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { // We need to return an empty string here on invalid MArch values as the // various places that call this function can't cope with a null result. - return Triple.getARMCPUForArch(MArch); + return llvm::ARM::getARMCPUForArch(Triple, MArch); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. @@ -964,7 +1053,8 @@ llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch, if (ArchKind == llvm::ARM::ArchKind::INVALID) // In case of generic Arch, i.e. "arm", // extract arch from default cpu of the Triple - ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch)); + ArchKind = + llvm::ARM::parseCPUArch(llvm::ARM::getARMCPUForArch(Triple, ARMArch)); } else { // FIXME: horrible hack to get around the fact that Cortex-A7 is only an // armv7k triple if it's actually been specified via "-arch armv7k". diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h index 862a2f2796be..fa62ac89e3a1 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -11,10 +11,10 @@ #include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" +#include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" -#include "llvm/Support/ARMTargetParser.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/TargetParser/ARMTargetParser.h" +#include "llvm/TargetParser/Triple.h" #include <string> #include <vector> @@ -38,7 +38,9 @@ void appendBE8LinkFlag(const llvm::opt::ArgList &Args, enum class ReadTPMode { Invalid, Soft, - Cp15, + TPIDRURW, + TPIDRURO, + TPIDRPRW, }; enum class FloatABI { @@ -64,13 +66,15 @@ bool useAAPCSForMachO(const llvm::Triple &T); void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args, llvm::StringRef &Arch, llvm::StringRef &CPU, bool FromAs = false); -void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - std::vector<llvm::StringRef> &Features, bool ForAS); +llvm::ARM::FPUKind getARMTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features, + bool ForAS, bool ForMultilib = false); int getARMSubArchVersionNumber(const llvm::Triple &Triple); bool isARMMProfile(const llvm::Triple &Triple); bool isARMAProfile(const llvm::Triple &Triple); +bool isARMBigEndian(const llvm::Triple &Triple, const llvm::opt::ArgList &Args); } // end namespace arm } // end namespace tools diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp new file mode 100644 index 000000000000..e94ea12f46dc --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp @@ -0,0 +1,169 @@ +//===--- CSKY.cpp - CSKY Helpers for Tools --------------------*- 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 "CSKY.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/CSKYTargetParser.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/TargetParser.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +std::optional<llvm::StringRef> +csky::getCSKYArchName(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseArch(A->getValue()); + + if (ArchKind == llvm::CSKY::ArchKind::INVALID) { + D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args); + return std::nullopt; + } + return std::optional<llvm::StringRef>(A->getValue()); + } + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { + llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseCPUArch(A->getValue()); + if (ArchKind == llvm::CSKY::ArchKind::INVALID) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return std::nullopt; + } + return std::optional<llvm::StringRef>(llvm::CSKY::getArchName(ArchKind)); + } + + return std::optional<llvm::StringRef>("ck810"); +} + +csky::FloatABI csky::getCSKYFloatABI(const Driver &D, const ArgList &Args) { + csky::FloatABI ABI = FloatABI::Soft; + if (Arg *A = + Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ)) { + if (A->getOption().matches(options::OPT_msoft_float)) { + ABI = FloatABI::Soft; + } else if (A->getOption().matches(options::OPT_mhard_float)) { + ABI = FloatABI::Hard; + } else { + ABI = llvm::StringSwitch<csky::FloatABI>(A->getValue()) + .Case("soft", FloatABI::Soft) + .Case("softfp", FloatABI::SoftFP) + .Case("hard", FloatABI::Hard) + .Default(FloatABI::Invalid); + if (ABI == FloatABI::Invalid) { + D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); + ABI = FloatABI::Soft; + } + } + } + + return ABI; +} + +// Handle -mfpu=. +static llvm::CSKY::CSKYFPUKind +getCSKYFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args, + StringRef FPU, std::vector<StringRef> &Features) { + + llvm::CSKY::CSKYFPUKind FPUID = + llvm::StringSwitch<llvm::CSKY::CSKYFPUKind>(FPU) + .Case("auto", llvm::CSKY::FK_AUTO) + .Case("fpv2", llvm::CSKY::FK_FPV2) + .Case("fpv2_divd", llvm::CSKY::FK_FPV2_DIVD) + .Case("fpv2_sf", llvm::CSKY::FK_FPV2_SF) + .Case("fpv3", llvm::CSKY::FK_FPV3) + .Case("fpv3_hf", llvm::CSKY::FK_FPV3_HF) + .Case("fpv3_hsf", llvm::CSKY::FK_FPV3_HSF) + .Case("fpv3_sdf", llvm::CSKY::FK_FPV3_SDF) + .Default(llvm::CSKY::FK_INVALID); + if (FPUID == llvm::CSKY::FK_INVALID) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return llvm::CSKY::FK_INVALID; + } + + auto RemoveTargetFPUFeature = + [&Features](ArrayRef<const char *> FPUFeatures) { + for (auto FPUFeature : FPUFeatures) { + auto it = llvm::find(Features, FPUFeature); + if (it != Features.end()) + Features.erase(it); + } + }; + + RemoveTargetFPUFeature({"+fpuv2_sf", "+fpuv2_df", "+fdivdu", "+fpuv3_hi", + "+fpuv3_hf", "+fpuv3_sf", "+fpuv3_df"}); + + if (!llvm::CSKY::getFPUFeatures(FPUID, Features)) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return llvm::CSKY::FK_INVALID; + } + + return FPUID; +} + +void csky::getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, ArgStringList &CmdArgs, + std::vector<llvm::StringRef> &Features) { + llvm::StringRef archName; + llvm::StringRef cpuName; + llvm::CSKY::ArchKind ArchKind = llvm::CSKY::ArchKind::INVALID; + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + ArchKind = llvm::CSKY::parseArch(A->getValue()); + if (ArchKind == llvm::CSKY::ArchKind::INVALID) { + D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args); + return; + } + archName = A->getValue(); + } + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { + llvm::CSKY::ArchKind Kind = llvm::CSKY::parseCPUArch(A->getValue()); + if (Kind == llvm::CSKY::ArchKind::INVALID) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return; + } + if (!archName.empty() && Kind != ArchKind) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return; + } + cpuName = A->getValue(); + if (archName.empty()) + archName = llvm::CSKY::getArchName(Kind); + } + + if (archName.empty() && cpuName.empty()) { + archName = "ck810"; + cpuName = "ck810"; + } else if (!archName.empty() && cpuName.empty()) { + cpuName = archName; + } + + csky::FloatABI FloatABI = csky::getCSKYFloatABI(D, Args); + + if (FloatABI == csky::FloatABI::Hard) { + Features.push_back("+hard-float-abi"); + Features.push_back("+hard-float"); + } else if (FloatABI == csky::FloatABI::SoftFP) { + Features.push_back("+hard-float"); + } + + uint64_t Extension = llvm::CSKY::getDefaultExtensions(cpuName); + llvm::CSKY::getExtensionFeatures(Extension, Features); + + if (const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ)) + getCSKYFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h new file mode 100644 index 000000000000..f3730d2cf4a1 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h @@ -0,0 +1,47 @@ +//===--- CSKY.h - CSKY-specific Tool Helpers ------------------*- 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_ARCH_CSKY_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CSKY_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace csky { + +enum class FloatABI { + Invalid, + Soft, + SoftFP, + Hard, +}; + +FloatABI getCSKYFloatABI(const Driver &D, const llvm::opt::ArgList &Args); + +void getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + std::vector<llvm::StringRef> &Features); + +std::optional<llvm::StringRef> getCSKYArchName(const Driver &D, + const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); + +} // end namespace csky +} // namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CSKY_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp new file mode 100644 index 000000000000..31153a67ad28 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp @@ -0,0 +1,232 @@ +//===--- LoongArch.cpp - LoongArch Helpers for Tools ------------*- 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 "LoongArch.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Basic/DiagnosticDriver.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/LoongArchTargetParser.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + assert((Triple.getArch() == llvm::Triple::loongarch32 || + Triple.getArch() == llvm::Triple::loongarch64) && + "Unexpected triple"); + bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32; + + // Record -mabi value for later use. + const Arg *MABIArg = Args.getLastArg(options::OPT_mabi_EQ); + StringRef MABIValue; + if (MABIArg) { + MABIValue = MABIArg->getValue(); + } + + // Parse -mfpu value for later use. + const Arg *MFPUArg = Args.getLastArg(options::OPT_mfpu_EQ); + int FPU = -1; + if (MFPUArg) { + StringRef V = MFPUArg->getValue(); + if (V == "64") + FPU = 64; + else if (V == "32") + FPU = 32; + else if (V == "0" || V == "none") + FPU = 0; + else + D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << V; + } + + // Check -m*-float firstly since they have highest priority. + if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float, + options::OPT_msingle_float, + options::OPT_msoft_float)) { + StringRef ImpliedABI; + int ImpliedFPU = -1; + if (A->getOption().matches(options::OPT_mdouble_float)) { + ImpliedABI = IsLA32 ? "ilp32d" : "lp64d"; + ImpliedFPU = 64; + } + if (A->getOption().matches(options::OPT_msingle_float)) { + ImpliedABI = IsLA32 ? "ilp32f" : "lp64f"; + ImpliedFPU = 32; + } + if (A->getOption().matches(options::OPT_msoft_float)) { + ImpliedABI = IsLA32 ? "ilp32s" : "lp64s"; + ImpliedFPU = 0; + } + + // Check `-mabi=` and `-mfpu=` settings and report if they conflict with + // the higher-priority settings implied by -m*-float. + // + // ImpliedABI and ImpliedFPU are guaranteed to have valid values because + // one of the match arms must match if execution can arrive here at all. + if (!MABIValue.empty() && ImpliedABI != MABIValue) + D.Diag(diag::warn_drv_loongarch_conflicting_implied_val) + << MABIArg->getAsString(Args) << A->getAsString(Args) << ImpliedABI; + + if (FPU != -1 && ImpliedFPU != FPU) + D.Diag(diag::warn_drv_loongarch_conflicting_implied_val) + << MFPUArg->getAsString(Args) << A->getAsString(Args) << ImpliedFPU; + + return ImpliedABI; + } + + // If `-mabi=` is specified, use it. + if (!MABIValue.empty()) + return MABIValue; + + // Select abi based on -mfpu=xx. + switch (FPU) { + case 64: + return IsLA32 ? "ilp32d" : "lp64d"; + case 32: + return IsLA32 ? "ilp32f" : "lp64f"; + case 0: + return IsLA32 ? "ilp32s" : "lp64s"; + } + + // Choose a default based on the triple. + // Honor the explicit ABI modifier suffix in triple's environment part if + // present, falling back to {ILP32,LP64}D otherwise. + switch (Triple.getEnvironment()) { + case llvm::Triple::GNUSF: + return IsLA32 ? "ilp32s" : "lp64s"; + case llvm::Triple::GNUF32: + return IsLA32 ? "ilp32f" : "lp64f"; + case llvm::Triple::GNUF64: + // This was originally permitted (and indeed the canonical way) to + // represent the {ILP32,LP64}D ABIs, but in Feb 2023 Loongson decided to + // drop the explicit suffix in favor of unmarked `-gnu` for the + // "general-purpose" ABIs, among other non-technical reasons. + // + // The spec change did not mention whether existing usages of "gnuf64" + // shall remain valid or not, so we are going to continue recognizing it + // for some time, until it is clear that everyone else has migrated away + // from it. + [[fallthrough]]; + case llvm::Triple::GNU: + default: + return IsLA32 ? "ilp32d" : "lp64d"; + } +} + +void loongarch::getLoongArchTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, + std::vector<StringRef> &Features) { + std::string ArchName; + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + ArchName = A->getValue(); + ArchName = postProcessTargetCPUString(ArchName, Triple); + llvm::LoongArch::getArchFeatures(ArchName, Features); + + // Select floating-point features determined by -mdouble-float, + // -msingle-float, -msoft-float and -mfpu. + // Note: -m*-float wins any other options. + if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float, + options::OPT_msingle_float, + options::OPT_msoft_float)) { + if (A->getOption().matches(options::OPT_mdouble_float)) { + Features.push_back("+f"); + Features.push_back("+d"); + } else if (A->getOption().matches(options::OPT_msingle_float)) { + Features.push_back("+f"); + Features.push_back("-d"); + } else /*Soft-float*/ { + Features.push_back("-f"); + Features.push_back("-d"); + } + } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) { + StringRef FPU = A->getValue(); + if (FPU == "64") { + Features.push_back("+f"); + Features.push_back("+d"); + } else if (FPU == "32") { + Features.push_back("+f"); + Features.push_back("-d"); + } else if (FPU == "0" || FPU == "none") { + Features.push_back("-f"); + Features.push_back("-d"); + } else { + D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU; + } + } + + // Select the `ual` feature determined by -m[no-]unaligned-access + // or the alias -m[no-]strict-align. + AddTargetFeature(Args, Features, options::OPT_munaligned_access, + options::OPT_mno_unaligned_access, "ual"); + + // Accept but warn about these TargetSpecific options. + if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) + A->ignoreTargetSpecific(); + if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ)) + A->ignoreTargetSpecific(); + + // Select lsx feature determined by -m[no-]lsx. + if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) { + // LSX depends on 64-bit FPU. + // -m*-float and -mfpu=none/0/32 conflict with -mlsx. + if (A->getOption().matches(options::OPT_mlsx)) { + if (llvm::find(Features, "-d") != Features.end()) + D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lsx); + else /*-mlsx*/ + Features.push_back("+lsx"); + } else /*-mno-lsx*/ { + Features.push_back("-lsx"); + } + } + + // Select lasx feature determined by -m[no-]lasx. + if (const Arg *A = + Args.getLastArg(options::OPT_mlasx, options::OPT_mno_lasx)) { + // LASX depends on 64-bit FPU and LSX. + // -mno-lsx conflicts with -mlasx. + if (A->getOption().matches(options::OPT_mlasx)) { + if (llvm::find(Features, "-d") != Features.end()) + D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lasx); + else if (llvm::find(Features, "-lsx") != Features.end()) + D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination); + else { /*-mlasx*/ + Features.push_back("+lsx"); + Features.push_back("+lasx"); + } + } else /*-mno-lasx*/ + Features.push_back("-lasx"); + } +} + +std::string loongarch::postProcessTargetCPUString(const std::string &CPU, + const llvm::Triple &Triple) { + std::string CPUString = CPU; + if (CPUString == "native") { + CPUString = llvm::sys::getHostCPUName(); + if (CPUString == "generic") + CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64()); + } + if (CPUString.empty()) + CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64()); + return CPUString; +} + +std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + std::string CPU; + // If we have -march, use that. + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + CPU = A->getValue(); + return postProcessTargetCPUString(CPU, Triple); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h new file mode 100644 index 000000000000..d8280cd836f8 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h @@ -0,0 +1,37 @@ +//===--- LoongArch.h - LoongArch-specific Tool Helpers ----------*- 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_ARCH_LOONGARCH_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" + +namespace clang { +namespace driver { +namespace tools { +namespace loongarch { +void getLoongArchTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features); + +StringRef getLoongArchABI(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); + +std::string postProcessTargetCPUString(const std::string &CPU, + const llvm::Triple &Triple); + +std::string getLoongArchTargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); +} // end namespace loongarch +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp index 119e24cedbab..963f7a187d63 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp @@ -14,8 +14,8 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Host.h" #include "llvm/Support/Regex.h" +#include "llvm/TargetParser/Host.h" #include <sstream> using namespace clang::driver; @@ -65,13 +65,35 @@ std::string m68k::getM68kTargetCPU(const ArgList &Args) { return ""; } +static void addFloatABIFeatures(const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features) { + Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_m68881); + // Opt out FPU even for newer CPUs. + if (A && A->getOption().matches(options::OPT_msoft_float)) { + Features.push_back("-isa-68881"); + Features.push_back("-isa-68882"); + return; + } + + std::string CPU = m68k::getM68kTargetCPU(Args); + // Only enable M68881 for CPU < 68020 if the related flags are present. + if ((A && (CPU == "M68000" || CPU == "M68010")) || + // Otherwise, by default we assume newer CPUs have M68881/2. + CPU == "M68020") + Features.push_back("+isa-68881"); + else if (CPU == "M68030" || CPU == "M68040" || CPU == "M68060") + // Note that although CPU >= M68040 imply M68882, we still add `isa-68882` + // anyway so that it's easier to add or not add the corresponding macro + // definitions later, in case we want to disable 68881/2 in newer CPUs + // (with -msoft-float, for instance). + Features.push_back("+isa-68882"); +} + void m68k::getM68kTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { - - m68k::FloatABI FloatABI = m68k::getM68kFloatABI(D, Args); - if (FloatABI == m68k::FloatABI::Soft) - Features.push_back("-hard-float"); + addFloatABIFeatures(Args, Features); // Handle '-ffixed-<register>' flags if (Args.hasArg(options::OPT_ffixed_a0)) @@ -105,21 +127,3 @@ void m68k::getM68kTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Args.hasArg(options::OPT_ffixed_d7)) Features.push_back("+reserve-d7"); } - -m68k::FloatABI m68k::getM68kFloatABI(const Driver &D, const ArgList &Args) { - m68k::FloatABI ABI = m68k::FloatABI::Invalid; - if (Arg *A = - Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { - - if (A->getOption().matches(options::OPT_msoft_float)) - ABI = m68k::FloatABI::Soft; - else if (A->getOption().matches(options::OPT_mhard_float)) - ABI = m68k::FloatABI::Hard; - } - - // If unspecified, choose the default based on the platform. - if (ABI == m68k::FloatABI::Invalid) - ABI = m68k::FloatABI::Hard; - - return ABI; -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h index 41d53efb940b..051e7e1af103 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h @@ -20,14 +20,6 @@ namespace driver { namespace tools { namespace m68k { -enum class FloatABI { - Invalid, - Soft, - Hard, -}; - -FloatABI getM68kFloatABI(const Driver &D, const llvm::opt::ArgList &Args); - std::string getM68kTargetCPU(const llvm::opt::ArgList &Args); void getM68kTargetFeatures(const Driver &D, const llvm::Triple &Triple, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp index c374d745da38..fe9d112b8800 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -39,12 +39,6 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, DefMips64CPU = "mips64r6"; } - // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android). - if (Triple.isAndroid()) { - DefMips32CPU = "mips32"; - DefMips64CPU = "mips64r6"; - } - // MIPS3 is the default for mips64*-unknown-openbsd. if (Triple.isOSOpenBSD()) DefMips64CPU = "mips3"; @@ -227,6 +221,7 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, bool IsN64 = ABIName == "64"; bool IsPIC = false; bool NonPIC = false; + bool HasNaN2008Opt = false; Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, @@ -291,9 +286,10 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { StringRef Val = StringRef(A->getValue()); if (Val == "2008") { - if (mips::getIEEE754Standard(CPUName) & mips::Std2008) + if (mips::getIEEE754Standard(CPUName) & mips::Std2008) { Features.push_back("+nan2008"); - else { + HasNaN2008Opt = true; + } else { Features.push_back("-nan2008"); D.Diag(diag::warn_target_unsupported_nan2008) << CPUName; } @@ -306,7 +302,7 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, } } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) { @@ -327,8 +323,10 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, } } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } + } else if (HasNaN2008Opt) { + Features.push_back("+abs2008"); } AddTargetFeature(Args, Features, options::OPT_msingle_float, @@ -467,11 +465,6 @@ bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) { bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI) { - if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies && - Triple.getVendor() != llvm::Triple::MipsTechnologies && - !Triple.isAndroid()) - return false; - if (ABIName != "32") return false; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h index f4c11a7e3188..62211c711420 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h @@ -11,8 +11,8 @@ #include "clang/Driver/Driver.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" +#include "llvm/TargetParser/Triple.h" #include <string> #include <vector> diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp index bcaecf4b2d98..ab24d14992cd 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -13,81 +13,83 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting. -std::string ppc::getPPCTargetCPU(const ArgList &Args) { - if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { - StringRef CPUName = A->getValue(); - - if (CPUName == "native") { - std::string CPU = std::string(llvm::sys::getHostCPUName()); - if (!CPU.empty() && CPU != "generic") - return CPU; - else - return ""; - } +static std::string getPPCGenericTargetCPU(const llvm::Triple &T) { + // 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 (T.isOSAIX()) + return "pwr7"; + else if (T.getArch() == llvm::Triple::ppc64le) + return "ppc64le"; + else if (T.getArch() == llvm::Triple::ppc64) + return "ppc64"; + else + return "ppc"; +} - return llvm::StringSwitch<const char *>(CPUName) - .Case("common", "generic") - .Case("440", "440") - .Case("440fp", "440") - .Case("450", "450") - .Case("601", "601") - .Case("602", "602") - .Case("603", "603") - .Case("603e", "603e") - .Case("603ev", "603ev") - .Case("604", "604") - .Case("604e", "604e") - .Case("620", "620") - .Case("630", "pwr3") - .Case("G3", "g3") - .Case("7400", "7400") - .Case("G4", "g4") - .Case("7450", "7450") - .Case("G4+", "g4+") - .Case("750", "750") - .Case("8548", "e500") - .Case("970", "970") - .Case("G5", "g5") - .Case("a2", "a2") - .Case("e500", "e500") - .Case("e500mc", "e500mc") - .Case("e5500", "e5500") - .Case("power3", "pwr3") - .Case("power4", "pwr4") - .Case("power5", "pwr5") - .Case("power5x", "pwr5x") - .Case("power6", "pwr6") - .Case("power6x", "pwr6x") - .Case("power7", "pwr7") - .Case("power8", "pwr8") - .Case("power9", "pwr9") - .Case("power10", "pwr10") - .Case("future", "future") - .Case("pwr3", "pwr3") - .Case("pwr4", "pwr4") - .Case("pwr5", "pwr5") - .Case("pwr5x", "pwr5x") - .Case("pwr6", "pwr6") - .Case("pwr6x", "pwr6x") - .Case("pwr7", "pwr7") - .Case("pwr8", "pwr8") - .Case("pwr9", "pwr9") - .Case("pwr10", "pwr10") - .Case("powerpc", "ppc") - .Case("powerpc64", "ppc64") - .Case("powerpc64le", "ppc64le") - .Default(""); +static std::string normalizeCPUName(StringRef CPUName, const llvm::Triple &T) { + // Clang/LLVM does not actually support code generation + // for the 405 CPU. However, there are uses of this CPU ID + // in projects that previously used GCC and rely on Clang + // accepting it. Clang has always ignored it and passed the + // generic CPU ID to the back end. + if (CPUName == "generic" || CPUName == "405") + return getPPCGenericTargetCPU(T); + + if (CPUName == "native") { + std::string CPU = std::string(llvm::sys::getHostCPUName()); + if (!CPU.empty() && CPU != "generic") + return CPU; + else + return getPPCGenericTargetCPU(T); } - return ""; + return llvm::StringSwitch<const char *>(CPUName) + .Case("common", "generic") + .Case("440fp", "440") + .Case("630", "pwr3") + .Case("G3", "g3") + .Case("G4", "g4") + .Case("G4+", "g4+") + .Case("8548", "e500") + .Case("G5", "g5") + .Case("power3", "pwr3") + .Case("power4", "pwr4") + .Case("power5", "pwr5") + .Case("power5x", "pwr5x") + .Case("power6", "pwr6") + .Case("power6x", "pwr6x") + .Case("power7", "pwr7") + .Case("power8", "pwr8") + .Case("power9", "pwr9") + .Case("power10", "pwr10") + .Case("future", "future") + .Case("powerpc", "ppc") + .Case("powerpc64", "ppc64") + .Case("powerpc64le", "ppc64le") + .Default(CPUName.data()); +} + +/// Get the (LLVM) name of the PowerPC cpu we are tuning for. +std::string ppc::getPPCTuneCPU(const ArgList &Args, const llvm::Triple &T) { + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) + return normalizeCPUName(A->getValue(), T); + return getPPCGenericTargetCPU(T); +} + +/// Get the (LLVM) name of the PowerPC cpu we are targeting. +std::string ppc::getPPCTargetCPU(const Driver &D, const ArgList &Args, + const llvm::Triple &T) { + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) + return normalizeCPUName(A->getValue(), T); + return getPPCGenericTargetCPU(T); } const char *ppc::getPPCAsmModeForCPU(StringRef Name) { @@ -110,7 +112,8 @@ void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe) Features.push_back("+spe"); - handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_ppc_Features_Group); ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); if (FloatABI == ppc::FloatABI::Soft) @@ -125,8 +128,7 @@ ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Tripl const ArgList &Args) { if (Args.getLastArg(options::OPT_msecure_plt)) return ppc::ReadGOTPtrMode::SecurePlt; - if ((Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 13) || - Triple.isOSNetBSD() || Triple.isOSOpenBSD() || Triple.isMusl()) + if (Triple.isPPC32SecurePlt()) return ppc::ReadGOTPtrMode::SecurePlt; else return ppc::ReadGOTPtrMode::Bss; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h index e1c943955e81..ec5b3c8140b6 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h @@ -35,7 +35,10 @@ enum class ReadGOTPtrMode { FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args); -std::string getPPCTargetCPU(const llvm::opt::ArgList &Args); +std::string getPPCTargetCPU(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &T); +std::string getPPCTuneCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &T); const char *getPPCAsmModeForCPU(StringRef Name); ReadGOTPtrMode getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 94b179636e4f..47b29e1577c2 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -1,4 +1,4 @@ -//===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===// +//===--- RISCV.cpp - RISC-V Helpers for Tools -------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,17 +7,18 @@ //===----------------------------------------------------------------------===// #include "RISCV.h" +#include "../Clang.h" #include "ToolChains/CommonArgs.h" #include "clang/Basic/CharInfo.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" -#include "llvm/ADT/Optional.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Error.h" #include "llvm/Support/RISCVISAInfo.h" -#include "llvm/Support/TargetParser.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/RISCVTargetParser.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -41,22 +42,34 @@ static bool getArchFeatures(const Driver &D, StringRef Arch, return false; } - (*ISAInfo)->toFeatures( - Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); }); + for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true, + /*IgnoreUnknown=*/false)) + Features.push_back(Args.MakeArgString(Str)); + + if (EnableExperimentalExtensions) + Features.push_back(Args.MakeArgString("+experimental")); + return true; } // Get features except standard extension feature -static void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, - const llvm::opt::Arg *A, StringRef Mcpu, +static void getRISCFeaturesFromMcpu(const Driver &D, const Arg *A, + const llvm::Triple &Triple, + StringRef Mcpu, std::vector<StringRef> &Features) { - bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64); - llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu); - if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) || - !llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) { - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + bool Is64Bit = Triple.isRISCV64(); + if (!llvm::RISCV::parseCPU(Mcpu, Is64Bit)) { + // Try inverting Is64Bit in case the CPU is valid, but for the wrong target. + if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit)) + D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target) + << Mcpu << Is64Bit; + else + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Mcpu; } + + if (llvm::RISCV::hasFastUnalignedAccess(Mcpu)) + Features.push_back("+fast-unaligned-access"); } void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, @@ -69,8 +82,13 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, // If users give march and mcpu, get std extension feature from MArch // and other features (ex. mirco architecture feature) from mcpu - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) - getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features); + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + StringRef CPU = A->getValue(); + if (CPU == "native") + CPU = llvm::sys::getHostCPUName(); + + getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features); + } // Handle features corresponding to "-ffixed-X" options if (Args.hasArg(options::OPT_ffixed_x1)) @@ -138,27 +156,30 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, // FreeBSD local, because ld.lld doesn't support relaxations // -mno-relax is default, unless -mrelax is specified. - if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) + if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) { Features.push_back("+relax"); - else + // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing + // into .debug_addr, which is currently not implemented. + Arg *A; + if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None) + D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation) + << A->getAsString(Args); + } else { Features.push_back("-relax"); + } - // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is - // specified. - if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) - Features.push_back("+save-restore"); - else - Features.push_back("-save-restore"); + // -mno-unaligned-access is default, unless -munaligned-access is specified. + AddTargetFeature(Args, Features, options::OPT_munaligned_access, + options::OPT_mno_unaligned_access, "fast-unaligned-access"); // Now add any that the user explicitly requested on the command line, // which may override the defaults. - handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_riscv_Features_Group); } StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { - assert((Triple.getArch() == llvm::Triple::riscv32 || - Triple.getArch() == llvm::Triple::riscv64) && - "Unexpected triple"); + assert(Triple.isRISCV() && "Unexpected triple"); // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not // configured using `--with-abi=`, then the logic for the default choice is @@ -190,23 +211,22 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { // rv32e -> ilp32e // rv32* -> ilp32 // rv64g | rv64*d -> lp64d + // rv64e -> lp64e // rv64* -> lp64 StringRef Arch = getRISCVArch(Args, Triple); auto ParseResult = llvm::RISCVISAInfo::parseArchString( Arch, /* EnableExperimentalExtension */ true); - if (!ParseResult) - // Ignore parsing error, just go 3rd step. - consumeError(ParseResult.takeError()); - else - return llvm::RISCV::computeDefaultABIFromArch(**ParseResult); + // Ignore parsing error, just go 3rd step. + if (!llvm::errorToBool(ParseResult.takeError())) + return (*ParseResult)->computeDefaultABI(); // 3. Choose a default based on the triple // // We deviate from GCC's defaults here: // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only. // - On all other OSs we use the double floating point calling convention. - if (Triple.getArch() == llvm::Triple::riscv32) { + if (Triple.isRISCV32()) { if (Triple.getOS() == llvm::Triple::UnknownOS) return "ilp32"; else @@ -221,9 +241,7 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple) { - assert((Triple.getArch() == llvm::Triple::riscv32 || - Triple.getArch() == llvm::Triple::riscv64) && - "Unexpected triple"); + assert(Triple.isRISCV() && "Unexpected triple"); // GCC's logic around choosing a default `-march=` is complex. If GCC is not // configured using `--with-arch=`, then the logic for the default choice is @@ -257,7 +275,10 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, // 2. Get march (isa string) based on `-mcpu=` if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue()); + StringRef CPU = A->getValue(); + if (CPU == "native") + CPU = llvm::sys::getHostCPUName(); + StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU); // Bypass if target cpu's default march is empty. if (MArch != "") return MArch; @@ -266,6 +287,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, // 3. Choose a default based on `-mabi=` // // ilp32e -> rv32e + // lp64e -> rv64e // ilp32 | ilp32f | ilp32d -> rv32imafdc // lp64 | lp64f | lp64d -> rv64imafdc if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { @@ -273,10 +295,16 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, if (MABI.equals_insensitive("ilp32e")) return "rv32e"; - else if (MABI.startswith_insensitive("ilp32")) + else if (MABI.equals_insensitive("lp64e")) + return "rv64e"; + else if (MABI.starts_with_insensitive("ilp32")) return "rv32imafdc"; - else if (MABI.startswith_insensitive("lp64")) + else if (MABI.starts_with_insensitive("lp64")) { + if (Triple.isAndroid()) + return "rv64imafdcv_zba_zbb_zbs"; + return "rv64imafdc"; + } } // 4. Choose a default based on the triple @@ -284,7 +312,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, // We deviate from GCC's defaults here: // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac` // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`) - if (Triple.getArch() == llvm::Triple::riscv32) { + if (Triple.isRISCV32()) { if (Triple.getOS() == llvm::Triple::UnknownOS) return "rv32imac"; else @@ -292,7 +320,26 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, } else { if (Triple.getOS() == llvm::Triple::UnknownOS) return "rv64imac"; + else if (Triple.isAndroid()) + return "rv64imafdcv_zba_zbb_zbs"; else return "rv64imafdc"; } } + +std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + std::string CPU; + // If we have -mcpu, use that. + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + CPU = A->getValue(); + + // Handle CPU name is 'native'. + if (CPU == "native") + CPU = llvm::sys::getHostCPUName(); + + if (!CPU.empty()) + return CPU; + + return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32"; +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h index d4a519cdab34..fcaf9d57ad13 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h @@ -1,4 +1,4 @@ -//===--- RISCV.h - RISCV-specific Tool Helpers ------------------*- C++ -*-===// +//===--- RISCV.h - RISC-V-specific Tool Helpers -----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -26,6 +26,8 @@ StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); StringRef getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +std::string getRISCVTargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); } // end namespace riscv } // namespace tools } // end namespace driver diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp index 70ba8eb2a7d0..ae1a4ba78826 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -62,10 +63,6 @@ const char *sparc::getSparcAsmModeForCPU(StringRef Name, .Case("ma2480", "-Aleon") .Case("ma2485", "-Aleon") .Case("ma2x8x", "-Aleon") - .Case("myriad2", "-Aleon") - .Case("myriad2.1", "-Aleon") - .Case("myriad2.2", "-Aleon") - .Case("myriad2.3", "-Aleon") .Case("leon2", "-Av8") .Case("at697e", "-Av8") .Case("at697f", "-Av8") @@ -81,12 +78,14 @@ const char *sparc::getSparcAsmModeForCPU(StringRef Name, sparc::FloatABI sparc::getSparcFloatABI(const Driver &D, const ArgList &Args) { sparc::FloatABI ABI = sparc::FloatABI::Invalid; - if (Arg *A = Args.getLastArg(clang::driver::options::OPT_msoft_float, - options::OPT_mhard_float, + if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mno_fpu, + options::OPT_mhard_float, options::OPT_mfpu, options::OPT_mfloat_abi_EQ)) { - if (A->getOption().matches(clang::driver::options::OPT_msoft_float)) + if (A->getOption().matches(options::OPT_msoft_float) || + A->getOption().matches(options::OPT_mno_fpu)) ABI = sparc::FloatABI::Soft; - else if (A->getOption().matches(options::OPT_mhard_float)) + else if (A->getOption().matches(options::OPT_mhard_float) || + A->getOption().matches(options::OPT_mfpu)) ABI = sparc::FloatABI::Hard; else { ABI = llvm::StringSwitch<sparc::FloatABI>(A->getValue()) @@ -113,9 +112,151 @@ sparc::FloatABI sparc::getSparcFloatABI(const Driver &D, return ABI; } +std::string sparc::getSparcTargetCPU(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { + StringRef CPUName = A->getValue(); + if (CPUName == "native") { + std::string CPU = std::string(llvm::sys::getHostCPUName()); + if (!CPU.empty() && CPU != "generic") + return CPU; + return ""; + } + return std::string(CPUName); + } + + if (Triple.getArch() == llvm::Triple::sparc && Triple.isOSSolaris()) + return "v9"; + return ""; +} + void sparc::getSparcTargetFeatures(const Driver &D, const ArgList &Args, std::vector<StringRef> &Features) { sparc::FloatABI FloatABI = sparc::getSparcFloatABI(D, Args); if (FloatABI == sparc::FloatABI::Soft) Features.push_back("+soft-float"); + + if (Arg *A = Args.getLastArg(options::OPT_mfsmuld, options::OPT_mno_fsmuld)) { + if (A->getOption().matches(options::OPT_mfsmuld)) + Features.push_back("+fsmuld"); + else + Features.push_back("-fsmuld"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mpopc, options::OPT_mno_popc)) { + if (A->getOption().matches(options::OPT_mpopc)) + Features.push_back("+popc"); + else + Features.push_back("-popc"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mvis, options::OPT_mno_vis)) { + if (A->getOption().matches(options::OPT_mvis)) + Features.push_back("+vis"); + else + Features.push_back("-vis"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mvis2, options::OPT_mno_vis2)) { + if (A->getOption().matches(options::OPT_mvis2)) + Features.push_back("+vis2"); + else + Features.push_back("-vis2"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mvis3, options::OPT_mno_vis3)) { + if (A->getOption().matches(options::OPT_mvis3)) + Features.push_back("+vis3"); + else + Features.push_back("-vis3"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mhard_quad_float, + options::OPT_msoft_quad_float)) { + if (A->getOption().matches(options::OPT_mhard_quad_float)) + Features.push_back("+hard-quad-float"); + else + Features.push_back("-hard-quad-float"); + } + + if (Args.hasArg(options::OPT_ffixed_g1)) + Features.push_back("+reserve-g1"); + + if (Args.hasArg(options::OPT_ffixed_g2)) + Features.push_back("+reserve-g2"); + + if (Args.hasArg(options::OPT_ffixed_g3)) + Features.push_back("+reserve-g3"); + + if (Args.hasArg(options::OPT_ffixed_g4)) + Features.push_back("+reserve-g4"); + + if (Args.hasArg(options::OPT_ffixed_g5)) + Features.push_back("+reserve-g5"); + + if (Args.hasArg(options::OPT_ffixed_g6)) + Features.push_back("+reserve-g6"); + + if (Args.hasArg(options::OPT_ffixed_g7)) + Features.push_back("+reserve-g7"); + + if (Args.hasArg(options::OPT_ffixed_o0)) + Features.push_back("+reserve-o0"); + + if (Args.hasArg(options::OPT_ffixed_o1)) + Features.push_back("+reserve-o1"); + + if (Args.hasArg(options::OPT_ffixed_o2)) + Features.push_back("+reserve-o2"); + + if (Args.hasArg(options::OPT_ffixed_o3)) + Features.push_back("+reserve-o3"); + + if (Args.hasArg(options::OPT_ffixed_o4)) + Features.push_back("+reserve-o4"); + + if (Args.hasArg(options::OPT_ffixed_o5)) + Features.push_back("+reserve-o5"); + + if (Args.hasArg(options::OPT_ffixed_l0)) + Features.push_back("+reserve-l0"); + + if (Args.hasArg(options::OPT_ffixed_l1)) + Features.push_back("+reserve-l1"); + + if (Args.hasArg(options::OPT_ffixed_l2)) + Features.push_back("+reserve-l2"); + + if (Args.hasArg(options::OPT_ffixed_l3)) + Features.push_back("+reserve-l3"); + + if (Args.hasArg(options::OPT_ffixed_l4)) + Features.push_back("+reserve-l4"); + + if (Args.hasArg(options::OPT_ffixed_l5)) + Features.push_back("+reserve-l5"); + + if (Args.hasArg(options::OPT_ffixed_l6)) + Features.push_back("+reserve-l6"); + + if (Args.hasArg(options::OPT_ffixed_l7)) + Features.push_back("+reserve-l7"); + + if (Args.hasArg(options::OPT_ffixed_i0)) + Features.push_back("+reserve-i0"); + + if (Args.hasArg(options::OPT_ffixed_i1)) + Features.push_back("+reserve-i1"); + + if (Args.hasArg(options::OPT_ffixed_i2)) + Features.push_back("+reserve-i2"); + + if (Args.hasArg(options::OPT_ffixed_i3)) + Features.push_back("+reserve-i3"); + + if (Args.hasArg(options::OPT_ffixed_i4)) + Features.push_back("+reserve-i4"); + + if (Args.hasArg(options::OPT_ffixed_i5)) + Features.push_back("+reserve-i5"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h index d12a9a70e264..44658c4259c6 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h @@ -28,6 +28,9 @@ enum class FloatABI { FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args); +std::string getSparcTargetCPU(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); + void getSparcTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, std::vector<llvm::StringRef> &Features); const char *getSparcAsmModeForCPU(llvm::StringRef Name, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp index f81bf68172de..588bc3176d73 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -11,7 +11,7 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp index 9dfd37c2106d..b19760898c64 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp @@ -10,7 +10,6 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" using namespace clang::driver; @@ -19,4 +18,9 @@ using namespace clang; using namespace llvm::opt; void ve::getVETargetFeatures(const Driver &D, const ArgList &Args, - std::vector<StringRef> &Features) {} + std::vector<StringRef> &Features) { + if (Args.hasFlag(options::OPT_mvevpu, options::OPT_mno_vevpu, true)) + Features.push_back("+vpu"); + else + Features.push_back("-vpu"); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h index 531433534914..c47a41df25bc 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h @@ -24,7 +24,7 @@ void getVETargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, std::vector<llvm::StringRef> &Features); } // end namespace ve -} // namespace tools +} // end namespace tools } // end namespace driver } // end namespace clang diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp index bfa008f964e1..53e26a9f8e22 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -13,9 +13,8 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -31,9 +30,6 @@ std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args, // FIXME: Reject attempts to use -march=native unless the target matches // the host. - // - // FIXME: We should also incorporate the detected target features for use - // with -native. CPU = llvm::sys::getHostCPUName(); if (!CPU.empty() && CPU != "generic") return std::string(CPU); @@ -84,13 +80,19 @@ std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args, // Simulators can still run on 10.11 though, like Xcode. if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12)) return "penryn"; + + if (Triple.isDriverKit()) + return "nehalem"; + // The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah. return Is64Bit ? "core2" : "yonah"; } - // Set up default CPU name for PS4 compilers. - if (Triple.isPS4CPU()) + // Set up default CPU name for PS4/PS5 compilers. + if (Triple.isPS4()) return "btver2"; + if (Triple.isPS5()) + return "znver2"; // On Android use targets compatible with gcc if (Triple.isAndroid()) @@ -117,6 +119,15 @@ std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args, void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { + // Claim and report unsupported -mabi=. Note: we don't support "sysv_abi" or + // "ms_abi" as default function attributes. + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mabi_EQ)) { + StringRef DefaultAbi = Triple.isOSWindows() ? "ms" : "sysv"; + if (A->getValue() != DefaultAbi) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << Triple.getTriple(); + } + // If -march=native, autodetect the feature list. if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { if (StringRef(A->getValue()) == "native") { @@ -218,6 +229,27 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, << D.getOpts().getOptionName(LVIOpt); } + for (const Arg *A : Args.filtered(options::OPT_m_x86_AVX10_Features_Group)) { + StringRef Name = A->getOption().getName(); + A->claim(); + + // Skip over "-m". + assert(Name.starts_with("m") && "Invalid feature name."); + Name = Name.substr(1); + + bool IsNegative = Name.consume_front("no-"); + +#ifndef NDEBUG + assert(Name.starts_with("avx10.") && "Invalid AVX10 feature name."); + StringRef Version, Width; + std::tie(Version, Width) = Name.substr(6).split('-'); + assert(Version == "1" && "Invalid AVX10 feature name."); + assert((Width == "256" || Width == "512") && "Invalid AVX10 feature name."); +#endif + + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); + } + // Now add any that the user explicitly requested on the command line, // which may override the defaults. for (const Arg *A : Args.filtered(options::OPT_m_x86_Features_Group, @@ -226,7 +258,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, A->claim(); // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); + assert(Name.starts_with("m") && "Invalid feature name."); Name = Name.substr(1); // Replace -mgeneral-regs-only with -x87, -mmx, -sse @@ -235,9 +267,46 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, continue; } - bool IsNegative = Name.startswith("no-"); + bool IsNegative = Name.starts_with("no-"); + if (A->getOption().matches(options::OPT_mapx_features_EQ) || + A->getOption().matches(options::OPT_mno_apx_features_EQ)) { + + for (StringRef Value : A->getValues()) { + if (Value == "egpr" || Value == "push2pop2" || Value == "ppx" || + Value == "ndd" || Value == "ccmp" || Value == "cf") { + Features.push_back( + Args.MakeArgString((IsNegative ? "-" : "+") + Value)); + continue; + } + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Value; + } + continue; + } if (IsNegative) Name = Name.substr(3); Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } + + // Enable/disable straight line speculation hardening. + if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) { + StringRef Scope = A->getValue(); + if (Scope == "all") { + Features.push_back("+harden-sls-ijmp"); + Features.push_back("+harden-sls-ret"); + } else if (Scope == "return") { + Features.push_back("+harden-sls-ret"); + } else if (Scope == "indirect-jmp") { + Features.push_back("+harden-sls-ijmp"); + } else if (Scope != "none") { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Scope; + } + } + + // -mno-gather, -mno-scatter support + if (Args.hasArg(options::OPT_mno_gather)) + Features.push_back("+prefer-no-gather"); + if (Args.hasArg(options::OPT_mno_scatter)) + Features.push_back("+prefer-no-scatter"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h index 36a2ab52899d..e07387f3ece3 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h @@ -11,8 +11,8 @@ #include "clang/Driver/Driver.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" +#include "llvm/TargetParser/Triple.h" #include <string> #include <vector> diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp index cd07692be358..391c47f88bde 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -12,26 +12,27 @@ #include "Gnu.h" #include "clang/Driver/InputInfo.h" +#include "Arch/ARM.h" #include "Arch/RISCV.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/MultilibBuilder.h" #include "clang/Driver/Options.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Path.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" +#include <sstream> + using namespace llvm::opt; using namespace clang; using namespace clang::driver; using namespace clang::driver::tools; using namespace clang::driver::toolchains; -static Multilib makeMultilib(StringRef commonSuffix) { - return Multilib(commonSuffix, commonSuffix, commonSuffix); -} - static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result) { @@ -39,37 +40,41 @@ static bool findRISCVMultilibs(const Driver &D, StringRef Arch = riscv::getRISCVArch(Args, TargetTriple); StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple); - if (TargetTriple.getArch() == llvm::Triple::riscv64) { - Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64"); - Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d") - .flag("+march=rv64imafdc") - .flag("+mabi=lp64d"); + if (TargetTriple.isRISCV64()) { + MultilibBuilder Imac = + MultilibBuilder().flag("-march=rv64imac").flag("-mabi=lp64"); + MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d") + .flag("-march=rv64imafdc") + .flag("-mabi=lp64d"); // Multilib reuse bool UseImafdc = (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc - addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags); - addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags); - addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags); - addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags); + addMultilibFlag((Arch == "rv64imac"), "-march=rv64imac", Flags); + addMultilibFlag(UseImafdc, "-march=rv64imafdc", Flags); + addMultilibFlag(Abi == "lp64", "-mabi=lp64", Flags); + addMultilibFlag(Abi == "lp64d", "-mabi=lp64d", Flags); - Result.Multilibs = MultilibSet().Either(Imac, Imafdc); - return Result.Multilibs.select(Flags, Result.SelectedMultilib); + Result.Multilibs = + MultilibSetBuilder().Either(Imac, Imafdc).makeMultilibSet(); + return Result.Multilibs.select(Flags, Result.SelectedMultilibs); } - if (TargetTriple.getArch() == llvm::Triple::riscv32) { - Multilib Imac = - makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32"); - Multilib I = - makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32"); - Multilib Im = - makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32"); - Multilib Iac = makeMultilib("/rv32iac/ilp32") - .flag("+march=rv32iac") - .flag("+mabi=ilp32"); - Multilib Imafc = makeMultilib("/rv32imafc/ilp32f") - .flag("+march=rv32imafc") - .flag("+mabi=ilp32f"); + if (TargetTriple.isRISCV32()) { + MultilibBuilder Imac = + MultilibBuilder().flag("-march=rv32imac").flag("-mabi=ilp32"); + MultilibBuilder I = MultilibBuilder("/rv32i/ilp32") + .flag("-march=rv32i") + .flag("-mabi=ilp32"); + MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32") + .flag("-march=rv32im") + .flag("-mabi=ilp32"); + MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32") + .flag("-march=rv32iac") + .flag("-mabi=ilp32"); + MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f") + .flag("-march=rv32imafc") + .flag("-mabi=ilp32f"); // Multilib reuse bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i @@ -77,22 +82,23 @@ static bool findRISCVMultilibs(const Driver &D, bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") || (Arch == "rv32gc"); // imafdc,gc => imafc - addMultilibFlag(UseI, "march=rv32i", Flags); - addMultilibFlag(UseIm, "march=rv32im", Flags); - addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags); - addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags); - addMultilibFlag(UseImafc, "march=rv32imafc", Flags); - addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags); - addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags); - - Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc); - return Result.Multilibs.select(Flags, Result.SelectedMultilib); + addMultilibFlag(UseI, "-march=rv32i", Flags); + addMultilibFlag(UseIm, "-march=rv32im", Flags); + addMultilibFlag((Arch == "rv32iac"), "-march=rv32iac", Flags); + addMultilibFlag((Arch == "rv32imac"), "-march=rv32imac", Flags); + addMultilibFlag(UseImafc, "-march=rv32imafc", Flags); + addMultilibFlag(Abi == "ilp32", "-mabi=ilp32", Flags); + addMultilibFlag(Abi == "ilp32f", "-mabi=ilp32f", Flags); + + Result.Multilibs = + MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet(); + return Result.Multilibs.select(Flags, Result.SelectedMultilibs); } return false; } BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) + const ArgList &Args) : ToolChain(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) @@ -101,15 +107,21 @@ BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, findMultilibs(D, Triple, Args); SmallString<128> SysRoot(computeSysRoot()); if (!SysRoot.empty()) { - llvm::sys::path::append(SysRoot, "lib"); - getFilePaths().push_back(std::string(SysRoot)); + for (const Multilib &M : getOrderedMultilibs()) { + SmallString<128> Dir(SysRoot); + llvm::sys::path::append(Dir, M.osSuffix(), "lib"); + getFilePaths().push_back(std::string(Dir)); + getLibraryPaths().push_back(std::string(Dir)); + } } } -/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ? +/// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ? static bool isARMBareMetal(const llvm::Triple &Triple) { if (Triple.getArch() != llvm::Triple::arm && - Triple.getArch() != llvm::Triple::thumb) + Triple.getArch() != llvm::Triple::thumb && + Triple.getArch() != llvm::Triple::armeb && + Triple.getArch() != llvm::Triple::thumbeb) return false; if (Triple.getVendor() != llvm::Triple::UnknownVendor) @@ -125,9 +137,10 @@ static bool isARMBareMetal(const llvm::Triple &Triple) { return true; } -/// Is the triple aarch64-none-elf? +/// Is the triple {aarch64.aarch64_be}-none-elf? static bool isAArch64BareMetal(const llvm::Triple &Triple) { - if (Triple.getArch() != llvm::Triple::aarch64) + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_be) return false; if (Triple.getVendor() != llvm::Triple::UnknownVendor) @@ -140,8 +153,7 @@ static bool isAArch64BareMetal(const llvm::Triple &Triple) { } static bool isRISCVBareMetal(const llvm::Triple &Triple) { - if (Triple.getArch() != llvm::Triple::riscv32 && - Triple.getArch() != llvm::Triple::riscv64) + if (!Triple.isRISCV()) return false; if (Triple.getVendor() != llvm::Triple::UnknownVendor) @@ -153,51 +165,100 @@ static bool isRISCVBareMetal(const llvm::Triple &Triple) { return Triple.getEnvironmentName() == "elf"; } +/// Is the triple powerpc[64][le]-*-none-eabi? +static bool isPPCBareMetal(const llvm::Triple &Triple) { + return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS && + Triple.getEnvironment() == llvm::Triple::EABI; +} + +static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D, + StringRef MultilibPath, const ArgList &Args, + DetectedMultilibs &Result) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = + D.getVFS().getBufferForFile(MultilibPath); + if (!MB) + return; + Multilib::flags_list Flags = TC.getMultilibFlags(Args); + llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet = + MultilibSet::parseYaml(*MB.get()); + if (ErrorOrMultilibSet.getError()) + return; + Result.Multilibs = ErrorOrMultilibSet.get(); + if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) + return; + D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " "); + std::stringstream ss; + for (const Multilib &Multilib : Result.Multilibs) + ss << "\n" << llvm::join(Multilib.flags(), " "); + D.Diag(clang::diag::note_drv_available_multilibs) << ss.str(); +} + +static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml"; + +// Get the sysroot, before multilib takes effect. +static std::string computeBaseSysRoot(const Driver &D, + const llvm::Triple &Triple) { + if (!D.SysRoot.empty()) + return D.SysRoot; + + SmallString<128> SysRootDir(D.Dir); + llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes"); + + SmallString<128> MultilibPath(SysRootDir); + llvm::sys::path::append(MultilibPath, MultilibFilename); + + // New behaviour: if multilib.yaml is found then use clang-runtimes as the + // sysroot. + if (D.getVFS().exists(MultilibPath)) + return std::string(SysRootDir); + + // Otherwise fall back to the old behaviour of appending the target triple. + llvm::sys::path::append(SysRootDir, D.getTargetTriple()); + return std::string(SysRootDir); +} + void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) { DetectedMultilibs Result; if (isRISCVBareMetal(Triple)) { if (findRISCVMultilibs(D, Triple, Args, Result)) { - SelectedMultilib = Result.SelectedMultilib; + SelectedMultilibs = Result.SelectedMultilibs; Multilibs = Result.Multilibs; } + } else { + llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple)); + llvm::sys::path::append(MultilibPath, MultilibFilename); + findMultilibsFromYAML(*this, D, MultilibPath, Args, Result); + SelectedMultilibs = Result.SelectedMultilibs; + Multilibs = Result.Multilibs; } } bool BareMetal::handlesTarget(const llvm::Triple &Triple) { return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) || - isRISCVBareMetal(Triple); + isRISCVBareMetal(Triple) || isPPCBareMetal(Triple); } Tool *BareMetal::buildLinker() const { return new tools::baremetal::Linker(*this); } -std::string BareMetal::getCompilerRTPath() const { return getRuntimesDir(); } - -std::string BareMetal::buildCompilerRTBasename(const llvm::opt::ArgList &, - StringRef, FileType, - bool) const { - return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str(); -} - -std::string BareMetal::getRuntimesDir() const { - SmallString<128> Dir(getDriver().ResourceDir); - llvm::sys::path::append(Dir, "lib", "baremetal"); - Dir += SelectedMultilib.gccSuffix(); - return std::string(Dir.str()); +Tool *BareMetal::buildStaticLibTool() const { + return new tools::baremetal::StaticLibTool(*this); } std::string BareMetal::computeSysRoot() const { - if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot + SelectedMultilib.osSuffix(); + return computeBaseSysRoot(getDriver(), getTriple()); +} - SmallString<128> SysRootDir; - llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes", - getDriver().getTargetTriple()); +BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const { + // Get multilibs in reverse order because they're ordered most-specific last. + if (!SelectedMultilibs.empty()) + return llvm::reverse(SelectedMultilibs); - SysRootDir += SelectedMultilib.osSuffix(); - return std::string(SysRootDir); + // No multilibs selected so return a single default multilib. + static const llvm::SmallVector<Multilib> Default = {Multilib()}; + return llvm::reverse(Default); } void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -212,10 +273,14 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, } if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { - SmallString<128> Dir(computeSysRoot()); - if (!Dir.empty()) { - llvm::sys::path::append(Dir, "include"); - addSystemInclude(DriverArgs, CC1Args, Dir.str()); + const SmallString<128> SysRoot(computeSysRoot()); + if (!SysRoot.empty()) { + for (const Multilib &M : getOrderedMultilibs()) { + SmallString<128> Dir(SysRoot); + llvm::sys::path::append(Dir, M.includeSuffix()); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } } } } @@ -226,48 +291,58 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, CC1Args.push_back("-nostdsysteminc"); } -void BareMetal::AddClangCXXStdlibIncludeArgs( - const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc) || - DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) +void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, + options::OPT_nostdincxx)) return; + const Driver &D = getDriver(); std::string SysRoot(computeSysRoot()); if (SysRoot.empty()) return; - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: { - SmallString<128> Dir(SysRoot); - llvm::sys::path::append(Dir, "include", "c++", "v1"); - addSystemInclude(DriverArgs, CC1Args, Dir.str()); - break; - } - case ToolChain::CST_Libstdcxx: { + for (const Multilib &M : getOrderedMultilibs()) { SmallString<128> Dir(SysRoot); - llvm::sys::path::append(Dir, "include", "c++"); - std::error_code EC; - Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; - // Walk the subdirs, and find the one with the newest gcc version: - for (llvm::vfs::directory_iterator - LI = getDriver().getVFS().dir_begin(Dir.str(), EC), - LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); - if (CandidateVersion.Major == -1) - continue; - if (CandidateVersion <= Version) - continue; - Version = CandidateVersion; + llvm::sys::path::append(Dir, M.gccSuffix()); + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + // First check sysroot/usr/include/c++/v1 if it exists. + SmallString<128> TargetDir(Dir); + llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1"); + if (D.getVFS().exists(TargetDir)) { + addSystemInclude(DriverArgs, CC1Args, TargetDir.str()); + break; + } + // Add generic path if nothing else succeeded so far. + llvm::sys::path::append(Dir, "include", "c++", "v1"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + break; + } + case ToolChain::CST_Libstdcxx: { + llvm::sys::path::append(Dir, "include", "c++"); + std::error_code EC; + Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; + // Walk the subdirs, and find the one with the newest gcc version: + for (llvm::vfs::directory_iterator + LI = D.getVFS().dir_begin(Dir.str(), EC), + LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); + if (CandidateVersion.Major == -1) + continue; + if (CandidateVersion <= Version) + continue; + Version = CandidateVersion; + } + if (Version.Major != -1) { + llvm::sys::path::append(Dir, Version.Text); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + break; + } } - if (Version.Major == -1) - return; - llvm::sys::path::append(Dir, Version.Text); - addSystemInclude(DriverArgs, CC1Args, Dir.str()); - break; - } } } @@ -276,6 +351,8 @@ void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: @@ -290,10 +367,14 @@ void BareMetal::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs) const { ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); switch (RLT) { - case ToolChain::RLT_CompilerRT: - CmdArgs.push_back( - Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName())); + case ToolChain::RLT_CompilerRT: { + const std::string FileName = getCompilerRT(Args, "builtins"); + llvm::StringRef BaseName = llvm::sys::path::filename(FileName); + BaseName.consume_front("lib"); + BaseName.consume_back(".a"); + CmdArgs.push_back(Args.MakeArgString("-l" + BaseName)); return; + } case ToolChain::RLT_Libgcc: CmdArgs.push_back("-lgcc"); return; @@ -301,6 +382,51 @@ void BareMetal::AddLinkRuntimeLib(const ArgList &Args, llvm_unreachable("Unhandled RuntimeLibType."); } +void baremetal::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); + + // ar tool command "llvm-ar <options> <output_file> <input_files>". + ArgStringList CmdArgs; + // Create and insert file members with a deterministic index. + CmdArgs.push_back("rcsD"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) { + if (II.isFilename()) { + CmdArgs.push_back(II.getFilename()); + } + } + + // Delete old output archive file if it already exists before generating a new + // archive file. + const char *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<Command>(JA, *this, + ResponseFileSupport::AtFileCurCP(), + Exec, CmdArgs, Inputs, Output)); +} + void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -308,22 +434,39 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { ArgStringList CmdArgs; - auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain()); + auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain()); + const llvm::Triple::ArchType Arch = TC.getArch(); + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); CmdArgs.push_back("-Bstatic"); - Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_e, options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_r}); + if (Triple.isARM() || Triple.isThumb()) { + bool IsBigEndian = arm::isARMBigEndian(Triple, Args); + if (IsBigEndian) + arm::appendBE8LinkFlag(Args, CmdArgs, Triple); + CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL"); + } else if (Triple.isAArch64()) { + CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL"); + } + + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_s, options::OPT_t, options::OPT_r}); TC.AddFilePathLibArgs(Args, CmdArgs); - CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); + for (const auto &LibPath : TC.getLibraryPaths()) + CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath))); + + const std::string FileName = TC.getCompilerRT(Args, "builtins"); + llvm::SmallString<128> PathBuf{FileName}; + llvm::sys::path::remove_filename(PathBuf); + CmdArgs.push_back(Args.MakeArgString("-L" + PathBuf)); if (TC.ShouldLinkCXXStdlib(Args)) TC.AddCXXStdlibLibArgs(Args, CmdArgs); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { CmdArgs.push_back("-lc"); CmdArgs.push_back("-lm"); @@ -331,10 +474,45 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, TC.AddLinkRuntimeLib(Args, CmdArgs); } + if (TC.getTriple().isRISCV()) + CmdArgs.push_back("-X"); + + // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf + // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and + // arm*-*-*bsd). + if (isARMBareMetal(TC.getTriple())) + CmdArgs.push_back("--target2=rel"); + CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Args.MakeArgString(TC.GetLinkerPath()), - CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output)); +} + +// BareMetal toolchain allows all sanitizers where the compiler generates valid +// code, ignoring all runtime library support issues on the assumption that +// baremetal targets typically implement their own runtime support. +SanitizerMask BareMetal::getSupportedSanitizers() const { + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::aarch64_be; + const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::KernelAddress; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; + Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::Vptr; + Res |= SanitizerKind::SafeStack; + Res |= SanitizerKind::Thread; + Res |= SanitizerKind::Scudo; + if (IsX86_64 || IsAArch64 || IsRISCV64) { + Res |= SanitizerKind::HWAddress; + Res |= SanitizerKind::KernelHWAddress; + } + return Res; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h index dc718e09ad43..67b5aa5998fc 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h @@ -1,4 +1,4 @@ -//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===// +//===--- BareMetal.h - Bare Metal Tool and ToolChain ------------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -32,15 +32,13 @@ public: protected: Tool *buildLinker() const override; - - std::string buildCompilerRTBasename(const llvm::opt::ArgList &Args, - StringRef Component, - FileType Type = ToolChain::FT_Static, - bool AddArch = true) const override; + Tool *buildStaticLibTool() const override; public: bool useIntegratedAs() const override { return true; } + bool isBareMetal() const override { return true; } bool isCrossCompiling() const override { return true; } + bool HasNativeLLVMSupport() const override { return true; } bool isPICDefault() const override { return false; } bool isPIEDefault(const llvm::opt::ArgList &Args) const override { return false; @@ -50,8 +48,6 @@ public: StringRef getOSLibName() const override { return "baremetal"; } - std::string getCompilerRTPath() const override; - RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; } @@ -61,12 +57,13 @@ public: const char *getDefaultLinker() const override { return "ld.lld"; } - std::string getRuntimesDir() const; - void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -75,6 +72,12 @@ public: void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; std::string computeSysRoot() const override; + SanitizerMask getSupportedSanitizers() const override; + +private: + using OrderedMultilibs = + llvm::iterator_range<llvm::SmallVector<Multilib>::const_reverse_iterator>; + OrderedMultilibs getOrderedMultilibs() const; }; } // namespace toolchains @@ -82,7 +85,21 @@ public: namespace tools { namespace baremetal { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY StaticLibTool : public Tool { +public: + StaticLibTool(const ToolChain &TC) + : Tool("baremetal::StaticLibTool", "llvm-ar", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {} bool isLinkJob() const override { return true; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp new file mode 100644 index 000000000000..feb3bc922920 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp @@ -0,0 +1,204 @@ +//===--- CSKYToolchain.cpp - CSKY 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 "CSKYToolChain.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/InputInfo.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +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); +} + +/// CSKY Toolchain +CSKYToolChain::CSKYToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + GCCInstallation.init(Triple, Args); + if (GCCInstallation.isValid()) { + Multilibs = GCCInstallation.getMultilibs(); + SelectedMultilibs.assign({GCCInstallation.getMultilib()}); + path_list &Paths = getFilePaths(); + // Add toolchain/multilib specific file paths. + addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(), + GCCInstallation.getInstallPath(), Paths); + getFilePaths().push_back(GCCInstallation.getInstallPath().str() + + SelectedMultilibs.back().osSuffix()); + ToolChain::path_list &PPaths = getProgramPaths(); + // Multilib cross-compiler GCC installations put ld in a triple-prefixed + // directory off of the parent of the GCC installation. + PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple().str() + "/bin") + .str()); + PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str()); + getFilePaths().push_back(computeSysRoot() + "/lib" + + SelectedMultilibs.back().osSuffix()); + } else { + getProgramPaths().push_back(D.Dir); + getFilePaths().push_back(computeSysRoot() + "/lib"); + } +} + +Tool *CSKYToolChain::buildLinker() const { + return new tools::CSKY::Linker(*this); +} + +ToolChain::RuntimeLibType CSKYToolChain::GetDefaultRuntimeLibType() const { + return GCCInstallation.isValid() ? ToolChain::RLT_Libgcc + : ToolChain::RLT_CompilerRT; +} + +ToolChain::UnwindLibType +CSKYToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const { + return ToolChain::UNW_None; +} + +void CSKYToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind) const { + CC1Args.push_back("-nostdsysteminc"); +} + +void CSKYToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { + SmallString<128> Dir(computeSysRoot()); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + SmallString<128> Dir2(computeSysRoot()); + llvm::sys::path::append(Dir2, "sys-include"); + addSystemInclude(DriverArgs, CC1Args, Dir2.str()); + } +} + +void CSKYToolChain::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const GCCVersion &Version = GCCInstallation.getVersion(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text, + TripleStr, Multilib.includeSuffix(), DriverArgs, + CC1Args); +} + +std::string CSKYToolChain::computeSysRoot() const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + + SmallString<128> SysRootDir; + if (GCCInstallation.isValid()) { + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + llvm::sys::path::append(SysRootDir, LibDir, "..", TripleStr); + } else { + // Use the triple as provided to the driver. Unlike the parsed triple + // this has not been normalized to always contain every field. + llvm::sys::path::append(SysRootDir, getDriver().Dir, "..", + getDriver().getTargetTriple()); + } + + if (!llvm::sys::fs::exists(SysRootDir)) + return std::string(); + + return std::string(SysRootDir); +} + +void CSKY::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const ToolChain &ToolChain = getToolChain(); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + CmdArgs.push_back("-m"); + CmdArgs.push_back("cskyelf"); + + std::string Linker = getToolChain().GetLinkerPath(); + + bool WantCRTs = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + + const char *crtbegin, *crtend; + auto RuntimeLib = ToolChain.GetRuntimeLibType(Args); + if (RuntimeLib == ToolChain::RLT_Libgcc) { + crtbegin = "crtbegin.o"; + crtend = "crtend.o"; + } else { + assert(RuntimeLib == ToolChain::RLT_CompilerRT); + crtbegin = ToolChain.getCompilerRTArgString(Args, "crtbegin", + ToolChain::FT_Object); + crtend = + ToolChain.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object); + } + + if (WantCRTs) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.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, options::OPT_s, + options::OPT_t, options::OPT_r}); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + // TODO: add C++ includes and libs if compiling C++. + + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lc"); + if (Args.hasArg(options::OPT_msim)) + CmdArgs.push_back("-lsemi"); + else + CmdArgs.push_back("-lnosys"); + CmdArgs.push_back("--end-group"); + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); + } + + if (WantCRTs) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker), + CmdArgs, Inputs, Output)); +} +// CSKY tools end. diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h new file mode 100644 index 000000000000..a57324a42641 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h @@ -0,0 +1,63 @@ +//===--- CSKYToolchain.h - CSKY 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CSKYTOOLCHAIN_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CSKYTOOLCHAIN_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY CSKYToolChain : public Generic_ELF { +public: + CSKYToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind) const override; + RuntimeLibType GetDefaultRuntimeLibType() const override; + UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + +protected: + Tool *buildLinker() const override; + +private: + std::string computeSysRoot() const override; +}; + +} // end namespace toolchains + +namespace tools { +namespace CSKY { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("CSKY::Linker", "ld", TC) {} + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace CSKY +} // end namespace tools + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CSKYTOOLCHAIN_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp index f2f18e901ab0..aa344b3465ab 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp @@ -10,6 +10,8 @@ #include "AMDGPU.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" +#include "Arch/CSKY.h" +#include "Arch/LoongArch.h" #include "Arch/M68k.h" #include "Arch/Mips.h" #include "Arch/PPC.h" @@ -25,9 +27,13 @@ #include "clang/Basic/CLWarnings.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/HeaderInclude.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/MakeSupport.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Driver/Action.h" #include "clang/Driver/Distro.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" @@ -35,18 +41,26 @@ #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/Types.h" #include "clang/Driver/XRayArgs.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/YAMLParser.h" +#include "llvm/TargetParser/ARMTargetParserCommon.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/LoongArchTargetParser.h" +#include "llvm/TargetParser/RISCVTargetParser.h" +#include <cctype> using namespace clang::driver; using namespace clang::driver::tools; @@ -56,7 +70,9 @@ using namespace llvm::opt; static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC, options::OPT_fminimize_whitespace, - options::OPT_fno_minimize_whitespace)) { + options::OPT_fno_minimize_whitespace, + options::OPT_fkeep_system_includes, + options::OPT_fno_keep_system_includes)) { if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) && !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) { D.Diag(clang::diag::err_drv_argument_only_allowed_with) @@ -93,34 +109,6 @@ static void EscapeSpacesAndBackslashes(const char *Arg, } } -// Quote target names for inclusion in GNU Make dependency files. -// Only the characters '$', '#', ' ', '\t' are quoted. -static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) { - for (unsigned i = 0, e = Target.size(); i != e; ++i) { - switch (Target[i]) { - case ' ': - case '\t': - // Escape the preceding backslashes - for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j) - Res.push_back('\\'); - - // Escape the space/tab - Res.push_back('\\'); - break; - case '$': - Res.push_back('$'); - break; - case '#': - Res.push_back('\\'); - break; - default: - break; - } - - Res.push_back(Target[i]); - } -} - /// Apply \a Work on the current tool chain \a RegularToolChain and any other /// offloading tool chain that is associated with the current action \a JA. static void @@ -223,17 +211,21 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, llvm::StringMap<bool> OptionStrings; OptionStrings.insert(std::make_pair("divd", false)); OptionStrings.insert(std::make_pair("divf", false)); + OptionStrings.insert(std::make_pair("divh", false)); OptionStrings.insert(std::make_pair("vec-divd", false)); OptionStrings.insert(std::make_pair("vec-divf", false)); + OptionStrings.insert(std::make_pair("vec-divh", false)); OptionStrings.insert(std::make_pair("sqrtd", false)); OptionStrings.insert(std::make_pair("sqrtf", false)); + OptionStrings.insert(std::make_pair("sqrth", false)); OptionStrings.insert(std::make_pair("vec-sqrtd", false)); OptionStrings.insert(std::make_pair("vec-sqrtf", false)); + OptionStrings.insert(std::make_pair("vec-sqrth", false)); for (unsigned i = 0; i != NumOptions; ++i) { StringRef Val = A->getValue(i); - bool IsDisabled = Val.startswith(DisabledPrefixIn); + bool IsDisabled = Val.starts_with(DisabledPrefixIn); // Ignore the disablement token for string matching. if (IsDisabled) Val = Val.substr(1); @@ -252,10 +244,11 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, D.Diag(diag::err_drv_unknown_argument) << Val; return; } - // The option was specified without a float or double suffix. - // Make sure that the double entry was not already specified. + // The option was specified without a half or float or double suffix. + // Make sure that the double or half entry was not already specified. // The float entry will be checked below. - if (OptionStrings[ValBase.str() + 'd']) { + if (OptionStrings[ValBase.str() + 'd'] || + OptionStrings[ValBase.str() + 'h']) { D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; return; } @@ -270,9 +263,12 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, // Mark the matched option as found. Do not allow duplicate specifiers. OptionIter->second = true; - // If the precision was not specified, also mark the double entry as found. - if (ValBase.back() != 'f' && ValBase.back() != 'd') + // If the precision was not specified, also mark the double and half entry + // as found. + if (ValBase.back() != 'f' && ValBase.back() != 'd' && ValBase.back() != 'h') { OptionStrings[ValBase.str() + 'd'] = true; + OptionStrings[ValBase.str() + 'h'] = true; + } // Build the output string. StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; @@ -305,88 +301,6 @@ static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args, } } -static void getWebAssemblyTargetFeatures(const ArgList &Args, - std::vector<StringRef> &Features) { - handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); -} - -static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args, ArgStringList &CmdArgs, - bool ForAS, bool IsAux = false) { - std::vector<StringRef> Features; - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - mips::getMIPSTargetFeatures(D, Triple, Args, Features); - break; - - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - arm::getARMTargetFeatures(D, Triple, Args, CmdArgs, Features, ForAS); - break; - - case llvm::Triple::ppc: - case llvm::Triple::ppcle: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - ppc::getPPCTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - riscv::getRISCVTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::systemz: - systemz::getSystemZTargetFeatures(D, Args, Features); - break; - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - case llvm::Triple::aarch64_be: - aarch64::getAArch64TargetFeatures(D, Triple, Args, CmdArgs, Features, - ForAS); - break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - x86::getX86TargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::hexagon: - hexagon::getHexagonTargetFeatures(D, Args, Features); - break; - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - getWebAssemblyTargetFeatures(Args, Features); - break; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - sparc::getSparcTargetFeatures(D, Args, Features); - break; - case llvm::Triple::r600: - case llvm::Triple::amdgcn: - amdgpu::getAMDGPUTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::m68k: - m68k::getM68kTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::msp430: - msp430::getMSP430TargetFeatures(D, Args, Features); - break; - case llvm::Triple::ve: - ve::getVETargetFeatures(D, Args, Features); - break; - } - - for (auto Feature : unifyTargetFeatures(Features)) { - CmdArgs.push_back(IsAux ? "-aux-target-feature" : "-target-feature"); - CmdArgs.push_back(Feature.data()); - } -} - static bool shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, const llvm::Triple &Triple) { @@ -450,9 +364,9 @@ static bool addExceptionArgs(const ArgList &Args, types::ID InputType, } if (types::isCXX(InputType)) { - // Disable C++ EH by default on XCore and PS4. - bool CXXExceptionsEnabled = - Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU(); + // Disable C++ EH by default on XCore and PS4/PS5. + bool CXXExceptionsEnabled = Triple.getArch() != llvm::Triple::xcore && + !Triple.isPS() && !Triple.isDriverKit(); Arg *ExceptionArg = Args.getLastArg( options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions, options::OPT_fexceptions, options::OPT_fno_exceptions); @@ -473,6 +387,9 @@ static bool addExceptionArgs(const ArgList &Args, types::ID InputType, // So we do not set EH to false. Args.AddLastArg(CmdArgs, options::OPT_fignore_exceptions); + Args.addOptInFlag(CmdArgs, options::OPT_fassume_nothrow_exception_dtor, + options::OPT_fno_assume_nothrow_exception_dtor); + if (EH) CmdArgs.push_back("-fexceptions"); return EH; @@ -494,138 +411,6 @@ static bool ShouldEnableAutolink(const ArgList &Args, const ToolChain &TC, Default); } -// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases -// to the corresponding DebugInfoKind. -static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) { - assert(A.getOption().matches(options::OPT_gN_Group) && - "Not a -g option that specifies a debug-info level"); - if (A.getOption().matches(options::OPT_g0) || - A.getOption().matches(options::OPT_ggdb0)) - return codegenoptions::NoDebugInfo; - if (A.getOption().matches(options::OPT_gline_tables_only) || - A.getOption().matches(options::OPT_ggdb1)) - return codegenoptions::DebugLineTablesOnly; - if (A.getOption().matches(options::OPT_gline_directives_only)) - return codegenoptions::DebugDirectivesOnly; - return codegenoptions::DebugInfoConstructor; -} - -static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { - switch (Triple.getArch()){ - default: - return false; - case llvm::Triple::arm: - case llvm::Triple::thumb: - // ARM Darwin targets require a frame pointer to be always present to aid - // offline debugging via backtraces. - return Triple.isOSDarwin(); - } -} - -static bool useFramePointerForTargetByDefault(const ArgList &Args, - const llvm::Triple &Triple) { - if (Args.hasArg(options::OPT_pg) && !Args.hasArg(options::OPT_mfentry)) - return true; - - switch (Triple.getArch()) { - case llvm::Triple::xcore: - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - case llvm::Triple::msp430: - // XCore never wants frame pointers, regardless of OS. - // WebAssembly never wants frame pointers. - return false; - case llvm::Triple::ppc: - case llvm::Triple::ppcle: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - case llvm::Triple::amdgcn: - case llvm::Triple::r600: - return !areOptimizationsEnabled(Args); - default: - break; - } - - if (Triple.isOSNetBSD()) { - return !areOptimizationsEnabled(Args); - } - - if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI || - Triple.isOSHurd()) { - switch (Triple.getArch()) { - // Don't use a frame pointer on linux if optimizing for certain targets. - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - if (Triple.isAndroid()) - return true; - LLVM_FALLTHROUGH; - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::systemz: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return !areOptimizationsEnabled(Args); - default: - return true; - } - } - - if (Triple.isOSWindows()) { - switch (Triple.getArch()) { - case llvm::Triple::x86: - return !areOptimizationsEnabled(Args); - case llvm::Triple::x86_64: - return Triple.isOSBinFormatMachO(); - case llvm::Triple::arm: - case llvm::Triple::thumb: - // Windows on ARM builds with FPO disabled to aid fast stack walking - return true; - default: - // All other supported Windows ISAs use xdata unwind information, so frame - // pointers are not generally useful. - return false; - } - } - - return true; -} - -static CodeGenOptions::FramePointerKind -getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { - // We have 4 states: - // - // 00) leaf retained, non-leaf retained - // 01) leaf retained, non-leaf omitted (this is invalid) - // 10) leaf omitted, non-leaf retained - // (what -momit-leaf-frame-pointer was designed for) - // 11) leaf omitted, non-leaf omitted - // - // "omit" options taking precedence over "no-omit" options is the only way - // to make 3 valid states representable - Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, - options::OPT_fno_omit_frame_pointer); - bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer); - bool NoOmitFP = - A && A->getOption().matches(options::OPT_fno_omit_frame_pointer); - bool OmitLeafFP = Args.hasFlag(options::OPT_momit_leaf_frame_pointer, - options::OPT_mno_omit_leaf_frame_pointer, - Triple.isAArch64() || Triple.isPS4CPU() || - Triple.isVE()); - if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || - (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { - if (OmitLeafFP) - return CodeGenOptions::FramePointerKind::NonLeaf; - return CodeGenOptions::FramePointerKind::All; - } - return CodeGenOptions::FramePointerKind::None; -} - /// Add a CC1 option to specify the debug compilation directory. static const char *addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, @@ -650,7 +435,7 @@ static void addDebugObjectName(const ArgList &Args, ArgStringList &CmdArgs, const char *OutputFileName) { // No need to generate a value for -object-file-name if it was provided. for (auto *Arg : Args.filtered(options::OPT_Xclang)) - if (StringRef(Arg->getValue()).startswith("-object-file-name")) + if (StringRef(Arg->getValue()).starts_with("-object-file-name")) return; if (Args.hasArg(options::OPT_object_file_name_EQ)) @@ -664,22 +449,39 @@ static void addDebugObjectName(const ArgList &Args, ArgStringList &CmdArgs, // Make the path absolute in the debug infos like MSVC does. llvm::sys::fs::make_absolute(ObjFileNameForDebug); } + // If the object file name is a relative path, then always use Windows + // backslash style as -object-file-name is used for embedding object file path + // in codeview and it can only be generated when targeting on Windows. + // Otherwise, just use native absolute path. + llvm::sys::path::Style Style = + llvm::sys::path::is_absolute(ObjFileNameForDebug) + ? llvm::sys::path::Style::native + : llvm::sys::path::Style::windows_backslash; + llvm::sys::path::remove_dots(ObjFileNameForDebug, /*remove_dot_dot=*/true, + Style); CmdArgs.push_back( Args.MakeArgString(Twine("-object-file-name=") + ObjFileNameForDebug)); } /// Add a CC1 and CC1AS option to specify the debug file path prefix map. -static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { - for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, - options::OPT_fdebug_prefix_map_EQ)) { - StringRef Map = A->getValue(); +static void addDebugPrefixMapArg(const Driver &D, const ToolChain &TC, + const ArgList &Args, ArgStringList &CmdArgs) { + auto AddOneArg = [&](StringRef Map, StringRef Name) { if (!Map.contains('=')) - D.Diag(diag::err_drv_invalid_argument_to_option) - << Map << A->getOption().getName(); + D.Diag(diag::err_drv_invalid_argument_to_option) << Map << Name; else CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); + }; + + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fdebug_prefix_map_EQ)) { + AddOneArg(A->getValue(), A->getOption().getName()); A->claim(); } + std::string GlobalRemapEntry = TC.GetGlobalDebugPathRemapping(); + if (GlobalRemapEntry.empty()) + return; + AddOneArg(GlobalRemapEntry, "environment"); } /// Add a CC1 and CC1AS option to specify the macro file path prefix map. @@ -777,10 +579,10 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input, } static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, - const Driver &D, const InputInfo &Output, + const JobAction &JA, const InputInfo &Output, const ArgList &Args, SanitizerArgs &SanArgs, ArgStringList &CmdArgs) { - + const Driver &D = TC.getDriver(); auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate, options::OPT_fprofile_generate_EQ, options::OPT_fno_profile_generate); @@ -788,12 +590,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) PGOGenerateArg = nullptr; - 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 *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args); auto *ProfileGenerateArg = Args.getLastArg( options::OPT_fprofile_instr_generate, @@ -825,9 +622,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, } if (TC.getTriple().isOSAIX()) { - if (ProfileGenerateArg) - D.Diag(diag::err_drv_unsupported_opt_for_target) - << ProfileGenerateArg->getSpelling() << TC.getTriple().str(); if (Arg *ProfileSampleUseArg = getLastProfileSampleUseArg(Args)) D.Diag(diag::err_drv_unsupported_opt_for_target) << ProfileSampleUseArg->getSpelling() << TC.getTriple().str(); @@ -895,10 +689,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, options::OPT_fno_test_coverage, false) || Args.hasArg(options::OPT_coverage); bool EmitCovData = TC.needsGCovInstrumentation(Args); - if (EmitCovNotes) - CmdArgs.push_back("-ftest-coverage"); - if (EmitCovData) - CmdArgs.push_back("-fprofile-arcs"); if (Args.hasFlag(options::OPT_fcoverage_mapping, options::OPT_fno_coverage_mapping, false)) { @@ -910,6 +700,17 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, CmdArgs.push_back("-fcoverage-mapping"); } + if (Args.hasFlag(options::OPT_fmcdc_coverage, options::OPT_fno_mcdc_coverage, + false)) { + if (!Args.hasFlag(options::OPT_fcoverage_mapping, + options::OPT_fno_coverage_mapping, false)) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "-fcoverage-mcdc" + << "-fcoverage-mapping"; + + CmdArgs.push_back("-fcoverage-mcdc"); + } + if (Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, options::OPT_fcoverage_compilation_dir_EQ)) { if (A->getOption().matches(options::OPT_ffile_compilation_dir_EQ)) @@ -951,11 +752,30 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, CmdArgs.push_back("-fprofile-update=atomic"); else if (Val != "single") D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; - } else if (SanArgs.needsTsanRt()) { - CmdArgs.push_back("-fprofile-update=atomic"); + << A->getSpelling() << Val; } + int FunctionGroups = 1; + int SelectedFunctionGroup = 0; + if (const auto *A = Args.getLastArg(options::OPT_fprofile_function_groups)) { + StringRef Val = A->getValue(); + if (Val.getAsInteger(0, FunctionGroups) || FunctionGroups < 1) + D.Diag(diag::err_drv_invalid_int_value) << A->getAsString(Args) << Val; + } + if (const auto *A = + Args.getLastArg(options::OPT_fprofile_selected_function_group)) { + StringRef Val = A->getValue(); + if (Val.getAsInteger(0, SelectedFunctionGroup) || + SelectedFunctionGroup < 0 || SelectedFunctionGroup >= FunctionGroups) + D.Diag(diag::err_drv_invalid_int_value) << A->getAsString(Args) << Val; + } + if (FunctionGroups != 1) + CmdArgs.push_back(Args.MakeArgString("-fprofile-function-groups=" + + Twine(FunctionGroups))); + if (SelectedFunctionGroup != 0) + CmdArgs.push_back(Args.MakeArgString("-fprofile-selected-function-group=" + + Twine(SelectedFunctionGroup))); + // Leave -fprofile-dir= an unused argument unless .gcda emission is // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider // the flag used. There is no -fno-profile-dir, so the user has no @@ -965,36 +785,45 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, Args.hasArg(options::OPT_coverage)) FProfileDir = Args.getLastArg(options::OPT_fprofile_dir); - // Put the .gcno and .gcda files (if needed) next to the object file or - // bitcode file in the case of LTO. - // FIXME: There should be a simpler way to find the object file for this - // input, and this code probably does the wrong thing for commands that - // compile and link all at once. - if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) && - (EmitCovNotes || EmitCovData) && Output.isFilename()) { - SmallString<128> OutputFilename; - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT__SLASH_Fo)) - OutputFilename = FinalOutput->getValue(); - else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) - OutputFilename = FinalOutput->getValue(); - else - OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); - SmallString<128> CoverageFilename = OutputFilename; + // TODO: Don't claim -c/-S to warn about -fsyntax-only -c/-S, -E -c/-S, + // like we warn about -fsyntax-only -E. + (void)(Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)); + + // Put the .gcno and .gcda files (if needed) next to the primary output file, + // or fall back to a file in the current directory for `clang -c --coverage + // d/a.c` in the absence of -o. + if (EmitCovNotes || EmitCovData) { + SmallString<128> CoverageFilename; + if (Arg *DumpDir = Args.getLastArgNoClaim(options::OPT_dumpdir)) { + // Form ${dumpdir}${basename}.gcno. Note that dumpdir may not end with a + // path separator. + CoverageFilename = DumpDir->getValue(); + CoverageFilename += llvm::sys::path::filename(Output.getBaseInput()); + } else if (Arg *FinalOutput = + C.getArgs().getLastArg(options::OPT__SLASH_Fo)) { + CoverageFilename = FinalOutput->getValue(); + } else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) { + CoverageFilename = FinalOutput->getValue(); + } else { + CoverageFilename = llvm::sys::path::filename(Output.getBaseInput()); + } if (llvm::sys::path::is_relative(CoverageFilename)) (void)D.getVFS().makeAbsolute(CoverageFilename); llvm::sys::path::replace_extension(CoverageFilename, "gcno"); - - CmdArgs.push_back("-coverage-notes-file"); - CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + if (EmitCovNotes) { + CmdArgs.push_back( + Args.MakeArgString("-coverage-notes-file=" + CoverageFilename)); + } if (EmitCovData) { if (FProfileDir) { + SmallString<128> Gcno = std::move(CoverageFilename); CoverageFilename = FProfileDir->getValue(); - llvm::sys::path::append(CoverageFilename, OutputFilename); + llvm::sys::path::append(CoverageFilename, Gcno); } llvm::sys::path::replace_extension(CoverageFilename, "gcda"); - CmdArgs.push_back("-coverage-data-file"); - CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + CmdArgs.push_back( + Args.MakeArgString("-coverage-data-file=" + CoverageFilename)); } } } @@ -1029,52 +858,12 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { RelaxDefault); } -// Extract the integer N from a string spelled "-dwarf-N", returning 0 -// on mismatch. The StringRef input (rather than an Arg) allows -// for use by the "-Xassembler" option parser. -static unsigned DwarfVersionNum(StringRef ArgValue) { - return llvm::StringSwitch<unsigned>(ArgValue) - .Case("-gdwarf-2", 2) - .Case("-gdwarf-3", 3) - .Case("-gdwarf-4", 4) - .Case("-gdwarf-5", 5) - .Default(0); -} - -// Find a DWARF format version option. -// This function is a complementary for DwarfVersionNum(). -static const Arg *getDwarfNArg(const ArgList &Args) { - return Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, - options::OPT_gdwarf_4, options::OPT_gdwarf_5, - options::OPT_gdwarf); -} - -static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind DebugInfoKind, - unsigned DwarfVersion, - llvm::DebuggerKind DebuggerTuning) { - switch (DebugInfoKind) { - case codegenoptions::DebugDirectivesOnly: - CmdArgs.push_back("-debug-info-kind=line-directives-only"); - break; - case codegenoptions::DebugLineTablesOnly: - CmdArgs.push_back("-debug-info-kind=line-tables-only"); - break; - case codegenoptions::DebugInfoConstructor: - CmdArgs.push_back("-debug-info-kind=constructor"); - break; - case codegenoptions::LimitedDebugInfo: - CmdArgs.push_back("-debug-info-kind=limited"); - break; - case codegenoptions::FullDebugInfo: - CmdArgs.push_back("-debug-info-kind=standalone"); - break; - case codegenoptions::UnusedTypeInfo: - CmdArgs.push_back("-debug-info-kind=unused-types"); - break; - default: - break; - } +static void +RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, + llvm::codegenoptions::DebugInfoKind DebugInfoKind, + unsigned DwarfVersion, + llvm::DebuggerKind DebuggerTuning) { + addDebugInfoKind(CmdArgs, DebugInfoKind); if (DwarfVersion > 0) CmdArgs.push_back( Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion))); @@ -1118,39 +907,30 @@ static void RenderDebugInfoCompressionArgs(const ArgList &Args, if (Value == "none") { CmdArgs.push_back("--compress-debug-sections=none"); } else if (Value == "zlib") { - if (llvm::zlib::isAvailable()) { + if (llvm::compression::zlib::isAvailable()) { + CmdArgs.push_back( + Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); + } else { + D.Diag(diag::warn_debug_compression_unavailable) << "zlib"; + } + } else if (Value == "zstd") { + if (llvm::compression::zstd::isAvailable()) { CmdArgs.push_back( Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); } else { - D.Diag(diag::warn_debug_compression_unavailable); + D.Diag(diag::warn_debug_compression_unavailable) << "zstd"; } } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } -static const char *RelocationModelName(llvm::Reloc::Model Model) { - switch (Model) { - case llvm::Reloc::Static: - return "static"; - case llvm::Reloc::PIC_: - return "pic"; - case llvm::Reloc::DynamicNoPIC: - return "dynamic-no-pic"; - case llvm::Reloc::ROPI: - return "ropi"; - case llvm::Reloc::RWPI: - return "rwpi"; - case llvm::Reloc::ROPI_RWPI: - return "ropi-rwpi"; - } - llvm_unreachable("Unknown Reloc::Model kind"); -} static void handleAMDGPUCodeObjectVersionOptions(const Driver &D, const ArgList &Args, - ArgStringList &CmdArgs) { + ArgStringList &CmdArgs, + bool IsCC1As = false) { // If no version was requested by the user, use the default value from the // back end. This is consistent with the value returned from // getAMDGPUCodeObjectVersion. This lets clang emit IR for amdgpu without @@ -1162,7 +942,51 @@ static void handleAMDGPUCodeObjectVersionOptions(const Driver &D, Args.MakeArgString(Twine("--amdhsa-code-object-version=") + Twine(CodeObjVer))); CmdArgs.insert(CmdArgs.begin() + 1, "-mllvm"); + // -cc1as does not accept -mcode-object-version option. + if (!IsCC1As) + CmdArgs.insert(CmdArgs.begin() + 1, + Args.MakeArgString(Twine("-mcode-object-version=") + + Twine(CodeObjVer))); + } +} + +static bool maybeHasClangPchSignature(const Driver &D, StringRef Path) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MemBuf = + D.getVFS().getBufferForFile(Path); + if (!MemBuf) + return false; + llvm::file_magic Magic = llvm::identify_magic((*MemBuf)->getBuffer()); + if (Magic == llvm::file_magic::unknown) + return false; + // Return true for both raw Clang AST files and object files which may + // contain a __clangast section. + if (Magic == llvm::file_magic::clang_ast) + return true; + Expected<std::unique_ptr<llvm::object::ObjectFile>> Obj = + llvm::object::ObjectFile::createObjectFile(**MemBuf, Magic); + return !Obj.takeError(); +} + +static bool gchProbe(const Driver &D, StringRef Path) { + llvm::ErrorOr<llvm::vfs::Status> Status = D.getVFS().status(Path); + if (!Status) + return false; + + if (Status->isDirectory()) { + std::error_code EC; + for (llvm::vfs::directory_iterator DI = D.getVFS().dir_begin(Path, EC), DE; + !EC && DI != DE; DI = DI.increment(EC)) { + if (maybeHasClangPchSignature(D, DI->path())) + return true; + } + D.Diag(diag::warn_drv_pch_ignoring_gch_dir) << Path; + return false; } + + if (maybeHasClangPchSignature(D, Path)) + return true; + D.Diag(diag::warn_drv_pch_ignoring_gch_file) << Path; + return false; } void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, @@ -1217,7 +1041,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, } else { CmdArgs.push_back("-MT"); SmallString<128> Quoted; - QuoteTarget(A->getValue(), Quoted); + quoteMakeTarget(A->getValue(), Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); } } @@ -1242,7 +1066,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, CmdArgs.push_back("-MT"); SmallString<128> Quoted; - QuoteTarget(DepTarget, Quoted); + quoteMakeTarget(DepTarget, Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); } @@ -1274,9 +1098,38 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, if (JA.isOffloading(Action::OFK_HIP)) getToolChain().AddHIPIncludeArgs(Args, CmdArgs); + // If we are compiling for a GPU target we want to override the system headers + // with ones created by the 'libc' project if present. + if (!Args.hasArg(options::OPT_nostdinc) && + !Args.hasArg(options::OPT_nogpuinc) && + !Args.hasArg(options::OPT_nobuiltininc)) { + // Without an offloading language we will include these headers directly. + // Offloading languages will instead only use the declarations stored in + // the resource directory at clang/lib/Headers/llvm_libc_wrappers. + if ((getToolChain().getTriple().isNVPTX() || + getToolChain().getTriple().isAMDGCN()) && + C.getActiveOffloadKinds() == Action::OFK_None) { + SmallString<128> P(llvm::sys::path::parent_path(D.InstalledDir)); + llvm::sys::path::append(P, "include"); + llvm::sys::path::append(P, "gpu-none-llvm"); + CmdArgs.push_back("-c-isystem"); + CmdArgs.push_back(Args.MakeArgString(P)); + } else if (C.getActiveOffloadKinds() == Action::OFK_OpenMP) { + // TODO: CUDA / HIP include their own headers for some common functions + // implemented here. We'll need to clean those up so they do not conflict. + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + llvm::sys::path::append(P, "llvm_libc_wrappers"); + CmdArgs.push_back("-internal-isystem"); + CmdArgs.push_back(Args.MakeArgString(P)); + } + } + // If we are offloading to a target via OpenMP we need to include the // openmp_wrappers folder which contains alternative system headers. if (JA.isDeviceOffloading(Action::OFK_OpenMP) && + !Args.hasArg(options::OPT_nostdinc) && + !Args.hasArg(options::OPT_nogpuinc) && (getToolChain().getTriple().isNVPTX() || getToolChain().getTriple().isAMDGCN())) { if (!Args.hasArg(options::OPT_nobuiltininc)) { @@ -1333,7 +1186,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, bool RenderedImplicitInclude = false; for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - if (A->getOption().matches(options::OPT_include)) { + if (A->getOption().matches(options::OPT_include) && + D.getProbePrecompiled()) { // Handling of gcc-style gch precompiled headers. bool IsFirstImplicitInclude = !RenderedImplicitInclude; RenderedImplicitInclude = true; @@ -1344,14 +1198,13 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // so that replace_extension does the right thing. P += ".dummy"; llvm::sys::path::replace_extension(P, "pch"); - if (llvm::sys::fs::exists(P)) + if (D.getVFS().exists(P)) FoundPCH = true; if (!FoundPCH) { + // For GCC compat, probe for a file or directory ending in .gch instead. llvm::sys::path::replace_extension(P, "gch"); - if (llvm::sys::fs::exists(P)) { - FoundPCH = true; - } + FoundPCH = gchProbe(D, P.str()); } if (FoundPCH) { @@ -1376,6 +1229,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, } else if (A->getOption().matches(options::OPT_stdlibxx_isystem)) { // Translated to -internal-isystem by the driver, no need to pass to cc1. continue; + } else if (A->getOption().matches(options::OPT_ibuiltininc)) { + // This is used only by the driver. No need to pass to cc1. + continue; } // Not translated, render as usual. @@ -1383,7 +1239,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } - Args.AddAllArgs(CmdArgs, + Args.addAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I_Group, options::OPT_F, options::OPT_index_header_map}); @@ -1453,6 +1309,17 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, addMacroPrefixMapArg(D, Args, CmdArgs); addCoveragePrefixMapArg(D, Args, CmdArgs); + + Args.AddLastArg(CmdArgs, options::OPT_ffile_reproducible, + options::OPT_fno_file_reproducible); + + if (const char *Epoch = std::getenv("SOURCE_DATE_EPOCH")) { + CmdArgs.push_back("-source-date-epoch"); + CmdArgs.push_back(Args.MakeArgString(Epoch)); + } + + Args.addOptInFlag(CmdArgs, options::OPT_fdefine_target_os_macros, + options::OPT_fno_define_target_os_macros); } // FIXME: Move to target hook. @@ -1625,6 +1492,16 @@ void RenderARMABI(const Driver &D, const llvm::Triple &Triple, CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); } + +void AddUnalignedAccessWarning(ArgStringList &CmdArgs) { + auto StrictAlignIter = + llvm::find_if(llvm::reverse(CmdArgs), [](StringRef Arg) { + return Arg == "+strict-align" || Arg == "-strict-align"; + }); + if (StrictAlignIter != CmdArgs.rend() && + StringRef(*StrictAlignIter) == "+strict-align") + CmdArgs.push_back("-Wunaligned-access"); +} } static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, @@ -1643,28 +1520,31 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, << Triple.getArchName(); StringRef Scope, Key; - bool IndirectBranches; + bool IndirectBranches, BranchProtectionPAuthLR, GuardedControlStack; if (A->getOption().matches(options::OPT_msign_return_address_EQ)) { Scope = A->getValue(); - if (!Scope.equals("none") && !Scope.equals("non-leaf") && - !Scope.equals("all")) - D.Diag(diag::err_invalid_branch_protection) - << Scope << A->getAsString(Args); + if (Scope != "none" && Scope != "non-leaf" && Scope != "all") + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Scope; Key = "a_key"; IndirectBranches = false; + BranchProtectionPAuthLR = false; + GuardedControlStack = false; } else { StringRef DiagMsg; llvm::ARM::ParsedBranchProtection PBP; if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg)) - D.Diag(diag::err_invalid_branch_protection) - << DiagMsg << A->getAsString(Args); + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << DiagMsg; if (!isAArch64 && PBP.Key == "b_key") D.Diag(diag::warn_unsupported_branch_protection) << "b-key" << A->getAsString(Args); Scope = PBP.Scope; Key = PBP.Key; + BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR; IndirectBranches = PBP.BranchTargetEnforcement; + GuardedControlStack = PBP.GuardedControlStack; } CmdArgs.push_back( @@ -1672,8 +1552,13 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, if (!Scope.equals("none")) CmdArgs.push_back( Args.MakeArgString(Twine("-msign-return-address-key=") + Key)); + if (BranchProtectionPAuthLR) + CmdArgs.push_back( + Args.MakeArgString(Twine("-mbranch-protection-pauth-lr"))); if (IndirectBranches) CmdArgs.push_back("-mbranch-target-enforce"); + if (GuardedControlStack) + CmdArgs.push_back("-mguarded-control-stack"); } void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, @@ -1720,6 +1605,8 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, // Enable/disable return address signing and indirect branch targets. CollectARMPACBTIOptions(getToolChain(), Args, CmdArgs, false /*isAArch64*/); + + AddUnalignedAccessWarning(CmdArgs); } void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, @@ -1741,14 +1628,17 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, case llvm::Triple::thumbeb: // Use the effective triple, which takes into account the deployment target. AddARMTargetArgs(EffectiveTriple, Args, CmdArgs, KernelOrKext); - CmdArgs.push_back("-fallow-half-arguments-and-returns"); break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: AddAArch64TargetArgs(Args, CmdArgs); - CmdArgs.push_back("-fallow-half-arguments-and-returns"); + break; + + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + AddLoongArchTargetArgs(Args, CmdArgs); break; case llvm::Triple::mips: @@ -1857,7 +1747,7 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") || Val.equals("2048+")) { unsigned Bits = 0; - if (Val.endswith("+")) + if (Val.ends_with("+")) Val = Val.substr(0, Val.size() - 1); else { bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid; @@ -1874,24 +1764,37 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, } else if (!Val.equals("scalable")) // Handle the unsupported values passed to msve-vector-bits. D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { - StringRef Name = A->getValue(); - - std::string TuneCPU; - if (Name == "native") - TuneCPU = std::string(llvm::sys::getHostCPUName()); + CmdArgs.push_back("-tune-cpu"); + if (strcmp(A->getValue(), "native") == 0) + CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); else - TuneCPU = std::string(Name); + CmdArgs.push_back(A->getValue()); + } - if (!TuneCPU.empty()) { - CmdArgs.push_back("-tune-cpu"); - CmdArgs.push_back(Args.MakeArgString(TuneCPU)); - } + AddUnalignedAccessWarning(CmdArgs); +} + +void Clang::AddLoongArchTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const llvm::Triple &Triple = getToolChain().getTriple(); + + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back( + loongarch::getLoongArchABI(getToolChain().getDriver(), Args, Triple) + .data()); + + // Handle -mtune. + if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { + std::string TuneCPU = A->getValue(); + TuneCPU = loongarch::postProcessTargetCPUString(TuneCPU, Triple); + CmdArgs.push_back("-tune-cpu"); + CmdArgs.push_back(Args.MakeArgString(TuneCPU)); } } @@ -2029,7 +1932,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val)); } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } else D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName; } @@ -2045,14 +1948,20 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, void Clang::AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + const llvm::Triple &T = getToolChain().getTriple(); + if (Args.getLastArg(options::OPT_mtune_EQ)) { + CmdArgs.push_back("-tune-cpu"); + std::string CPU = ppc::getPPCTuneCPU(Args, T); + CmdArgs.push_back(Args.MakeArgString(CPU)); + } + // Select the ABI to use. const char *ABIName = nullptr; - const llvm::Triple &T = getToolChain().getTriple(); if (T.isOSBinFormatELF()) { switch (getToolChain().getArch()) { case llvm::Triple::ppc64: { - if ((T.isOSFreeBSD() && T.getOSMajorVersion() >= 13) || - T.isOSOpenBSD() || T.isMusl()) + if (T.isPPC64ELFv2ABI()) ABIName = "elfv2"; else ABIName = "elfv1"; @@ -2067,13 +1976,28 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, } bool IEEELongDouble = getToolChain().defaultToIEEELongDouble(); + bool VecExtabi = false; for (const Arg *A : Args.filtered(options::OPT_mabi_EQ)) { StringRef V = A->getValue(); - if (V == "ieeelongdouble") + if (V == "ieeelongdouble") { IEEELongDouble = true; - else if (V == "ibmlongdouble") + A->claim(); + } else if (V == "ibmlongdouble") { IEEELongDouble = false; - else if (V != "altivec") + A->claim(); + } else if (V == "vec-default") { + VecExtabi = false; + A->claim(); + } else if (V == "vec-extabi") { + VecExtabi = true; + A->claim(); + } else if (V == "elfv1") { + ABIName = "elfv1"; + A->claim(); + } else if (V == "elfv2") { + ABIName = "elfv2"; + A->claim(); + } else if (V != "altivec") // The ppc64 linux abis are all "altivec" abis by default. Accept and ignore // the option if given as we don't have backend support for any targets // that don't use the altivec abi. @@ -2081,10 +2005,14 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, } if (IEEELongDouble) CmdArgs.push_back("-mabi=ieeelongdouble"); + if (VecExtabi) { + if (!T.isOSAIX()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << "-mabi=vec-extabi" << T.str(); + CmdArgs.push_back("-mabi=vec-extabi"); + } - ppc::FloatABI FloatABI = - ppc::getPPCFloatABI(getToolChain().getDriver(), Args); - + ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); if (FloatABI == ppc::FloatABI::Soft) { // Floating point operations and argument passing are soft. CmdArgs.push_back("-msoft-float"); @@ -2125,6 +2053,12 @@ static void SetRISCVSmallDataLimit(const ToolChain &TC, const ArgList &Args, if (Args.hasArg(options::OPT_G)) { D.Diag(diag::warn_drv_unsupported_sdata); } + } else if (Triple.isAndroid()) { + // GP relaxation is not supported on Android. + SmallDataLimit = "0"; + if (Args.hasArg(options::OPT_G)) { + D.Diag(diag::warn_drv_unsupported_sdata); + } } else if (Arg *A = Args.getLastArg(options::OPT_G)) { SmallDataLimit = A->getValue(); } @@ -2143,18 +2077,57 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args, SetRISCVSmallDataLimit(getToolChain(), Args, CmdArgs); - std::string TuneCPU; - - if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { - StringRef Name = A->getValue(); + if (!Args.hasFlag(options::OPT_mimplicit_float, + options::OPT_mno_implicit_float, true)) + CmdArgs.push_back("-no-implicit-float"); - Name = llvm::RISCV::resolveTuneCPUAlias(Name, Triple.isArch64Bit()); - TuneCPU = std::string(Name); + if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { + CmdArgs.push_back("-tune-cpu"); + if (strcmp(A->getValue(), "native") == 0) + CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); + else + CmdArgs.push_back(A->getValue()); } - if (!TuneCPU.empty()) { - CmdArgs.push_back("-tune-cpu"); - CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + // Handle -mrvv-vector-bits=<bits> + if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) { + StringRef Val = A->getValue(); + const Driver &D = getToolChain().getDriver(); + + // Get minimum VLen from march. + unsigned MinVLen = 0; + StringRef Arch = riscv::getRISCVArch(Args, Triple); + auto ISAInfo = llvm::RISCVISAInfo::parseArchString( + Arch, /*EnableExperimentalExtensions*/ true); + // Ignore parsing error. + if (!errorToBool(ISAInfo.takeError())) + MinVLen = (*ISAInfo)->getMinVLen(); + + // If the value is "zvl", use MinVLen from march. Otherwise, try to parse + // as integer as long as we have a MinVLen. + unsigned Bits = 0; + if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) { + Bits = MinVLen; + } else if (!Val.getAsInteger(10, Bits)) { + // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that + // at least MinVLen. + if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock || + Bits > 65536 || !llvm::isPowerOf2_32(Bits)) + Bits = 0; + } + + // If we got a valid value try to use it. + if (Bits != 0) { + unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock; + CmdArgs.push_back( + Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin))); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin))); + } else if (!Val.equals("scalable")) { + // Handle the unsupported values passed to mrvv-vector-bits. + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } } } @@ -2174,12 +2147,32 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("hard"); } + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { + StringRef Name = A->getValue(); + std::string TuneCPU; + if (Name == "native") + TuneCPU = std::string(llvm::sys::getHostCPUName()); + else + TuneCPU = std::string(Name); + + CmdArgs.push_back("-tune-cpu"); + CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + } } void Clang::AddSystemZTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - bool HasBackchain = Args.hasFlag(options::OPT_mbackchain, - options::OPT_mno_backchain, false); + if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { + CmdArgs.push_back("-tune-cpu"); + if (strcmp(A->getValue(), "native") == 0) + CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); + else + CmdArgs.push_back(A->getValue()); + } + + bool HasBackchain = + Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false); bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack, options::OPT_mno_packed_stack, false); systemz::FloatABI FloatABI = @@ -2238,7 +2231,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-inline-asm=" + Value)); } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } else if (D.IsCLMode()) { CmdArgs.push_back("-mllvm"); @@ -2259,10 +2252,10 @@ void Clang::AddX86TargetArgs(const ArgList &Args, // Handle -mtune. - // Default to "generic" unless -march is present or targetting the PS4. + // Default to "generic" unless -march is present or targetting the PS4/PS5. std::string TuneCPU; if (!Args.hasArg(clang::driver::options::OPT_march_EQ) && - !getToolChain().getTriple().isPS4CPU()) + !getToolChain().getTriple().isPS()) TuneCPU = "generic"; // Override based on -mtune. @@ -2290,8 +2283,8 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args, if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-hexagon-small-data-threshold=" + - Twine(G.getValue()))); + CmdArgs.push_back( + Args.MakeArgString("-hexagon-small-data-threshold=" + Twine(*G))); } if (!Args.hasArg(options::OPT_fno_short_enums)) @@ -2321,7 +2314,7 @@ void Clang::AddLanaiTargetArgs(const ArgList &Args, if (Mregparm != 4) { getToolChain().getDriver().Diag( diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } @@ -2331,10 +2324,8 @@ void Clang::AddWebAssemblyTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Default to "hidden" visibility. if (!Args.hasArg(options::OPT_fvisibility_EQ, - options::OPT_fvisibility_ms_compat)) { - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back("hidden"); - } + options::OPT_fvisibility_ms_compat)) + CmdArgs.push_back("-fvisibility=hidden"); } void Clang::AddVETargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { @@ -2356,7 +2347,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, if (!CompilationDatabase) { std::error_code EC; auto File = std::make_unique<llvm::raw_fd_ostream>( - Filename, EC, llvm::sys::fs::OF_TextWithCRLF); + Filename, EC, + llvm::sys::fs::OF_TextWithCRLF | llvm::sys::fs::OF_Append); if (EC) { D.Diag(clang::diag::err_drv_compilationdatabase) << Filename << EC.message(); @@ -2370,7 +2362,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, CWD = "."; CDB << "{ \"directory\": \"" << escape(*CWD) << "\""; CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\""; - CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\""; + if (Output.isFilename()) + CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\""; CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\""; SmallString<128> Buf; Buf = "-x"; @@ -2382,6 +2375,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, CDB << ", \"" << escape(Buf) << "\""; } CDB << ", \"" << escape(Input.getFilename()) << "\""; + if (Output.isFilename()) + CDB << ", \"-o\", \"" << escape(Output.getFilename()) << "\""; for (auto &A: Args) { auto &O = A->getOption(); // Skip language selection, which is positional. @@ -2395,6 +2390,9 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, // Skip inputs. if (O.getKind() == Option::InputClass) continue; + // Skip output. + if (O.getID() == options::OPT_o) + continue; // All other arguments are quoted and appended. ArgStringList ASL; A->render(Args, ASL); @@ -2468,6 +2466,11 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, DefaultIncrementalLinkerCompatible)) CmdArgs.push_back("-mincremental-linker-compatible"); + Args.AddLastArg(CmdArgs, options::OPT_femit_dwarf_unwind_EQ); + + Args.addOptInFlag(CmdArgs, options::OPT_femit_compact_unwind_non_canonical, + options::OPT_fno_emit_compact_unwind_non_canonical); + // If you add more args here, also add them to the block below that // starts with "// If CollectArgsForIntegratedAssembler() isn't called below". @@ -2497,7 +2500,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, ImplicitIt = A->getValue(); if (!CheckARMImplicitITArg(ImplicitIt)) D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << ImplicitIt; + << A->getSpelling() << ImplicitIt; continue; default: break; @@ -2518,11 +2521,18 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, switch (C.getDefaultToolChain().getArch()) { default: break; + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + if (Value == "--no-type-check") { + CmdArgs.push_back("-mno-type-check"); + continue; + } + break; case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::arm: case llvm::Triple::armeb: - if (Value.startswith("-mimplicit-it=")) { + if (Value.starts_with("-mimplicit-it=")) { // Only store the value; the last value set takes effect. ImplicitIt = Value.split("=").second; if (CheckARMImplicitITArg(ImplicitIt)) @@ -2547,12 +2557,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, CmdArgs.push_back("-use-tcc-in-div"); continue; } - if (Value.startswith("-msoft-float")) { + if (Value.starts_with("-msoft-float")) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+soft-float"); continue; } - if (Value.startswith("-mhard-float")) { + if (Value.starts_with("-mhard-float")) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("-soft-float"); continue; @@ -2589,8 +2599,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, CmdArgs.push_back("-massembler-no-warn"); } else if (Value == "--noexecstack") { UseNoExecStack = true; - } else if (Value.startswith("-compress-debug-sections") || - Value.startswith("--compress-debug-sections") || + } else if (Value.starts_with("-compress-debug-sections") || + Value.starts_with("--compress-debug-sections") || Value == "-nocompress-debug-sections" || Value == "--nocompress-debug-sections") { CmdArgs.push_back(Value.data()); @@ -2600,46 +2610,46 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } else if (Value == "-mrelax-relocations=no" || Value == "--mrelax-relocations=no") { UseRelaxRelocations = false; - } else if (Value.startswith("-I")) { + } else if (Value.starts_with("-I")) { CmdArgs.push_back(Value.data()); // We need to consume the next argument if the current arg is a plain // -I. The next arg will be the include directory. if (Value == "-I") TakeNextArg = true; - } else if (Value.startswith("-gdwarf-")) { + } else if (Value.starts_with("-gdwarf-")) { // "-gdwarf-N" options are not cc1as options. unsigned DwarfVersion = DwarfVersionNum(Value); if (DwarfVersion == 0) { // Send it onward, and let cc1as complain. CmdArgs.push_back(Value.data()); } else { RenderDebugEnablingArgs(Args, CmdArgs, - codegenoptions::DebugInfoConstructor, + llvm::codegenoptions::DebugInfoConstructor, DwarfVersion, llvm::DebuggerKind::Default); } - } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || - Value.startswith("-mhwdiv") || Value.startswith("-march")) { + } else if (Value.starts_with("-mcpu") || Value.starts_with("-mfpu") || + Value.starts_with("-mhwdiv") || Value.starts_with("-march")) { // Do nothing, we'll validate it later. } else if (Value == "-defsym") { - if (A->getNumValues() != 2) { - D.Diag(diag::err_drv_defsym_invalid_format) << Value; - break; - } - const char *S = A->getValue(1); - auto Pair = StringRef(S).split('='); - auto Sym = Pair.first; - auto SVal = Pair.second; - - if (Sym.empty() || SVal.empty()) { - D.Diag(diag::err_drv_defsym_invalid_format) << S; - break; - } - int64_t IVal; - if (SVal.getAsInteger(0, IVal)) { - D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; - break; - } - CmdArgs.push_back(Value.data()); - TakeNextArg = true; + if (A->getNumValues() != 2) { + D.Diag(diag::err_drv_defsym_invalid_format) << Value; + break; + } + const char *S = A->getValue(1); + auto Pair = StringRef(S).split('='); + auto Sym = Pair.first; + auto SVal = Pair.second; + + if (Sym.empty() || SVal.empty()) { + D.Diag(diag::err_drv_defsym_invalid_format) << S; + break; + } + int64_t IVal; + if (SVal.getAsInteger(0, IVal)) { + D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; + break; + } + CmdArgs.push_back(Value.data()); + TakeNextArg = true; } else if (Value == "-fdebug-compilation-dir") { CmdArgs.push_back("-fdebug-compilation-dir"); TakeNextArg = true; @@ -2653,14 +2663,14 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, D.PrintVersion(C, llvm::outs()); } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } if (ImplicitIt.size()) AddARMImplicitITArgs(Args, CmdArgs, ImplicitIt); - if (UseRelaxRelocations) - CmdArgs.push_back("--mrelax-relocations"); + if (!UseRelaxRelocations) + CmdArgs.push_back("-mrelax-relocations=no"); if (UseNoExecStack) CmdArgs.push_back("-mnoexecstack"); if (MipsTargetFeature != nullptr) { @@ -2672,6 +2682,53 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, if (C.getDriver().embedBitcodeEnabled() || C.getDriver().embedBitcodeMarkerOnly()) Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ); + + if (const char *AsSecureLogFile = getenv("AS_SECURE_LOG_FILE")) { + CmdArgs.push_back("-as-secure-log-file"); + CmdArgs.push_back(Args.MakeArgString(AsSecureLogFile)); + } +} + +static StringRef EnumComplexRangeToStr(LangOptions::ComplexRangeKind Range) { + StringRef RangeStr = ""; + switch (Range) { + case LangOptions::ComplexRangeKind::CX_Limited: + return "-fcx-limited-range"; + break; + case LangOptions::ComplexRangeKind::CX_Fortran: + return "-fcx-fortran-rules"; + break; + default: + return RangeStr; + break; + } +} + +static void EmitComplexRangeDiag(const Driver &D, + LangOptions::ComplexRangeKind Range1, + LangOptions::ComplexRangeKind Range2) { + if (Range1 != LangOptions::ComplexRangeKind::CX_Full) + D.Diag(clang::diag::warn_drv_overriding_option) + << EnumComplexRangeToStr(Range1) << EnumComplexRangeToStr(Range2); +} + +static std::string +RenderComplexRangeOption(LangOptions::ComplexRangeKind Range) { + std::string ComplexRangeStr = "-complex-range="; + switch (Range) { + case LangOptions::ComplexRangeKind::CX_Full: + ComplexRangeStr += "full"; + break; + case LangOptions::ComplexRangeKind::CX_Limited: + ComplexRangeStr += "limited"; + break; + case LangOptions::ComplexRangeKind::CX_Fortran: + ComplexRangeStr += "fortran"; + break; + default: + assert(0 && "Unexpected range option"); + } + return ComplexRangeStr; } static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, @@ -2700,6 +2757,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, StringRef FPModel = ""; // -ffp-exception-behavior options: strict, maytrap, ignore StringRef FPExceptionBehavior = ""; + // -ffp-eval-method options: double, extended, source + StringRef FPEvalMethod = ""; const llvm::DenormalMode DefaultDenormalFPMath = TC.getDefaultDenormalModeForType(Args, JA); const llvm::DenormalMode DefaultDenormalFP32Math = @@ -2710,10 +2769,16 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // CUDA and HIP don't rely on the frontend to pass an ffp-contract option. // If one wasn't given by the user, don't pass it here. StringRef FPContract; + StringRef LastSeenFfpContractOption; + bool SeenUnsafeMathModeOption = false; if (!JA.isDeviceOffloading(Action::OFK_Cuda) && !JA.isOffloading(Action::OFK_HIP)) FPContract = "on"; bool StrictFPModel = false; + StringRef Float16ExcessPrecision = ""; + StringRef BFloat16ExcessPrecision = ""; + LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_None; + std::string ComplexRangeStr = ""; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2726,10 +2791,29 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, switch (optID) { default: break; + case options::OPT_fcx_limited_range: { + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Limited); + Range = LangOptions::ComplexRangeKind::CX_Limited; + break; + } + case options::OPT_fno_cx_limited_range: + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full); + Range = LangOptions::ComplexRangeKind::CX_Full; + break; + case options::OPT_fcx_fortran_rules: { + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Fortran); + Range = LangOptions::ComplexRangeKind::CX_Fortran; + break; + } + case options::OPT_fno_cx_fortran_rules: + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full); + Range = LangOptions::ComplexRangeKind::CX_Full; + break; case options::OPT_ffp_model_EQ: { // If -ffp-model= is seen, reset to fno-fast-math HonorINFs = true; HonorNaNs = true; + ApproxFunc = false; // Turning *off* -ffast-math restores the toolchain default. MathErrno = TC.IsMathErrnoDefault(); AssociativeMath = false; @@ -2746,9 +2830,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, StringRef Val = A->getValue(); if (OFastEnabled && !Val.equals("fast")) { // Only -ffp-model=fast is compatible with OFast, ignore. - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-model=" + Val) - << "-Ofast"; + D.Diag(clang::diag::warn_drv_overriding_option) + << Args.MakeArgString("-ffp-model=" + Val) << "-Ofast"; break; } StrictFPModel = false; @@ -2757,7 +2840,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // granular options before being passed into cc1. // Use the gcc option in the switch below. if (!FPModel.empty() && !FPModel.equals(Val)) - D.Diag(clang::diag::warn_drv_overriding_flag_option) + D.Diag(clang::diag::warn_drv_overriding_option) << Args.MakeArgString("-ffp-model=" + FPModel) << Args.MakeArgString("-ffp-model=" + Val); if (Val.equals("fast")) { @@ -2778,9 +2861,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, TrappingMath = true; } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; break; - } + } } switch (optID) { @@ -2806,9 +2889,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!TrappingMathPresent && !FPExceptionBehavior.empty() && !FPExceptionBehavior.equals("strict")) // Warn that previous value of option is overridden. - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) - << "-ftrapping-math"; + D.Diag(clang::diag::warn_drv_overriding_option) + << Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior) + << "-ftrapping-math"; TrappingMath = true; TrappingMathPresent = true; FPExceptionBehavior = "strict"; @@ -2817,9 +2901,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!TrappingMathPresent && !FPExceptionBehavior.empty() && !FPExceptionBehavior.equals("ignore")) // Warn that previous value of option is overridden. - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) - << "-fno-trapping-math"; + D.Diag(clang::diag::warn_drv_overriding_option) + << Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior) + << "-fno-trapping-math"; TrappingMath = false; TrappingMathPresent = true; FPExceptionBehavior = "ignore"; @@ -2837,6 +2922,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_fdenormal_fp_math_EQ: DenormalFPMath = llvm::parseDenormalFPAttribute(A->getValue()); + DenormalFP32Math = DenormalFPMath; if (!DenormalFPMath.isValid()) { D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); @@ -2859,11 +2945,13 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // -ffp-model=precise sets PreciseFPModel to on and Val to // "precise". FPContract is set. ; - } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) + } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off") || + Val.equals("fast-honor-pragmas")) { FPContract = Val; - else + LastSeenFfpContractOption = Val; + } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; break; } @@ -2880,9 +2968,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!TrappingMathPresent && !FPExceptionBehavior.empty() && !FPExceptionBehavior.equals(Val)) // Warn that previous value of option is overridden. - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) - << Args.MakeArgString("-ffp-exception-behavior=" + Val); + D.Diag(clang::diag::warn_drv_overriding_option) + << Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior) + << Args.MakeArgString("-ffp-exception-behavior=" + Val); TrappingMath = TrappingMathPresent = false; if (Val.equals("ignore") || Val.equals("maytrap")) FPExceptionBehavior = Val; @@ -2891,10 +2980,44 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, TrappingMath = TrappingMathPresent = true; } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; + break; + } + + // Validate and pass through -ffp-eval-method option. + case options::OPT_ffp_eval_method_EQ: { + StringRef Val = A->getValue(); + if (Val.equals("double") || Val.equals("extended") || + Val.equals("source")) + FPEvalMethod = Val; + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; break; } + case options::OPT_fexcess_precision_EQ: { + StringRef Val = A->getValue(); + const llvm::Triple::ArchType Arch = TC.getArch(); + if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { + if (Val.equals("standard") || Val.equals("fast")) + Float16ExcessPrecision = Val; + // To make it GCC compatible, allow the value of "16" which + // means disable excess precision, the same meaning than clang's + // equivalent value "none". + else if (Val.equals("16")) + Float16ExcessPrecision = "none"; + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } else { + if (!(Val.equals("standard") || Val.equals("fast"))) + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } + BFloat16ExcessPrecision = Float16ExcessPrecision; + break; + } case options::OPT_ffinite_math_only: HonorINFs = false; HonorNaNs = false; @@ -2911,6 +3034,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ApproxFunc = true; TrappingMath = false; FPExceptionBehavior = ""; + FPContract = "fast"; + SeenUnsafeMathModeOption = true; break; case options::OPT_fno_unsafe_math_optimizations: AssociativeMath = false; @@ -2923,14 +3048,21 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // The target may have opted to flush by default, so force IEEE. DenormalFPMath = llvm::DenormalMode::getIEEE(); DenormalFP32Math = llvm::DenormalMode::getIEEE(); + if (!JA.isDeviceOffloading(Action::OFK_Cuda) && + !JA.isOffloading(Action::OFK_HIP)) { + if (LastSeenFfpContractOption != "") { + FPContract = LastSeenFfpContractOption; + } else if (SeenUnsafeMathModeOption) + FPContract = "on"; + } break; case options::OPT_Ofast: // If -Ofast is the optimization level, then -ffast-math should be enabled if (!OFastEnabled) continue; - LLVM_FALLTHROUGH; - case options::OPT_ffast_math: + [[fallthrough]]; + case options::OPT_ffast_math: { HonorINFs = false; HonorNaNs = false; MathErrno = false; @@ -2940,9 +3072,15 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, SignedZeros = false; TrappingMath = false; RoundingFPMath = false; + FPExceptionBehavior = ""; // If fast-math is set then set the fp-contract mode to fast. FPContract = "fast"; + SeenUnsafeMathModeOption = true; + // ffast-math enables fortran rules for complex multiplication and + // division. + Range = LangOptions::ComplexRangeKind::CX_Limited; break; + } case options::OPT_fno_fast_math: HonorINFs = true; HonorNaNs = true; @@ -2958,13 +3096,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, DenormalFPMath = DefaultDenormalFPMath; DenormalFP32Math = llvm::DenormalMode::getIEEE(); if (!JA.isDeviceOffloading(Action::OFK_Cuda) && - !JA.isOffloading(Action::OFK_HIP)) - if (FPContract == "fast") { + !JA.isOffloading(Action::OFK_HIP)) { + if (LastSeenFfpContractOption != "") { + FPContract = LastSeenFfpContractOption; + } else if (SeenUnsafeMathModeOption) FPContract = "on"; - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << "-ffp-contract=fast" - << "-ffp-contract=on"; - } + } break; } if (StrictFPModel) { @@ -2980,10 +3117,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, else { StrictFPModel = false; FPModel = ""; - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << "-ffp-model=strict" << - ((A->getNumValues() == 0) ? A->getSpelling() - : Args.MakeArgString(A->getSpelling() + A->getValue())); + auto RHS = (A->getNumValues() == 0) + ? A->getSpelling() + : Args.MakeArgString(A->getSpelling() + A->getValue()); + if (RHS != "-ffp-model=strict") + D.Diag(clang::diag::warn_drv_overriding_option) + << "-ffp-model=strict" << RHS; } } @@ -3003,9 +3142,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (MathErrno) CmdArgs.push_back("-fmath-errno"); - if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && - ApproxFunc && !TrappingMath) - CmdArgs.push_back("-menable-unsafe-fp-math"); + if (AssociativeMath && ReciprocalMath && !SignedZeros && ApproxFunc && + !TrappingMath) + CmdArgs.push_back("-funsafe-math-optimizations"); if (!SignedZeros) CmdArgs.push_back("-fno-signed-zeros"); @@ -3050,6 +3189,16 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior)); + if (!FPEvalMethod.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-eval-method=" + FPEvalMethod)); + + if (!Float16ExcessPrecision.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffloat16-excess-precision=" + + Float16ExcessPrecision)); + if (!BFloat16ExcessPrecision.empty()) + CmdArgs.push_back(Args.MakeArgString("-fbfloat16-excess-precision=" + + BFloat16ExcessPrecision)); + ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the @@ -3066,9 +3215,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // Enable -ffp-contract=fast CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); else - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << "-ffp-model=fast" - << Args.MakeArgString("-ffp-contract=" + FPContract); + D.Diag(clang::diag::warn_drv_overriding_option) + << "-ffp-model=fast" + << Args.MakeArgString("-ffp-contract=" + FPContract); } } @@ -3085,17 +3234,24 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow, options::OPT_fstrict_float_cast_overflow, false)) CmdArgs.push_back("-fno-strict-float-cast-overflow"); + + if (Range != LangOptions::ComplexRangeKind::CX_None) + ComplexRangeStr = RenderComplexRangeOption(Range); + if (!ComplexRangeStr.empty()) + CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr)); + if (Args.hasArg(options::OPT_fcx_limited_range)) + CmdArgs.push_back("-fcx-limited-range"); + if (Args.hasArg(options::OPT_fcx_fortran_rules)) + CmdArgs.push_back("-fcx-fortran-rules"); + if (Args.hasArg(options::OPT_fno_cx_limited_range)) + CmdArgs.push_back("-fno-cx-limited-range"); + if (Args.hasArg(options::OPT_fno_cx_fortran_rules)) + CmdArgs.push_back("-fno-cx-fortran-rules"); } static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, const llvm::Triple &Triple, const InputInfo &Input) { - // Enable region store model by default. - CmdArgs.push_back("-analyzer-store=region"); - - // Treat blocks as analysis entry points. - CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); - // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-analyzer-checker=core"); @@ -3113,8 +3269,8 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg"); } - // Disable some unix checkers for PS4. - if (Triple.isPS4CPU()) { + // Disable some unix checkers for PS4/PS5. + if (Triple.isPS()) { CmdArgs.push_back("-analyzer-disable-checker=unix.API"); CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork"); } @@ -3132,7 +3288,7 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, if (types::isCXX(Input.getType())) CmdArgs.push_back("-analyzer-checker=cplusplus"); - if (!Triple.isPS4CPU()) { + if (!Triple.isPS()) { CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets"); @@ -3162,6 +3318,16 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); } +static bool isValidSymbolName(StringRef S) { + if (S.empty()) + return false; + + if (std::isdigit(S[0])) + return false; + + return llvm::all_of(S, [](char C) { return std::isalnum(C) || C == '_'; }); +} + static void RenderSSPOptions(const Driver &D, const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, bool KernelOrKext) { @@ -3188,6 +3354,12 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, StackProtectorLevel = LangOptions::SSPStrong; else if (A->getOption().matches(options::OPT_fstack_protector_all)) StackProtectorLevel = LangOptions::SSPReq; + + if (EffectiveTriple.isBPF() && StackProtectorLevel != LangOptions::SSPOff) { + D.Diag(diag::warn_drv_unsupported_option_for_target) + << A->getSpelling() << EffectiveTriple.getTriple(); + StackProtectorLevel = DefaultStackProtectorLevel; + } } else { StackProtectorLevel = DefaultStackProtectorLevel; } @@ -3200,7 +3372,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, // --param ssp-buffer-size= for (const Arg *A : Args.filtered(options::OPT__param)) { StringRef Str(A->getValue()); - if (Str.startswith("ssp-buffer-size=")) { + if (Str.starts_with("ssp-buffer-size=")) { if (StackProtectorLevel) { CmdArgs.push_back("-stack-protector-buffer-size"); // FIXME: Verify the argument is a valid integer. @@ -3247,7 +3419,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, } } CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+read-tp-hard"); + CmdArgs.push_back("+read-tp-tpidruro"); } if (EffectiveTriple.isAArch64() && Value != "sysreg" && Value != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) @@ -3293,6 +3465,16 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, } A->render(Args, CmdArgs); } + + if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_symbol_EQ)) { + StringRef Value = A->getValue(); + if (!isValidSymbolName(Value)) { + D.Diag(diag::err_drv_argument_only_allowed_with) + << A->getOption().getName() << "legal symbol name"; + return; + } + A->render(Args, CmdArgs); + } } static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args, @@ -3303,12 +3485,11 @@ static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args, return; if (!EffectiveTriple.isX86() && !EffectiveTriple.isSystemZ() && - !EffectiveTriple.isPPC64()) + !EffectiveTriple.isPPC64() && !EffectiveTriple.isAArch64()) return; - if (Args.hasFlag(options::OPT_fstack_clash_protection, - options::OPT_fno_stack_clash_protection, false)) - CmdArgs.push_back("-fstack-clash-protection"); + Args.addOptInFlag(CmdArgs, options::OPT_fstack_clash_protection, + options::OPT_fno_stack_clash_protection); } static void RenderTrivialAutoVarInitOptions(const Driver &D, @@ -3329,7 +3510,7 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D, TrivialAutoVarInit = Val; else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; break; } } @@ -3348,8 +3529,6 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D, } if (!TrivialAutoVarInit.empty()) { - if (TrivialAutoVarInit == "zero" && !Args.hasArg(options::OPT_enable_trivial_var_init_zero)) - D.Diag(diag::err_drv_trivial_auto_var_init_zero_disabled); CmdArgs.push_back( Args.MakeArgString("-ftrivial-auto-var-init=" + TrivialAutoVarInit)); } @@ -3368,6 +3547,20 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D, CmdArgs.push_back( Args.MakeArgString("-ftrivial-auto-var-init-stop-after=" + Val)); } + + if (Arg *A = Args.getLastArg(options::OPT_ftrivial_auto_var_init_max_size)) { + if (!Args.hasArg(options::OPT_ftrivial_auto_var_init) || + StringRef( + Args.getLastArg(options::OPT_ftrivial_auto_var_init)->getValue()) == + "uninitialized") + D.Diag(diag::err_drv_trivial_auto_var_init_max_size_missing_dependency); + A->claim(); + StringRef Val = A->getValue(); + if (std::stoi(Val.str()) <= 0) + D.Diag(diag::err_drv_trivial_auto_var_init_max_size_invalid_value); + CmdArgs.push_back( + Args.MakeArgString("-ftrivial-auto-var-init-max-size=" + Val)); + } } static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs, @@ -3391,6 +3584,9 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs, if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { std::string CLStdStr = std::string("-cl-std=") + A->getValue(); CmdArgs.push_back(Args.MakeArgString(CLStdStr)); + } else if (Arg *A = Args.getLastArg(options::OPT_cl_ext_EQ)) { + std::string CLExtStr = std::string("-cl-ext=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(CLExtStr)); } for (const auto &Arg : ForwardedArguments) @@ -3406,6 +3602,46 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs, } } +static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs, + types::ID InputType) { + const unsigned ForwardedArguments[] = {options::OPT_dxil_validator_version, + options::OPT_D, + options::OPT_I, + options::OPT_S, + options::OPT_O, + options::OPT_emit_llvm, + options::OPT_emit_obj, + options::OPT_disable_llvm_passes, + options::OPT_fnative_half_type, + options::OPT_hlsl_entrypoint}; + if (!types::isHLSL(InputType)) + return; + for (const auto &Arg : ForwardedArguments) + if (const auto *A = Args.getLastArg(Arg)) + A->renderAsInput(Args, CmdArgs); + // Add the default headers if dxc_no_stdinc is not set. + if (!Args.hasArg(options::OPT_dxc_no_stdinc) && + !Args.hasArg(options::OPT_nostdinc)) + CmdArgs.push_back("-finclude-default-header"); +} + +static void RenderOpenACCOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs, types::ID InputType) { + if (!Args.hasArg(options::OPT_fopenacc)) + return; + + CmdArgs.push_back("-fopenacc"); + + if (Arg *A = Args.getLastArg(options::OPT_openacc_macro_override)) { + StringRef Value = A->getValue(); + int Version; + if (!Value.getAsInteger(10, Version)) + A->renderAsInput(Args, CmdArgs); + else + D.Diag(diag::err_drv_clang_unsupported) << Value; + } +} + static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { bool ARCMTEnabled = false; @@ -3492,20 +3728,13 @@ static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, UseBuiltins = false; // Process the -fno-builtin-* options. - for (const auto &Arg : Args) { - const Option &O = Arg->getOption(); - if (!O.matches(options::OPT_fno_builtin_)) - continue; - - Arg->claim(); + for (const Arg *A : Args.filtered(options::OPT_fno_builtin_)) { + A->claim(); // If -fno-builtin is specified, then there's no need to pass the option to // the frontend. - if (!UseBuiltins) - continue; - - StringRef FuncName = Arg->getValue(); - CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName)); + if (UseBuiltins) + A->render(Args, CmdArgs); } // le32-specific flags: @@ -3516,6 +3745,11 @@ static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, } bool Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) { + if (const char *Str = std::getenv("CLANG_MODULE_CACHE_PATH")) { + Twine Path{Str}; + Path.toVector(Result); + return Path.getSingleStringRef() != ""; + } if (llvm::sys::path::cache_directory(Result)) { llvm::sys::path::append(Result, "clang"); llvm::sys::path::append(Result, "ModuleCache"); @@ -3524,10 +3758,14 @@ bool Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) { return false; } -static void RenderModulesOptions(Compilation &C, const Driver &D, +static bool RenderModulesOptions(Compilation &C, const Driver &D, const ArgList &Args, const InputInfo &Input, - const InputInfo &Output, - ArgStringList &CmdArgs, bool &HaveModules) { + const InputInfo &Output, bool HaveStd20, + ArgStringList &CmdArgs) { + bool IsCXX = types::isCXX(Input.getType()); + bool HaveStdCXXModules = IsCXX && HaveStd20; + bool HaveModules = HaveStdCXXModules; + // -fmodules enables the use of precompiled modules (off by default). // Users can pass -fno-cxx-modules to turn off modules support for // C++/Objective-C++ programs. @@ -3535,17 +3773,13 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, options::OPT_fno_cxx_modules, true); - if (AllowedInCXX || !types::isCXX(Input.getType())) { + if (AllowedInCXX || !IsCXX) { CmdArgs.push_back("-fmodules"); HaveClangModules = true; } } HaveModules |= HaveClangModules; - if (Args.hasArg(options::OPT_fmodules_ts)) { - CmdArgs.push_back("-fmodules-ts"); - HaveModules = true; - } // -fmodule-maps enables implicit reading of module map files. By default, // this is enabled if we are using Clang's flavor of precompiled modules. @@ -3554,9 +3788,8 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, CmdArgs.push_back("-fimplicit-module-maps"); // -fmodules-decluse checks that modules used are declared so (off by default) - if (Args.hasFlag(options::OPT_fmodules_decluse, - options::OPT_fno_modules_decluse, false)) - CmdArgs.push_back("-fmodules-decluse"); + Args.addOptInFlag(CmdArgs, options::OPT_fmodules_decluse, + options::OPT_fno_modules_decluse); // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that // all #included headers are part of modules. @@ -3600,12 +3833,6 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, } if (HaveModules) { - // -fprebuilt-module-path specifies where to load the prebuilt module files. - for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) { - CmdArgs.push_back(Args.MakeArgString( - std::string("-fprebuilt-module-path=") + A->getValue())); - A->claim(); - } if (Args.hasFlag(options::OPT_fprebuilt_implicit_modules, options::OPT_fno_prebuilt_implicit_modules, false)) CmdArgs.push_back("-fprebuilt-implicit-modules"); @@ -3638,9 +3865,16 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, // names to precompiled module files (the module is loaded only if used). // The -fmodule-file=<file> form can be used to unconditionally load // precompiled module files (whether used or not). - if (HaveModules) + if (HaveModules || Input.getType() == clang::driver::types::TY_ModuleFile) { Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); - else + + // -fprebuilt-module-path specifies where to load the prebuilt module files. + for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) { + CmdArgs.push_back(Args.MakeArgString( + std::string("-fprebuilt-module-path=") + A->getValue())); + A->claim(); + } + } else Args.ClaimAllArgs(options::OPT_fmodule_file); // When building modules and generating crashdumps, we need to dump a module @@ -3664,38 +3898,59 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); - Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); + if (HaveClangModules) { + Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); - if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { - if (Args.hasArg(options::OPT_fbuild_session_timestamp)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << A->getAsString(Args) << "-fbuild-session-timestamp"; + if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { + if (Args.hasArg(options::OPT_fbuild_session_timestamp)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-fbuild-session-timestamp"; - llvm::sys::fs::file_status Status; - if (llvm::sys::fs::status(A->getValue(), Status)) - D.Diag(diag::err_drv_no_such_file) << A->getValue(); - CmdArgs.push_back(Args.MakeArgString( - "-fbuild-session-timestamp=" + - Twine((uint64_t)std::chrono::duration_cast<std::chrono::seconds>( - Status.getLastModificationTime().time_since_epoch()) - .count()))); - } + llvm::sys::fs::file_status Status; + if (llvm::sys::fs::status(A->getValue(), Status)) + D.Diag(diag::err_drv_no_such_file) << A->getValue(); + CmdArgs.push_back(Args.MakeArgString( + "-fbuild-session-timestamp=" + + Twine((uint64_t)std::chrono::duration_cast<std::chrono::seconds>( + Status.getLastModificationTime().time_since_epoch()) + .count()))); + } + + if (Args.getLastArg( + options::OPT_fmodules_validate_once_per_build_session)) { + if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, + options::OPT_fbuild_session_file)) + D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); - if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { - if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, - options::OPT_fbuild_session_file)) - D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); + Args.AddLastArg(CmdArgs, + options::OPT_fmodules_validate_once_per_build_session); + } + + if (Args.hasFlag(options::OPT_fmodules_validate_system_headers, + options::OPT_fno_modules_validate_system_headers, + ImplicitModules)) + CmdArgs.push_back("-fmodules-validate-system-headers"); Args.AddLastArg(CmdArgs, - options::OPT_fmodules_validate_once_per_build_session); + options::OPT_fmodules_disable_diagnostic_validation); + } else { + Args.ClaimAllArgs(options::OPT_fbuild_session_timestamp); + Args.ClaimAllArgs(options::OPT_fbuild_session_file); + Args.ClaimAllArgs(options::OPT_fmodules_validate_once_per_build_session); + Args.ClaimAllArgs(options::OPT_fmodules_validate_system_headers); + Args.ClaimAllArgs(options::OPT_fno_modules_validate_system_headers); + Args.ClaimAllArgs(options::OPT_fmodules_disable_diagnostic_validation); } - if (Args.hasFlag(options::OPT_fmodules_validate_system_headers, - options::OPT_fno_modules_validate_system_headers, - ImplicitModules)) - CmdArgs.push_back("-fmodules-validate-system-headers"); + // FIXME: We provisionally don't check ODR violations for decls in the global + // module fragment. + CmdArgs.push_back("-fskip-odr-check-in-gmf"); + + // Claim `-fmodule-output` and `-fmodule-output=` to avoid unused warnings. + Args.ClaimAllArgs(options::OPT_fmodule_output); + Args.ClaimAllArgs(options::OPT_fmodule_output_EQ); - Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); + return HaveModules; } static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T, @@ -3730,7 +3985,8 @@ static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T, else CmdArgs.push_back("-fsigned-wchar"); } - } + } else if (T.isOSzOS()) + CmdArgs.push_back("-fno-signed-wchar"); } static void RenderObjCOptions(const ToolChain &TC, const Driver &D, @@ -3855,15 +4111,10 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, options::OPT_fno_caret_diagnostics, CaretDefault)) CmdArgs.push_back("-fno-caret-diagnostics"); - // -fdiagnostics-fixit-info is default, only pass non-default. - if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, - options::OPT_fno_diagnostics_fixit_info)) - CmdArgs.push_back("-fno-diagnostics-fixit-info"); - - // Enable -fdiagnostics-show-option by default. - if (!Args.hasFlag(options::OPT_fdiagnostics_show_option, - options::OPT_fno_diagnostics_show_option, true)) - CmdArgs.push_back("-fno-diagnostics-show-option"); + Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_fixit_info, + options::OPT_fno_diagnostics_fixit_info); + Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_show_option, + options::OPT_fno_diagnostics_show_option); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { @@ -3871,9 +4122,8 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, CmdArgs.push_back(A->getValue()); } - if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, - options::OPT_fno_diagnostics_show_hotness, false)) - CmdArgs.push_back("-fdiagnostics-show-hotness"); + Args.addOptInFlag(CmdArgs, options::OPT_fdiagnostics_show_hotness, + options::OPT_fno_diagnostics_show_hotness); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { @@ -3882,9 +4132,19 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(Opt)); } + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_misexpect_tolerance_EQ)) { + std::string Opt = + std::string("-fdiagnostics-misexpect-tolerance=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } + if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { CmdArgs.push_back("-fdiagnostics-format"); CmdArgs.push_back(A->getValue()); + if (StringRef(A->getValue()) == "sarif" || + StringRef(A->getValue()) == "SARIF") + D.Diag(diag::warn_drv_sarif_format_unstable); } if (const Arg *A = Args.getLastArg( @@ -3901,22 +4161,13 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, // re-parsed to construct this job; claim any possible color diagnostic here // to avoid warn_drv_unused_argument and diagnose bad // OPT_fdiagnostics_color_EQ values. - for (const Arg *A : Args) { - const Option &O = A->getOption(); - if (!O.matches(options::OPT_fcolor_diagnostics) && - !O.matches(options::OPT_fdiagnostics_color) && - !O.matches(options::OPT_fno_color_diagnostics) && - !O.matches(options::OPT_fno_diagnostics_color) && - !O.matches(options::OPT_fdiagnostics_color_EQ)) - continue; - - if (O.matches(options::OPT_fdiagnostics_color_EQ)) { - StringRef Value(A->getValue()); - if (Value != "always" && Value != "never" && Value != "auto") - D.Diag(diag::err_drv_clang_unsupported) - << ("-fdiagnostics-color=" + Value).str(); - } - A->claim(); + Args.getLastArg(options::OPT_fcolor_diagnostics, + options::OPT_fno_color_diagnostics); + if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_color_EQ)) { + StringRef Value(A->getValue()); + if (Value != "always" && Value != "never" && Value != "auto") + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); } if (D.getDiags().getDiagnosticOptions().ShowColors) @@ -3925,9 +4176,11 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, if (Args.hasArg(options::OPT_fansi_escape_codes)) CmdArgs.push_back("-fansi-escape-codes"); - if (!Args.hasFlag(options::OPT_fshow_source_location, - options::OPT_fno_show_source_location)) - CmdArgs.push_back("-fno-show-source-location"); + Args.addOptOutFlag(CmdArgs, options::OPT_fshow_source_location, + options::OPT_fno_show_source_location); + + Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_show_line_numbers, + options::OPT_fno_diagnostics_show_line_numbers); if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) CmdArgs.push_back("-fdiagnostics-absolute-paths"); @@ -3936,14 +4189,11 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, ColumnDefault)) CmdArgs.push_back("-fno-show-column"); - if (!Args.hasFlag(options::OPT_fspell_checking, - options::OPT_fno_spell_checking)) - CmdArgs.push_back("-fno-spell-checking"); + Args.addOptOutFlag(CmdArgs, options::OPT_fspell_checking, + options::OPT_fno_spell_checking); } -enum class DwarfFissionKind { None, Split, Single }; - -static DwarfFissionKind getDebugFissionKind(const Driver &D, +DwarfFissionKind tools::getDebugFissionKind(const Driver &D, const ArgList &Args, Arg *&Arg) { Arg = Args.getLastArg(options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ, options::OPT_gno_split_dwarf); @@ -3960,7 +4210,7 @@ static DwarfFissionKind getDebugFissionKind(const Driver &D, return DwarfFissionKind::Single; D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << Arg->getValue(); + << Arg->getSpelling() << Arg->getValue(); return DwarfFissionKind::None; } @@ -3987,12 +4237,12 @@ static void renderDwarfFormat(const Driver &D, const llvm::Triple &T, DwarfFormatArg->render(Args, CmdArgs); } -static void renderDebugOptions(const ToolChain &TC, const Driver &D, - const llvm::Triple &T, const ArgList &Args, - bool EmitCodeView, bool IRInput, - ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind &DebugInfoKind, - DwarfFissionKind &DwarfFission) { +static void +renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, + const ArgList &Args, bool IRInput, ArgStringList &CmdArgs, + const InputInfo &Output, + llvm::codegenoptions::DebugInfoKind &DebugInfoKind, + DwarfFissionKind &DwarfFission) { if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, options::OPT_fno_debug_info_for_profiling, false) && checkDebugInfoOption( @@ -4027,27 +4277,29 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, } } if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) { - DebugInfoKind = codegenoptions::DebugInfoConstructor; + DebugInfoKind = llvm::codegenoptions::DebugInfoConstructor; // If the last option explicitly specified a debug-info level, use it. if (checkDebugInfoOption(A, Args, D, TC) && A->getOption().matches(options::OPT_gN_Group)) { - DebugInfoKind = DebugLevelToInfoKind(*A); + DebugInfoKind = debugLevelToInfoKind(*A); // For -g0 or -gline-tables-only, drop -gsplit-dwarf. This gets a bit more // complicated if you've disabled inline info in the skeleton CUs // (SplitDWARFInlining) - then there's value in composing split-dwarf and // line-tables-only, so let those compose naturally in that case. - if (DebugInfoKind == codegenoptions::NoDebugInfo || - DebugInfoKind == codegenoptions::DebugDirectivesOnly || - (DebugInfoKind == codegenoptions::DebugLineTablesOnly && + if (DebugInfoKind == llvm::codegenoptions::NoDebugInfo || + DebugInfoKind == llvm::codegenoptions::DebugDirectivesOnly || + (DebugInfoKind == llvm::codegenoptions::DebugLineTablesOnly && SplitDWARFInlining)) DwarfFission = DwarfFissionKind::None; } } // If a debugger tuning argument appeared, remember it. + bool HasDebuggerTuning = false; if (const Arg *A = Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { + HasDebuggerTuning = true; if (checkDebugInfoOption(A, Args, D, TC)) { if (A->getOption().matches(options::OPT_glldb)) DebuggerTuning = llvm::DebuggerKind::LLDB; @@ -4061,29 +4313,23 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, } // If a -gdwarf argument appeared, remember it. - const Arg *GDwarfN = getDwarfNArg(Args); bool EmitDwarf = false; - if (GDwarfN) { - if (checkDebugInfoOption(GDwarfN, Args, D, TC)) - EmitDwarf = true; - else - GDwarfN = nullptr; - } + if (const Arg *A = getDwarfNArg(Args)) + EmitDwarf = checkDebugInfoOption(A, Args, D, TC); - if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) { - if (checkDebugInfoOption(A, Args, D, TC)) - EmitCodeView = true; - } + bool EmitCodeView = false; + if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) + EmitCodeView = checkDebugInfoOption(A, Args, D, TC); // If the user asked for debug info but did not explicitly specify -gcodeview // or -gdwarf, ask the toolchain for the default format. if (!EmitCodeView && !EmitDwarf && - DebugInfoKind != codegenoptions::NoDebugInfo) { + DebugInfoKind != llvm::codegenoptions::NoDebugInfo) { switch (TC.getDefaultDebugFormat()) { - case codegenoptions::DIF_CodeView: + case llvm::codegenoptions::DIF_CodeView: EmitCodeView = true; break; - case codegenoptions::DIF_DWARF: + case llvm::codegenoptions::DIF_DWARF: EmitDwarf = true; break; } @@ -4092,31 +4338,19 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, unsigned RequestedDWARFVersion = 0; // DWARF version requested by the user unsigned EffectiveDWARFVersion = 0; // DWARF version TC can generate. It may // be lower than what the user wanted. - unsigned DefaultDWARFVersion = ParseDebugDefaultVersion(TC, Args); if (EmitDwarf) { - // Start with the platform default DWARF version - RequestedDWARFVersion = TC.GetDefaultDwarfVersion(); - assert(RequestedDWARFVersion && - "toolchain default DWARF version must be nonzero"); - - // If the user specified a default DWARF version, that takes precedence - // over the platform default. - if (DefaultDWARFVersion) - RequestedDWARFVersion = DefaultDWARFVersion; - - // Override with a user-specified DWARF version - if (GDwarfN) - if (auto ExplicitVersion = DwarfVersionNum(GDwarfN->getSpelling())) - RequestedDWARFVersion = ExplicitVersion; + RequestedDWARFVersion = getDwarfVersion(TC, Args); // Clamp effective DWARF version to the max supported by the toolchain. EffectiveDWARFVersion = std::min(RequestedDWARFVersion, TC.getMaxDwarfVersion()); + } else { + Args.ClaimAllArgs(options::OPT_fdebug_default_version); } // -gline-directives-only supported only for the DWARF debug info. if (RequestedDWARFVersion == 0 && - DebugInfoKind == codegenoptions::DebugDirectivesOnly) - DebugInfoKind = codegenoptions::NoDebugInfo; + DebugInfoKind == llvm::codegenoptions::DebugDirectivesOnly) + DebugInfoKind = llvm::codegenoptions::NoDebugInfo; // strict DWARF is set to false by default. But for DBX, we need it to be set // as true by default. @@ -4144,16 +4378,19 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-gno-column-info"); // FIXME: Move backend command line options to the module. - // If -gline-tables-only or -gline-directives-only is the last option it wins. - if (const Arg *A = Args.getLastArg(options::OPT_gmodules)) - if (checkDebugInfoOption(A, Args, D, TC)) { - if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && - DebugInfoKind != codegenoptions::DebugDirectivesOnly) { - DebugInfoKind = codegenoptions::DebugInfoConstructor; + if (Args.hasFlag(options::OPT_gmodules, options::OPT_gno_modules, false)) { + // If -gline-tables-only or -gline-directives-only is the last option it + // wins. + if (checkDebugInfoOption(Args.getLastArg(options::OPT_gmodules), Args, D, + TC)) { + if (DebugInfoKind != llvm::codegenoptions::DebugLineTablesOnly && + DebugInfoKind != llvm::codegenoptions::DebugDirectivesOnly) { + DebugInfoKind = llvm::codegenoptions::DebugInfoConstructor; CmdArgs.push_back("-dwarf-ext-refs"); CmdArgs.push_back("-fmodule-format=obj"); } } + } if (T.isOSBinFormatELF() && SplitDWARFInlining) CmdArgs.push_back("-fsplit-dwarf-inlining"); @@ -4170,13 +4407,13 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug)) (void)checkDebugInfoOption(A, Args, D, TC); - if (DebugInfoKind == codegenoptions::LimitedDebugInfo || - DebugInfoKind == codegenoptions::DebugInfoConstructor) { + if (DebugInfoKind == llvm::codegenoptions::LimitedDebugInfo || + DebugInfoKind == llvm::codegenoptions::DebugInfoConstructor) { if (Args.hasFlag(options::OPT_fno_eliminate_unused_debug_types, options::OPT_feliminate_unused_debug_types, false)) - DebugInfoKind = codegenoptions::UnusedTypeInfo; + DebugInfoKind = llvm::codegenoptions::UnusedTypeInfo; else if (NeedFullDebug) - DebugInfoKind = codegenoptions::FullDebugInfo; + DebugInfoKind = llvm::codegenoptions::FullDebugInfo; } if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source, @@ -4202,29 +4439,30 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, if (EmitCodeView) { CmdArgs.push_back("-gcodeview"); - // Emit codeview type hashes if requested. - if (Args.hasFlag(options::OPT_gcodeview_ghash, - options::OPT_gno_codeview_ghash, false)) { - CmdArgs.push_back("-gcodeview-ghash"); - } - } + Args.addOptInFlag(CmdArgs, options::OPT_gcodeview_ghash, + options::OPT_gno_codeview_ghash); - // Omit inline line tables if requested. - if (Args.hasFlag(options::OPT_gno_inline_line_tables, - options::OPT_ginline_line_tables, false)) { - CmdArgs.push_back("-gno-inline-line-tables"); + Args.addOptOutFlag(CmdArgs, options::OPT_gcodeview_command_line, + options::OPT_gno_codeview_command_line); } + Args.addOptOutFlag(CmdArgs, options::OPT_ginline_line_tables, + options::OPT_gno_inline_line_tables); + // When emitting remarks, we need at least debug lines in the output. if (willEmitRemarks(Args) && - DebugInfoKind <= codegenoptions::DebugDirectivesOnly) - DebugInfoKind = codegenoptions::DebugLineTablesOnly; + DebugInfoKind <= llvm::codegenoptions::DebugDirectivesOnly) + DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly; // Adjust the debug info kind for the given toolchain. TC.adjustDebugInfoKind(DebugInfoKind, Args); + // On AIX, the debugger tuning option can be omitted if it is not explicitly + // set. RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, EffectiveDWARFVersion, - DebuggerTuning); + T.isOSAIX() && !HasDebuggerTuning + ? llvm::DebuggerKind::Default + : DebuggerTuning); // -fdebug-macro turns on macro debug info generation. if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, @@ -4247,8 +4485,8 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, ? "-gpubnames" : "-ggnu-pubnames"); const auto *SimpleTemplateNamesArg = - Args.getLastArg(options::OPT_gsimple_template_names, options::OPT_gno_simple_template_names, - options::OPT_gsimple_template_names_EQ); + Args.getLastArg(options::OPT_gsimple_template_names, + options::OPT_gno_simple_template_names); bool ForwardTemplateParams = DebuggerTuning == llvm::DebuggerKind::SCE; if (SimpleTemplateNamesArg && checkDebugInfoOption(SimpleTemplateNamesArg, Args, D, TC)) { @@ -4256,25 +4494,17 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, if (Opt.matches(options::OPT_gsimple_template_names)) { ForwardTemplateParams = true; CmdArgs.push_back("-gsimple-template-names=simple"); - } else if (Opt.matches(options::OPT_gsimple_template_names_EQ)) { - ForwardTemplateParams = true; - StringRef Value = SimpleTemplateNamesArg->getValue(); - if (Value == "simple") { - CmdArgs.push_back("-gsimple-template-names=simple"); - } else if (Value == "mangled") { - CmdArgs.push_back("-gsimple-template-names=mangled"); - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << Opt.getName() << SimpleTemplateNamesArg->getValue(); - } } } - if (Args.hasFlag(options::OPT_fdebug_ranges_base_address, - options::OPT_fno_debug_ranges_base_address, false)) { - CmdArgs.push_back("-fdebug-ranges-base-address"); + if (const Arg *A = Args.getLastArg(options::OPT_gsrc_hash_EQ)) { + StringRef v = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-gsrc-hash=" + v)); } + Args.addOptInFlag(CmdArgs, options::OPT_fdebug_ranges_base_address, + options::OPT_fno_debug_ranges_base_address); + // -gdwarf-aranges turns on the emission of the aranges section in the // backend. // Always enabled for SCE tuning. @@ -4286,9 +4516,8 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-generate-arange-section"); } - if (Args.hasFlag(options::OPT_fforce_dwarf_frame, - options::OPT_fno_force_dwarf_frame, false)) - CmdArgs.push_back("-fforce-dwarf-frame"); + Args.addOptInFlag(CmdArgs, options::OPT_fforce_dwarf_frame, + options::OPT_fno_force_dwarf_frame); if (Args.hasFlag(options::OPT_fdebug_types_section, options::OPT_fno_debug_types_section, false)) { @@ -4325,6 +4554,98 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, renderDwarfFormat(D, T, Args, CmdArgs, EffectiveDWARFVersion); RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); + + // This controls whether or not we perform JustMyCode instrumentation. + if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) { + if (TC.getTriple().isOSBinFormatELF() || D.IsCLMode()) { + if (DebugInfoKind >= llvm::codegenoptions::DebugInfoConstructor) + CmdArgs.push_back("-fjmc"); + else if (D.IsCLMode()) + D.Diag(clang::diag::warn_drv_jmc_requires_debuginfo) << "/JMC" + << "'/Zi', '/Z7'"; + else + D.Diag(clang::diag::warn_drv_jmc_requires_debuginfo) << "-fjmc" + << "-g"; + } else { + D.Diag(clang::diag::warn_drv_fjmc_for_elf_only); + } + } + + // Add in -fdebug-compilation-dir if necessary. + const char *DebugCompilationDir = + addDebugCompDirArg(Args, CmdArgs, D.getVFS()); + + addDebugPrefixMapArg(D, TC, Args, CmdArgs); + + // Add the output path to the object file for CodeView debug infos. + if (EmitCodeView && Output.isFilename()) + addDebugObjectName(Args, CmdArgs, DebugCompilationDir, + Output.getFilename()); +} + +static void ProcessVSRuntimeLibrary(const ArgList &Args, + ArgStringList &CmdArgs) { + unsigned RTOptionID = options::OPT__SLASH_MT; + + if (Args.hasArg(options::OPT__SLASH_LDd)) + // The /LDd option implies /MTd. The dependent lib part can be overridden, + // but defining _DEBUG is sticky. + RTOptionID = options::OPT__SLASH_MTd; + + if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) + RTOptionID = A->getOption().getID(); + + if (Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + RTOptionID = llvm::StringSwitch<unsigned>(A->getValue()) + .Case("static", options::OPT__SLASH_MT) + .Case("static_dbg", options::OPT__SLASH_MTd) + .Case("dll", options::OPT__SLASH_MD) + .Case("dll_dbg", options::OPT__SLASH_MDd) + .Default(options::OPT__SLASH_MT); + } + + StringRef FlagForCRT; + switch (RTOptionID) { + case options::OPT__SLASH_MD: + if (Args.hasArg(options::OPT__SLASH_LDd)) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + FlagForCRT = "--dependent-lib=msvcrt"; + break; + case options::OPT__SLASH_MDd: + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + FlagForCRT = "--dependent-lib=msvcrtd"; + break; + case options::OPT__SLASH_MT: + if (Args.hasArg(options::OPT__SLASH_LDd)) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-flto-visibility-public-std"); + FlagForCRT = "--dependent-lib=libcmt"; + break; + case options::OPT__SLASH_MTd: + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-flto-visibility-public-std"); + FlagForCRT = "--dependent-lib=libcmtd"; + break; + default: + llvm_unreachable("Unexpected option ID."); + } + + if (Args.hasArg(options::OPT_fms_omit_default_lib)) { + CmdArgs.push_back("-D_VC_NODEFAULTLIB"); + } else { + CmdArgs.push_back(FlagForCRT.data()); + + // This provides POSIX compatibility (maps 'open' to '_open'), which most + // users want. The /Za flag to cl.exe turns this off, but it's not + // implemented in clang. + CmdArgs.push_back("--dependent-lib=oldnames"); + } } void Clang::ConstructJob(Compilation &C, const JobAction &JA, @@ -4344,53 +4665,57 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // CUDA/HIP compilation may have multiple inputs (source file + results of // device-side compilations). OpenMP device jobs also take the host IR as a // second input. Module precompilation accepts a list of header files to - // include as part of the module. All other jobs are expected to have exactly - // one input. + // include as part of the module. API extraction accepts a list of header + // files whose API information is emitted in the output. All other jobs are + // expected to have exactly one input. bool IsCuda = JA.isOffloading(Action::OFK_Cuda); bool IsCudaDevice = JA.isDeviceOffloading(Action::OFK_Cuda); bool IsHIP = JA.isOffloading(Action::OFK_HIP); bool IsHIPDevice = JA.isDeviceOffloading(Action::OFK_HIP); bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); - bool IsOpenMPHost = JA.isHostOffloading(Action::OFK_OpenMP); - bool IsHeaderModulePrecompile = isa<HeaderModulePrecompileJobAction>(JA); + bool IsExtractAPI = isa<ExtractAPIJobAction>(JA); bool IsDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) || JA.isDeviceOffloading(Action::OFK_Host)); + bool IsHostOffloadingAction = + JA.isHostOffloading(Action::OFK_OpenMP) || + (JA.isHostOffloading(C.getActiveOffloadKinds()) && + Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false)); + + bool IsRDCMode = + Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false); bool IsUsingLTO = D.isUsingLTO(IsDeviceOffloadAction); auto LTOMode = D.getLTOMode(IsDeviceOffloadAction); - // A header module compilation doesn't have a main input file, so invent a - // fake one as a placeholder. - const char *ModuleName = [&]{ - auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ); - return ModuleNameArg ? ModuleNameArg->getValue() : ""; - }(); - InputInfo HeaderModuleInput(Inputs[0].getType(), ModuleName, ModuleName); + // Extract API doesn't have a main input file, so invent a fake one as a + // placeholder. + InputInfo ExtractAPIPlaceholderInput(Inputs[0].getType(), "extract-api", + "extract-api"); const InputInfo &Input = - IsHeaderModulePrecompile ? HeaderModuleInput : Inputs[0]; + IsExtractAPI ? ExtractAPIPlaceholderInput : Inputs[0]; - InputInfoList ModuleHeaderInputs; - InputInfoList OpenMPHostInputs; + InputInfoList ExtractAPIInputs; + InputInfoList HostOffloadingInputs; const InputInfo *CudaDeviceInput = nullptr; const InputInfo *OpenMPDeviceInput = nullptr; for (const InputInfo &I : Inputs) { - if (&I == &Input) { - // This is the primary input. - } else if (IsHeaderModulePrecompile && - types::getPrecompiledType(I.getType()) == types::TY_PCH) { - types::ID Expected = HeaderModuleInput.getType(); - if (I.getType() != Expected) { - D.Diag(diag::err_drv_module_header_wrong_kind) + if (&I == &Input || I.getType() == types::TY_Nothing) { + // This is the primary input or contains nothing. + } else if (IsExtractAPI) { + auto ExpectedInputType = ExtractAPIPlaceholderInput.getType(); + if (I.getType() != ExpectedInputType) { + D.Diag(diag::err_drv_extract_api_wrong_kind) << I.getFilename() << types::getTypeName(I.getType()) - << types::getTypeName(Expected); + << types::getTypeName(ExpectedInputType); } - ModuleHeaderInputs.push_back(I); + ExtractAPIInputs.push_back(I); + } else if (IsHostOffloadingAction) { + HostOffloadingInputs.push_back(I); } else if ((IsCuda || IsHIP) && !CudaDeviceInput) { CudaDeviceInput = &I; } else if (IsOpenMPDevice && !OpenMPDeviceInput) { OpenMPDeviceInput = &I; - } else if (IsOpenMPHost) { - OpenMPHostInputs.push_back(I); } else { llvm_unreachable("unexpectedly given multiple inputs"); } @@ -4456,12 +4781,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString( Twine("-target-sdk-version=") + CudaVersionToString(CTC->CudaInstallation.version()))); + // Unsized function arguments used for variadics were introduced in + // CUDA-9.0. We still do not support generating code that actually uses + // variadic arguments yet, but we do need to allow parsing them as + // recent CUDA headers rely on that. + // https://github.com/llvm/llvm-project/issues/58410 + if (CTC->CudaInstallation.version() >= CudaVersion::CUDA_90) + CmdArgs.push_back("-fcuda-allow-variadic-functions"); } } CmdArgs.push_back("-aux-triple"); CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); + + if (JA.isDeviceOffloading(Action::OFK_HIP) && + getToolChain().getTriple().isAMDGPU()) { + // Device side compilation printf + if (Args.getLastArg(options::OPT_mprintf_kind_EQ)) { + CmdArgs.push_back(Args.MakeArgString( + "-mprintf-kind=" + + Args.getLastArgValue(options::OPT_mprintf_kind_EQ))); + // Force compiler error on invalid conversion specifiers + CmdArgs.push_back( + Args.MakeArgString("-Werror=format-invalid-specifier")); + } + } } + // Unconditionally claim the printf option now to avoid unused diagnostic. + if (const Arg *PF = Args.getLastArg(options::OPT_mprintf_kind_EQ)) + PF->claim(); + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { CmdArgs.push_back("-fsycl-is-device"); @@ -4506,6 +4855,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Select the appropriate action. RewriteKind rewriteKind = RK_None; + bool UnifiedLTO = false; + if (IsUsingLTO) { + UnifiedLTO = Args.hasFlag(options::OPT_funified_lto, + options::OPT_fno_unified_lto, Triple.isPS()); + if (UnifiedLTO) + CmdArgs.push_back("-funified-lto"); + } + // If CollectArgsForIntegratedAssembler() isn't called below, claim the args // it claims when not running an assembler. Otherwise, clang would emit // "argument unused" warnings for assembler flags when e.g. adding "-E" to @@ -4534,6 +4891,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } Args.ClaimAllArgs(options::OPT_Wa_COMMA); Args.ClaimAllArgs(options::OPT_Xassembler); + Args.ClaimAllArgs(options::OPT_femit_dwarf_unwind_EQ); } if (isa<AnalyzeJobAction>(JA)) { @@ -4549,6 +4907,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_rewrite_objc) && !Args.hasArg(options::OPT_g_Group)) CmdArgs.push_back("-P"); + else if (JA.getType() == types::TY_PP_CXXHeaderUnit) + CmdArgs.push_back("-fdirectives-only"); } } else if (isa<AssembleJobAction>(JA)) { CmdArgs.push_back("-emit-obj"); @@ -4561,13 +4921,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (JA.getType() == types::TY_Nothing) CmdArgs.push_back("-fsyntax-only"); else if (JA.getType() == types::TY_ModuleFile) - CmdArgs.push_back(IsHeaderModulePrecompile - ? "-emit-header-module" - : "-emit-module-interface"); + CmdArgs.push_back("-emit-module-interface"); + else if (JA.getType() == types::TY_HeaderUnit) + CmdArgs.push_back("-emit-header-unit"); else CmdArgs.push_back("-emit-pch"); } else if (isa<VerifyPCHJobAction>(JA)) { CmdArgs.push_back("-verify-pch"); + } else if (isa<ExtractAPIJobAction>(JA)) { + assert(JA.getType() == types::TY_API_INFO && + "Extract API actions must generate a API information."); + CmdArgs.push_back("-extract-api"); + if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ)) + ProductNameArg->render(Args, CmdArgs); + if (Arg *ExtractAPIIgnoresFileArg = + Args.getLastArg(options::OPT_extract_api_ignores_EQ)) + ExtractAPIIgnoresFileArg->render(Args, CmdArgs); } else { assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && "Invalid action for clang tool."); @@ -4606,8 +4975,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (JA.getType() == types::TY_RewrittenLegacyObjC) { CmdArgs.push_back("-rewrite-objc"); rewriteKind = RK_Fragile; - } else if (JA.getType() == types::TY_API_INFO) { - CmdArgs.push_back("-extract-api"); } else { assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!"); } @@ -4619,29 +4986,48 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (JA.getType() == types::TY_LLVM_BC) CmdArgs.push_back("-emit-llvm-uselists"); - if (IsUsingLTO && !Args.hasArg(options::OPT_fopenmp_new_driver)) { - // Only AMDGPU supports device-side LTO. - if (IsDeviceOffloadAction && !Triple.isAMDGPU()) { + if (IsUsingLTO) { + if (IsDeviceOffloadAction && !JA.isDeviceOffloading(Action::OFK_OpenMP) && + !Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false) && + !Triple.isAMDGPU()) { D.Diag(diag::err_drv_unsupported_opt_for_target) << Args.getLastArg(options::OPT_foffload_lto, options::OPT_foffload_lto_EQ) ->getAsString(Args) << Triple.getTriple(); + } else if (Triple.isNVPTX() && !IsRDCMode && + JA.isDeviceOffloading(Action::OFK_Cuda)) { + D.Diag(diag::err_drv_unsupported_opt_for_language_mode) + << Args.getLastArg(options::OPT_foffload_lto, + options::OPT_foffload_lto_EQ) + ->getAsString(Args) + << "-fno-gpu-rdc"; } else { assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); CmdArgs.push_back(Args.MakeArgString( Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); - CmdArgs.push_back("-flto-unit"); + // PS4 uses the legacy LTO API, which does not support some of the + // features enabled by -flto-unit. + if (!RawTriple.isPS4() || + (D.getLTOMode() == LTOK_Full) || !UnifiedLTO) + CmdArgs.push_back("-flto-unit"); } } } + Args.AddLastArg(CmdArgs, options::OPT_dumpdir); + if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) { if (!types::isLLVMIR(Input.getType())) D.Diag(diag::err_drv_arg_requires_bitcode_input) << A->getAsString(Args); Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); } + if (Triple.isPPC()) + Args.addOptInFlag(CmdArgs, options::OPT_mregnames, + options::OPT_mno_regnames); + if (Args.getLastArg(options::OPT_fthin_link_bitcode_EQ)) Args.AddLastArg(CmdArgs, options::OPT_fthin_link_bitcode_EQ); @@ -4655,6 +5041,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, !MemProfArg->getOption().matches(options::OPT_fno_memory_profile)) MemProfArg->render(Args, CmdArgs); + if (auto *MemProfUseArg = + Args.getLastArg(options::OPT_fmemory_profile_use_EQ)) { + if (MemProfArg) + D.Diag(diag::err_drv_argument_not_allowed_with) + << MemProfUseArg->getAsString(Args) << MemProfArg->getAsString(Args); + if (auto *PGOInstrArg = Args.getLastArg(options::OPT_fprofile_generate, + options::OPT_fprofile_generate_EQ)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << MemProfUseArg->getAsString(Args) << PGOInstrArg->getAsString(Args); + MemProfUseArg->render(Args, CmdArgs); + } + // Embed-bitcode option. // Only white-listed flags below are allowed to be embedded. if (C.getDriver().embedBitcodeInObject() && !IsUsingLTO && @@ -4717,9 +5115,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(diag::err_drv_unsupported_embed_bitcode) << A->getSpelling(); // Render the CodeGen options that need to be passed. - if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, - options::OPT_fno_optimize_sibling_calls)) - CmdArgs.push_back("-mdisable-tail-calls"); + Args.addOptOutFlag(CmdArgs, options::OPT_foptimize_sibling_calls, + options::OPT_fno_optimize_sibling_calls); RenderFloatingPointOptions(TC, D, isOptimizationLevelFast(Args), Args, CmdArgs, JA); @@ -4769,7 +5166,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::AtFileUTF8(), D.getClangProgramPath(), - CmdArgs, Inputs, Output)); + CmdArgs, Inputs, Output, D.getPrependArg())); return; } @@ -4789,9 +5186,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const bool IsAssertBuild = true; #endif - // Disable the verification pass in -asserts builds. - if (!IsAssertBuild) + // Disable the verification pass in asserts builds unless otherwise specified. + if (Args.hasFlag(options::OPT_fno_verify_intermediate_code, + options::OPT_fverify_intermediate_code, !IsAssertBuild)) { CmdArgs.push_back("-disable-llvm-verifier"); + } // Discard value names in assert builds unless otherwise specified. if (Args.hasFlag(options::OPT_fdiscard_value_names, @@ -4829,13 +5228,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Since we can't access frontend flags through hasArg, let's manually iterate // through them. bool FoundAnalyzerConfig = false; - for (auto Arg : Args.filtered(options::OPT_Xclang)) + for (auto *Arg : Args.filtered(options::OPT_Xclang)) if (StringRef(Arg->getValue()) == "-analyzer-config") { FoundAnalyzerConfig = true; break; } if (!FoundAnalyzerConfig) - for (auto Arg : Args.filtered(options::OPT_Xanalyzer)) + for (auto *Arg : Args.filtered(options::OPT_Xanalyzer)) if (StringRef(Arg->getValue()) == "-analyzer-config") { FoundAnalyzerConfig = true; break; @@ -4868,10 +5267,58 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Twine(std::min(Value, 65536u)))); } + if (Triple.isOSzOS()) { + // On z/OS some of the system header feature macros need to + // be defined to enable most cross platform projects to build + // successfully. Ths include the libc++ library. A + // complicating factor is that users can define these + // macros to the same or different values. We need to add + // the definition for these macros to the compilation command + // if the user hasn't already defined them. + + auto findMacroDefinition = [&](const std::string &Macro) { + auto MacroDefs = Args.getAllArgValues(options::OPT_D); + return llvm::any_of(MacroDefs, [&](const std::string &M) { + return M == Macro || M.find(Macro + '=') != std::string::npos; + }); + }; + + // _UNIX03_WITHDRAWN is required for libcxx & porting. + if (!findMacroDefinition("_UNIX03_WITHDRAWN")) + CmdArgs.push_back("-D_UNIX03_WITHDRAWN"); + // _OPEN_DEFAULT is required for XL compat + if (!findMacroDefinition("_OPEN_DEFAULT")) + CmdArgs.push_back("-D_OPEN_DEFAULT"); + if (D.CCCIsCXX() || types::isCXX(Input.getType())) { + // _XOPEN_SOURCE=600 is required for libcxx. + if (!findMacroDefinition("_XOPEN_SOURCE")) + CmdArgs.push_back("-D_XOPEN_SOURCE=600"); + } + } + llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(TC, Args); + Arg *LastPICDataRelArg = + Args.getLastArg(options::OPT_mno_pic_data_is_text_relative, + options::OPT_mpic_data_is_text_relative); + bool NoPICDataIsTextRelative = false; + if (LastPICDataRelArg) { + if (LastPICDataRelArg->getOption().matches( + options::OPT_mno_pic_data_is_text_relative)) { + NoPICDataIsTextRelative = true; + if (!PICLevel) + D.Diag(diag::err_drv_argument_only_allowed_with) + << "-mno-pic-data-is-text-relative" + << "-fpic/-fpie"; + } + if (!Triple.isSystemZ()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << (NoPICDataIsTextRelative ? "-mno-pic-data-is-text-relative" + : "-mpic-data-is-text-relative") + << RawTriple.str(); + } bool IsROPI = RelocationModel == llvm::Reloc::ROPI || RelocationModel == llvm::Reloc::ROPI_RWPI; @@ -4900,6 +5347,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); if (IsPIE) CmdArgs.push_back("-pic-is-pie"); + if (NoPICDataIsTextRelative) + CmdArgs.push_back("-mcmodel=medium"); } if (RelocationModel == llvm::Reloc::ROPI || @@ -4956,37 +5405,41 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - Args.AddLastArg(CmdArgs, options::OPT_fveclib); + if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { + StringRef Name = A->getValue(); + if (Name == "SVML") { + if (Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } else if (Name == "LIBMVEC-X86") { + if (Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } else if (Name == "SLEEF" || Name == "ArmPL") { + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_be) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } + A->render(Args, CmdArgs); + } if (Args.hasFlag(options::OPT_fmerge_all_constants, options::OPT_fno_merge_all_constants, false)) CmdArgs.push_back("-fmerge-all-constants"); - if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks, - options::OPT_fdelete_null_pointer_checks, false)) - CmdArgs.push_back("-fno-delete-null-pointer-checks"); + Args.addOptOutFlag(CmdArgs, options::OPT_fdelete_null_pointer_checks, + options::OPT_fno_delete_null_pointer_checks); // LLVM Code Generator Options. - for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file_EQ)) { - StringRef Map = A->getValue(); - if (!llvm::sys::fs::exists(Map)) { - D.Diag(diag::err_drv_no_such_file) << Map; - } else { - A->render(Args, CmdArgs); - A->claim(); - } - } - - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_vec_extabi, - options::OPT_mabi_EQ_vec_default)) { - if (!Triple.isOSAIX()) + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_quadword_atomics)) { + if (!Triple.isOSAIX() || Triple.isPPC32()) D.Diag(diag::err_drv_unsupported_opt_for_target) - << A->getSpelling() << RawTriple.str(); - if (A->getOption().getID() == options::OPT_mabi_EQ_vec_extabi) - CmdArgs.push_back("-mabi=vec-extabi"); - else - CmdArgs.push_back("-mabi=vec-default"); + << A->getSpelling() << RawTriple.str(); + CmdArgs.push_back("-mabi=quadword-atomics"); } if (Arg *A = Args.getLastArg(options::OPT_mlong_double_128)) { @@ -4998,27 +5451,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) { - StringRef v = A->getValue(); - // FIXME: Validate the argument here so we don't produce meaningless errors - // about -fwarn-stack-size=. - if (v.empty()) - D.Diag(diag::err_drv_missing_argument) << A->getSpelling() << 1; + StringRef V = A->getValue(), V1 = V; + unsigned Size; + if (V1.consumeInteger(10, Size) || !V1.empty()) + D.Diag(diag::err_drv_invalid_argument_to_option) + << V << A->getOption().getName(); else - CmdArgs.push_back(Args.MakeArgString("-fwarn-stack-size=" + v)); - A->claim(); + CmdArgs.push_back(Args.MakeArgString("-fwarn-stack-size=" + V)); } - if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables, - true)) - CmdArgs.push_back("-fno-jump-tables"); - - if (Args.hasFlag(options::OPT_fprofile_sample_accurate, - options::OPT_fno_profile_sample_accurate, false)) - CmdArgs.push_back("-fprofile-sample-accurate"); - - if (!Args.hasFlag(options::OPT_fpreserve_as_comments, - options::OPT_fno_preserve_as_comments, true)) - CmdArgs.push_back("-fno-preserve-as-comments"); + Args.addOptOutFlag(CmdArgs, options::OPT_fjump_tables, + options::OPT_fno_jump_tables); + Args.addOptInFlag(CmdArgs, options::OPT_fprofile_sample_accurate, + options::OPT_fno_profile_sample_accurate); + Args.addOptOutFlag(CmdArgs, options::OPT_fpreserve_as_comments, + options::OPT_fno_preserve_as_comments); if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { CmdArgs.push_back("-mregparm"); @@ -5051,8 +5498,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) - CmdArgs.push_back("-fdefault-calling-conv=stdcall"); + if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) { + if (Triple.getArch() == llvm::Triple::m68k) + CmdArgs.push_back("-fdefault-calling-conv=rtdcall"); + else + CmdArgs.push_back("-fdefault-calling-conv=stdcall"); + } if (Args.hasArg(options::OPT_fenable_matrix)) { // enable-matrix is needed by both the LangOpts and by LLVM. @@ -5078,9 +5529,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(FPKeepKindStr && "unknown FramePointerKind"); CmdArgs.push_back(FPKeepKindStr); - if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, - options::OPT_fno_zero_initialized_in_bss, true)) - CmdArgs.push_back("-fno-zero-initialized-in-bss"); + Args.addOptOutFlag(CmdArgs, options::OPT_fzero_initialized_in_bss, + options::OPT_fno_zero_initialized_in_bss); bool OFastEnabled = isOptimizationLevelFast(Args); // If -Ofast is the optimization level, then -fstrict-aliasing should be @@ -5094,31 +5544,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_strict_aliasing, TBAAOnByDefault)) CmdArgs.push_back("-relaxed-aliasing"); if (!Args.hasFlag(options::OPT_fstruct_path_tbaa, - options::OPT_fno_struct_path_tbaa)) + options::OPT_fno_struct_path_tbaa, true)) CmdArgs.push_back("-no-struct-path-tbaa"); - if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, - false)) - CmdArgs.push_back("-fstrict-enums"); - if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return, - true)) - CmdArgs.push_back("-fno-strict-return"); - if (Args.hasFlag(options::OPT_fallow_editor_placeholders, - options::OPT_fno_allow_editor_placeholders, false)) - CmdArgs.push_back("-fallow-editor-placeholders"); - if (Args.hasFlag(options::OPT_fstrict_vtable_pointers, - options::OPT_fno_strict_vtable_pointers, - false)) - CmdArgs.push_back("-fstrict-vtable-pointers"); - if (Args.hasFlag(options::OPT_fforce_emit_vtables, - options::OPT_fno_force_emit_vtables, - false)) - CmdArgs.push_back("-fforce-emit-vtables"); - if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, - options::OPT_fno_optimize_sibling_calls)) - CmdArgs.push_back("-mdisable-tail-calls"); - if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls, - options::OPT_fescaping_block_tail_calls, false)) - CmdArgs.push_back("-fno-escaping-block-tail-calls"); + Args.addOptInFlag(CmdArgs, options::OPT_fstrict_enums, + options::OPT_fno_strict_enums); + Args.addOptOutFlag(CmdArgs, options::OPT_fstrict_return, + options::OPT_fno_strict_return); + Args.addOptInFlag(CmdArgs, options::OPT_fallow_editor_placeholders, + options::OPT_fno_allow_editor_placeholders); + Args.addOptInFlag(CmdArgs, options::OPT_fstrict_vtable_pointers, + options::OPT_fno_strict_vtable_pointers); + Args.addOptInFlag(CmdArgs, options::OPT_fforce_emit_vtables, + options::OPT_fno_force_emit_vtables); + Args.addOptOutFlag(CmdArgs, options::OPT_foptimize_sibling_calls, + options::OPT_fno_optimize_sibling_calls); + Args.addOptOutFlag(CmdArgs, options::OPT_fescaping_block_tail_calls, + options::OPT_fno_escaping_block_tail_calls); Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses, options::OPT_fno_fine_grained_bitfield_accesses); @@ -5126,10 +5567,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables, options::OPT_fno_experimental_relative_cxx_abi_vtables); + Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti, + options::OPT_fno_experimental_omit_vtable_rtti); + // Handle segmented stacks. - if (Args.hasFlag(options::OPT_fsplit_stack, options::OPT_fno_split_stack, - false)) - CmdArgs.push_back("-fsplit-stack"); + Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack, + options::OPT_fno_split_stack); // -fprotect-parens=0 is default. if (Args.hasFlag(options::OPT_fprotect_parens, @@ -5209,8 +5652,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Enable -mconstructor-aliases except on darwin, where we have to work around - // a linker bug (see <rdar://problem/7651567>), and CUDA device code, where - // aliases aren't supported. + // a linker bug (see https://openradar.appspot.com/7198997), and CUDA device + // code, where aliases aren't supported. if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX()) CmdArgs.push_back("-mconstructor-aliases"); @@ -5224,14 +5667,28 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mms-bitfields"); } + if (Triple.isWindowsGNUEnvironment()) { + Args.addOptOutFlag(CmdArgs, options::OPT_fauto_import, + options::OPT_fno_auto_import); + } + + if (Args.hasFlag(options::OPT_fms_volatile, options::OPT_fno_ms_volatile, + Triple.isX86() && D.IsCLMode())) + CmdArgs.push_back("-fms-volatile"); + // Non-PIC code defaults to -fdirect-access-external-data while PIC code // defaults to -fno-direct-access-external-data. Pass the option if different // from the default. if (Arg *A = Args.getLastArg(options::OPT_fdirect_access_external_data, - options::OPT_fno_direct_access_external_data)) + options::OPT_fno_direct_access_external_data)) { if (A->getOption().matches(options::OPT_fdirect_access_external_data) != (PICLevel == 0)) A->render(Args, CmdArgs); + } else if (PICLevel == 0 && Triple.isLoongArch()) { + // Some targets default to -fno-direct-access-external-data even for + // -fno-pic. + CmdArgs.push_back("-fno-direct-access-external-data"); + } if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) { CmdArgs.push_back("-fno-plt"); @@ -5246,21 +5703,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Freestanding) CmdArgs.push_back("-ffreestanding"); + Args.AddLastArg(CmdArgs, options::OPT_fno_knr_functions); + // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. auto SanitizeArgs = TC.getSanitizerArgs(Args); + + bool IsAsyncUnwindTablesDefault = + TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Asynchronous; + bool IsSyncUnwindTablesDefault = + TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Synchronous; + bool AsyncUnwindTables = Args.hasFlag( options::OPT_fasynchronous_unwind_tables, options::OPT_fno_asynchronous_unwind_tables, - (TC.IsUnwindTablesDefault(Args) || SanitizeArgs.needsUnwindTables()) && + (IsAsyncUnwindTablesDefault || SanitizeArgs.needsUnwindTables()) && !Freestanding); - bool UnwindTables = Args.hasFlag(options::OPT_funwind_tables, - options::OPT_fno_unwind_tables, false); + bool UnwindTables = + Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, + IsSyncUnwindTablesDefault && !Freestanding); if (AsyncUnwindTables) CmdArgs.push_back("-funwind-tables=2"); else if (UnwindTables) - CmdArgs.push_back("-funwind-tables=1"); + CmdArgs.push_back("-funwind-tables=1"); // Prepare `-aux-target-cpu` and `-aux-target-feature` unless // `--gpu-use-aux-triple-only` is specified. @@ -5280,20 +5746,78 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind()); - // FIXME: Handle -mtune=. - (void)Args.hasArg(options::OPT_mtune_EQ); - if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { StringRef CM = A->getValue(); - if (CM == "small" || CM == "kernel" || CM == "medium" || CM == "large" || - CM == "tiny") { - if (Triple.isOSAIX() && CM == "medium") - CmdArgs.push_back("-mcmodel=large"); - else - A->render(Args, CmdArgs); + bool Ok = false; + if (Triple.isOSAIX() && CM == "medium") + CM = "large"; + if (Triple.isAArch64(64)) { + Ok = CM == "tiny" || CM == "small" || CM == "large"; + if (CM == "large" && RelocationModel != llvm::Reloc::Static) + D.Diag(diag::err_drv_argument_only_allowed_with) + << A->getAsString(Args) << "-fno-pic"; + } else if (Triple.isLoongArch()) { + if (CM == "extreme" && + Args.hasFlagNoClaim(options::OPT_fplt, options::OPT_fno_plt, false)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-fplt"; + Ok = CM == "normal" || CM == "medium" || CM == "extreme"; + // Convert to LLVM recognizable names. + if (Ok) + CM = llvm::StringSwitch<StringRef>(CM) + .Case("normal", "small") + .Case("extreme", "large") + .Default(CM); + } else if (Triple.isPPC64() || Triple.isOSAIX()) { + Ok = CM == "small" || CM == "medium" || CM == "large"; + } else if (Triple.isRISCV()) { + if (CM == "medlow") + CM = "small"; + else if (CM == "medany") + CM = "medium"; + Ok = CM == "small" || CM == "medium"; + } else if (Triple.getArch() == llvm::Triple::x86_64) { + Ok = llvm::is_contained({"small", "kernel", "medium", "large", "tiny"}, + CM); + } else if (Triple.isNVPTX() || Triple.isAMDGPU()) { + // NVPTX/AMDGPU does not care about the code model and will accept + // whatever works for the host. + Ok = true; + } else if (Triple.isSPARC64()) { + if (CM == "medlow") + CM = "small"; + else if (CM == "medmid") + CM = "medium"; + else if (CM == "medany") + CM = "large"; + Ok = CM == "small" || CM == "medium" || CM == "large"; + } + if (Ok) { + CmdArgs.push_back(Args.MakeArgString("-mcmodel=" + CM)); } else { - D.Diag(diag::err_drv_invalid_argument_to_option) - << CM << A->getOption().getName(); + D.Diag(diag::err_drv_unsupported_option_argument_for_target) + << A->getSpelling() << CM << TripleStr; + } + } + + if (Triple.getArch() == llvm::Triple::x86_64) { + bool IsMediumCM = false; + bool IsLargeCM = false; + if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { + IsMediumCM = StringRef(A->getValue()) == "medium"; + IsLargeCM = StringRef(A->getValue()) == "large"; + } + if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) { + if (!IsMediumCM && !IsLargeCM) { + D.Diag(diag::warn_drv_large_data_threshold_invalid_code_model) + << A->getOption().getRenderName(); + } else { + A->render(Args, CmdArgs); + } + } else if (IsMediumCM) { + CmdArgs.push_back("-mlarge-data-threshold=65536"); + } else if (IsLargeCM) { + CmdArgs.push_back("-mlarge-data-threshold=0"); } } @@ -5310,6 +5834,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_mtls_size_EQ); } + if (isTLSDESCEnabled(TC, Args)) + CmdArgs.push_back("-enable-tlsdesc"); + // Add the target cpu std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ false); if (!CPU.empty()) { @@ -5319,41 +5846,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs); - // FIXME: For now we want to demote any errors to warnings, when they have - // been raised for asking the wrong question of scalable vectors, such as - // asking for the fixed number of elements. This may happen because code that - // is not yet ported to work for scalable vectors uses the wrong interfaces, - // whereas the behaviour is actually correct. Emitting a warning helps bring - // up scalable vector support in an incremental way. When scalable vector - // support is stable enough, all uses of wrong interfaces should be considered - // as errors, but until then, we can live with a warning being emitted by the - // compiler. This way, Clang can be used to compile code with scalable vectors - // and identify possible issues. - if (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || - isa<BackendJobAction>(JA)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-treat-scalable-fixed-error-as-warning"); - } - - // These two are potentially updated by AddClangCLArgs. - codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; - bool EmitCodeView = false; - // Add clang-cl arguments. types::ID InputType = Input.getType(); if (D.IsCLMode()) - AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); + AddClangCLArgs(Args, InputType, CmdArgs); + llvm::codegenoptions::DebugInfoKind DebugInfoKind = + llvm::codegenoptions::NoDebugInfo; DwarfFissionKind DwarfFission = DwarfFissionKind::None; - renderDebugOptions(TC, D, RawTriple, Args, EmitCodeView, - types::isLLVMIR(InputType), CmdArgs, DebugInfoKind, - DwarfFission); + renderDebugOptions(TC, D, RawTriple, Args, types::isLLVMIR(InputType), + CmdArgs, Output, DebugInfoKind, DwarfFission); // Add the split debug info name to the command lines here so we // can propagate it to the backend. bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) && (TC.getTriple().isOSBinFormatELF() || - TC.getTriple().isOSBinFormatWasm()) && + TC.getTriple().isOSBinFormatWasm() || + TC.getTriple().isOSBinFormatCOFF()) && (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)); if (SplitDWARF) { @@ -5401,12 +5910,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddAllArgs(CmdArgs, options::OPT_fshow_skipped_includes); - if (D.CCPrintHeaders && !D.CCGenDiagnostics) { + if (D.CCPrintHeadersFormat && !D.CCGenDiagnostics) { CmdArgs.push_back("-header-include-file"); CmdArgs.push_back(!D.CCPrintHeadersFilename.empty() ? D.CCPrintHeadersFilename.c_str() : "-"); CmdArgs.push_back("-sys-header-deps"); + CmdArgs.push_back(Args.MakeArgString( + "-header-include-format=" + + std::string(headerIncludeFormatKindToString(D.CCPrintHeadersFormat)))); + CmdArgs.push_back( + Args.MakeArgString("-header-include-filtering=" + + std::string(headerIncludeFilteringKindToString( + D.CCPrintHeadersFiltering)))); } Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); @@ -5442,7 +5958,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef Val = A->getValue(); if (Triple.isX86() && Triple.isOSBinFormatELF()) { if (Val != "all" && Val != "labels" && Val != "none" && - !Val.startswith("list=")) + !Val.starts_with("list=")) D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); else @@ -5464,27 +5980,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fdata-sections"); } - if (!Args.hasFlag(options::OPT_funique_section_names, - options::OPT_fno_unique_section_names, true)) - CmdArgs.push_back("-fno-unique-section-names"); - - if (Args.hasFlag(options::OPT_funique_internal_linkage_names, - options::OPT_fno_unique_internal_linkage_names, false)) - CmdArgs.push_back("-funique-internal-linkage-names"); - - if (Args.hasFlag(options::OPT_funique_basic_block_section_names, - options::OPT_fno_unique_basic_block_section_names, false)) - CmdArgs.push_back("-funique-basic-block-section-names"); + Args.addOptOutFlag(CmdArgs, options::OPT_funique_section_names, + options::OPT_fno_unique_section_names); + Args.addOptInFlag(CmdArgs, options::OPT_funique_internal_linkage_names, + options::OPT_fno_unique_internal_linkage_names); + Args.addOptInFlag(CmdArgs, options::OPT_funique_basic_block_section_names, + options::OPT_fno_unique_basic_block_section_names); + Args.addOptInFlag(CmdArgs, options::OPT_fconvergent_functions, + options::OPT_fno_convergent_functions); if (Arg *A = Args.getLastArg(options::OPT_fsplit_machine_functions, options::OPT_fno_split_machine_functions)) { - // This codegen pass is only available on x86-elf targets. - if (Triple.isX86() && Triple.isOSBinFormatELF()) { - if (A->getOption().matches(options::OPT_fsplit_machine_functions)) + if (!A->getOption().matches(options::OPT_fno_split_machine_functions)) { + // This codegen pass is only available on x86 and AArch64 ELF targets. + if ((Triple.isX86() || Triple.isAArch64()) && Triple.isOSBinFormatELF()) A->render(Args, CmdArgs); - } else { - D.Diag(diag::err_drv_unsupported_opt_for_target) - << A->getAsString(Args) << TripleStr; + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; } } @@ -5496,15 +6009,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // for sampling, overhead of call arc collection is way too high and there's // no way to collect the output. if (!Triple.isNVPTX() && !Triple.isAMDGCN()) - addPGOAndCoverageFlags(TC, C, D, Output, Args, SanitizeArgs, CmdArgs); + addPGOAndCoverageFlags(TC, C, JA, Output, Args, SanitizeArgs, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ); - // Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled. - if (RawTriple.isPS4CPU() && + if (getLastProfileSampleUseArg(Args) && + Args.hasArg(options::OPT_fsample_profile_use_profi)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-sample-profile-use-profi"); + } + + // Add runtime flag for PS4/PS5 when PGO, coverage, or sanitizers are enabled. + if (RawTriple.isPS() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - PS4cpu::addProfileRTArgs(TC, Args, CmdArgs); - PS4cpu::addSanitizerArgs(TC, Args, CmdArgs); + PScpu::addProfileRTArgs(TC, Args, CmdArgs); + PScpu::addSanitizerArgs(TC, Args, CmdArgs); } // Pass options for controlling the default header search paths. @@ -5586,15 +6105,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } + Args.AddAllArgs(CmdArgs, options::OPT_Wsystem_headers_in_module_EQ); + if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) CmdArgs.push_back("-pedantic"); Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); Args.AddLastArg(CmdArgs, options::OPT_w); - // Fixed point flags - if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point, - /*Default=*/false)) - Args.AddLastArg(CmdArgs, options::OPT_ffixed_point); + Args.addOptInFlag(CmdArgs, options::OPT_ffixed_point, + options::OPT_fno_fixed_point); if (Arg *A = Args.getLastArg(options::OPT_fcxx_abi_EQ)) A->render(Args, CmdArgs); @@ -5602,6 +6121,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables, options::OPT_fno_experimental_relative_cxx_abi_vtables); + Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti, + options::OPT_fno_experimental_omit_vtable_rtti); + if (Arg *A = Args.getLastArg(options::OPT_ffuchsia_api_level_EQ)) A->render(Args, CmdArgs); @@ -5647,11 +6169,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs, options::OPT_fno_trigraphs); - - // HIP headers has minimum C++ standard requirements. Therefore set the - // default language standard. - if (IsHIP) - CmdArgs.push_back(IsWindowsMSVC ? "-std=c++14" : "-std=c++11"); } // GCC's behavior for -Wwrite-strings is a bit strange: @@ -5694,32 +6211,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!ShouldEnableAutolink(Args, TC, JA)) CmdArgs.push_back("-fno-autolink"); - // Add in -fdebug-compilation-dir if necessary. - const char *DebugCompilationDir = - addDebugCompDirArg(Args, CmdArgs, D.getVFS()); - - addDebugPrefixMapArg(D, Args, CmdArgs); - - if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, - options::OPT_ftemplate_depth_EQ)) { - CmdArgs.push_back("-ftemplate-depth"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) { - CmdArgs.push_back("-foperator-arrow-depth"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) { - CmdArgs.push_back("-fconstexpr-depth"); - CmdArgs.push_back(A->getValue()); - } + Args.AddLastArg(CmdArgs, options::OPT_ftemplate_depth_EQ); + Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ); - if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) { - CmdArgs.push_back("-fconstexpr-steps"); - CmdArgs.push_back(A->getValue()); - } + Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library); if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter)) CmdArgs.push_back("-fexperimental-new-constant-interpreter"); @@ -5746,7 +6243,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, "standalone", "objc", "swift", "swift-5.0", "swift-4.2", "swift-4.1", }; - if (find(kCFABIs, StringRef(A->getValue())) == std::end(kCFABIs)) + if (!llvm::is_contained(kCFABIs, StringRef(A->getValue()))) D.Diag(diag::err_drv_invalid_cf_runtime_abi) << A->getValue(); else A->render(Args, CmdArgs); @@ -5762,9 +6259,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } - if (Args.hasFlag(options::OPT_fstack_size_section, - options::OPT_fno_stack_size_section, RawTriple.isPS4())) - CmdArgs.push_back("-fstack-size-section"); + Args.addOptInFlag(CmdArgs, options::OPT_fstack_size_section, + options::OPT_fno_stack_size_section); if (Args.hasArg(options::OPT_fstack_usage)) { CmdArgs.push_back("-stack-usage-file"); @@ -5784,25 +6280,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("19"); - if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { - CmdArgs.push_back("-fmacro-backtrace-limit"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) { - CmdArgs.push_back("-ftemplate-backtrace-limit"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) { - CmdArgs.push_back("-fconstexpr-backtrace-limit"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) { - CmdArgs.push_back("-fspell-checking-limit"); - CmdArgs.push_back(A->getValue()); - } + Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_backtrace_limit_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fmacro_backtrace_limit_EQ); + Args.AddLastArg(CmdArgs, options::OPT_ftemplate_backtrace_limit_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fspell_checking_limit_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fcaret_diagnostics_max_lines_EQ); // Pass -fmessage-length=. unsigned MessageLength = 0; @@ -5820,28 +6302,33 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString("-fmessage-length=" + Twine(MessageLength))); + if (Arg *A = Args.getLastArg(options::OPT_frandomize_layout_seed_EQ)) + CmdArgs.push_back( + Args.MakeArgString("-frandomize-layout-seed=" + Twine(A->getValue(0)))); + + if (Arg *A = Args.getLastArg(options::OPT_frandomize_layout_seed_file_EQ)) + CmdArgs.push_back(Args.MakeArgString("-frandomize-layout-seed-file=" + + Twine(A->getValue(0)))); + // -fvisibility= and -fvisibility-ms-compat are of a piece. if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ, options::OPT_fvisibility_ms_compat)) { if (A->getOption().matches(options::OPT_fvisibility_EQ)) { - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back(A->getValue()); + A->render(Args, CmdArgs); } else { assert(A->getOption().matches(options::OPT_fvisibility_ms_compat)); - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back("hidden"); - CmdArgs.push_back("-ftype-visibility"); - CmdArgs.push_back("default"); + CmdArgs.push_back("-fvisibility=hidden"); + CmdArgs.push_back("-ftype-visibility=default"); } } else if (IsOpenMPDevice) { // When compiling for the OpenMP device we want protected visibility by - // default. This prevents the device from accidenally preempting code on the - // host, makes the system more robust, and improves performance. - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back("protected"); + // default. This prevents the device from accidentally preempting code on + // the host, makes the system more robust, and improves performance. + CmdArgs.push_back("-fvisibility=protected"); } - if (!RawTriple.isPS4()) + // PS4/PS5 process these options in addClangTargetOptions. + if (!RawTriple.isPS()) { if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_from_dllstorageclass, options::OPT_fno_visibility_from_dllstorageclass)) { @@ -5855,23 +6342,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fvisibility_externs_nodllstorageclass_EQ); } } - - if (const Arg *A = Args.getLastArg(options::OPT_mignore_xcoff_visibility)) { - if (Triple.isOSAIX()) - CmdArgs.push_back("-mignore-xcoff-visibility"); - else - D.Diag(diag::err_drv_unsupported_opt_for_target) - << A->getAsString(Args) << TripleStr; } - if (Args.hasFlag(options::OPT_fvisibility_inlines_hidden, options::OPT_fno_visibility_inlines_hidden, false)) CmdArgs.push_back("-fvisibility-inlines-hidden"); Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var, options::OPT_fno_visibility_inlines_hidden_static_local_var); - Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden); + + // -fvisibility-global-new-delete-hidden is a deprecated spelling of + // -fvisibility-global-new-delete=force-hidden. + if (const Arg *A = + Args.getLastArg(options::OPT_fvisibility_global_new_delete_hidden)) { + D.Diag(diag::warn_drv_deprecated_arg) + << A->getAsString(Args) + << "-fvisibility-global-new-delete=force-hidden"; + } + + if (const Arg *A = + Args.getLastArg(options::OPT_fvisibility_global_new_delete_EQ, + options::OPT_fvisibility_global_new_delete_hidden)) { + if (A->getOption().matches(options::OPT_fvisibility_global_new_delete_EQ)) { + A->render(Args, CmdArgs); + } else { + assert(A->getOption().matches( + options::OPT_fvisibility_global_new_delete_hidden)); + CmdArgs.push_back("-fvisibility-global-new-delete=force-hidden"); + } + } + Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); if (Args.hasFlag(options::OPT_fnew_infallible, @@ -5886,8 +6386,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs); - Args.AddLastArg(CmdArgs, options::OPT_femulated_tls, - options::OPT_fno_emulated_tls); + Args.AddLastArg(CmdArgs, options::OPT_fzero_call_used_regs_EQ); + + if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, + Triple.hasDefaultEmulatedTLS())) + CmdArgs.push_back("-femulated-tls"); + + Args.addOptInFlag(CmdArgs, options::OPT_fcheck_new, + options::OPT_fno_check_new); + + if (Arg *A = Args.getLastArg(options::OPT_fzero_call_used_regs_EQ)) { + // FIXME: There's no reason for this to be restricted to X86. The backend + // code needs to be changed to include the appropriate function calls + // automatically. + if (!Triple.isX86() && !Triple.isAArch64()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } // AltiVec-like language extensions aren't relevant for assembling. if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) @@ -5936,26 +6451,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_openmp_cuda_mode, /*Default=*/false)) CmdArgs.push_back("-fopenmp-cuda-mode"); - // When in OpenMP offloading mode, enable or disable the new device - // runtime. - if (Args.hasFlag(options::OPT_fopenmp_target_new_runtime, - options::OPT_fno_openmp_target_new_runtime, - /*Default=*/true)) - CmdArgs.push_back("-fopenmp-target-new-runtime"); - // When in OpenMP offloading mode, enable debugging on the device. Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); if (Args.hasFlag(options::OPT_fopenmp_target_debug, options::OPT_fno_openmp_target_debug, /*Default=*/false)) CmdArgs.push_back("-fopenmp-target-debug"); - // When in OpenMP offloading mode with NVPTX target, check if full runtime - // is required. - if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime, - options::OPT_fno_openmp_cuda_force_full_runtime, - /*Default=*/false)) - CmdArgs.push_back("-fopenmp-cuda-force-full-runtime"); - // When in OpenMP offloading mode, forward assumptions information about // thread and team counts in the device. if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, @@ -5966,6 +6467,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_openmp_assume_threads_oversubscription, /*Default=*/false)) CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); + if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) + CmdArgs.push_back("-fopenmp-assume-no-thread-state"); + if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) + CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); + if (Args.hasArg(options::OPT_fopenmp_offload_mandatory)) + CmdArgs.push_back("-fopenmp-offload-mandatory"); + if (Args.hasArg(options::OPT_fopenmp_force_usm)) + CmdArgs.push_back("-fopenmp-force-usm"); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -5980,11 +6489,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); - if (!Args.hasFlag(options::OPT_fopenmp_extensions, - options::OPT_fno_openmp_extensions, /*Default=*/true)) - CmdArgs.push_back("-fno-openmp-extensions"); + Args.addOptOutFlag(CmdArgs, options::OPT_fopenmp_extensions, + options::OPT_fno_openmp_extensions); } + // Forward the new driver to change offloading code generation. + if (Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false)) + CmdArgs.push_back("--offload-new-driver"); + SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType); const XRayArgs &XRay = TC.getXRayArgs(); @@ -6001,7 +6514,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) { StringRef S0 = A->getValue(), S = S0; unsigned Size, Offset = 0; - if (!Triple.isAArch64() && !Triple.isRISCV() && !Triple.isX86()) + if (!Triple.isAArch64() && !Triple.isLoongArch() && !Triple.isRISCV() && + !Triple.isX86()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; else if (S.consumeInteger(10, Size) || @@ -6047,6 +6561,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (Arg *A = Args.getLastArgNoClaim(options::OPT_pg)) { + if (TC.getTriple().isOSzOS()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + } + if (Arg *A = Args.getLastArgNoClaim(options::OPT_p)) { + if (!(TC.getTriple().isOSAIX() || TC.getTriple().isOSOpenBSD())) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + } + if (Arg *A = Args.getLastArgNoClaim(options::OPT_p, options::OPT_pg)) { + if (A->getOption().matches(options::OPT_p)) { + A->claim(); + if (TC.getTriple().isOSAIX() && !Args.hasArgNoClaim(options::OPT_pg)) + CmdArgs.push_back("-pg"); + } + } + + // Reject AIX-specific link options on other targets. + if (!TC.getTriple().isOSAIX()) { + for (const Arg *A : Args.filtered(options::OPT_b, options::OPT_K, + options::OPT_mxcoff_build_id_EQ)) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << TripleStr; + } + } + if (Args.getLastArg(options::OPT_fapple_kext) || (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) CmdArgs.push_back("-fapple-kext"); @@ -6058,12 +6601,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ); - Args.AddLastArg(CmdArgs, options::OPT_ftime_trace); - Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); Args.AddLastArg(CmdArgs, options::OPT_malign_double); Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file); + if (const char *Name = C.getTimeTraceFile(&JA)) { + CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name))); + Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); + } + if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { CmdArgs.push_back("-ftrapv-handler"); CmdArgs.push_back(A->getValue()); @@ -6094,11 +6640,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_funroll_loops, options::OPT_fno_unroll_loops); + Args.AddLastArg(CmdArgs, options::OPT_fstrict_flex_arrays_EQ); + Args.AddLastArg(CmdArgs, options::OPT_pthread); - if (Args.hasFlag(options::OPT_mspeculative_load_hardening, - options::OPT_mno_speculative_load_hardening, false)) - CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening")); + Args.addOptInFlag(CmdArgs, options::OPT_mspeculative_load_hardening, + options::OPT_mno_speculative_load_hardening); RenderSSPOptions(D, TC, Args, CmdArgs, KernelOrKext); RenderSCPOptions(TC, Args, CmdArgs); @@ -6106,10 +6653,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fswift_async_fp_EQ); - // Translate -mstackrealign - if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, - false)) - CmdArgs.push_back(Args.MakeArgString("-mstackrealign")); + Args.addOptInFlag(CmdArgs, options::OPT_mstackrealign, + options::OPT_mno_stackrealign); if (Args.hasArg(options::OPT_mstack_alignment)) { StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); @@ -6125,9 +6670,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mstack-probe-size=0"); } - if (!Args.hasFlag(options::OPT_mstack_arg_probe, - options::OPT_mno_stack_arg_probe, true)) - CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe")); + Args.addOptOutFlag(CmdArgs, options::OPT_mstack_arg_probe, + options::OPT_mno_stack_arg_probe); if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, options::OPT_mno_restrict_it)) { @@ -6136,34 +6680,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-arm-restrict-it"); } else { CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-arm-no-restrict-it"); + CmdArgs.push_back("-arm-default-it"); } - } else if (Triple.isOSWindows() && - (Triple.getArch() == llvm::Triple::arm || - Triple.getArch() == llvm::Triple::thumb)) { - // Windows on ARM expects restricted IT blocks - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-arm-restrict-it"); } // Forward -cl options to -cc1 RenderOpenCLOptions(Args, CmdArgs, InputType); + // Forward hlsl options to -cc1 + RenderHLSLOptions(Args, CmdArgs, InputType); + + // Forward OpenACC options to -cc1 + RenderOpenACCOptions(D, Args, CmdArgs, InputType); + if (IsHIP) { if (Args.hasFlag(options::OPT_fhip_new_launch_api, options::OPT_fno_hip_new_launch_api, true)) CmdArgs.push_back("-fhip-new-launch-api"); - if (Args.hasFlag(options::OPT_fgpu_allow_device_init, - options::OPT_fno_gpu_allow_device_init, false)) - CmdArgs.push_back("-fgpu-allow-device-init"); + Args.addOptInFlag(CmdArgs, options::OPT_fgpu_allow_device_init, + options::OPT_fno_gpu_allow_device_init); + Args.AddLastArg(CmdArgs, options::OPT_hipstdpar); + Args.AddLastArg(CmdArgs, options::OPT_hipstdpar_interpose_alloc); + Args.addOptInFlag(CmdArgs, options::OPT_fhip_kernel_arg_name, + options::OPT_fno_hip_kernel_arg_name); } if (IsCuda || IsHIP) { - if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) + if (IsRDCMode) CmdArgs.push_back("-fgpu-rdc"); - if (Args.hasFlag(options::OPT_fgpu_defer_diag, - options::OPT_fno_gpu_defer_diag, false)) - CmdArgs.push_back("-fgpu-defer-diag"); + Args.addOptInFlag(CmdArgs, options::OPT_fgpu_defer_diag, + options::OPT_fno_gpu_defer_diag); if (Args.hasFlag(options::OPT_fgpu_exclude_wrong_side_overloads, options::OPT_fno_gpu_exclude_wrong_side_overloads, false)) { @@ -6172,13 +6718,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + // Forward -nogpulib to -cc1. + if (Args.hasArg(options::OPT_nogpulib)) + CmdArgs.push_back("-nogpulib"); + if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) { CmdArgs.push_back( Args.MakeArgString(Twine("-fcf-protection=") + A->getValue())); } - if (IsUsingLTO) - Args.AddLastArg(CmdArgs, options::OPT_mibt_seal); + if (Arg *A = Args.getLastArg(options::OPT_mfunction_return_EQ)) + CmdArgs.push_back( + Args.MakeArgString(Twine("-mfunction-return=") + A->getValue())); + + Args.AddLastArg(CmdArgs, options::OPT_mindirect_branch_cs_prefix); // Forward -f options with positive and negative forms; we translate these by // hand. Do not propagate PGO options to the GPU-side compilations as the @@ -6214,9 +6767,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } RenderBuiltinOptions(TC, RawTriple, Args, CmdArgs); - if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, - options::OPT_fno_assume_sane_operator_new)) - CmdArgs.push_back("-fno-assume-sane-operator-new"); + Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, + options::OPT_fno_assume_sane_operator_new); + + if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false)) + CmdArgs.push_back("-fapinotes"); + if (Args.hasFlag(options::OPT_fapinotes_modules, + options::OPT_fno_apinotes_modules, false)) + CmdArgs.push_back("-fapinotes-modules"); + Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version); // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, @@ -6234,24 +6793,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (TC.IsEncodeExtendedBlockSignatureDefault()) CmdArgs.push_back("-fencode-extended-block-signature"); - if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts, - false) && - types::isCXX(InputType)) { - CmdArgs.push_back("-fcoroutines-ts"); - } + if (Args.hasFlag(options::OPT_fcoro_aligned_allocation, + options::OPT_fno_coro_aligned_allocation, false) && + types::isCXX(InputType)) + CmdArgs.push_back("-fcoro-aligned-allocation"); Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes, options::OPT_fno_double_square_bracket_attributes); - // -faccess-control is default. - if (Args.hasFlag(options::OPT_fno_access_control, - options::OPT_faccess_control, false)) - CmdArgs.push_back("-fno-access-control"); - - // -felide-constructors is the default. - if (Args.hasFlag(options::OPT_fno_elide_constructors, - options::OPT_felide_constructors, false)) - CmdArgs.push_back("-fno-elide-constructors"); + Args.addOptOutFlag(CmdArgs, options::OPT_faccess_control, + options::OPT_fno_access_control); + Args.addOptOutFlag(CmdArgs, options::OPT_felide_constructors, + options::OPT_fno_elide_constructors); ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); @@ -6280,21 +6833,29 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RawTriple.isOSDarwin() && !KernelOrKext)) CmdArgs.push_back("-fregister-global-dtors-with-atexit"); - // -fno-use-line-directives is default. - if (Args.hasFlag(options::OPT_fuse_line_directives, - options::OPT_fno_use_line_directives, false)) - CmdArgs.push_back("-fuse-line-directives"); + Args.addOptInFlag(CmdArgs, options::OPT_fuse_line_directives, + options::OPT_fno_use_line_directives); // -fno-minimize-whitespace is default. if (Args.hasFlag(options::OPT_fminimize_whitespace, options::OPT_fno_minimize_whitespace, false)) { types::ID InputType = Inputs[0].getType(); if (!isDerivedFromC(InputType)) - D.Diag(diag::err_drv_minws_unsupported_input_type) - << types::getTypeName(InputType); + D.Diag(diag::err_drv_opt_unsupported_input_type) + << "-fminimize-whitespace" << types::getTypeName(InputType); CmdArgs.push_back("-fminimize-whitespace"); } + // -fno-keep-system-includes is default. + if (Args.hasFlag(options::OPT_fkeep_system_includes, + options::OPT_fno_keep_system_includes, false)) { + types::ID InputType = Inputs[0].getType(); + if (!isDerivedFromC(InputType)) + D.Diag(diag::err_drv_opt_unsupported_input_type) + << "-fkeep-system-includes" << types::getTypeName(InputType); + CmdArgs.push_back("-fkeep-system-includes"); + } + // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) @@ -6308,6 +6869,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (IsMSVCCompat) CmdArgs.push_back("-fms-compatibility"); + if (Triple.isWindowsMSVCEnvironment() && !D.IsCLMode() && + Args.hasArg(options::OPT_fms_runtime_lib_EQ)) + ProcessVSRuntimeLibrary(Args, CmdArgs); + // Handle -fgcc-version, if present. VersionTuple GNUCVer; if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) { @@ -6316,8 +6881,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef Val = A->getValue(); Val = Val.empty() ? "0" : Val; // Treat "" as 0 or disable. bool Invalid = GNUCVer.tryParse(Val); - unsigned Minor = GNUCVer.getMinor().getValueOr(0); - unsigned Patch = GNUCVer.getSubminor().getValueOr(0); + unsigned Minor = GNUCVer.getMinor().value_or(0); + unsigned Patch = GNUCVer.getSubminor().value_or(0); if (Invalid || GNUCVer.getBuild() || Minor >= 100 || Patch >= 100) { D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); @@ -6359,7 +6924,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, .Case("c++14", "-std=c++14") .Case("c++17", "-std=c++17") .Case("c++20", "-std=c++20") - .Case("c++latest", "-std=c++2b") + // TODO add c++23 and c++26 when MSVC supports it. + .Case("c++latest", "-std=c++26") .Default(""); if (LanguageStandard.empty()) D.Diag(clang::diag::warn_drv_unused_argument) @@ -6376,14 +6942,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(LanguageStandard.data()); } - // -fno-borland-extensions is default. - if (Args.hasFlag(options::OPT_fborland_extensions, - options::OPT_fno_borland_extensions, false)) - CmdArgs.push_back("-fborland-extensions"); + Args.addOptInFlag(CmdArgs, options::OPT_fborland_extensions, + options::OPT_fno_borland_extensions); - // -fno-declspec is default, except for PS4. + // -fno-declspec is default, except for PS4/PS5. if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec, - RawTriple.isPS4())) + RawTriple.isPS())) CmdArgs.push_back("-fdeclspec"); else if (Args.hasArg(options::OPT_fno_declspec)) CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec. @@ -6396,36 +6960,58 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, (!IsWindowsMSVC || IsMSVC2015Compatible))) CmdArgs.push_back("-fno-threadsafe-statics"); - // -fno-delayed-template-parsing is default, except when targeting MSVC. - // Many old Windows SDK versions require this to parse. - // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their - // compiler. We should be able to disable this by default at some point. - if (Args.hasFlag(options::OPT_fdelayed_template_parsing, - options::OPT_fno_delayed_template_parsing, IsWindowsMSVC)) - CmdArgs.push_back("-fdelayed-template-parsing"); - // -fgnu-keywords default varies depending on language; only pass if // specified. Args.AddLastArg(CmdArgs, options::OPT_fgnu_keywords, options::OPT_fno_gnu_keywords); - if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline, - false)) - CmdArgs.push_back("-fgnu89-inline"); + Args.addOptInFlag(CmdArgs, options::OPT_fgnu89_inline, + options::OPT_fno_gnu89_inline); - if (Args.hasArg(options::OPT_fno_inline)) - CmdArgs.push_back("-fno-inline"); + const Arg *InlineArg = Args.getLastArg(options::OPT_finline_functions, + options::OPT_finline_hint_functions, + options::OPT_fno_inline_functions); + if (Arg *A = Args.getLastArg(options::OPT_finline, options::OPT_fno_inline)) { + if (A->getOption().matches(options::OPT_fno_inline)) + A->render(Args, CmdArgs); + } else if (InlineArg) { + InlineArg->render(Args, CmdArgs); + } + + Args.AddLastArg(CmdArgs, options::OPT_finline_max_stacksize_EQ); + + // FIXME: Find a better way to determine whether we are in C++20. + bool HaveCxx20 = + Std && + (Std->containsValue("c++2a") || Std->containsValue("gnu++2a") || + Std->containsValue("c++20") || Std->containsValue("gnu++20") || + Std->containsValue("c++2b") || Std->containsValue("gnu++2b") || + Std->containsValue("c++23") || Std->containsValue("gnu++23") || + Std->containsValue("c++2c") || Std->containsValue("gnu++2c") || + Std->containsValue("c++26") || Std->containsValue("gnu++26") || + Std->containsValue("c++latest") || Std->containsValue("gnu++latest")); + bool HaveModules = + RenderModulesOptions(C, D, Args, Input, Output, HaveCxx20, CmdArgs); - Args.AddLastArg(CmdArgs, options::OPT_finline_functions, - options::OPT_finline_hint_functions, - options::OPT_fno_inline_functions); + // -fdelayed-template-parsing is default when targeting MSVC. + // Many old Windows SDK versions require this to parse. + // + // According to + // https://learn.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=msvc-170, + // MSVC actually defaults to -fno-delayed-template-parsing (/Zc:twoPhase- + // with MSVC CLI) if using C++20. So we match the behavior with MSVC here to + // not enable -fdelayed-template-parsing by default after C++20. + // + // FIXME: Given -fdelayed-template-parsing is a source of bugs, we should be + // able to disable this by default at some point. + if (Args.hasFlag(options::OPT_fdelayed_template_parsing, + options::OPT_fno_delayed_template_parsing, + IsWindowsMSVC && !HaveCxx20)) { + if (HaveCxx20) + D.Diag(clang::diag::warn_drv_delayed_template_parsing_after_cxx20); - // FIXME: Find a better way to determine whether the language has modules - // support by default, or just assume that all languages do. - bool HaveModules = - Std && (Std->containsValue("c++2a") || Std->containsValue("c++20") || - Std->containsValue("c++latest")); - RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules); + CmdArgs.push_back("-fdelayed-template-parsing"); + } if (Args.hasFlag(options::OPT_fpch_validate_input_files_content, options::OPT_fno_pch_validate_input_files_content, false)) @@ -6440,9 +7026,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("-fmodules-debuginfo"); - Args.AddLastArg(CmdArgs, options::OPT_flegacy_pass_manager, - options::OPT_fno_legacy_pass_manager); - ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, Inputs, CmdArgs, rewriteKind); RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None, Input, CmdArgs); @@ -6493,22 +7076,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // C++ "sane" operator new. - if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, - options::OPT_fno_assume_sane_operator_new)) - CmdArgs.push_back("-fno-assume-sane-operator-new"); + Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, + options::OPT_fno_assume_sane_operator_new); + + // -fassume-unique-vtables is on by default. + Args.addOptOutFlag(CmdArgs, options::OPT_fassume_unique_vtables, + options::OPT_fno_assume_unique_vtables); // -frelaxed-template-template-args is off by default, as it is a severe // breaking change until a corresponding change to template partial ordering // is provided. - if (Args.hasFlag(options::OPT_frelaxed_template_template_args, - options::OPT_fno_relaxed_template_template_args, false)) - CmdArgs.push_back("-frelaxed-template-template-args"); + Args.addOptInFlag(CmdArgs, options::OPT_frelaxed_template_template_args, + options::OPT_fno_relaxed_template_template_args); // -fsized-deallocation is off by default, as it is an ABI-breaking change for // most platforms. - if (Args.hasFlag(options::OPT_fsized_deallocation, - options::OPT_fno_sized_deallocation, false)) - CmdArgs.push_back("-fsized-deallocation"); + Args.addOptInFlag(CmdArgs, options::OPT_fsized_deallocation, + options::OPT_fno_sized_deallocation); // -faligned-allocation is on by default in C++17 onwards and otherwise off // by default. @@ -6531,15 +7115,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fconstant-cfstrings is default, and may be subject to argument translation // on Darwin. if (!Args.hasFlag(options::OPT_fconstant_cfstrings, - options::OPT_fno_constant_cfstrings) || + options::OPT_fno_constant_cfstrings, true) || !Args.hasFlag(options::OPT_mconstant_cfstrings, - options::OPT_mno_constant_cfstrings)) + options::OPT_mno_constant_cfstrings, true)) CmdArgs.push_back("-fno-constant-cfstrings"); - // -fno-pascal-strings is default, only pass non-default. - if (Args.hasFlag(options::OPT_fpascal_strings, - options::OPT_fno_pascal_strings, false)) - CmdArgs.push_back("-fpascal-strings"); + Args.addOptInFlag(CmdArgs, options::OPT_fpascal_strings, + options::OPT_fno_pascal_strings); // Honor -fpack-struct= and -fpack-struct, if given. Note that // -fno-pack-struct doesn't apply to -fpack-struct=. @@ -6571,18 +7153,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-Qn"); // -fno-common is the default, set -fcommon only when that flag is set. - if (Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, false)) - CmdArgs.push_back("-fcommon"); + Args.addOptInFlag(CmdArgs, options::OPT_fcommon, options::OPT_fno_common); // -fsigned-bitfields is default, and clang doesn't yet support // -funsigned-bitfields. if (!Args.hasFlag(options::OPT_fsigned_bitfields, - options::OPT_funsigned_bitfields)) + options::OPT_funsigned_bitfields, true)) D.Diag(diag::warn_drv_clang_unsupported) << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args); // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope. - if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope)) + if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope, true)) D.Diag(diag::err_drv_clang_unsupported) << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args); @@ -6604,15 +7185,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderDiagnosticsOptions(D, Args, CmdArgs); - // -fno-asm-blocks is default. - if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, - false)) - CmdArgs.push_back("-fasm-blocks"); + Args.addOptInFlag(CmdArgs, options::OPT_fasm_blocks, + options::OPT_fno_asm_blocks); - // -fgnu-inline-asm is default. - if (!Args.hasFlag(options::OPT_fgnu_inline_asm, - options::OPT_fno_gnu_inline_asm, true)) - CmdArgs.push_back("-fno-gnu-inline-asm"); + Args.addOptOutFlag(CmdArgs, options::OPT_fgnu_inline_asm, + options::OPT_fno_gnu_inline_asm); // Enable vectorization per default according to the optimization level // selected. For optimization levels that want vectorization we use the alias @@ -6648,21 +7225,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-dollars-in-identifiers"); } - // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for - // practical purposes. - if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, - options::OPT_fno_unit_at_a_time)) { - if (A->getOption().matches(options::OPT_fno_unit_at_a_time)) - D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args); - } - - if (Args.hasFlag(options::OPT_fapple_pragma_pack, - options::OPT_fno_apple_pragma_pack, false)) - CmdArgs.push_back("-fapple-pragma-pack"); - - if (Args.hasFlag(options::OPT_fxl_pragma_pack, - options::OPT_fno_xl_pragma_pack, RawTriple.isOSAIX())) - CmdArgs.push_back("-fxl-pragma-pack"); + Args.addOptInFlag(CmdArgs, options::OPT_fapple_pragma_pack, + options::OPT_fno_apple_pragma_pack); // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. if (willEmitRemarks(Args) && checkRemarksOptions(D, Args, Triple)) @@ -6673,6 +7237,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (RewriteImports) CmdArgs.push_back("-frewrite-imports"); + Args.addOptInFlag(CmdArgs, options::OPT_fdirectives_only, + options::OPT_fno_directives_only); + // Enable rewrite includes if the user's asked for it or if we're generating // diagnostics. // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be @@ -6754,25 +7321,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } + // Forward --vfsoverlay to -cc1. + for (const Arg *A : Args.filtered(options::OPT_vfsoverlay)) { + CmdArgs.push_back("--vfsoverlay"); + CmdArgs.push_back(A->getValue()); + A->claim(); + } + + Args.addOptInFlag(CmdArgs, options::OPT_fsafe_buffer_usage_suggestions, + options::OPT_fno_safe_buffer_usage_suggestions); + // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); - if (!StatsFile.empty()) + if (!StatsFile.empty()) { CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile)); + if (D.CCPrintInternalStats) + CmdArgs.push_back("-stats-file-append"); + } // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. - // -finclude-default-header flag is for preprocessor, - // do not pass it to other cc1 commands when save-temps is enabled - if (C.getDriver().isSaveTempsEnabled() && - !isa<PreprocessJobAction>(JA)) { - for (auto Arg : Args.filtered(options::OPT_Xclang)) { - Arg->claim(); - if (StringRef(Arg->getValue()) != "-finclude-default-header") - CmdArgs.push_back(Arg->getValue()); + for (auto Arg : Args.filtered(options::OPT_Xclang)) { + Arg->claim(); + // -finclude-default-header flag is for preprocessor, + // do not pass it to other cc1 commands when save-temps is enabled + if (C.getDriver().isSaveTempsEnabled() && + !isa<PreprocessJobAction>(JA)) { + if (StringRef(Arg->getValue()) == "-finclude-default-header") + continue; } - } - else { - Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); + CmdArgs.push_back(Arg->getValue()); } for (const Arg *A : Args.filtered(options::OPT_mllvm)) { A->claim(); @@ -6816,7 +7394,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, auto FRecordSwitches = Args.hasFlag(options::OPT_frecord_command_line, options::OPT_fno_record_command_line, false); - if (FRecordSwitches && !Triple.isOSBinFormatELF()) + if (FRecordSwitches && !Triple.isOSBinFormatELF() && + !Triple.isOSBinFormatXCOFF() && !Triple.isOSBinFormatMachO()) D.Diag(diag::err_drv_unsupported_opt_for_target) << Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args) << TripleStr; @@ -6844,13 +7423,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - // Host-side cuda compilation receives all device-side outputs in a single - // fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary. + // Host-side offloading compilation receives all device-side outputs. Include + // them in the host compilation depending on the target. If the host inputs + // are not empty we use the new-driver scheme, otherwise use the old scheme. if ((IsCuda || IsHIP) && CudaDeviceInput) { + CmdArgs.push_back("-fcuda-include-gpubinary"); + CmdArgs.push_back(CudaDeviceInput->getFilename()); + } else if (!HostOffloadingInputs.empty()) { + if ((IsCuda || IsHIP) && !IsRDCMode) { + assert(HostOffloadingInputs.size() == 1 && "Only one input expected"); CmdArgs.push_back("-fcuda-include-gpubinary"); - CmdArgs.push_back(CudaDeviceInput->getFilename()); - if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) - CmdArgs.push_back("-fgpu-rdc"); + CmdArgs.push_back(HostOffloadingInputs.front().getFilename()); + } else { + for (const InputInfo Input : HostOffloadingInputs) + CmdArgs.push_back(Args.MakeArgString("-fembed-offload-object=" + + TC.getInputFilename(Input))); + } } if (IsCuda) { @@ -6869,10 +7457,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, auto CUID = cast<InputAction>(SourceAction)->getId(); if (!CUID.empty()) CmdArgs.push_back(Args.MakeArgString(Twine("-cuid=") + Twine(CUID))); + + // -ffast-math turns on -fgpu-approx-transcendentals implicitly, but will + // be overriden by -fno-gpu-approx-transcendentals. + bool UseApproxTranscendentals = Args.hasFlag( + options::OPT_ffast_math, options::OPT_fno_fast_math, false); + if (Args.hasFlag(options::OPT_fgpu_approx_transcendentals, + options::OPT_fno_gpu_approx_transcendentals, + UseApproxTranscendentals)) + CmdArgs.push_back("-fgpu-approx-transcendentals"); + } else { + Args.claimAllArgs(options::OPT_fgpu_approx_transcendentals, + options::OPT_fno_gpu_approx_transcendentals); } - if (IsHIP) + if (IsHIP) { CmdArgs.push_back("-fcuda-allow-variadic-functions"); + Args.AddLastArg(CmdArgs, options::OPT_fgpu_default_stream_EQ); + } + + Args.AddLastArg(CmdArgs, options::OPT_foffload_uniform_block, + options::OPT_fno_offload_uniform_block); + + Args.AddLastArg(CmdArgs, options::OPT_foffload_implicit_host_device_templates, + options::OPT_fno_offload_implicit_host_device_templates); if (IsCudaDevice || IsHIPDevice) { StringRef InlineThresh = @@ -6884,63 +7492,43 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (IsHIPDevice) + Args.addOptOutFlag(CmdArgs, + options::OPT_fhip_fp32_correctly_rounded_divide_sqrt, + options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt); + // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path // to specify the result of the compile phase on the host, so the meaningful - // device declarations can be identified. Also, -fopenmp-is-device is passed - // along to tell the frontend that it is generating code for a device, so that - // only the relevant declarations are emitted. + // device declarations can be identified. Also, -fopenmp-is-target-device is + // passed along to tell the frontend that it is generating code for a device, + // so that only the relevant declarations are emitted. if (IsOpenMPDevice) { - CmdArgs.push_back("-fopenmp-is-device"); + CmdArgs.push_back("-fopenmp-is-target-device"); if (OpenMPDeviceInput) { CmdArgs.push_back("-fopenmp-host-ir-file-path"); CmdArgs.push_back(Args.MakeArgString(OpenMPDeviceInput->getFilename())); } } - // Host-side OpenMP offloading recieves the device object files and embeds it - // in a named section including the associated target triple and architecture. - if (IsOpenMPHost && !OpenMPHostInputs.empty()) { - auto InputFile = OpenMPHostInputs.begin(); - auto OpenMPTCs = C.getOffloadToolChains<Action::OFK_OpenMP>(); - for (auto TI = OpenMPTCs.first, TE = OpenMPTCs.second; TI != TE; - ++TI, ++InputFile) { - const ToolChain *TC = TI->second; - const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP); - StringRef File = - C.getArgs().MakeArgString(TC->getInputFilename(*InputFile)); - StringRef InputName = Clang::getBaseInputStem(Args, Inputs); - - CmdArgs.push_back(Args.MakeArgString( - "-fembed-offload-object=" + File + "," + TC->getTripleString() + "." + - TCArgs.getLastArgValue(options::OPT_march_EQ) + "." + InputName)); - } - } - if (Triple.isAMDGPU()) { handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs); - if (Args.hasFlag(options::OPT_munsafe_fp_atomics, - options::OPT_mno_unsafe_fp_atomics, /*Default=*/false)) - CmdArgs.push_back("-munsafe-fp-atomics"); + Args.addOptInFlag(CmdArgs, options::OPT_munsafe_fp_atomics, + options::OPT_mno_unsafe_fp_atomics); + Args.addOptOutFlag(CmdArgs, options::OPT_mamdgpu_ieee, + options::OPT_mno_amdgpu_ieee); } // For all the host OpenMP offloading compile jobs we need to pass the targets // information using -fopenmp-targets= option. if (JA.isHostOffloading(Action::OFK_OpenMP)) { - SmallString<128> TargetInfo("-fopenmp-targets="); + SmallString<128> Targets("-fopenmp-targets="); - Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ); - assert(Tgts && Tgts->getNumValues() && - "OpenMP offloading has to have targets specified."); - for (unsigned i = 0; i < Tgts->getNumValues(); ++i) { - if (i) - TargetInfo += ','; - // We need to get the string from the triple because it may be not exactly - // the same as the one we get directly from the arguments. - llvm::Triple T(Tgts->getValue(i)); - TargetInfo += T.getTriple(); - } - CmdArgs.push_back(Args.MakeArgString(TargetInfo.str())); + SmallVector<std::string, 4> Triples; + auto TCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); + std::transform(TCRange.first, TCRange.second, std::back_inserter(Triples), + [](auto TC) { return TC.second->getTripleString(); }); + CmdArgs.push_back(Args.MakeArgString(Targets + llvm::join(Triples, ","))); } bool VirtualFunctionElimination = @@ -6968,22 +7556,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (WholeProgramVTables) { - // Propagate -fwhole-program-vtables if this is an LTO compile. - if (IsUsingLTO) - CmdArgs.push_back("-fwhole-program-vtables"); + // PS4 uses the legacy LTO API, which does not support this feature in + // ThinLTO mode. + bool IsPS4 = getToolChain().getTriple().isPS4(); + // Check if we passed LTO options but they were suppressed because this is a // device offloading action, or we passed device offload LTO options which // were suppressed because this is not the device offload action. + // Check if we are using PS4 in regular LTO mode. // Otherwise, issue an error. - else if (!D.isUsingLTO(!IsDeviceOffloadAction)) + if ((!IsUsingLTO && !D.isUsingLTO(!IsDeviceOffloadAction)) || + (IsPS4 && !UnifiedLTO && (D.getLTOMode() != LTOK_Full))) D.Diag(diag::err_drv_argument_only_allowed_with) << "-fwhole-program-vtables" - << "-flto"; + << ((IsPS4 && !UnifiedLTO) ? "-flto=full" : "-flto"); + + // Propagate -fwhole-program-vtables if this is an LTO compile. + if (IsUsingLTO) + CmdArgs.push_back("-fwhole-program-vtables"); } bool DefaultsSplitLTOUnit = - (WholeProgramVTables || SanitizeArgs.needsLTO()) && - (LTOMode == LTOK_Full || TC.canSplitThinLTOUnit()); + ((WholeProgramVTables || SanitizeArgs.needsLTO()) && + (LTOMode == LTOK_Full || TC.canSplitThinLTOUnit())) || + (!Triple.isPS4() && UnifiedLTO); bool SplitLTOUnit = Args.hasFlag(options::OPT_fsplit_lto_unit, options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit); @@ -6993,6 +7589,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (SplitLTOUnit) CmdArgs.push_back("-fsplit-lto-unit"); + if (Arg *A = Args.getLastArg(options::OPT_ffat_lto_objects, + options::OPT_fno_fat_lto_objects)) { + if (IsUsingLTO && A->getOption().matches(options::OPT_ffat_lto_objects)) { + assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); + if (!Triple.isOSBinFormatELF()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TC.getTripleString(); + } + CmdArgs.push_back(Args.MakeArgString( + Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); + CmdArgs.push_back("-flto-unit"); + CmdArgs.push_back("-ffat-lto-objects"); + A->render(Args, CmdArgs); + } + } + if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel, options::OPT_fno_global_isel)) { CmdArgs.push_back("-mllvm"); @@ -7041,17 +7653,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fforce-enable-int128"); } - if (Args.hasFlag(options::OPT_fkeep_static_consts, - options::OPT_fno_keep_static_consts, false)) - CmdArgs.push_back("-fkeep-static-consts"); - - if (Args.hasFlag(options::OPT_fcomplete_member_pointers, - options::OPT_fno_complete_member_pointers, false)) - CmdArgs.push_back("-fcomplete-member-pointers"); - - if (!Args.hasFlag(options::OPT_fcxx_static_destructors, - options::OPT_fno_cxx_static_destructors, true)) - CmdArgs.push_back("-fno-c++-static-destructors"); + Args.addOptInFlag(CmdArgs, options::OPT_fkeep_static_consts, + options::OPT_fno_keep_static_consts); + Args.addOptInFlag(CmdArgs, options::OPT_fkeep_persistent_storage_variables, + options::OPT_fno_keep_persistent_storage_variables); + Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers, + options::OPT_fno_complete_member_pointers); + Args.addOptOutFlag(CmdArgs, options::OPT_fcxx_static_destructors, + options::OPT_fno_cxx_static_destructors); addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false); @@ -7076,6 +7685,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("+outline-atomics"); } + if (Triple.isAArch64() && + (Args.hasArg(options::OPT_mno_fmv) || + (Triple.isAndroid() && Triple.isAndroidVersionLT(23)) || + getToolChain().GetRuntimeLibType(Args) != ToolChain::RLT_CompilerRT)) { + // Disable Function Multiversioning on AArch64 target. + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-fmv"); + } + if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig, (TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSBinFormatCOFF()) && @@ -7086,8 +7704,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-faddrsig"); if ((Triple.isOSBinFormatELF() || Triple.isOSBinFormatMachO()) && - (EH || AsyncUnwindTables || UnwindTables || - DebugInfoKind != codegenoptions::NoDebugInfo)) + (EH || UnwindTables || AsyncUnwindTables || + DebugInfoKind != llvm::codegenoptions::NoDebugInfo)) CmdArgs.push_back("-D__GCC_HAVE_DWARF2_CFI_ASM=1"); if (Arg *A = Args.getLastArg(options::OPT_fsymbol_partition_EQ)) { @@ -7098,11 +7716,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Str)); } - // Add the output path to the object file for CodeView debug infos. - if (EmitCodeView && Output.isFilename()) - addDebugObjectName(Args, CmdArgs, DebugCompilationDir, - Output.getFilename()); - // Add the "-o out -x type src.c" flags last. This is done primarily to make // the -cc1 command easier to edit when reproducing compiler crashes. if (Output.getType() == types::TY_Dependencies) { @@ -7125,8 +7738,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, addDashXForInput(Args, Input, CmdArgs); ArrayRef<InputInfo> FrontendInputs = Input; - if (IsHeaderModulePrecompile) - FrontendInputs = ModuleHeaderInputs; + if (IsExtractAPI) + FrontendInputs = ExtractAPIInputs; else if (Input.isNothing()) FrontendInputs = {}; @@ -7139,13 +7752,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (D.CC1Main && !D.CCGenDiagnostics) { // Invoke the CC1 directly in this process - C.addCommand(std::make_unique<CC1Command>(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<CC1Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getPrependArg())); } else { - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getPrependArg())); } // Make the compile command echo its inputs for /showFilenames. @@ -7378,66 +7991,20 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { EH.NoUnwindC = true; } + if (Args.hasArg(options::OPT__SLASH_kernel)) { + EH.Synch = false; + EH.NoUnwindC = false; + EH.Asynch = false; + } + return EH; } void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, - ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind *DebugInfoKind, - bool *EmitCodeView) const { - unsigned RTOptionID = options::OPT__SLASH_MT; + ArgStringList &CmdArgs) const { bool isNVPTX = getToolChain().getTriple().isNVPTX(); - if (Args.hasArg(options::OPT__SLASH_LDd)) - // The /LDd option implies /MTd. The dependent lib part can be overridden, - // but defining _DEBUG is sticky. - RTOptionID = options::OPT__SLASH_MTd; - - if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) - RTOptionID = A->getOption().getID(); - - StringRef FlagForCRT; - switch (RTOptionID) { - case options::OPT__SLASH_MD: - if (Args.hasArg(options::OPT__SLASH_LDd)) - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-D_DLL"); - FlagForCRT = "--dependent-lib=msvcrt"; - break; - case options::OPT__SLASH_MDd: - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-D_DLL"); - FlagForCRT = "--dependent-lib=msvcrtd"; - break; - case options::OPT__SLASH_MT: - if (Args.hasArg(options::OPT__SLASH_LDd)) - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-flto-visibility-public-std"); - FlagForCRT = "--dependent-lib=libcmt"; - break; - case options::OPT__SLASH_MTd: - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-flto-visibility-public-std"); - FlagForCRT = "--dependent-lib=libcmtd"; - break; - default: - llvm_unreachable("Unexpected option ID."); - } - - if (Args.hasArg(options::OPT__SLASH_Zl)) { - CmdArgs.push_back("-D_VC_NODEFAULTLIB"); - } else { - CmdArgs.push_back(FlagForCRT.data()); - - // This provides POSIX compatibility (maps 'open' to '_open'), which most - // users want. The /Za flag to cl.exe turns this off, but it's not - // implemented in clang. - CmdArgs.push_back("--dependent-lib=oldnames"); - } + ProcessVSRuntimeLibrary(Args, CmdArgs); if (Arg *ShowIncludes = Args.getLastArg(options::OPT__SLASH_showIncludes, @@ -7460,24 +8027,15 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong))); } - // Emit CodeView if -Z7 or -gline-tables-only are present. - if (Arg *DebugInfoArg = Args.getLastArg(options::OPT__SLASH_Z7, - options::OPT_gline_tables_only)) { - *EmitCodeView = true; - if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7)) - *DebugInfoKind = codegenoptions::DebugInfoConstructor; - else - *DebugInfoKind = codegenoptions::DebugLineTablesOnly; - } else { - *EmitCodeView = false; - } - const Driver &D = getToolChain().getDriver(); + EHFlags EH = parseClangCLEHFlags(D, Args); if (!isNVPTX && (EH.Synch || EH.Asynch)) { if (types::isCXX(InputType)) CmdArgs.push_back("-fcxx-exceptions"); CmdArgs.push_back("-fexceptions"); + if (EH.Asynch) + CmdArgs.push_back("-fasync-exceptions"); } if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC) CmdArgs.push_back("-fexternc-nounwind"); @@ -7488,24 +8046,38 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-P"); } - unsigned VolatileOptionID; - if (getToolChain().getTriple().isX86()) - VolatileOptionID = options::OPT__SLASH_volatile_ms; - else - VolatileOptionID = options::OPT__SLASH_volatile_iso; - - if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group)) - VolatileOptionID = A->getOption().getID(); - - if (VolatileOptionID == options::OPT__SLASH_volatile_ms) - CmdArgs.push_back("-fms-volatile"); - if (Args.hasFlag(options::OPT__SLASH_Zc_dllexportInlines_, options::OPT__SLASH_Zc_dllexportInlines, false)) { CmdArgs.push_back("-fno-dllexport-inlines"); } + if (Args.hasFlag(options::OPT__SLASH_Zc_wchar_t_, + options::OPT__SLASH_Zc_wchar_t, false)) { + CmdArgs.push_back("-fno-wchar"); + } + + if (Args.hasArg(options::OPT__SLASH_kernel)) { + llvm::Triple::ArchType Arch = getToolChain().getArch(); + std::vector<std::string> Values = + Args.getAllArgValues(options::OPT__SLASH_arch); + if (!Values.empty()) { + llvm::SmallSet<std::string, 4> SupportedArches; + if (Arch == llvm::Triple::x86) + SupportedArches.insert("IA32"); + + for (auto &V : Values) + if (!SupportedArches.contains(V)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << std::string("/arch:").append(V) << "/kernel"; + } + + CmdArgs.push_back("-fno-rtti"); + if (Args.hasFlag(options::OPT__SLASH_GR, options::OPT__SLASH_GR_, false)) + D.Diag(diag::err_drv_argument_not_allowed_with) << "/GR" + << "/kernel"; + } + Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg); Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb); if (MostGeneralArg && BestCaseArg) @@ -7532,6 +8104,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-fms-memptr-rep=virtual"); } + if (Args.hasArg(options::OPT_regcall4)) + CmdArgs.push_back("-regcall4"); + // Parse the default calling convention options. if (Arg *CCArg = Args.getLastArg(options::OPT__SLASH_Gd, options::OPT__SLASH_Gr, @@ -7568,6 +8143,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back(DCCFlag); } + if (Args.hasArg(options::OPT__SLASH_Gregcall4)) + CmdArgs.push_back("-regcall4"); + Args.AddLastArg(CmdArgs, options::OPT_vtordisp_mode_EQ); if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) { @@ -7575,7 +8153,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("msvc"); } - if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { + if (Args.hasArg(options::OPT__SLASH_kernel)) + CmdArgs.push_back("-fms-kernel"); + + for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) { StringRef GuardArgs = A->getValue(); // The only valid options are "cf", "cf,nochecks", "cf-", "ehcont" and // "ehcont-". @@ -7594,6 +8175,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, } else { D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << GuardArgs; } + A->claim(); } } @@ -7650,11 +8232,19 @@ void ClangAs::AddX86TargetArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); } else { getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } +void ClangAs::AddLoongArchTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(loongarch::getLoongArchABI(getToolChain().getDriver(), Args, + getToolChain().getTriple()) + .data()); +} + void ClangAs::AddRISCVTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const llvm::Triple &Triple = getToolChain().getTriple(); @@ -7662,6 +8252,12 @@ void ClangAs::AddRISCVTargetArgs(const ArgList &Args, CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName.data()); + + if (Args.hasFlag(options::OPT_mdefault_build_attributes, + options::OPT_mno_default_build_attributes, true)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-riscv-add-build-attributes"); + } } void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, @@ -7693,6 +8289,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-triple"); CmdArgs.push_back(Args.MakeArgString(TripleStr)); + getToolChain().addClangCC1ASTargetOptions(Args, CmdArgs); + // Set the output mode, we currently only expect to be used as a real // assembler. CmdArgs.push_back("-filetype"); @@ -7737,14 +8335,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, WantDebug = !A->getOption().matches(options::OPT_g0) && !A->getOption().matches(options::OPT_ggdb0); - unsigned DwarfVersion = ParseDebugDefaultVersion(getToolChain(), Args); - if (const Arg *GDwarfN = getDwarfNArg(Args)) - DwarfVersion = DwarfVersionNum(GDwarfN->getSpelling()); - - if (DwarfVersion == 0) - DwarfVersion = getToolChain().GetDefaultDwarfVersion(); - - codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; + llvm::codegenoptions::DebugInfoKind DebugInfoKind = + llvm::codegenoptions::NoDebugInfo; // Add the -fdebug-compilation-dir flag if needed. const char *DebugCompilationDir = @@ -7756,10 +8348,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // the guard for source type, however there is a test which asserts // that some assembler invocation receives no -debug-info-kind, // and it's not clear whether that test is just overly restrictive. - DebugInfoKind = (WantDebug ? codegenoptions::DebugInfoConstructor - : codegenoptions::NoDebugInfo); + DebugInfoKind = (WantDebug ? llvm::codegenoptions::DebugInfoConstructor + : llvm::codegenoptions::NoDebugInfo); - addDebugPrefixMapArg(getToolChain().getDriver(), Args, CmdArgs); + addDebugPrefixMapArg(getToolChain().getDriver(), getToolChain(), Args, + CmdArgs); // Set the AT_producer to the clang version when using the integrated // assembler on assembly source files. @@ -7769,12 +8362,12 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // And pass along -I options Args.AddAllArgs(CmdArgs, options::OPT_I); } + const unsigned DwarfVersion = getDwarfVersion(getToolChain(), Args); RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, llvm::DebuggerKind::Default); renderDwarfFormat(D, Triple, Args, CmdArgs, DwarfVersion); RenderDebugInfoCompressionArgs(Args, CmdArgs, D, getToolChain()); - // Handle -fPIC et al -- the relocation-model affects the assembler // for some targets. llvm::Reloc::Model RelocationModel; @@ -7850,6 +8443,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, } break; + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + AddLoongArchTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::riscv32: case llvm::Triple::riscv64: AddRISCVTargetArgs(Args, CmdArgs); @@ -7868,7 +8466,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_mllvm); - if (DebugInfoKind > codegenoptions::NoDebugInfo && Output.isFilename()) + if (DebugInfoKind > llvm::codegenoptions::NoDebugInfo && Output.isFilename()) addDebugObjectName(Args, CmdArgs, DebugCompilationDir, Output.getFilename()); @@ -7879,14 +8477,14 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, continue; auto &JArgs = J.getArguments(); for (unsigned I = 0; I < JArgs.size(); ++I) { - if (StringRef(JArgs[I]).startswith("-object-file-name=") && + if (StringRef(JArgs[I]).starts_with("-object-file-name=") && Output.isFilename()) { - ArgStringList NewArgs(JArgs.begin(), JArgs.begin() + I); - addDebugObjectName(Args, NewArgs, DebugCompilationDir, - Output.getFilename()); - NewArgs.append(JArgs.begin() + I + 1, JArgs.end()); - J.replaceArguments(NewArgs); - break; + ArgStringList NewArgs(JArgs.begin(), JArgs.begin() + I); + addDebugObjectName(Args, NewArgs, DebugCompilationDir, + Output.getFilename()); + NewArgs.append(JArgs.begin() + I + 1, JArgs.end()); + J.replaceArguments(NewArgs); + break; } } } @@ -7904,7 +8502,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, } if (Triple.isAMDGPU()) - handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs); + handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs, /*IsCC1As=*/true); assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); @@ -7912,13 +8510,13 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = getToolChain().getDriver().getClangProgramPath(); if (D.CC1Main && !D.CCGenDiagnostics) { // Invoke cc1as directly in this process. - C.addCommand(std::make_unique<CC1Command>(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<CC1Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getPrependArg())); } else { - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getPrependArg())); } } @@ -7935,8 +8533,10 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, // The bundling command looks like this: // clang-offload-bundler -type=bc // -targets=host-triple,openmp-triple1,openmp-triple2 - // -outputs=input_file - // -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + // -output=output_file + // -input=unbundle_file_host + // -input=unbundle_file_tgt1 + // -input=unbundle_file_tgt2 ArgStringList CmdArgs; @@ -7983,7 +8583,7 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, // Extract GPUArch from -march argument in TC argument list. for (unsigned ArgIndex = 0; ArgIndex < TCArgs.size(); ArgIndex++) { auto ArchStr = StringRef(TCArgs.getArgString(ArgIndex)); - auto Arch = ArchStr.startswith_insensitive("-march="); + auto Arch = ArchStr.starts_with_insensitive("-march="); if (Arch) { GPUArchName = ArchStr.substr(7); Triples += "-"; @@ -7997,14 +8597,12 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, // Get bundled file command. CmdArgs.push_back( - TCArgs.MakeArgString(Twine("-outputs=") + Output.getFilename())); + TCArgs.MakeArgString(Twine("-output=") + Output.getFilename())); // Get unbundled files command. - SmallString<128> UB; - UB += "-inputs="; for (unsigned I = 0; I < Inputs.size(); ++I) { - if (I) - UB += ','; + SmallString<128> UB; + UB += "-input="; // Find ToolChain for this input. const ToolChain *CurTC = &getToolChain(); @@ -8019,14 +8617,18 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, } else { UB += CurTC->getInputFilename(Inputs[I]); } + CmdArgs.push_back(TCArgs.MakeArgString(UB)); } - CmdArgs.push_back(TCArgs.MakeArgString(UB)); - + if (TCArgs.hasFlag(options::OPT_offload_compress, + options::OPT_no_offload_compress, false)) + CmdArgs.push_back("-compress"); + if (TCArgs.hasArg(options::OPT_v)) + CmdArgs.push_back("-verbose"); // All the inputs are encoded as commands. C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::None(), TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), - CmdArgs, None, Output)); + CmdArgs, std::nullopt, Output)); } void OffloadBundler::ConstructJobMultipleOutputs( @@ -8039,8 +8641,10 @@ void OffloadBundler::ConstructJobMultipleOutputs( // The unbundling command looks like this: // clang-offload-bundler -type=bc // -targets=host-triple,openmp-triple1,openmp-triple2 - // -inputs=input_file - // -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + // -input=input_file + // -output=unbundle_file_host + // -output=unbundle_file_tgt1 + // -output=unbundle_file_tgt2 // -unbundle ArgStringList CmdArgs; @@ -8077,7 +8681,7 @@ void OffloadBundler::ConstructJobMultipleOutputs( // Extract GPUArch from -march argument in TC argument list. for (unsigned ArgIndex = 0; ArgIndex < TCArgs.size(); ArgIndex++) { StringRef ArchStr = StringRef(TCArgs.getArgString(ArgIndex)); - auto Arch = ArchStr.startswith_insensitive("-march="); + auto Arch = ArchStr.starts_with_insensitive("-march="); if (Arch) { GPUArchName = ArchStr.substr(7); Triples += "-"; @@ -8092,49 +8696,82 @@ void OffloadBundler::ConstructJobMultipleOutputs( // Get bundled file command. CmdArgs.push_back( - TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename())); + TCArgs.MakeArgString(Twine("-input=") + Input.getFilename())); // Get unbundled files command. - SmallString<128> UB; - UB += "-outputs="; for (unsigned I = 0; I < Outputs.size(); ++I) { - if (I) - UB += ','; + SmallString<128> UB; + UB += "-output="; UB += DepInfo[I].DependentToolChain->getInputFilename(Outputs[I]); + CmdArgs.push_back(TCArgs.MakeArgString(UB)); } - CmdArgs.push_back(TCArgs.MakeArgString(UB)); CmdArgs.push_back("-unbundle"); CmdArgs.push_back("-allow-missing-bundles"); + if (TCArgs.hasArg(options::OPT_v)) + CmdArgs.push_back("-verbose"); // All the inputs are encoded as commands. C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::None(), TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), - CmdArgs, None, Outputs)); + CmdArgs, std::nullopt, Outputs)); } -void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; - const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); - - // Add the "effective" target triple. - CmdArgs.push_back("-target"); - CmdArgs.push_back(Args.MakeArgString(Triple.getTriple())); - // Add the output file name. assert(Output.isFilename() && "Invalid output."); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - // Add inputs. - for (const InputInfo &I : Inputs) { - assert(I.isFilename() && "Invalid input."); - CmdArgs.push_back(I.getFilename()); + // Create the inputs to bundle the needed metadata. + for (const InputInfo &Input : Inputs) { + const Action *OffloadAction = Input.getAction(); + const ToolChain *TC = OffloadAction->getOffloadingToolChain(); + const ArgList &TCArgs = + C.getArgsForToolChain(TC, OffloadAction->getOffloadingArch(), + OffloadAction->getOffloadingDeviceKind()); + StringRef File = C.getArgs().MakeArgString(TC->getInputFilename(Input)); + StringRef Arch = OffloadAction->getOffloadingArch() + ? OffloadAction->getOffloadingArch() + : TCArgs.getLastArgValue(options::OPT_march_EQ); + StringRef Kind = + Action::GetOffloadKindName(OffloadAction->getOffloadingDeviceKind()); + + ArgStringList Features; + SmallVector<StringRef> FeatureArgs; + getTargetFeatures(TC->getDriver(), TC->getTriple(), TCArgs, Features, + false); + llvm::copy_if(Features, std::back_inserter(FeatureArgs), + [](StringRef Arg) { return !Arg.starts_with("-target"); }); + + if (TC->getTriple().isAMDGPU()) { + for (StringRef Feature : llvm::split(Arch.split(':').second, ':')) { + FeatureArgs.emplace_back( + Args.MakeArgString(Feature.take_back() + Feature.drop_back())); + } + } + + // TODO: We need to pass in the full target-id and handle it properly in the + // linker wrapper. + SmallVector<std::string> Parts{ + "file=" + File.str(), + "triple=" + TC->getTripleString(), + "arch=" + Arch.str(), + "kind=" + Kind.str(), + }; + + if (TC->getDriver().isUsingLTO(/* IsOffload */ true) || + TC->getTriple().isAMDGPU()) + for (StringRef Feature : FeatureArgs) + Parts.emplace_back("feature=" + Feature.str()); + + CmdArgs.push_back(Args.MakeArgString("--image=" + llvm::join(Parts, ","))); } C.addCommand(std::make_unique<Command>( @@ -8150,120 +8787,108 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); const llvm::Triple TheTriple = getToolChain().getTriple(); - auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); ArgStringList CmdArgs; // Pass the CUDA path to the linker wrapper tool. - for (auto &I : llvm::make_range(OpenMPTCRange.first, OpenMPTCRange.second)) { - const ToolChain *TC = I.second; - if (TC->getTriple().isNVPTX()) { - CudaInstallationDetector CudaInstallation(D, TheTriple, Args); - if (CudaInstallation.isValid()) - CmdArgs.push_back(Args.MakeArgString( - "--cuda-path=" + CudaInstallation.getInstallPath())); - break; - } - } - - if (D.isUsingLTO(/* IsOffload */ true)) { - // Pass in target features for each toolchain. - for (auto &I : - llvm::make_range(OpenMPTCRange.first, OpenMPTCRange.second)) { + for (Action::OffloadKind Kind : {Action::OFK_Cuda, Action::OFK_OpenMP}) { + auto TCRange = C.getOffloadToolChains(Kind); + for (auto &I : llvm::make_range(TCRange.first, TCRange.second)) { const ToolChain *TC = I.second; - const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP); - ArgStringList FeatureArgs; - TC->addClangTargetOptions(TCArgs, FeatureArgs, Action::OFK_OpenMP); - auto FeatureIt = llvm::find(FeatureArgs, "-target-feature"); - CmdArgs.push_back(Args.MakeArgString( - "-target-feature=" + TC->getTripleString() + "=" + *(FeatureIt + 1))); + if (TC->getTriple().isNVPTX()) { + CudaInstallationDetector CudaInstallation(D, TheTriple, Args); + if (CudaInstallation.isValid()) + CmdArgs.push_back(Args.MakeArgString( + "--cuda-path=" + CudaInstallation.getInstallPath())); + break; + } } + } - // Pass in the bitcode library to be linked during LTO. - for (auto &I : - llvm::make_range(OpenMPTCRange.first, OpenMPTCRange.second)) { - const ToolChain *TC = I.second; - const Driver &TCDriver = TC->getDriver(); - const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP); - StringRef Arch = TCArgs.getLastArgValue(options::OPT_march_EQ); - - std::string BitcodeSuffix; - if (TCArgs.hasFlag(options::OPT_fopenmp_target_new_runtime, - options::OPT_fno_openmp_target_new_runtime, true)) - BitcodeSuffix += "new-"; - if (TC->getTriple().isNVPTX()) - BitcodeSuffix += "nvptx-"; - else if (TC->getTriple().isAMDGPU()) - BitcodeSuffix += "amdgpu-"; - BitcodeSuffix += Arch; - - ArgStringList BitcodeLibrary; - addOpenMPDeviceRTL(TCDriver, TCArgs, BitcodeLibrary, BitcodeSuffix, - TC->getTriple()); - - if (!BitcodeLibrary.empty()) - CmdArgs.push_back( - Args.MakeArgString("-target-library=" + TC->getTripleString() + - "-" + Arch + "=" + BitcodeLibrary.back())); - } + // Pass in the optimization level to use for LTO. + if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { + 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("--opt-level=O") + OOpt)); + } - // Pass in the optimization level to use for LTO. - if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { - 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("-opt-level=O") + OOpt)); - } - } - - CmdArgs.push_back("-host-triple"); - CmdArgs.push_back(Args.MakeArgString(TheTriple.getTriple())); + CmdArgs.push_back( + Args.MakeArgString("--host-triple=" + TheTriple.getTriple())); if (Args.hasArg(options::OPT_v)) - CmdArgs.push_back("-v"); + CmdArgs.push_back("--wrapper-verbose"); - // Add debug information if present. if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) { - const Option &Opt = A->getOption(); - if (Opt.matches(options::OPT_gN_Group)) { - if (Opt.matches(options::OPT_gline_directives_only) || - Opt.matches(options::OPT_gline_tables_only)) - CmdArgs.push_back("-gline-directives-only"); - } else - CmdArgs.push_back("-g"); + if (!A->getOption().matches(options::OPT_g0)) + CmdArgs.push_back("--device-debug"); + } + + // code-object-version=X needs to be passed to clang-linker-wrapper to ensure + // that it is used by lld. + if (const Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) { + CmdArgs.push_back(Args.MakeArgString("-mllvm")); + CmdArgs.push_back(Args.MakeArgString( + Twine("--amdhsa-code-object-version=") + A->getValue())); } for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) - CmdArgs.push_back(Args.MakeArgString("-ptxas-args=" + A)); + CmdArgs.push_back(Args.MakeArgString("--ptxas-arg=" + A)); // Forward remarks passes to the LLVM backend in the wrapper. if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ)) - CmdArgs.push_back( - Args.MakeArgString(Twine("-pass-remarks=") + A->getValue())); + CmdArgs.push_back(Args.MakeArgString(Twine("--offload-opt=-pass-remarks=") + + A->getValue())); if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ)) - CmdArgs.push_back( - Args.MakeArgString(Twine("-pass-remarks-missed=") + A->getValue())); + CmdArgs.push_back(Args.MakeArgString( + Twine("--offload-opt=-pass-remarks-missed=") + A->getValue())); if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ)) - CmdArgs.push_back( - Args.MakeArgString(Twine("-pass-remarks-analysis=") + A->getValue())); + CmdArgs.push_back(Args.MakeArgString( + Twine("--offload-opt=-pass-remarks-analysis=") + A->getValue())); if (Args.getLastArg(options::OPT_save_temps_EQ)) - CmdArgs.push_back("-save-temps"); + CmdArgs.push_back("--save-temps"); // Construct the link job so we can wrap around it. Linker->ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput); const auto &LinkCommand = C.getJobs().getJobs().back(); + // Forward -Xoffload-linker<-triple> arguments to the device link job. + for (Arg *A : Args.filtered(options::OPT_Xoffload_linker)) { + StringRef Val = A->getValue(0); + if (Val.empty()) + CmdArgs.push_back( + Args.MakeArgString(Twine("--device-linker=") + A->getValue(1))); + else + CmdArgs.push_back(Args.MakeArgString( + "--device-linker=" + + ToolChain::getOpenMPTriple(Val.drop_front()).getTriple() + "=" + + A->getValue(1))); + } + Args.ClaimAllArgs(options::OPT_Xoffload_linker); + + // Embed bitcode instead of an object in JIT mode. + if (Args.hasFlag(options::OPT_fopenmp_target_jit, + options::OPT_fno_openmp_target_jit, false)) + CmdArgs.push_back("--embed-bitcode"); + + // Forward `-mllvm` arguments to the LLVM invocations if present. + for (Arg *A : Args.filtered(options::OPT_mllvm)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(A->getValue()); + A->claim(); + } + // Add the linker arguments to be forwarded by the wrapper. - CmdArgs.push_back("-linker-path"); - CmdArgs.push_back(LinkCommand->getExecutable()); + CmdArgs.push_back(Args.MakeArgString(Twine("--linker-path=") + + LinkCommand->getExecutable())); CmdArgs.push_back("--"); for (const char *LinkArg : LinkCommand->getArguments()) CmdArgs.push_back(LinkArg); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h index 79407c9884d5..0f503c4bd1c4 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h @@ -10,13 +10,13 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H #include "MSVC.h" -#include "clang/Basic/DebugInfoOptions.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" #include "clang/Driver/Types.h" -#include "llvm/ADT/Triple.h" +#include "llvm/Frontend/Debug/Options.h" #include "llvm/Option/Option.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" namespace clang { class ObjCRuntime; @@ -57,6 +57,8 @@ private: bool KernelOrKext) const; void AddARM64TargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + void AddLoongArchTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; void AddPPCTargetArgs(const llvm::opt::ArgList &Args, @@ -88,9 +90,7 @@ private: RewriteKind rewrite) const; void AddClangCLArgs(const llvm::opt::ArgList &Args, types::ID InputType, - llvm::opt::ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind *DebugInfoKind, - bool *EmitCodeView) const; + llvm::opt::ArgStringList &CmdArgs) const; mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr; void DumpCompilationDatabase(Compilation &C, StringRef Filename, @@ -123,6 +123,8 @@ class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { public: ClangAs(const ToolChain &TC) : Tool("clang::as", "clang integrated assembler", TC) {} + void AddLoongArchTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; void AddX86TargetArgs(const llvm::opt::ArgList &Args, @@ -157,11 +159,11 @@ public: const char *LinkingOutput) const override; }; -/// Offload wrapper tool. -class LLVM_LIBRARY_VISIBILITY OffloadWrapper final : public Tool { +/// Offload binary tool. +class LLVM_LIBRARY_VISIBILITY OffloadPackager final : public Tool { public: - OffloadWrapper(const ToolChain &TC) - : Tool("offload wrapper", "clang-offload-wrapper", TC) {} + OffloadPackager(const ToolChain &TC) + : Tool("Offload::Packager", "clang-offload-packager", TC) {} bool hasIntegratedCPP() const override { return false; } void ConstructJob(Compilation &C, const JobAction &JA, @@ -185,6 +187,12 @@ public: const char *LinkingOutput) const override; }; +enum class DwarfFissionKind { None, Split, Single }; + +DwarfFissionKind getDebugFissionKind(const Driver &D, + const llvm::opt::ArgList &Args, + llvm::opt::Arg *&Arg); + } // end namespace tools } // end namespace driver diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp deleted file mode 100644 index 501e3a382ec1..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp +++ /dev/null @@ -1,149 +0,0 @@ -//===--- CloudABI.cpp - CloudABI 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 "CloudABI.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/InputInfo.h" -#include "clang/Driver/Options.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Support/Path.h" - -using namespace clang::driver; -using namespace clang::driver::tools; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const ToolChain &ToolChain = getToolChain(); - const Driver &D = ToolChain.getDriver(); - 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)); - - // CloudABI only supports static linkage. - CmdArgs.push_back("-Bstatic"); - CmdArgs.push_back("--no-dynamic-linker"); - - // Provide PIE linker flags in case PIE is default for the architecture. - if (ToolChain.isPIEDefault(Args)) { - CmdArgs.push_back("-pie"); - CmdArgs.push_back("-zrelro"); - } - - CmdArgs.push_back("--eh-frame-hdr"); - CmdArgs.push_back("--gc-sections"); - - 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)) { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_Z_Flag, 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); - } - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (ToolChain.ShouldLinkCXXStdlib(Args)) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lcompiler_rt"); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); - - const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -// CloudABI - CloudABI tool chain which can call ld(1) directly. - -CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - SmallString<128> P(getDriver().Dir); - llvm::sys::path::append(P, "..", getTriple().str(), "lib"); - getFilePaths().push_back(std::string(P.str())); -} - -void CloudABI::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - SmallString<128> P(getDriver().Dir); - llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1"); - addSystemInclude(DriverArgs, CC1Args, P.str()); -} - -void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lunwind"); -} - -Tool *CloudABI::buildLinker() const { - return new tools::cloudabi::Linker(*this); -} - -bool CloudABI::isPIEDefault(const llvm::opt::ArgList &Args) const { - // Only enable PIE on architectures that support PC-relative - // addressing. PC-relative addressing is required, as the process - // startup code must be able to relocate itself. - switch (getTriple().getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::x86_64: - return true; - default: - return false; - } -} - -SanitizerMask CloudABI::getSupportedSanitizers() const { - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - Res |= SanitizerKind::SafeStack; - return Res; -} - -SanitizerMask CloudABI::getDefaultSanitizers() const { - return SanitizerKind::SafeStack; -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h deleted file mode 100644 index 8856fe3dde6d..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h +++ /dev/null @@ -1,70 +0,0 @@ -//===--- CloudABI.h - CloudABI 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H - -#include "Gnu.h" -#include "clang/Driver/Tool.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { - -/// cloudabi -- Directly call GNU Binutils linker -namespace cloudabi { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { -public: - Linker(const ToolChain &TC) : Tool("cloudabi::Linker", "linker", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace cloudabi -} // end namespace tools - -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF { -public: - CloudABI(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - bool HasNativeLLVMSupport() const override { return true; } - - bool IsMathErrnoDefault() const override { return false; } - bool IsObjCNonFragileABIDefault() const override { return true; } - - CXXStdlibType - GetCXXStdlibType(const llvm::opt::ArgList &Args) const override { - return ToolChain::CST_Libcxx; - } - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - bool isPIEDefault(const llvm::opt::ArgList &Args) const override; - SanitizerMask getSupportedSanitizers() const override; - SanitizerMask getDefaultSanitizers() const override; - -protected: - Tool *buildLinker() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp index dfcef2304040..2b916f000336 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -9,15 +9,22 @@ #include "CommonArgs.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" +#include "Arch/CSKY.h" +#include "Arch/LoongArch.h" #include "Arch/M68k.h" #include "Arch/Mips.h" #include "Arch/PPC.h" +#include "Arch/RISCV.h" +#include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "Arch/VE.h" #include "Arch/X86.h" #include "HIPAMD.h" #include "Hexagon.h" +#include "MSP430.h" +#include "Solaris.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" @@ -39,6 +46,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Config/llvm-config.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" @@ -48,39 +56,180 @@ #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" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/TargetParser.h" +#include <optional> using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs) { +static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + if (Args.hasArg(clang::driver::options::OPT_pg) && + !Args.hasArg(clang::driver::options::OPT_mfentry)) + return true; + + if (Triple.isAndroid()) { + switch (Triple.getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::riscv64: + return true; + default: + break; + } + } + + switch (Triple.getArch()) { + case llvm::Triple::xcore: + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + case llvm::Triple::msp430: + // XCore never wants frame pointers, regardless of OS. + // WebAssembly never wants frame pointers. + return false; + case llvm::Triple::ppc: + case llvm::Triple::ppcle: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + case llvm::Triple::amdgcn: + case llvm::Triple::r600: + case llvm::Triple::csky: + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + return !clang::driver::tools::areOptimizationsEnabled(Args); + default: + break; + } + + if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) { + return !clang::driver::tools::areOptimizationsEnabled(Args); + } + + if (Triple.isOSLinux() || Triple.isOSHurd()) { + switch (Triple.getArch()) { + // Don't use a frame pointer on linux if optimizing for certain targets. + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::systemz: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return !clang::driver::tools::areOptimizationsEnabled(Args); + default: + return true; + } + } + + if (Triple.isOSWindows()) { + switch (Triple.getArch()) { + case llvm::Triple::x86: + return !clang::driver::tools::areOptimizationsEnabled(Args); + case llvm::Triple::x86_64: + return Triple.isOSBinFormatMachO(); + case llvm::Triple::arm: + case llvm::Triple::thumb: + // Windows on ARM builds with FPO disabled to aid fast stack walking + return true; + default: + // All other supported Windows ISAs use xdata unwind information, so frame + // pointers are not generally useful. + return false; + } + } + + return true; +} + +static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { + switch (Triple.getArch()) { + default: + return false; + case llvm::Triple::arm: + case llvm::Triple::thumb: + // ARM Darwin targets require a frame pointer to be always present to aid + // offline debugging via backtraces. + return Triple.isOSDarwin(); + } +} + +clang::CodeGenOptions::FramePointerKind +getFramePointerKind(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + // We have 4 states: + // + // 00) leaf retained, non-leaf retained + // 01) leaf retained, non-leaf omitted (this is invalid) + // 10) leaf omitted, non-leaf retained + // (what -momit-leaf-frame-pointer was designed for) + // 11) leaf omitted, non-leaf omitted + // + // "omit" options taking precedence over "no-omit" options is the only way + // to make 3 valid states representable + llvm::opt::Arg *A = + Args.getLastArg(clang::driver::options::OPT_fomit_frame_pointer, + clang::driver::options::OPT_fno_omit_frame_pointer); + + bool OmitFP = A && A->getOption().matches( + clang::driver::options::OPT_fomit_frame_pointer); + bool NoOmitFP = A && A->getOption().matches( + clang::driver::options::OPT_fno_omit_frame_pointer); + bool OmitLeafFP = + Args.hasFlag(clang::driver::options::OPT_momit_leaf_frame_pointer, + clang::driver::options::OPT_mno_omit_leaf_frame_pointer, + Triple.isAArch64() || Triple.isPS() || Triple.isVE() || + (Triple.isAndroid() && Triple.isRISCV64())); + if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || + (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { + if (OmitLeafFP) + return clang::CodeGenOptions::FramePointerKind::NonLeaf; + return clang::CodeGenOptions::FramePointerKind::All; + } + return clang::CodeGenOptions::FramePointerKind::None; +} + +static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs, + const StringRef PluginOptPrefix) { if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ)) - CmdArgs.push_back(Args.MakeArgString(Twine("--plugin-opt=-pass-remarks=") + - A->getValue())); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "-pass-remarks=" + A->getValue())); if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ)) CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=-pass-remarks-missed=") + A->getValue())); + Twine(PluginOptPrefix) + "-pass-remarks-missed=" + A->getValue())); if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ)) CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=-pass-remarks-analysis=") + A->getValue())); + Twine(PluginOptPrefix) + "-pass-remarks-analysis=" + A->getValue())); } static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, const llvm::Triple &Triple, const InputInfo &Input, - const InputInfo &Output) { + const InputInfo &Output, + const StringRef PluginOptPrefix) { StringRef Format = "yaml"; if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) Format = A->getValue(); @@ -94,29 +243,47 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, assert(!F.empty() && "Cannot determine remarks output name."); // Append "opt.ld.<format>" to the end of the file name. - CmdArgs.push_back( - Args.MakeArgString(Twine("--plugin-opt=opt-remarks-filename=") + F + - Twine(".opt.ld.") + Format)); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "opt-remarks-filename=" + F + + ".opt.ld." + Format)); if (const Arg *A = Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=opt-remarks-passes=") + A->getValue())); + Twine(PluginOptPrefix) + "opt-remarks-passes=" + A->getValue())); - CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=opt-remarks-format=") + Format.data())); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "opt-remarks-format=" + Format.data())); } static void renderRemarksHotnessOptions(const ArgList &Args, - ArgStringList &CmdArgs) { + ArgStringList &CmdArgs, + const StringRef PluginOptPrefix) { if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, options::OPT_fno_diagnostics_show_hotness, false)) - CmdArgs.push_back("--plugin-opt=opt-remarks-with-hotness"); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "opt-remarks-with-hotness")); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) - CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=opt-remarks-hotness-threshold=") + A->getValue())); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + + "opt-remarks-hotness-threshold=" + A->getValue())); +} + +static bool shouldIgnoreUnsupportedTargetFeature(const Arg &TargetFeatureArg, + llvm::Triple T, + StringRef Processor) { + // Warn no-cumode for AMDGCN processors not supporing WGP mode. + if (!T.isAMDGPU()) + return false; + auto GPUKind = T.isAMDGCN() ? llvm::AMDGPU::parseArchAMDGCN(Processor) + : llvm::AMDGPU::parseArchR600(Processor); + auto GPUFeatures = T.isAMDGCN() ? llvm::AMDGPU::getArchAttrAMDGCN(GPUKind) + : llvm::AMDGPU::getArchAttrR600(GPUKind); + if (GPUFeatures & llvm::AMDGPU::FEATURE_WGP) + return false; + return TargetFeatureArg.getOption().matches(options::OPT_mno_cumode); } void tools::addPathIfExists(const Driver &D, const Twine &Path, @@ -125,46 +292,49 @@ void tools::addPathIfExists(const Driver &D, const Twine &Path, Paths.push_back(Path.str()); } -void tools::handleTargetFeaturesGroup(const ArgList &Args, +void tools::handleTargetFeaturesGroup(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, std::vector<StringRef> &Features, OptSpecifier Group) { + std::set<StringRef> Warned; for (const Arg *A : Args.filtered(Group)) { StringRef Name = A->getOption().getName(); A->claim(); // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); + assert(Name.starts_with("m") && "Invalid feature name."); Name = Name.substr(1); - bool IsNegative = Name.startswith("no-"); + auto Proc = getCPUName(D, Args, Triple); + if (shouldIgnoreUnsupportedTargetFeature(*A, Triple, Proc)) { + if (Warned.count(Name) == 0) { + D.getDiags().Report( + clang::diag::warn_drv_unsupported_option_for_processor) + << A->getAsString(Args) << Proc; + Warned.insert(Name); + } + continue; + } + + bool IsNegative = Name.starts_with("no-"); if (IsNegative) Name = Name.substr(3); + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } } -std::vector<StringRef> -tools::unifyTargetFeatures(const std::vector<StringRef> &Features) { - std::vector<StringRef> UnifiedFeatures; - // Find the last of each feature. - llvm::StringMap<unsigned> 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; +SmallVector<StringRef> +tools::unifyTargetFeatures(ArrayRef<StringRef> Features) { + // Only add a feature if it hasn't been seen before starting from the end. + SmallVector<StringRef> UnifiedFeatures; + llvm::DenseSet<StringRef> UsedFeatures; + for (StringRef Feature : llvm::reverse(Features)) { + if (UsedFeatures.insert(Feature.drop_front()).second) + UnifiedFeatures.insert(UnifiedFeatures.begin(), Feature); } - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - // If this feature was overridden, ignore it. - StringRef Name = Features[I]; - llvm::StringMap<unsigned>::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; } @@ -255,6 +425,10 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, continue; } + // In some error cases, the input could be Nothing; skip those. + if (II.isNothing()) + continue; + // Otherwise, this is a linker input argument. const Arg &A = II.getInputArg(); @@ -263,22 +437,8 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, 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 if (A.getOption().matches(options::OPT_b)) { - const llvm::Triple &T = TC.getTriple(); - if (!T.isOSAIX()) { - TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) - << A.getSpelling() << T.str(); - } - // Pass -b prefix for AIX linker. - A.claim(); - A.render(Args, CmdArgs); - } else { + else A.renderAsInput(Args, CmdArgs); - } } } @@ -292,11 +452,11 @@ void tools::addLinkerCompressDebugSectionsOption( // argument. if (const Arg *A = Args.getLastArg(options::OPT_gz_EQ)) { StringRef V = A->getValue(); - if (V == "none" || V == "zlib") + if (V == "none" || V == "zlib" || V == "zstd") CmdArgs.push_back(Args.MakeArgString("--compress-debug-sections=" + V)); else TC.getDriver().Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << V; + << A->getSpelling() << V; } } @@ -315,6 +475,7 @@ void tools::AddTargetFeature(const ArgList &Args, /// Get the (LLVM) name of the AMDGPU gpu we are targeting. static std::string getAMDGPUTargetGPU(const llvm::Triple &T, const ArgList &Args) { + Arg *MArch = Args.getLastArg(options::OPT_march_EQ); if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { auto GPUName = getProcessorFromTargetID(T, A->getValue()); return llvm::StringSwitch<std::string>(GPUName) @@ -327,6 +488,8 @@ static std::string getAMDGPUTargetGPU(const llvm::Triple &T, .Case("aruba", "cayman") .Default(GPUName.str()); } + if (MArch) + return getProcessorFromTargetID(T, MArch->getValue()).str(); return ""; } @@ -405,41 +568,30 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args, case llvm::Triple::ppc: case llvm::Triple::ppcle: 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 = "pwr7"; - else if (T.getArch() == llvm::Triple::ppc64le) - TargetCPUName = "ppc64le"; - else if (T.getArch() == llvm::Triple::ppc64) - TargetCPUName = "ppc64"; - else - TargetCPUName = "ppc"; + case llvm::Triple::ppc64le: + return ppc::getPPCTargetCPU(D, Args, T); - return TargetCPUName; - } + case llvm::Triple::csky: + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + return A->getValue(); + else if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + return A->getValue(); + else + return "ck810"; case llvm::Triple::riscv32: case llvm::Triple::riscv64: + return riscv::getRISCVTargetCPU(Args, T); + + case llvm::Triple::bpfel: + case llvm::Triple::bpfeb: 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(); - if (T.getArch() == llvm::Triple::sparc && T.isOSSolaris()) - return "v9"; - return ""; + return sparc::getSparcTargetCPU(D, Args, T); case llvm::Triple::x86: case llvm::Triple::x86_64: @@ -462,6 +614,103 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args, case llvm::Triple::wasm32: case llvm::Triple::wasm64: return std::string(getWebAssemblyTargetCPU(Args)); + + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + return loongarch::getLoongArchTargetCPU(Args, T); + } +} + +static void getWebAssemblyTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, + std::vector<StringRef> &Features) { + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_wasm_Features_Group); +} + +void tools::getTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, ArgStringList &CmdArgs, + bool ForAS, bool IsAux) { + std::vector<StringRef> Features; + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + mips::getMIPSTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + arm::getARMTargetFeatures(D, Triple, Args, Features, ForAS); + break; + case llvm::Triple::ppc: + case llvm::Triple::ppcle: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + ppc::getPPCTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + riscv::getRISCVTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::systemz: + systemz::getSystemZTargetFeatures(D, Args, Features); + break; + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: + case llvm::Triple::aarch64_be: + aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + x86::getX86TargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::hexagon: + hexagon::getHexagonTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + getWebAssemblyTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + sparc::getSparcTargetFeatures(D, Args, Features); + break; + case llvm::Triple::r600: + case llvm::Triple::amdgcn: + amdgpu::getAMDGPUTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + NVPTX::getNVPTXTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::m68k: + m68k::getM68kTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::msp430: + msp430::getMSP430TargetFeatures(D, Args, Features); + break; + case llvm::Triple::ve: + ve::getVETargetFeatures(D, Args, Features); + break; + case llvm::Triple::csky: + csky::getCSKYTargetFeatures(D, Triple, Args, CmdArgs, Features); + break; + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + loongarch::getLoongArchTargetFeatures(D, Triple, Args, Features); + break; + } + + for (auto Feature : unifyTargetFeatures(Features)) { + CmdArgs.push_back(IsAux ? "-aux-target-feature" : "-target-feature"); + CmdArgs.push_back(Feature.data()); } } @@ -475,22 +724,58 @@ llvm::StringRef tools::getLTOParallelism(const ArgList &Args, const Driver &D) { return LtoJobsArg->getValue(); } -// CloudABI uses -ffunction-sections and -fdata-sections by default. +// PS4/PS5 uses -ffunction-sections and -fdata-sections by default. bool tools::isUseSeparateSections(const llvm::Triple &Triple) { - return Triple.getOS() == llvm::Triple::CloudABI; + return Triple.isPS(); +} + +bool tools::isTLSDESCEnabled(const ToolChain &TC, + const llvm::opt::ArgList &Args) { + const llvm::Triple &Triple = TC.getEffectiveTriple(); + Arg *A = Args.getLastArg(options::OPT_mtls_dialect_EQ); + if (!A) + return Triple.hasDefaultTLSDESC(); + StringRef V = A->getValue(); + bool SupportedArgument = false, EnableTLSDESC = false; + bool Unsupported = !Triple.isOSBinFormatELF(); + if (Triple.isRISCV()) { + SupportedArgument = V == "desc" || V == "trad"; + EnableTLSDESC = V == "desc"; + } else if (Triple.isX86()) { + SupportedArgument = V == "gnu"; + } else { + Unsupported = true; + } + if (Unsupported) { + TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << Triple.getTriple(); + } else if (!SupportedArgument) { + TC.getDriver().Diag(diag::err_drv_unsupported_option_argument_for_target) + << A->getSpelling() << V << Triple.getTriple(); + } + return EnableTLSDESC; } void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO) { + const bool IsOSAIX = ToolChain.getTriple().isOSAIX(); + const bool IsAMDGCN = ToolChain.getTriple().isAMDGCN(); const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath()); const Driver &D = ToolChain.getDriver(); + const bool IsFatLTO = Args.hasArg(options::OPT_ffat_lto_objects); + const bool IsUnifiedLTO = Args.hasArg(options::OPT_funified_lto); if (llvm::sys::path::filename(Linker) != "ld.lld" && - llvm::sys::path::stem(Linker) != "ld.lld") { + llvm::sys::path::stem(Linker) != "ld.lld" && + !ToolChain.getTriple().isOSOpenBSD()) { // 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"); + // AddLinkerInputs as gold requires -plugin and AIX ld requires -bplugin to + // come before any -plugin-opt/-bplugin_opt that -Wl might forward. + const char *PluginPrefix = IsOSAIX ? "-bplugin:" : ""; + const char *PluginName = IsOSAIX ? "/libLTO" : "/LLVMgold"; + + if (!IsOSAIX) + CmdArgs.push_back("-plugin"); #if defined(_WIN32) const char *Suffix = ".dll"; @@ -501,10 +786,50 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, #endif SmallString<1024> Plugin; - llvm::sys::path::native( - Twine(D.Dir) + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + Suffix, - Plugin); - CmdArgs.push_back(Args.MakeArgString(Plugin)); + llvm::sys::path::native(Twine(D.Dir) + + "/../" CLANG_INSTALL_LIBDIR_BASENAME + + PluginName + Suffix, + Plugin); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginPrefix) + Plugin)); + } else { + // Tell LLD to find and use .llvm.lto section in regular relocatable object + // files + if (IsFatLTO) + CmdArgs.push_back("--fat-lto-objects"); + } + + const char *PluginOptPrefix = IsOSAIX ? "-bplugin_opt:" : "-plugin-opt="; + const char *ExtraDash = IsOSAIX ? "-" : ""; + const char *ParallelismOpt = IsOSAIX ? "-threads=" : "jobs="; + + // Note, this solution is far from perfect, better to encode it into IR + // metadata, but this may not be worth it, since it looks like aranges is on + // the way out. + if (Args.hasArg(options::OPT_gdwarf_aranges)) { + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "-generate-arange-section")); + } + + // Pass vector library arguments to LTO. + Arg *ArgVecLib = Args.getLastArg(options::OPT_fveclib); + if (ArgVecLib && ArgVecLib->getNumValues() == 1) { + // Map the vector library names from clang front-end to opt front-end. The + // values are taken from the TargetLibraryInfo class command line options. + std::optional<StringRef> OptVal = + llvm::StringSwitch<std::optional<StringRef>>(ArgVecLib->getValue()) + .Case("Accelerate", "Accelerate") + .Case("LIBMVEC", "LIBMVEC-X86") + .Case("MASSV", "MASSV") + .Case("SVML", "SVML") + .Case("SLEEF", "sleefgnuabi") + .Case("Darwin_libsystem_m", "Darwin_libsystem_m") + .Case("ArmPL", "ArmPL") + .Case("none", "none") + .Default(std::nullopt); + + if (OptVal) + CmdArgs.push_back(Args.MakeArgString( + Twine(PluginOptPrefix) + "-vector-library=" + OptVal.value())); } // Try to pass driver level flags relevant to LTO code generation down to @@ -513,7 +838,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, // Handle flags for selecting CPU variants. std::string CPU = getCPUName(D, Args, ToolChain.getTriple()); if (!CPU.empty()) - CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "mcpu=" + CPU)); if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { // The optimization level matches @@ -530,48 +856,140 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, 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 (!OOpt.empty()) { + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "O" + OOpt)); + if (IsAMDGCN) + CmdArgs.push_back(Args.MakeArgString(Twine("--lto-CGO") + OOpt)); + } } - if (Args.hasArg(options::OPT_gsplit_dwarf)) { + if (Args.hasArg(options::OPT_gsplit_dwarf)) + CmdArgs.push_back(Args.MakeArgString( + Twine(PluginOptPrefix) + "dwo_dir=" + Output.getFilename() + "_dwo")); + + if (IsThinLTO && !IsOSAIX) + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + "thinlto")); + else if (IsThinLTO && IsOSAIX) + CmdArgs.push_back(Args.MakeArgString(Twine("-bdbg:thinlto"))); + + // Matrix intrinsic lowering happens at link time with ThinLTO. Enable + // LowerMatrixIntrinsicsPass, which is transitively called by + // buildThinLTODefaultPipeline under EnableMatrix. + if ((IsThinLTO || IsFatLTO || IsUnifiedLTO) && + Args.hasArg(options::OPT_fenable_matrix)) CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=dwo_dir=") + - Output.getFilename() + "_dwo")); - } - - if (IsThinLTO) - CmdArgs.push_back("-plugin-opt=thinlto"); + Args.MakeArgString(Twine(PluginOptPrefix) + "-enable-matrix")); StringRef Parallelism = getLTOParallelism(Args, D); if (!Parallelism.empty()) - CmdArgs.push_back( - Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism))); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + ParallelismOpt + Parallelism)); + + // Pass down GlobalISel options. + if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel, + options::OPT_fno_global_isel)) { + // Parsing -fno-global-isel explicitly gives architectures that enable GISel + // by default a chance to disable it. + CmdArgs.push_back(Args.MakeArgString( + Twine(PluginOptPrefix) + "-global-isel=" + + (A->getOption().matches(options::OPT_fglobal_isel) ? "1" : "0"))); + } // If an explicit debugger tuning argument appeared, pass it along. - if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, - options::OPT_ggdbN_Group)) { + 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"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=lldb")); else if (A->getOption().matches(options::OPT_gsce)) - CmdArgs.push_back("-plugin-opt=-debugger-tune=sce"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=sce")); else if (A->getOption().matches(options::OPT_gdbx)) - CmdArgs.push_back("-plugin-opt=-debugger-tune=dbx"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=dbx")); else - CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=gdb")); + } + + if (IsOSAIX) { + if (!ToolChain.useIntegratedAs()) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-no-integrated-as=1")); + + // On AIX, clang assumes strict-dwarf is true if any debug option is + // specified, unless it is told explicitly not to assume so. + Arg *A = Args.getLastArg(options::OPT_g_Group); + bool EnableDebugInfo = A && !A->getOption().matches(options::OPT_g0) && + !A->getOption().matches(options::OPT_ggdb0); + if (EnableDebugInfo && Args.hasFlag(options::OPT_gstrict_dwarf, + options::OPT_gno_strict_dwarf, true)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-strict-dwarf=true")); + + for (const Arg *A : Args.filtered_reverse(options::OPT_mabi_EQ)) { + StringRef V = A->getValue(); + if (V == "vec-default") + break; + if (V == "vec-extabi") { + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-vec-extabi")); + break; + } + } } 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"); - } + options::OPT_fno_function_sections, UseSeparateSections)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=1")); + else if (Args.hasArg(options::OPT_fno_function_sections)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=0")); + bool DataSectionsTurnedOff = false; if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, UseSeparateSections)) { - CmdArgs.push_back("-plugin-opt=-data-sections"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=1")); + } else if (Args.hasArg(options::OPT_fno_data_sections)) { + DataSectionsTurnedOff = true; + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=0")); + } + + if (Args.hasArg(options::OPT_mxcoff_roptr) || + Args.hasArg(options::OPT_mno_xcoff_roptr)) { + bool HasRoptr = Args.hasFlag(options::OPT_mxcoff_roptr, + options::OPT_mno_xcoff_roptr, false); + StringRef OptStr = HasRoptr ? "-mxcoff-roptr" : "-mno-xcoff-roptr"; + + if (!IsOSAIX) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << OptStr << ToolChain.getTriple().str(); + + if (HasRoptr) { + // The data sections option is on by default on AIX. We only need to error + // out when -fno-data-sections is specified explicitly to turn off data + // sections. + if (DataSectionsTurnedOff) + D.Diag(diag::err_roptr_requires_data_sections); + + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-mxcoff-roptr")); + } + } + + // Pass an option to enable split machine functions. + if (auto *A = Args.getLastArg(options::OPT_fsplit_machine_functions, + options::OPT_fno_split_machine_functions)) { + if (A->getOption().matches(options::OPT_fsplit_machine_functions)) + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "-split-machine-functions")); } if (Arg *A = getLastProfileSampleUseArg(Args)) { @@ -579,101 +997,126 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, 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)); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "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 (auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args)) { + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + + "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)); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + + "cs-profile-path=" + Path)); } else CmdArgs.push_back( - Args.MakeArgString("-plugin-opt=cs-profile-path=default_%m.profraw")); - } else if (ProfileUseArg) { + Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + + "cs-profile-path=default_%m.profraw")); + } else if (auto *ProfileUseArg = getLastProfileUseArg(Args)) { 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)); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + + "cs-profile-path=" + Path)); } - // Pass an option to enable/disable the new pass manager. - if (auto *A = Args.getLastArg(options::OPT_flegacy_pass_manager, - options::OPT_fno_legacy_pass_manager)) { - if (A->getOption().matches(options::OPT_flegacy_pass_manager)) - CmdArgs.push_back("-plugin-opt=legacy-pass-manager"); + // This controls whether or not we perform JustMyCode instrumentation. + if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) { + if (ToolChain.getEffectiveTriple().isOSBinFormatELF()) + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "-enable-jmc-instrument")); else - CmdArgs.push_back("-plugin-opt=new-pass-manager"); + D.Diag(clang::diag::warn_drv_fjmc_for_elf_only); } + if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, + ToolChain.getTriple().hasDefaultEmulatedTLS())) { + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-emulated-tls")); + } + if (isTLSDESCEnabled(ToolChain, Args)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-enable-tlsdesc")); + + if (Args.hasFlag(options::OPT_fstack_size_section, + options::OPT_fno_stack_size_section, false)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-stack-size-section")); + // 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)); + Args.MakeArgString(Twine(PluginOptPrefix) + "stats-file=" + StatsFile)); + + // Setup crash diagnostics dir. + if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir)) + CmdArgs.push_back(Args.MakeArgString( + Twine(PluginOptPrefix) + "-crash-diagnostics-dir=" + A->getValue())); - addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true); + addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true, PluginOptPrefix); // Handle remark diagnostics on screen options: '-Rpass-*'. - renderRpassOptions(Args, CmdArgs); + renderRpassOptions(Args, CmdArgs, PluginOptPrefix); // Handle serialized remarks options: '-fsave-optimization-record' // and '-foptimization-record-*'. if (willEmitRemarks(Args)) renderRemarksOptions(Args, CmdArgs, ToolChain.getEffectiveTriple(), Input, - Output); + Output, PluginOptPrefix); // Handle remarks hotness/threshold related options. - renderRemarksHotnessOptions(Args, CmdArgs); + renderRemarksHotnessOptions(Args, CmdArgs, PluginOptPrefix); addMachineOutlinerArgs(D, Args, CmdArgs, ToolChain.getEffectiveTriple(), - /*IsLTO=*/true); + /*IsLTO=*/true, PluginOptPrefix); } -void tools::addOpenMPRuntimeSpecificRPath(const ToolChain &TC, - const ArgList &Args, - ArgStringList &CmdArgs) { +/// Adds the '-lcgpu' and '-lmgpu' libraries to the compilation to include the +/// LLVM C library for GPUs. +static void addOpenMPDeviceLibC(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_nogpulib) || Args.hasArg(options::OPT_nolibc)) + return; - if (Args.hasFlag(options::OPT_fopenmp_implicit_rpath, - options::OPT_fno_openmp_implicit_rpath, true)) { - // Default to clang lib / lib64 folder, i.e. the same location as device - // runtime - SmallString<256> DefaultLibPath = - llvm::sys::path::parent_path(TC.getDriver().Dir); - llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX); - CmdArgs.push_back("-rpath"); - CmdArgs.push_back(Args.MakeArgString(DefaultLibPath)); + // Check the resource directory for the LLVM libc GPU declarations. If it's + // found we can assume that LLVM was built with support for the GPU libc. + SmallString<256> LibCDecls(TC.getDriver().ResourceDir); + llvm::sys::path::append(LibCDecls, "include", "llvm_libc_wrappers", + "llvm-libc-decls"); + bool HasLibC = llvm::sys::fs::exists(LibCDecls) && + llvm::sys::fs::is_directory(LibCDecls); + if (Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, HasLibC)) { + CmdArgs.push_back("-lcgpu"); + CmdArgs.push_back("-lmgpu"); } } +void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC, + const ArgList &Args, + ArgStringList &CmdArgs) { + // Default to clang lib / lib64 folder, i.e. the same location as device + // runtime. + SmallString<256> DefaultLibPath = + llvm::sys::path::parent_path(TC.getDriver().Dir); + llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME); + CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath)); +} + 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)) + options::OPT_fno_rtlib_add_rpath, false)) return; - std::string CandidateRPath = TC.getArchSpecificLibPath(); - if (TC.getVFS().exists(CandidateRPath)) { - CmdArgs.push_back("-rpath"); - CmdArgs.push_back(Args.MakeArgString(CandidateRPath)); + for (const auto &CandidateRPath : TC.getArchSpecificLibPaths()) { + if (TC.getVFS().exists(CandidateRPath)) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back(Args.MakeArgString(CandidateRPath)); + } } } @@ -716,14 +1159,155 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, if (IsOffloadingHost) CmdArgs.push_back("-lomptarget"); - addArchSpecificRPath(TC, Args, CmdArgs); + if (IsOffloadingHost && !Args.hasArg(options::OPT_nogpulib)) + CmdArgs.push_back("-lomptarget.devicertl"); + + if (IsOffloadingHost) + addOpenMPDeviceLibC(TC, Args, CmdArgs); - if (RTKind == Driver::OMPRT_OMP) - addOpenMPRuntimeSpecificRPath(TC, Args, CmdArgs); + addArchSpecificRPath(TC, Args, CmdArgs); + addOpenMPRuntimeLibraryPath(TC, Args, CmdArgs); return true; } +/// Determines if --whole-archive is active in the list of arguments. +static bool isWholeArchivePresent(const ArgList &Args) { + bool WholeArchiveActive = false; + for (auto *Arg : Args.filtered(options::OPT_Wl_COMMA)) { + if (Arg) { + for (StringRef ArgValue : Arg->getValues()) { + if (ArgValue == "--whole-archive") + WholeArchiveActive = true; + if (ArgValue == "--no-whole-archive") + WholeArchiveActive = false; + } + } + } + + return WholeArchiveActive; +} + +/// Determine if driver is invoked to create a shared object library (-static) +static bool isSharedLinkage(const ArgList &Args) { + return Args.hasArg(options::OPT_shared); +} + +/// Determine if driver is invoked to create a static object library (-shared) +static bool isStaticLinkage(const ArgList &Args) { + return Args.hasArg(options::OPT_static); +} + +/// Add Fortran runtime libs for MSVC +static void addFortranRuntimeLibsMSVC(const ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + unsigned RTOptionID = options::OPT__SLASH_MT; + if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue()) + .Case("static", options::OPT__SLASH_MT) + .Case("static_dbg", options::OPT__SLASH_MTd) + .Case("dll", options::OPT__SLASH_MD) + .Case("dll_dbg", options::OPT__SLASH_MDd) + .Default(options::OPT__SLASH_MT); + } + switch (RTOptionID) { + case options::OPT__SLASH_MT: + CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static.lib"); + break; + case options::OPT__SLASH_MTd: + CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static_dbg.lib"); + break; + case options::OPT__SLASH_MD: + CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic.lib"); + break; + case options::OPT__SLASH_MDd: + CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic_dbg.lib"); + break; + } +} + +// Add FortranMain runtime lib +static void addFortranMain(const ToolChain &TC, const ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + // 0. Shared-library linkage + // If we are attempting to link a library, we should not add + // -lFortran_main.a to the link line, as the `main` symbol is not + // required for a library and should also be provided by one of + // the translation units of the code that this shared library + // will be linked against eventually. + if (isSharedLinkage(Args) || isStaticLinkage(Args)) { + return; + } + + // 1. MSVC + if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { + addFortranRuntimeLibsMSVC(Args, CmdArgs); + return; + } + + // 2. GNU and similar + const Driver &D = TC.getDriver(); + const char *FortranMainLinkFlag = "-lFortran_main"; + + // Warn if the user added `-lFortran_main` - this library is an implementation + // detail of Flang and should be handled automaticaly by the driver. + for (const char *arg : CmdArgs) { + if (strncmp(arg, FortranMainLinkFlag, strlen(FortranMainLinkFlag)) == 0) + D.Diag(diag::warn_drv_deprecated_custom) + << FortranMainLinkFlag + << "see the Flang driver documentation for correct usage"; + } + + // The --whole-archive option needs to be part of the link line to make + // sure that the main() function from Fortran_main.a is pulled in by the + // linker. However, it shouldn't be used if it's already active. + // TODO: Find an equivalent of `--whole-archive` for Darwin and AIX. + if (!isWholeArchivePresent(Args) && !TC.getTriple().isMacOSX() && + !TC.getTriple().isOSAIX()) { + CmdArgs.push_back("--whole-archive"); + CmdArgs.push_back(FortranMainLinkFlag); + CmdArgs.push_back("--no-whole-archive"); + return; + } + + CmdArgs.push_back(FortranMainLinkFlag); +} + +/// Add Fortran runtime libs +void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + // 1. Link FortranMain + // FortranMain depends on FortranRuntime, so needs to be listed first. If + // -fno-fortran-main has been passed, skip linking Fortran_main.a + if (!Args.hasArg(options::OPT_no_fortran_main)) + addFortranMain(TC, Args, CmdArgs); + + // 2. Link FortranRuntime and FortranDecimal + // These are handled earlier on Windows by telling the frontend driver to + // add the correct libraries to link against as dependents in the object + // file. + if (!TC.getTriple().isKnownWindowsMSVCEnvironment()) { + CmdArgs.push_back("-lFortranRuntime"); + CmdArgs.push_back("-lFortranDecimal"); + } +} + +void tools::addFortranRuntimeLibraryPath(const ToolChain &TC, + const llvm::opt::ArgList &Args, + ArgStringList &CmdArgs) { + // Default to the <driver-path>/../lib directory. This works fine on the + // platforms that we have tested so far. We will probably have to re-fine + // this in the future. In particular, on some platforms, we may need to use + // lib64 instead of lib. + SmallString<256> DefaultLibPath = + llvm::sys::path::parent_path(TC.getDriver().Dir); + llvm::sys::path::append(DefaultLibPath, "lib"); + if (TC.getTriple().isKnownWindowsMSVCEnvironment()) + CmdArgs.push_back(Args.MakeArgString("-libpath:" + DefaultLibPath)); + else + CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath)); +} + static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer, bool IsShared, bool IsWhole) { @@ -744,9 +1328,11 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer) { + bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args); + // 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) + if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd) return true; SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer)); if (llvm::sys::fs::exists(SanRT + ".syms")) { @@ -756,32 +1342,36 @@ static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, return false; } -const char *tools::getAsNeededOption(const ToolChain &TC, bool as_needed) { +void tools::addAsNeededOption(const ToolChain &TC, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + bool as_needed) { assert(!TC.getTriple().isOSAIX() && "AIX linker does not support any form of --as-needed option yet."); + bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args); // While the Solaris 11.2 ld added --as-needed/--no-as-needed as aliases // for the native forms -z ignore/-z record, they are missing in Illumos, // so always use the native form. - if (TC.getTriple().isOSSolaris()) - return as_needed ? "-zignore" : "-zrecord"; - else - return as_needed ? "--as-needed" : "--no-as-needed"; + // GNU ld doesn't support -z ignore/-z record, so don't use them even on + // Solaris. + if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd) { + CmdArgs.push_back("-z"); + CmdArgs.push_back(as_needed ? "ignore" : "record"); + } else { + CmdArgs.push_back(as_needed ? "--as-needed" : "--no-as-needed"); + } } void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, + const llvm::opt::ArgList &Args, 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(getAsNeededOption(TC, false)); + addAsNeededOption(TC, Args, CmdArgs, false); // There's no libpthread or librt on RTEMS & Android. if (TC.getTriple().getOS() != llvm::Triple::RTEMS && - !TC.getTriple().isAndroid()) { + !TC.getTriple().isAndroid() && !TC.getTriple().isOHOSFamily()) { CmdArgs.push_back("-lpthread"); if (!TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lrt"); @@ -797,6 +1387,12 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, TC.getTriple().isOSNetBSD() || TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lexecinfo"); + // There is no libresolv on Android, FreeBSD, OpenBSD, etc. On musl + // libresolv.a, even if exists, is an empty archive to satisfy POSIX -lresolv + // requirement. + if (TC.getTriple().isOSLinux() && !TC.getTriple().isAndroid() && + !TC.getTriple().isMusl()) + CmdArgs.push_back("-lresolv"); } static void @@ -809,40 +1405,39 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); // Collect shared runtimes. if (SanArgs.needsSharedRt()) { - if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsAsanRt()) { SharedRuntimes.push_back("asan"); if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid()) HelperStaticRuntimes.push_back("asan-preinit"); } - if (SanArgs.needsMemProfRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsMemProfRt()) { SharedRuntimes.push_back("memprof"); if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid()) HelperStaticRuntimes.push_back("memprof-preinit"); } - if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsUbsanRt()) { 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.needsScudoRt()) { + SharedRuntimes.push_back("scudo_standalone"); } - if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes()) + if (SanArgs.needsTsanRt()) SharedRuntimes.push_back("tsan"); - if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsHwasanRt()) { if (SanArgs.needsHwasanAliasesRt()) SharedRuntimes.push_back("hwasan_aliases"); else SharedRuntimes.push_back("hwasan"); + if (!Args.hasArg(options::OPT_shared)) + HelperStaticRuntimes.push_back("hwasan-preinit"); } } // The stats_client library is also statically linked into DSOs. - if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) + if (SanArgs.needsStatsRt()) StaticRuntimes.push_back("stats_client"); // Always link the static runtime regardless of DSO or executable. @@ -858,20 +1453,19 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, // 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()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt()) { StaticRuntimes.push_back("asan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("asan_cxx"); } - if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt() && - SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt()) { StaticRuntimes.push_back("memprof"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("memprof_cxx"); } - if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt()) { if (SanArgs.needsHwasanAliasesRt()) { StaticRuntimes.push_back("hwasan_aliases"); if (SanArgs.linkCXXRuntimes()) @@ -882,22 +1476,21 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("hwasan_cxx"); } } - if (SanArgs.needsDfsanRt() && SanArgs.linkRuntimes()) + if (SanArgs.needsDfsanRt()) StaticRuntimes.push_back("dfsan"); - if (SanArgs.needsLsanRt() && SanArgs.linkRuntimes()) + if (SanArgs.needsLsanRt()) StaticRuntimes.push_back("lsan"); - if (SanArgs.needsMsanRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsMsanRt()) { StaticRuntimes.push_back("msan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("msan_cxx"); } - if (!SanArgs.needsSharedRt() && SanArgs.needsTsanRt() && - SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsTsanRt()) { StaticRuntimes.push_back("tsan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("tsan_cxx"); } - if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) { if (SanArgs.requiresMinimalRuntime()) { StaticRuntimes.push_back("ubsan_minimal"); } else { @@ -906,33 +1499,27 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("ubsan_standalone_cxx"); } } - if (SanArgs.needsSafeStackRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsSafeStackRt()) { NonWholeStaticRuntimes.push_back("safestack"); RequiredSymbols.push_back("__safestack_init"); } - if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes())) { - if (SanArgs.needsCfiRt() && SanArgs.linkRuntimes()) + if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt())) { + if (SanArgs.needsCfiRt()) StaticRuntimes.push_back("cfi"); - if (SanArgs.needsCfiDiagRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsCfiDiagRt()) { StaticRuntimes.push_back("cfi_diag"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("ubsan_standalone_cxx"); } } - if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsStatsRt()) { 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"); - } + if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt()) { + StaticRuntimes.push_back("scudo_standalone"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("scudo_standalone_cxx"); } } @@ -940,13 +1527,15 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, // 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) { + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols; - collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, - NonWholeStaticRuntimes, HelperStaticRuntimes, - RequiredSymbols); + if (SanArgs.linkRuntimes()) { + collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, + NonWholeStaticRuntimes, HelperStaticRuntimes, + RequiredSymbols); + } - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); // Inject libfuzzer dependencies. if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() && !Args.hasArg(options::OPT_shared)) { @@ -991,6 +1580,19 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) CmdArgs.push_back("--export-dynamic-symbol=__cfi_check"); + if (SanArgs.hasMemTag()) { + if (!TC.getTriple().isAndroid()) { + TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << "-fsanitize=memtag*" << TC.getTriple().str(); + } + CmdArgs.push_back( + Args.MakeArgString("--android-memtag-mode=" + SanArgs.getMemtagMode())); + if (SanArgs.hasMemtagHeap()) + CmdArgs.push_back("--android-memtag-heap"); + if (SanArgs.hasMemtagStack()) + CmdArgs.push_back("--android-memtag-stack"); + } + return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty(); } @@ -999,19 +1601,21 @@ bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args, ArgStringLis return false; if (TC.getXRayArgs().needsXRayRt()) { - CmdArgs.push_back("-whole-archive"); + 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"); + CmdArgs.push_back("--no-whole-archive"); return true; } return false; } -void tools::linkXRayRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { - CmdArgs.push_back(getAsNeededOption(TC, false)); +void tools::linkXRayRuntimeDeps(const ToolChain &TC, + const llvm::opt::ArgList &Args, + ArgStringList &CmdArgs) { + addAsNeededOption(TC, Args, CmdArgs, false); CmdArgs.push_back("-lpthread"); if (!TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lrt"); @@ -1040,26 +1644,27 @@ const char *tools::SplitDebugName(const JobAction &JA, const ArgList &Args, F += ".dwo"; }; if (Arg *A = Args.getLastArg(options::OPT_gsplit_dwarf_EQ)) - if (StringRef(A->getValue()) == "single") + if (StringRef(A->getValue()) == "single" && Output.isFilename()) 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::remove_filename(T); - llvm::sys::path::append(T, llvm::sys::path::stem(FinalOutput->getValue())); - AddPostfix(T); - return Args.MakeArgString(T); + SmallString<128> T; + if (const Arg *A = Args.getLastArg(options::OPT_dumpdir)) { + T = A->getValue(); } else { - // Use the compilation dir. - Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, - options::OPT_fdebug_compilation_dir_EQ); - SmallString<128> T(A ? A->getValue() : ""); - SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput())); - AddPostfix(F); - T += F; - return Args.MakeArgString(T); + Arg *FinalOutput = Args.getLastArg(options::OPT_o, options::OPT__SLASH_o); + if (FinalOutput && Args.hasArg(options::OPT_c)) { + T = FinalOutput->getValue(); + llvm::sys::path::remove_filename(T); + llvm::sys::path::append(T, + llvm::sys::path::stem(FinalOutput->getValue())); + AddPostfix(T); + return Args.MakeArgString(T); + } } + + T += llvm::sys::path::stem(Input.getBaseInput()); + AddPostfix(T); + return Args.MakeArgString(T); } void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, @@ -1101,6 +1706,17 @@ void tools::claimNoWarnArgs(const ArgList &Args) { Args.ClaimAllArgs(options::OPT_fno_lto); } +Arg *tools::getLastCSProfileGenerateArg(const ArgList &Args) { + 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; + + return CSPGOGenerateArg; +} + Arg *tools::getLastProfileUseArg(const ArgList &Args) { auto *ProfileUseArg = Args.getLastArg( options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, @@ -1130,6 +1746,24 @@ Arg *tools::getLastProfileSampleUseArg(const ArgList &Args) { options::OPT_fauto_profile_EQ); } +const char *tools::RelocationModelName(llvm::Reloc::Model Model) { + switch (Model) { + case llvm::Reloc::Static: + return "static"; + case llvm::Reloc::PIC_: + return "pic"; + case llvm::Reloc::DynamicNoPIC: + return "dynamic-no-pic"; + case llvm::Reloc::ROPI: + return "ropi"; + case llvm::Reloc::RWPI: + return "rwpi"; + case llvm::Reloc::ROPI_RWPI: + return "ropi-rwpi"; + } + llvm_unreachable("Unknown Reloc::Model kind"); +} + /// 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 @@ -1175,6 +1809,10 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { } } + // OHOS-specific defaults for PIC/PIE + if (Triple.isOHOSFamily() && Triple.getArch() == llvm::Triple::aarch64) + PIC = true; + // OpenBSD-specific defaults for PIE if (Triple.isOSOpenBSD()) { switch (ToolChain.getArch()) { @@ -1197,10 +1835,6 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { } } - // AMDGPU-specific defaults for PIC. - if (Triple.getArch() == llvm::Triple::amdgcn) - PIC = true; - // The last argument relating to either PIC or PIE wins, and no // other argument is used. If the last argument is any flavor of the // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE @@ -1233,30 +1867,31 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); } else { PIE = PIC = false; - if (EffectiveTriple.isPS4CPU()) { + if (EffectiveTriple.isPS()) { 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(); + ToolChain.getDriver().Diag(diag::warn_drv_ps_force_pic) + << LastPICArg->getSpelling() + << (EffectiveTriple.isPS4() ? "PS4" : "PS5"); } } } } } - // 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 + // Introduce a Darwin and PS4/PS5-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())) + if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS())) 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())) + !EffectiveTriple.isWatchOS() && !EffectiveTriple.isDriverKit())) PIC = PIE = false; if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { @@ -1374,7 +2009,49 @@ unsigned tools::ParseFunctionAlignment(const ToolChain &TC, return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value; } -unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC, +void tools::addDebugInfoKind( + ArgStringList &CmdArgs, llvm::codegenoptions::DebugInfoKind DebugInfoKind) { + switch (DebugInfoKind) { + case llvm::codegenoptions::DebugDirectivesOnly: + CmdArgs.push_back("-debug-info-kind=line-directives-only"); + break; + case llvm::codegenoptions::DebugLineTablesOnly: + CmdArgs.push_back("-debug-info-kind=line-tables-only"); + break; + case llvm::codegenoptions::DebugInfoConstructor: + CmdArgs.push_back("-debug-info-kind=constructor"); + break; + case llvm::codegenoptions::LimitedDebugInfo: + CmdArgs.push_back("-debug-info-kind=limited"); + break; + case llvm::codegenoptions::FullDebugInfo: + CmdArgs.push_back("-debug-info-kind=standalone"); + break; + case llvm::codegenoptions::UnusedTypeInfo: + CmdArgs.push_back("-debug-info-kind=unused-types"); + break; + default: + break; + } +} + +// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases +// to the corresponding DebugInfoKind. +llvm::codegenoptions::DebugInfoKind tools::debugLevelToInfoKind(const Arg &A) { + assert(A.getOption().matches(options::OPT_gN_Group) && + "Not a -g option that specifies a debug-info level"); + if (A.getOption().matches(options::OPT_g0) || + A.getOption().matches(options::OPT_ggdb0)) + return llvm::codegenoptions::NoDebugInfo; + if (A.getOption().matches(options::OPT_gline_tables_only) || + A.getOption().matches(options::OPT_ggdb1)) + return llvm::codegenoptions::DebugLineTablesOnly; + if (A.getOption().matches(options::OPT_gline_directives_only)) + return llvm::codegenoptions::DebugDirectivesOnly; + return llvm::codegenoptions::DebugInfoConstructor; +} + +static unsigned ParseDebugDefaultVersion(const ToolChain &TC, const ArgList &Args) { const Arg *A = Args.getLastArg(options::OPT_fdebug_default_version); @@ -1389,6 +2066,34 @@ unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC, return Value; } +unsigned tools::DwarfVersionNum(StringRef ArgValue) { + return llvm::StringSwitch<unsigned>(ArgValue) + .Case("-gdwarf-2", 2) + .Case("-gdwarf-3", 3) + .Case("-gdwarf-4", 4) + .Case("-gdwarf-5", 5) + .Default(0); +} + +const Arg *tools::getDwarfNArg(const ArgList &Args) { + return Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, + options::OPT_gdwarf_4, options::OPT_gdwarf_5, + options::OPT_gdwarf); +} + +unsigned tools::getDwarfVersion(const ToolChain &TC, + const llvm::opt::ArgList &Args) { + unsigned DwarfVersion = ParseDebugDefaultVersion(TC, Args); + if (const Arg *GDwarfN = getDwarfNArg(Args)) + if (int N = DwarfVersionNum(GDwarfN->getSpelling())) + DwarfVersion = N; + if (DwarfVersion == 0) { + DwarfVersion = TC.GetDefaultDwarfVersion(); + assert(DwarfVersion && "toolchain default DWARF version must be nonzero"); + } + return DwarfVersion; +} + void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs) { llvm::Reloc::Model RelocationModel; @@ -1411,17 +2116,12 @@ enum class LibGccType { UnspecifiedLibGcc, StaticLibGcc, SharedLibGcc }; static LibGccType getLibGccType(const ToolChain &TC, const Driver &D, const ArgList &Args) { if (Args.hasArg(options::OPT_static_libgcc) || - Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_pie)) + Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_pie) || + // The Android NDK only provides libunwind.a, not libunwind.so. + TC.getTriple().isAndroid()) return LibGccType::StaticLibGcc; if (Args.hasArg(options::OPT_shared_libgcc)) return LibGccType::SharedLibGcc; - // The Android NDK only provides libunwind.a, not libunwind.so. - if (TC.getTriple().isAndroid()) - return LibGccType::StaticLibGcc; - // For MinGW, don't imply a shared libgcc here, we only want to return - // SharedLibGcc if that was explicitly requested. - if (D.CCCIsCXX() && !TC.getTriple().isOSCygMing()) - return LibGccType::SharedLibGcc; return LibGccType::UnspecifiedLibGcc; } @@ -1441,18 +2141,25 @@ static LibGccType getLibGccType(const ToolChain &TC, const Driver &D, static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { ToolChain::UnwindLibType UNW = TC.GetUnwindLibType(Args); + // By default OHOS binaries are linked statically to libunwind. + if (TC.getTriple().isOHOSFamily() && UNW == ToolChain::UNW_CompilerRT) { + CmdArgs.push_back("-l:libunwind.a"); + return; + } + // Targets that don't use unwind libraries. if ((TC.getTriple().isAndroid() && UNW == ToolChain::UNW_Libgcc) || TC.getTriple().isOSIAMCU() || TC.getTriple().isOSBinFormatWasm() || - UNW == ToolChain::UNW_None) + TC.getTriple().isWindowsMSVCEnvironment() || UNW == ToolChain::UNW_None) return; LibGccType LGT = getLibGccType(TC, D, Args); bool AsNeeded = LGT == LibGccType::UnspecifiedLibGcc && + (UNW == ToolChain::UNW_CompilerRT || !D.CCCIsCXX()) && !TC.getTriple().isAndroid() && !TC.getTriple().isOSCygMing() && !TC.getTriple().isOSAIX(); if (AsNeeded) - CmdArgs.push_back(getAsNeededOption(TC, true)); + addAsNeededOption(TC, Args, CmdArgs, true); switch (UNW) { case ToolChain::UNW_None: @@ -1472,30 +2179,32 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-lunwind"); } else if (LGT == LibGccType::StaticLibGcc) { CmdArgs.push_back("-l:libunwind.a"); - } else if (TC.getTriple().isOSCygMing()) { - if (LGT == LibGccType::SharedLibGcc) + } else if (LGT == LibGccType::SharedLibGcc) { + if (TC.getTriple().isOSCygMing()) 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"); + CmdArgs.push_back("-l:libunwind.so"); } else { - CmdArgs.push_back("-l:libunwind.so"); + // Let the linker choose between libunwind.so and libunwind.a + // depending on what's available, and depending on the -static flag + CmdArgs.push_back("-lunwind"); } break; } if (AsNeeded) - CmdArgs.push_back(getAsNeededOption(TC, false)); + addAsNeededOption(TC, Args, CmdArgs, false); } static void AddLibgcc(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { LibGccType LGT = getLibGccType(TC, D, Args); - if (LGT != LibGccType::SharedLibGcc) + if (LGT == LibGccType::StaticLibGcc || + (LGT == LibGccType::UnspecifiedLibGcc && !D.CCCIsCXX())) CmdArgs.push_back("-lgcc"); AddUnwindLibrary(TC, D, CmdArgs, Args); - if (LGT == LibGccType::SharedLibGcc) + if (LGT == LibGccType::SharedLibGcc || + (LGT == LibGccType::UnspecifiedLibGcc && D.CCCIsCXX())) CmdArgs.push_back("-lgcc"); } @@ -1514,9 +2223,10 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, 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)) { + Arg *A = Args.getLastArg(options::OPT_rtlib_EQ); + if (A && A->getValue() != StringRef("platform")) { TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) - << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC"; + << A->getValue() << "MSVC"; } } else AddLibgcc(TC, D, CmdArgs, Args); @@ -1536,35 +2246,49 @@ SmallString<128> tools::getStatsFileName(const llvm::opt::ArgList &Args, const InputInfo &Input, const Driver &D) { const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ); - if (!A) + if (!A && !D.CCPrintInternalStats) 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 {}; - } + if (A) { + StringRef SaveStats = A->getValue(); + 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"); + StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); + llvm::sys::path::append(StatsFile, BaseName); + llvm::sys::path::replace_extension(StatsFile, "stats"); + } else { + assert(D.CCPrintInternalStats); + StatsFile.assign(D.CCPrintInternalStatReportFilename.empty() + ? "-" + : D.CCPrintInternalStatReportFilename); + } return StatsFile; } -void tools::addMultilibFlag(bool Enabled, const char *const Flag, +void tools::addMultilibFlag(bool Enabled, const StringRef Flag, Multilib::flags_list &Flags) { - Flags.push_back(std::string(Enabled ? "+" : "-") + Flag); + assert(Flag.front() == '-'); + if (Enabled) { + Flags.push_back(Flag.str()); + } else { + Flags.push_back(("!" + Flag.substr(1)).str()); + } } void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args, - ArgStringList &CmdArgs, bool IsLTO) { + ArgStringList &CmdArgs, bool IsLTO, + const StringRef PluginOptPrefix) { auto addArg = [&, IsLTO](const Twine &Arg) { if (IsLTO) { - CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg)); + assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!"); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg)); } else { CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString(Arg)); @@ -1630,11 +2354,11 @@ void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args, /// convention has been to use the prefix “lib”. To avoid confusion with host /// archive libraries, we use prefix "libbc-" for the bitcode SDL archives. /// -bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, +static bool SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, - SmallVector<std::string, 8> LibraryPaths, std::string Lib, - StringRef Arch, StringRef Target, bool isBitCodeSDL, - bool postClangLink) { + const SmallVectorImpl<std::string> &LibraryPaths, + StringRef Lib, StringRef Arch, StringRef Target, + bool isBitCodeSDL) { SmallVector<std::string, 12> SDLs; std::string LibDeviceLoc = "/libdevice"; @@ -1693,8 +2417,6 @@ bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, for (auto SDL : SDLs) { auto FullName = Twine(LPath + SDL).str(); if (llvm::sys::fs::exists(FullName)) { - if (postClangLink) - CC1Args.push_back("-mlink-builtin-bitcode"); CC1Args.push_back(DriverArgs.MakeArgString(FullName)); FoundSDL = true; break; @@ -1709,111 +2431,124 @@ bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, /// Search if a user provided archive file lib<libname>.a exists in any of /// the library paths. If so, add a new command to clang-offload-bundler to /// unbundle this archive and create a temporary device specific archive. Name -/// of this SDL is passed to the llvm-link (for amdgcn) or to the -/// clang-nvlink-wrapper (for nvptx) commands by the driver. -bool tools::GetSDLFromOffloadArchive( +/// of this SDL is passed to the llvm-link tool. +static void GetSDLFromOffloadArchive( Compilation &C, const Driver &D, const Tool &T, const JobAction &JA, const InputInfoList &Inputs, const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, SmallVector<std::string, 8> LibraryPaths, - StringRef Lib, StringRef Arch, StringRef Target, bool isBitCodeSDL, - bool postClangLink) { + llvm::opt::ArgStringList &CC1Args, + const SmallVectorImpl<std::string> &LibraryPaths, StringRef Lib, + StringRef Arch, StringRef Target, bool isBitCodeSDL) { // We don't support bitcode archive bundles for nvptx if (isBitCodeSDL && Arch.contains("nvptx")) - return false; + return; bool FoundAOB = false; - SmallVector<std::string, 2> AOBFileNames; std::string ArchiveOfBundles; - for (auto LPath : LibraryPaths) { - ArchiveOfBundles.clear(); - - AOBFileNames.push_back(Twine(LPath + "/libdevice/lib" + Lib + ".a").str()); - AOBFileNames.push_back(Twine(LPath + "/lib" + Lib + ".a").str()); - for (auto AOB : AOBFileNames) { - if (llvm::sys::fs::exists(AOB)) { - ArchiveOfBundles = AOB; - FoundAOB = true; - break; + llvm::Triple Triple(D.getTargetTriple()); + bool IsMSVC = Triple.isWindowsMSVCEnvironment(); + auto Ext = IsMSVC ? ".lib" : ".a"; + if (!Lib.starts_with(":") && !Lib.starts_with("-l")) { + if (llvm::sys::fs::exists(Lib)) { + ArchiveOfBundles = Lib; + FoundAOB = true; + } + } else { + Lib.consume_front("-l"); + for (auto LPath : LibraryPaths) { + ArchiveOfBundles.clear(); + auto LibFile = (Lib.starts_with(":") ? Lib.drop_front() + : IsMSVC ? Lib + Ext + : "lib" + Lib + Ext) + .str(); + for (auto Prefix : {"/libdevice/", "/"}) { + auto AOB = Twine(LPath + Prefix + LibFile).str(); + if (llvm::sys::fs::exists(AOB)) { + ArchiveOfBundles = AOB; + FoundAOB = true; + break; + } } + if (FoundAOB) + break; } + } - if (!FoundAOB) - continue; - - StringRef Prefix = isBitCodeSDL ? "libbc-" : "lib"; - std::string OutputLib = D.GetTemporaryPath( - Twine(Prefix + Lib + "-" + Arch + "-" + Target).str(), "a"); + if (!FoundAOB) + return; - C.addTempFile(C.getArgs().MakeArgString(OutputLib)); + llvm::file_magic Magic; + auto EC = llvm::identify_magic(ArchiveOfBundles, Magic); + if (EC || Magic != llvm::file_magic::archive) + return; - ArgStringList CmdArgs; - SmallString<128> DeviceTriple; - DeviceTriple += Action::GetOffloadKindName(JA.getOffloadingDeviceKind()); + StringRef Prefix = isBitCodeSDL ? "libbc-" : "lib"; + std::string OutputLib = + D.GetTemporaryPath(Twine(Prefix + llvm::sys::path::filename(Lib) + "-" + + Arch + "-" + Target) + .str(), + "a"); + + C.addTempFile(C.getArgs().MakeArgString(OutputLib)); + + ArgStringList CmdArgs; + SmallString<128> DeviceTriple; + DeviceTriple += Action::GetOffloadKindName(JA.getOffloadingDeviceKind()); + DeviceTriple += '-'; + std::string NormalizedTriple = T.getToolChain().getTriple().normalize(); + DeviceTriple += NormalizedTriple; + if (!Target.empty()) { DeviceTriple += '-'; - std::string NormalizedTriple = T.getToolChain().getTriple().normalize(); - DeviceTriple += NormalizedTriple; - if (!Target.empty()) { - DeviceTriple += '-'; - DeviceTriple += Target; - } + DeviceTriple += Target; + } - std::string UnbundleArg("-unbundle"); - std::string TypeArg("-type=a"); - std::string InputArg("-inputs=" + ArchiveOfBundles); - std::string OffloadArg("-targets=" + std::string(DeviceTriple)); - std::string OutputArg("-outputs=" + OutputLib); - - const char *UBProgram = DriverArgs.MakeArgString( - T.getToolChain().GetProgramPath("clang-offload-bundler")); - - ArgStringList UBArgs; - UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg)); - UBArgs.push_back(C.getArgs().MakeArgString(TypeArg)); - UBArgs.push_back(C.getArgs().MakeArgString(InputArg)); - UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg)); - UBArgs.push_back(C.getArgs().MakeArgString(OutputArg)); - - // Add this flag to not exit from clang-offload-bundler if no compatible - // code object is found in heterogenous archive library. - std::string AdditionalArgs("-allow-missing-bundles"); - UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs)); - - C.addCommand(std::make_unique<Command>( - JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs, - InputInfo(&JA, C.getArgs().MakeArgString(OutputLib)))); - if (postClangLink) - CC1Args.push_back("-mlink-builtin-bitcode"); + std::string UnbundleArg("-unbundle"); + std::string TypeArg("-type=a"); + std::string InputArg("-input=" + ArchiveOfBundles); + std::string OffloadArg("-targets=" + std::string(DeviceTriple)); + std::string OutputArg("-output=" + OutputLib); - CC1Args.push_back(DriverArgs.MakeArgString(OutputLib)); - break; - } + const char *UBProgram = DriverArgs.MakeArgString( + T.getToolChain().GetProgramPath("clang-offload-bundler")); + + ArgStringList UBArgs; + UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg)); + UBArgs.push_back(C.getArgs().MakeArgString(TypeArg)); + UBArgs.push_back(C.getArgs().MakeArgString(InputArg)); + UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg)); + UBArgs.push_back(C.getArgs().MakeArgString(OutputArg)); + + // Add this flag to not exit from clang-offload-bundler if no compatible + // code object is found in heterogenous archive library. + std::string AdditionalArgs("-allow-missing-bundles"); + UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs)); + + // Add this flag to treat hip and hipv4 offload kinds as compatible with + // openmp offload kind while extracting code objects from a heterogenous + // archive library. Vice versa is also considered compatible. + std::string HipCompatibleArgs("-hip-openmp-compatible"); + UBArgs.push_back(C.getArgs().MakeArgString(HipCompatibleArgs)); - return FoundAOB; + C.addCommand(std::make_unique<Command>( + JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs, + InputInfo(&JA, C.getArgs().MakeArgString(OutputLib)))); + + CC1Args.push_back(DriverArgs.MakeArgString(OutputLib)); + + return; } // Wrapper function used by driver for adding SDLs during link phase. void tools::AddStaticDeviceLibsLinking(Compilation &C, const Tool &T, - const JobAction &JA, - const InputInfoList &Inputs, - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - StringRef Arch, StringRef Target, - bool isBitCodeSDL, bool postClangLink) { + const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Arch, StringRef Target, + bool isBitCodeSDL) { AddStaticDeviceLibs(&C, &T, &JA, &Inputs, C.getDriver(), DriverArgs, CC1Args, - Arch, Target, isBitCodeSDL, postClangLink); -} - -// Wrapper function used for post clang linking of bitcode SDLS for nvptx by -// the CUDA toolchain. -void tools::AddStaticDeviceLibsPostLinking(const Driver &D, - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - StringRef Arch, StringRef Target, - bool isBitCodeSDL, bool postClangLink) { - AddStaticDeviceLibs(nullptr, nullptr, nullptr, nullptr, D, DriverArgs, - CC1Args, Arch, Target, isBitCodeSDL, postClangLink); + Arch, Target, isBitCodeSDL); } // User defined Static Device Libraries(SDLs) can be passed to clang for @@ -1828,11 +2563,9 @@ void tools::AddStaticDeviceLibsPostLinking(const Driver &D, // compilation. For AMDGPU, these libraries are linked one time // during the application link phase. // -// * Machine-code SDLs: They are archive files. For NVPTX, the archive members -// contain cubin for Nvidia GPUs and are linked one time during the -// link phase by the CUDA SDK linker called nvlink. For AMDGPU, the -// process for machine code SDLs is still in development. But they -// will be linked by the LLVM tool lld. +// * Machine-code SDLs: They are archive files. For AMDGPU, the process for +// machine code SDLs is still in development. But they will be linked +// by the LLVM tool lld. // // * Bundled objects that contain both host and device codes: Bundled objects // may also contain library code compiled from source. For NVPTX, the @@ -1847,11 +2580,11 @@ void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, StringRef Arch, StringRef Target, - bool isBitCodeSDL, bool postClangLink) { + bool isBitCodeSDL) { SmallVector<std::string, 8> LibraryPaths; // Add search directories from LIBRARY_PATH env variable - llvm::Optional<std::string> LibPath = + std::optional<std::string> LibPath = llvm::sys::Process::GetEnv("LIBRARY_PATH"); if (LibPath) { SmallVector<StringRef, 8> Frags; @@ -1867,7 +2600,7 @@ void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T, // Add path to lib-debug folders SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir); - llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX); + llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME); LibraryPaths.emplace_back(DefaultLibPath.c_str()); // Build list of Static Device Libraries SDLs specified by -l option @@ -1875,49 +2608,51 @@ void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T, static const StringRef HostOnlyArchives[] = { "omp", "cudart", "m", "gcc", "gcc_s", "pthread", "hip_hcc"}; for (auto SDLName : DriverArgs.getAllArgValues(options::OPT_l)) { - if (!HostOnlyArchives->contains(SDLName)) { - SDLNames.insert(SDLName); + if (!llvm::is_contained(HostOnlyArchives, SDLName)) { + SDLNames.insert(std::string("-l") + SDLName); } } + for (auto Input : DriverArgs.getAllArgValues(options::OPT_INPUT)) { + auto FileName = StringRef(Input); + // Clang treats any unknown file types as archives and passes them to the + // linker. Files with extension 'lib' are classified as TY_Object by clang + // but they are usually archives. It is OK if the file is not really an + // archive since GetSDLFromOffloadArchive will check the magic of the file + // and only unbundle it if it is really an archive. + const StringRef LibFileExt = ".lib"; + if (!llvm::sys::path::has_extension(FileName) || + types::lookupTypeForExtension( + llvm::sys::path::extension(FileName).drop_front()) == + types::TY_INVALID || + llvm::sys::path::extension(FileName) == LibFileExt) + SDLNames.insert(Input); + } + // The search stops as soon as an SDL file is found. The driver then provides - // the full filename of the SDL to the llvm-link or clang-nvlink-wrapper - // command. If no SDL is found after searching each LINKPATH with - // SEARCH-ORDER, it is possible that an archive file lib<libname>.a exists - // and may contain bundled object files. + // the full filename of the SDL to the llvm-link command. If no SDL is found + // after searching each LINKPATH with SEARCH-ORDER, it is possible that an + // archive file lib<libname>.a exists and may contain bundled object files. for (auto SDLName : SDLNames) { // This is the only call to SDLSearch if (!SDLSearch(D, DriverArgs, CC1Args, LibraryPaths, SDLName, Arch, Target, - isBitCodeSDL, postClangLink)) { + isBitCodeSDL)) { GetSDLFromOffloadArchive(*C, D, *T, *JA, *Inputs, DriverArgs, CC1Args, LibraryPaths, SDLName, Arch, Target, - isBitCodeSDL, postClangLink); + isBitCodeSDL); } } } static llvm::opt::Arg * getAMDGPUCodeObjectArgument(const Driver &D, const llvm::opt::ArgList &Args) { - // The last of -mcode-object-v3, -mno-code-object-v3 and - // -mcode-object-version=<version> wins. - return Args.getLastArg(options::OPT_mcode_object_v3_legacy, - options::OPT_mno_code_object_v3_legacy, - options::OPT_mcode_object_version_EQ); + return Args.getLastArg(options::OPT_mcode_object_version_EQ); } void tools::checkAMDGPUCodeObjectVersion(const Driver &D, const llvm::opt::ArgList &Args) { - const unsigned MinCodeObjVer = 2; - const unsigned MaxCodeObjVer = 4; - - // Emit warnings for legacy options even if they are overridden. - if (Args.hasArg(options::OPT_mno_code_object_v3_legacy)) - D.Diag(diag::warn_drv_deprecated_arg) << "-mno-code-object-v3" - << "-mcode-object-version=2"; - - if (Args.hasArg(options::OPT_mcode_object_v3_legacy)) - D.Diag(diag::warn_drv_deprecated_arg) << "-mcode-object-v3" - << "-mcode-object-version=3"; + const unsigned MinCodeObjVer = 4; + const unsigned MaxCodeObjVer = 5; if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) { if (CodeObjArg->getOption().getID() == @@ -1935,17 +2670,8 @@ void tools::checkAMDGPUCodeObjectVersion(const Driver &D, unsigned tools::getAMDGPUCodeObjectVersion(const Driver &D, const llvm::opt::ArgList &Args) { unsigned CodeObjVer = 4; // default - if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) { - if (CodeObjArg->getOption().getID() == - options::OPT_mno_code_object_v3_legacy) { - CodeObjVer = 2; - } else if (CodeObjArg->getOption().getID() == - options::OPT_mcode_object_v3_legacy) { - CodeObjVer = 3; - } else { - StringRef(CodeObjArg->getValue()).getAsInteger(0, CodeObjVer); - } - } + if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) + StringRef(CodeObjArg->getValue()).getAsInteger(0, CodeObjVer); return CodeObjVer; } @@ -1957,10 +2683,12 @@ bool tools::haveAMDGPUCodeObjectVersionArgument( void tools::addMachineOutlinerArgs(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - const llvm::Triple &Triple, bool IsLTO) { + const llvm::Triple &Triple, bool IsLTO, + const StringRef PluginOptPrefix) { auto addArg = [&, IsLTO](const Twine &Arg) { if (IsLTO) { - CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg)); + assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!"); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg)); } else { CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString(Arg)); @@ -1973,9 +2701,7 @@ void tools::addMachineOutlinerArgs(const Driver &D, // We only support -moutline in AArch64 and ARM targets right now. If // we're not compiling for these, emit a warning and ignore the flag. // Otherwise, add the proper mllvm flags. - if (!(Triple.isARM() || Triple.isThumb() || - Triple.getArch() == llvm::Triple::aarch64 || - Triple.getArch() == llvm::Triple::aarch64_32)) { + if (!(Triple.isARM() || Triple.isThumb() || Triple.isAArch64())) { D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName(); } else { addArg(Twine("-enable-machine-outliner")); @@ -1996,11 +2722,11 @@ void tools::addOpenMPDeviceRTL(const Driver &D, // Add path to clang lib / lib64 folder. SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir); - llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX); + llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME); LibraryPaths.emplace_back(DefaultLibPath.c_str()); // Add user defined library paths from LIBRARY_PATH. - llvm::Optional<std::string> LibPath = + std::optional<std::string> LibPath = llvm::sys::Process::GetEnv("LIBRARY_PATH"); if (LibPath) { SmallVector<StringRef, 8> Frags; @@ -2011,11 +2737,12 @@ void tools::addOpenMPDeviceRTL(const Driver &D, } OptSpecifier LibomptargetBCPathOpt = - Triple.isAMDGCN() ? options::OPT_libomptarget_amdgcn_bc_path_EQ + Triple.isAMDGCN() ? options::OPT_libomptarget_amdgpu_bc_path_EQ : options::OPT_libomptarget_nvptx_bc_path_EQ; - StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgcn" : "nvptx"; - std::string LibOmpTargetName = "libomptarget-" + BitcodeSuffix.str() + ".bc"; + StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgpu" : "nvptx"; + std::string LibOmpTargetName = + ("libomptarget-" + ArchPrefix + "-" + BitcodeSuffix + ".bc").str(); // First check whether user specifies bc library if (const Arg *A = DriverArgs.getLastArg(LibomptargetBCPathOpt)) { @@ -2051,3 +2778,17 @@ void tools::addOpenMPDeviceRTL(const Driver &D, << LibOmpTargetName << ArchPrefix; } } +void tools::addHIPRuntimeLibArgs(const ToolChain &TC, Compilation &C, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + if ((C.getActiveOffloadKinds() & Action::OFK_HIP) && + !Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_no_hip_rt)) { + TC.AddHIPRuntimeLibArgs(Args, CmdArgs); + } else { + // Claim "no HIP libraries" arguments if any + for (auto *Arg : Args.filtered(options::OPT_no_hip_rt)) { + Arg->claim(); + } + } +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h index 23012dc247e4..807867f13a5c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h @@ -9,11 +9,15 @@ #ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H +#include "clang/Basic/CodeGenOptions.h" #include "clang/Driver/Driver.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Multilib.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" namespace clang { @@ -37,12 +41,13 @@ bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); void linkSanitizerRuntimeDeps(const ToolChain &TC, + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); bool addXRayRuntime(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); -void linkXRayRuntimeDeps(const ToolChain &TC, +void linkXRayRuntimeDeps(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); void AddRunTimeLibs(const ToolChain &TC, const Driver &D, @@ -55,32 +60,12 @@ void AddStaticDeviceLibsLinking(Compilation &C, const Tool &T, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CmdArgs, StringRef Arch, StringRef Target, - bool isBitCodeSDL, bool postClangLink); -void AddStaticDeviceLibsPostLinking(const Driver &D, - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CmdArgs, - StringRef Arch, StringRef Target, - bool isBitCodeSDL, bool postClangLink); + bool isBitCodeSDL); void AddStaticDeviceLibs(Compilation *C, const Tool *T, const JobAction *JA, const InputInfoList *Inputs, const Driver &D, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CmdArgs, StringRef Arch, - StringRef Target, bool isBitCodeSDL, - bool postClangLink); - -bool SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CmdArgs, - SmallVector<std::string, 8> LibraryPaths, std::string Lib, - StringRef Arch, StringRef Target, bool isBitCodeSDL, - bool postClangLink); - -bool GetSDLFromOffloadArchive(Compilation &C, const Driver &D, const Tool &T, - const JobAction &JA, const InputInfoList &Inputs, - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - SmallVector<std::string, 8> LibraryPaths, - StringRef Lib, StringRef Arch, StringRef Target, - bool isBitCodeSDL, bool postClangLink); + StringRef Target, bool isBitCodeSDL); const char *SplitDebugName(const JobAction &JA, const llvm::opt::ArgList &Args, const InputInfo &Input, const InputInfo &Output); @@ -93,32 +78,61 @@ void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO); +const char *RelocationModelName(llvm::Reloc::Model Model); + std::tuple<llvm::Reloc::Model, unsigned, bool> 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 addDebugInfoKind(llvm::opt::ArgStringList &CmdArgs, + llvm::codegenoptions::DebugInfoKind DebugInfoKind); + +llvm::codegenoptions::DebugInfoKind +debugLevelToInfoKind(const llvm::opt::Arg &A); + +// Extract the integer N from a string spelled "-dwarf-N", returning 0 +// on mismatch. The StringRef input (rather than an Arg) allows +// for use by the "-Xassembler" option parser. +unsigned DwarfVersionNum(StringRef ArgValue); +// Find a DWARF format version option. +// This function is a complementary for DwarfVersionNum(). +const llvm::opt::Arg *getDwarfNArg(const llvm::opt::ArgList &Args); +unsigned getDwarfVersion(const ToolChain &TC, const llvm::opt::ArgList &Args); void AddAssemblerKPIC(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); -void addOpenMPRuntimeSpecificRPath(const ToolChain &TC, - const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs); void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); +void addOpenMPRuntimeLibraryPath(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); -const char *getAsNeededOption(const ToolChain &TC, bool as_needed); +/// Adds Fortran runtime libraries to \p CmdArgs. +void addFortranRuntimeLibs(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + +/// Adds the path for the Fortran runtime libraries to \p CmdArgs. +void addFortranRuntimeLibraryPath(const ToolChain &TC, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); +void addHIPRuntimeLibArgs(const ToolChain &TC, Compilation &C, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + +void addAsNeededOption(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, bool as_needed); + +llvm::opt::Arg *getLastCSProfileGenerateArg(const llvm::opt::ArgList &Args); llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args); llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args); @@ -130,6 +144,9 @@ llvm::StringRef getLTOParallelism(const llvm::opt::ArgList &Args, bool areOptimizationsEnabled(const llvm::opt::ArgList &Args); bool isUseSeparateSections(const llvm::Triple &Triple); +// Parse -mtls-dialect=. Return true if the target supports both general-dynamic +// and TLSDESC, and TLSDESC is requested. +bool isTLSDESCEnabled(const ToolChain &TC, const llvm::opt::ArgList &Args); /// \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 @@ -148,19 +165,24 @@ void AddTargetFeature(const llvm::opt::ArgList &Args, std::string getCPUName(const Driver &D, const llvm::opt::ArgList &Args, const llvm::Triple &T, bool FromAs = false); +void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, bool ForAS, + bool IsAux = 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, +void handleTargetFeaturesGroup(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, std::vector<StringRef> &Features, llvm::opt::OptSpecifier Group); /// If there are multiple +xxx or -xxx features, keep the last one. -std::vector<StringRef> -unifyTargetFeatures(const std::vector<StringRef> &Features); +SmallVector<StringRef> unifyTargetFeatures(ArrayRef<StringRef> Features); /// Handles the -save-stats option and returns the filename to save statistics /// to. @@ -168,13 +190,13 @@ 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, +/// \p Flag must be a flag accepted by the driver. +void addMultilibFlag(bool Enabled, const StringRef Flag, Multilib::flags_list &Flags); void addX86AlignBranchArgs(const Driver &D, const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, bool IsLTO); + llvm::opt::ArgStringList &CmdArgs, bool IsLTO, + const StringRef PluginOptPrefix = ""); void checkAMDGPUCodeObjectVersion(const Driver &D, const llvm::opt::ArgList &Args); @@ -187,7 +209,8 @@ bool haveAMDGPUCodeObjectVersionArgument(const Driver &D, void addMachineOutlinerArgs(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - const llvm::Triple &Triple, bool IsLTO); + const llvm::Triple &Triple, bool IsLTO, + const StringRef PluginOptPrefix = ""); void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, @@ -196,4 +219,7 @@ void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs, } // end namespace driver } // end namespace clang +clang::CodeGenOptions::FramePointerKind +getFramePointerKind(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); + #endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp deleted file mode 100644 index 5dda1b1b09fb..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp +++ /dev/null @@ -1,27 +0,0 @@ -//===--- Contiki.cpp - Contiki 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 "Contiki.h" -#include "CommonArgs.h" - -using namespace clang::driver; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -Contiki::Contiki(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) {} - -SanitizerMask Contiki::getSupportedSanitizers() const { - const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - if (IsX86) - Res |= SanitizerKind::SafeStack; - return Res; -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h deleted file mode 100644 index 627d80bdda09..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h +++ /dev/null @@ -1,39 +0,0 @@ -//===--- Contiki.h - Contiki 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H - -#include "Gnu.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY Contiki : public Generic_ELF { -public: - Contiki(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - // No support for finding a C++ standard library yet. - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} - - SanitizerMask getSupportedSanitizers() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp index 2b043fbeecda..3c5dfba329cf 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp @@ -94,7 +94,8 @@ void tools::CrossWindows::Linker::ConstructJob( CmdArgs.push_back("-m"); switch (TC.getArch()) { default: - llvm_unreachable("unsupported architecture"); + D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str(); + break; case llvm::Triple::arm: case llvm::Triple::thumb: // FIXME: this is incorrect for WinCE @@ -213,10 +214,11 @@ CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, const llvm::opt::ArgList &Args) : Generic_GCC(D, T, Args) {} -bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel +CrossWindowsToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const { // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does // not know how to emit them. - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 ? UnwindTableLevel::Asynchronous : UnwindTableLevel::None; } bool CrossWindowsToolChain::isPICDefault() const { @@ -273,8 +275,11 @@ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, void CrossWindowsToolChain:: AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { - if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); + } } clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const { diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h index bab690ea34d0..c5df55a24296 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h @@ -20,7 +20,7 @@ namespace driver { namespace tools { namespace CrossWindows { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("CrossWindows::Assembler", "as", TC) {} @@ -32,7 +32,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("CrossWindows::Linker", "ld", TC) {} @@ -54,8 +54,8 @@ public: CrossWindowsToolChain(const Driver &D, const llvm::Triple &T, const llvm::opt::ArgList &Args); - bool IsIntegratedAssemblerDefault() const override { return true; } - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp index 4a9f6d4c4e3e..1462576ca870 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp @@ -16,16 +16,17 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" -#include "llvm/Support/TargetParser.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/TargetParser.h" #include <system_error> using namespace clang::driver; @@ -67,15 +68,29 @@ CudaVersion getCudaVersion(uint32_t raw_version) { return CudaVersion::CUDA_114; if (raw_version < 11060) return CudaVersion::CUDA_115; + if (raw_version < 11070) + return CudaVersion::CUDA_116; + if (raw_version < 11080) + return CudaVersion::CUDA_117; + if (raw_version < 11090) + return CudaVersion::CUDA_118; + if (raw_version < 12010) + return CudaVersion::CUDA_120; + if (raw_version < 12020) + return CudaVersion::CUDA_121; + if (raw_version < 12030) + return CudaVersion::CUDA_122; + if (raw_version < 12040) + return CudaVersion::CUDA_123; return CudaVersion::NEW; } CudaVersion parseCudaHFile(llvm::StringRef Input) { // Helper lambda which skips the words if the line starts with them or returns - // None otherwise. + // std::nullopt otherwise. auto StartsWithWords = [](llvm::StringRef Line, - const SmallVector<StringRef, 3> words) -> llvm::Optional<StringRef> { + const SmallVector<StringRef, 3> words) -> std::optional<StringRef> { for (StringRef word : words) { if (!Line.consume_front(word)) return {}; @@ -189,19 +204,6 @@ CudaInstallationDetector::CudaInstallationDetector( if (CheckLibDevice && !FS.exists(LibDevicePath)) continue; - // On Linux, we have both lib and lib64 directories, and we need to choose - // based on our triple. On MacOS, we have only a lib directory. - // - // It's sufficient for our purposes to be flexible: If both lib and lib64 - // exist, we choose whichever one matches our triple. Otherwise, if only - // lib exists, we use it. - if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64")) - LibPath = InstallPath + "/lib64"; - else if (FS.exists(InstallPath + "/lib")) - LibPath = InstallPath + "/lib"; - else - continue; - Version = CudaVersion::UNKNOWN; if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h")) Version = parseCudaHFile((*CudaHFile)->getBuffer()); @@ -236,7 +238,7 @@ CudaInstallationDetector::CudaInstallationDetector( // Process all bitcode filenames that look like // libdevice.compute_XX.YY.bc const StringRef LibDeviceName = "libdevice."; - if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) + if (!(FileName.starts_with(LibDeviceName) && FileName.ends_with(".bc"))) continue; StringRef GpuArch = FileName.slice( LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); @@ -375,18 +377,20 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { const auto &TC = - static_cast<const toolchains::CudaToolChain &>(getToolChain()); + static_cast<const toolchains::NVPTXToolChain &>(getToolChain()); assert(TC.getTriple().isNVPTX() && "Wrong platform"); StringRef GPUArchName; - // If this is an OpenMP action we need to extract the device architecture - // from the -march=arch option. This option may come from -Xopenmp-target - // flag or the default value. - if (JA.isDeviceOffloading(Action::OFK_OpenMP)) { + // If this is a CUDA action we need to extract the device architecture + // from the Job's associated architecture, otherwise use the -march=arch + // option. This option may come from -Xopenmp-target flag or the default + // value. + if (JA.isDeviceOffloading(Action::OFK_Cuda)) { + GPUArchName = JA.getOffloadingArch(); + } else { GPUArchName = Args.getLastArgValue(options::OPT_march_EQ); assert(!GPUArchName.empty() && "Must have an architecture passed in."); - } else - GPUArchName = JA.getOffloadingArch(); + } // Obtain architecture from the action. CudaArch gpu_arch = StringToCudaArch(GPUArchName); @@ -447,22 +451,38 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--gpu-name"); CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch))); CmdArgs.push_back("--output-file"); - CmdArgs.push_back(Args.MakeArgString(TC.getInputFilename(Output))); - for (const auto& II : Inputs) + std::string OutputFileName = TC.getInputFilename(Output); + + // If we are invoking `nvlink` internally we need to output a `.cubin` file. + // FIXME: This should hopefully be removed if NVIDIA updates their tooling. + if (!C.getInputArgs().getLastArg(options::OPT_c)) { + SmallString<256> Filename(Output.getFilename()); + llvm::sys::path::replace_extension(Filename, "cubin"); + OutputFileName = Filename.str(); + } + if (Output.isFilename() && OutputFileName != Output.getFilename()) + C.addTempFile(Args.MakeArgString(OutputFileName)); + + CmdArgs.push_back(Args.MakeArgString(OutputFileName)); + for (const auto &II : Inputs) CmdArgs.push_back(Args.MakeArgString(II.getFilename())); - for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) + for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) CmdArgs.push_back(Args.MakeArgString(A)); - bool Relocatable = false; + bool Relocatable; if (JA.isOffloading(Action::OFK_OpenMP)) // In OpenMP we need to generate relocatable code. Relocatable = Args.hasFlag(options::OPT_fopenmp_relocatable_target, options::OPT_fnoopenmp_relocatable_target, /*Default=*/true); else if (JA.isOffloading(Action::OFK_Cuda)) - Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, - options::OPT_fno_gpu_rdc, /*Default=*/false); + // In CUDA we generate relocatable code by default. + Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + /*Default=*/false); + else + // Otherwise, we are compiling directly and should create linkable output. + Relocatable = true; if (Relocatable) CmdArgs.push_back("-c"); @@ -498,11 +518,11 @@ static bool shouldIncludePTX(const ArgList &Args, const char *gpu_arch) { // All inputs to this linker must be from CudaDeviceActions, as we need to look // at the Inputs' Actions in order to figure out which GPU architecture they // correspond to. -void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void NVPTX::FatBinary::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const auto &TC = static_cast<const toolchains::CudaToolChain &>(getToolChain()); assert(TC.getTriple().isNVPTX() && "Wrong platform"); @@ -516,7 +536,7 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost) CmdArgs.push_back("-g"); - for (const auto& II : Inputs) { + for (const auto &II : Inputs) { auto *A = II.getAction(); assert(A->getInputs().size() == 1 && "Device offload action is expected to have a single input"); @@ -533,11 +553,12 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *Arch = (II.getType() == types::TY_PP_Asm) ? CudaArchToVirtualArchString(gpu_arch) : gpu_arch_str; - CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") + - Arch + ",file=" + II.getFilename())); + CmdArgs.push_back( + Args.MakeArgString(llvm::Twine("--image=profile=") + Arch + + ",file=" + getToolChain().getInputFilename(II))); } - for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary)) + for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary)) CmdArgs.push_back(Args.MakeArgString(A)); const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary")); @@ -548,36 +569,31 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, Exec, CmdArgs, Inputs, Output)); } -void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const auto &TC = - static_cast<const toolchains::CudaToolChain &>(getToolChain()); - assert(TC.getTriple().isNVPTX() && "Wrong platform"); - + static_cast<const toolchains::NVPTXToolChain &>(getToolChain()); ArgStringList CmdArgs; - // OpenMP uses nvlink to link cubin files. The result will be embedded in the - // host binary by the host linker. - assert(!JA.isHostOffloading(Action::OFK_OpenMP) && - "CUDA toolchain not expected for an OpenMP host device."); + assert(TC.getTriple().isNVPTX() && "Wrong platform"); + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else - assert(Output.isNothing() && "Invalid output."); + } + if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost) CmdArgs.push_back("-g"); if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-v"); - StringRef GPUArch = - Args.getLastArgValue(options::OPT_march_EQ); - assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas."); + StringRef GPUArch = Args.getLastArgValue(options::OPT_march_EQ); + assert(!GPUArch.empty() && "At least one GPU Arch required for nvlink."); CmdArgs.push_back("-arch"); CmdArgs.push_back(Args.MakeArgString(GPUArch)); @@ -588,14 +604,12 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, // Add paths for the default clang library path. SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(TC.getDriver().Dir); - llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX); + llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME); CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath)); for (const auto &II : Inputs) { - if (II.getType() == types::TY_LLVM_IR || - II.getType() == types::TY_LTO_IR || - II.getType() == types::TY_LTO_BC || - II.getType() == types::TY_LLVM_BC) { + if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || + II.getType() == types::TY_LTO_BC || II.getType() == types::TY_LLVM_BC) { C.getDriver().Diag(diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); continue; @@ -606,65 +620,179 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, if (!II.isFilename()) continue; - const char *CubinF = C.addTempFile( - C.getArgs().MakeArgString(getToolChain().getInputFilename(II))); + // The 'nvlink' application performs RDC-mode linking when given a '.o' + // file and device linking when given a '.cubin' file. We always want to + // perform device linking, so just rename any '.o' files. + // FIXME: This should hopefully be removed if NVIDIA updates their tooling. + auto InputFile = getToolChain().getInputFilename(II); + if (llvm::sys::path::extension(InputFile) != ".cubin") { + // If there are no actions above this one then this is direct input and we + // can copy it. Otherwise the input is internal so a `.cubin` file should + // exist. + if (II.getAction() && II.getAction()->getInputs().size() == 0) { + const char *CubinF = + Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath( + llvm::sys::path::stem(InputFile), "cubin")); + if (llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF))) + continue; - CmdArgs.push_back(CubinF); + CmdArgs.push_back(CubinF); + } else { + SmallString<256> Filename(InputFile); + llvm::sys::path::replace_extension(Filename, "cubin"); + CmdArgs.push_back(Args.MakeArgString(Filename)); + } + } else { + CmdArgs.push_back(Args.MakeArgString(InputFile)); + } } - AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "nvptx", - GPUArch, /*isBitCodeSDL=*/false, - /*postClangLink=*/false); - - // Find nvlink and pass it as "--nvlink-path=" argument of - // clang-nvlink-wrapper. - CmdArgs.push_back(Args.MakeArgString( - Twine("--nvlink-path=" + getToolChain().GetProgramPath("nvlink")))); - - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("clang-nvlink-wrapper")); C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8, "--options-file"}, - Exec, CmdArgs, Inputs, Output)); + Args.MakeArgString(getToolChain().GetProgramPath("nvlink")), CmdArgs, + Inputs, Output)); } -/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary, -/// which isn't properly a linker but nonetheless performs the step of stitching -/// together object files from the assembler into a single blob. +void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features) { + if (Args.hasArg(options::OPT_cuda_feature_EQ)) { + StringRef PtxFeature = + Args.getLastArgValue(options::OPT_cuda_feature_EQ, "+ptx42"); + Features.push_back(Args.MakeArgString(PtxFeature)); + return; + } + CudaInstallationDetector CudaInstallation(D, Triple, Args); -CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const ArgList &Args, - const Action::OffloadKind OK) - : ToolChain(D, Triple, Args), HostTC(HostTC), - CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) { - if (CudaInstallation.isValid()) { - CudaInstallation.WarnIfUnsupportedVersion(); - getProgramPaths().push_back(std::string(CudaInstallation.getBinPath())); + // New CUDA versions often introduce new instructions that are only supported + // by new PTX version, so we need to raise PTX level to enable them in NVPTX + // back-end. + const char *PtxFeature = nullptr; + switch (CudaInstallation.version()) { +#define CASE_CUDA_VERSION(CUDA_VER, PTX_VER) \ + case CudaVersion::CUDA_##CUDA_VER: \ + PtxFeature = "+ptx" #PTX_VER; \ + break; + CASE_CUDA_VERSION(123, 83); + CASE_CUDA_VERSION(122, 82); + CASE_CUDA_VERSION(121, 81); + CASE_CUDA_VERSION(120, 80); + CASE_CUDA_VERSION(118, 78); + CASE_CUDA_VERSION(117, 77); + CASE_CUDA_VERSION(116, 76); + CASE_CUDA_VERSION(115, 75); + CASE_CUDA_VERSION(114, 74); + CASE_CUDA_VERSION(113, 73); + CASE_CUDA_VERSION(112, 72); + CASE_CUDA_VERSION(111, 71); + CASE_CUDA_VERSION(110, 70); + CASE_CUDA_VERSION(102, 65); + CASE_CUDA_VERSION(101, 64); + CASE_CUDA_VERSION(100, 63); + CASE_CUDA_VERSION(92, 61); + CASE_CUDA_VERSION(91, 61); + CASE_CUDA_VERSION(90, 60); +#undef CASE_CUDA_VERSION + default: + PtxFeature = "+ptx42"; } + Features.push_back(PtxFeature); +} + +/// NVPTX toolchain. Our assembler is ptxas, and our linker is nvlink. This +/// operates as a stand-alone version of the NVPTX tools without the host +/// toolchain. +NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::Triple &HostTriple, + const ArgList &Args, bool Freestanding = false) + : ToolChain(D, Triple, Args), CudaInstallation(D, HostTriple, Args), + Freestanding(Freestanding) { + if (CudaInstallation.isValid()) + getProgramPaths().push_back(std::string(CudaInstallation.getBinPath())); // Lookup binaries into the driver directory, this is used to - // discover the clang-offload-bundler executable. + // discover the 'nvptx-arch' executable. getProgramPaths().push_back(getDriver().Dir); } -std::string CudaToolChain::getInputFilename(const InputInfo &Input) const { - // Only object files are changed, for example assembly files keep their .s - // extensions. CUDA also continues to use .o as they don't use nvlink but - // fatbinary. - if (!(OK == Action::OFK_OpenMP && Input.getType() == types::TY_Object)) - return ToolChain::getInputFilename(Input); +/// We only need the host triple to locate the CUDA binary utilities, use the +/// system's default triple if not provided. +NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : NVPTXToolChain(D, Triple, llvm::Triple(LLVM_HOST_TRIPLE), Args, + /*Freestanding=*/true) {} - // Replace extension for object files with cubin because nvlink relies on - // these particular file names. - SmallString<256> Filename(ToolChain::getInputFilename(Input)); - llvm::sys::path::replace_extension(Filename, "cubin"); - return std::string(Filename.str()); +llvm::opt::DerivedArgList * +NVPTXToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + DerivedArgList *DAL = + ToolChain::TranslateArgs(Args, BoundArch, DeviceOffloadKind); + if (!DAL) + DAL = new DerivedArgList(Args.getBaseArgs()); + + const OptTable &Opts = getDriver().getOpts(); + + for (Arg *A : Args) + if (!llvm::is_contained(*DAL, A)) + DAL->append(A); + + if (!DAL->hasArg(options::OPT_march_EQ)) + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), + CudaArchToString(CudaArch::CudaDefault)); + + return DAL; +} + +void NVPTXToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + // If we are compiling with a standalone NVPTX toolchain we want to try to + // mimic a standard environment as much as possible. So we enable lowering + // ctor / dtor functions to global symbols that can be registered. + if (Freestanding) + CC1Args.append({"-mllvm", "--nvptx-lower-global-ctor-dtor"}); +} + +bool NVPTXToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const { + const Option &O = A->getOption(); + return (O.matches(options::OPT_gN_Group) && + !O.matches(options::OPT_gmodules)) || + O.matches(options::OPT_g_Flag) || + O.matches(options::OPT_ggdbN_Group) || O.matches(options::OPT_ggdb) || + O.matches(options::OPT_gdwarf) || O.matches(options::OPT_gdwarf_2) || + O.matches(options::OPT_gdwarf_3) || O.matches(options::OPT_gdwarf_4) || + O.matches(options::OPT_gdwarf_5) || + O.matches(options::OPT_gcolumn_info); } +void NVPTXToolChain::adjustDebugInfoKind( + llvm::codegenoptions::DebugInfoKind &DebugInfoKind, + const ArgList &Args) const { + switch (mustEmitDebugInfo(Args)) { + case DisableDebugInfo: + DebugInfoKind = llvm::codegenoptions::NoDebugInfo; + break; + case DebugDirectivesOnly: + DebugInfoKind = llvm::codegenoptions::DebugDirectivesOnly; + break; + case EmitSameDebugInfoAsHost: + // Use same debug info level as the host. + break; + } +} + +/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary, +/// which isn't properly a linker but nonetheless performs the step of stitching +/// together object files from the assembler into a single blob. + +CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const ArgList &Args) + : NVPTXToolChain(D, Triple, HostTC.getTriple(), Args), HostTC(HostTC) {} + void CudaToolChain::addClangTargetOptions( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); @@ -678,9 +806,12 @@ void CudaToolChain::addClangTargetOptions( CC1Args.append( {"-fcuda-is-device", "-mllvm", "-enable-memcpyopt-without-libcalls"}); - if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, - options::OPT_fno_cuda_approx_transcendentals, false)) - CC1Args.push_back("-fcuda-approx-transcendentals"); + // Unsized function arguments used for variadics were introduced in CUDA-9.0 + // We still do not support generating code that actually uses variadic + // arguments yet, but we do need to allow parsing them as recent CUDA + // headers rely on that. https://github.com/llvm/llvm-project/issues/58410 + if (CudaInstallation.version() >= CudaVersion::CUDA_90) + CC1Args.push_back("-fcuda-allow-variadic-functions"); } if (DriverArgs.hasArg(options::OPT_nogpulib)) @@ -701,32 +832,6 @@ void CudaToolChain::addClangTargetOptions( clang::CudaVersion CudaInstallationVersion = CudaInstallation.version(); - // New CUDA versions often introduce new instructions that are only supported - // by new PTX version, so we need to raise PTX level to enable them in NVPTX - // back-end. - const char *PtxFeature = nullptr; - switch (CudaInstallationVersion) { -#define CASE_CUDA_VERSION(CUDA_VER, PTX_VER) \ - case CudaVersion::CUDA_##CUDA_VER: \ - PtxFeature = "+ptx" #PTX_VER; \ - break; - CASE_CUDA_VERSION(115, 75); - CASE_CUDA_VERSION(114, 74); - CASE_CUDA_VERSION(113, 73); - CASE_CUDA_VERSION(112, 72); - CASE_CUDA_VERSION(111, 71); - CASE_CUDA_VERSION(110, 70); - CASE_CUDA_VERSION(102, 65); - CASE_CUDA_VERSION(101, 64); - CASE_CUDA_VERSION(100, 63); - CASE_CUDA_VERSION(92, 61); - CASE_CUDA_VERSION(91, 61); - CASE_CUDA_VERSION(90, 60); -#undef CASE_CUDA_VERSION - default: - PtxFeature = "+ptx42"; - } - CC1Args.append({"-target-feature", PtxFeature}); if (DriverArgs.hasFlag(options::OPT_fcuda_short_ptr, options::OPT_fno_cuda_short_ptr, false)) CC1Args.append({"-mllvm", "--nvptx-short-ptr"}); @@ -748,18 +853,8 @@ void CudaToolChain::addClangTargetOptions( if (getDriver().isUsingLTO(/* IsOffload */ true)) return; - std::string BitcodeSuffix; - if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime, - options::OPT_fno_openmp_target_new_runtime, true)) - BitcodeSuffix = "new-nvptx-" + GpuArch.str(); - else - BitcodeSuffix = "nvptx-" + GpuArch.str(); - - addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, + addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, GpuArch.str(), getTriple()); - AddStaticDeviceLibsPostLinking(getDriver(), DriverArgs, CC1Args, "nvptx", - GpuArch, /*isBitCodeSDL=*/true, - /*postClangLink=*/true); } } @@ -777,33 +872,6 @@ llvm::DenormalMode CudaToolChain::getDefaultDenormalModeForType( return llvm::DenormalMode::getIEEE(); } -bool CudaToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const { - const Option &O = A->getOption(); - return (O.matches(options::OPT_gN_Group) && - !O.matches(options::OPT_gmodules)) || - O.matches(options::OPT_g_Flag) || - O.matches(options::OPT_ggdbN_Group) || O.matches(options::OPT_ggdb) || - O.matches(options::OPT_gdwarf) || O.matches(options::OPT_gdwarf_2) || - O.matches(options::OPT_gdwarf_3) || O.matches(options::OPT_gdwarf_4) || - O.matches(options::OPT_gdwarf_5) || - O.matches(options::OPT_gcolumn_info); -} - -void CudaToolChain::adjustDebugInfoKind( - codegenoptions::DebugInfoKind &DebugInfoKind, const ArgList &Args) const { - switch (mustEmitDebugInfo(Args)) { - case DisableDebugInfo: - DebugInfoKind = codegenoptions::NoDebugInfo; - break; - case DebugDirectivesOnly: - DebugInfoKind = codegenoptions::DebugDirectivesOnly; - break; - case EmitSameDebugInfoAsHost: - // Use same debug info level as the host. - break; - } -} - void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { // Check our CUDA version if we're going to include the CUDA headers. @@ -816,6 +884,19 @@ void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } +std::string CudaToolChain::getInputFilename(const InputInfo &Input) const { + // Only object files are changed, for example assembly files keep their .s + // extensions. If the user requested device-only compilation don't change it. + if (Input.getType() != types::TY_Object || getDriver().offloadDeviceOnly()) + return ToolChain::getInputFilename(Input); + + // Replace extension for object files with cubin because nvlink relies on + // these particular file names. + SmallString<256> Filename(ToolChain::getInputFilename(Input)); + llvm::sys::path::replace_extension(Filename, "cubin"); + return std::string(Filename); +} + llvm::opt::DerivedArgList * CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, @@ -835,10 +916,22 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, if (!llvm::is_contained(*DAL, A)) DAL->append(A); - StringRef Arch = DAL->getLastArgValue(options::OPT_march_EQ); - if (Arch.empty()) - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), - CLANG_OPENMP_NVPTX_DEFAULT_ARCH); + if (!DAL->hasArg(options::OPT_march_EQ)) { + StringRef Arch = BoundArch; + if (Arch.empty()) { + auto ArchsOrErr = getSystemGPUArchs(Args); + if (!ArchsOrErr) { + std::string ErrMsg = + llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError())); + getDriver().Diag(diag::err_drv_undetermined_gpu_arch) + << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march"; + Arch = CudaArchToString(CudaArch::CudaDefault); + } else { + Arch = Args.MakeArgString(ArchsOrErr->front()); + } + } + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch); + } return DAL; } @@ -849,19 +942,51 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, if (!BoundArch.empty()) { DAL->eraseArg(options::OPT_march_EQ); - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), + BoundArch); } return DAL; } +Expected<SmallVector<std::string>> +CudaToolChain::getSystemGPUArchs(const ArgList &Args) const { + // Detect NVIDIA GPUs availible on the system. + std::string Program; + if (Arg *A = Args.getLastArg(options::OPT_nvptx_arch_tool_EQ)) + Program = A->getValue(); + else + Program = GetProgramPath("nvptx-arch"); + + auto StdoutOrErr = executeToolChainProgram(Program); + if (!StdoutOrErr) + return StdoutOrErr.takeError(); + + SmallVector<std::string, 1> GPUArchs; + for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n")) + if (!Arch.empty()) + GPUArchs.push_back(Arch.str()); + + if (GPUArchs.empty()) + return llvm::createStringError(std::error_code(), + "No NVIDIA GPU detected in the system"); + + return std::move(GPUArchs); +} + +Tool *NVPTXToolChain::buildAssembler() const { + return new tools::NVPTX::Assembler(*this); +} + +Tool *NVPTXToolChain::buildLinker() const { + return new tools::NVPTX::Linker(*this); +} + Tool *CudaToolChain::buildAssembler() const { return new tools::NVPTX::Assembler(*this); } Tool *CudaToolChain::buildLinker() const { - if (OK == Action::OFK_OpenMP) - return new tools::NVPTX::OpenMPLinker(*this); - return new tools::NVPTX::Linker(*this); + return new tools::NVPTX::FatBinary(*this); } void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h index a7e6e84f4902..8a053f3393e1 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h @@ -14,7 +14,6 @@ #include "clang/Driver/Multilib.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" -#include "llvm/ADT/Optional.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/VersionTuple.h" #include <bitset> @@ -32,7 +31,6 @@ private: CudaVersion Version = CudaVersion::UNKNOWN; std::string InstallPath; std::string BinPath; - std::string LibPath; std::string LibDevicePath; std::string IncludePath; llvm::StringMap<std::string> LibDeviceMap; @@ -70,8 +68,6 @@ public: StringRef getBinPath() const { return BinPath; } /// Get the detected Cuda Include path. StringRef getIncludePath() const { return IncludePath; } - /// Get the detected Cuda library path. - StringRef getLibPath() const { return LibPath; } /// Get the detected Cuda device library path. StringRef getLibDevicePath() const { return LibDevicePath; } /// Get libdevice file for given architecture @@ -85,72 +81,71 @@ namespace tools { namespace NVPTX { // Run ptxas, the NVPTX assembler. -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { - public: - Assembler(const ToolChain &TC) : Tool("NVPTX::Assembler", "ptxas", TC) {} +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("NVPTX::Assembler", "ptxas", TC) {} - bool hasIntegratedCPP() const override { return false; } + bool hasIntegratedCPP() const override { return false; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; // Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX // assembly into a single output file. -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { - public: - Linker(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {} +class LLVM_LIBRARY_VISIBILITY FatBinary : public Tool { +public: + FatBinary(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {} - bool hasIntegratedCPP() const override { return false; } + bool hasIntegratedCPP() const override { return false; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool { - public: - OpenMPLinker(const ToolChain &TC) - : Tool("NVPTX::OpenMPLinker", "nvlink", TC) {} +// Runs nvlink, which links GPU object files ("cubin" files) into a single file. +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("NVPTX::Linker", "nvlink", TC) {} - bool hasIntegratedCPP() const override { return false; } + bool hasIntegratedCPP() const override { return false; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; +void getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features); + } // end namespace NVPTX } // end namespace tools namespace toolchains { -class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain { +class LLVM_LIBRARY_VISIBILITY NVPTXToolChain : public ToolChain { public: - CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const llvm::opt::ArgList &Args, - const Action::OffloadKind OK); - - const llvm::Triple *getAuxTriple() const override { - return &HostTC.getTriple(); - } + NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::Triple &HostTriple, const llvm::opt::ArgList &Args, + bool Freestanding); - std::string getInputFilename(const InputInfo &Input) const override; + NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const override; - llvm::DenormalMode getDefaultDenormalModeForType( - const llvm::opt::ArgList &DriverArgs, const JobAction &JA, - const llvm::fltSemantics *FPType = nullptr) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; // Never try to use the integrated assembler with CUDA; always fork out to // ptxas. @@ -162,10 +157,49 @@ public: } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } + + bool IsMathErrnoDefault() const override { return false; } + bool supportsDebugInfoOption(const llvm::opt::Arg *A) const override; - void adjustDebugInfoKind(codegenoptions::DebugInfoKind &DebugInfoKind, + void adjustDebugInfoKind(llvm::codegenoptions::DebugInfoKind &DebugInfoKind, const llvm::opt::ArgList &Args) const override; - bool IsMathErrnoDefault() const override { return false; } + + // NVPTX supports only DWARF2. + unsigned GetDefaultDwarfVersion() const override { return 2; } + unsigned getMaxDwarfVersion() const override { return 2; } + + CudaInstallationDetector CudaInstallation; + +protected: + Tool *buildAssembler() const override; // ptxas. + Tool *buildLinker() const override; // nvlink. + +private: + bool Freestanding = false; +}; + +class LLVM_LIBRARY_VISIBILITY CudaToolChain : public NVPTXToolChain { +public: + CudaToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const llvm::opt::ArgList &Args); + + const llvm::Triple *getAuxTriple() const override { + return &HostTC.getTriple(); + } + + std::string getInputFilename(const InputInfo &Input) const override; + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + + llvm::DenormalMode getDefaultDenormalModeForType( + const llvm::opt::ArgList &DriverArgs, const JobAction &JA, + const llvm::fltSemantics *FPType = nullptr) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -187,19 +221,16 @@ public: computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } - // NVPTX supports only DWARF2. - unsigned getMaxDwarfVersion() const override { return 2; } - const ToolChain &HostTC; - CudaInstallationDetector CudaInstallation; -protected: - Tool *buildAssembler() const override; // ptxas - Tool *buildLinker() const override; // fatbinary (ok, not really a linker) + /// Uses nvptx-arch tool to get arch of the system GPU. Will return error + /// if unable to find one. + virtual Expected<SmallVector<std::string>> + getSystemGPUArchs(const llvm::opt::ArgList &Args) const override; -private: - const Action::OffloadKind OK; +protected: + Tool *buildAssembler() const override; // ptxas + Tool *buildLinker() const override; // fatbinary (ok, not really a linker) }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp index f7da3f187814..fae8ad1a958a 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp @@ -23,9 +23,10 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/TargetParser.h" #include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/TargetParser.h" +#include "llvm/TargetParser/Triple.h" #include <cstdlib> // ::getenv using namespace clang::driver; @@ -44,7 +45,7 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { // The matching this routine does is fairly pointless, since it is neither the // complete architecture list, nor a reasonable subset. The problem is that - // historically the driver driver accepts this and also ties its -march= + // historically the driver accepts this and also ties its -march= // handling to the architecture name, so we need to be careful before removing // support for it. @@ -52,14 +53,11 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { // translation. return llvm::StringSwitch<llvm::Triple::ArchType>(Str) - .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc) - .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc) - .Case("ppc64", llvm::Triple::ppc64) .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86) .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4", llvm::Triple::x86) .Cases("x86_64", "x86_64h", llvm::Triple::x86_64) - // This is derived from the driver driver. + // This is derived from the driver. .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm) .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm) .Cases("armv7s", "xscale", llvm::Triple::arm) @@ -74,7 +72,8 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { .Default(llvm::Triple::UnknownArch); } -void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { +void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str, + const ArgList &Args) { const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str); llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(Str); T.setArch(Arch); @@ -84,6 +83,17 @@ void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { if (ArchKind == llvm::ARM::ArchKind::ARMV6M || ArchKind == llvm::ARM::ArchKind::ARMV7M || ArchKind == llvm::ARM::ArchKind::ARMV7EM) { + // Don't reject these -version-min= if we have the appropriate triple. + if (T.getOS() == llvm::Triple::IOS) + for (Arg *A : Args.filtered(options::OPT_mios_version_min_EQ)) + A->ignoreTargetSpecific(); + if (T.getOS() == llvm::Triple::WatchOS) + for (Arg *A : Args.filtered(options::OPT_mwatchos_version_min_EQ)) + A->ignoreTargetSpecific(); + if (T.getOS() == llvm::Triple::TvOS) + for (Arg *A : Args.filtered(options::OPT_mtvos_version_min_EQ)) + A->ignoreTargetSpecific(); + T.setOS(llvm::Triple::UnknownOS); T.setObjectFormat(llvm::Triple::MachO); } @@ -209,19 +219,19 @@ static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) { void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs, - unsigned Version[5], bool LinkerIsLLD) const { + VersionTuple Version, bool LinkerIsLLD, + bool UsePlatformVersion) const { const Driver &D = getToolChain().getDriver(); const toolchains::MachO &MachOTC = getMachOToolChain(); // Newer linkers support -demangle. Pass it if supported and not disabled by // the user. - if ((Version[0] >= 100 || LinkerIsLLD) && + if ((Version >= VersionTuple(100) || LinkerIsLLD) && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("-demangle"); - // FIXME: Pass most of the flags below that check Version if LinkerIsLLD too. - - if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137) + if (Args.hasArg(options::OPT_rdynamic) && + (Version >= VersionTuple(137) || LinkerIsLLD)) CmdArgs.push_back("-export_dynamic"); // If we are using App Extension restrictions, pass a flag to the linker @@ -230,7 +240,8 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, options::OPT_fno_application_extension, false)) CmdArgs.push_back("-application_extension"); - if (D.isUsingLTO() && Version[0] >= 116 && NeedsTempPath(Inputs)) { + if (D.isUsingLTO() && (Version >= VersionTuple(116) || LinkerIsLLD) && + NeedsTempPath(Inputs)) { std::string TmpPathName; if (D.getLTOMode() == LTOK_Full) { // If we are using full LTO, then automatically create a temporary file @@ -259,7 +270,7 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, // clang version won't work anyways. // lld is built at the same revision as clang and statically links in // LLVM libraries, so it doesn't need libLTO.dylib. - if (Version[0] >= 133 && !LinkerIsLLD) { + if (Version >= VersionTuple(133) && !LinkerIsLLD) { // Search for libLTO in <InstalledDir>/../lib/libLTO.dylib StringRef P = llvm::sys::path::parent_path(D.Dir); SmallString<128> LibLTOPath(P); @@ -269,8 +280,11 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath)); } - // ld64 version 262 and above run the deduplicate pass by default. - if (Version[0] >= 262 && shouldLinkerNotDedup(C.getJobs().empty(), Args)) + // ld64 version 262 and above runs the deduplicate pass by default. + // FIXME: lld doesn't dedup by default. Should we pass `--icf=safe` + // if `!shouldLinkerNotDedup()` if LinkerIsLLD here? + if (Version >= VersionTuple(262) && + shouldLinkerNotDedup(C.getJobs().empty(), Args)) CmdArgs.push_back("-no_deduplicate"); // Derived from the "link" spec. @@ -342,7 +356,7 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_init); // Add the deployment target. - if (Version[0] >= 520 || LinkerIsLLD) + if (Version >= VersionTuple(520) || LinkerIsLLD || UsePlatformVersion) MachOTC.addPlatformVersionArgs(Args, CmdArgs); else MachOTC.addMinVersionArgs(Args, CmdArgs); @@ -368,7 +382,9 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, // Check if the toolchain supports bitcode build flow. if (MachOTC.SupportsEmbeddedBitcode()) { CmdArgs.push_back("-bitcode_bundle"); - if (C.getDriver().embedBitcodeMarkerOnly() && Version[0] >= 278) { + // FIXME: Pass this if LinkerIsLLD too, once it implements this flag. + if (C.getDriver().embedBitcodeMarkerOnly() && + Version >= VersionTuple(278)) { CmdArgs.push_back("-bitcode_process_mode"); CmdArgs.push_back("marker"); } @@ -388,6 +404,13 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, } } + if (Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext) || + Args.hasArg(options::OPT_ffreestanding)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-disable-atexit-based-global-dtor-lowering"); + } + Args.AddLastArg(CmdArgs, options::OPT_prebind); Args.AddLastArg(CmdArgs, options::OPT_noprebind); Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding); @@ -437,6 +460,23 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name); Args.AddLastArg(CmdArgs, options::OPT_dylinker); Args.AddLastArg(CmdArgs, options::OPT_Mach); + + if (LinkerIsLLD) { + if (auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args)) { + SmallString<128> Path(CSPGOGenerateArg->getNumValues() == 0 + ? "" + : CSPGOGenerateArg->getValue()); + llvm::sys::path::append(Path, "default_%m.profraw"); + CmdArgs.push_back("--cs-profile-generate"); + CmdArgs.push_back(Args.MakeArgString(Twine("--cs-profile-path=") + Path)); + } else if (auto *ProfileUseArg = getLastProfileUseArg(Args)) { + 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("--cs-profile-path=") + Path)); + } + } } /// Determine whether we are linking the ObjC runtime. @@ -517,6 +557,8 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, } } +static void AppendPlatformPrefix(SmallString<128> &Path, const llvm::Triple &T); + void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -543,25 +585,25 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("touch")); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, None, Output)); + C.addCommand(std::make_unique<Command>(JA, *this, + ResponseFileSupport::None(), Exec, + CmdArgs, std::nullopt, Output)); return; } - unsigned Version[5] = {0, 0, 0, 0, 0}; - if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { - if (!Driver::GetReleaseVersion(A->getValue(), Version)) - getToolChain().getDriver().Diag(diag::err_drv_invalid_version_number) - << A->getAsString(Args); - } + VersionTuple Version = getMachOToolChain().getLinkerVersion(Args); bool LinkerIsLLD; const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath(&LinkerIsLLD)); + // xrOS always uses -platform-version. + bool UsePlatformVersion = getToolChain().getTriple().isXROS(); + // I'm not sure why this particular decomposition exists in gcc, but // we follow suite for ease of comparison. - AddLinkArgs(C, Args, CmdArgs, Inputs, Version, LinkerIsLLD); + AddLinkArgs(C, Args, CmdArgs, Inputs, Version, LinkerIsLLD, + UsePlatformVersion); if (willEmitRemarks(Args) && checkRemarksOptions(getToolChain().getDriver(), Args, @@ -575,10 +617,6 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (getMachOToolChain().getMachOArchName(Args) == "arm64") { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-enable-machine-outliner"); - - // Outline from linkonceodr functions by default in LTO. - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-enable-linkonceodr-outlining"); } } else { // Disable all outlining behaviour if we have mno-outline. We need to do @@ -589,6 +627,12 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + // Outline from linkonceodr functions by default in LTO, whenever the outliner + // is enabled. Note that the target may enable the machine outliner + // independently of -moutline. + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-linkonceodr-outlining"); + // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Inputs[0], getToolChain().getDriver()); @@ -599,9 +643,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, // It seems that the 'e' option is completely ignored for dynamic executables // (the default), and with static executables, the last one wins, as expected. - Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_u_Group, - options::OPT_e, options::OPT_r}); + Args.addAllArgs(CmdArgs, + {options::OPT_d_Flag, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_u_Group, options::OPT_r}); // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading // members of static archive libraries which implement Objective-C classes or @@ -635,6 +679,13 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, InputFileList.push_back(II.getFilename()); } + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. + if (getToolChain().getDriver().IsFlangMode()) { + addFortranRuntimeLibraryPath(getToolChain(), Args, CmdArgs); + addFortranRuntimeLibs(getToolChain(), Args, CmdArgs); + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) addOpenMPRuntime(CmdArgs, getToolChain(), Args); @@ -712,8 +763,37 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + // Add non-standard, platform-specific search paths, e.g., for DriverKit: + // -L<sysroot>/System/DriverKit/usr/lib + // -F<sysroot>/System/DriverKit/System/Library/Framework + { + bool NonStandardSearchPath = false; + const auto &Triple = getToolChain().getTriple(); + if (Triple.isDriverKit()) { + // ld64 fixed the implicit -F and -L paths in ld64-605.1+. + NonStandardSearchPath = + Version.getMajor() < 605 || + (Version.getMajor() == 605 && Version.getMinor().value_or(0) < 1); + } + + if (NonStandardSearchPath) { + if (auto *Sysroot = Args.getLastArg(options::OPT_isysroot)) { + auto AddSearchPath = [&](StringRef Flag, StringRef SearchPath) { + SmallString<128> P(Sysroot->getValue()); + AppendPlatformPrefix(P, Triple); + llvm::sys::path::append(P, SearchPath); + if (getToolChain().getVFS().exists(P)) { + CmdArgs.push_back(Args.MakeArgString(Flag + P)); + } + }; + AddSearchPath("-L", "/usr/lib"); + AddSearchPath("-F", "/System/Library/Frameworks"); + } + } + } + ResponseFileSupport ResponseSupport; - if (Version[0] >= 705 || LinkerIsLLD) { + if (Version >= VersionTuple(705) || LinkerIsLLD) { ResponseSupport = ResponseFileSupport::AtFileUTF8(); } else { // For older versions of the linker, use the legacy filelist method instead. @@ -869,13 +949,8 @@ types::ID MachO::LookupTypeForExtension(StringRef Ext) const { bool MachO::HasNativeLLVMSupport() const { return true; } ToolChain::CXXStdlibType Darwin::GetDefaultCXXStdlibType() const { - // Default to use libc++ on OS X 10.9+ and iOS 7+. - if ((isTargetMacOSBased() && !isMacosxVersionLT(10, 9)) || - (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) || - isTargetWatchOSBased()) - return ToolChain::CST_Libcxx; - - return ToolChain::CST_Libstdcxx; + // Always use libc++ by default + return ToolChain::CST_Libcxx; } /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. @@ -884,6 +959,13 @@ ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion); if (isTargetIOSBased()) return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); + if (isTargetXROS()) { + // XROS uses the iOS runtime. + auto T = llvm::Triple(Twine("arm64-apple-") + + llvm::Triple::getOSTypeName(llvm::Triple::XROS) + + TargetVersion.getAsString()); + return ObjCRuntime(ObjCRuntime::iOS, T.getiOSVersion()); + } if (isNonFragile) return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion); @@ -891,7 +973,7 @@ ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { /// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. bool Darwin::hasBlocksRuntime() const { - if (isTargetWatchOSBased()) + if (isTargetWatchOSBased() || isTargetDriverKit() || isTargetXROS()) return true; else if (isTargetIOSBased()) return !isIPhoneOSVersionLT(3, 2); @@ -903,12 +985,12 @@ bool Darwin::hasBlocksRuntime() const { void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void Darwin::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } // This is just a MachO name translation routine and there's no @@ -940,13 +1022,13 @@ static const char *ArmMachOArchNameCPU(StringRef CPU) { // FIXME: Make sure this MachO triple mangling is really necessary. // ARMv5* normalises to ARMv5. - if (Arch.startswith("armv5")) + if (Arch.starts_with("armv5")) Arch = Arch.substr(0, 5); // ARMv6*, except ARMv6M, normalises to ARMv6. - else if (Arch.startswith("armv6") && !Arch.endswith("6m")) + else if (Arch.starts_with("armv6") && !Arch.ends_with("6m")) Arch = Arch.substr(0, 5); // ARMv7A normalises to ARMv7. - else if (Arch.endswith("v7a")) + else if (Arch.ends_with("v7a")) Arch = Arch.substr(0, 5); return Arch.data(); } @@ -979,6 +1061,27 @@ StringRef MachO::getMachOArchName(const ArgList &Args) const { } } +VersionTuple MachO::getLinkerVersion(const llvm::opt::ArgList &Args) const { + if (LinkerVersion) { +#ifndef NDEBUG + VersionTuple NewLinkerVersion; + if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) + (void)NewLinkerVersion.tryParse(A->getValue()); + assert(NewLinkerVersion == LinkerVersion); +#endif + return *LinkerVersion; + } + + VersionTuple NewLinkerVersion; + if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) + if (NewLinkerVersion.tryParse(A->getValue())) + getDriver().Diag(diag::err_drv_invalid_version_number) + << A->getAsString(Args); + + LinkerVersion = NewLinkerVersion; + return *LinkerVersion; +} + Darwin::~Darwin() {} MachO::~MachO() {} @@ -997,8 +1100,12 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, Str += "watchos"; else if (isTargetTvOSBased()) Str += "tvos"; + else if (isTargetDriverKit()) + Str += "driverkit"; else if (isTargetIOSBased() || isTargetMacCatalyst()) Str += "ios"; + else if (isTargetXROS()) + Str += llvm::Triple::getOSTypeName(llvm::Triple::XROS); else Str += "macosx"; Str += getTripleTargetVersion().getAsString(); @@ -1081,6 +1188,8 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, // ARC runtime is supported everywhere on arm64e. if (getTriple().isArm64e()) return; + if (isTargetXROS()) + return; ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true); @@ -1091,25 +1200,38 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, SmallString<128> P(getDriver().ClangExecutable); llvm::sys::path::remove_filename(P); // 'clang' llvm::sys::path::remove_filename(P); // 'bin' + llvm::sys::path::append(P, "lib", "arc"); // 'libarclite' usually lives in the same toolchain as 'clang'. However, the // Swift open source toolchains for macOS distribute Clang without libarclite. // In that case, to allow the linker to find 'libarclite', we point to the // 'libarclite' in the XcodeDefault toolchain instead. - if (getXcodeDeveloperPath(P).empty()) { - if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + if (!getVFS().exists(P)) { + auto updatePath = [&](const Arg *A) { // Try to infer the path to 'libarclite' in the toolchain from the // specified SDK path. StringRef XcodePathForSDK = getXcodeDeveloperPath(A->getValue()); - if (!XcodePathForSDK.empty()) { - P = XcodePathForSDK; - llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr"); - } + if (XcodePathForSDK.empty()) + return false; + + P = XcodePathForSDK; + llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr", + "lib", "arc"); + return getVFS().exists(P); + }; + + bool updated = false; + if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) + updated = updatePath(A); + + if (!updated) { + if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) + updatePath(A); } } CmdArgs.push_back("-force_load"); - llvm::sys::path::append(P, "lib", "arc", "libarclite_"); + llvm::sys::path::append(P, "libarclite_"); // Mash in the platform. if (isTargetWatchOSSimulator()) P += "watchsimulator"; @@ -1127,6 +1249,9 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, P += "macosx"; P += ".a"; + if (!getVFS().exists(P)) + getDriver().Diag(clang::diag::err_drv_darwin_sdk_missing_arclite) << P; + CmdArgs.push_back(Args.MakeArgString(P)); } @@ -1152,8 +1277,9 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, DarwinLibName += getOSLibraryNameSuffix(); DarwinLibName += IsShared ? "_dynamic.dylib" : ".a"; SmallString<128> Dir(getDriver().ResourceDir); - llvm::sys::path::append( - Dir, "lib", (Opts & RLO_IsEmbedded) ? "macho_embedded" : "darwin"); + llvm::sys::path::append(Dir, "lib", "darwin"); + if (Opts & RLO_IsEmbedded) + llvm::sys::path::append(Dir, "macho_embedded"); SmallString<128> P(Dir); llvm::sys::path::append(P, DarwinLibName); @@ -1171,7 +1297,7 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, // rpaths. This is currently true from this place, but we need to be // careful if this function is ever called before user's rpaths are emitted. if (Opts & RLO_AddRPath) { - assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); + assert(DarwinLibName.ends_with(".dylib") && "must be a dynamic library"); // Add @executable_path to rpath to support having the dylib copied with // the executable. @@ -1197,6 +1323,10 @@ StringRef Darwin::getPlatformFamily() const { return "AppleTV"; case DarwinPlatformKind::WatchOS: return "Watch"; + case DarwinPlatformKind::DriverKit: + return "DriverKit"; + case DarwinPlatformKind::XROS: + return "XR"; } llvm_unreachable("Unsupported platform"); } @@ -1207,8 +1337,8 @@ StringRef Darwin::getSDKName(StringRef isysroot) { auto EndSDK = llvm::sys::path::rend(isysroot); for (auto IT = BeginSDK; IT != EndSDK; ++IT) { StringRef SDK = *IT; - if (SDK.endswith(".sdk")) - return SDK.slice(0, SDK.size() - 4); + if (SDK.ends_with(".sdk")) + return SDK.slice(0, SDK.size() - 4); } return ""; } @@ -1228,6 +1358,11 @@ StringRef Darwin::getOSLibraryNameSuffix(bool IgnoreSim) const { case DarwinPlatformKind::WatchOS: return TargetEnvironment == NativeEnvironment || IgnoreSim ? "watchos" : "watchossim"; + case DarwinPlatformKind::XROS: + return TargetEnvironment == NativeEnvironment || IgnoreSim ? "xros" + : "xrossim"; + case DarwinPlatformKind::DriverKit: + return "driverkit"; } llvm_unreachable("Unsupported platform"); } @@ -1279,20 +1414,14 @@ void Darwin::addProfileRTLibs(const ArgList &Args, // If we have a symbol export directive and we're linking in the profile // runtime, automatically export symbols necessary to implement some of the // runtime's functionality. - if (hasExportSymbolDirective(Args)) { - if (ForGCOV) { - addExportedSymbol(CmdArgs, "___gcov_dump"); - addExportedSymbol(CmdArgs, "___gcov_reset"); - addExportedSymbol(CmdArgs, "_writeout_fn_list"); - addExportedSymbol(CmdArgs, "_reset_fn_list"); - } else { - addExportedSymbol(CmdArgs, "___llvm_profile_filename"); - addExportedSymbol(CmdArgs, "___llvm_profile_raw_version"); - } - addExportedSymbol(CmdArgs, "_lprofDirMode"); + if (hasExportSymbolDirective(Args) && ForGCOV) { + addExportedSymbol(CmdArgs, "___gcov_dump"); + addExportedSymbol(CmdArgs, "___gcov_reset"); + addExportedSymbol(CmdArgs, "_writeout_fn_list"); + addExportedSymbol(CmdArgs, "_reset_fn_list"); } - // Align __llvm_prf_{cnts,data} sections to the maximum expected page + // Align __llvm_prf_{cnts,bits,data} sections to the maximum expected page // alignment. This allows profile counters to be mmap()'d to disk. Note that // it's not enough to just page-align __llvm_prf_cnts: the following section // must also be page-aligned so that its data is not clobbered by mmap(). @@ -1302,7 +1431,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args, // extra alignment also allows the same binary to be used with/without sync // enabled. if (!ForGCOV) { - for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_data}) { + for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_bitmap, llvm::IPSK_data}) { addSectalignToPage( Args, CmdArgs, "__DATA", llvm::getInstrProfSectionName(IPSK, llvm::Triple::MachO, @@ -1323,7 +1452,7 @@ ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType( const ArgList &Args) const { if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) { StringRef Value = A->getValue(); - if (Value != "compiler-rt") + if (Value != "compiler-rt" && Value != "platform") getDriver().Diag(clang::diag::err_drv_unsupported_rtlib_for_platform) << Value << "darwin"; } @@ -1356,26 +1485,57 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } const SanitizerArgs &Sanitize = getSanitizerArgs(Args); - if (Sanitize.needsAsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); - if (Sanitize.needsLsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan"); - if (Sanitize.needsUbsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, - Sanitize.requiresMinimalRuntime() ? "ubsan_minimal" - : "ubsan", - Sanitize.needsSharedRt()); - if (Sanitize.needsTsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); - if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) { - AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false); - - // Libfuzzer is written in C++ and requires libcxx. - AddCXXStdlibLibArgs(Args, CmdArgs); - } - if (Sanitize.needsStatsRt()) { - AddLinkRuntimeLib(Args, CmdArgs, "stats_client", RLO_AlwaysLink); - AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); + + if (!Sanitize.needsSharedRt()) { + const char *sanitizer = nullptr; + if (Sanitize.needsUbsanRt()) { + sanitizer = "UndefinedBehaviorSanitizer"; + } else if (Sanitize.needsAsanRt()) { + sanitizer = "AddressSanitizer"; + } else if (Sanitize.needsTsanRt()) { + sanitizer = "ThreadSanitizer"; + } + if (sanitizer) { + getDriver().Diag(diag::err_drv_unsupported_static_sanitizer_darwin) + << sanitizer; + return; + } + } + + if (Sanitize.linkRuntimes()) { + if (Sanitize.needsAsanRt()) { + if (Sanitize.needsStableAbi()) { + AddLinkSanitizerLibArgs(Args, CmdArgs, "asan_abi", /*shared=*/false); + } else { + assert(Sanitize.needsSharedRt() && + "Static sanitizer runtimes not supported"); + AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); + } + } + if (Sanitize.needsLsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan"); + if (Sanitize.needsUbsanRt()) { + assert(Sanitize.needsSharedRt() && + "Static sanitizer runtimes not supported"); + AddLinkSanitizerLibArgs( + Args, CmdArgs, + Sanitize.requiresMinimalRuntime() ? "ubsan_minimal" : "ubsan"); + } + if (Sanitize.needsTsanRt()) { + assert(Sanitize.needsSharedRt() && + "Static sanitizer runtimes not supported"); + AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); + } + if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) { + AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false); + + // Libfuzzer is written in C++ and requires libcxx. + AddCXXStdlibLibArgs(Args, CmdArgs); + } + if (Sanitize.needsStatsRt()) { + AddLinkRuntimeLib(Args, CmdArgs, "stats_client", RLO_AlwaysLink); + AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); + } } const XRayArgs &XRay = getXRayArgs(); @@ -1385,9 +1545,15 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, AddLinkRuntimeLib(Args, CmdArgs, "xray-fdr"); } + if (isTargetDriverKit() && !Args.hasArg(options::OPT_nodriverkitlib)) { + CmdArgs.push_back("-framework"); + CmdArgs.push_back("DriverKit"); + } + // Otherwise link libSystem, then the dynamic runtime library, and finally any // target specific static runtime library. - CmdArgs.push_back("-lSystem"); + if (!isTargetDriverKit()) + CmdArgs.push_back("-lSystem"); // Select the dynamic runtime library and the target specific static library. if (isTargetIOSBased()) { @@ -1406,17 +1572,19 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, /// If the macOS SDK version is the same or earlier than the system version, /// then the SDK version is returned. Otherwise the system version is returned. static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) { - unsigned Major, Minor, Micro; llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); if (!SystemTriple.isMacOSX()) return std::string(MacOSSDKVersion); VersionTuple SystemVersion; SystemTriple.getMacOSXVersion(SystemVersion); + + unsigned Major, Minor, Micro; bool HadExtra; if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro, HadExtra)) return std::string(MacOSSDKVersion); VersionTuple SDKVersion(Major, Minor, Micro); + if (SDKVersion > SystemVersion) return SystemVersion.getAsString(); return std::string(MacOSSDKVersion); @@ -1478,6 +1646,10 @@ struct DarwinPlatform { /// Returns true if the simulator environment can be inferred from the arch. bool canInferSimulatorFromArch() const { return InferSimulatorFromArch; } + const std::optional<llvm::Triple> &getTargetVariantTriple() const { + return TargetVariantTriple; + } + /// Adds the -m<os>-version-min argument to the compiler invocation. void addOSVersionMinArgument(DerivedArgList &Args, const OptTable &Opts) { if (Argument) @@ -1487,10 +1659,10 @@ struct DarwinPlatform { options::ID Opt; switch (Platform) { case DarwinPlatformKind::MacOS: - Opt = options::OPT_mmacosx_version_min_EQ; + Opt = options::OPT_mmacos_version_min_EQ; break; case DarwinPlatformKind::IPhoneOS: - Opt = options::OPT_miphoneos_version_min_EQ; + Opt = options::OPT_mios_version_min_EQ; break; case DarwinPlatformKind::TvOS: Opt = options::OPT_mtvos_version_min_EQ; @@ -1498,6 +1670,12 @@ struct DarwinPlatform { case DarwinPlatformKind::WatchOS: Opt = options::OPT_mwatchos_version_min_EQ; break; + case DarwinPlatformKind::XROS: + // xrOS always explicitly provides a version in the triple. + return; + case DarwinPlatformKind::DriverKit: + // DriverKit always explicitly provides a version in the triple. + return; } Argument = Args.MakeJoinedArg(nullptr, Opts.getOption(Opt), OSVersion); Args.append(Argument); @@ -1522,7 +1700,7 @@ struct DarwinPlatform { void setEnvironment(llvm::Triple::EnvironmentType EnvType, const VersionTuple &OSVersion, - const Optional<DarwinSDKInfo> &SDKInfo) { + const std::optional<DarwinSDKInfo> &SDKInfo) { switch (EnvType) { case llvm::Triple::Simulator: Environment = DarwinEnvironmentKind::Simulator; @@ -1535,11 +1713,21 @@ struct DarwinPlatform { if (const auto *MacCatalystToMacOSMapping = SDKInfo->getVersionMapping( DarwinSDKInfo::OSEnvPair::macCatalystToMacOSPair())) { if (auto MacOSVersion = MacCatalystToMacOSMapping->map( - OSVersion, NativeTargetVersion, None)) { + OSVersion, NativeTargetVersion, std::nullopt)) { NativeTargetVersion = *MacOSVersion; } } } + // In a zippered build, we could be building for a macOS target that's + // lower than the version that's implied by the OS version. In that case + // we need to use the minimum version as the native target version. + if (TargetVariantTriple) { + auto TargetVariantVersion = TargetVariantTriple->getOSVersion(); + if (TargetVariantVersion.getMajor()) { + if (TargetVariantVersion < NativeTargetVersion) + NativeTargetVersion = TargetVariantVersion; + } + } break; } default: @@ -1549,28 +1737,33 @@ struct DarwinPlatform { static DarwinPlatform createFromTarget(const llvm::Triple &TT, StringRef OSVersion, Arg *A, - const Optional<DarwinSDKInfo> &SDKInfo) { + std::optional<llvm::Triple> TargetVariantTriple, + const std::optional<DarwinSDKInfo> &SDKInfo) { DarwinPlatform Result(TargetArg, getPlatformFromOS(TT.getOS()), OSVersion, A); VersionTuple OsVersion = TT.getOSVersion(); if (OsVersion.getMajor() == 0) Result.HasOSVersion = false; + Result.TargetVariantTriple = TargetVariantTriple; Result.setEnvironment(TT.getEnvironment(), OsVersion, SDKInfo); return Result; } static DarwinPlatform createFromMTargetOS(llvm::Triple::OSType OS, VersionTuple OSVersion, llvm::Triple::EnvironmentType Environment, Arg *A, - const Optional<DarwinSDKInfo> &SDKInfo) { + const std::optional<DarwinSDKInfo> &SDKInfo) { DarwinPlatform Result(MTargetOSArg, getPlatformFromOS(OS), OSVersion.getAsString(), A); Result.InferSimulatorFromArch = false; Result.setEnvironment(Environment, OSVersion, SDKInfo); return Result; } - static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, - Arg *A) { - return DarwinPlatform(OSVersionArg, Platform, A); + static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, Arg *A, + bool IsSimulator) { + DarwinPlatform Result{OSVersionArg, Platform, A}; + if (IsSimulator) + Result.Environment = DarwinEnvironmentKind::Simulator; + return Result; } static DarwinPlatform createDeploymentTargetEnv(DarwinPlatformKind Platform, StringRef EnvVarName, @@ -1625,6 +1818,10 @@ private: return DarwinPlatformKind::TvOS; case llvm::Triple::WatchOS: return DarwinPlatformKind::WatchOS; + case llvm::Triple::XROS: + return DarwinPlatformKind::XROS; + case llvm::Triple::DriverKit: + return DarwinPlatformKind::DriverKit; default: llvm_unreachable("Unable to infer Darwin variant"); } @@ -1638,15 +1835,16 @@ private: bool HasOSVersion = true, InferSimulatorFromArch = true; Arg *Argument; StringRef EnvVarName; + std::optional<llvm::Triple> TargetVariantTriple; }; /// Returns the deployment target that's specified using the -m<os>-version-min /// argument. -Optional<DarwinPlatform> +std::optional<DarwinPlatform> getDeploymentTargetFromOSVersionArg(DerivedArgList &Args, const Driver &TheDriver) { - Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); - Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ, + Arg *macOSVersion = Args.getLastArg(options::OPT_mmacos_version_min_EQ); + Arg *iOSVersion = Args.getLastArg(options::OPT_mios_version_min_EQ, options::OPT_mios_simulator_version_min_EQ); Arg *TvOSVersion = Args.getLastArg(options::OPT_mtvos_version_min_EQ, @@ -1654,37 +1852,47 @@ getDeploymentTargetFromOSVersionArg(DerivedArgList &Args, Arg *WatchOSVersion = Args.getLastArg(options::OPT_mwatchos_version_min_EQ, options::OPT_mwatchos_simulator_version_min_EQ); - if (OSXVersion) { + if (macOSVersion) { if (iOSVersion || TvOSVersion || WatchOSVersion) { TheDriver.Diag(diag::err_drv_argument_not_allowed_with) - << OSXVersion->getAsString(Args) + << macOSVersion->getAsString(Args) << (iOSVersion ? iOSVersion : TvOSVersion ? TvOSVersion : WatchOSVersion) ->getAsString(Args); } - return DarwinPlatform::createOSVersionArg(Darwin::MacOS, OSXVersion); + return DarwinPlatform::createOSVersionArg(Darwin::MacOS, macOSVersion, + /*IsSimulator=*/false); } else if (iOSVersion) { if (TvOSVersion || WatchOSVersion) { TheDriver.Diag(diag::err_drv_argument_not_allowed_with) << iOSVersion->getAsString(Args) << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); } - return DarwinPlatform::createOSVersionArg(Darwin::IPhoneOS, iOSVersion); + return DarwinPlatform::createOSVersionArg( + Darwin::IPhoneOS, iOSVersion, + iOSVersion->getOption().getID() == + options::OPT_mios_simulator_version_min_EQ); } else if (TvOSVersion) { if (WatchOSVersion) { TheDriver.Diag(diag::err_drv_argument_not_allowed_with) << TvOSVersion->getAsString(Args) << WatchOSVersion->getAsString(Args); } - return DarwinPlatform::createOSVersionArg(Darwin::TvOS, TvOSVersion); + return DarwinPlatform::createOSVersionArg( + Darwin::TvOS, TvOSVersion, + TvOSVersion->getOption().getID() == + options::OPT_mtvos_simulator_version_min_EQ); } else if (WatchOSVersion) - return DarwinPlatform::createOSVersionArg(Darwin::WatchOS, WatchOSVersion); - return None; + return DarwinPlatform::createOSVersionArg( + Darwin::WatchOS, WatchOSVersion, + WatchOSVersion->getOption().getID() == + options::OPT_mwatchos_simulator_version_min_EQ); + return std::nullopt; } /// Returns the deployment target that's specified using the /// OS_DEPLOYMENT_TARGET environment variable. -Optional<DarwinPlatform> +std::optional<DarwinPlatform> getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, const llvm::Triple &Triple) { std::string Targets[Darwin::LastDarwinPlatform + 1]; @@ -1693,10 +1901,11 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, "IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET", "WATCHOS_DEPLOYMENT_TARGET", + "DRIVERKIT_DEPLOYMENT_TARGET", }; - static_assert(llvm::array_lengthof(EnvVars) == Darwin::LastDarwinPlatform + 1, + static_assert(std::size(EnvVars) == Darwin::LastDarwinPlatform + 1, "Missing platform"); - for (const auto &I : llvm::enumerate(llvm::makeArrayRef(EnvVars))) { + for (const auto &I : llvm::enumerate(llvm::ArrayRef(EnvVars))) { if (char *Env = ::getenv(I.value())) Targets[I.index()] = Env; } @@ -1715,11 +1924,11 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, Targets[Darwin::TvOS] = ""; } else { // Don't allow conflicts in any other platform. - unsigned FirstTarget = llvm::array_lengthof(Targets); - for (unsigned I = 0; I != llvm::array_lengthof(Targets); ++I) { + unsigned FirstTarget = std::size(Targets); + for (unsigned I = 0; I != std::size(Targets); ++I) { if (Targets[I].empty()) continue; - if (FirstTarget == llvm::array_lengthof(Targets)) + if (FirstTarget == std::size(Targets)) FirstTarget = I; else TheDriver.Diag(diag::err_drv_conflicting_deployment_targets) @@ -1727,13 +1936,13 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, } } - for (const auto &Target : llvm::enumerate(llvm::makeArrayRef(Targets))) { + for (const auto &Target : llvm::enumerate(llvm::ArrayRef(Targets))) { if (!Target.value().empty()) return DarwinPlatform::createDeploymentTargetEnv( (Darwin::DarwinPlatformKind)Target.index(), EnvVars[Target.index()], Target.value()); } - return None; + return std::nullopt; } /// Returns the SDK name without the optional prefix that ends with a '.' or an @@ -1748,16 +1957,16 @@ static StringRef dropSDKNamePrefix(StringRef SDKName) { /// Tries to infer the deployment target from the SDK specified by -isysroot /// (or SDKROOT). Uses the version specified in the SDKSettings.json file if /// it's available. -Optional<DarwinPlatform> +std::optional<DarwinPlatform> inferDeploymentTargetFromSDK(DerivedArgList &Args, - const Optional<DarwinSDKInfo> &SDKInfo) { + const std::optional<DarwinSDKInfo> &SDKInfo) { const Arg *A = Args.getLastArg(options::OPT_isysroot); if (!A) - return None; + return std::nullopt; StringRef isysroot = A->getValue(); StringRef SDK = Darwin::getSDKName(isysroot); if (!SDK.size()) - return None; + return std::nullopt; std::string Version; if (SDKInfo) { @@ -1772,26 +1981,33 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args, Version = std::string(SDK.slice(StartVer, EndVer + 1)); } if (Version.empty()) - return None; + return std::nullopt; auto CreatePlatformFromSDKName = - [&](StringRef SDK) -> Optional<DarwinPlatform> { - if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator")) + [&](StringRef SDK) -> std::optional<DarwinPlatform> { + if (SDK.starts_with("iPhoneOS") || SDK.starts_with("iPhoneSimulator")) return DarwinPlatform::createFromSDK( Darwin::IPhoneOS, Version, - /*IsSimulator=*/SDK.startswith("iPhoneSimulator")); - else if (SDK.startswith("MacOSX")) + /*IsSimulator=*/SDK.starts_with("iPhoneSimulator")); + else if (SDK.starts_with("MacOSX")) return DarwinPlatform::createFromSDK(Darwin::MacOS, getSystemOrSDKMacOSVersion(Version)); - else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator")) + else if (SDK.starts_with("WatchOS") || SDK.starts_with("WatchSimulator")) return DarwinPlatform::createFromSDK( Darwin::WatchOS, Version, - /*IsSimulator=*/SDK.startswith("WatchSimulator")); - else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator")) + /*IsSimulator=*/SDK.starts_with("WatchSimulator")); + else if (SDK.starts_with("AppleTVOS") || + SDK.starts_with("AppleTVSimulator")) return DarwinPlatform::createFromSDK( Darwin::TvOS, Version, - /*IsSimulator=*/SDK.startswith("AppleTVSimulator")); - return None; + /*IsSimulator=*/SDK.starts_with("AppleTVSimulator")); + else if (SDK.starts_with("XR")) + return DarwinPlatform::createFromSDK( + Darwin::XROS, Version, + /*IsSimulator=*/SDK.contains("Simulator")); + else if (SDK.starts_with("DriverKit")) + return DarwinPlatform::createFromSDK(Darwin::DriverKit, Version); + return std::nullopt; }; if (auto Result = CreatePlatformFromSDKName(SDK)) return Result; @@ -1827,6 +2043,14 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, case llvm::Triple::WatchOS: OsVersion = Triple.getWatchOSVersion(); break; + case llvm::Triple::XROS: + OsVersion = Triple.getOSVersion(); + if (!OsVersion.getMajor()) + OsVersion = OsVersion.withMajorReplaced(1); + break; + case llvm::Triple::DriverKit: + OsVersion = Triple.getDriverKitVersion(); + break; default: llvm_unreachable("Unexpected OS type"); break; @@ -1834,99 +2058,117 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, std::string OSVersion; llvm::raw_string_ostream(OSVersion) - << OsVersion.getMajor() << '.' << OsVersion.getMinor().getValueOr(0) - << '.' << OsVersion.getSubminor().getValueOr(0); + << OsVersion.getMajor() << '.' << OsVersion.getMinor().value_or(0) << '.' + << OsVersion.getSubminor().value_or(0); return OSVersion; } /// Tries to infer the target OS from the -arch. -Optional<DarwinPlatform> +std::optional<DarwinPlatform> inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, const llvm::Triple &Triple, const Driver &TheDriver) { llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS; StringRef MachOArchName = Toolchain.getMachOArchName(Args); - if (MachOArchName == "arm64" || MachOArchName == "arm64e") { -#if __arm64__ - // A clang running on an Apple Silicon mac defaults - // to building for mac when building for arm64 rather than - // defaulting to iOS. + if (MachOArchName == "arm64" || MachOArchName == "arm64e") OSTy = llvm::Triple::MacOSX; -#else - OSTy = llvm::Triple::IOS; -#endif - } else if (MachOArchName == "armv7" || MachOArchName == "armv7s") + else if (MachOArchName == "armv7" || MachOArchName == "armv7s") OSTy = llvm::Triple::IOS; else if (MachOArchName == "armv7k" || MachOArchName == "arm64_32") OSTy = llvm::Triple::WatchOS; else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && MachOArchName != "armv7em") OSTy = llvm::Triple::MacOSX; - if (OSTy == llvm::Triple::UnknownOS) - return None; + return std::nullopt; return DarwinPlatform::createFromArch(OSTy, getOSVersion(OSTy, Triple, TheDriver)); } /// Returns the deployment target that's specified using the -target option. -Optional<DarwinPlatform> getDeploymentTargetFromTargetArg( +std::optional<DarwinPlatform> getDeploymentTargetFromTargetArg( DerivedArgList &Args, const llvm::Triple &Triple, const Driver &TheDriver, - const Optional<DarwinSDKInfo> &SDKInfo) { + const std::optional<DarwinSDKInfo> &SDKInfo) { if (!Args.hasArg(options::OPT_target)) - return None; + return std::nullopt; if (Triple.getOS() == llvm::Triple::Darwin || Triple.getOS() == llvm::Triple::UnknownOS) - return None; + return std::nullopt; std::string OSVersion = getOSVersion(Triple.getOS(), Triple, TheDriver); - return DarwinPlatform::createFromTarget( - Triple, OSVersion, Args.getLastArg(options::OPT_target), SDKInfo); + std::optional<llvm::Triple> TargetVariantTriple; + for (const Arg *A : Args.filtered(options::OPT_darwin_target_variant)) { + llvm::Triple TVT(A->getValue()); + // Find a matching <arch>-<vendor> target variant triple that can be used. + if ((Triple.getArch() == llvm::Triple::aarch64 || + TVT.getArchName() == Triple.getArchName()) && + TVT.getArch() == Triple.getArch() && + TVT.getSubArch() == Triple.getSubArch() && + TVT.getVendor() == Triple.getVendor()) { + if (TargetVariantTriple) + continue; + A->claim(); + // Accept a -target-variant triple when compiling code that may run on + // macOS or Mac Catalyst. + if ((Triple.isMacOSX() && TVT.getOS() == llvm::Triple::IOS && + TVT.isMacCatalystEnvironment()) || + (TVT.isMacOSX() && Triple.getOS() == llvm::Triple::IOS && + Triple.isMacCatalystEnvironment())) { + TargetVariantTriple = TVT; + continue; + } + TheDriver.Diag(diag::err_drv_target_variant_invalid) + << A->getSpelling() << A->getValue(); + } + } + return DarwinPlatform::createFromTarget(Triple, OSVersion, + Args.getLastArg(options::OPT_target), + TargetVariantTriple, SDKInfo); } /// Returns the deployment target that's specified using the -mtargetos option. -Optional<DarwinPlatform> -getDeploymentTargetFromMTargetOSArg(DerivedArgList &Args, - const Driver &TheDriver, - const Optional<DarwinSDKInfo> &SDKInfo) { +std::optional<DarwinPlatform> getDeploymentTargetFromMTargetOSArg( + DerivedArgList &Args, const Driver &TheDriver, + const std::optional<DarwinSDKInfo> &SDKInfo) { auto *A = Args.getLastArg(options::OPT_mtargetos_EQ); if (!A) - return None; + return std::nullopt; llvm::Triple TT(llvm::Twine("unknown-apple-") + A->getValue()); switch (TT.getOS()) { case llvm::Triple::MacOSX: case llvm::Triple::IOS: case llvm::Triple::TvOS: case llvm::Triple::WatchOS: + case llvm::Triple::XROS: break; default: TheDriver.Diag(diag::err_drv_invalid_os_in_arg) << TT.getOSName() << A->getAsString(Args); - return None; + return std::nullopt; } VersionTuple Version = TT.getOSVersion(); if (!Version.getMajor()) { TheDriver.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args); - return None; + return std::nullopt; } return DarwinPlatform::createFromMTargetOS(TT.getOS(), Version, TT.getEnvironment(), A, SDKInfo); } -Optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS, - const ArgList &Args, - const Driver &TheDriver) { +std::optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS, + const ArgList &Args, + const Driver &TheDriver) { const Arg *A = Args.getLastArg(options::OPT_isysroot); if (!A) - return None; + return std::nullopt; StringRef isysroot = A->getValue(); auto SDKInfoOrErr = parseDarwinSDKInfo(VFS, isysroot); if (!SDKInfoOrErr) { llvm::consumeError(SDKInfoOrErr.takeError()); TheDriver.Diag(diag::warn_drv_darwin_sdk_invalid_settings); - return None; + return std::nullopt; } return *SDKInfoOrErr; } @@ -1960,7 +2202,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { SDKInfo = parseSDKSettings(getVFS(), Args, getDriver()); // The OS and the version can be specified using the -target argument. - Optional<DarwinPlatform> OSTarget = + std::optional<DarwinPlatform> OSTarget = getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver(), SDKInfo); if (OSTarget) { // Disallow mixing -target and -mtargetos=. @@ -1970,7 +2212,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { getDriver().Diag(diag::err_drv_cannot_mix_options) << TargetArgStr << MTargetOSArgStr; } - Optional<DarwinPlatform> OSVersionArgTarget = + std::optional<DarwinPlatform> OSVersionArgTarget = getDeploymentTargetFromOSVersionArg(Args, getDriver()); if (OSVersionArgTarget) { unsigned TargetMajor, TargetMinor, TargetMicro; @@ -1996,7 +2238,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { std::string OSVersionArg = OSVersionArgTarget->getAsString(Args, Opts); std::string TargetArg = OSTarget->getAsString(Args, Opts); - getDriver().Diag(clang::diag::warn_drv_overriding_flag_option) + getDriver().Diag(clang::diag::warn_drv_overriding_option) << OSVersionArg << TargetArg; } } @@ -2005,7 +2247,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { SDKInfo))) { // The OS target can be specified using the -mtargetos= argument. // Disallow mixing -mtargetos= and -m<os>version-min=. - Optional<DarwinPlatform> OSVersionArgTarget = + std::optional<DarwinPlatform> OSVersionArgTarget = getDeploymentTargetFromOSVersionArg(Args, getDriver()); if (OSVersionArgTarget) { std::string MTargetOSArgStr = OSTarget->getAsString(Args, Opts); @@ -2023,7 +2265,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple()); if (OSTarget) { // Don't infer simulator from the arch when the SDK is also specified. - Optional<DarwinPlatform> SDKTarget = + std::optional<DarwinPlatform> SDKTarget = inferDeploymentTargetFromSDK(Args, SDKInfo); if (SDKTarget) OSTarget->setEnvironment(SDKTarget->getEnvironment()); @@ -2052,17 +2294,20 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { unsigned Major, Minor, Micro; bool HadExtra; + // The major version should not be over this number. + const unsigned MajorVersionLimit = 1000; // Set the tool chain target information. if (Platform == MacOS) { if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, Micro, HadExtra) || - HadExtra || Major < 10 || Major >= 100 || Minor >= 100 || Micro >= 100) + HadExtra || Major < 10 || Major >= MajorVersionLimit || Minor >= 100 || + Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSTarget->getAsString(Args, Opts); } else if (Platform == IPhoneOS) { if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, Micro, HadExtra) || - HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) + HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSTarget->getAsString(Args, Opts); ; @@ -2094,13 +2339,27 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } else if (Platform == TvOS) { if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, Micro, HadExtra) || - HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) + HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSTarget->getAsString(Args, Opts); } else if (Platform == WatchOS) { if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, Micro, HadExtra) || - HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) + HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << OSTarget->getAsString(Args, Opts); + } else if (Platform == DriverKit) { + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || + HadExtra || Major < 19 || Major >= MajorVersionLimit || Minor >= 100 || + Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << OSTarget->getAsString(Args, Opts); + } else if (Platform == XROS) { + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || + HadExtra || Major < 1 || Major >= MajorVersionLimit || Minor >= 100 || + Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSTarget->getAsString(Args, Opts); } else @@ -2109,42 +2368,60 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { DarwinEnvironmentKind Environment = OSTarget->getEnvironment(); // Recognize iOS targets with an x86 architecture as the iOS simulator. if (Environment == NativeEnvironment && Platform != MacOS && - OSTarget->canInferSimulatorFromArch() && getTriple().isX86()) + Platform != DriverKit && OSTarget->canInferSimulatorFromArch() && + getTriple().isX86()) Environment = Simulator; VersionTuple NativeTargetVersion; if (Environment == MacCatalyst) NativeTargetVersion = OSTarget->getNativeTargetVersion(); setTarget(Platform, Environment, Major, Minor, Micro, NativeTargetVersion); + TargetVariantTriple = OSTarget->getTargetVariantTriple(); if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef SDK = getSDKName(A->getValue()); if (SDK.size() > 0) { size_t StartVer = SDK.find_first_of("0123456789"); StringRef SDKName = SDK.slice(0, StartVer); - if (!SDKName.startswith(getPlatformFamily()) && - !dropSDKNamePrefix(SDKName).startswith(getPlatformFamily())) + if (!SDKName.starts_with(getPlatformFamily()) && + !dropSDKNamePrefix(SDKName).starts_with(getPlatformFamily())) getDriver().Diag(diag::warn_incompatible_sysroot) << SDKName << getPlatformFamily(); } } } -// Returns the effective header sysroot path to use. This comes either from -// -isysroot or --sysroot. -llvm::StringRef DarwinClang::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const { - if(DriverArgs.hasArg(options::OPT_isysroot)) - return DriverArgs.getLastArgValue(options::OPT_isysroot); - if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot; - return "/"; +// For certain platforms/environments almost all resources (e.g., headers) are +// located in sub-directories, e.g., for DriverKit they live in +// <SYSROOT>/System/DriverKit/usr/include (instead of <SYSROOT>/usr/include). +static void AppendPlatformPrefix(SmallString<128> &Path, + const llvm::Triple &T) { + if (T.isDriverKit()) { + llvm::sys::path::append(Path, "System", "DriverKit"); + } +} + +// Returns the effective sysroot from either -isysroot or --sysroot, plus the +// platform prefix (if any). +llvm::SmallString<128> +DarwinClang::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const { + llvm::SmallString<128> Path("/"); + if (DriverArgs.hasArg(options::OPT_isysroot)) + Path = DriverArgs.getLastArgValue(options::OPT_isysroot); + else if (!getDriver().SysRoot.empty()) + Path = getDriver().SysRoot; + + if (hasEffectiveTriple()) { + AppendPlatformPrefix(Path, getEffectiveTriple()); + } + return Path; } void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { const Driver &D = getDriver(); - llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); + llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs); bool NoStdInc = DriverArgs.hasArg(options::OPT_nostdinc); bool NoStdlibInc = DriverArgs.hasArg(options::OPT_nostdlibinc); @@ -2229,22 +2506,27 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( // Also check whether this is used for setting library search paths. ToolChain::AddClangCXXStdlibIncludeArgs(DriverArgs, CC1Args); - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) + if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, + options::OPT_nostdincxx)) return; - llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); + llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs); switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: { - // On Darwin, libc++ can be installed in one of the following two places: - // 1. Alongside the compiler in <install>/include/c++/v1 - // 2. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1 + // On Darwin, libc++ can be installed in one of the following places: + // 1. Alongside the compiler in <install>/include/c++/v1 + // 2. Alongside the compiler in <clang-executable-folder>/../include/c++/v1 + // 3. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1 // - // The precendence of paths is as listed above, i.e. we take the first path - // that exists. Also note that we never include libc++ twice -- we take the - // first path that exists and don't send the other paths to CC1 (otherwise + // The precedence of paths is as listed above, i.e. we take the first path + // that exists. Note that we never include libc++ twice -- we take the first + // path that exists and don't send the other paths to CC1 (otherwise // include_next could break). + // + // Also note that in most cases, (1) and (2) are exactly the same path. + // Those two paths will differ only when the `clang` program being run + // is actually a symlink to the real executable. // Check for (1) // Get from '<install>/bin' to '<install>/include/c++/v1'. @@ -2261,7 +2543,20 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( << "\"\n"; } - // Otherwise, check for (2) + // (2) Check for the folder where the executable is located, if different. + if (getDriver().getInstalledDir() != getDriver().Dir) { + InstallBin = llvm::StringRef(getDriver().Dir); + llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1"); + if (getVFS().exists(InstallBin)) { + addSystemInclude(DriverArgs, CC1Args, InstallBin); + return; + } else if (DriverArgs.hasArg(options::OPT_v)) { + llvm::errs() << "ignoring nonexistent directory \"" << InstallBin + << "\"\n"; + } + } + + // Otherwise, check for (3) llvm::SmallString<128> SysrootUsr = Sysroot; llvm::sys::path::append(SysrootUsr, "usr", "include", "c++", "v1"); if (getVFS().exists(SysrootUsr)) { @@ -2285,17 +2580,6 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( switch (arch) { default: break; - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "powerpc-apple-darwin10", - arch == llvm::Triple::ppc64 ? "ppc64" : ""); - IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.0.0", "powerpc-apple-darwin10", - arch == llvm::Triple::ppc64 ? "ppc64" : ""); - break; - case llvm::Triple::x86: case llvm::Triple::x86_64: IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, @@ -2334,6 +2618,7 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( break; } } + void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); @@ -2341,6 +2626,8 @@ void DarwinClang::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: @@ -2395,6 +2682,12 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a"); } else if (isTargetIPhoneOS()) { llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a"); + } else if (isTargetDriverKit()) { + // DriverKit doesn't want extra runtime support. + } else if (isTargetXROSDevice()) { + llvm::sys::path::append( + P, llvm::Twine("libclang_rt.cc_kext_") + + llvm::Triple::getOSTypeName(llvm::Triple::XROS) + ".a"); } else { llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); } @@ -2422,12 +2715,9 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches either the toolchain // triple arch, or the arch being bound. - llvm::Triple::ArchType XarchArch = - tools::darwin::getArchTypeForMachOArchName(A->getValue(0)); - if (!(XarchArch == getArch() || - (!BoundArch.empty() && - XarchArch == - tools::darwin::getArchTypeForMachOArchName(BoundArch)))) + StringRef XarchArch = A->getValue(0); + if (!(XarchArch == getArchName() || + (!BoundArch.empty() && XarchArch == BoundArch))) continue; Arg *OriginalArg = A; @@ -2497,19 +2787,11 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, DAL->AddFlagArg( A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings)); break; - - case options::OPT_fpascal_strings: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings)); - break; - - case options::OPT_fno_pascal_strings: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings)); - break; } } // Add the arch options based on the particular spelling of -arch, to match - // how the driver driver works. + // how the driver works. if (!BoundArch.empty()) { StringRef Name = BoundArch; const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ); @@ -2620,11 +2902,36 @@ bool Darwin::isAlignedAllocationUnavailable() const { case WatchOS: // Earlier than 4.0. OS = llvm::Triple::WatchOS; break; + case XROS: // Always available. + return false; + case DriverKit: // Always available. + return false; } return TargetVersion < alignedAllocMinVersion(OS); } +static bool sdkSupportsBuiltinModules(const Darwin::DarwinPlatformKind &TargetPlatform, const std::optional<DarwinSDKInfo> &SDKInfo) { + if (!SDKInfo) + return false; + + VersionTuple SDKVersion = SDKInfo->getVersion(); + switch (TargetPlatform) { + case Darwin::MacOS: + return SDKVersion >= VersionTuple(99U); + case Darwin::IPhoneOS: + return SDKVersion >= VersionTuple(99U); + case Darwin::TvOS: + return SDKVersion >= VersionTuple(99U); + case Darwin::WatchOS: + return SDKVersion >= VersionTuple(99U); + case Darwin::XROS: + return SDKVersion >= VersionTuple(99U); + default: + return true; + } +} + void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const { @@ -2635,6 +2942,45 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, isAlignedAllocationUnavailable()) CC1Args.push_back("-faligned-alloc-unavailable"); + addClangCC1ASTargetOptions(DriverArgs, CC1Args); + + // Enable compatibility mode for NSItemProviderCompletionHandler in + // Foundation/NSItemProvider.h. + CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking"); + + // Give static local variables in inline functions hidden visibility when + // -fvisibility-inlines-hidden is enabled. + if (!DriverArgs.getLastArgNoClaim( + options::OPT_fvisibility_inlines_hidden_static_local_var, + options::OPT_fno_visibility_inlines_hidden_static_local_var)) + CC1Args.push_back("-fvisibility-inlines-hidden-static-local-var"); + + // Earlier versions of the darwin SDK have the C standard library headers + // all together in the Darwin module. That leads to module cycles with + // the _Builtin_ modules. e.g. <inttypes.h> on darwin includes <stdint.h>. + // The builtin <stdint.h> include-nexts <stdint.h>. When both of those + // darwin headers are in the Darwin module, there's a module cycle Darwin -> + // _Builtin_stdint -> Darwin (i.e. inttypes.h (darwin) -> stdint.h (builtin) -> + // stdint.h (darwin)). This is fixed in later versions of the darwin SDK, + // but until then, the builtin headers need to join the system modules. + // i.e. when the builtin stdint.h is in the Darwin module too, the cycle + // goes away. Note that -fbuiltin-headers-in-system-modules does nothing + // to fix the same problem with C++ headers, and is generally fragile. + if (!sdkSupportsBuiltinModules(TargetPlatform, SDKInfo)) + CC1Args.push_back("-fbuiltin-headers-in-system-modules"); + + if (!DriverArgs.hasArgNoClaim(options::OPT_fdefine_target_os_macros, + options::OPT_fno_define_target_os_macros)) + CC1Args.push_back("-fdefine-target-os-macros"); +} + +void Darwin::addClangCC1ASTargetOptions( + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1ASArgs) const { + if (TargetVariantTriple) { + CC1ASArgs.push_back("-darwin-target-variant-triple"); + CC1ASArgs.push_back(Args.MakeArgString(TargetVariantTriple->getTriple())); + } + if (SDKInfo) { /// Pass the SDK version to the compiler when the SDK information is /// available. @@ -2642,32 +2988,45 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, std::string Arg; llvm::raw_string_ostream OS(Arg); OS << "-target-sdk-version=" << V; - CC1Args.push_back(DriverArgs.MakeArgString(OS.str())); + CC1ASArgs.push_back(Args.MakeArgString(OS.str())); }; if (isTargetMacCatalyst()) { if (const auto *MacOStoMacCatalystMapping = SDKInfo->getVersionMapping( DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) { - Optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map( - SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(), None); + std::optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map( + SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(), + std::nullopt); EmitTargetSDKVersionArg( SDKVersion ? *SDKVersion : minimumMacCatalystDeploymentTarget()); } } else { EmitTargetSDKVersionArg(SDKInfo->getVersion()); } - } - - // Enable compatibility mode for NSItemProviderCompletionHandler in - // Foundation/NSItemProvider.h. - CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking"); - // Give static local variables in inline functions hidden visibility when - // -fvisibility-inlines-hidden is enabled. - if (!DriverArgs.getLastArgNoClaim( - options::OPT_fvisibility_inlines_hidden_static_local_var, - options::OPT_fno_visibility_inlines_hidden_static_local_var)) - CC1Args.push_back("-fvisibility-inlines-hidden-static-local-var"); + /// Pass the target variant SDK version to the compiler when the SDK + /// information is available and is required for target variant. + if (TargetVariantTriple) { + if (isTargetMacCatalyst()) { + std::string Arg; + llvm::raw_string_ostream OS(Arg); + OS << "-darwin-target-variant-sdk-version=" << SDKInfo->getVersion(); + CC1ASArgs.push_back(Args.MakeArgString(OS.str())); + } else if (const auto *MacOStoMacCatalystMapping = + SDKInfo->getVersionMapping( + DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) { + if (std::optional<VersionTuple> SDKVersion = + MacOStoMacCatalystMapping->map( + SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(), + std::nullopt)) { + std::string Arg; + llvm::raw_string_ostream OS(Arg); + OS << "-darwin-target-variant-sdk-version=" << *SDKVersion; + CC1ASArgs.push_back(Args.MakeArgString(OS.str())); + } + } + } + } } DerivedArgList * @@ -2676,7 +3035,6 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, // First get the generic Apple args, before moving onto Darwin-specific ones. DerivedArgList *DAL = MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind); - const OptTable &Opts = getDriver().getOpts(); // If no architecture is bound, none of the translations here are relevant. if (BoundArch.empty()) @@ -2691,7 +3049,7 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, // FIXME: It would be far better to avoid inserting those -static arguments, // but we can't check the deployment target in the translation code until // it is set here. - if (isTargetWatchOSBased() || + if (isTargetWatchOSBased() || isTargetDriverKit() || isTargetXROS() || (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) { for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { Arg *A = *it; @@ -2708,26 +3066,6 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, } } - if (!Args.getLastArg(options::OPT_stdlib_EQ) && - GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ), - "libc++"); - - // Validate the C++ standard library choice. - CXXStdlibType Type = GetCXXStdlibType(*DAL); - if (Type == ToolChain::CST_Libcxx) { - // Check whether the target provides libc++. - StringRef where; - - // Complain about targeting iOS < 5.0 in any way. - if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0)) - where = "iOS 5.0"; - - if (where != StringRef()) { - getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where; - } - } - auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch); if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) { if (Args.hasFlag(options::OPT_fomit_frame_pointer, @@ -2739,13 +3077,19 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, return DAL; } -bool MachO::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel MachO::getDefaultUnwindTableLevel(const ArgList &Args) const { // Unwind tables are not emitted if -fno-exceptions is supplied (except when // targeting x86_64). - return getArch() == llvm::Triple::x86_64 || - (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj && - Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, - true)); + if (getArch() == llvm::Triple::x86_64 || + (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj && + Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, + true))) + return (getArch() == llvm::Triple::aarch64 || + getArch() == llvm::Triple::aarch64_32) + ? UnwindTableLevel::Synchronous + : UnwindTableLevel::Asynchronous; + + return UnwindTableLevel::None; } bool MachO::UseDwarfDebugFlags() const { @@ -2754,6 +3098,12 @@ bool MachO::UseDwarfDebugFlags() const { return false; } +std::string MachO::GetGlobalDebugPathRemapping() const { + if (const char *S = ::getenv("RC_DEBUG_PREFIX_MAP")) + return S; + return {}; +} + llvm::ExceptionHandling Darwin::GetExceptionModel(const ArgList &Args) const { // Darwin uses SjLj exceptions on ARM. if (getTriple().getArch() != llvm::Triple::arm && @@ -2793,6 +3143,8 @@ void Darwin::addMinVersionArgs(const ArgList &Args, ArgStringList &CmdArgs) const { VersionTuple TargetVersion = getTripleTargetVersion(); + assert(!isTargetXROS() && "xrOS always uses -platform-version"); + if (isTargetWatchOS()) CmdArgs.push_back("-watchos_version_min"); else if (isTargetWatchOSSimulator()) @@ -2801,6 +3153,8 @@ void Darwin::addMinVersionArgs(const ArgList &Args, CmdArgs.push_back("-tvos_version_min"); else if (isTargetTvOSSimulator()) CmdArgs.push_back("-tvos_simulator_version_min"); + else if (isTargetDriverKit()) + CmdArgs.push_back("-driverkit_version_min"); else if (isTargetIOSSimulator()) CmdArgs.push_back("-ios_simulator_version_min"); else if (isTargetIOSBased()) @@ -2816,6 +3170,25 @@ void Darwin::addMinVersionArgs(const ArgList &Args, if (!MinTgtVers.empty() && MinTgtVers > TargetVersion) TargetVersion = MinTgtVers; CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + if (TargetVariantTriple) { + assert(isTargetMacOSBased() && "unexpected target"); + VersionTuple VariantTargetVersion; + if (TargetVariantTriple->isMacOSX()) { + CmdArgs.push_back("-macosx_version_min"); + TargetVariantTriple->getMacOSXVersion(VariantTargetVersion); + } else { + assert(TargetVariantTriple->isiOS() && + TargetVariantTriple->isMacCatalystEnvironment() && + "unexpected target variant triple"); + CmdArgs.push_back("-maccatalyst_version_min"); + VariantTargetVersion = TargetVariantTriple->getiOSVersion(); + } + VersionTuple MinTgtVers = + TargetVariantTriple->getMinimumSupportedOSVersion(); + if (MinTgtVers.getMajor() && MinTgtVers > VariantTargetVersion) + VariantTargetVersion = MinTgtVers; + CmdArgs.push_back(Args.MakeArgString(VariantTargetVersion.getAsString())); + } } static const char *getPlatformName(Darwin::DarwinPlatformKind Platform, @@ -2831,58 +3204,100 @@ static const char *getPlatformName(Darwin::DarwinPlatformKind Platform, return "tvos"; case Darwin::WatchOS: return "watchos"; + case Darwin::XROS: + return "xros"; + case Darwin::DriverKit: + return "driverkit"; } llvm_unreachable("invalid platform"); } void Darwin::addPlatformVersionArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { - // -platform_version <platform> <target_version> <sdk_version> - // Both the target and SDK version support only up to 3 components. - CmdArgs.push_back("-platform_version"); - std::string PlatformName = getPlatformName(TargetPlatform, TargetEnvironment); - if (TargetEnvironment == Darwin::Simulator) - PlatformName += "-simulator"; - CmdArgs.push_back(Args.MakeArgString(PlatformName)); - VersionTuple TargetVersion = getTripleTargetVersion().withoutBuild(); - VersionTuple MinTgtVers = getEffectiveTriple().getMinimumSupportedOSVersion(); - if (!MinTgtVers.empty() && MinTgtVers > TargetVersion) - TargetVersion = MinTgtVers; - CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + auto EmitPlatformVersionArg = + [&](const VersionTuple &TV, Darwin::DarwinPlatformKind TargetPlatform, + Darwin::DarwinEnvironmentKind TargetEnvironment, + const llvm::Triple &TT) { + // -platform_version <platform> <target_version> <sdk_version> + // Both the target and SDK version support only up to 3 components. + CmdArgs.push_back("-platform_version"); + std::string PlatformName = + getPlatformName(TargetPlatform, TargetEnvironment); + if (TargetEnvironment == Darwin::Simulator) + PlatformName += "-simulator"; + CmdArgs.push_back(Args.MakeArgString(PlatformName)); + VersionTuple TargetVersion = TV.withoutBuild(); + if ((TargetPlatform == Darwin::IPhoneOS || + TargetPlatform == Darwin::TvOS) && + getTriple().getArchName() == "arm64e" && + TargetVersion.getMajor() < 14) { + // arm64e slice is supported on iOS/tvOS 14+ only. + TargetVersion = VersionTuple(14, 0); + } + VersionTuple MinTgtVers = TT.getMinimumSupportedOSVersion(); + if (!MinTgtVers.empty() && MinTgtVers > TargetVersion) + TargetVersion = MinTgtVers; + CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + + if (TargetPlatform == IPhoneOS && TargetEnvironment == MacCatalyst) { + // Mac Catalyst programs must use the appropriate iOS SDK version + // that corresponds to the macOS SDK version used for the compilation. + std::optional<VersionTuple> iOSSDKVersion; + if (SDKInfo) { + if (const auto *MacOStoMacCatalystMapping = + SDKInfo->getVersionMapping( + DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) { + iOSSDKVersion = MacOStoMacCatalystMapping->map( + SDKInfo->getVersion().withoutBuild(), + minimumMacCatalystDeploymentTarget(), std::nullopt); + } + } + CmdArgs.push_back(Args.MakeArgString( + (iOSSDKVersion ? *iOSSDKVersion + : minimumMacCatalystDeploymentTarget()) + .getAsString())); + return; + } - if (isTargetMacCatalyst()) { - // Mac Catalyst programs must use the appropriate iOS SDK version - // that corresponds to the macOS SDK version used for the compilation. - Optional<VersionTuple> iOSSDKVersion; - if (SDKInfo) { - if (const auto *MacOStoMacCatalystMapping = SDKInfo->getVersionMapping( - DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) { - iOSSDKVersion = MacOStoMacCatalystMapping->map( - SDKInfo->getVersion().withoutBuild(), - minimumMacCatalystDeploymentTarget(), None); - } - } - CmdArgs.push_back(Args.MakeArgString( - (iOSSDKVersion ? *iOSSDKVersion : minimumMacCatalystDeploymentTarget()) - .getAsString())); + if (SDKInfo) { + VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild(); + if (!SDKVersion.getMinor()) + SDKVersion = VersionTuple(SDKVersion.getMajor(), 0); + CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString())); + } else { + // Use an SDK version that's matching the deployment target if the SDK + // version is missing. This is preferred over an empty SDK version + // (0.0.0) as the system's runtime might expect the linked binary to + // contain a valid SDK version in order for the binary to work + // correctly. It's reasonable to use the deployment target version as + // a proxy for the SDK version because older SDKs don't guarantee + // support for deployment targets newer than the SDK versions, so that + // rules out using some predetermined older SDK version, which leaves + // the deployment target version as the only reasonable choice. + CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + } + }; + EmitPlatformVersionArg(getTripleTargetVersion(), TargetPlatform, + TargetEnvironment, getEffectiveTriple()); + if (!TargetVariantTriple) return; - } - - if (SDKInfo) { - VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild(); - CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString())); + Darwin::DarwinPlatformKind Platform; + Darwin::DarwinEnvironmentKind Environment; + VersionTuple TargetVariantVersion; + if (TargetVariantTriple->isMacOSX()) { + TargetVariantTriple->getMacOSXVersion(TargetVariantVersion); + Platform = Darwin::MacOS; + Environment = Darwin::NativeEnvironment; } else { - // Use an SDK version that's matching the deployment target if the SDK - // version is missing. This is preferred over an empty SDK version (0.0.0) - // as the system's runtime might expect the linked binary to contain a - // valid SDK version in order for the binary to work correctly. It's - // reasonable to use the deployment target version as a proxy for the - // SDK version because older SDKs don't guarantee support for deployment - // targets newer than the SDK versions, so that rules out using some - // predetermined older SDK version, which leaves the deployment target - // version as the only reasonable choice. - CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + assert(TargetVariantTriple->isiOS() && + TargetVariantTriple->isMacCatalystEnvironment() && + "unexpected target variant triple"); + TargetVariantVersion = TargetVariantTriple->getiOSVersion(); + Platform = Darwin::IPhoneOS; + Environment = Darwin::MacCatalyst; } + EmitPlatformVersionArg(TargetVariantVersion, Platform, Environment, + *TargetVariantTriple); } // Add additional link args for the -dynamiclib option. @@ -2987,7 +3402,7 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, } void Darwin::CheckObjCARC() const { - if (isTargetIOSBased() || isTargetWatchOSBased() || + if (isTargetIOSBased() || isTargetWatchOSBased() || isTargetXROS() || (isTargetMacOSBased() && !isMacosxVersionLT(10, 6))) return; getDriver().Diag(diag::err_arc_unsupported_on_toolchain); @@ -3003,7 +3418,6 @@ SanitizerMask Darwin::getSupportedSanitizers() const { Res |= SanitizerKind::Leak; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; - Res |= SanitizerKind::Function; Res |= SanitizerKind::ObjCCast; // Prior to 10.9, macOS shipped a version of the C++ standard library without @@ -3013,16 +3427,15 @@ SanitizerMask Darwin::getSupportedSanitizers() const { !(isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0))) Res |= SanitizerKind::Vptr; - if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) { + if ((IsX86_64 || IsAArch64) && + (isTargetMacOSBased() || isTargetIOSSimulator() || + isTargetTvOSSimulator() || isTargetWatchOSSimulator())) { Res |= SanitizerKind::Thread; - } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) { - if (IsX86_64) - Res |= SanitizerKind::Thread; } return Res; } void Darwin::printVerboseInfo(raw_ostream &OS) const { - CudaInstallation.print(OS); - RocmInstallation.print(OS); + CudaInstallation->print(OS); + RocmInstallation->print(OS); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h index 5e23047a5512..5e60b0841d6d 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H #include "Cuda.h" +#include "LazyDetector.h" #include "ROCm.h" #include "clang/Basic/DarwinSDKInfo.h" #include "clang/Basic/LangOptions.h" @@ -28,7 +29,8 @@ namespace tools { namespace darwin { llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str); -void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str); +void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str, + const llvm::opt::ArgList &Args); class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool { virtual void anchor(); @@ -63,8 +65,8 @@ class LLVM_LIBRARY_VISIBILITY Linker : public MachOTool { bool NeedsTempPath(const InputInfoList &Inputs) const; void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - const InputInfoList &Inputs, unsigned Version[5], - bool LinkerIsLLD) const; + const InputInfoList &Inputs, VersionTuple Version, + bool LinkerIsLLD, bool UsePlatformVersion) const; public: Linker(const ToolChain &TC) : MachOTool("darwin::Linker", "linker", TC) {} @@ -147,6 +149,9 @@ private: mutable std::unique_ptr<tools::darwin::Dsymutil> Dsymutil; mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug; + /// The version of the linker known to be available in the tool chain. + mutable std::optional<VersionTuple> LinkerVersion; + public: MachO(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); @@ -159,6 +164,10 @@ public: /// example, Apple treats different ARM variations as distinct architectures. StringRef getMachOArchName(const llvm::opt::ArgList &Args) const; + /// Get the version of the linker known to be available for a particular + /// compiler invocation (via the `-mlinker-version=` arg). + VersionTuple getLinkerVersion(const llvm::opt::ArgList &Args) const; + /// Add the linker arguments to link the ARC runtime library. virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const {} @@ -231,10 +240,6 @@ public: // expected to use /usr/include/Block.h. return true; } - bool IsIntegratedAssemblerDefault() const override { - // Default integrated assembler to on for Apple's MachO targets. - return true; - } bool IsMathErrnoDefault() const override { return false; } @@ -247,7 +252,8 @@ public: bool UseObjCMixedDispatch() const override { return true; } - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; @@ -260,6 +266,7 @@ public: bool SupportsProfiling() const override; bool UseDwarfDebugFlags() const override; + std::string GetGlobalDebugPathRemapping() const override; llvm::ExceptionHandling GetExceptionModel(const llvm::opt::ArgList &Args) const override { @@ -291,7 +298,9 @@ public: IPhoneOS, TvOS, WatchOS, - LastDarwinPlatform = WatchOS + DriverKit, + XROS, + LastDarwinPlatform = DriverKit }; enum DarwinEnvironmentKind { NativeEnvironment, @@ -308,10 +317,13 @@ public: mutable VersionTuple OSTargetVersion; /// The information about the darwin SDK that was used. - mutable Optional<DarwinSDKInfo> SDKInfo; + mutable std::optional<DarwinSDKInfo> SDKInfo; - CudaInstallationDetector CudaInstallation; - RocmInstallationDetector RocmInstallation; + /// The target variant triple that was specified (if any). + mutable std::optional<llvm::Triple> TargetVariantTriple; + + LazyDetector<CudaInstallationDetector> CudaInstallation; + LazyDetector<RocmInstallationDetector> RocmInstallation; private: void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; @@ -338,7 +350,7 @@ public: bool isKernelStatic() const override { return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) && - !isTargetWatchOS()); + !isTargetWatchOS() && !isTargetDriverKit()); } void addProfileRTLibs(const llvm::opt::ArgList &Args, @@ -394,6 +406,16 @@ public: return isTargetIPhoneOS() || isTargetIOSSimulator(); } + bool isTargetXROSDevice() const { + return TargetPlatform == XROS && TargetEnvironment == NativeEnvironment; + } + + bool isTargetXROSSimulator() const { + return TargetPlatform == XROS && TargetEnvironment == Simulator; + } + + bool isTargetXROS() const { return TargetPlatform == XROS; } + bool isTargetTvOS() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == TvOS && TargetEnvironment == NativeEnvironment; @@ -424,6 +446,11 @@ public: return TargetPlatform == WatchOS; } + bool isTargetDriverKit() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == DriverKit; + } + bool isTargetMacCatalyst() const { return TargetPlatform == IPhoneOS && TargetEnvironment == MacCatalyst; } @@ -488,6 +515,10 @@ protected: llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + void addClangCC1ASTargetOptions( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1ASArgs) const override; + StringRef getPlatformFamily() const; StringRef getOSLibraryNameSuffix(bool IgnoreSim = false) const override; @@ -527,7 +558,8 @@ public: GetDefaultStackProtectorLevel(bool KernelOrKext) const override { // Stack protectors default to on for user code on 10.5, // and for everything in 10.6 and beyond - if (isTargetIOSBased() || isTargetWatchOSBased()) + if (isTargetIOSBased() || isTargetWatchOSBased() || isTargetDriverKit() || + isTargetXROS()) return LangOptions::SSPOn; else if (isTargetMacOSBased() && !isMacosxVersionLT(10, 6)) return LangOptions::SSPOn; @@ -605,7 +637,8 @@ private: llvm::StringRef ArchDir, llvm::StringRef BitDir) const; - llvm::StringRef GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const; + llvm::SmallString<128> + GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp index 8cfec6a6c4e0..9942fc632e0a 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -19,21 +20,19 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; -/// DragonFly Tools - -// For now, DragonFly Assemble does just about the same as for -// FreeBSD, but this may change soon. void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - claimNoWarnArgs(Args); + const auto &ToolChain = static_cast<const DragonFly &>(getToolChain()); ArgStringList CmdArgs; + claimNoWarnArgs(Args); + // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct as in the base system to assemble 32-bit code. - if (getToolChain().getArch() == llvm::Triple::x86) + if (ToolChain.getArch() == llvm::Triple::x86) CmdArgs.push_back("--32"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -44,7 +43,7 @@ void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as")); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -55,21 +54,27 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); + const auto &ToolChain = static_cast<const DragonFly &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool Static = Args.hasArg(options::OPT_static); + const bool Shared = Args.hasArg(options::OPT_shared); + const bool Profiling = Args.hasArg(options::OPT_pg); + const bool Pie = Args.hasArg(options::OPT_pie); ArgStringList CmdArgs; if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_static)) { + if (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 { + if (Shared) + CmdArgs.push_back("-shared"); + else if (!Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); } @@ -79,77 +84,92 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct ld in the base system to link 32-bit code. - if (getToolChain().getArch() == llvm::Triple::x86) { + if (Arch == llvm::Triple::x86) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); } + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 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, options::OPT_r)) { - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("gcrt1.o"))); + const char *crt1 = nullptr; + const char *crtbegin = nullptr; + if (!Shared) { + if (Profiling) + crt1 = "gcrt1.o"; else { - if (Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("Scrt1.o"))); + if (Pie) + crt1 = "Scrt1.o"; else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); + crt1 = "crt1.o"; } } - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); + + if (Shared || Pie) + crtbegin = "crtbeginS.o"; else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); + crtbegin = "crtbegin.o"; + + if (crt1) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } - Args.AddAllArgs(CmdArgs, - {options::OPT_L, options::OPT_T_Group, options::OPT_e}); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_s, options::OPT_t, options::OPT_r}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, options::OPT_r)) { - CmdArgs.push_back("-L/usr/lib/gcc80"); - - if (!Args.hasArg(options::OPT_static)) { + if (!Static) { CmdArgs.push_back("-rpath"); CmdArgs.push_back("/usr/lib/gcc80"); } + // Use the static OpenMP runtime with -static-openmp + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + if (D.CCCIsCXX()) { - if (getToolChain().ShouldLinkCXXStdlib(Args)) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); CmdArgs.push_back("-lm"); } if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); - if (!Args.hasArg(options::OPT_nolibc)) { + if (!Args.hasArg(options::OPT_nolibc)) CmdArgs.push_back("-lc"); - } - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_static_libgcc)) { + if (Static || Args.hasArg(options::OPT_static_libgcc)) { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("-lgcc_eh"); } else { if (Args.hasArg(options::OPT_shared_libgcc)) { CmdArgs.push_back("-lgcc_pic"); - if (!Args.hasArg(options::OPT_shared)) + if (!Shared) CmdArgs.push_back("-lgcc"); } else { CmdArgs.push_back("-lgcc"); @@ -162,18 +182,19 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, options::OPT_r)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); + const char *crtend = nullptr; + if (Shared || Pie) + crtend ="crtendS.o"; else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); + crtend = "crtend.o"; + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } - getToolChain().addProfileRTLibs(Args, CmdArgs); + ToolChain.addProfileRTLibs(Args, CmdArgs); - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -191,8 +212,35 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); - getFilePaths().push_back("/usr/lib"); - getFilePaths().push_back("/usr/lib/gcc80"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/gcc80")); +} + +void DragonFly::AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); +} + +void DragonFly::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/c++/8.0"), "", "", + DriverArgs, CC1Args); } Tool *DragonFly::buildAssembler() const { diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h index 3ed5acefaefb..715f6b45519b 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h @@ -16,9 +16,10 @@ namespace clang { namespace driver { namespace tools { -/// dragonfly -- Directly call GNU Binutils assembler and linker + +/// Directly call GNU Binutils assembler and linker namespace dragonfly { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("dragonfly::Assembler", "assembler", TC) {} @@ -31,7 +32,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("dragonfly::Linker", "linker", TC) {} @@ -55,6 +56,13 @@ public: bool IsMathErrnoDefault() const override { return false; } + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp index c169e3d45793..03d68c3df7fb 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp @@ -6,11 +6,17 @@ // //===----------------------------------------------------------------------===// - #include "Flang.h" +#include "Arch/RISCV.h" #include "CommonArgs.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/Driver/Options.h" +#include "llvm/Frontend/Debug/Options.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/RISCVISAInfo.h" +#include "llvm/TargetParser/RISCVTargetParser.h" #include <cassert> @@ -19,56 +25,653 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -void Flang::AddFortranDialectOptions(const ArgList &Args, +/// Add -x lang to \p CmdArgs for \p Input. +static void addDashXForInput(const ArgList &Args, const InputInfo &Input, + ArgStringList &CmdArgs) { + CmdArgs.push_back("-x"); + // Map the driver type to the frontend type. + CmdArgs.push_back(types::getTypeName(Input.getType())); +} + +void Flang::addFortranDialectOptions(const ArgList &Args, ArgStringList &CmdArgs) const { - Args.AddAllArgs( - CmdArgs, {options::OPT_ffixed_form, options::OPT_ffree_form, - options::OPT_ffixed_line_length_EQ, options::OPT_fopenmp, - options::OPT_fopenacc, options::OPT_finput_charset_EQ, - options::OPT_fimplicit_none, options::OPT_fno_implicit_none, - options::OPT_fbackslash, options::OPT_fno_backslash, - options::OPT_flogical_abbreviations, - options::OPT_fno_logical_abbreviations, - options::OPT_fxor_operator, options::OPT_fno_xor_operator, - options::OPT_falternative_parameter_statement, - options::OPT_fdefault_real_8, options::OPT_fdefault_integer_8, - options::OPT_fdefault_double_8, options::OPT_flarge_sizes, - options::OPT_fno_automatic}); -} - -void Flang::AddPreprocessingOptions(const ArgList &Args, + Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form, + options::OPT_ffree_form, + options::OPT_ffixed_line_length_EQ, + options::OPT_fopenmp, + options::OPT_fopenmp_version_EQ, + options::OPT_fopenacc, + options::OPT_finput_charset_EQ, + options::OPT_fimplicit_none, + options::OPT_fno_implicit_none, + options::OPT_fbackslash, + options::OPT_fno_backslash, + options::OPT_flogical_abbreviations, + options::OPT_fno_logical_abbreviations, + options::OPT_fxor_operator, + options::OPT_fno_xor_operator, + options::OPT_falternative_parameter_statement, + options::OPT_fdefault_real_8, + options::OPT_fdefault_integer_8, + options::OPT_fdefault_double_8, + options::OPT_flarge_sizes, + options::OPT_fno_automatic}); +} + +void Flang::addPreprocessingOptions(const ArgList &Args, ArgStringList &CmdArgs) const { - Args.AddAllArgs(CmdArgs, + Args.addAllArgs(CmdArgs, {options::OPT_P, options::OPT_D, options::OPT_U, options::OPT_I, options::OPT_cpp, options::OPT_nocpp}); } -void Flang::AddOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { - Args.AddAllArgs(CmdArgs, +/// @C shouldLoopVersion +/// +/// Check if Loop Versioning should be enabled. +/// We look for the last of one of the following: +/// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride. +/// Loop versioning is disabled if the last option is +/// -fno-version-loops-for-stride. +/// Loop versioning is enabled if the last option is one of: +/// -floop-versioning +/// -Ofast +/// -O4 +/// -O3 +/// For all other cases, loop versioning is is disabled. +/// +/// The gfortran compiler automatically enables the option for -O3 or -Ofast. +/// +/// @return true if loop-versioning should be enabled, otherwise false. +static bool shouldLoopVersion(const ArgList &Args) { + const Arg *LoopVersioningArg = Args.getLastArg( + options::OPT_Ofast, options::OPT_O, options::OPT_O4, + options::OPT_floop_versioning, options::OPT_fno_loop_versioning); + if (!LoopVersioningArg) + return false; + + if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning)) + return false; + + if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning)) + return true; + + if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) || + LoopVersioningArg->getOption().matches(options::OPT_O4)) + return true; + + if (LoopVersioningArg->getOption().matches(options::OPT_O)) { + StringRef S(LoopVersioningArg->getValue()); + unsigned OptLevel = 0; + // Note -Os or Oz woould "fail" here, so return false. Which is the + // desiered behavior. + if (S.getAsInteger(10, OptLevel)) + return false; + + return OptLevel > 2; + } + + llvm_unreachable("We should not end up here"); + return false; +} + +void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { + Args.addAllArgs(CmdArgs, {options::OPT_module_dir, options::OPT_fdebug_module_writer, options::OPT_fintrinsic_modules_path, options::OPT_pedantic, - options::OPT_std_EQ, options::OPT_W_Joined}); + options::OPT_std_EQ, options::OPT_W_Joined, + options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ, + options::OPT_funderscoring, options::OPT_fno_underscoring}); + + llvm::codegenoptions::DebugInfoKind DebugInfoKind; + if (Args.hasArg(options::OPT_gN_Group)) { + Arg *gNArg = Args.getLastArg(options::OPT_gN_Group); + DebugInfoKind = debugLevelToInfoKind(*gNArg); + } else if (Args.hasArg(options::OPT_g_Flag)) { + DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly; + } else { + DebugInfoKind = llvm::codegenoptions::NoDebugInfo; + } + addDebugInfoKind(CmdArgs, DebugInfoKind); +} + +void Flang::addCodegenOptions(const ArgList &Args, + ArgStringList &CmdArgs) const { + Arg *stackArrays = + Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays, + options::OPT_fno_stack_arrays); + if (stackArrays && + !stackArrays->getOption().matches(options::OPT_fno_stack_arrays)) + CmdArgs.push_back("-fstack-arrays"); + + if (shouldLoopVersion(Args)) + CmdArgs.push_back("-fversion-loops-for-stride"); + + Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir, + options::OPT_flang_deprecated_no_hlfir, + options::OPT_flang_experimental_polymorphism, + options::OPT_fno_ppc_native_vec_elem_order, + options::OPT_fppc_native_vec_elem_order}); +} + +void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { + // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of + // (RelocationModel, PICLevel, IsPIE). + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Args); + + if (auto *RMName = RelocationModelName(RelocationModel)) { + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back(RMName); + } + if (PICLevel > 0) { + CmdArgs.push_back("-pic-level"); + CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); + if (IsPIE) + CmdArgs.push_back("-pic-is-pie"); + } +} + +void Flang::AddAArch64TargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Handle -msve_vector_bits=<bits> + if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { + StringRef Val = A->getValue(); + const Driver &D = getToolChain().getDriver(); + if (Val.equals("128") || Val.equals("256") || Val.equals("512") || + Val.equals("1024") || Val.equals("2048") || Val.equals("128+") || + Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") || + Val.equals("2048+")) { + unsigned Bits = 0; + if (Val.ends_with("+")) + Val = Val.substr(0, Val.size() - 1); + else { + [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); + assert(!Invalid && "Failed to parse value"); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128))); + } + + [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); + assert(!Invalid && "Failed to parse value"); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128))); + // Silently drop requests for vector-length agnostic code as it's implied. + } else if (!Val.equals("scalable")) + // Handle the unsupported values passed to msve-vector-bits. + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } +} + +void Flang::AddRISCVTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const llvm::Triple &Triple = getToolChain().getTriple(); + // Handle -mrvv-vector-bits=<bits> + if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) { + StringRef Val = A->getValue(); + const Driver &D = getToolChain().getDriver(); + + // Get minimum VLen from march. + unsigned MinVLen = 0; + StringRef Arch = riscv::getRISCVArch(Args, Triple); + auto ISAInfo = llvm::RISCVISAInfo::parseArchString( + Arch, /*EnableExperimentalExtensions*/ true); + // Ignore parsing error. + if (!errorToBool(ISAInfo.takeError())) + MinVLen = (*ISAInfo)->getMinVLen(); + + // If the value is "zvl", use MinVLen from march. Otherwise, try to parse + // as integer as long as we have a MinVLen. + unsigned Bits = 0; + if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) { + Bits = MinVLen; + } else if (!Val.getAsInteger(10, Bits)) { + // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that + // at least MinVLen. + if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock || + Bits > 65536 || !llvm::isPowerOf2_32(Bits)) + Bits = 0; + } + + // If we got a valid value try to use it. + if (Bits != 0) { + unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock; + CmdArgs.push_back( + Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin))); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin))); + } else if (!Val.equals("scalable")) { + // Handle the unsupported values passed to mrvv-vector-bits. + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } + } +} + +static void addVSDefines(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + + unsigned ver = 0; + const VersionTuple vt = TC.computeMSVCVersion(nullptr, Args); + ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(0) * 100000 + + vt.getSubminor().value_or(0); + CmdArgs.push_back(Args.MakeArgString("-D_MSC_VER=" + Twine(ver / 100000))); + CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver))); + CmdArgs.push_back(Args.MakeArgString("-D_WIN32")); + + llvm::Triple triple = TC.getTriple(); + if (triple.isAArch64()) { + CmdArgs.push_back("-D_M_ARM64=1"); + } else if (triple.isX86() && triple.isArch32Bit()) { + CmdArgs.push_back("-D_M_IX86=600"); + } else if (triple.isX86() && triple.isArch64Bit()) { + CmdArgs.push_back("-D_M_X64=100"); + } else { + llvm_unreachable( + "Flang on Windows only supports X86_32, X86_64 and AArch64"); + } +} + +static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + assert(TC.getTriple().isKnownWindowsMSVCEnvironment() && + "can only add VS runtime library on Windows!"); + // if -fno-fortran-main has been passed, skip linking Fortran_main.a + bool LinkFortranMain = !Args.hasArg(options::OPT_no_fortran_main); + if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { + CmdArgs.push_back(Args.MakeArgString( + "--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins"))); + } + unsigned RTOptionID = options::OPT__SLASH_MT; + if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue()) + .Case("static", options::OPT__SLASH_MT) + .Case("static_dbg", options::OPT__SLASH_MTd) + .Case("dll", options::OPT__SLASH_MD) + .Case("dll_dbg", options::OPT__SLASH_MDd) + .Default(options::OPT__SLASH_MT); + } + switch (RTOptionID) { + case options::OPT__SLASH_MT: + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("--dependent-lib=libcmt"); + if (LinkFortranMain) + CmdArgs.push_back("--dependent-lib=Fortran_main.static.lib"); + CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib"); + CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib"); + break; + case options::OPT__SLASH_MTd: + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("--dependent-lib=libcmtd"); + if (LinkFortranMain) + CmdArgs.push_back("--dependent-lib=Fortran_main.static_dbg.lib"); + CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib"); + CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib"); + break; + case options::OPT__SLASH_MD: + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + CmdArgs.push_back("--dependent-lib=msvcrt"); + if (LinkFortranMain) + CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic.lib"); + CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib"); + CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib"); + break; + case options::OPT__SLASH_MDd: + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_DLL"); + CmdArgs.push_back("--dependent-lib=msvcrtd"); + if (LinkFortranMain) + CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib"); + CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib"); + CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib"); + break; + } +} + +void Flang::AddAMDGPUTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + if (Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) { + StringRef Val = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val)); + } +} + +void Flang::addTargetOptions(const ArgList &Args, + ArgStringList &CmdArgs) const { + const ToolChain &TC = getToolChain(); + const llvm::Triple &Triple = TC.getEffectiveTriple(); + const Driver &D = TC.getDriver(); + + std::string CPU = getCPUName(D, Args, Triple); + if (!CPU.empty()) { + CmdArgs.push_back("-target-cpu"); + CmdArgs.push_back(Args.MakeArgString(CPU)); + } + + // Add the target features. + switch (TC.getArch()) { + default: + break; + case llvm::Triple::aarch64: + getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); + AddAArch64TargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::r600: + case llvm::Triple::amdgcn: + getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); + AddAMDGPUTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::riscv64: + getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); + AddRISCVTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::x86_64: + getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); + break; + } + + if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { + StringRef Name = A->getValue(); + if (Name == "SVML") { + if (Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } else if (Name == "LIBMVEC-X86") { + if (Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } else if (Name == "SLEEF" || Name == "ArmPL") { + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_be) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } + + if (Triple.isOSDarwin()) { + // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these + // here incase they are added someday + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (A->getValue() == StringRef{"Accelerate"}) { + CmdArgs.push_back("-framework"); + CmdArgs.push_back("Accelerate"); + } + } + } + A->render(Args, CmdArgs); + } + + if (Triple.isKnownWindowsMSVCEnvironment()) { + processVSRuntimeLibrary(TC, Args, CmdArgs); + addVSDefines(TC, Args, CmdArgs); + } + + // TODO: Add target specific flags, ABI, mtune option etc. +} + +void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, + const JobAction &JA, const ArgList &Args, + ArgStringList &CmdArgs) const { + bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); + bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) || + JA.isHostOffloading(C.getActiveOffloadKinds()); + + // Skips the primary input file, which is the input file that the compilation + // proccess will be executed upon (e.g. the host bitcode file) and + // adds other secondary input (e.g. device bitcode files for embedding to the + // -fembed-offload-object argument or the host IR file for proccessing + // during device compilation to the fopenmp-host-ir-file-path argument via + // OpenMPDeviceInput). This is condensed logic from the ConstructJob + // function inside of the Clang driver for pushing on further input arguments + // needed for offloading during various phases of compilation. + for (size_t i = 1; i < Inputs.size(); ++i) { + if (Inputs[i].getType() == types::TY_Nothing) { + // contains nothing, so it's skippable + } else if (IsHostOffloadingAction) { + CmdArgs.push_back( + Args.MakeArgString("-fembed-offload-object=" + + getToolChain().getInputFilename(Inputs[i]))); + } else if (IsOpenMPDevice) { + if (Inputs[i].getFilename()) { + CmdArgs.push_back("-fopenmp-host-ir-file-path"); + CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename())); + } else { + llvm_unreachable("missing openmp host-ir file for device offloading"); + } + } else { + llvm_unreachable( + "unexpectedly given multiple inputs or given unknown input"); + } + } + + if (IsOpenMPDevice) { + // -fopenmp-is-target-device is passed along to tell the frontend that it is + // generating code for a device, so that only the relevant code is emitted. + CmdArgs.push_back("-fopenmp-is-target-device"); + + // When in OpenMP offloading mode, enable debugging on the device. + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); + if (Args.hasFlag(options::OPT_fopenmp_target_debug, + options::OPT_fno_openmp_target_debug, /*Default=*/false)) + CmdArgs.push_back("-fopenmp-target-debug"); + + // When in OpenMP offloading mode, forward assumptions information about + // thread and team counts in the device. + if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, + options::OPT_fno_openmp_assume_teams_oversubscription, + /*Default=*/false)) + CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); + if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, + options::OPT_fno_openmp_assume_threads_oversubscription, + /*Default=*/false)) + CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); + if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) + CmdArgs.push_back("-fopenmp-assume-no-thread-state"); + if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) + CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); + if (Args.hasArg(options::OPT_nogpulib)) + CmdArgs.push_back("-nogpulib"); + } +} + +static void addFloatingPointOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + StringRef FPContract; + bool HonorINFs = true; + bool HonorNaNs = true; + bool ApproxFunc = false; + bool SignedZeros = true; + bool AssociativeMath = false; + bool ReciprocalMath = false; + + if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { + const StringRef Val = A->getValue(); + if (Val == "fast" || Val == "off") { + FPContract = Val; + } else if (Val == "on") { + // Warn instead of error because users might have makefiles written for + // gfortran (which accepts -ffp-contract=on) + D.Diag(diag::warn_drv_unsupported_option_for_flang) + << Val << A->getOption().getName() << "off"; + FPContract = "off"; + } else + // Clang's "fast-honor-pragmas" option is not supported because it is + // non-standard + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } + + for (const Arg *A : Args) { + auto optId = A->getOption().getID(); + switch (optId) { + // if this isn't an FP option, skip the claim below + default: + continue; + + case options::OPT_fhonor_infinities: + HonorINFs = true; + break; + case options::OPT_fno_honor_infinities: + HonorINFs = false; + break; + case options::OPT_fhonor_nans: + HonorNaNs = true; + break; + case options::OPT_fno_honor_nans: + HonorNaNs = false; + break; + case options::OPT_fapprox_func: + ApproxFunc = true; + break; + case options::OPT_fno_approx_func: + ApproxFunc = false; + break; + case options::OPT_fsigned_zeros: + SignedZeros = true; + break; + case options::OPT_fno_signed_zeros: + SignedZeros = false; + break; + case options::OPT_fassociative_math: + AssociativeMath = true; + break; + case options::OPT_fno_associative_math: + AssociativeMath = false; + break; + case options::OPT_freciprocal_math: + ReciprocalMath = true; + break; + case options::OPT_fno_reciprocal_math: + ReciprocalMath = false; + break; + case options::OPT_Ofast: + [[fallthrough]]; + case options::OPT_ffast_math: + HonorINFs = false; + HonorNaNs = false; + AssociativeMath = true; + ReciprocalMath = true; + ApproxFunc = true; + SignedZeros = false; + FPContract = "fast"; + break; + case options::OPT_fno_fast_math: + HonorINFs = true; + HonorNaNs = true; + AssociativeMath = false; + ReciprocalMath = false; + ApproxFunc = false; + SignedZeros = true; + // -fno-fast-math should undo -ffast-math so I return FPContract to the + // default. It is important to check it is "fast" (the default) so that + // --ffp-contract=off -fno-fast-math --> -ffp-contract=off + if (FPContract == "fast") + FPContract = ""; + break; + } + + // If we handled this option claim it + A->claim(); + } + + if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && + ApproxFunc && !SignedZeros && + (FPContract == "fast" || FPContract == "")) { + CmdArgs.push_back("-ffast-math"); + return; + } + + if (!FPContract.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + + if (!HonorINFs) + CmdArgs.push_back("-menable-no-infs"); + + if (!HonorNaNs) + CmdArgs.push_back("-menable-no-nans"); + + if (ApproxFunc) + CmdArgs.push_back("-fapprox-func"); + + if (!SignedZeros) + CmdArgs.push_back("-fno-signed-zeros"); + + if (AssociativeMath && !SignedZeros) + CmdArgs.push_back("-mreassociate"); + + if (ReciprocalMath) + CmdArgs.push_back("-freciprocal-math"); +} + +static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, + const InputInfo &Input) { + StringRef Format = "yaml"; + if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) + Format = A->getValue(); + + CmdArgs.push_back("-opt-record-file"); + + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + CmdArgs.push_back(A->getValue()); + } else { + SmallString<128> F; + + if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { + if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) + F = FinalOutput->getValue(); + } + + if (F.empty()) { + // Use the input filename. + F = llvm::sys::path::stem(Input.getBaseInput()); + } + + SmallString<32> Extension; + Extension += "opt."; + Extension += Format; + + llvm::sys::path::replace_extension(F, Extension); + CmdArgs.push_back(Args.MakeArgString(F)); + } + + if (const Arg *A = + Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { + CmdArgs.push_back("-opt-record-passes"); + CmdArgs.push_back(A->getValue()); + } + + if (!Format.empty()) { + CmdArgs.push_back("-opt-record-format"); + CmdArgs.push_back(Format.data()); + } } void Flang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const auto &TC = getToolChain(); - // TODO: Once code-generation is available, this will need to be commented - // out. - // const llvm::Triple &Triple = TC.getEffectiveTriple(); - // const std::string &TripleStr = Triple.getTriple(); + const llvm::Triple &Triple = TC.getEffectiveTriple(); + const std::string &TripleStr = Triple.getTriple(); + const Driver &D = TC.getDriver(); ArgStringList CmdArgs; + DiagnosticsEngine &Diags = D.getDiags(); // Invoke ourselves in -fc1 mode. CmdArgs.push_back("-fc1"); - // TODO: Once code-generation is available, this will need to be commented - // out. // Add the "effective" target triple. - // CmdArgs.push_back("-triple"); - // CmdArgs.push_back(Args.MakeArgString(TripleStr)); + CmdArgs.push_back("-triple"); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); if (isa<PreprocessJobAction>(JA)) { CmdArgs.push_back("-E"); @@ -100,27 +703,122 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor (i.e. skip when dealing with e.g. binary files). if (types::getPreprocessedType(InputType) != types::TY_INVALID) - AddPreprocessingOptions(Args, CmdArgs); + addPreprocessingOptions(Args, CmdArgs); - AddFortranDialectOptions(Args, CmdArgs); + addFortranDialectOptions(Args, CmdArgs); + + // Color diagnostics are parsed by the driver directly from argv and later + // re-parsed to construct this job; claim any possible color diagnostic here + // to avoid warn_drv_unused_argument. + Args.getLastArg(options::OPT_fcolor_diagnostics, + options::OPT_fno_color_diagnostics); + if (Diags.getDiagnosticOptions().ShowColors) + CmdArgs.push_back("-fcolor-diagnostics"); + + // LTO mode is parsed by the Clang driver library. + LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false); + assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); + if (LTOMode == LTOK_Full) + CmdArgs.push_back("-flto=full"); + else if (LTOMode == LTOK_Thin) { + Diags.Report( + Diags.getCustomDiagID(DiagnosticsEngine::Warning, + "the option '-flto=thin' is a work in progress")); + CmdArgs.push_back("-flto=thin"); + } + + // -fPIC and related options. + addPicOptions(Args, CmdArgs); + + // Floating point related options + addFloatingPointOptions(D, Args, CmdArgs); + + // Add target args, features, etc. + addTargetOptions(Args, CmdArgs); + + // Add Codegen options + addCodegenOptions(Args, CmdArgs); + + // Add R Group options + Args.AddAllArgs(CmdArgs, options::OPT_R_Group); + + // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. + if (willEmitRemarks(Args)) + renderRemarksOptions(Args, CmdArgs, Input); // Add other compile options - AddOtherOptions(Args, CmdArgs); + addOtherOptions(Args, CmdArgs); + + // Offloading related options + addOffloadOptions(C, Inputs, JA, Args, CmdArgs); // Forward -Xflang arguments to -fc1 Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); + CodeGenOptions::FramePointerKind FPKeepKind = + getFramePointerKind(Args, Triple); + + const char *FPKeepKindStr = nullptr; + switch (FPKeepKind) { + case CodeGenOptions::FramePointerKind::None: + FPKeepKindStr = "-mframe-pointer=none"; + break; + case CodeGenOptions::FramePointerKind::NonLeaf: + FPKeepKindStr = "-mframe-pointer=non-leaf"; + break; + case CodeGenOptions::FramePointerKind::All: + FPKeepKindStr = "-mframe-pointer=all"; + break; + } + assert(FPKeepKindStr && "unknown FramePointerKind"); + CmdArgs.push_back(FPKeepKindStr); + + // Forward -mllvm options to the LLVM option parser. In practice, this means + // forwarding to `-fc1` as that's where the LLVM parser is run. + for (const Arg *A : Args.filtered(options::OPT_mllvm)) { + A->claim(); + A->render(Args, CmdArgs); + } + + for (const Arg *A : Args.filtered(options::OPT_mmlir)) { + A->claim(); + A->render(Args, CmdArgs); + } + + // Remove any unsupported gfortran diagnostic options + for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) { + A->claim(); + D.Diag(diag::warn_drv_unsupported_diag_option_for_flang) + << A->getOption().getName(); + } + + // Optimization level for CodeGen. + if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O4)) { + CmdArgs.push_back("-O3"); + D.Diag(diag::warn_O4_is_O3); + } else if (A->getOption().matches(options::OPT_Ofast)) { + CmdArgs.push_back("-O3"); + } else { + A->render(Args, CmdArgs); + } + } + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } assert(Input.isFilename() && "Invalid input."); + + if (Args.getLastArg(options::OPT_save_temps_EQ)) + Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); + + addDashXForInput(Args, Input, CmdArgs); + CmdArgs.push_back(Input.getFilename()); - const auto& D = C.getDriver(); // TODO: Replace flang-new with flang once the new driver replaces the // throwaway driver const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC)); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h index efbdbe854e24..ec2e545a1d0b 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h @@ -29,7 +29,7 @@ private: /// /// \param [in] Args The list of input driver arguments /// \param [out] CmdArgs The list of output command arguments - void AddFortranDialectOptions(const llvm::opt::ArgList &Args, + void addFortranDialectOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; /// Extract preprocessing options from the driver arguments and add them to @@ -37,14 +37,71 @@ private: /// /// \param [in] Args The list of input driver arguments /// \param [out] CmdArgs The list of output command arguments - void AddPreprocessingOptions(const llvm::opt::ArgList &Args, + void addPreprocessingOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + + /// Extract PIC options from the driver arguments and add them to + /// the command arguments. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addPicOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Extract target options from the driver arguments and add them to + /// the command arguments. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addTargetOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Add specific options for AArch64 target. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Add specific options for AMDGPU target. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void AddAMDGPUTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Add specific options for RISC-V target. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void AddRISCVTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Extract offload options from the driver arguments and add them to + /// the command arguments. + /// \param [in] C The current compilation for the driver invocation + /// \param [in] Inputs The input infomration on the current file inputs + /// \param [in] JA The job action + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addOffloadOptions(Compilation &C, const InputInfoList &Inputs, + const JobAction &JA, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Extract options for code generation from the driver arguments and add them + /// to the command arguments. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addCodegenOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + /// Extract other compilation options from the driver arguments and add them /// to the command arguments. /// /// \param [in] Args The list of input driver arguments /// \param [out] CmdArgs The list of output command arguments - void AddOtherOptions(const llvm::opt::ArgList &Args, + void addOtherOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; public: diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp index 05c58a8f43a8..b7c9e0e51cdb 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -11,6 +11,7 @@ #include "Arch/Mips.h" #include "Arch/Sparc.h" #include "CommonArgs.h" +#include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" @@ -29,13 +30,16 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; + const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain()); const auto &D = getToolChain().getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); + ArgStringList CmdArgs; + + claimNoWarnArgs(Args); // 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()) { + switch (ToolChain.getArch()) { default: break; case llvm::Triple::x86: @@ -51,7 +55,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); @@ -59,7 +63,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mabi"); CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - if (getToolChain().getTriple().isLittleEndian()) + if (Triple.isLittleEndian()) CmdArgs.push_back("-EL"); else CmdArgs.push_back("-EB"); @@ -70,39 +74,27 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + AddAssemblerKPIC(ToolChain, 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); + arm::FloatABI ABI = arm::getARMFloatABI(ToolChain, 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"); - } + CmdArgs.push_back("-meabi=5"); break; } - case llvm::Triple::sparc: - case llvm::Triple::sparcel: case llvm::Triple::sparcv9: { - std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); - CmdArgs.push_back( - sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + std::string CPU = getCPUName(D, Args, Triple); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } } @@ -128,7 +120,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as")); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -139,8 +131,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(getToolChain()); + const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsPIE = @@ -169,16 +160,14 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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("-shared"); + } else if (!Args.hasArg(options::OPT_r)) { 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"); - } + if (Arch == llvm::Triple::arm || T.isX86()) + CmdArgs.push_back("--hash-style=both"); CmdArgs.push_back("--enable-new-dtags"); } @@ -220,13 +209,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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"); + CmdArgs.push_back("-X"); break; default: break; @@ -240,11 +226,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 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, @@ -276,16 +261,20 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); - addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, D.getLTOMode() == LTOK_Thin); } @@ -311,10 +300,27 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-lm"); } + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + if (Profiling) + CmdArgs.push_back("-lm_p"); + else + CmdArgs.push_back("-lm"); + } + if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, CmdArgs); + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding // the default system libraries. Just mimic this for now. if (Profiling) @@ -362,10 +368,12 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, options::OPT_r)) { + const char *crtend = nullptr; if (Args.hasArg(options::OPT_shared) || IsPIE) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); + crtend = "crtendS.o"; else - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + crtend = "crtend.o"; + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } @@ -385,65 +393,71 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, // 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.isPPC32()) && - D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); + if (Triple.isArch32Bit() && + D.getVFS().exists(concat(getDriver().SysRoot, "/usr/lib32/crt1.o"))) + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib32")); else - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } -ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { - unsigned Major = getTriple().getOSMajorVersion(); - if (Major >= 10 || Major == 0) - return ToolChain::CST_Libcxx; - return ToolChain::CST_Libstdcxx; -} +void FreeBSD::AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } -unsigned FreeBSD::GetDefaultDwarfVersion() const { - if (getTriple().getOSMajorVersion() < 12) - return 2; - return 4; + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); } 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); + concat(getDriver().SysRoot, "/usr/include/c++/v1")); } void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - CXXStdlibType Type = GetCXXStdlibType(Args); unsigned Major = getTriple().getOSMajorVersion(); bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14; - 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; - } + CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); } void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void FreeBSD::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } Tool *FreeBSD::buildAssembler() const { @@ -452,24 +466,12 @@ Tool *FreeBSD::buildAssembler() const { 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; } +ToolChain::UnwindTableLevel +FreeBSD::getDefaultUnwindTableLevel(const ArgList &Args) const { + return UnwindTableLevel::Asynchronous; +} bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const { return getSanitizerArgs(Args).requiresPIE(); @@ -485,12 +487,11 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const { Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Vptr; - if (IsX86_64 || IsMIPS64) { + if (IsAArch64 || IsX86_64 || IsMIPS64) { Res |= SanitizerKind::Leak; Res |= SanitizerKind::Thread; } - if (IsX86 || IsX86_64) { - Res |= SanitizerKind::Function; + if (IsAArch64 || IsX86 || IsX86_64) { Res |= SanitizerKind::SafeStack; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; @@ -498,18 +499,7 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const { if (IsAArch64 || IsX86_64) { Res |= SanitizerKind::KernelAddress; Res |= SanitizerKind::KernelMemory; - } - 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/FreeBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h index 2a721c750a64..7ab63905ed4f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h @@ -17,9 +17,9 @@ namespace clang { namespace driver { namespace tools { -/// freebsd -- Directly call GNU Binutils assembler and linker +/// Directly call GNU Binutils assembler and linker namespace freebsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("freebsd::Assembler", "assembler", TC) {} @@ -32,7 +32,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("freebsd::Linker", "linker", TC) {} @@ -58,12 +58,19 @@ public: bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } - CXXStdlibType GetDefaultCXXStdlibType() const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void - addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, @@ -71,19 +78,14 @@ public: void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - llvm::ExceptionHandling - GetExceptionModel(const llvm::opt::ArgList &Args) const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPIEDefault(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; - unsigned GetDefaultDwarfVersion() const override; + unsigned GetDefaultDwarfVersion() const override { return 4; } // Until dtrace (via CTF) and LLDB can deal with distributed debug info, // FreeBSD defaults to standalone/full debug info. bool GetDefaultStandaloneDebug() const override { return true; } - void - addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const override; protected: Tool *buildAssembler() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp index bd1600d060c8..14b838500bec 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/MultilibBuilder.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" @@ -33,10 +34,11 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::Fuchsia &ToolChain = - static_cast<const toolchains::Fuchsia &>(getToolChain()); + const auto &ToolChain = static_cast<const Fuchsia &>(getToolChain()); const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getEffectiveTriple(); + ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -53,6 +55,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-z"); CmdArgs.push_back("now"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("start-stop-visibility=hidden"); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); if (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") || llvm::sys::path::stem(Exec).equals_insensitive("ld.lld")) { @@ -84,6 +89,14 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--hash-style=gnu"); } + if (ToolChain.getArch() == llvm::Triple::aarch64) { + CmdArgs.push_back("--execute-only"); + + std::string CPU = getCPUName(D, Args, Triple); + if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") + CmdArgs.push_back("--fix-cortex-a53-843419"); + } + CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) @@ -93,7 +106,7 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args); - if (!Args.hasArg(options::OPT_shared)) { + if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) { std::string Dyld = D.DyldPrefix; if (SanArgs.needsAsanRt() && SanArgs.needsSharedRt()) Dyld += "asan/"; @@ -106,6 +119,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Dyld)); } + if (ToolChain.getArch() == llvm::Triple::riscv64) + CmdArgs.push_back("-X"); + CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -116,21 +132,26 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + Args.addAllArgs(CmdArgs, {options::OPT_L, 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], + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, 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); - ToolChain.addProfileRTLibs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, options::OPT_r)) { @@ -153,11 +174,14 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + // Note that Fuchsia never needs to link in sanitizer runtime deps. Any + // sanitizer runtimes with system dependencies use the `.deplibs` feature + // instead. + addSanitizerRuntimes(ToolChain, Args, CmdArgs); - if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, CmdArgs); + addXRayRuntime(ToolChain, Args, CmdArgs); + + ToolChain.addProfileRTLibs(Args, CmdArgs); AddRunTimeLibs(ToolChain, D, CmdArgs, Args); @@ -172,7 +196,53 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lc"); } - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + C.addCommand(std::make_unique<Command>(JA, *this, + ResponseFileSupport::AtFileCurCP(), + Exec, CmdArgs, Inputs, Output)); +} + +void fuchsia::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); + + // ar tool command "llvm-ar <options> <output_file> <input_files>". + ArgStringList CmdArgs; + // Create and insert file members with a deterministic index. + CmdArgs.push_back("rcsD"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) { + if (II.isFilename()) { + CmdArgs.push_back(II.getFilename()); + } + } + + // Delete old output archive file if it already exists before generating a new + // archive file. + const char *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<Command>(JA, *this, + ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); } @@ -188,68 +258,50 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, if (!D.SysRoot.empty()) { SmallString<128> P(D.SysRoot); llvm::sys::path::append(P, "lib"); - getFilePaths().push_back(std::string(P.str())); + getFilePaths().push_back(std::string(P)); } auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> { std::vector<std::string> FP; - for (const std::string &Path : getStdlibPaths()) { - SmallString<128> P(Path); + if (std::optional<std::string> Path = getStdlibPath()) { + SmallString<128> P(*Path); llvm::sys::path::append(P, M.gccSuffix()); - FP.push_back(std::string(P.str())); + FP.push_back(std::string(P)); } return FP; }; Multilibs.push_back(Multilib()); // Use the noexcept variant with -fno-exceptions to avoid the extra overhead. - Multilibs.push_back(Multilib("noexcept", {}, {}, 1) - .flag("-fexceptions") - .flag("+fno-exceptions")); + Multilibs.push_back(MultilibBuilder("noexcept", {}, {}) + .flag("-fexceptions", /*Disallow=*/true) + .flag("-fno-exceptions") + .makeMultilib()); // ASan has higher priority because we always want the instrumentated version. - Multilibs.push_back(Multilib("asan", {}, {}, 2) - .flag("+fsanitize=address")); + Multilibs.push_back(MultilibBuilder("asan", {}, {}) + .flag("-fsanitize=address") + .makeMultilib()); // Use the asan+noexcept variant with ASan and -fno-exceptions. - Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3) - .flag("+fsanitize=address") - .flag("-fexceptions") - .flag("+fno-exceptions")); + Multilibs.push_back(MultilibBuilder("asan+noexcept", {}, {}) + .flag("-fsanitize=address") + .flag("-fexceptions", /*Disallow=*/true) + .flag("-fno-exceptions") + .makeMultilib()); // HWASan has higher priority because we always want the instrumentated // version. - Multilibs.push_back( - Multilib("hwasan", {}, {}, 4).flag("+fsanitize=hwaddress")); + Multilibs.push_back(MultilibBuilder("hwasan", {}, {}) + .flag("-fsanitize=hwaddress") + .makeMultilib()); // Use the hwasan+noexcept variant with HWASan and -fno-exceptions. - Multilibs.push_back(Multilib("hwasan+noexcept", {}, {}, 5) - .flag("+fsanitize=hwaddress") - .flag("-fexceptions") - .flag("+fno-exceptions")); - // Use the relative vtables ABI. - // TODO: Remove these multilibs once relative vtables are enabled by default - // for Fuchsia. - Multilibs.push_back(Multilib("relative-vtables", {}, {}, 6) - .flag("+fexperimental-relative-c++-abi-vtables")); - Multilibs.push_back(Multilib("relative-vtables+noexcept", {}, {}, 7) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("-fexceptions") - .flag("+fno-exceptions")); - Multilibs.push_back(Multilib("relative-vtables+asan", {}, {}, 8) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("+fsanitize=address")); - Multilibs.push_back(Multilib("relative-vtables+asan+noexcept", {}, {}, 9) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("+fsanitize=address") - .flag("-fexceptions") - .flag("+fno-exceptions")); - Multilibs.push_back(Multilib("relative-vtables+hwasan", {}, {}, 10) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("+fsanitize=hwaddress")); - Multilibs.push_back(Multilib("relative-vtables+hwasan+noexcept", {}, {}, 11) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("+fsanitize=hwaddress") - .flag("-fexceptions") - .flag("+fno-exceptions")); + Multilibs.push_back(MultilibBuilder("hwasan+noexcept", {}, {}) + .flag("-fsanitize=hwaddress") + .flag("-fexceptions", /*Disallow=*/true) + .flag("-fno-exceptions") + .makeMultilib()); // Use Itanium C++ ABI for the compat multilib. - Multilibs.push_back(Multilib("compat", {}, {}, 12).flag("+fc++-abi=itanium")); + Multilibs.push_back(MultilibBuilder("compat", {}, {}) + .flag("-fc++-abi=itanium") + .makeMultilib()); Multilibs.FilterOut([&](const Multilib &M) { std::vector<std::string> RD = FilePaths(M); @@ -257,30 +309,31 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, }); Multilib::flags_list Flags; - addMultilibFlag( - Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true), - "fexceptions", Flags); - addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "fsanitize=address", - Flags); - addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), "fsanitize=hwaddress", + bool Exceptions = + Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true); + addMultilibFlag(Exceptions, "-fexceptions", Flags); + addMultilibFlag(!Exceptions, "-fno-exceptions", Flags); + addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "-fsanitize=address", Flags); + addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), + "-fsanitize=hwaddress", Flags); - addMultilibFlag( - Args.hasFlag(options::OPT_fexperimental_relative_cxx_abi_vtables, - options::OPT_fno_experimental_relative_cxx_abi_vtables, - /*default=*/false), - "fexperimental-relative-c++-abi-vtables", Flags); addMultilibFlag(Args.getLastArgValue(options::OPT_fcxx_abi_EQ) == "itanium", - "fc++-abi=itanium", Flags); + "-fc++-abi=itanium", Flags); Multilibs.setFilePathsCallback(FilePaths); - if (Multilibs.select(Flags, SelectedMultilib)) - if (!SelectedMultilib.isDefault()) + if (Multilibs.select(Flags, SelectedMultilibs)) { + // Ensure that -print-multi-directory only outputs one multilib directory. + Multilib LastSelected = SelectedMultilibs.back(); + SelectedMultilibs = {LastSelected}; + + if (!SelectedMultilibs.back().isDefault()) if (const auto &PathsCallback = Multilibs.filePathsCallback()) - for (const auto &Path : PathsCallback(SelectedMultilib)) + for (const auto &Path : PathsCallback(SelectedMultilibs.back())) // Prepend the multilib path to ensure it takes the precedence. getFilePaths().insert(getFilePaths().begin(), Path); + } } std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, @@ -293,6 +346,10 @@ Tool *Fuchsia::buildLinker() const { return new tools::fuchsia::Linker(*this); } +Tool *Fuchsia::buildStaticLibTool() const { + return new tools::fuchsia::StaticLibTool(*this); +} + ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType( const ArgList &Args) const { if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) { @@ -363,8 +420,8 @@ void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) + if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, + options::OPT_nostdincxx)) return; const Driver &D = getDriver(); @@ -405,6 +462,8 @@ void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, switch (GetCXXStdlibType(Args)) { 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: @@ -431,13 +490,13 @@ SanitizerMask Fuchsia::getDefaultSanitizers() const { SanitizerMask Res; switch (getTriple().getArch()) { case llvm::Triple::aarch64: + case llvm::Triple::riscv64: Res |= SanitizerKind::ShadowCallStack; break; case llvm::Triple::x86_64: Res |= SanitizerKind::SafeStack; break; default: - // TODO: Enable SafeStack on RISC-V once tested. break; } return Res; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h index c0e69df22821..619968f58502 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h @@ -18,7 +18,21 @@ namespace clang { namespace driver { namespace tools { namespace fuchsia { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY StaticLibTool : public Tool { +public: + StaticLibTool(const ToolChain &TC) + : Tool("fuchsia::StaticLibTool", "llvm-ar", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("fuchsia::Linker", "ld.lld", TC) {} @@ -41,17 +55,16 @@ public: const llvm::opt::ArgList &Args); bool HasNativeLLVMSupport() const override { return true; } - bool IsIntegratedAssemblerDefault() const override { return true; } bool IsMathErrnoDefault() const override { return false; } - bool useRelaxRelocations() const override { return true; }; RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; } CXXStdlibType GetDefaultCXXStdlibType() const override { return ToolChain::CST_Libcxx; } - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override { - return true; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override { + return UnwindTableLevel::Asynchronous; } bool isPICDefault() const override { return false; } bool isPIEDefault(const llvm::opt::ArgList &Args) const override { @@ -75,27 +88,31 @@ public: RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; - CXXStdlibType - GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const override; + bool IsAArch64OutlineAtomicsDefault( + const llvm::opt::ArgList &Args) const override { + return true; + } + + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void - AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - const char *getDefaultLinker() const override { - return "ld.lld"; - } + const char *getDefaultLinker() const override { return "ld.lld"; } protected: Tool *buildLinker() const override; + Tool *buildStaticLibTool() const override; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp index 7a9570a686f4..e5e1b1d77269 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp @@ -8,6 +8,8 @@ #include "Gnu.h" #include "Arch/ARM.h" +#include "Arch/CSKY.h" +#include "Arch/LoongArch.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/RISCV.h" @@ -19,14 +21,18 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/MultilibBuilder.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Twine.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Path.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/TargetParser.h" #include <system_error> using namespace clang::driver; @@ -82,7 +88,7 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, RenderExtraToolArgs(JA, CmdArgs); - // If using a driver driver, force the arch. + // If using a driver, force the arch. if (getToolChain().getTriple().isOSDarwin()) { CmdArgs.push_back("-arch"); CmdArgs.push_back( @@ -112,11 +118,11 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, break; } + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { - assert(Output.isNothing() && "Unexpected output"); CmdArgs.push_back("-fsyntax-only"); } @@ -215,30 +221,6 @@ void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, // 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: @@ -253,7 +235,8 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { case llvm::Triple::thumb: case llvm::Triple::armeb: case llvm::Triple::thumbeb: - return isArmBigEndian(T, Args) ? "armelfb_linux_eabi" : "armelf_linux_eabi"; + return tools::arm::isARMBigEndian(T, Args) ? "armelfb_linux_eabi" + : "armelf_linux_eabi"; case llvm::Triple::m68k: return "m68kelf"; case llvm::Triple::ppc: @@ -277,6 +260,10 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { return "elf32_sparc"; case llvm::Triple::sparcv9: return "elf64_sparc"; + case llvm::Triple::loongarch32: + return "elf32loongarch"; + case llvm::Triple::loongarch64: + return "elf64loongarch"; case llvm::Triple::mips: return "elf32btsmip"; case llvm::Triple::mipsel: @@ -299,32 +286,20 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { return "elf_x86_64"; case llvm::Triple::ve: return "elf64ve"; + case llvm::Triple::csky: + return "cskyelf_linux"; 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(Args); - 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)) { + if (HasStaticPIE && Args.hasArg(options::OPT_no_pie)) { 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); + StringRef StaticPIEName = Opts.getOptionName(options::OPT_static_pie); + StringRef NoPIEName = Opts.getOptionName(options::OPT_nopie); D.Diag(diag::err_drv_cannot_mix_options) << StaticPIEName << NoPIEName; } return HasStaticPIE; @@ -388,17 +363,16 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // 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<const toolchains::Generic_ELF &>(getToolChain()); + const auto &ToolChain = static_cast<const Generic_ELF &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool isOHOSFamily = ToolChain.getTriple().isOHOSFamily(); 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 = @@ -418,44 +392,26 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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 (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 (Triple.isARM() || Triple.isThumb()) { + bool IsBigEndian = arm::isARMBigEndian(Triple, Args); if (IsBigEndian) arm::appendBE8LinkFlag(Args, CmdArgs, Triple); - IsBigEndian = IsBigEndian || Arch == llvm::Triple::aarch64_be; CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL"); + } else if (Triple.isAArch64()) { + CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-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) { + if (Arch == llvm::Triple::aarch64 && (isAndroid || isOHOSFamily)) { std::string CPU = getCPUName(D, 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"); @@ -467,17 +423,29 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(diag::err_target_unknown_triple) << Triple.str(); return; } + if (Triple.isRISCV()) + CmdArgs.push_back("-X"); - if (Args.hasArg(options::OPT_shared)) + const bool IsShared = Args.hasArg(options::OPT_shared); + if (IsShared) CmdArgs.push_back("-shared"); - - if (IsStatic) { + bool IsPIE = false; + if (IsStaticPIE) { CmdArgs.push_back("-static"); - } else { + CmdArgs.push_back("-pie"); + CmdArgs.push_back("--no-dynamic-linker"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("text"); + } else if (IsStatic) { + CmdArgs.push_back("-static"); + } else if (!Args.hasArg(options::OPT_r)) { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); - - if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE) { + if (!IsShared) { + IsPIE = Args.hasFlag(options::OPT_pie, options::OPT_no_pie, + ToolChain.isPIEDefault(Args)); + if (IsPIE) + CmdArgs.push_back("-pie"); CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back(Args.MakeArgString(Twine(D.DyldPrefix) + ToolChain.getDynamicLinker(Args))); @@ -540,16 +508,28 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Add crtfastmath.o if available and fast math is enabled. ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs); + + if (isAndroid && Args.hasFlag(options::OPT_fandroid_pad_segment, + options::OPT_fno_android_pad_segment, false)) + CmdArgs.push_back( + Args.MakeArgString(ToolChain.GetFilePath("crt_pad_segment.o"))); } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + Args.addAllArgs(CmdArgs, {options::OPT_L, 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], + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, D.getLTOMode() == LTOK_Thin); } @@ -560,6 +540,9 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + addHIPRuntimeLibArgs(ToolChain, C, Args, CmdArgs); + // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); @@ -577,19 +560,30 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } CmdArgs.push_back("-lm"); } + // Silence warnings when linking C code with a C++ '-stdlib' argument. Args.ClaimAllArgs(options::OPT_stdlib_EQ); + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { if (IsStatic || IsStaticPIE) CmdArgs.push_back("--start-group"); if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, CmdArgs); + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); @@ -609,7 +603,19 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddRunTimeLibs(ToolChain, D, CmdArgs, Args); - if (WantPthread && !isAndroid) + // LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so + // forcibly link with libatomic as a workaround. + // TODO: Issue #41880 and D118021. + if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) { + CmdArgs.push_back("--push-state"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-latomic"); + CmdArgs.push_back("--pop-state"); + } + + // We don't need libpthread neither for bionic (Android) nor for musl, + // (used by OHOS as runtime library). + if (WantPthread && !isAndroid && !isOHOSFamily) CmdArgs.push_back("-lpthread"); if (Args.hasArg(options::OPT_fsplit_stack)) @@ -686,6 +692,10 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, unsigned PICLevel; bool IsPIE; const char *DefaultAssembler = "as"; + // Enforce GNU as on Solaris; the native assembler's input syntax isn't fully + // compatible. + if (getToolChain().getTriple().isOSSolaris()) + DefaultAssembler = "gas"; std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(getToolChain(), Args); @@ -694,12 +704,12 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, CmdArgs.push_back("--compress-debug-sections"); } else { StringRef Value = A->getValue(); - if (Value == "none" || Value == "zlib") { + if (Value == "none" || Value == "zlib" || Value == "zstd") { CmdArgs.push_back( Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } @@ -758,6 +768,8 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, StringRef MArchName = riscv::getRISCVArch(Args, getToolChain().getTriple()); CmdArgs.push_back("-march"); CmdArgs.push_back(MArchName.data()); + if (!Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) + Args.addOptOutFlag(CmdArgs, options::OPT_mrelax, options::OPT_mno_relax); break; } case llvm::Triple::sparc: @@ -782,7 +794,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, case llvm::Triple::thumb: case llvm::Triple::thumbeb: { const llvm::Triple &Triple2 = getToolChain().getTriple(); - CmdArgs.push_back(isArmBigEndian(Triple2, Args) ? "-EB" : "-EL"); + CmdArgs.push_back(arm::isARMBigEndian(Triple2, Args) ? "-EB" : "-EL"); switch (Triple2.getSubArch()) { case llvm::Triple::ARMSubArch_v7: CmdArgs.push_back("-mfpu=neon"); @@ -811,6 +823,11 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, normalizeCPUNamesForAssembler(Args, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); + // The integrated assembler doesn't implement e_flags setting behavior for + // -meabi=gnu (gcc -mabi={apcs-gnu,atpcs} passes -meabi=gnu to gas). For + // compatibility we accept but warn. + if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) + A->ignoreTargetSpecific(); break; } case llvm::Triple::aarch64: @@ -822,6 +839,13 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, break; } + // TODO: handle loongarch32. + case llvm::Triple::loongarch64: { + StringRef ABIName = + loongarch::getLoongArchABI(D, Args, getToolChain().getTriple()); + CmdArgs.push_back(Args.MakeArgString("-mabi=" + ABIName)); + break; + } case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -938,6 +962,17 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); + if (Arg *A = Args.getLastArg(options::OPT_g_Flag, options::OPT_gN_Group, + options::OPT_gdwarf_2, options::OPT_gdwarf_3, + options::OPT_gdwarf_4, options::OPT_gdwarf_5, + options::OPT_gdwarf)) + if (!A->getOption().matches(options::OPT_g0)) { + Args.AddLastArg(CmdArgs, options::OPT_g_Flag); + + unsigned DwarfVersion = getDwarfVersion(getToolChain(), Args); + CmdArgs.push_back(Args.MakeArgString("-gdwarf-" + Twine(DwarfVersion))); + } + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(DefaultAssembler)); C.addCommand(std::make_unique<Command>(JA, *this, @@ -1001,46 +1036,47 @@ 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 MArchMips16 = MultilibBuilder("/mips16").flag("-m32").flag("-mips16"); auto MArchMicroMips = - makeMultilib("/micromips").flag("+m32").flag("+mmicromips"); + MultilibBuilder("/micromips").flag("-m32").flag("-mmicromips"); - auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips"); + auto MArchDefault = MultilibBuilder("") + .flag("-mips16", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); - auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + auto UCLibc = MultilibBuilder("/uclibc").flag("-muclibc"); - auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float"); + auto SoftFloat = MultilibBuilder("/soft-float").flag("-msoft-float"); - auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + auto Nan2008 = MultilibBuilder("/nan2008").flag("-mnan=2008"); - auto DefaultFloat = - makeMultilib("").flag("-msoft-float").flag("-mnan=2008"); + auto DefaultFloat = MultilibBuilder("") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true); - auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + auto BigEndian = + MultilibBuilder("").flag("-EB").flag("-EL", /*Disallow=*/true); - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + auto LittleEndian = + MultilibBuilder("/el").flag("-EL").flag("-EB", /*Disallow=*/true); // Note that this one's osSuffix is "" - auto MAbi64 = makeMultilib("") + auto MAbi64 = MultilibBuilder("") .gccSuffix("/64") .includeSuffix("/64") - .flag("+mabi=n64") - .flag("-mabi=n32") - .flag("-m32"); + .flag("-mabi=n64") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-m32", /*Disallow=*/true); CSMipsMultilibs = - MultilibSet() + MultilibSetBuilder() .Either(MArchMips16, MArchMicroMips, MArchDefault) .Maybe(UCLibc) .Either(SoftFloat, Nan2008, DefaultFloat) @@ -1050,10 +1086,11 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, .Maybe(MAbi64) .FilterOut("/mips16.*/64") .FilterOut("/micromips.*/64") + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector<std::string> Dirs({"/include"}); - if (StringRef(M.includeSuffix()).startswith("/uclibc")) + if (StringRef(M.includeSuffix()).starts_with("/uclibc")) Dirs.push_back( "/../../../../mips-linux-gnu/libc/uclibc/usr/include"); else @@ -1064,21 +1101,27 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, MultilibSet DebianMipsMultilibs; { - Multilib MAbiN32 = - Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32"); + MultilibBuilder MAbiN32 = + MultilibBuilder().gccSuffix("/n32").includeSuffix("/n32").flag( + "-mabi=n32"); - Multilib M64 = Multilib() - .gccSuffix("/64") - .includeSuffix("/64") - .flag("+m64") - .flag("-m32") - .flag("-mabi=n32"); + MultilibBuilder M64 = MultilibBuilder() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("-m64") + .flag("-m32", /*Disallow=*/true) + .flag("-mabi=n32", /*Disallow=*/true); - Multilib M32 = - Multilib().gccSuffix("/32").flag("-m64").flag("+m32").flag("-mabi=n32"); + MultilibBuilder M32 = MultilibBuilder() + .gccSuffix("/32") + .flag("-m64", /*Disallow=*/true) + .flag("-m32") + .flag("-mabi=n32", /*Disallow=*/true); - DebianMipsMultilibs = - MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); + DebianMipsMultilibs = MultilibSetBuilder() + .Either(M32, M64, MAbiN32) + .makeMultilibSet() + .FilterOut(NonExistent); } // Sort candidates. Toolchain that best meets the directories tree goes first. @@ -1087,7 +1130,7 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, if (CSMipsMultilibs.size() < DebianMipsMultilibs.size()) std::iter_swap(Candidates, Candidates + 1); for (const MultilibSet *Candidate : Candidates) { - if (Candidate->select(Flags, Result.SelectedMultilib)) { + if (Candidate->select(Flags, Result.SelectedMultilibs)) { if (Candidate == &DebianMipsMultilibs) Result.BiarchSibling = Multilib(); Result.Multilibs = *Candidate; @@ -1103,25 +1146,32 @@ static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path, DetectedMultilibs &Result) { MultilibSet AndroidMipsMultilibs = - MultilibSet() - .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) - .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) + MultilibSetBuilder() + .Maybe(MultilibBuilder("/mips-r2", {}, {}).flag("-march=mips32r2")) + .Maybe(MultilibBuilder("/mips-r6", {}, {}).flag("-march=mips32r6")) + .makeMultilibSet() .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")) + MultilibSetBuilder() + .Either(MultilibBuilder().flag("-march=mips32"), + MultilibBuilder("/mips-r2", "", "/mips-r2") + .flag("-march=mips32r2"), + MultilibBuilder("/mips-r6", "", "/mips-r6") + .flag("-march=mips32r6")) + .makeMultilibSet() .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")) + MultilibSetBuilder() + .Either(MultilibBuilder().flag("-march=mips64r6"), + MultilibBuilder("/32/mips-r1", "", "/mips-r1") + .flag("-march=mips32"), + MultilibBuilder("/32/mips-r2", "", "/mips-r2") + .flag("-march=mips32r2"), + MultilibBuilder("/32/mips-r6", "", "/mips-r6") + .flag("-march=mips32r6")) + .makeMultilibSet() .FilterOut(NonExistent); MultilibSet *MS = &AndroidMipsMultilibs; @@ -1129,7 +1179,7 @@ static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path, MS = &AndroidMipselMultilibs; else if (VFS.exists(Path + "/32")) MS = &AndroidMips64elMultilibs; - if (MS->select(Flags, Result.SelectedMultilib)) { + if (MS->select(Flags, Result.SelectedMultilibs)) { Result.Multilibs = *MS; return true; } @@ -1142,18 +1192,20 @@ static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, // Musl toolchain multilibs MultilibSet MuslMipsMultilibs; { - auto MArchMipsR2 = makeMultilib("") + auto MArchMipsR2 = MultilibBuilder("") .osSuffix("/mips-r2-hard-musl") - .flag("+EB") - .flag("-EL") - .flag("+march=mips32r2"); + .flag("-EB") + .flag("-EL", /*Disallow=*/true) + .flag("-march=mips32r2"); - auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl") - .flag("-EB") - .flag("+EL") - .flag("+march=mips32r2"); + auto MArchMipselR2 = MultilibBuilder("/mipsel-r2-hard-musl") + .flag("-EB", /*Disallow=*/true) + .flag("-EL") + .flag("-march=mips32r2"); - MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2); + MuslMipsMultilibs = MultilibSetBuilder() + .Either(MArchMipsR2, MArchMipselR2) + .makeMultilibSet(); // Specify the callback that computes the include directories. MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) { @@ -1161,7 +1213,7 @@ static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, {"/../sysroot" + M.osSuffix() + "/usr/include"}); }); } - if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) { + if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilibs)) { Result.Multilibs = MuslMipsMultilibs; return true; } @@ -1174,48 +1226,54 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, // CodeScape MTI toolchain v1.2 and early. MultilibSet MtiMipsMultilibsV1; { - auto MArchMips32 = makeMultilib("/mips32") - .flag("+m32") + auto MArchMips32 = MultilibBuilder("/mips32") + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true) + .flag("-march=mips32"); + + auto MArchMicroMips = MultilibBuilder("/micromips") + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mmicromips"); + + auto MArchMips64r2 = MultilibBuilder("/mips64r2") + .flag("-m32", /*Disallow=*/true) + .flag("-m64") + .flag("-march=mips64r2"); + + auto MArchMips64 = MultilibBuilder("/mips64") + .flag("-m32", /*Disallow=*/true) .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"); + .flag("-march=mips64r2", /*Disallow=*/true); - auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag( - "-march=mips64r2"); + auto MArchDefault = MultilibBuilder("") + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true) + .flag("-march=mips32r2"); - auto MArchDefault = makeMultilib("") - .flag("+m32") - .flag("-m64") - .flag("-mmicromips") - .flag("+march=mips32r2"); + auto Mips16 = MultilibBuilder("/mips16").flag("-mips16"); - auto Mips16 = makeMultilib("/mips16").flag("+mips16"); + auto UCLibc = MultilibBuilder("/uclibc").flag("-muclibc"); - auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + auto MAbi64 = MultilibBuilder("/64") + .flag("-mabi=n64") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-m32", /*Disallow=*/true); - auto MAbi64 = - makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + auto BigEndian = + MultilibBuilder("").flag("-EB").flag("-EL", /*Disallow=*/true); - auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + auto LittleEndian = + MultilibBuilder("/el").flag("-EL").flag("-EB", /*Disallow=*/true); - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + auto SoftFloat = MultilibBuilder("/sof").flag("-msoft-float"); - auto SoftFloat = makeMultilib("/sof").flag("+msoft-float"); - - auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + auto Nan2008 = MultilibBuilder("/nan2008").flag("-mnan=2008"); MtiMipsMultilibsV1 = - MultilibSet() + MultilibSetBuilder() .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, MArchDefault) .Maybe(UCLibc) @@ -1232,10 +1290,11 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, .Maybe(SoftFloat) .Maybe(Nan2008) .FilterOut(".*sof/nan2008") + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector<std::string> Dirs({"/include"}); - if (StringRef(M.includeSuffix()).startswith("/uclibc")) + if (StringRef(M.includeSuffix()).starts_with("/uclibc")) Dirs.push_back("/../../../../sysroot/uclibc/usr/include"); else Dirs.push_back("/../../../../sysroot/usr/include"); @@ -1246,80 +1305,87 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, // CodeScape IMG toolchain starting from v1.3. MultilibSet MtiMipsMultilibsV2; { - auto BeHard = makeMultilib("/mips-r2-hard") - .flag("+EB") + auto BeHard = MultilibBuilder("/mips-r2-hard") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-muclibc", /*Disallow=*/true); + auto BeSoft = MultilibBuilder("/mips-r2-soft") + .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("-mnan=2008", /*Disallow=*/true); + auto ElHard = MultilibBuilder("/mipsel-r2-hard") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-muclibc", /*Disallow=*/true); + auto ElSoft = MultilibBuilder("/mipsel-r2-soft") + .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"); + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); + auto BeHardNan = MultilibBuilder("/mips-r2-hard-nan2008") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-muclibc", /*Disallow=*/true); + auto ElHardNan = MultilibBuilder("/mipsel-r2-hard-nan2008") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-muclibc", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); + auto BeHardNanUclibc = MultilibBuilder("/mips-r2-hard-nan2008-uclibc") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-muclibc"); + auto ElHardNanUclibc = MultilibBuilder("/mipsel-r2-hard-nan2008-uclibc") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-muclibc"); + auto BeHardUclibc = MultilibBuilder("/mips-r2-hard-uclibc") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-muclibc"); + auto ElHardUclibc = MultilibBuilder("/mipsel-r2-hard-uclibc") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-muclibc"); + auto ElMicroHardNan = MultilibBuilder("/micromipsel-r2-hard-nan2008") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-mmicromips"); + auto ElMicroSoft = MultilibBuilder("/micromipsel-r2-soft") + .flag("-EL") + .flag("-msoft-float") + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-mmicromips"); + + auto O32 = MultilibBuilder("/lib") + .osSuffix("") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-mabi=n64", /*Disallow=*/true); + auto N32 = MultilibBuilder("/lib32") + .osSuffix("") + .flag("-mabi=n32") + .flag("-mabi=n64", /*Disallow=*/true); + auto N64 = MultilibBuilder("/lib64") + .osSuffix("") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-mabi=n64"); MtiMipsMultilibsV2 = - MultilibSet() + MultilibSetBuilder() .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan, BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc, ElHardUclibc, ElMicroHardNan, ElMicroSoft}) .Either(O32, N32, N64) + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector<std::string>({"/../../../../sysroot" + @@ -1331,8 +1397,8 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, {"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()}); }); } - for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { - if (Candidate->select(Flags, Result.SelectedMultilib)) { + for (auto *Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { + if (Candidate->select(Flags, Result.SelectedMultilibs)) { Result.Multilibs = *Candidate; return true; } @@ -1346,18 +1412,24 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, // CodeScape IMG toolchain v1.2 and early. MultilibSet ImgMultilibsV1; { - auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32"); + auto Mips64r6 = MultilibBuilder("/mips64r6") + .flag("-m64") + .flag("-m32", /*Disallow=*/true); - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + auto LittleEndian = + MultilibBuilder("/el").flag("-EL").flag("-EB", /*Disallow=*/true); - auto MAbi64 = - makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + auto MAbi64 = MultilibBuilder("/64") + .flag("-mabi=n64") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-m32", /*Disallow=*/true); ImgMultilibsV1 = - MultilibSet() + MultilibSetBuilder() .Maybe(Mips64r6) .Maybe(MAbi64) .Maybe(LittleEndian) + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector<std::string>( @@ -1368,51 +1440,58 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, // CodeScape IMG toolchain starting from v1.3. MultilibSet ImgMultilibsV2; { - auto BeHard = makeMultilib("/mips-r6-hard") - .flag("+EB") + auto BeHard = MultilibBuilder("/mips-r6-hard") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); + auto BeSoft = MultilibBuilder("/mips-r6-soft") + .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("-mmicromips", /*Disallow=*/true); + auto ElHard = MultilibBuilder("/mipsel-r6-hard") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); + auto ElSoft = MultilibBuilder("/mipsel-r6-soft") + .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("-mmicromips", /*Disallow=*/true); + auto BeMicroHard = MultilibBuilder("/micromips-r6-hard") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mmicromips"); + auto BeMicroSoft = MultilibBuilder("/micromips-r6-soft") + .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("-mmicromips"); + auto ElMicroHard = MultilibBuilder("/micromipsel-r6-hard") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mmicromips"); + auto ElMicroSoft = MultilibBuilder("/micromipsel-r6-soft") + .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"); + .flag("-mmicromips"); + + auto O32 = MultilibBuilder("/lib") + .osSuffix("") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-mabi=n64", /*Disallow=*/true); + auto N32 = MultilibBuilder("/lib32") + .osSuffix("") + .flag("-mabi=n32") + .flag("-mabi=n64", /*Disallow=*/true); + auto N64 = MultilibBuilder("/lib64") + .osSuffix("") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-mabi=n64"); ImgMultilibsV2 = - MultilibSet() + MultilibSetBuilder() .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft, ElMicroHard, ElMicroSoft}) .Either(O32, N32, N64) + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector<std::string>({"/../../../../sysroot" + @@ -1424,8 +1503,8 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, {"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()}); }); } - for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) { - if (Candidate->select(Flags, Result.SelectedMultilib)) { + for (auto *Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) { + if (Candidate->select(Flags, Result.SelectedMultilibs)) { Result.Multilibs = *Candidate; return true; } @@ -1446,30 +1525,30 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, 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(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); + "-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(D, Args, TargetTriple), "mnan=2008", + "-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(D, 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); + 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, @@ -1498,7 +1577,7 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, Result.Multilibs.push_back(Default); Result.Multilibs.FilterOut(NonExistent); - if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) { + if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) { Result.BiarchSibling = Multilib(); return true; } @@ -1512,22 +1591,23 @@ static void findAndroidArmMultilibs(const Driver &D, 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"); + MultilibBuilder ArmV7Multilib = MultilibBuilder("/armv7-a") + .flag("-march=armv7-a") + .flag("-mthumb", /*Disallow=*/true); + MultilibBuilder ThumbMultilib = MultilibBuilder("/thumb") + .flag("-march=armv7-a", /*Disallow=*/true) + .flag("-mthumb"); + MultilibBuilder ArmV7ThumbMultilib = + MultilibBuilder("/armv7-a/thumb").flag("-march=armv7-a").flag("-mthumb"); + MultilibBuilder DefaultMultilib = + MultilibBuilder("") + .flag("-march=armv7-a", /*Disallow=*/true) + .flag("-mthumb", /*Disallow=*/true); MultilibSet AndroidArmMultilibs = - MultilibSet() - .Either(ThumbMultilib, ArmV7Multilib, - ArmV7ThumbMultilib, DefaultMultilib) + MultilibSetBuilder() + .Either(ThumbMultilib, ArmV7Multilib, ArmV7ThumbMultilib, + DefaultMultilib) + .makeMultilibSet() .FilterOut(NonExistent); Multilib::flags_list Flags; @@ -1541,10 +1621,10 @@ static void findAndroidArmMultilibs(const Driver &D, bool IsArmV7Mode = (IsArmArch || IsThumbArch) && (llvm::ARM::parseArchVersion(Arch) == 7 || (IsArmArch && Arch == "" && IsV7SubArch)); - addMultilibFlag(IsArmV7Mode, "march=armv7-a", Flags); - addMultilibFlag(IsThumbMode, "mthumb", Flags); + addMultilibFlag(IsArmV7Mode, "-march=armv7-a", Flags); + addMultilibFlag(IsThumbMode, "-mthumb", Flags); - if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib)) + if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilibs)) Result.Multilibs = AndroidArmMultilibs; } @@ -1553,27 +1633,213 @@ static bool findMSP430Multilibs(const Driver &D, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); - Multilib WithoutExceptions = makeMultilib("/430").flag("-exceptions"); - Multilib WithExceptions = makeMultilib("/430/exceptions").flag("+exceptions"); + MultilibBuilder WithoutExceptions = + MultilibBuilder("/430").flag("-exceptions", /*Disallow=*/true); + MultilibBuilder WithExceptions = + MultilibBuilder("/430/exceptions").flag("-exceptions"); // FIXME: when clang starts to support msp430x ISA additional logic // to select between multilib must be implemented - // Multilib MSP430xMultilib = makeMultilib("/large"); + // MultilibBuilder MSP430xMultilib = MultilibBuilder("/large"); - Result.Multilibs.push_back(WithoutExceptions); - Result.Multilibs.push_back(WithExceptions); + Result.Multilibs.push_back(WithoutExceptions.makeMultilib()); + Result.Multilibs.push_back(WithExceptions.makeMultilib()); Result.Multilibs.FilterOut(NonExistent); Multilib::flags_list Flags; addMultilibFlag(Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, false), - "exceptions", Flags); - if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) + "-exceptions", Flags); + if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) return true; return false; } +static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + + tools::csky::FloatABI TheFloatABI = tools::csky::getCSKYFloatABI(D, Args); + std::optional<llvm::StringRef> Res = + tools::csky::getCSKYArchName(D, Args, TargetTriple); + + if (!Res) + return; + auto ARCHName = *Res; + + Multilib::flags_list Flags; + addMultilibFlag(TheFloatABI == tools::csky::FloatABI::Hard, "-hard-fp", + Flags); + addMultilibFlag(TheFloatABI == tools::csky::FloatABI::SoftFP, "-soft-fp", + Flags); + addMultilibFlag(TheFloatABI == tools::csky::FloatABI::Soft, "-soft", Flags); + addMultilibFlag(ARCHName == "ck801", "-march=ck801", Flags); + addMultilibFlag(ARCHName == "ck802", "-march=ck802", Flags); + addMultilibFlag(ARCHName == "ck803", "-march=ck803", Flags); + addMultilibFlag(ARCHName == "ck804", "-march=ck804", Flags); + addMultilibFlag(ARCHName == "ck805", "-march=ck805", Flags); + addMultilibFlag(ARCHName == "ck807", "-march=ck807", Flags); + addMultilibFlag(ARCHName == "ck810", "-march=ck810", Flags); + addMultilibFlag(ARCHName == "ck810v", "-march=ck810v", Flags); + addMultilibFlag(ARCHName == "ck860", "-march=ck860", Flags); + addMultilibFlag(ARCHName == "ck860v", "-march=ck860v", Flags); + + bool isBigEndian = false; + if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, + options::OPT_mbig_endian)) + isBigEndian = !A->getOption().matches(options::OPT_mlittle_endian); + addMultilibFlag(isBigEndian, "-EB", Flags); + + auto HardFloat = MultilibBuilder("/hard-fp").flag("-hard-fp"); + auto SoftFpFloat = MultilibBuilder("/soft-fp").flag("-soft-fp"); + auto SoftFloat = MultilibBuilder("").flag("-soft"); + auto Arch801 = MultilibBuilder("/ck801").flag("-march=ck801"); + auto Arch802 = MultilibBuilder("/ck802").flag("-march=ck802"); + auto Arch803 = MultilibBuilder("/ck803").flag("-march=ck803"); + // CK804 use the same library as CK803 + auto Arch804 = MultilibBuilder("/ck803").flag("-march=ck804"); + auto Arch805 = MultilibBuilder("/ck805").flag("-march=ck805"); + auto Arch807 = MultilibBuilder("/ck807").flag("-march=ck807"); + auto Arch810 = MultilibBuilder("").flag("-march=ck810"); + auto Arch810v = MultilibBuilder("/ck810v").flag("-march=ck810v"); + auto Arch860 = MultilibBuilder("/ck860").flag("-march=ck860"); + auto Arch860v = MultilibBuilder("/ck860v").flag("-march=ck860v"); + auto BigEndian = MultilibBuilder("/big").flag("-EB"); + + MultilibSet CSKYMultilibs = + MultilibSetBuilder() + .Maybe(BigEndian) + .Either({Arch801, Arch802, Arch803, Arch804, Arch805, Arch807, + Arch810, Arch810v, Arch860, Arch860v}) + .Either(HardFloat, SoftFpFloat, SoftFloat) + .makeMultilibSet() + .FilterOut(NonExistent); + + if (CSKYMultilibs.select(Flags, Result.SelectedMultilibs)) + Result.Multilibs = CSKYMultilibs; +} + +/// Extend the multi-lib re-use selection mechanism for RISC-V. +/// This function will try to re-use multi-lib if they are compatible. +/// Definition of compatible: +/// - ABI must be the same. +/// - multi-lib is a subset of current arch, e.g. multi-lib=march=rv32im +/// is a subset of march=rv32imc. +/// - march that contains atomic extension can't reuse multi-lib that +/// doesn't have atomic, vice versa. e.g. multi-lib=march=rv32im and +/// march=rv32ima are not compatible, because software and hardware +/// atomic operation can't work together correctly. +static bool +selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch, + const Multilib::flags_list &Flags, + llvm::SmallVectorImpl<Multilib> &SelectedMultilibs) { + // Try to find the perfect matching multi-lib first. + if (RISCVMultilibSet.select(Flags, SelectedMultilibs)) + return true; + + Multilib::flags_list NewFlags; + std::vector<MultilibBuilder> NewMultilibs; + + llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> ParseResult = + llvm::RISCVISAInfo::parseArchString( + Arch, /*EnableExperimentalExtension=*/true, + /*ExperimentalExtensionVersionCheck=*/false); + // Ignore any error here, we assume it will be handled in another place. + if (llvm::errorToBool(ParseResult.takeError())) + return false; + + auto &ISAInfo = *ParseResult; + + addMultilibFlag(ISAInfo->getXLen() == 32, "-m32", NewFlags); + addMultilibFlag(ISAInfo->getXLen() == 64, "-m64", NewFlags); + + // Collect all flags except march=* + for (StringRef Flag : Flags) { + if (Flag.starts_with("!march=") || Flag.starts_with("-march=")) + continue; + + NewFlags.push_back(Flag.str()); + } + + llvm::StringSet<> AllArchExts; + // Reconstruct multi-lib list, and break march option into separated + // extension. e.g. march=rv32im -> +i +m + for (const auto &M : RISCVMultilibSet) { + bool Skip = false; + + MultilibBuilder NewMultilib = + MultilibBuilder(M.gccSuffix(), M.osSuffix(), M.includeSuffix()); + for (StringRef Flag : M.flags()) { + // Add back all flags except -march. + if (!Flag.consume_front("-march=")) { + NewMultilib.flag(Flag); + continue; + } + + // Break down -march into individual extension. + llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> MLConfigParseResult = + llvm::RISCVISAInfo::parseArchString( + Flag, /*EnableExperimentalExtension=*/true, + /*ExperimentalExtensionVersionCheck=*/false); + // Ignore any error here, we assume it will handled in another place. + if (llvm::errorToBool(MLConfigParseResult.takeError())) { + // We might get a parsing error if rv32e in the list, we could just skip + // that and process the rest of multi-lib configs. + Skip = true; + continue; + } + auto &MLConfigISAInfo = *MLConfigParseResult; + + const llvm::RISCVISAInfo::OrderedExtensionMap &MLConfigArchExts = + MLConfigISAInfo->getExtensions(); + for (auto MLConfigArchExt : MLConfigArchExts) { + auto ExtName = MLConfigArchExt.first; + NewMultilib.flag(Twine("-", ExtName).str()); + + if (AllArchExts.insert(ExtName).second) { + addMultilibFlag(ISAInfo->hasExtension(ExtName), + Twine("-", ExtName).str(), NewFlags); + } + } + + // Check the XLEN explicitly. + if (MLConfigISAInfo->getXLen() == 32) { + NewMultilib.flag("-m32"); + NewMultilib.flag("-m64", /*Disallow*/ true); + } else { + NewMultilib.flag("-m32", /*Disallow*/ true); + NewMultilib.flag("-m64"); + } + + // Atomic extension must be explicitly checked, soft and hard atomic + // operation never co-work correctly. + if (!MLConfigISAInfo->hasExtension("a")) + NewMultilib.flag("-a", /*Disallow*/ true); + } + + if (Skip) + continue; + + NewMultilibs.emplace_back(NewMultilib); + } + + // Build an internal used only multi-lib list, used for checking any + // compatible multi-lib. + MultilibSet NewRISCVMultilibs = + MultilibSetBuilder().Either(NewMultilibs).makeMultilibSet(); + + if (NewRISCVMultilibs.select(NewFlags, SelectedMultilibs)) + for (const Multilib &NewSelectedM : SelectedMultilibs) + for (const auto &M : RISCVMultilibSet) + // Look up the corresponding multi-lib entry in original multi-lib set. + if (M.gccSuffix() == NewSelectedM.gccSuffix()) + return true; + + return false; +} + static void findRISCVBareMetalMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, @@ -1590,17 +1856,19 @@ static void findRISCVBareMetalMultilibs(const Driver &D, {"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"}, {"rv64imafdc", "lp64d"}}; - std::vector<Multilib> Ms; + std::vector<MultilibBuilder> 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())); + MultilibBuilder( + (Twine(Element.march) + "/" + Twine(Element.mabi)).str()) + .flag(Twine("-march=", Element.march).str()) + .flag(Twine("-mabi=", Element.mabi).str())); } MultilibSet RISCVMultilibs = - MultilibSet() - .Either(ArrayRef<Multilib>(Ms)) + MultilibSetBuilder() + .Either(Ms) + .makeMultilibSet() .FilterOut(NonExistent) .setFilePathsCallback([](const Multilib &M) { return std::vector<std::string>( @@ -1609,22 +1877,22 @@ static void findRISCVBareMetalMultilibs(const Driver &D, "/../../../../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); + 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); + Twine("-mabi=", Element.mabi).str().c_str(), Flags); } } - if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) + if (selectRISCVMultilib(RISCVMultilibs, MArch, Flags, + Result.SelectedMultilibs)) Result.Multilibs = RISCVMultilibs; } @@ -1635,33 +1903,38 @@ static void findRISCVMultilibs(const Driver &D, 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"); + MultilibBuilder Ilp32 = + MultilibBuilder("lib32/ilp32").flag("-m32").flag("-mabi=ilp32"); + MultilibBuilder Ilp32f = + MultilibBuilder("lib32/ilp32f").flag("-m32").flag("-mabi=ilp32f"); + MultilibBuilder Ilp32d = + MultilibBuilder("lib32/ilp32d").flag("-m32").flag("-mabi=ilp32d"); + MultilibBuilder Lp64 = + MultilibBuilder("lib64/lp64").flag("-m64").flag("-mabi=lp64"); + MultilibBuilder Lp64f = + MultilibBuilder("lib64/lp64f").flag("-m64").flag("-mabi=lp64f"); + MultilibBuilder Lp64d = + MultilibBuilder("lib64/lp64d").flag("-m64").flag("-mabi=lp64d"); MultilibSet RISCVMultilibs = - MultilibSet() + MultilibSetBuilder() .Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d}) + .makeMultilibSet() .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); + 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)) + if (RISCVMultilibs.select(Flags, Result.SelectedMultilibs)) Result.Multilibs = RISCVMultilibs; } @@ -1670,7 +1943,7 @@ static bool findBiarchMultilibs(const Driver &D, StringRef Path, const ArgList &Args, bool NeedsBiarchSuffix, DetectedMultilibs &Result) { - Multilib Default; + MultilibBuilder DefaultBuilder; // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit @@ -1681,7 +1954,7 @@ static bool findBiarchMultilibs(const Driver &D, StringRef Suff64 = "/64"; // Solaris uses platform-specific suffixes instead of /64. - if (TargetTriple.getOS() == llvm::Triple::Solaris) { + if (TargetTriple.isOSSolaris()) { switch (TargetTriple.getArch()) { case llvm::Triple::x86: case llvm::Triple::x86_64: @@ -1696,24 +1969,33 @@ static bool findBiarchMultilibs(const Driver &D, } } - Multilib Alt64 = Multilib() + Multilib Alt64 = MultilibBuilder() .gccSuffix(Suff64) .includeSuffix(Suff64) - .flag("-m32") - .flag("+m64") - .flag("-mx32"); - Multilib Alt32 = Multilib() + .flag("-m32", /*Disallow=*/true) + .flag("-m64") + .flag("-mx32", /*Disallow=*/true) + .makeMultilib(); + Multilib Alt32 = MultilibBuilder() .gccSuffix("/32") .includeSuffix("/32") - .flag("+m32") - .flag("-m64") - .flag("-mx32"); - Multilib Altx32 = Multilib() + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mx32", /*Disallow=*/true) + .makeMultilib(); + Multilib Altx32 = MultilibBuilder() .gccSuffix("/x32") .includeSuffix("/x32") - .flag("-m32") - .flag("-m64") - .flag("+mx32"); + .flag("-m32", /*Disallow=*/true) + .flag("-m64", /*Disallow=*/true) + .flag("-mx32") + .makeMultilib(); + Multilib Alt32sparc = MultilibBuilder() + .gccSuffix("/sparcv8plus") + .includeSuffix("/sparcv8plus") + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .makeMultilib(); // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a. FilterNonExistent NonExistent( @@ -1725,10 +2007,14 @@ static bool findBiarchMultilibs(const Driver &D, const bool IsX32 = TargetTriple.isX32(); if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) Want = WANT64; + if (TargetTriple.isArch32Bit() && !NonExistent(Alt32sparc)) + Want = WANT64; else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32)) Want = WANT64; else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64)) Want = WANT32; + else if (TargetTriple.isArch64Bit() && !NonExistent(Alt32sparc)) + Want = WANT64; else { if (TargetTriple.isArch32Bit()) Want = NeedsBiarchSuffix ? WANT64 : WANT32; @@ -1739,31 +2025,42 @@ static bool findBiarchMultilibs(const Driver &D, } if (Want == WANT32) - Default.flag("+m32").flag("-m64").flag("-mx32"); + DefaultBuilder.flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mx32", /*Disallow=*/true); else if (Want == WANT64) - Default.flag("-m32").flag("+m64").flag("-mx32"); + DefaultBuilder.flag("-m32", /*Disallow=*/true) + .flag("-m64") + .flag("-mx32", /*Disallow=*/true); else if (Want == WANTX32) - Default.flag("-m32").flag("-m64").flag("+mx32"); + DefaultBuilder.flag("-m32", /*Disallow=*/true) + .flag("-m64", /*Disallow=*/true) + .flag("-mx32"); else return false; + Multilib Default = DefaultBuilder.makeMultilib(); + Result.Multilibs.push_back(Default); Result.Multilibs.push_back(Alt64); Result.Multilibs.push_back(Alt32); Result.Multilibs.push_back(Altx32); + Result.Multilibs.push_back(Alt32sparc); 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); + addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "-m64", Flags); + addMultilibFlag(TargetTriple.isArch32Bit(), "-m32", Flags); + addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "-mx32", Flags); - if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) + if (!Result.Multilibs.select(Flags, Result.SelectedMultilibs)) return false; - if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 || - Result.SelectedMultilib == Altx32) + if (Result.SelectedMultilibs.back() == Alt64 || + Result.SelectedMultilibs.back() == Alt32 || + Result.SelectedMultilibs.back() == Altx32 || + Result.SelectedMultilibs.back() == Alt32sparc) Result.BiarchSibling = Default; return true; @@ -1779,8 +2076,15 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, StringRef RHSPatchSuffix) const { if (Major != RHSMajor) return Major < RHSMajor; - if (Minor != RHSMinor) + if (Minor != RHSMinor) { + // Note that versions without a specified minor sort higher than those with + // a minor. + if (RHSMinor == -1) + return true; + if (Minor == -1) + return false; return Minor < RHSMinor; + } if (Patch != RHSPatch) { // Note that versions without a specified patch sort higher than those with // a patch. @@ -1816,45 +2120,72 @@ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { std::pair<StringRef, StringRef> First = VersionText.split('.'); std::pair<StringRef, StringRef> 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 MajorStr = First.first; 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(); + StringRef PatchStr = Second.second; + + GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; - // 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) + // Parse version number strings such as: + // 5 // 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)); + // 10-win32 + // Split on '.', handle 1, 2 or 3 such segments. Each segment must contain + // purely a number, except for the last one, where a non-number suffix + // is stored in PatchSuffix. The third segment is allowed to not contain + // a number at all. + + auto TryParseLastNumber = [&](StringRef Segment, int &Number, + std::string &OutStr) -> bool { + // Look for a number prefix and parse that, and split out any trailing + // string into GoodVersion.PatchSuffix. + + if (size_t EndNumber = Segment.find_first_not_of("0123456789")) { + StringRef NumberStr = Segment.slice(0, EndNumber); + if (NumberStr.getAsInteger(10, Number) || Number < 0) + return false; + OutStr = NumberStr; + GoodVersion.PatchSuffix = Segment.substr(EndNumber); + return true; } + return false; + }; + auto TryParseNumber = [](StringRef Segment, int &Number) -> bool { + if (Segment.getAsInteger(10, Number) || Number < 0) + return false; + return true; + }; + + if (MinorStr.empty()) { + // If no minor string, major is the last segment + if (!TryParseLastNumber(MajorStr, GoodVersion.Major, GoodVersion.MajorStr)) + return BadVersion; + return GoodVersion; } + if (!TryParseNumber(MajorStr, GoodVersion.Major)) + return BadVersion; + GoodVersion.MajorStr = MajorStr; + + if (PatchStr.empty()) { + // If no patch string, minor is the last segment + if (!TryParseLastNumber(MinorStr, GoodVersion.Minor, GoodVersion.MinorStr)) + return BadVersion; + return GoodVersion; + } + + if (!TryParseNumber(MinorStr, GoodVersion.Minor)) + return BadVersion; + GoodVersion.MinorStr = MinorStr; + + // For the last segment, tolerate a missing number. + std::string DummyStr; + TryParseLastNumber(PatchStr, GoodVersion.Patch, DummyStr); return GoodVersion; } @@ -1883,8 +2214,7 @@ static llvm::StringRef getGCCToolchainDir(const ArgList &Args, /// 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<std::string> ExtraTripleAliases) { + const llvm::Triple &TargetTriple, const ArgList &Args) { llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); @@ -1893,10 +2223,48 @@ void Generic_GCC::GCCInstallationDetector::init( // The compatible GCC triples for this particular architecture. SmallVector<StringRef, 16> CandidateTripleAliases; SmallVector<StringRef, 16> CandidateBiarchTripleAliases; + // Add some triples that we want to check first. + CandidateTripleAliases.push_back(TargetTriple.str()); + std::string TripleNoVendor = TargetTriple.getArchName().str() + "-" + + TargetTriple.getOSAndEnvironmentName().str(); + if (TargetTriple.getVendor() == llvm::Triple::UnknownVendor) + CandidateTripleAliases.push_back(TripleNoVendor); + CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, CandidateTripleAliases, CandidateBiarchLibDirs, CandidateBiarchTripleAliases); + // If --gcc-install-dir= is specified, skip filesystem detection. + if (const Arg *A = + Args.getLastArg(clang::driver::options::OPT_gcc_install_dir_EQ); + A && A->getValue()[0]) { + StringRef InstallDir = A->getValue(); + if (!ScanGCCForMultilibs(TargetTriple, Args, InstallDir, false)) { + D.Diag(diag::err_drv_invalid_gcc_install_dir) << InstallDir; + } else { + (void)InstallDir.consume_back("/"); + StringRef VersionText = llvm::sys::path::filename(InstallDir); + StringRef TripleText = + llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir)); + + Version = GCCVersion::Parse(VersionText); + GCCTriple.setTriple(TripleText); + GCCInstallPath = std::string(InstallDir); + GCCParentLibPath = GCCInstallPath + "/../../.."; + IsValid = true; + } + return; + } + + // If --gcc-triple is specified use this instead of trying to + // auto-detect a triple. + if (const Arg *A = + Args.getLastArg(clang::driver::options::OPT_gcc_triple_EQ)) { + StringRef GCCTriple = A->getValue(); + CandidateTripleAliases.clear(); + CandidateTripleAliases.push_back(GCCTriple); + } + // Compute the set of prefixes for our search. SmallVector<std::string, 8> Prefixes; StringRef GCCToolchainDir = getGCCToolchainDir(Args, D.SysRoot); @@ -1932,9 +2300,6 @@ void Generic_GCC::GCCInstallationDetector::init( // 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, @@ -1951,19 +2316,12 @@ void Generic_GCC::GCCInstallationDetector::init( if (!VFS.exists(Prefix)) continue; for (StringRef Suffix : CandidateLibDirs) { - const std::string LibDir = Prefix + Suffix.str(); + const std::string LibDir = concat(Prefix, Suffix); if (!VFS.exists(LibDir)) continue; // Maybe filter out <libdir>/gcc and <libdir>/gcc-cross. bool GCCDirExists = VFS.exists(LibDir + "/gcc"); bool GCCCrossDirExists = VFS.exists(LibDir + "/gcc-cross"); - // Try to match the exact target triple first. - ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, TargetTriple.str(), - false, GCCDirExists, GCCCrossDirExists); - // Try rest of possible triples. - for (StringRef Candidate : ExtraTripleAliases) // Try these first. - ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, false, - GCCDirExists, GCCCrossDirExists); for (StringRef Candidate : CandidateTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, false, GCCDirExists, GCCCrossDirExists); @@ -2000,8 +2358,8 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { } bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { - if (BiarchSibling.hasValue()) { - M = BiarchSibling.getValue(); + if (BiarchSibling) { + M = *BiarchSibling; return true; } return false; @@ -2010,14 +2368,21 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( const llvm::Triple &TargetTriple, SmallVectorImpl<std::string> &Prefixes, StringRef SysRoot) { - if (TargetTriple.getOS() == llvm::Triple::Solaris) { + + if (TargetTriple.isOSHaiku()) { + Prefixes.push_back(concat(SysRoot, "/boot/system/develop/tools")); + return; + } + + if (TargetTriple.isOSSolaris()) { // Solaris is a special case. // The GCC installation is under // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/ // so we need to find those /usr/gcc/*/lib/gcc libdirs and go with // /usr/gcc/<version> as a prefix. - std::string PrefixDir = SysRoot.str() + "/usr/gcc"; + SmallVector<std::pair<GCCVersion, std::string>, 8> SolarisPrefixes; + std::string PrefixDir = concat(SysRoot, "/usr/gcc"); std::error_code EC; for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), LE; @@ -2034,15 +2399,27 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( if (!D.getVFS().exists(CandidateLibPath)) continue; - Prefixes.push_back(CandidatePrefix); + SolarisPrefixes.emplace_back( + std::make_pair(CandidateVersion, CandidatePrefix)); } + // Sort in reverse order so GCCInstallationDetector::init picks the latest. + std::sort(SolarisPrefixes.rbegin(), SolarisPrefixes.rend()); + for (auto p : SolarisPrefixes) + Prefixes.emplace_back(p.second); 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/CentOS devtoolsets and gcc-toolsets. + // For Linux, if --sysroot is not specified, look for RHEL/CentOS devtoolsets + // and gcc-toolsets. + if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux && + D.getVFS().exists("/opt/rh")) { + // TODO: We may want to remove this, since the functionality + // can be achieved using config files. + Prefixes.push_back("/opt/rh/gcc-toolset-12/root/usr"); + Prefixes.push_back("/opt/rh/gcc-toolset-11/root/usr"); Prefixes.push_back("/opt/rh/gcc-toolset-10/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-12/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-11/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-10/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-9/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-8/root/usr"); @@ -2052,7 +2429,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); } - Prefixes.push_back(SysRoot.str() + "/usr"); + + // Fall back to /usr which is used by most non-Solaris systems. + Prefixes.push_back(concat(SysRoot, "/usr")); } /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( @@ -2092,6 +2471,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const AVRLibDirs[] = {"/lib"}; static const char *const AVRTriples[] = {"avr"}; + static const char *const CSKYLibDirs[] = {"/lib"}; + static const char *const CSKYTriples[] = { + "csky-linux-gnuabiv2", "csky-linux-uclibcabiv2", "csky-elf-noneabiv2"}; + static const char *const X86_64LibDirs[] = {"/lib64", "/lib"}; static const char *const X86_64Triples[] = { "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", @@ -2107,9 +2490,13 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const X86Triples[] = { "i586-linux-gnu", "i686-linux-gnu", "i686-pc-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", "i386-redhat-linux", - "i586-suse-linux", "i686-montavista-linux", "i686-gnu", + "i586-suse-linux", "i686-montavista-linux", }; + static const char *const LoongArch64LibDirs[] = {"/lib64", "/lib"}; + static const char *const LoongArch64Triples[] = { + "loongarch64-linux-gnu", "loongarch64-unknown-linux-gnu"}; + static const char *const M68kLibDirs[] = {"/lib"}; static const char *const M68kTriples[] = { "m68k-linux-gnu", "m68k-unknown-linux-gnu", "m68k-suse-linux"}; @@ -2189,16 +2576,14 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( using std::begin; using std::end; - if (TargetTriple.getOS() == llvm::Triple::Solaris) { + if (TargetTriple.isOSSolaris()) { static const char *const SolarisLibDirs[] = {"/lib"}; static const char *const SolarisSparcV8Triples[] = { - "sparc-sun-solaris2.11", "sparc-sun-solaris2.12"}; + "sparc-sun-solaris2.11"}; 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"}; + "sparcv9-sun-solaris2.11"}; + static const char *const SolarisX86Triples[] = {"i386-pc-solaris2.11"}; + static const char *const SolarisX86_64Triples[] = {"x86_64-pc-solaris2.11"}; LibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); BiarchLibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); switch (TargetTriple.getArch()) { @@ -2236,9 +2621,6 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( 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"}; @@ -2253,22 +2635,6 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( 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), @@ -2291,6 +2657,23 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( return; } + if (TargetTriple.isOSHurd()) { + switch (TargetTriple.getArch()) { + case llvm::Triple::x86_64: + LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + TripleAliases.push_back("x86_64-gnu"); + break; + case llvm::Triple::x86: + LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + TripleAliases.push_back("i686-gnu"); + break; + default: + break; + } + + return; + } + switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); @@ -2307,7 +2690,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); - if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::EABIHF) { TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); } else { TripleAliases.append(begin(ARMTriples), end(ARMTriples)); @@ -2316,7 +2701,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( case llvm::Triple::armeb: case llvm::Triple::thumbeb: LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); - if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::EABIHF) { TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); } else { TripleAliases.append(begin(ARMebTriples), end(ARMebTriples)); @@ -2326,6 +2713,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( LibDirs.append(begin(AVRLibDirs), end(AVRLibDirs)); TripleAliases.append(begin(AVRTriples), end(AVRTriples)); break; + case llvm::Triple::csky: + LibDirs.append(begin(CSKYLibDirs), end(CSKYLibDirs)); + TripleAliases.append(begin(CSKYTriples), end(CSKYTriples)); + break; case llvm::Triple::x86_64: if (TargetTriple.isX32()) { LibDirs.append(begin(X32LibDirs), end(X32LibDirs)); @@ -2353,6 +2744,11 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( BiarchTripleAliases.append(begin(X32Triples), end(X32Triples)); } break; + // TODO: Handle loongarch32. + case llvm::Triple::loongarch64: + LibDirs.append(begin(LoongArch64LibDirs), end(LoongArch64LibDirs)); + TripleAliases.append(begin(LoongArch64Triples), end(LoongArch64Triples)); + break; case llvm::Triple::m68k: LibDirs.append(begin(M68kLibDirs), end(M68kLibDirs)); TripleAliases.append(begin(M68kTriples), end(M68kTriples)); @@ -2454,10 +2850,6 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( 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()); @@ -2475,6 +2867,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { // It should also work without multilibs in a simplified toolchain. findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); + } else if (TargetTriple.isCSKY()) { + findCSKYMultilibs(D, TargetTriple, Path, Args, Detected); } else if (TargetTriple.isMIPS()) { if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) return false; @@ -2490,7 +2884,9 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( } Multilibs = Detected.Multilibs; - SelectedMultilib = Detected.SelectedMultilib; + SelectedMultilib = Detected.SelectedMultilibs.empty() + ? Multilib() + : Detected.SelectedMultilibs.back(); BiarchSibling = Detected.BiarchSibling; return true; @@ -2565,7 +2961,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( const llvm::Triple &TargetTriple, const ArgList &Args, const SmallVectorImpl<StringRef> &CandidateTriples, const SmallVectorImpl<StringRef> &CandidateBiarchTriples) { - if (!D.getVFS().exists(D.SysRoot + GentooConfigDir)) + if (!D.getVFS().exists(concat(D.SysRoot, GentooConfigDir))) return false; for (StringRef CandidateTriple : CandidateTriples) { @@ -2584,8 +2980,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( const llvm::Triple &TargetTriple, const ArgList &Args, StringRef CandidateTriple, bool NeedsBiarchSuffix) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = - D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/config-" + - CandidateTriple.str()); + D.getVFS().getBufferForFile(concat(D.SysRoot, GentooConfigDir, + "/config-" + CandidateTriple.str())); if (File) { SmallVector<StringRef, 2> Lines; File.get()->getBuffer().split(Lines, "\n"); @@ -2596,8 +2992,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( continue; // Process the config file pointed to by CURRENT. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ConfigFile = - D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/" + - Line.str()); + D.getVFS().getBufferForFile( + concat(D.SysRoot, GentooConfigDir, "/" + Line)); std::pair<StringRef, StringRef> ActiveVersion = Line.rsplit('-'); // List of paths to scan for libraries. SmallVector<StringRef, 4> GentooScanPaths; @@ -2630,7 +3026,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( // Scan all paths for GCC libraries. for (const auto &GentooScanPath : GentooScanPaths) { - std::string GentooPath = D.SysRoot + std::string(GentooScanPath); + std::string GentooPath = concat(D.SysRoot, GentooScanPath); if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, NeedsBiarchSuffix)) @@ -2685,22 +3081,26 @@ 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); + CudaInstallation->print(OS); + RocmInstallation->print(OS); } -bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel +Generic_GCC::getDefaultUnwindTableLevel(const ArgList &Args) const { switch (getArch()) { case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: case llvm::Triple::ppc: case llvm::Triple::ppcle: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: case llvm::Triple::x86: case llvm::Triple::x86_64: - return true; + return UnwindTableLevel::Asynchronous; default: - return false; + return UnwindTableLevel::None; } } @@ -2726,40 +3126,12 @@ bool Generic_GCC::isPICDefaultForced() const { 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::ppcle: - 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: - case llvm::Triple::m68k: - return true; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - if (getTriple().isOSFreeBSD() || getTriple().isOSOpenBSD() || - getTriple().isOSSolaris()) - return true; + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + case llvm::Triple::xcore: return false; default: - return false; + return true; } } @@ -2785,6 +3157,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, path_list &Paths) { // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { + assert(!SelectedMultilibs.empty()); const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = std::string(GCCInstallation.getParentLibPath()); @@ -2792,13 +3165,19 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, // Sourcery CodeBench MIPS toolchain holds some libraries under // a biarch-like suffix of the GCC installation. if (const auto &PathsCallback = Multilibs.filePathsCallback()) - for (const auto &Path : PathsCallback(SelectedMultilib)) + for (const auto &Path : PathsCallback(SelectedMultilibs.back())) addPathIfExists(D, GCCInstallation.getInstallPath() + Path, Paths); // Add lib/gcc/$triple/$version, with an optional /multilib suffix. - addPathIfExists( - D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(), - Paths); + addPathIfExists(D, + GCCInstallation.getInstallPath() + + SelectedMultilibs.back().gccSuffix(), + Paths); + + // Add lib/gcc/$triple/$libdir + // For GCC built with --enable-version-specific-runtime-libs. + addPathIfExists(D, GCCInstallation.getInstallPath() + "/../" + OSLibDir, + Paths); // GCC cross compiling toolchains will install target libraries which ship // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as @@ -2820,7 +3199,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, // Clang diverges from GCC's behavior. addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + - SelectedMultilib.osSuffix(), + SelectedMultilibs.back().osSuffix(), Paths); // If the GCC installation we found is inside of the sysroot, we want to @@ -2832,7 +3211,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, // 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)) + if (StringRef(LibPath).starts_with(SysRoot)) addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); } } @@ -2893,34 +3272,53 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { const Driver &D = getDriver(); std::string SysRoot = computeSysRoot(); - std::string Target = getTripleString(); + if (SysRoot.empty()) + SysRoot = llvm::sys::path::get_separator(); - auto AddIncludePath = [&](std::string Path) { + auto AddIncludePath = [&](StringRef Path, bool TargetDirRequired = false) { std::string Version = detectLibcxxVersion(Path); if (Version.empty()) return false; // First add the per-target include path if it exists. - std::string TargetDir = Path + "/" + Target + "/c++/" + Version; - if (D.getVFS().exists(TargetDir)) - addSystemInclude(DriverArgs, CC1Args, TargetDir); + bool TargetDirExists = false; + std::optional<std::string> TargetIncludeDir = getTargetSubDirPath(Path); + if (TargetIncludeDir) { + SmallString<128> TargetDir(*TargetIncludeDir); + llvm::sys::path::append(TargetDir, "c++", Version); + if (D.getVFS().exists(TargetDir)) { + addSystemInclude(DriverArgs, CC1Args, TargetDir); + TargetDirExists = true; + } + } + if (TargetDirRequired && !TargetDirExists) + return false; // Second add the generic one. - addSystemInclude(DriverArgs, CC1Args, Path + "/c++/" + Version); + SmallString<128> GenericDir(Path); + llvm::sys::path::append(GenericDir, "c++", Version); + addSystemInclude(DriverArgs, CC1Args, GenericDir); 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")) - return; + // Android only uses the libc++ headers installed alongside the toolchain if + // they contain an Android-specific target include path, otherwise they're + // incompatible with the NDK libraries. + SmallString<128> DriverIncludeDir(getDriver().Dir); + llvm::sys::path::append(DriverIncludeDir, "..", "include"); + if (AddIncludePath(DriverIncludeDir, + /*TargetDirRequired=*/getTriple().isAndroid())) + 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: - if (AddIncludePath(SysRoot + "/usr/local/include")) + SmallString<128> UsrLocalIncludeDir(SysRoot); + llvm::sys::path::append(UsrLocalIncludeDir, "usr", "local", "include"); + if (AddIncludePath(UsrLocalIncludeDir)) return; - if (AddIncludePath(SysRoot + "/usr/include")) + SmallString<128> UsrIncludeDir(SysRoot); + llvm::sys::path::append(UsrIncludeDir, "usr", "include"); + if (AddIncludePath(UsrIncludeDir)) return; } @@ -2978,6 +3376,15 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths( TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args)) return true; + // Try /gcc/$triple/$version/include/c++/ (gcc --print-multiarch is not + // empty). Like above but for GCC built with + // --enable-version-specific-runtime-libs. + if (addLibStdCXXIncludePaths(LibDir.str() + "/gcc/" + TripleStr + "/" + + Version.Text + "/include/c++/", + TripleStr, Multilib.includeSuffix(), DriverArgs, + CC1Args)) + return true; + // Detect Debian g++-multiarch-incdir.diff. if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text, DebianMultiarch, Multilib.includeSuffix(), diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h index 4eb7ab0215ab..0b664a182d75 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H #include "Cuda.h" +#include "LazyDetector.h" #include "ROCm.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" @@ -22,12 +23,12 @@ struct DetectedMultilibs { /// The set of multilibs that the detected installation supports. MultilibSet Multilibs; - /// The primary multilib appropriate for the given flags. - Multilib SelectedMultilib; + /// The multilibs appropriate for the given flags. + llvm::SmallVector<Multilib> SelectedMultilibs; /// On Biarch systems, this corresponds to the default multilib when /// targeting the non-default multilib. Otherwise, it is empty. - llvm::Optional<Multilib> BiarchSibling; + std::optional<Multilib> BiarchSibling; }; bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, @@ -201,7 +202,7 @@ public: Multilib SelectedMultilib; /// On Biarch systems, this corresponds to the default multilib when /// targeting the non-default multilib. Otherwise, it is empty. - llvm::Optional<Multilib> BiarchSibling; + std::optional<Multilib> BiarchSibling; GCCVersion Version; @@ -217,8 +218,7 @@ public: public: explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} - void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, - ArrayRef<std::string> ExtraTripleAliases = None); + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); /// Check whether we detected a valid GCC install. bool isValid() const { return IsValid; } @@ -286,8 +286,8 @@ public: protected: GCCInstallationDetector GCCInstallation; - CudaInstallationDetector CudaInstallation; - RocmInstallationDetector RocmInstallation; + LazyDetector<CudaInstallationDetector> CudaInstallation; + LazyDetector<RocmInstallationDetector> RocmInstallation; public: Generic_GCC(const Driver &D, const llvm::Triple &Triple, @@ -296,7 +296,8 @@ public: void printVerboseInfo(raw_ostream &OS) const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp index 6d553791b394..ccb36a6c846c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp @@ -21,7 +21,7 @@ #include "llvm/Support/Alignment.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/TargetParser/TargetParser.h" using namespace clang::driver; using namespace clang::driver::toolchains; @@ -47,7 +47,7 @@ static bool shouldSkipSanitizeOption(const ToolChain &TC, return false; if (!DriverArgs.hasFlag(options::OPT_fgpu_sanitize, - -options::OPT_fno_gpu_sanitize)) + options::OPT_fno_gpu_sanitize, true)) return true; auto &Diags = TC.getDriver().getDiags(); @@ -72,14 +72,49 @@ static bool shouldSkipSanitizeOption(const ToolChain &TC, return false; } +void AMDGCN::Linker::constructLlvmLinkCommand(Compilation &C, + const JobAction &JA, + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args) const { + // Construct llvm-link command. + // The output from llvm-link is a bitcode file. + ArgStringList LlvmLinkArgs; + + assert(!Inputs.empty() && "Must have at least one input."); + + LlvmLinkArgs.append({"-o", Output.getFilename()}); + for (auto Input : Inputs) + LlvmLinkArgs.push_back(Input.getFilename()); + + // Look for archive of bundled bitcode in arguments, and add temporary files + // for the extracted archive of bitcode to inputs. + auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ); + AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LlvmLinkArgs, "amdgcn", + TargetID, /*IsBitCodeSDL=*/true); + + const char *LlvmLink = + Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + LlvmLink, LlvmLinkArgs, Inputs, + Output)); +} + 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", + ArgStringList LldArgs{"-flavor", + "gnu", + "-m", + "elf64_amdgpu", + "--no-undefined", + "-shared", "-plugin-opt=-amdgpu-internalize-symbols"}; + if (Args.hasArg(options::OPT_hipstdpar)) + LldArgs.push_back("-plugin-opt=-amdgpu-enable-hipstdpar"); auto &TC = getToolChain(); auto &D = TC.getDriver(); @@ -107,27 +142,55 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, if (IsThinLTO) LldArgs.push_back(Args.MakeArgString("-plugin-opt=-force-import-all")); - 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); + // Given that host and device linking happen in separate processes, the device + // linker doesn't always have the visibility as to which device symbols are + // needed by a program, especially for the device symbol dependencies that are + // introduced through the host symbol resolution. + // For example: host_A() (A.obj) --> host_B(B.obj) --> device_kernel_B() + // (B.obj) In this case, the device linker doesn't know that A.obj actually + // depends on the kernel functions in B.obj. When linking to static device + // library, the device linker may drop some of the device global symbols if + // they aren't referenced. As a workaround, we are adding to the + // --whole-archive flag such that all global symbols would be linked in. + LldArgs.push_back("--whole-archive"); + + for (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) { + StringRef ArgVal = Arg->getValue(1); + auto SplitArg = ArgVal.split("-mllvm="); + if (!SplitArg.second.empty()) { + LldArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=") + SplitArg.second)); + } else { + LldArgs.push_back(Args.MakeArgString(ArgVal)); + } + Arg->claim(); + } + LldArgs.append({"-o", Output.getFilename()}); for (auto Input : Inputs) LldArgs.push_back(Input.getFilename()); + // Look for archive of bundled bitcode in arguments, and add temporary files + // for the extracted archive of bitcode to inputs. + auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ); + AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LldArgs, "amdgcn", + TargetID, /*IsBitCodeSDL=*/true); + + LldArgs.push_back("--no-whole-archive"); + const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), Lld, LldArgs, Inputs, Output)); } // 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. +// either an object file or bitcode (-emit-llvm). It calls llvm-link, opt, +// llc, then lld steps. void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -143,6 +206,9 @@ void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, Args, *this); + if (JA.getType() == types::TY_LLVM_BC) + return constructLlvmLinkCommand(C, JA, Inputs, Output, Args); + return constructLldCommand(C, JA, Inputs, Output, Args); } @@ -154,7 +220,10 @@ HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple, getProgramPaths().push_back(getDriver().Dir); // Diagnose unsupported sanitizer options only once. - for (auto A : Args.filtered(options::OPT_fsanitize_EQ)) { + if (!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize, + true)) + return; + for (auto *A : Args.filtered(options::OPT_fsanitize_EQ)) { SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false); if (K != SanitizerKind::Address) D.getDiags().Report(clang::diag::warn_drv_unsupported_option_for_target) @@ -172,19 +241,17 @@ void HIPAMDToolChain::addClangTargetOptions( 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.append({"-mllvm", "-amdgpu-internalize-symbols"}); + if (DriverArgs.hasArgNoClaim(options::OPT_hipstdpar)) + CC1Args.append({"-mllvm", "-amdgpu-enable-hipstdpar"}); 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(); + (Twine("--gpu-max-threads-per-block=") + MaxThreadsPerBlock).str(); CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr)); } @@ -194,15 +261,15 @@ void HIPAMDToolChain::addClangTargetOptions( // supported for the foreseeable future. if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, options::OPT_fvisibility_ms_compat)) { - CC1Args.append({"-fvisibility", "hidden"}); + CC1Args.append({"-fvisibility=hidden"}); CC1Args.push_back("-fapply-global-visibility-to-externs"); } - llvm::for_each(getHIPDeviceLibs(DriverArgs), [&](auto BCFile) { + for (auto BCFile : getDeviceLibs(DriverArgs)) { CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" : "-mlink-bitcode-file"); CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path)); - }); + } } llvm::opt::DerivedArgList * @@ -217,8 +284,7 @@ HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, const OptTable &Opts = getDriver().getOpts(); for (Arg *A : Args) { - if (!shouldSkipArgument(A) && - !shouldSkipSanitizeOption(*this, Args, BoundArch, A)) + if (!shouldSkipSanitizeOption(*this, Args, BoundArch, A)) DAL->append(A); } @@ -262,7 +328,7 @@ void HIPAMDToolChain::AddIAMCUIncludeArgs(const ArgList &Args, void HIPAMDToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } SanitizerMask HIPAMDToolChain::getSupportedSanitizers() const { @@ -284,14 +350,14 @@ VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D, } llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> -HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { +HIPAMDToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs; if (DriverArgs.hasArg(options::OPT_nogpulib)) return {}; ArgStringList LibraryPaths; // Find in --hip-device-lib-path and HIP_LIBRARY_PATH. - for (auto Path : RocmInstallation.getRocmDeviceLibPathArg()) + for (StringRef Path : RocmInstallation->getRocmDeviceLibPathArg()) LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH"); @@ -301,7 +367,7 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { if (!BCLibArgs.empty()) { llvm::for_each(BCLibArgs, [&](StringRef BCName) { StringRef FullName; - for (std::string LibraryPath : LibraryPaths) { + for (StringRef LibraryPath : LibraryPaths) { SmallString<128> Path(LibraryPath); llvm::sys::path::append(Path, BCName); FullName = Path; @@ -313,7 +379,7 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { getDriver().Diag(diag::err_drv_no_such_file) << BCName; }); } else { - if (!RocmInstallation.hasDeviceLibrary()) { + if (!RocmInstallation->hasDeviceLibrary()) { getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; return {}; } @@ -322,9 +388,9 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { // If --hip-device-lib is not set, add the default bitcode libraries. if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize, - options::OPT_fno_gpu_sanitize) && + options::OPT_fno_gpu_sanitize, true) && getSanitizerArgs(DriverArgs).needsAsanRt()) { - auto AsanRTL = RocmInstallation.getAsanRTLPath(); + auto AsanRTL = RocmInstallation->getAsanRTLPath(); if (AsanRTL.empty()) { unsigned DiagID = getDriver().getDiags().getCustomDiagID( DiagnosticsEngine::Error, @@ -334,15 +400,15 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { getDriver().Diag(DiagID); return {}; } else - BCLibs.push_back({AsanRTL.str(), /*ShouldInternalize=*/false}); + BCLibs.emplace_back(AsanRTL, /*ShouldInternalize=*/false); } // Add the HIP specific bitcode library. - BCLibs.push_back(RocmInstallation.getHIPPath()); + BCLibs.push_back(RocmInstallation->getHIPPath()); // Add common device libraries like ocml etc. - for (auto N : getCommonDeviceLibNames(DriverArgs, GpuArch.str())) - BCLibs.push_back(StringRef(N)); + for (StringRef N : getCommonDeviceLibNames(DriverArgs, GpuArch.str())) + BCLibs.emplace_back(N); // Add instrument lib. auto InstLib = @@ -363,6 +429,6 @@ void HIPAMDToolChain::checkTargetID( auto PTID = getParsedTargetID(DriverArgs); if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) { getDriver().Diag(clang::diag::err_drv_bad_target_id) - << PTID.OptionalTargetID.getValue(); + << *PTID.OptionalTargetID; } } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h index cc472a595db9..d81a9733014c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h @@ -21,7 +21,7 @@ namespace tools { namespace AMDGCN { // Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with // device library, then compiles it to ISA in a shared object. -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("AMDGCN::Linker", "amdgcn-link", TC) {} @@ -36,6 +36,10 @@ private: void constructLldCommand(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const InputInfo &Output, const llvm::opt::ArgList &Args) const; + void constructLlvmLinkCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args) const; }; } // end namespace AMDGCN @@ -72,7 +76,7 @@ public: void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; llvm::SmallVector<BitCodeLibraryInfo, 12> - getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override; + getDeviceLibs(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp index d68c87e9b3e7..a144b28057f4 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp @@ -143,18 +143,14 @@ void HIPSPVToolChain::addClangTargetOptions( // TODO: Allow autovectorization when SPIR-V backend arrives. "-mllvm", "-vectorize-loops=false", "-mllvm", "-vectorize-slp=false"}); - if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, - options::OPT_fno_cuda_approx_transcendentals, false)) - CC1Args.push_back("-fcuda-approx-transcendentals"); - // 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", "-fapply-global-visibility-to-externs"}); + {"-fvisibility=hidden", "-fapply-global-visibility-to-externs"}); - llvm::for_each(getHIPDeviceLibs(DriverArgs), + llvm::for_each(getDeviceLibs(DriverArgs), [&](const BitCodeLibraryInfo &BCFile) { CC1Args.append({"-mlink-builtin-bitcode", DriverArgs.MakeArgString(BCFile.Path)}); @@ -206,7 +202,7 @@ void HIPSPVToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, } llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> -HIPSPVToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { +HIPSPVToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> BCLibs; if (DriverArgs.hasArg(options::OPT_nogpulib)) return {}; @@ -283,10 +279,10 @@ VersionTuple HIPSPVToolChain::computeMSVCVersion(const Driver *D, } void HIPSPVToolChain::adjustDebugInfoKind( - codegenoptions::DebugInfoKind &DebugInfoKind, + llvm::codegenoptions::DebugInfoKind &DebugInfoKind, const llvm::opt::ArgList &Args) const { // Debug info generation is disabled for SPIRV-LLVM-Translator // which currently aborts on the presence of DW_OP_LLVM_convert. // TODO: Enable debug info when the SPIR-V backend arrives. - DebugInfoKind = codegenoptions::NoDebugInfo; + DebugInfoKind = llvm::codegenoptions::NoDebugInfo; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h index 79520f77c742..ecd82e7052e4 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h @@ -20,7 +20,7 @@ namespace HIPSPV { // Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with // device library, then compiles it to SPIR-V in a shared object. -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("HIPSPV::Linker", "hipspv-link", TC) {} @@ -69,7 +69,7 @@ public: void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; llvm::SmallVector<BitCodeLibraryInfo, 12> - getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override; + getDeviceLibs(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; @@ -77,9 +77,8 @@ public: computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override; - void adjustDebugInfoKind(codegenoptions::DebugInfoKind &DebugInfoKind, + void adjustDebugInfoKind(llvm::codegenoptions::DebugInfoKind &DebugInfoKind, const llvm::opt::ArgList &Args) const override; - bool IsIntegratedAssemblerDefault() const override { return true; } bool IsMathErrnoDefault() const override { return false; } bool useIntegratedAs() const override { return true; } bool isCrossCompiling() const override { return true; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp index 1b04a20bacbf..f692458b775d 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp @@ -10,8 +10,8 @@ #include "CommonArgs.h" #include "clang/Driver/Compilation.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/Support/Path.h" +#include "llvm/TargetParser/Triple.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -53,8 +53,6 @@ void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, // 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; - // AMDGCN: // For code object version 2 and 3, the offload kind in bundle ID is 'hip' // for backward compatibility. For code object version 4 and greater, the @@ -70,16 +68,28 @@ void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, "," + OffloadKind + "-" + normalizeForBundler(TT, !ArchStr.empty()); if (!ArchStr.empty()) BundlerTargetArg += "-" + ArchStr.str(); - BundlerInputArg = BundlerInputArg + "," + II.getFilename(); } BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg)); + + // Use a NULL file as input for the dummy host binary entry + std::string BundlerInputArg = "-input=" NULL_FILE; BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg)); + for (const auto &II : Inputs) { + BundlerInputArg = std::string("-input=") + II.getFilename(); + BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg)); + } std::string Output = std::string(OutputFileName); auto *BundlerOutputArg = - Args.MakeArgString(std::string("-outputs=").append(Output)); + Args.MakeArgString(std::string("-output=").append(Output)); BundlerArgs.push_back(BundlerOutputArg); + if (Args.hasFlag(options::OPT_offload_compress, + options::OPT_no_offload_compress, false)) + BundlerArgs.push_back("-compress"); + if (Args.hasArg(options::OPT_v)) + BundlerArgs.push_back("-verbose"); + const char *Bundler = Args.MakeArgString( T.getToolChain().GetProgramPath("clang-offload-bundler")); C.addCommand(std::make_unique<Command>( @@ -140,6 +150,8 @@ void HIP::constructGenerateObjFileFromHIPFatBinary( ObjStream << " .incbin "; llvm::sys::printArg(ObjStream, BundleFile, /*Quote=*/true); ObjStream << "\n"; + if (HostTriple.isOSLinux() && HostTriple.isOSBinFormatELF()) + ObjStream << " .section .note.GNU-stack, \"\", @progbits\n"; ObjStream.flush(); // Dump the contents of the temp object file gen if the user requested that. diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp new file mode 100644 index 000000000000..c6ad862b2294 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp @@ -0,0 +1,259 @@ +//===--- HLSL.cpp - HLSL 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 "HLSL.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Job.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TargetParser/Triple.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; +using namespace llvm; + +namespace { + +const unsigned OfflineLibMinor = 0xF; + +bool isLegalShaderModel(Triple &T) { + if (T.getOS() != Triple::OSType::ShaderModel) + return false; + + auto Version = T.getOSVersion(); + if (Version.getBuild()) + return false; + if (Version.getSubminor()) + return false; + + auto Kind = T.getEnvironment(); + + switch (Kind) { + default: + return false; + case Triple::EnvironmentType::Vertex: + case Triple::EnvironmentType::Hull: + case Triple::EnvironmentType::Domain: + case Triple::EnvironmentType::Geometry: + case Triple::EnvironmentType::Pixel: + case Triple::EnvironmentType::Compute: { + VersionTuple MinVer(4, 0); + return MinVer <= Version; + } break; + case Triple::EnvironmentType::Library: { + VersionTuple SM6x(6, OfflineLibMinor); + if (Version == SM6x) + return true; + + VersionTuple MinVer(6, 3); + return MinVer <= Version; + } break; + case Triple::EnvironmentType::Amplification: + case Triple::EnvironmentType::Mesh: { + VersionTuple MinVer(6, 5); + return MinVer <= Version; + } break; + } + return false; +} + +std::optional<std::string> tryParseProfile(StringRef Profile) { + // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor] + SmallVector<StringRef, 3> Parts; + Profile.split(Parts, "_"); + if (Parts.size() != 3) + return std::nullopt; + + Triple::EnvironmentType Kind = + StringSwitch<Triple::EnvironmentType>(Parts[0]) + .Case("ps", Triple::EnvironmentType::Pixel) + .Case("vs", Triple::EnvironmentType::Vertex) + .Case("gs", Triple::EnvironmentType::Geometry) + .Case("hs", Triple::EnvironmentType::Hull) + .Case("ds", Triple::EnvironmentType::Domain) + .Case("cs", Triple::EnvironmentType::Compute) + .Case("lib", Triple::EnvironmentType::Library) + .Case("ms", Triple::EnvironmentType::Mesh) + .Case("as", Triple::EnvironmentType::Amplification) + .Default(Triple::EnvironmentType::UnknownEnvironment); + if (Kind == Triple::EnvironmentType::UnknownEnvironment) + return std::nullopt; + + unsigned long long Major = 0; + if (llvm::getAsUnsignedInteger(Parts[1], 0, Major)) + return std::nullopt; + + unsigned long long Minor = 0; + if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library) + Minor = OfflineLibMinor; + else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor)) + return std::nullopt; + + // dxil-unknown-shadermodel-hull + llvm::Triple T; + T.setArch(Triple::ArchType::dxil); + T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() + + VersionTuple(Major, Minor).getAsString()); + T.setEnvironment(Kind); + if (isLegalShaderModel(T)) + return T.getTriple(); + else + return std::nullopt; +} + +bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) { + VersionTuple Version; + if (Version.tryParse(ValVersionStr) || Version.getBuild() || + Version.getSubminor() || !Version.getMinor()) { + D.Diag(diag::err_drv_invalid_format_dxil_validator_version) + << ValVersionStr; + return false; + } + + uint64_t Major = Version.getMajor(); + uint64_t Minor = *Version.getMinor(); + if (Major == 0 && Minor != 0) { + D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr; + return false; + } + VersionTuple MinVer(1, 0); + if (Version < MinVer) { + D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr; + return false; + } + return true; +} + +} // namespace + +void tools::hlsl::Validator::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + std::string DxvPath = getToolChain().GetProgramPath("dxv"); + assert(DxvPath != "dxv" && "cannot find dxv"); + + ArgStringList CmdArgs; + assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Unexpected verify input"); + // Grabbing the output of the earlier cc1 run. + CmdArgs.push_back(Input.getFilename()); + // Use the same name as output. + CmdArgs.push_back("-o"); + CmdArgs.push_back(Input.getFilename()); + + const char *Exec = Args.MakeArgString(DxvPath); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs, Input)); +} + +/// DirectX Toolchain +HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { + if (Args.hasArg(options::OPT_dxc_validator_path_EQ)) + getProgramPaths().push_back( + Args.getLastArgValue(options::OPT_dxc_validator_path_EQ).str()); +} + +Tool *clang::driver::toolchains::HLSLToolChain::getTool( + Action::ActionClass AC) const { + switch (AC) { + case Action::BinaryAnalyzeJobClass: + if (!Validator) + Validator.reset(new tools::hlsl::Validator(*this)); + return Validator.get(); + default: + return ToolChain::getTool(AC); + } +} + +std::optional<std::string> +clang::driver::toolchains::HLSLToolChain::parseTargetProfile( + StringRef TargetProfile) { + return tryParseProfile(TargetProfile); +} + +DerivedArgList * +HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + + const OptTable &Opts = getDriver().getOpts(); + + for (Arg *A : Args) { + if (A->getOption().getID() == options::OPT_dxil_validator_version) { + StringRef ValVerStr = A->getValue(); + std::string ErrorMsg; + if (!isLegalValidatorVersion(ValVerStr, getDriver())) + continue; + } + if (A->getOption().getID() == options::OPT_dxc_entrypoint) { + DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint), + A->getValue()); + A->claim(); + continue; + } + if (A->getOption().getID() == options::OPT__SLASH_O) { + StringRef OStr = A->getValue(); + if (OStr == "d") { + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0)); + A->claim(); + continue; + } else { + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr); + A->claim(); + continue; + } + } + if (A->getOption().getID() == options::OPT_emit_pristine_llvm) { + // Translate fcgl into -S -emit-llvm and -disable-llvm-passes. + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S)); + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm)); + DAL->AddFlagArg(nullptr, + Opts.getOption(options::OPT_disable_llvm_passes)); + A->claim(); + continue; + } + DAL->append(A); + } + + // Add default validator version if not set. + // TODO: remove this once read validator version from validator. + if (!DAL->hasArg(options::OPT_dxil_validator_version)) { + const StringRef DefaultValidatorVer = "1.7"; + DAL->AddSeparateArg(nullptr, + Opts.getOption(options::OPT_dxil_validator_version), + DefaultValidatorVer); + } + if (!DAL->hasArg(options::OPT_O_Group)) { + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3"); + } + // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and + // shader model 6.2. + // See: https://github.com/llvm/llvm-project/issues/57876 + return DAL; +} + +bool HLSLToolChain::requiresValidation(DerivedArgList &Args) const { + if (Args.getLastArg(options::OPT_dxc_disable_validation)) + return false; + + std::string DxvPath = GetProgramPath("dxv"); + if (DxvPath != "dxv") + return true; + + getDriver().Diag(diag::warn_drv_dxc_missing_dxv); + return false; +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h new file mode 100644 index 000000000000..7b775b897431 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h @@ -0,0 +1,63 @@ +//===--- HLSL.h - HLSL 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { + +namespace tools { + +namespace hlsl { +class LLVM_LIBRARY_VISIBILITY Validator : public Tool { +public: + Validator(const ToolChain &TC) : Tool("hlsl::Validator", "dxv", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // namespace hlsl +} // namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY HLSLToolChain : public ToolChain { +public: + HLSLToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + Tool *getTool(Action::ActionClass AC) const override; + + bool isPICDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } + bool isPICDefaultForced() const override { return false; } + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + static std::optional<std::string> parseTargetProfile(StringRef TargetProfile); + bool requiresValidation(llvm::opt::DerivedArgList &Args) const; + +private: + mutable std::unique_ptr<tools::hlsl::Validator> Validator; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp index a79f0f7622ad..e0d94035823f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp @@ -8,27 +8,272 @@ #include "Haiku.h" #include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "llvm/Support/Path.h" using namespace clang::driver; +using namespace clang::driver::tools; using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; +void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const auto &ToolChain = static_cast<const Haiku &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool Static = Args.hasArg(options::OPT_static); + const bool Shared = Args.hasArg(options::OPT_shared); + 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); + + // Silence warning for "clang -pie foo.o -o foo" + Args.ClaimAllArgs(options::OPT_pie); + + // -rdynamic is a no-op with Haiku. Claim argument to avoid warning. + Args.ClaimAllArgs(options::OPT_rdynamic); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + CmdArgs.push_back("--eh-frame-hdr"); + if (Static) { + CmdArgs.push_back("-Bstatic"); + } else { + if (Shared) + CmdArgs.push_back("-shared"); + CmdArgs.push_back("--enable-new-dtags"); + } + + CmdArgs.push_back("-shared"); + + if (!Shared) + CmdArgs.push_back("--no-undefined"); + + if (Arch == llvm::Triple::riscv64) + CmdArgs.push_back("-X"); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o"))); + if (!Shared) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("start_dyn.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("init_term_dyn.o"))); + } + + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_s, options::OPT_t, options::OPT_r}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, + D.getLTOMode() == LTOK_Thin); + } + + addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { + // Use the static OpenMP runtime with -static-openmp + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + + if (D.CCCIsCXX() && ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + } + + CmdArgs.push_back("-lgcc"); + + CmdArgs.push_back("--push-state"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("--pop-state"); + + CmdArgs.push_back("-lroot"); + + CmdArgs.push_back("-lgcc"); + + CmdArgs.push_back("--push-state"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("--pop-state"); + } + + // No need to do anything for pthreads. Claim argument to avoid warning. + Args.claimAllArgs(options::OPT_pthread, options::OPT_pthreads); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.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<Command>(JA, *this, + ResponseFileSupport::AtFileCurCP(), + Exec, CmdArgs, Inputs, Output)); +} + /// Haiku - Haiku tool chain which can call as(1) and ld(1) directly. Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { + GCCInstallation.init(Triple, Args); + + getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/lib")); + getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/develop/lib")); + + if (GCCInstallation.isValid()) + getFilePaths().push_back(GCCInstallation.getInstallPath().str()); +} + +void Haiku::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Add dirs specified via 'configure --with-c-include-dirs'. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (!CIncludeDirs.empty()) { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/non-packaged/develop/headers")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/app")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/device")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/drivers")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/game")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/interface")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/kernel")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/locale")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/mail")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/media")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/midi")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/midi2")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/net")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/opengl")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/storage")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/support")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/translation")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/graphics")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/input_server")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/mail_daemon")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/registrar")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/screen_saver")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/tracker")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/be_apps/Deskbar")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/be_apps/NetPositive")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/be_apps/Tracker")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/3rdparty")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/bsd")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/glibc")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/gnu")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/posix")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers")); } void Haiku::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/system/develop/headers/c++/v1"); + concat(getDriver().SysRoot, "/boot/system/develop/headers/c++/v1")); } -void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot + "/system/develop/headers/c++", - getTriple().str(), "", DriverArgs, CC1Args); -} +Tool *Haiku::buildLinker() const { return new tools::haiku::Linker(*this); } + +bool Haiku::HasNativeLLVMSupport() const { return true; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h index 669379a21605..a34f76e22284 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h @@ -15,6 +15,25 @@ namespace clang { namespace driver { +namespace tools { + +/// Directly call GNU Binutils assembler and linker +namespace haiku { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("haiku::Linker", "linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace haiku +} // end namespace tools + namespace toolchains { class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF { @@ -22,16 +41,27 @@ public: Haiku(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - bool isPIEDefault(const llvm::opt::ArgList &Args) const override { - return getTriple().getArch() == llvm::Triple::x86_64; - } + bool HasNativeLLVMSupport() const override; - void addLibCxxIncludePaths( + bool IsMathErrnoDefault() const override { return false; } + bool IsObjCNonFragileABIDefault() const override { return true; } + bool isPICDefault() const override { return true; } + + const char *getDefaultLinker() const override { return "ld.lld"; } + + void AddClangSystemIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void addLibStdCxxIncludePaths( + void addLibCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + + unsigned GetDefaultDwarfVersion() const override { return 4; } + + bool GetDefaultStandaloneDebug() const override { return true; } + +protected: + Tool *buildLinker() const override; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp index e772122f5ff5..d1eed931be5f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -40,7 +40,7 @@ static void handleHVXWarnings(const Driver &D, const ArgList &Args) { StringRef Val = A->getValue(); if (!Val.equals_insensitive("64b") && !Val.equals_insensitive("128b")) D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } } @@ -54,11 +54,11 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, auto makeFeature = [&Args](Twine T, bool Enable) -> StringRef { const std::string &S = T.str(); StringRef Opt(S); - if (Opt.endswith("=")) + if (Opt.ends_with("=")) Opt = Opt.drop_back(1); - if (Opt.startswith("mno-")) + if (Opt.starts_with("mno-")) Opt = Opt.drop_front(4); - else if (Opt.startswith("m")) + else if (Opt.starts_with("m")) Opt = Opt.drop_front(1); return Args.MakeArgString(Twine(Enable ? "+" : "-") + Twine(Opt)); }; @@ -120,16 +120,17 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, HvxVerNum = 0; // Handle HVX floating point flags. - auto checkFlagHvxVersion = [&](auto FlagOn, auto FlagOff, - unsigned MinVerNum) -> Optional<StringRef> { - // Return an Optional<StringRef>: - // - None indicates a verification failure, or that the flag was not + auto checkFlagHvxVersion = + [&](auto FlagOn, auto FlagOff, + unsigned MinVerNum) -> std::optional<StringRef> { + // Return an std::optional<StringRef>: + // - std::nullopt indicates a verification failure, or that the flag was not // present in Args. // - Otherwise the returned value is that name of the feature to add // to Features. Arg *A = Args.getLastArg(FlagOn, FlagOff); if (!A) - return None; + return std::nullopt; StringRef OptName = A->getOption().getName(); if (A->getOption().matches(FlagOff)) @@ -137,12 +138,12 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, if (!HasHVX) { D.Diag(diag::err_drv_needs_hvx) << withMinus(OptName); - return None; + return std::nullopt; } if (HvxVerNum < MinVerNum) { D.Diag(diag::err_drv_needs_hvx_version) << withMinus(OptName) << ("v" + std::to_string(HvxVerNum)); - return None; + return std::nullopt; } return makeFeature(OptName, true); }; @@ -158,9 +159,11 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, } // Hexagon target features. -void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args, +void hexagon::getHexagonTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, std::vector<StringRef> &Features) { - handleTargetFeaturesGroup(Args, Features, + handleTargetFeaturesGroup(D, Triple, Args, Features, options::OPT_m_hexagon_Features_Group); bool UseLongCalls = false; @@ -215,11 +218,11 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, addSanitizerRuntimes(HTC, Args, CmdArgs); + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { - assert(Output.isNothing() && "Unexpected output"); CmdArgs.push_back("-fsyntax-only"); } @@ -230,7 +233,7 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, } if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { - CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(G.getValue()))); + CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(*G))); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -340,8 +343,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, CmdArgs.push_back("-pie"); if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { - CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue()))); - UseG0 = G.getValue() == 0; + CmdArgs.push_back(Args.MakeArgString("-G" + Twine(*G))); + UseG0 = *G == 0; } CmdArgs.push_back("-o"); @@ -360,27 +363,31 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString(StringRef("-L") + D.SysRoot + "/usr/lib")); - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_u_Group}); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_u_Group}); AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (NeedsSanitizerDeps) { - linkSanitizerRuntimeDeps(HTC, CmdArgs); + linkSanitizerRuntimeDeps(HTC, Args, CmdArgs); CmdArgs.push_back("-lunwind"); } if (NeedsXRayDeps) - linkXRayRuntimeDeps(HTC, CmdArgs); + linkXRayRuntimeDeps(HTC, Args, CmdArgs); CmdArgs.push_back("-lclang_rt.builtins-hexagon"); - CmdArgs.push_back("-lc"); + if (!Args.hasArg(options::OPT_nolibc)) + CmdArgs.push_back("-lc"); } if (D.CCCIsCXX()) { if (HTC.ShouldLinkCXXStdlib(Args)) HTC.AddCXXStdlibLibArgs(Args, CmdArgs); } + const ToolChain::path_list &LibPaths = HTC.getFilePaths(); + for (const auto &LibPath : LibPaths) + CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); + Args.ClaimAllArgs(options::OPT_L); return; } @@ -439,13 +446,13 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, const ToolChain::path_list &LibPaths = HTC.getFilePaths(); for (const auto &LibPath : LibPaths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); + Args.ClaimAllArgs(options::OPT_L); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_u_Group}); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_u_Group}); AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); @@ -464,7 +471,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, if (!IsShared) { for (StringRef Lib : OsLibs) CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); - CmdArgs.push_back("-lc"); + if (!Args.hasArg(options::OPT_nolibc)) + CmdArgs.push_back("-lc"); } CmdArgs.push_back("-lgcc"); @@ -519,8 +527,8 @@ std::string HexagonToolChain::getHexagonTargetDir( return InstalledDir; } -Optional<unsigned> HexagonToolChain::getSmallDataThreshold( - const ArgList &Args) { +std::optional<unsigned> +HexagonToolChain::getSmallDataThreshold(const ArgList &Args) { StringRef Gn = ""; if (Arg *A = Args.getLastArg(options::OPT_G)) { Gn = A->getValue(); @@ -533,14 +541,16 @@ Optional<unsigned> HexagonToolChain::getSmallDataThreshold( if (!Gn.getAsInteger(10, G)) return G; - return None; + return std::nullopt; } std::string HexagonToolChain::getCompilerRTPath() const { SmallString<128> Dir(getDriver().SysRoot); llvm::sys::path::append(Dir, "usr", "lib"); - Dir += SelectedMultilib.gccSuffix(); - return std::string(Dir.str()); + if (!SelectedMultilibs.empty()) { + Dir += SelectedMultilibs.back().gccSuffix(); + } + return std::string(Dir); } void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, @@ -551,8 +561,7 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, // -L Args //---------------------------------------------------------------------------- for (Arg *A : Args.filtered(options::OPT_L)) - for (const char *Value : A->getValues()) - LibPaths.push_back(Value); + llvm::append_range(LibPaths, A->getValues()); //---------------------------------------------------------------------------- // Other standard paths @@ -570,7 +579,7 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, // Assume G0 with -shared. bool HasG0 = Args.hasArg(options::OPT_shared); if (auto G = getSmallDataThreshold(Args)) - HasG0 = G.getValue() == 0; + HasG0 = *G == 0; const std::string CpuVer = GetTargetCPUVersion(Args).str(); for (auto &Dir : RootDirs) { @@ -615,6 +624,8 @@ void HexagonToolChain::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"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); break; @@ -790,7 +801,7 @@ StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { CpuArg = A; StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); - if (CPU.startswith("hexagon")) + if (CPU.starts_with("hexagon")) return CPU.substr(sizeof("hexagon") - 1); return CPU; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h index 899630555352..e35a224dced4 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h @@ -20,7 +20,7 @@ namespace hexagon { // For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile // and Compile. // We simply use "clang -cc1" for those actions. -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("hexagon::Assembler", "hexagon-as", TC) {} @@ -35,7 +35,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("hexagon::Linker", "hexagon-ld", TC) {} @@ -50,7 +50,8 @@ public: const char *LinkingOutput) const override; }; -void getHexagonTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, +void getHexagonTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, std::vector<StringRef> &Features); } // end namespace hexagon. @@ -94,9 +95,6 @@ public: llvm::opt::ArgStringList &CmdArgs) const override; StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } - bool IsIntegratedAssemblerDefault() const override { - return true; - } std::string getHexagonTargetDir( const std::string &InstalledDir, @@ -110,8 +108,8 @@ public: static StringRef GetDefaultCPU(); static StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); - static Optional<unsigned> getSmallDataThreshold( - const llvm::opt::ArgList &Args); + static std::optional<unsigned> + getSmallDataThreshold(const llvm::opt::ArgList &Args); }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp index 48b9ccadf36f..0bc114b90ffc 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp @@ -30,13 +30,21 @@ using tools::addPathIfExists; std::string Hurd::getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, StringRef SysRoot) const { - if (TargetTriple.getArch() == llvm::Triple::x86) { + switch (TargetTriple.getArch()) { + default: + break; + + case llvm::Triple::x86: // We use the existence of '/lib/<triple>' as a directory to detect some // common hurd triples that don't quite match the Clang triple for both // 32-bit and 64-bit targets. Multiarch fixes its install triples to these // regardless of what the actual target triple is. if (D.getVFS().exists(SysRoot + "/lib/i386-gnu")) return "i386-gnu"; + break; + + case llvm::Triple::x86_64: + return "x86_64-gnu"; } // For most architectures, just use whatever we have rather than trying to be @@ -65,7 +73,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); - SelectedMultilib = GCCInstallation.getMultilib(); + SelectedMultilibs.assign({GCCInstallation.getMultilib()}); std::string SysRoot = computeSysRoot(); ToolChain::path_list &PPaths = getProgramPaths(); @@ -92,7 +100,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // those searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) { + if (StringRef(D.Dir).starts_with(SysRoot)) { addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); } @@ -110,7 +118,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) + if (StringRef(D.Dir).starts_with(SysRoot)) addPathIfExists(D, D.Dir + "/../lib", Paths); addPathIfExists(D, SysRoot + "/lib", Paths); @@ -126,8 +134,14 @@ Tool *Hurd::buildAssembler() const { } std::string Hurd::getDynamicLinker(const ArgList &Args) const { - if (getArch() == llvm::Triple::x86) + switch (getArch()) { + case llvm::Triple::x86: return "/lib/ld.so"; + case llvm::Triple::x86_64: + return "/lib/ld-x86-64.so.1"; + default: + break; + } llvm_unreachable("unsupported architecture"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h index dc04b0cfe2ee..33701f7cc045 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h @@ -29,8 +29,6 @@ public: void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override {} - - bool IsIntegratedAssemblerDefault() const override { return true; } }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h new file mode 100644 index 000000000000..813d00a87bb8 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h @@ -0,0 +1,45 @@ +//===--- LazyDetector.h - Lazy ToolChain Detection --------------*- 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_LAZYDETECTOR_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LAZYDETECTOR_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include <optional> + +namespace clang { + +/// Simple wrapper for toolchain detector with costly initialization. This +/// delays the creation of the actual detector until its first usage. + +template <class T> class LazyDetector { + const driver::Driver &D; + llvm::Triple Triple; + const llvm::opt::ArgList &Args; + + std::optional<T> Detector; + +public: + LazyDetector(const driver::Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : D(D), Triple(Triple), Args(Args) {} + T *operator->() { + if (!Detector) + Detector.emplace(D, Triple, Args); + return &*Detector; + } + const T *operator->() const { + return const_cast<T const *>( + const_cast<LazyDetector &>(*this).operator->()); + } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LAZYDETECTOR_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp index f85c04df4f6c..4300a2bdff17 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp @@ -8,6 +8,7 @@ #include "Linux.h" #include "Arch/ARM.h" +#include "Arch/LoongArch.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/RISCV.h" @@ -60,12 +61,16 @@ std::string Linux::getMultiarchTriple(const Driver &D, case llvm::Triple::thumb: if (IsAndroid) return "arm-linux-androideabi"; - if (TargetEnvironment == llvm::Triple::GNUEABIHF) + if (TargetEnvironment == llvm::Triple::GNUEABIHF || + TargetEnvironment == llvm::Triple::MuslEABIHF || + TargetEnvironment == llvm::Triple::EABIHF) return "arm-linux-gnueabihf"; return "arm-linux-gnueabi"; case llvm::Triple::armeb: case llvm::Triple::thumbeb: - if (TargetEnvironment == llvm::Triple::GNUEABIHF) + if (TargetEnvironment == llvm::Triple::GNUEABIHF || + TargetEnvironment == llvm::Triple::MuslEABIHF || + TargetEnvironment == llvm::Triple::EABIHF) return "armeb-linux-gnueabihf"; return "armeb-linux-gnueabi"; case llvm::Triple::x86: @@ -85,37 +90,66 @@ std::string Linux::getMultiarchTriple(const Driver &D, case llvm::Triple::aarch64_be: return "aarch64_be-linux-gnu"; + case llvm::Triple::loongarch64: { + const char *Libc; + const char *FPFlavor; + + if (TargetTriple.isGNUEnvironment()) { + Libc = "gnu"; + } else if (TargetTriple.isMusl()) { + Libc = "musl"; + } else { + return TargetTriple.str(); + } + + switch (TargetEnvironment) { + default: + return TargetTriple.str(); + case llvm::Triple::GNUSF: + FPFlavor = "sf"; + break; + case llvm::Triple::GNUF32: + FPFlavor = "f32"; + break; + case llvm::Triple::GNU: + case llvm::Triple::GNUF64: + // This was going to be "f64" in an earlier Toolchain Conventions + // revision, but starting from Feb 2023 the F64 ABI variants are + // unmarked in their canonical forms. + FPFlavor = ""; + break; + } + + return (Twine("loongarch64-linux-") + Libc + FPFlavor).str(); + } + case llvm::Triple::m68k: return "m68k-linux-gnu"; case llvm::Triple::mips: return IsMipsR6 ? "mipsisa32r6-linux-gnu" : "mips-linux-gnu"; case llvm::Triple::mipsel: - if (IsAndroid) - return "mipsel-linux-android"; return IsMipsR6 ? "mipsisa32r6el-linux-gnu" : "mipsel-linux-gnu"; case llvm::Triple::mips64: { std::string MT = std::string(IsMipsR6 ? "mipsisa64r6" : "mips64") + "-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64"); - if (D.getVFS().exists(SysRoot + "/lib/" + MT)) + if (D.getVFS().exists(concat(SysRoot, "/lib", MT))) return MT; - if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu")) + if (D.getVFS().exists(concat(SysRoot, "/lib/mips64-linux-gnu"))) return "mips64-linux-gnu"; break; } case llvm::Triple::mips64el: { - if (IsAndroid) - return "mips64el-linux-android"; std::string MT = std::string(IsMipsR6 ? "mipsisa64r6el" : "mips64el") + "-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64"); - if (D.getVFS().exists(SysRoot + "/lib/" + MT)) + if (D.getVFS().exists(concat(SysRoot, "/lib", MT))) return MT; - if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu")) + if (D.getVFS().exists(concat(SysRoot, "/lib/mips64el-linux-gnu"))) return "mips64el-linux-gnu"; break; } case llvm::Triple::ppc: - if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe")) + if (D.getVFS().exists(concat(SysRoot, "/lib/powerpc-linux-gnuspe"))) return "powerpc-linux-gnuspe"; return "powerpc-linux-gnu"; case llvm::Triple::ppcle: @@ -124,6 +158,10 @@ std::string Linux::getMultiarchTriple(const Driver &D, return "powerpc64-linux-gnu"; case llvm::Triple::ppc64le: return "powerpc64le-linux-gnu"; + case llvm::Triple::riscv64: + if (IsAndroid) + return "riscv64-linux-android"; + return "riscv64-linux-gnu"; case llvm::Triple::sparc: return "sparc-linux-gnu"; case llvm::Triple::sparcv9: @@ -179,7 +217,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); - SelectedMultilib = GCCInstallation.getMultilib(); + SelectedMultilibs.assign({GCCInstallation.getMultilib()}); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); ToolChain::path_list &PPaths = getProgramPaths(); @@ -221,8 +259,12 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) const bool IsMips = Triple.isMIPS(); const bool IsHexagon = Arch == llvm::Triple::hexagon; const bool IsRISCV = Triple.isRISCV(); + const bool IsCSKY = Triple.isCSKY(); + + if (IsCSKY && !SelectedMultilibs.empty()) + SysRoot = SysRoot + SelectedMultilibs.back().osSuffix(); - if (IsMips && !SysRoot.empty()) + if ((IsMips || IsCSKY) && !SysRoot.empty()) ExtraOpts.push_back("--sysroot=" + SysRoot); // Do not use 'gnu' hash style for Mips targets because .gnu.hash @@ -232,25 +274,18 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // Android loader does not support .gnu.hash until API 23. // Hexagon linker/loader does not support .gnu.hash if (!IsMips && !IsHexagon) { - if (Distro.IsRedhat() || Distro.IsOpenSUSE() || Distro.IsAlpineLinux() || - (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick) || - (IsAndroid && !Triple.isAndroidVersionLT(23))) - ExtraOpts.push_back("--hash-style=gnu"); - - if (Distro.IsDebian() || Distro.IsOpenSUSE() || - Distro == Distro::UbuntuLucid || Distro == Distro::UbuntuJaunty || - Distro == Distro::UbuntuKarmic || + if (Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid || + Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic || (IsAndroid && Triple.isAndroidVersionLT(23))) ExtraOpts.push_back("--hash-style=both"); + else + ExtraOpts.push_back("--hash-style=gnu"); } #ifdef ENABLE_LINKER_BUILD_ID ExtraOpts.push_back("--build-id"); #endif - if (IsAndroid || Distro.IsOpenSUSE()) - ExtraOpts.push_back("--enable-new-dtags"); - // The selection of paths to try here is designed to match the patterns which // the GCC driver itself uses, as this is part of the GCC-compatible driver. // This was determined by running GCC in a fake filesystem, creating all @@ -265,13 +300,13 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // used. We need add both libo32 and /lib. if (Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel) { Generic_GCC::AddMultilibPaths(D, SysRoot, "libo32", MultiarchTriple, Paths); - addPathIfExists(D, SysRoot + "/libo32", Paths); - addPathIfExists(D, SysRoot + "/usr/libo32", Paths); + addPathIfExists(D, concat(SysRoot, "/libo32"), Paths); + addPathIfExists(D, concat(SysRoot, "/usr/libo32"), Paths); } Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths); - addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); - addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); + addPathIfExists(D, concat(SysRoot, "/lib", MultiarchTriple), Paths); + addPathIfExists(D, concat(SysRoot, "/lib/..", OSLibDir), Paths); if (IsAndroid) { // Android sysroots contain a library directory for each supported OS @@ -279,43 +314,30 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // directory. addPathIfExists( D, - SysRoot + "/usr/lib/" + MultiarchTriple + "/" + - llvm::to_string(Triple.getEnvironmentVersion().getMajor()), + concat(SysRoot, "/usr/lib", MultiarchTriple, + llvm::to_string(Triple.getEnvironmentVersion().getMajor())), Paths); } - addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); + addPathIfExists(D, concat(SysRoot, "/usr/lib", MultiarchTriple), Paths); // 64-bit OpenEmbedded sysroots may not have a /usr/lib dir. So they cannot // find /usr/lib64 as it is referenced as /usr/lib/../lib64. So we handle // this here. if (Triple.getVendor() == llvm::Triple::OpenEmbedded && Triple.isArch64Bit()) - addPathIfExists(D, SysRoot + "/usr/" + OSLibDir, Paths); + addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir), Paths); else - addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); + addPathIfExists(D, concat(SysRoot, "/usr/lib/..", OSLibDir), Paths); if (IsRISCV) { StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple); - addPathIfExists(D, SysRoot + "/" + OSLibDir + "/" + ABIName, Paths); - addPathIfExists(D, SysRoot + "/usr/" + OSLibDir + "/" + ABIName, Paths); + addPathIfExists(D, concat(SysRoot, "/", OSLibDir, ABIName), Paths); + addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir, ABIName), Paths); } Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths); - // Similar to the logic for GCC above, if we are currently running Clang - // inside of the requested system root, add its parent library path to those - // searched. - // FIXME: It's not clear whether we should use the driver's installed - // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) { - // Even if OSLibDir != "lib", this is needed for Clang in the build - // directory (not installed) to find libc++. - addPathIfExists(D, D.Dir + "/../lib", Paths); - if (OSLibDir != "lib") - addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); - } - - addPathIfExists(D, SysRoot + "/lib", Paths); - addPathIfExists(D, SysRoot + "/usr/lib", Paths); + addPathIfExists(D, concat(SysRoot, "/lib"), Paths); + addPathIfExists(D, concat(SysRoot, "/usr/lib"), Paths); } ToolChain::RuntimeLibType Linux::GetDefaultRuntimeLibType() const { @@ -361,6 +383,21 @@ std::string Linux::computeSysRoot() const { return AndroidSysRootPath; } + if (getTriple().isCSKY()) { + // CSKY toolchains use different names for sysroot folder. + if (!GCCInstallation.isValid()) + return std::string(); + // GCCInstallation.getInstallPath() = + // $GCCToolchainPath/lib/gcc/csky-linux-gnuabiv2/6.3.0 + // Path = $GCCToolchainPath/csky-linux-gnuabiv2/libc + std::string Path = (GCCInstallation.getInstallPath() + "/../../../../" + + GCCInstallation.getTriple().str() + "/libc") + .str(); + if (getVFS().exists(Path)) + return Path; + return std::string(); + } + if (!GCCInstallation.isValid() || !getTriple().isMIPS()) return std::string(); @@ -393,9 +430,17 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { const Distro Distro(getDriver().getVFS(), Triple); - if (Triple.isAndroid()) + if (Triple.isAndroid()) { + if (getSanitizerArgs(Args).needsHwasanRt() && + !Triple.isAndroidVersionLT(34) && Triple.isArch64Bit()) { + // On Android 14 and newer, there is a special linker_hwasan64 that + // allows to run HWASan binaries on non-HWASan system images. This + // is also available on HWASan system images, so we can just always + // use that instead. + return "/system/bin/linker_hwasan64"; + } return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; - + } if (Triple.isMusl()) { std::string ArchName; bool IsArm = false; @@ -458,6 +503,22 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3"; break; } + case llvm::Triple::loongarch32: { + LibDir = "lib32"; + Loader = + ("ld-linux-loongarch-" + + tools::loongarch::getLoongArchABI(getDriver(), Args, Triple) + ".so.1") + .str(); + break; + } + case llvm::Triple::loongarch64: { + LibDir = "lib64"; + Loader = + ("ld-linux-loongarch-" + + tools::loongarch::getLoongArchABI(getDriver(), Args, Triple) + ".so.1") + .str(); + break; + } case llvm::Triple::m68k: LibDir = "lib"; Loader = "ld.so.1"; @@ -537,6 +598,11 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { } case llvm::Triple::ve: return "/opt/nec/ve/lib/ld-linux-ve.so.1"; + case llvm::Triple::csky: { + LibDir = "lib"; + Loader = "ld.so.1"; + break; + } } if (Distro == Distro::Exherbo && @@ -568,7 +634,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; // LOCAL_INCLUDE_DIR - addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); + addSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/local/include")); // TOOL_INCLUDE_DIR AddMultilibIncludeArgs(DriverArgs, CC1Args); @@ -589,9 +655,10 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // /usr/include. std::string MultiarchIncludeDir = getMultiarchTriple(D, getTriple(), SysRoot); if (!MultiarchIncludeDir.empty() && - D.getVFS().exists(SysRoot + "/usr/include/" + MultiarchIncludeDir)) - addExternCSystemInclude(DriverArgs, CC1Args, - SysRoot + "/usr/include/" + MultiarchIncludeDir); + D.getVFS().exists(concat(SysRoot, "/usr/include", MultiarchIncludeDir))) + addExternCSystemInclude( + DriverArgs, CC1Args, + concat(SysRoot, "/usr/include", MultiarchIncludeDir)); if (getTriple().getOS() == llvm::Triple::RTEMS) return; @@ -599,9 +666,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Add an include of '/include' directly. This isn't provided by default by // system GCCs, but is often used with cross-compiling GCCs, and harmless to // add even when Clang is acting as-if it were a system compiler. - addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); + addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/include")); - addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); + addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/include")); if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl()) addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); @@ -650,12 +717,25 @@ void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void Linux::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); +} + +void Linux::AddHIPRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.push_back( + Args.MakeArgString(StringRef("-L") + RocmInstallation->getLibPath())); + + if (Args.hasFlag(options::OPT_frtlib_add_rpath, + options::OPT_fno_rtlib_add_rpath, false)) + CmdArgs.append( + {"-rpath", Args.MakeArgString(RocmInstallation->getLibPath())}); + + CmdArgs.push_back("-lamdhip64"); } void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, @@ -705,6 +785,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { getTriple().getArch() == llvm::Triple::thumb || getTriple().getArch() == llvm::Triple::armeb || getTriple().getArch() == llvm::Triple::thumbeb; + const bool IsLoongArch64 = getTriple().getArch() == llvm::Triple::loongarch64; const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64; const bool IsSystemZ = getTriple().getArch() == llvm::Triple::systemz; const bool IsHexagon = getTriple().getArch() == llvm::Triple::hexagon; @@ -718,24 +799,28 @@ SanitizerMask Linux::getSupportedSanitizers() const { Res |= SanitizerKind::Memory; Res |= SanitizerKind::Vptr; Res |= SanitizerKind::SafeStack; - if (IsX86_64 || IsMIPS64 || IsAArch64) + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsLoongArch64) Res |= SanitizerKind::DataFlow; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 || - IsRISCV64 || IsSystemZ || IsHexagon) + IsRISCV64 || IsSystemZ || IsHexagon || IsLoongArch64) Res |= SanitizerKind::Leak; - if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ) + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ || + IsLoongArch64 || IsRISCV64) Res |= SanitizerKind::Thread; - if (IsX86_64) + if (IsX86_64 || IsSystemZ) Res |= SanitizerKind::KernelMemory; - if (IsX86 || IsX86_64) - Res |= SanitizerKind::Function; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || - IsPowerPC64 || IsHexagon) + IsPowerPC64 || IsHexagon || IsLoongArch64 || IsRISCV64) Res |= SanitizerKind::Scudo; - if (IsX86_64 || IsAArch64) { + if (IsX86_64 || IsAArch64 || IsRISCV64) { Res |= SanitizerKind::HWAddress; + } + if (IsX86_64 || IsAArch64) { Res |= SanitizerKind::KernelHWAddress; } + // Work around "Cannot represent a difference across sections". + if (getTriple().getArch() == llvm::Triple::ppc64) + Res &= ~SanitizerKind::Function; return Res; } @@ -772,3 +857,9 @@ void Linux::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { for (const auto &Opt : ExtraOpts) CmdArgs.push_back(Opt.c_str()); } + +const char *Linux::getDefaultLinker() const { + if (getTriple().isAndroid()) + return "ld.lld"; + return Generic_ELF::getDefaultLinker(); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h index a5648d79d655..524391743090 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h @@ -37,6 +37,8 @@ public: llvm::opt::ArgStringList &CC1Args) const override; void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPRuntimeLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; RuntimeLibType GetDefaultRuntimeLibType() const override; @@ -61,6 +63,8 @@ public: const llvm::opt::ArgList &DriverArgs, const JobAction &JA, const llvm::fltSemantics *FPType = nullptr) const override; + const char *getDefaultLinker() const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp index 96994ba77fac..07e875c64960 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp @@ -101,7 +101,7 @@ void msp430::getMSP430TargetFeatures(const Driver &D, const ArgList &Args, Features.push_back("+hwmultf5"); } else { D.Diag(clang::diag::err_drv_unsupported_option_argument) - << HWMultArg->getAsString(Args) << HWMult; + << HWMultArg->getSpelling() << HWMult; } } @@ -142,7 +142,7 @@ std::string MSP430ToolChain::computeSysRoot() const { else llvm::sys::path::append(Dir, getDriver().Dir, ".."); - return std::string(Dir.str()); + return std::string(Dir); } void MSP430ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -166,7 +166,7 @@ void MSP430ToolChain::addClangTargetOptions(const ArgList &DriverArgs, return; const StringRef MCU = MCUArg->getValue(); - if (MCU.startswith("msp430i")) { + if (MCU.starts_with("msp430i")) { // 'i' should be in lower case as it's defined in TI MSP430-GCC headers CC1Args.push_back(DriverArgs.MakeArgString( "-D__MSP430i" + MCU.drop_front(7).upper() + "__")); @@ -279,8 +279,7 @@ void msp430::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_r, options::OPT_g_Group)) CmdArgs.push_back("--gc-sections"); - Args.AddAllArgs(CmdArgs, { - options::OPT_e, + Args.addAllArgs(CmdArgs, { options::OPT_n, options::OPT_s, options::OPT_t, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h index 2e838c027e0f..a224c6375411 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h @@ -59,7 +59,7 @@ private: namespace tools { namespace msp430 { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("MSP430::Linker", "msp430-elf-ld", TC) {} bool hasIntegratedCPP() const override { return false; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp index 9f4751167ac1..396522225158 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp @@ -18,17 +18,16 @@ #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Host.h" #include <cstdio> #ifdef _WIN32 @@ -40,91 +39,12 @@ #include <windows.h> #endif -#ifdef _MSC_VER -// Don't support SetupApi on MinGW. -#define USE_MSVC_SETUP_API - -// Make sure this comes before MSVCSetupApi.h -#include <comdef.h> - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-virtual-dtor" -#endif -#include "MSVCSetupApi.h" -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -#include "llvm/Support/COM.h" -_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); -_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); -_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper)); -_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); -_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); -_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2)); -#endif - using namespace clang::driver; using namespace clang::driver::toolchains; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -// Windows SDKs and VC Toolchains group their contents into subdirectories based -// on the target architecture. This function converts an llvm::Triple::ArchType -// to the corresponding subdirectory name. -static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) { - using ArchType = llvm::Triple::ArchType; - switch (Arch) { - case ArchType::x86: - return "x86"; - case ArchType::x86_64: - return "x64"; - case ArchType::arm: - return "arm"; - case ArchType::aarch64: - return "arm64"; - default: - return ""; - } -} - -// Similar to the above function, but for Visual Studios before VS2017. -static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) { - using ArchType = llvm::Triple::ArchType; - switch (Arch) { - case ArchType::x86: - // x86 is default in legacy VC toolchains. - // e.g. x86 libs are directly in /lib as opposed to /lib/x86. - return ""; - case ArchType::x86_64: - return "amd64"; - case ArchType::arm: - return "arm"; - case ArchType::aarch64: - return "arm64"; - default: - return ""; - } -} - -// Similar to the above function, but for DevDiv internal builds. -static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) { - using ArchType = llvm::Triple::ArchType; - switch (Arch) { - case ArchType::x86: - return "i386"; - case ArchType::x86_64: - return "amd64"; - case ArchType::arm: - return "arm"; - case ArchType::aarch64: - return "arm64"; - default: - return ""; - } -} - static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) { auto Status = VFS.status(Path); if (!Status) @@ -132,294 +52,6 @@ static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) { return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0; } -// Defined below. -// Forward declare this so there aren't too many things above the constructor. -static bool getSystemRegistryString(const char *keyPath, const char *valueName, - std::string &value, std::string *phValue); - -static std::string getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS, - StringRef Directory) { - std::string Highest; - llvm::VersionTuple HighestTuple; - - std::error_code EC; - for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC), - DirEnd; - !EC && DirIt != DirEnd; DirIt.increment(EC)) { - auto Status = VFS.status(DirIt->path()); - if (!Status || !Status->isDirectory()) - continue; - StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); - llvm::VersionTuple Tuple; - if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error. - continue; - if (Tuple > HighestTuple) { - HighestTuple = Tuple; - Highest = CandidateName.str(); - } - } - - return Highest; -} - -// Check command line arguments to try and find a toolchain. -static bool -findVCToolChainViaCommandLine(llvm::vfs::FileSystem &VFS, const ArgList &Args, - std::string &Path, - MSVCToolChain::ToolsetLayout &VSLayout) { - // Don't validate the input; trust the value supplied by the user. - // The primary motivation is to prevent unnecessary file and registry access. - if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir, - options::OPT__SLASH_winsysroot)) { - if (A->getOption().getID() == options::OPT__SLASH_winsysroot) { - llvm::SmallString<128> ToolsPath(A->getValue()); - llvm::sys::path::append(ToolsPath, "VC", "Tools", "MSVC"); - std::string VCToolsVersion; - if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion)) - VCToolsVersion = A->getValue(); - else - VCToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath); - llvm::sys::path::append(ToolsPath, VCToolsVersion); - Path = std::string(ToolsPath.str()); - } else { - Path = A->getValue(); - } - VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; - return true; - } - return false; -} - -// Check various environment variables to try and find a toolchain. -static bool -findVCToolChainViaEnvironment(llvm::vfs::FileSystem &VFS, std::string &Path, - MSVCToolChain::ToolsetLayout &VSLayout) { - // These variables are typically set by vcvarsall.bat - // when launching a developer command prompt. - if (llvm::Optional<std::string> VCToolsInstallDir = - llvm::sys::Process::GetEnv("VCToolsInstallDir")) { - // This is only set by newer Visual Studios, and it leads straight to - // the toolchain directory. - Path = std::move(*VCToolsInstallDir); - VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; - return true; - } - if (llvm::Optional<std::string> VCInstallDir = - llvm::sys::Process::GetEnv("VCINSTALLDIR")) { - // If the previous variable isn't set but this one is, then we've found - // an older Visual Studio. This variable is set by newer Visual Studios too, - // so this check has to appear second. - // In older Visual Studios, the VC directory is the toolchain. - Path = std::move(*VCInstallDir); - VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; - return true; - } - - // We couldn't find any VC environment variables. Let's walk through PATH and - // see if it leads us to a VC toolchain bin directory. If it does, pick the - // first one that we find. - if (llvm::Optional<std::string> PathEnv = - llvm::sys::Process::GetEnv("PATH")) { - llvm::SmallVector<llvm::StringRef, 8> PathEntries; - llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator); - for (llvm::StringRef PathEntry : PathEntries) { - if (PathEntry.empty()) - continue; - - llvm::SmallString<256> ExeTestPath; - - // If cl.exe doesn't exist, then this definitely isn't a VC toolchain. - ExeTestPath = PathEntry; - llvm::sys::path::append(ExeTestPath, "cl.exe"); - if (!VFS.exists(ExeTestPath)) - continue; - - // cl.exe existing isn't a conclusive test for a VC toolchain; clang also - // has a cl.exe. So let's check for link.exe too. - ExeTestPath = PathEntry; - llvm::sys::path::append(ExeTestPath, "link.exe"); - if (!VFS.exists(ExeTestPath)) - continue; - - // whatever/VC/bin --> old toolchain, VC dir is toolchain dir. - llvm::StringRef TestPath = PathEntry; - bool IsBin = - llvm::sys::path::filename(TestPath).equals_insensitive("bin"); - if (!IsBin) { - // Strip any architecture subdir like "amd64". - TestPath = llvm::sys::path::parent_path(TestPath); - IsBin = llvm::sys::path::filename(TestPath).equals_insensitive("bin"); - } - if (IsBin) { - llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath); - llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath); - if (ParentFilename.equals_insensitive("VC")) { - Path = std::string(ParentPath); - VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; - return true; - } - if (ParentFilename.equals_insensitive("x86ret") || - ParentFilename.equals_insensitive("x86chk") || - ParentFilename.equals_insensitive("amd64ret") || - ParentFilename.equals_insensitive("amd64chk")) { - Path = std::string(ParentPath); - VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal; - return true; - } - - } else { - // This could be a new (>=VS2017) toolchain. If it is, we should find - // path components with these prefixes when walking backwards through - // the path. - // Note: empty strings match anything. - llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "", - "MSVC", "Tools", "VC"}; - - auto It = llvm::sys::path::rbegin(PathEntry); - auto End = llvm::sys::path::rend(PathEntry); - for (llvm::StringRef Prefix : ExpectedPrefixes) { - if (It == End) - goto NotAToolChain; - if (!It->startswith_insensitive(Prefix)) - goto NotAToolChain; - ++It; - } - - // We've found a new toolchain! - // Back up 3 times (/bin/Host/arch) to get the root path. - llvm::StringRef ToolChainPath(PathEntry); - for (int i = 0; i < 3; ++i) - ToolChainPath = llvm::sys::path::parent_path(ToolChainPath); - - Path = std::string(ToolChainPath); - VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; - return true; - } - - NotAToolChain: - continue; - } - } - return false; -} - -// Query the Setup Config server for installs, then pick the newest version -// and find its default VC toolchain. -// This is the preferred way to discover new Visual Studios, as they're no -// longer listed in the registry. -static bool -findVCToolChainViaSetupConfig(llvm::vfs::FileSystem &VFS, std::string &Path, - MSVCToolChain::ToolsetLayout &VSLayout) { -#if !defined(USE_MSVC_SETUP_API) - return false; -#else - // FIXME: This really should be done once in the top-level program's main - // function, as it may have already been initialized with a different - // threading model otherwise. - llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded); - HRESULT HR; - - // _com_ptr_t will throw a _com_error if a COM calls fail. - // The LLVM coding standards forbid exception handling, so we'll have to - // stop them from being thrown in the first place. - // The destructor will put the regular error handler back when we leave - // this scope. - struct SuppressCOMErrorsRAII { - static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {} - - SuppressCOMErrorsRAII() { _set_com_error_handler(handler); } - - ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); } - - } COMErrorSuppressor; - - ISetupConfigurationPtr Query; - HR = Query.CreateInstance(__uuidof(SetupConfiguration)); - if (FAILED(HR)) - return false; - - IEnumSetupInstancesPtr EnumInstances; - HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances); - if (FAILED(HR)) - return false; - - ISetupInstancePtr Instance; - HR = EnumInstances->Next(1, &Instance, nullptr); - if (HR != S_OK) - return false; - - ISetupInstancePtr NewestInstance; - Optional<uint64_t> NewestVersionNum; - do { - bstr_t VersionString; - uint64_t VersionNum; - HR = Instance->GetInstallationVersion(VersionString.GetAddress()); - if (FAILED(HR)) - continue; - HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum); - if (FAILED(HR)) - continue; - if (!NewestVersionNum || (VersionNum > NewestVersionNum)) { - NewestInstance = Instance; - NewestVersionNum = VersionNum; - } - } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK); - - if (!NewestInstance) - return false; - - bstr_t VCPathWide; - HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress()); - if (FAILED(HR)) - return false; - - std::string VCRootPath; - llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath); - - llvm::SmallString<256> ToolsVersionFilePath(VCRootPath); - llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build", - "Microsoft.VCToolsVersion.default.txt"); - - auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath); - if (!ToolsVersionFile) - return false; - - llvm::SmallString<256> ToolchainPath(VCRootPath); - llvm::sys::path::append(ToolchainPath, "Tools", "MSVC", - ToolsVersionFile->get()->getBuffer().rtrim()); - auto Status = VFS.status(ToolchainPath); - if (!Status || !Status->isDirectory()) - return false; - - Path = std::string(ToolchainPath.str()); - VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; - return true; -#endif -} - -// Look in the registry for Visual Studio installs, and use that to get -// a toolchain path. VS2017 and newer don't get added to the registry. -// So if we find something here, we know that it's an older version. -static bool findVCToolChainViaRegistry(std::string &Path, - MSVCToolChain::ToolsetLayout &VSLayout) { - std::string VSInstallPath; - if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)", - "InstallDir", VSInstallPath, nullptr) || - getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)", - "InstallDir", VSInstallPath, nullptr)) { - if (!VSInstallPath.empty()) { - llvm::SmallString<256> VCPath(llvm::StringRef( - VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)"))); - llvm::sys::path::append(VCPath, "VC"); - - Path = std::string(VCPath.str()); - VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; - return true; - } - } - return false; -} - // Try to find Exe from a Visual Studio distribution. This first tries to find // an installed copy of Visual Studio and, failing that, looks in the PATH, // making sure that whatever executable that's found is not a same-named exe @@ -427,8 +59,8 @@ static bool findVCToolChainViaRegistry(std::string &Path, static std::string FindVisualStudioExecutable(const ToolChain &TC, const char *Exe) { const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC); - SmallString<128> FilePath(MSVC.getSubDirectoryPath( - toolchains::MSVCToolChain::SubDirectoryType::Bin)); + SmallString<128> FilePath( + MSVC.getSubDirectoryPath(llvm::SubDirectoryType::Bin)); llvm::sys::path::append(FilePath, Exe); return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe); } @@ -448,7 +80,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(std::string("-out:") + Output.getFilename())); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && - !C.getDriver().IsCLMode()) { + !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { CmdArgs.push_back("-defaultlib:libcmt"); CmdArgs.push_back("-defaultlib:oldnames"); } @@ -469,7 +101,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, // The DIA SDK always uses the legacy vc arch, even in new MSVC versions. llvm::sys::path::append(DIAPath, "lib", - llvmArchToLegacyVCArch(TC.getArch())); + llvm::archToLegacyVCArch(TC.getArch())); CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath)); } if (!llvm::sys::Process::GetEnv("LIB") || @@ -477,12 +109,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT__SLASH_winsysroot)) { CmdArgs.push_back(Args.MakeArgString( Twine("-libpath:") + - TC.getSubDirectoryPath( - toolchains::MSVCToolChain::SubDirectoryType::Lib))); + TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib))); CmdArgs.push_back(Args.MakeArgString( Twine("-libpath:") + - TC.getSubDirectoryPath(toolchains::MSVCToolChain::SubDirectoryType::Lib, - "atlmfc"))); + TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc"))); } if (!llvm::sys::Process::GetEnv("LIB") || Args.getLastArg(options::OPT__SLASH_winsdkdir, @@ -499,6 +129,16 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); } + if (C.getDriver().IsFlangMode()) { + addFortranRuntimeLibraryPath(TC, Args, CmdArgs); + addFortranRuntimeLibs(TC, Args, CmdArgs); + + // Inform the MSVC linker that we're generating a console application, i.e. + // one with `main` as the "user-defined" entry point. The `main` function is + // defined in flang's runtime libraries. + CmdArgs.push_back("/subsystem:console"); + } + // Add the compiler-rt library directories to libpath if they exist to help // the linker find the various sanitizer, builtin, and profiling runtimes. for (const auto &LibPath : TC.getLibraryPaths()) { @@ -587,7 +227,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); // Control Flow Guard checks - if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { + for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) { StringRef GuardArgs = A->getValue(); if (GuardArgs.equals_insensitive("cf") || GuardArgs.equals_insensitive("cf,nochecks")) { @@ -629,6 +269,26 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args); } + StringRef Linker = + Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER); + if (Linker.empty()) + Linker = "link"; + // We need to translate 'lld' into 'lld-link'. + else if (Linker.equals_insensitive("lld")) + Linker = "lld-link"; + + if (Linker == "lld-link") { + for (Arg *A : Args.filtered(options::OPT_vfsoverlay)) + CmdArgs.push_back( + Args.MakeArgString(std::string("/vfsoverlay:") + A->getValue())); + + if (C.getDriver().isUsingLTO() && + Args.hasFlag(options::OPT_gsplit_dwarf, options::OPT_gno_split_dwarf, + false)) + CmdArgs.push_back(Args.MakeArgString(Twine("/dwodir:") + + Output.getFilename() + "_dwo")); + } + // Add filenames, libraries, and other linker inputs. for (const auto &Input : Inputs) { if (Input.isFilename()) { @@ -642,7 +302,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (A.getOption().matches(options::OPT_l)) { StringRef Lib = A.getValue(); const char *LinkLibArg; - if (Lib.endswith(".lib")) + if (Lib.ends_with(".lib")) LinkLibArg = Args.MakeArgString(Lib); else LinkLibArg = Args.MakeArgString(Lib + ".lib"); @@ -655,21 +315,15 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, A.renderAsInput(Args, CmdArgs); } + addHIPRuntimeLibArgs(TC, C, Args, CmdArgs); + TC.addProfileRTLibs(Args, CmdArgs); std::vector<const char *> Environment; - // We need to special case some linker paths. In the case of lld, we need to - // translate 'lld' into 'lld-link', and in the case of the regular msvc + // We need to special case some linker paths. In the case of the regular msvc // linker, we need to use a special search algorithm. llvm::SmallString<128> linkPath; - StringRef Linker - = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER); - if (Linker.empty()) - Linker = "link"; - if (Linker.equals_insensitive("lld")) - Linker = "lld-link"; - if (Linker.equals_insensitive("link")) { // If we're using the MSVC linker, it's not sufficient to just use link // from the program PATH, because other environments like GnuWin32 install @@ -689,13 +343,18 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + // Clang handles passing the proper asan libs to the linker, which goes + // against link.exe's /INFERASANLIBS which automatically finds asan libs. + if (TC.getSanitizerArgs(Args).needsAsanRt()) + CmdArgs.push_back("/INFERASANLIBS:NO"); + #ifdef _WIN32 // When cross-compiling with VS2017 or newer, link.exe expects to have // its containing bin directory at the top of PATH, followed by the // native target bin directory. // e.g. when compiling for x86 on an x64 host, PATH should start with: // /bin/Hostx64/x86;/bin/Hostx64/x64 - // This doesn't attempt to handle ToolsetLayout::DevDivInternal. + // This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal. if (TC.getIsVS2017OrNewer() && llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) { auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch(); @@ -729,14 +388,13 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, // find it. for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) { llvm::StringRef EnvVar(Cursor); - if (EnvVar.startswith_insensitive("path=")) { - using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType; + if (EnvVar.starts_with_insensitive("path=")) { constexpr size_t PrefixLen = 5; // strlen("path=") Environment.push_back(Args.MakeArgString( EnvVar.substr(0, PrefixLen) + - TC.getSubDirectoryPath(SubDirectoryType::Bin) + + TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) + llvm::Twine(llvm::sys::EnvPathSeparator) + - TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) + + TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin, HostArch) + (EnvVar.size() > PrefixLen ? llvm::Twine(llvm::sys::EnvPathSeparator) + EnvVar.substr(PrefixLen) @@ -769,14 +427,29 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); + std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion; + if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir)) + VCToolsDir = A->getValue(); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion)) + VCToolsVersion = A->getValue(); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir)) + WinSdkDir = A->getValue(); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion)) + WinSdkVersion = A->getValue(); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot)) + WinSysRoot = A->getValue(); + // Check the command line first, that's the user explicitly telling us what to // use. Check the environment next, in case we're being invoked from a VS // command prompt. Failing that, just try to find the newest Visual Studio // version we can and use its default VC toolchain. - findVCToolChainViaCommandLine(getVFS(), Args, VCToolChainPath, VSLayout) || - findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, VSLayout) || - findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, VSLayout) || - findVCToolChainViaRegistry(VCToolChainPath, VSLayout); + llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion, + WinSysRoot, VCToolChainPath, VSLayout) || + llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, + VSLayout) || + llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolsVersion, + VCToolChainPath, VSLayout) || + llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout); } Tool *MSVCToolChain::buildLinker() const { @@ -790,20 +463,20 @@ Tool *MSVCToolChain::buildAssembler() const { return nullptr; } -bool MSVCToolChain::IsIntegratedAssemblerDefault() const { - return true; -} - -bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel +MSVCToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const { // Don't emit unwind tables by default for MachO targets. if (getTriple().isOSBinFormatMachO()) - return false; + return UnwindTableLevel::None; // All non-x86_32 Windows targets require unwind tables. However, LLVM // doesn't know how to generate them for all targets, so only enable // the ones that are actually implemented. - return getArch() == llvm::Triple::x86_64 || - getArch() == llvm::Triple::aarch64; + if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm || + getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64) + return UnwindTableLevel::Asynchronous; + + return UnwindTableLevel::None; } bool MSVCToolChain::isPICDefault() const { @@ -822,368 +495,72 @@ bool MSVCToolChain::isPICDefaultForced() const { void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } -void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { - CudaInstallation.print(OS); - RocmInstallation.print(OS); +void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") + + RocmInstallation->getLibPath()), + "amdhip64.lib"}); } -// Get the path to a specific subdirectory in the current toolchain for -// a given target architecture. -// VS2017 changed the VC toolchain layout, so this should be used instead -// of hardcoding paths. -std::string -MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type, - llvm::StringRef SubdirParent, - llvm::Triple::ArchType TargetArch) const { - const char *SubdirName; - const char *IncludeName; - switch (VSLayout) { - case ToolsetLayout::OlderVS: - SubdirName = llvmArchToLegacyVCArch(TargetArch); - IncludeName = "include"; - break; - case ToolsetLayout::VS2017OrNewer: - SubdirName = llvmArchToWindowsSDKArch(TargetArch); - IncludeName = "include"; - break; - case ToolsetLayout::DevDivInternal: - SubdirName = llvmArchToDevDivInternalArch(TargetArch); - IncludeName = "inc"; - break; - } - - llvm::SmallString<256> Path(VCToolChainPath); - if (!SubdirParent.empty()) - llvm::sys::path::append(Path, SubdirParent); - - switch (Type) { - case SubDirectoryType::Bin: - if (VSLayout == ToolsetLayout::VS2017OrNewer) { - const bool HostIsX64 = - llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit(); - const char *const HostName = HostIsX64 ? "Hostx64" : "Hostx86"; - llvm::sys::path::append(Path, "bin", HostName, SubdirName); - } else { // OlderVS or DevDivInternal - llvm::sys::path::append(Path, "bin", SubdirName); - } - break; - case SubDirectoryType::Include: - llvm::sys::path::append(Path, IncludeName); - break; - case SubDirectoryType::Lib: - llvm::sys::path::append(Path, "lib", SubdirName); - break; - } - return std::string(Path.str()); +void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { + CudaInstallation->print(OS); + RocmInstallation->print(OS); } -#ifdef _WIN32 -static bool readFullStringValue(HKEY hkey, const char *valueName, - std::string &value) { - std::wstring WideValueName; - if (!llvm::ConvertUTF8toWide(valueName, WideValueName)) - return false; - - DWORD result = 0; - DWORD valueSize = 0; - DWORD type = 0; - // First just query for the required size. - result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL, - &valueSize); - if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize) - return false; - std::vector<BYTE> buffer(valueSize); - result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0], - &valueSize); - if (result == ERROR_SUCCESS) { - std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()), - valueSize / sizeof(wchar_t)); - if (valueSize && WideValue.back() == L'\0') { - WideValue.pop_back(); - } - // The destination buffer must be empty as an invariant of the conversion - // function; but this function is sometimes called in a loop that passes in - // the same buffer, however. Simply clear it out so we can overwrite it. - value.clear(); - return llvm::convertWideToUTF8(WideValue, value); - } - return false; +std::string +MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type, + llvm::StringRef SubdirParent) const { + return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(), + SubdirParent); } -#endif -/// Read registry string. -/// This also supports a means to look for high-versioned keys by use -/// of a $VERSION placeholder in the key path. -/// $VERSION in the key path is a placeholder for the version number, -/// causing the highest value path to be searched for and used. -/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". -/// There can be additional characters in the component. Only the numeric -/// characters are compared. This function only searches HKLM. -static bool getSystemRegistryString(const char *keyPath, const char *valueName, - std::string &value, std::string *phValue) { -#ifndef _WIN32 - return false; -#else - HKEY hRootKey = HKEY_LOCAL_MACHINE; - HKEY hKey = NULL; - long lResult; - bool returnValue = false; - - const char *placeHolder = strstr(keyPath, "$VERSION"); - std::string bestName; - // If we have a $VERSION placeholder, do the highest-version search. - if (placeHolder) { - const char *keyEnd = placeHolder - 1; - const char *nextKey = placeHolder; - // Find end of previous key. - while ((keyEnd > keyPath) && (*keyEnd != '\\')) - keyEnd--; - // Find end of key containing $VERSION. - while (*nextKey && (*nextKey != '\\')) - nextKey++; - size_t partialKeyLength = keyEnd - keyPath; - char partialKey[256]; - if (partialKeyLength >= sizeof(partialKey)) - partialKeyLength = sizeof(partialKey) - 1; - strncpy(partialKey, keyPath, partialKeyLength); - partialKey[partialKeyLength] = '\0'; - HKEY hTopKey = NULL; - lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY, - &hTopKey); - if (lResult == ERROR_SUCCESS) { - char keyName[256]; - double bestValue = 0.0; - DWORD index, size = sizeof(keyName) - 1; - for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL, - NULL, NULL) == ERROR_SUCCESS; - index++) { - const char *sp = keyName; - while (*sp && !isDigit(*sp)) - sp++; - if (!*sp) - continue; - const char *ep = sp + 1; - while (*ep && (isDigit(*ep) || (*ep == '.'))) - ep++; - char numBuf[32]; - strncpy(numBuf, sp, sizeof(numBuf) - 1); - numBuf[sizeof(numBuf) - 1] = '\0'; - double dvalue = strtod(numBuf, NULL); - if (dvalue > bestValue) { - // Test that InstallDir is indeed there before keeping this index. - // Open the chosen key path remainder. - bestName = keyName; - // Append rest of key. - bestName.append(nextKey); - lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0, - KEY_READ | KEY_WOW64_32KEY, &hKey); - if (lResult == ERROR_SUCCESS) { - if (readFullStringValue(hKey, valueName, value)) { - bestValue = dvalue; - if (phValue) - *phValue = bestName; - returnValue = true; - } - RegCloseKey(hKey); - } - } - size = sizeof(keyName) - 1; - } - RegCloseKey(hTopKey); - } - } else { - lResult = - RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey); - if (lResult == ERROR_SUCCESS) { - if (readFullStringValue(hKey, valueName, value)) - returnValue = true; - if (phValue) - phValue->clear(); - RegCloseKey(hKey); - } - } - return returnValue; -#endif // _WIN32 +std::string +MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type, + llvm::Triple::ArchType TargetArch) const { + return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch, + ""); } // Find the most recent version of Universal CRT or Windows 10 SDK. // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include // directory by name and uses the last one of the list. // So we compare entry names lexicographically to find the greatest one. -static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS, - const std::string &SDKPath, - std::string &SDKVersion) { - llvm::SmallString<128> IncludePath(SDKPath); - llvm::sys::path::append(IncludePath, "Include"); - SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath); - return !SDKVersion.empty(); -} - -static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS, - const ArgList &Args, - std::string &Path, int &Major, - std::string &Version) { - if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir, - options::OPT__SLASH_winsysroot)) { - // Don't validate the input; trust the value supplied by the user. - // The motivation is to prevent unnecessary file and registry access. - llvm::VersionTuple SDKVersion; - if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion)) - SDKVersion.tryParse(A->getValue()); - - if (A->getOption().getID() == options::OPT__SLASH_winsysroot) { - llvm::SmallString<128> SDKPath(A->getValue()); - llvm::sys::path::append(SDKPath, "Windows Kits"); - if (!SDKVersion.empty()) - llvm::sys::path::append(SDKPath, Twine(SDKVersion.getMajor())); - else - llvm::sys::path::append( - SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath)); - Path = std::string(SDKPath.str()); - } else { - Path = A->getValue(); - } - - if (!SDKVersion.empty()) { - Major = SDKVersion.getMajor(); - Version = SDKVersion.getAsString(); - } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) { - Major = 10; - } - return true; - } - return false; -} - -/// Get Windows SDK installation directory. -static bool getWindowsSDKDir(llvm::vfs::FileSystem &VFS, const ArgList &Args, - std::string &Path, int &Major, - std::string &WindowsSDKIncludeVersion, - std::string &WindowsSDKLibVersion) { - // Trust /winsdkdir and /winsdkversion if present. - if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, - WindowsSDKIncludeVersion)) { - WindowsSDKLibVersion = WindowsSDKIncludeVersion; - return true; - } - - // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry. - - // Try the Windows registry. - std::string RegistrySDKVersion; - if (!getSystemRegistryString( - "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", - "InstallationFolder", Path, &RegistrySDKVersion)) - return false; - if (Path.empty() || RegistrySDKVersion.empty()) - return false; - - WindowsSDKIncludeVersion.clear(); - WindowsSDKLibVersion.clear(); - Major = 0; - std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major); - if (Major <= 7) - return true; - if (Major == 8) { - // Windows SDK 8.x installs libraries in a folder whose names depend on the - // version of the OS you're targeting. By default choose the newest, which - // usually corresponds to the version of the OS you've installed the SDK on. - const char *Tests[] = {"winv6.3", "win8", "win7"}; - for (const char *Test : Tests) { - llvm::SmallString<128> TestPath(Path); - llvm::sys::path::append(TestPath, "Lib", Test); - if (VFS.exists(TestPath)) { - WindowsSDKLibVersion = Test; - break; - } - } - return !WindowsSDKLibVersion.empty(); - } - if (Major == 10) { - if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion)) - return false; - WindowsSDKLibVersion = WindowsSDKIncludeVersion; - return true; - } - // Unsupported SDK version - return false; -} - // Gets the library path required to link against the Windows SDK. -bool MSVCToolChain::getWindowsSDKLibraryPath( - const ArgList &Args, std::string &path) const { +bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args, + std::string &path) const { std::string sdkPath; int sdkMajor = 0; std::string windowsSDKIncludeVersion; std::string windowsSDKLibVersion; path.clear(); - if (!getWindowsSDKDir(getVFS(), Args, sdkPath, sdkMajor, - windowsSDKIncludeVersion, windowsSDKLibVersion)) + if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot, + sdkPath, sdkMajor, windowsSDKIncludeVersion, + windowsSDKLibVersion)) return false; llvm::SmallString<128> libPath(sdkPath); llvm::sys::path::append(libPath, "Lib"); - if (sdkMajor >= 8) { - llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", - llvmArchToWindowsSDKArch(getArch())); - } else { - switch (getArch()) { - // In Windows SDK 7.x, x86 libraries are directly in the Lib folder. - case llvm::Triple::x86: - break; - case llvm::Triple::x86_64: - llvm::sys::path::append(libPath, "x64"); - break; - case llvm::Triple::arm: - // It is not necessary to link against Windows SDK 7.x when targeting ARM. - return false; - default: - return false; - } - } - - path = std::string(libPath.str()); - return true; + if (sdkMajor >= 10) + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + windowsSDKLibVersion = *WinSdkVersion; + if (sdkMajor >= 8) + llvm::sys::path::append(libPath, windowsSDKLibVersion, "um"); + return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(), + path); } -// Check if the Include path of a specified version of Visual Studio contains -// specific header files. If not, they are probably shipped with Universal CRT. bool MSVCToolChain::useUniversalCRT() const { - llvm::SmallString<128> TestPath( - getSubDirectoryPath(SubDirectoryType::Include)); - llvm::sys::path::append(TestPath, "stdlib.h"); - return !getVFS().exists(TestPath); -} - -static bool getUniversalCRTSdkDir(llvm::vfs::FileSystem &VFS, - const ArgList &Args, std::string &Path, - std::string &UCRTVersion) { - // If /winsdkdir is passed, use it as location for the UCRT too. - // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir? - int Major; - if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, UCRTVersion)) - return true; - - // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to - // registry. - - // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry - // for the specific key "KitsRoot10". So do we. - if (!getSystemRegistryString( - "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", - Path, nullptr)) - return false; - - return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion); + return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS()); } bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args, @@ -1192,17 +569,23 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args, std::string UCRTVersion; Path.clear(); - if (!getUniversalCRTSdkDir(getVFS(), Args, UniversalCRTSdkPath, UCRTVersion)) + if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion, + WinSysRoot, UniversalCRTSdkPath, + UCRTVersion)) return false; - StringRef ArchName = llvmArchToWindowsSDKArch(getArch()); + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + UCRTVersion = *WinSdkVersion; + + StringRef ArchName = llvm::archToWindowsSDKArch(getArch()); if (ArchName.empty()) return false; llvm::SmallString<128> LibPath(UniversalCRTSdkPath); llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName); - Path = std::string(LibPath.str()); + Path = std::string(LibPath); return true; } @@ -1313,15 +696,20 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // the correct include paths first. if (!VCToolChainPath.empty()) { addSystemInclude(DriverArgs, CC1Args, - getSubDirectoryPath(SubDirectoryType::Include)); - addSystemInclude(DriverArgs, CC1Args, - getSubDirectoryPath(SubDirectoryType::Include, "atlmfc")); + getSubDirectoryPath(llvm::SubDirectoryType::Include)); + addSystemInclude( + DriverArgs, CC1Args, + getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc")); if (useUniversalCRT()) { std::string UniversalCRTSdkPath; std::string UCRTVersion; - if (getUniversalCRTSdkDir(getVFS(), DriverArgs, UniversalCRTSdkPath, - UCRTVersion)) { + if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion, + WinSysRoot, UniversalCRTSdkPath, + UCRTVersion)) { + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + UCRTVersion = *WinSdkVersion; AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, "Include", UCRTVersion, "ucrt"); } @@ -1331,8 +719,13 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, int major = 0; std::string windowsSDKIncludeVersion; std::string windowsSDKLibVersion; - if (getWindowsSDKDir(getVFS(), DriverArgs, WindowsSDKDir, major, - windowsSDKIncludeVersion, windowsSDKLibVersion)) { + if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot, + WindowsSDKDir, major, windowsSDKIncludeVersion, + windowsSDKLibVersion)) { + if (major >= 10) + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + windowsSDKIncludeVersion = windowsSDKLibVersion = *WinSdkVersion; if (major >= 8) { // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. // Anyway, llvm::sys::path::append is able to manage it. @@ -1348,7 +741,7 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (major >= 10) { llvm::VersionTuple Tuple; if (!Tuple.tryParse(windowsSDKIncludeVersion) && - Tuple.getSubminor().getValueOr(0) >= 17134) { + Tuple.getSubminor().value_or(0) >= 17134) { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "Include", windowsSDKIncludeVersion, "cppwinrt"); @@ -1389,12 +782,16 @@ VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D, if (MSVT.empty()) MSVT = getTriple().getEnvironmentVersion(); if (MSVT.empty() && IsWindowsMSVC) - MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin)); + MSVT = + getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin)); if (MSVT.empty() && Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) { - // -fms-compatibility-version=19.20 is default, aka 2019, 16.x - MSVT = VersionTuple(19, 20); + // -fms-compatibility-version=19.33 is default, aka 2022, 17.3 + // NOTE: when changing this value, also update + // clang/docs/CommandGuide/clang.rst and clang/docs/UsersManual.rst + // accordingly. + MSVT = VersionTuple(19, 33); } return MSVT; } @@ -1405,8 +802,8 @@ MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, // The MSVC version doesn't care about the architecture, even though it // may look at the triple internally. VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args); - MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0), - MSVT.getSubminor().getValueOr(0)); + MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().value_or(0), + MSVT.getSubminor().value_or(0)); // For the rest of the triple, however, a computed architecture name may // be needed. @@ -1619,7 +1016,7 @@ void MSVCToolChain::addClangTargetOptions( Action::OffloadKind DeviceOffloadKind) const { // MSVC STL kindly allows removing all usages of typeid by defining // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti - if (DriverArgs.hasArg(options::OPT_fno_rtti, options::OPT_frtti, - /*Default=*/false)) + if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti, + /*Default=*/false)) CC1Args.push_back("-D_HAS_STATIC_RTTI=0"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h index c842773996ed..48369e030aad 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h @@ -11,10 +11,12 @@ #include "AMDGPU.h" #include "Cuda.h" -#include "clang/Basic/DebugInfoOptions.h" +#include "LazyDetector.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/Frontend/Debug/Options.h" +#include "llvm/WindowsDriver/MSVCPaths.h" namespace clang { namespace driver { @@ -22,7 +24,7 @@ namespace tools { /// Visual studio tools. namespace visualstudio { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("visualstudio::Linker", "linker", TC) {} @@ -49,8 +51,8 @@ public: TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; - bool IsIntegratedAssemblerDefault() const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; @@ -58,9 +60,10 @@ public: /// Set CodeView as the default debug info format for non-MachO binary /// formats, and to DWARF otherwise. Users can use -gcodeview and -gdwarf to /// override the default. - codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override { - return getTriple().isOSBinFormatMachO() ? codegenoptions::DIF_DWARF - : codegenoptions::DIF_CodeView; + llvm::codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override { + return getTriple().isOSBinFormatMachO() + ? llvm::codegenoptions::DIF_DWARF + : llvm::codegenoptions::DIF_CodeView; } /// Set the debugger tuning to "default", since we're definitely not tuning @@ -73,29 +76,15 @@ public: return 4; } - enum class SubDirectoryType { - Bin, - Include, - Lib, - }; - std::string getSubDirectoryPath(SubDirectoryType Type, - llvm::StringRef SubdirParent, + std::string getSubDirectoryPath(llvm::SubDirectoryType Type, + llvm::StringRef SubdirParent = "") const; + std::string getSubDirectoryPath(llvm::SubDirectoryType Type, llvm::Triple::ArchType TargetArch) const; - // Convenience overload. - // Uses the current target arch. - std::string getSubDirectoryPath(SubDirectoryType Type, - llvm::StringRef SubdirParent = "") const { - return getSubDirectoryPath(Type, SubdirParent, getArch()); + bool getIsVS2017OrNewer() const { + return VSLayout == llvm::ToolsetLayout::VS2017OrNewer; } - enum class ToolsetLayout { - OlderVS, - VS2017OrNewer, - DevDivInternal, - }; - bool getIsVS2017OrNewer() const { return VSLayout == ToolsetLayout::VS2017OrNewer; } - void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -109,6 +98,9 @@ public: void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPRuntimeLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + bool getWindowsSDKLibraryPath( const llvm::opt::ArgList &Args, std::string &path) const; bool getUniversalCRTLibraryPath(const llvm::opt::ArgList &Args, @@ -142,10 +134,11 @@ protected: Tool *buildLinker() const override; Tool *buildAssembler() const override; private: + std::optional<llvm::StringRef> WinSdkDir, WinSdkVersion, WinSysRoot; std::string VCToolChainPath; - ToolsetLayout VSLayout = ToolsetLayout::OlderVS; - CudaInstallationDetector CudaInstallation; - RocmInstallationDetector RocmInstallation; + llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS; + LazyDetector<CudaInstallationDetector> CudaInstallation; + LazyDetector<RocmInstallationDetector> RocmInstallation; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h deleted file mode 100644 index 28e6e3e08e37..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h +++ /dev/null @@ -1,523 +0,0 @@ -// <copyright file="Program.cpp" company="Microsoft Corporation"> -// Copyright (C) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. -// </copyright> -// <license> -// The MIT License (MIT) -// -// Copyright (C) Microsoft Corporation. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// </license> - -#pragma once - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-virtual-dtor" -#endif - -// Constants -// -#ifndef E_NOTFOUND -#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND) -#endif - -#ifndef E_FILENOTFOUND -#define E_FILENOTFOUND HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) -#endif - -// Enumerations -// -/// <summary> -/// The state of an instance. -/// </summary> -enum InstanceState : unsigned { - /// <summary> - /// The instance state has not been determined. - /// </summary> - eNone = 0, - - /// <summary> - /// The instance installation path exists. - /// </summary> - eLocal = 1, - - /// <summary> - /// A product is registered to the instance. - /// </summary> - eRegistered = 2, - - /// <summary> - /// No reboot is required for the instance. - /// </summary> - eNoRebootRequired = 4, - - /// <summary> - /// The instance represents a complete install. - /// </summary> - eComplete = MAXUINT, -}; - -// Forward interface declarations -// -#ifndef __ISetupInstance_FWD_DEFINED__ -#define __ISetupInstance_FWD_DEFINED__ -typedef struct ISetupInstance ISetupInstance; -#endif - -#ifndef __ISetupInstance2_FWD_DEFINED__ -#define __ISetupInstance2_FWD_DEFINED__ -typedef struct ISetupInstance2 ISetupInstance2; -#endif - -#ifndef __IEnumSetupInstances_FWD_DEFINED__ -#define __IEnumSetupInstances_FWD_DEFINED__ -typedef struct IEnumSetupInstances IEnumSetupInstances; -#endif - -#ifndef __ISetupConfiguration_FWD_DEFINED__ -#define __ISetupConfiguration_FWD_DEFINED__ -typedef struct ISetupConfiguration ISetupConfiguration; -#endif - -#ifndef __ISetupConfiguration2_FWD_DEFINED__ -#define __ISetupConfiguration2_FWD_DEFINED__ -typedef struct ISetupConfiguration2 ISetupConfiguration2; -#endif - -#ifndef __ISetupPackageReference_FWD_DEFINED__ -#define __ISetupPackageReference_FWD_DEFINED__ -typedef struct ISetupPackageReference ISetupPackageReference; -#endif - -#ifndef __ISetupHelper_FWD_DEFINED__ -#define __ISetupHelper_FWD_DEFINED__ -typedef struct ISetupHelper ISetupHelper; -#endif - -// Forward class declarations -// -#ifndef __SetupConfiguration_FWD_DEFINED__ -#define __SetupConfiguration_FWD_DEFINED__ - -#ifdef __cplusplus -typedef class SetupConfiguration SetupConfiguration; -#endif - -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// Interface definitions -// -EXTERN_C const IID IID_ISetupInstance; - -#if defined(__cplusplus) && !defined(CINTERFACE) -/// <summary> -/// Information about an instance of a product. -/// </summary> -struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E") - DECLSPEC_NOVTABLE ISetupInstance : public IUnknown { - /// <summary> - /// Gets the instance identifier (should match the name of the parent instance - /// directory). - /// </summary> - /// <param name="pbstrInstanceId">The instance identifier.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist.</returns> - STDMETHOD(GetInstanceId)(_Out_ BSTR *pbstrInstanceId) = 0; - - /// <summary> - /// Gets the local date and time when the installation was originally - /// installed. - /// </summary> - /// <param name="pInstallDate">The local date and time when the installation - /// was originally installed.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the - /// property is not defined.</returns> - STDMETHOD(GetInstallDate)(_Out_ LPFILETIME pInstallDate) = 0; - - /// <summary> - /// Gets the unique name of the installation, often indicating the branch and - /// other information used for telemetry. - /// </summary> - /// <param name="pbstrInstallationName">The unique name of the installation, - /// often indicating the branch and other information used for - /// telemetry.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the - /// property is not defined.</returns> - STDMETHOD(GetInstallationName)(_Out_ BSTR *pbstrInstallationName) = 0; - - /// <summary> - /// Gets the path to the installation root of the product. - /// </summary> - /// <param name="pbstrInstallationPath">The path to the installation root of - /// the product.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the - /// property is not defined.</returns> - STDMETHOD(GetInstallationPath)(_Out_ BSTR *pbstrInstallationPath) = 0; - - /// <summary> - /// Gets the version of the product installed in this instance. - /// </summary> - /// <param name="pbstrInstallationVersion">The version of the product - /// installed in this instance.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the - /// property is not defined.</returns> - STDMETHOD(GetInstallationVersion)(_Out_ BSTR *pbstrInstallationVersion) = 0; - - /// <summary> - /// Gets the display name (title) of the product installed in this instance. - /// </summary> - /// <param name="lcid">The LCID for the display name.</param> - /// <param name="pbstrDisplayName">The display name (title) of the product - /// installed in this instance.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the - /// property is not defined.</returns> - STDMETHOD(GetDisplayName)(_In_ LCID lcid, _Out_ BSTR *pbstrDisplayName) = 0; - - /// <summary> - /// Gets the description of the product installed in this instance. - /// </summary> - /// <param name="lcid">The LCID for the description.</param> - /// <param name="pbstrDescription">The description of the product installed in - /// this instance.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the - /// property is not defined.</returns> - STDMETHOD(GetDescription)(_In_ LCID lcid, _Out_ BSTR *pbstrDescription) = 0; - - /// <summary> - /// Resolves the optional relative path to the root path of the instance. - /// </summary> - /// <param name="pwszRelativePath">A relative path within the instance to - /// resolve, or NULL to get the root path.</param> - /// <param name="pbstrAbsolutePath">The full path to the optional relative - /// path within the instance. If the relative path is NULL, the root path will - /// always terminate in a backslash.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the - /// property is not defined.</returns> - STDMETHOD(ResolvePath) - (_In_opt_z_ LPCOLESTR pwszRelativePath, _Out_ BSTR *pbstrAbsolutePath) = 0; -}; -#endif - -EXTERN_C const IID IID_ISetupInstance2; - -#if defined(__cplusplus) && !defined(CINTERFACE) -/// <summary> -/// Information about an instance of a product. -/// </summary> -struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C") - DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance { - /// <summary> - /// Gets the state of the instance. - /// </summary> - /// <param name="pState">The state of the instance.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist.</returns> - STDMETHOD(GetState)(_Out_ InstanceState *pState) = 0; - - /// <summary> - /// Gets an array of package references registered to the instance. - /// </summary> - /// <param name="ppsaPackages">Pointer to an array of <see - /// cref="ISetupPackageReference"/>.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the - /// packages property is not defined.</returns> - STDMETHOD(GetPackages)(_Out_ LPSAFEARRAY *ppsaPackages) = 0; - - /// <summary> - /// Gets a pointer to the <see cref="ISetupPackageReference"/> that represents - /// the registered product. - /// </summary> - /// <param name="ppPackage">Pointer to an instance of <see - /// cref="ISetupPackageReference"/>. This may be NULL if <see - /// cref="GetState"/> does not return <see cref="eComplete"/>.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the - /// packages property is not defined.</returns> - STDMETHOD(GetProduct) - (_Outptr_result_maybenull_ ISetupPackageReference **ppPackage) = 0; - - /// <summary> - /// Gets the relative path to the product application, if available. - /// </summary> - /// <param name="pbstrProductPath">The relative path to the product - /// application, if available.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_FILENOTFOUND if the instance state does not exist.</returns> - STDMETHOD(GetProductPath) - (_Outptr_result_maybenull_ BSTR *pbstrProductPath) = 0; -}; -#endif - -EXTERN_C const IID IID_IEnumSetupInstances; - -#if defined(__cplusplus) && !defined(CINTERFACE) -/// <summary> -/// A enumerator of installed <see cref="ISetupInstance"/> objects. -/// </summary> -struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") - DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown { - /// <summary> - /// Retrieves the next set of product instances in the enumeration sequence. - /// </summary> - /// <param name="celt">The number of product instances to retrieve.</param> - /// <param name="rgelt">A pointer to an array of <see - /// cref="ISetupInstance"/>.</param> - /// <param name="pceltFetched">A pointer to the number of product instances - /// retrieved. If celt is 1 this parameter may be NULL.</param> - /// <returns>S_OK if the number of elements were fetched, S_FALSE if nothing - /// was fetched (at end of enumeration), E_INVALIDARG if celt is greater than - /// 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an <see - /// cref="ISetupInstance"/> could not be allocated.</returns> - STDMETHOD(Next) - (_In_ ULONG celt, _Out_writes_to_(celt, *pceltFetched) ISetupInstance **rgelt, - _Out_opt_ _Deref_out_range_(0, celt) ULONG *pceltFetched) = 0; - - /// <summary> - /// Skips the next set of product instances in the enumeration sequence. - /// </summary> - /// <param name="celt">The number of product instances to skip.</param> - /// <returns>S_OK if the number of elements could be skipped; otherwise, - /// S_FALSE;</returns> - STDMETHOD(Skip)(_In_ ULONG celt) = 0; - - /// <summary> - /// Resets the enumeration sequence to the beginning. - /// </summary> - /// <returns>Always returns S_OK;</returns> - STDMETHOD(Reset)(void) = 0; - - /// <summary> - /// Creates a new enumeration object in the same state as the current - /// enumeration object: the new object points to the same place in the - /// enumeration sequence. - /// </summary> - /// <param name="ppenum">A pointer to a pointer to a new <see - /// cref="IEnumSetupInstances"/> interface. If the method fails, this - /// parameter is undefined.</param> - /// <returns>S_OK if a clone was returned; otherwise, E_OUTOFMEMORY.</returns> - STDMETHOD(Clone)(_Deref_out_opt_ IEnumSetupInstances **ppenum) = 0; -}; -#endif - -EXTERN_C const IID IID_ISetupConfiguration; - -#if defined(__cplusplus) && !defined(CINTERFACE) -/// <summary> -/// Gets information about product instances set up on the machine. -/// </summary> -struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") - DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown { - /// <summary> - /// Enumerates all completed product instances installed. - /// </summary> - /// <param name="ppEnumInstances">An enumeration of completed, installed - /// product instances.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(EnumInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0; - - /// <summary> - /// Gets the instance for the current process path. - /// </summary> - /// <param name="ppInstance">The instance for the current process - /// path.</param> - /// <returns>The instance for the current process path, or E_NOTFOUND if not - /// found.</returns> - STDMETHOD(GetInstanceForCurrentProcess) - (_Out_ ISetupInstance **ppInstance) = 0; - - /// <summary> - /// Gets the instance for the given path. - /// </summary> - /// <param name="ppInstance">The instance for the given path.</param> - /// <returns>The instance for the given path, or E_NOTFOUND if not - /// found.</returns> - STDMETHOD(GetInstanceForPath) - (_In_z_ LPCWSTR wzPath, _Out_ ISetupInstance **ppInstance) = 0; -}; -#endif - -EXTERN_C const IID IID_ISetupConfiguration2; - -#if defined(__cplusplus) && !defined(CINTERFACE) -/// <summary> -/// Gets information about product instances. -/// </summary> -struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D") - DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration { - /// <summary> - /// Enumerates all product instances. - /// </summary> - /// <param name="ppEnumInstances">An enumeration of all product - /// instances.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(EnumAllInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0; -}; -#endif - -EXTERN_C const IID IID_ISetupPackageReference; - -#if defined(__cplusplus) && !defined(CINTERFACE) -/// <summary> -/// A reference to a package. -/// </summary> -struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5") - DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown { - /// <summary> - /// Gets the general package identifier. - /// </summary> - /// <param name="pbstrId">The general package identifier.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(GetId)(_Out_ BSTR *pbstrId) = 0; - - /// <summary> - /// Gets the version of the package. - /// </summary> - /// <param name="pbstrVersion">The version of the package.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(GetVersion)(_Out_ BSTR *pbstrVersion) = 0; - - /// <summary> - /// Gets the target process architecture of the package. - /// </summary> - /// <param name="pbstrChip">The target process architecture of the - /// package.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(GetChip)(_Out_ BSTR *pbstrChip) = 0; - - /// <summary> - /// Gets the language and optional region identifier. - /// </summary> - /// <param name="pbstrLanguage">The language and optional region - /// identifier.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(GetLanguage)(_Out_ BSTR *pbstrLanguage) = 0; - - /// <summary> - /// Gets the build branch of the package. - /// </summary> - /// <param name="pbstrBranch">The build branch of the package.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(GetBranch)(_Out_ BSTR *pbstrBranch) = 0; - - /// <summary> - /// Gets the type of the package. - /// </summary> - /// <param name="pbstrType">The type of the package.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(GetType)(_Out_ BSTR *pbstrType) = 0; - - /// <summary> - /// Gets the unique identifier consisting of all defined tokens. - /// </summary> - /// <param name="pbstrUniqueId">The unique identifier consisting of all - /// defined tokens.</param> - /// <returns>Standard HRESULT indicating success or failure, including - /// E_UNEXPECTED if no Id was defined (required).</returns> - STDMETHOD(GetUniqueId)(_Out_ BSTR *pbstrUniqueId) = 0; -}; -#endif - -EXTERN_C const IID IID_ISetupHelper; - -#if defined(__cplusplus) && !defined(CINTERFACE) -/// <summary> -/// Helper functions. -/// </summary> -/// <remarks> -/// You can query for this interface from the <see cref="SetupConfiguration"/> -/// class. -/// </remarks> -struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c") - DECLSPEC_NOVTABLE ISetupHelper : public IUnknown { - /// <summary> - /// Parses a dotted quad version string into a 64-bit unsigned integer. - /// </summary> - /// <param name="pwszVersion">The dotted quad version string to parse, e.g. - /// 1.2.3.4.</param> - /// <param name="pullVersion">A 64-bit unsigned integer representing the - /// version. You can compare this to other versions.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(ParseVersion) - (_In_ LPCOLESTR pwszVersion, _Out_ PULONGLONG pullVersion) = 0; - - /// <summary> - /// Parses a dotted quad version string into a 64-bit unsigned integer. - /// </summary> - /// <param name="pwszVersionRange">The string containing 1 or 2 dotted quad - /// version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer.</param> - /// <param name="pullMinVersion">A 64-bit unsigned integer representing the - /// minimum version, which may be 0. You can compare this to other - /// versions.</param> - /// <param name="pullMaxVersion">A 64-bit unsigned integer representing the - /// maximum version, which may be MAXULONGLONG. You can compare this to other - /// versions.</param> - /// <returns>Standard HRESULT indicating success or failure.</returns> - STDMETHOD(ParseVersionRange) - (_In_ LPCOLESTR pwszVersionRange, _Out_ PULONGLONG pullMinVersion, - _Out_ PULONGLONG pullMaxVersion) = 0; -}; -#endif - -// Class declarations -// -EXTERN_C const CLSID CLSID_SetupConfiguration; - -#ifdef __cplusplus -/// <summary> -/// This class implements <see cref="ISetupConfiguration"/>, <see -/// cref="ISetupConfiguration2"/>, and <see cref="ISetupHelper"/>. -/// </summary> -class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration; -#endif - -// Function declarations -// -/// <summary> -/// Gets an <see cref="ISetupConfiguration"/> that provides information about -/// product instances installed on the machine. -/// </summary> -/// <param name="ppConfiguration">The <see cref="ISetupConfiguration"/> that -/// provides information about product instances installed on the -/// machine.</param> -/// <param name="pReserved">Reserved for future use.</param> -/// <returns>Standard HRESULT indicating success or failure.</returns> -STDMETHODIMP GetSetupConfiguration(_Out_ ISetupConfiguration **ppConfiguration, - _Reserved_ LPVOID pReserved); - -#ifdef __cplusplus -} -#endif - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp index ceeaa79bc202..067758c05e97 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp @@ -86,9 +86,9 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, CmdArgs.push_back("-lmoldname"); CmdArgs.push_back("-lmingwex"); for (auto Lib : Args.getAllArgValues(options::OPT_l)) - if (StringRef(Lib).startswith("msvcr") || - StringRef(Lib).startswith("ucrt") || - StringRef(Lib).startswith("crtdll")) + if (StringRef(Lib).starts_with("msvcr") || + StringRef(Lib).starts_with("ucrt") || + StringRef(Lib).starts_with("crtdll")) return; CmdArgs.push_back("-lmsvcrt"); } @@ -135,7 +135,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("arm64pe"); break; default: - llvm_unreachable("Unsupported target architecture."); + D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str(); } Arg *SubsysArg = @@ -169,6 +169,21 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); + if (!Args.hasFlag(options::OPT_fauto_import, options::OPT_fno_auto_import, + true)) + CmdArgs.push_back("--disable-auto-import"); + + if (Arg *A = Args.getLastArg(options::OPT_mguard_EQ)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs == "none") + CmdArgs.push_back("--no-guard-cf"); + else if (GuardArgs == "cf" || GuardArgs == "cf-nochecks") + CmdArgs.push_back("--guard-cf"); + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << GuardArgs; + } + CmdArgs.push_back("-o"); const char *OutputFile = Output.getFilename(); // GCC implicitly adds an .exe extension if it is given an output file name @@ -181,13 +196,21 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, } else CmdArgs.push_back(OutputFile); - Args.AddAllArgs(CmdArgs, options::OPT_e); // FIXME: add -N, -n flags Args.AddLastArg(CmdArgs, options::OPT_r); Args.AddLastArg(CmdArgs, options::OPT_s); Args.AddLastArg(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_u_Group); - Args.AddLastArg(CmdArgs, options::OPT_Z_Flag); + + // Add asan_dynamic as the first import lib before other libs. This allows + // asan to be initialized as early as possible to increase its instrumentation + // coverage to include other user DLLs which has not been built with asan. + if (Sanitize.needsAsanRt() && !Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + // MinGW always links against a shared MSVCRT. + CmdArgs.push_back( + TC.getCompilerRTArgString(Args, "asan_dynamic", ToolChain::FT_Shared)); + } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) { @@ -218,6 +241,17 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + addLTOOptions(TC, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } + + if (C.getDriver().IsFlangMode()) { + addFortranRuntimeLibraryPath(TC, Args, CmdArgs); + addFortranRuntimeLibs(TC, Args, CmdArgs); + } + // TODO: Add profile stuff here if (TC.ShouldLinkCXXStdlib(Args)) { @@ -332,10 +366,20 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, Exec, CmdArgs, Inputs, Output)); } +static bool isCrossCompiling(const llvm::Triple &T, bool RequireArchMatch) { + llvm::Triple HostTriple(llvm::Triple::normalize(LLVM_HOST_TRIPLE)); + if (HostTriple.getOS() != llvm::Triple::Win32) + return true; + if (RequireArchMatch && HostTriple.getArch() != T.getArch()) + return true; + return false; +} + // Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple. static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, - std::string &Ver) { - auto Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0"); + std::string &Ver, + toolchains::Generic_GCC::GCCVersion &Version) { + Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0"); std::error_code EC; for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { @@ -353,20 +397,33 @@ static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, return Ver.size(); } -void toolchains::MinGW::findGccLibDir() { - llvm::SmallVector<llvm::SmallString<32>, 2> SubdirNames; +static llvm::Triple getLiteralTriple(const Driver &D, const llvm::Triple &T) { + llvm::Triple LiteralTriple(D.getTargetTriple()); + // The arch portion of the triple may be overridden by -m32/-m64. + LiteralTriple.setArchName(T.getArchName()); + return LiteralTriple; +} + +void toolchains::MinGW::findGccLibDir(const llvm::Triple &LiteralTriple) { + llvm::SmallVector<llvm::SmallString<32>, 5> SubdirNames; + SubdirNames.emplace_back(LiteralTriple.str()); + SubdirNames.emplace_back(getTriple().str()); SubdirNames.emplace_back(getTriple().getArchName()); - SubdirNames[0] += "-w64-mingw32"; + SubdirNames.back() += "-w64-mingw32"; + SubdirNames.emplace_back(getTriple().getArchName()); + SubdirNames.back() += "-w64-mingw32ucrt"; SubdirNames.emplace_back("mingw32"); - if (SubdirName.empty()) - SubdirName = std::string(SubdirNames[0].str()); + if (SubdirName.empty()) { + SubdirName = getTriple().getArchName(); + SubdirName += "-w64-mingw32"; + } // lib: Arch Linux, Ubuntu, Windows // lib64: openSUSE Linux for (StringRef CandidateLib : {"lib", "lib64"}) { for (StringRef CandidateSysroot : SubdirNames) { llvm::SmallString<1024> LibDir(Base); llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot); - if (findGccVersion(LibDir, GccLibDir, Ver)) { + if (findGccVersion(LibDir, GccLibDir, Ver, GccVer)) { SubdirName = std::string(CandidateSysroot); return; } @@ -374,10 +431,17 @@ void toolchains::MinGW::findGccLibDir() { } } -static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &T) { - llvm::SmallVector<llvm::SmallString<32>, 2> Gccs; +static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &LiteralTriple, + const llvm::Triple &T) { + llvm::SmallVector<llvm::SmallString<32>, 5> Gccs; + Gccs.emplace_back(LiteralTriple.str()); + Gccs.back() += "-gcc"; + Gccs.emplace_back(T.str()); + Gccs.back() += "-gcc"; + Gccs.emplace_back(T.getArchName()); + Gccs.back() += "-w64-mingw32-gcc"; Gccs.emplace_back(T.getArchName()); - Gccs[0] += "-w64-mingw32-gcc"; + Gccs.back() += "-w64-mingw32ucrt-gcc"; Gccs.emplace_back("mingw32-gcc"); // Please do not add "gcc" here for (StringRef CandidateGcc : Gccs) @@ -387,12 +451,15 @@ static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &T) { } static llvm::ErrorOr<std::string> -findClangRelativeSysroot(const Driver &D, const llvm::Triple &T, - std::string &SubdirName) { - llvm::SmallVector<llvm::SmallString<32>, 2> Subdirs; +findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple, + const llvm::Triple &T, std::string &SubdirName) { + llvm::SmallVector<llvm::SmallString<32>, 4> Subdirs; + Subdirs.emplace_back(LiteralTriple.str()); Subdirs.emplace_back(T.str()); Subdirs.emplace_back(T.getArchName()); - Subdirs[1] += "-w64-mingw32"; + Subdirs.back() += "-w64-mingw32"; + Subdirs.emplace_back(T.getArchName()); + Subdirs.back() += "-w64-mingw32ucrt"; StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir()); StringRef Sep = llvm::sys::path::get_separator(); for (StringRef CandidateSubdir : Subdirs) { @@ -404,46 +471,77 @@ findClangRelativeSysroot(const Driver &D, const llvm::Triple &T, return make_error_code(std::errc::no_such_file_or_directory); } +static bool looksLikeMinGWSysroot(const std::string &Directory) { + StringRef Sep = llvm::sys::path::get_separator(); + if (!llvm::sys::fs::exists(Directory + Sep + "include" + Sep + "_mingw.h")) + return false; + if (!llvm::sys::fs::exists(Directory + Sep + "lib" + Sep + "libkernel32.a")) + return false; + return true; +} + toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); + std::string InstallBase = + std::string(llvm::sys::path::parent_path(getDriver().getInstalledDir())); // The sequence for detecting a sysroot here should be kept in sync with // the testTriple function below. + llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple()); if (getDriver().SysRoot.size()) Base = getDriver().SysRoot; // Look for <clang-bin>/../<triplet>; if found, use <clang-bin>/.. as the // base as it could still be a base for a gcc setup with libgcc. - else if (llvm::ErrorOr<std::string> TargetSubdir = - findClangRelativeSysroot(getDriver(), getTriple(), SubdirName)) + else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot( + getDriver(), LiteralTriple, getTriple(), SubdirName)) Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); - else if (llvm::ErrorOr<std::string> GPPName = findGcc(getTriple())) + // If the install base of Clang seems to have mingw sysroot files directly + // in the toplevel include and lib directories, use this as base instead of + // looking for a triple prefixed GCC in the path. + else if (looksLikeMinGWSysroot(InstallBase)) + Base = InstallBase; + else if (llvm::ErrorOr<std::string> GPPName = + findGcc(LiteralTriple, getTriple())) Base = std::string(llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get()))); else - Base = std::string( - llvm::sys::path::parent_path(getDriver().getInstalledDir())); + Base = InstallBase; Base += llvm::sys::path::get_separator(); - findGccLibDir(); + findGccLibDir(LiteralTriple); + TripleDirName = SubdirName; // GccLibDir must precede Base/lib so that the // correct crtbegin.o ,cetend.o would be found. getFilePaths().push_back(GccLibDir); + + // openSUSE/Fedora + std::string CandidateSubdir = SubdirName + "/sys-root/mingw"; + if (getDriver().getVFS().exists(Base + CandidateSubdir)) + SubdirName = CandidateSubdir; + getFilePaths().push_back( (Base + SubdirName + llvm::sys::path::get_separator() + "lib").str()); - getFilePaths().push_back(Base + "lib"); - // openSUSE - getFilePaths().push_back(Base + SubdirName + "/sys-root/mingw/lib"); + + // Gentoo + getFilePaths().push_back( + (Base + SubdirName + llvm::sys::path::get_separator() + "mingw/lib").str()); + + // Only include <base>/lib if we're not cross compiling (not even for + // windows->windows to a different arch), or if the sysroot has been set + // (where we presume the user has pointed it at an arch specific + // subdirectory). + if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/true) || + getDriver().SysRoot.size()) + getFilePaths().push_back(Base + "lib"); NativeLLVMSupport = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER) .equals_insensitive("lld"); } -bool toolchains::MinGW::IsIntegratedAssemblerDefault() const { return true; } - Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const { switch (AC) { case Action::PreprocessJobClass: @@ -471,15 +569,19 @@ bool toolchains::MinGW::HasNativeLLVMSupport() const { return NativeLLVMSupport; } -bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel +toolchains::MinGW::getDefaultUnwindTableLevel(const ArgList &Args) const { Arg *ExceptionArg = Args.getLastArg(options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions, options::OPT_fdwarf_exceptions); if (ExceptionArg && ExceptionArg->getOption().matches(options::OPT_fseh_exceptions)) - return true; - return getArch() == llvm::Triple::x86_64 || - getArch() == llvm::Triple::aarch64; + return UnwindTableLevel::Asynchronous; + + if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm || + getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64) + return UnwindTableLevel::Asynchronous; + return UnwindTableLevel::None; } bool toolchains::MinGW::isPICDefault() const { @@ -495,7 +597,8 @@ bool toolchains::MinGW::isPICDefaultForced() const { return true; } llvm::ExceptionHandling toolchains::MinGW::GetExceptionModel(const ArgList &Args) const { - if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64) + if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64 || + getArch() == llvm::Triple::arm || getArch() == llvm::Triple::thumb) return llvm::ExceptionHandling::WinEH; return llvm::ExceptionHandling::DwarfCFI; } @@ -511,17 +614,17 @@ SanitizerMask toolchains::MinGW::getSupportedSanitizers() const { void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void toolchains::MinGW::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const { - CudaInstallation.print(OS); - RocmInstallation.print(OS); + CudaInstallation->print(OS); + RocmInstallation->print(OS); } // Include directories for various hosts: @@ -564,6 +667,12 @@ void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const { // /usr/include/c++/4.8/backward // /usr/x86_64-w64-mingw32/include +// Fedora +// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/x86_64-w64-mingw32ucrt +// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/backward +// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include +// /usr/lib/gcc/x86_64-w64-mingw32ucrt/12.2.1/include-fixed + void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc)) @@ -578,22 +687,55 @@ void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; - if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) { - // openSUSE - addSystemInclude(DriverArgs, CC1Args, - Base + SubdirName + "/sys-root/mingw/include"); - } - addSystemInclude(DriverArgs, CC1Args, Base + SubdirName + llvm::sys::path::get_separator() + "include"); - addSystemInclude(DriverArgs, CC1Args, Base + "include"); + + // Gentoo + addSystemInclude(DriverArgs, CC1Args, + Base + SubdirName + llvm::sys::path::get_separator() + "usr/include"); + + // Only include <base>/include if we're not cross compiling (but do allow it + // if we're on Windows and building for Windows on another architecture), + // or if the sysroot has been set (where we presume the user has pointed it + // at an arch specific subdirectory). + if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/false) || + getDriver().SysRoot.size()) + addSystemInclude(DriverArgs, CC1Args, Base + "include"); +} + +void toolchains::MinGW::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { + if (Arg *A = DriverArgs.getLastArg(options::OPT_mguard_EQ)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs == "none") { + // Do nothing. + } else if (GuardArgs == "cf") { + // Emit CFG instrumentation and the table of address-taken functions. + CC1Args.push_back("-cfguard"); + } else if (GuardArgs == "cf-nochecks") { + // Emit only the table of address-taken functions. + CC1Args.push_back("-cfguard-no-checks"); + } else { + getDriver().Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << GuardArgs; + } + } + + CC1Args.push_back("-fno-use-init-array"); + + for (auto Opt : {options::OPT_mthreads, options::OPT_mwindows, + options::OPT_mconsole, options::OPT_mdll}) { + if (Arg *A = DriverArgs.getLastArgNoClaim(Opt)) + A->ignoreTargetSpecific(); + } } void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) + if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, + options::OPT_nostdincxx)) return; StringRef Slash = llvm::sys::path::get_separator(); @@ -614,7 +756,7 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( } case ToolChain::CST_Libstdcxx: - llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases; + llvm::SmallVector<llvm::SmallString<1024>, 7> CppIncludeBases; CppIncludeBases.emplace_back(Base); llvm::sys::path::append(CppIncludeBases[0], SubdirName, "include", "c++"); CppIncludeBases.emplace_back(Base); @@ -624,10 +766,19 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver); CppIncludeBases.emplace_back(GccLibDir); llvm::sys::path::append(CppIncludeBases[3], "include", "c++"); + CppIncludeBases.emplace_back(GccLibDir); + llvm::sys::path::append(CppIncludeBases[4], "include", + "g++-v" + GccVer.Text); + CppIncludeBases.emplace_back(GccLibDir); + llvm::sys::path::append(CppIncludeBases[5], "include", + "g++-v" + GccVer.MajorStr + "." + GccVer.MinorStr); + CppIncludeBases.emplace_back(GccLibDir); + llvm::sys::path::append(CppIncludeBases[6], "include", + "g++-v" + GccVer.MajorStr); for (auto &CppIncludeBase : CppIncludeBases) { addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); CppIncludeBase += Slash; - addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + SubdirName); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + TripleDirName); addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); } break; @@ -641,10 +792,17 @@ static bool testTriple(const Driver &D, const llvm::Triple &Triple, std::string SubdirName; if (D.SysRoot.size()) return true; + llvm::Triple LiteralTriple = getLiteralTriple(D, Triple); + std::string InstallBase = + std::string(llvm::sys::path::parent_path(D.getInstalledDir())); if (llvm::ErrorOr<std::string> TargetSubdir = - findClangRelativeSysroot(D, Triple, SubdirName)) + findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName)) return true; - if (llvm::ErrorOr<std::string> GPPName = findGcc(Triple)) + // If the install base itself looks like a mingw sysroot, we'll use that + // - don't use any potentially unrelated gcc to influence what triple to use. + if (looksLikeMinGWSysroot(InstallBase)) + return false; + if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, Triple)) return true; // If we neither found a colocated sysroot or a matching gcc executable, // conclude that we can't know if this is the correct spelling of the triple. diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h index c9553b4f4652..a9963d8d06c2 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h @@ -11,6 +11,7 @@ #include "Cuda.h" #include "Gnu.h" +#include "LazyDetector.h" #include "ROCm.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" @@ -20,7 +21,7 @@ namespace clang { namespace driver { namespace tools { -/// MinGW -- Directly call GNU Binutils assembler and linker +/// Directly call GNU Binutils assembler and linker namespace MinGW { class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: @@ -34,7 +35,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("MinGW::Linker", "linker", TC) {} @@ -65,8 +66,8 @@ public: bool HasNativeLLVMSupport() const override; - bool IsIntegratedAssemblerDefault() const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; @@ -79,6 +80,10 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -98,16 +103,18 @@ protected: Tool *buildAssembler() const override; private: - CudaInstallationDetector CudaInstallation; - RocmInstallationDetector RocmInstallation; + LazyDetector<CudaInstallationDetector> CudaInstallation; + LazyDetector<RocmInstallationDetector> RocmInstallation; std::string Base; std::string GccLibDir; + clang::driver::toolchains::Generic_GCC::GCCVersion GccVer; std::string Ver; std::string SubdirName; + std::string TripleDirName; mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; mutable std::unique_ptr<tools::gcc::Compiler> Compiler; - void findGccLibDir(); + void findGccLibDir(const llvm::Triple &LiteralTriple); bool NativeLLVMSupport; }; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp deleted file mode 100644 index 5bceb9aba3e9..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp +++ /dev/null @@ -1,113 +0,0 @@ -//===--- Minix.cpp - Minix 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 "Minix.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/InputInfo.h" -#include "clang/Driver/Options.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Support/VirtualFileSystem.h" - -using namespace clang::driver; -using namespace clang; -using namespace llvm::opt; - -void tools::minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - 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<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -void tools::minix::Linker::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; - - 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)) { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - } - - Args.AddAllArgs(CmdArgs, - {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - getToolChain().addProfileRTLibs(Args, CmdArgs); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) { - if (getToolChain().ShouldLinkCXXStdlib(Args)) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-lm"); - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lCompilerRT-Generic"); - CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib"); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - } - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -/// Minix - Minix tool chain which can call as(1) and ld(1) directly. - -toolchains::Minix::Minix(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().Dir + "/../lib"); - getFilePaths().push_back("/usr/lib"); -} - -Tool *toolchains::Minix::buildAssembler() const { - return new tools::minix::Assembler(*this); -} - -Tool *toolchains::Minix::buildLinker() const { - return new tools::minix::Linker(*this); -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h deleted file mode 100644 index af8d59c5085a..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h +++ /dev/null @@ -1,64 +0,0 @@ -//===--- Minix.h - Minix 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H - -#include "Gnu.h" -#include "clang/Driver/Tool.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { -/// minix -- Directly call GNU Binutils assembler and linker -namespace minix { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("minix::Assembler", "assembler", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { -public: - Linker(const ToolChain &TC) : Tool("minix::Linker", "linker", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace minix -} // end namespace tools - -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF { -public: - Minix(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp index 41b7b839f3b3..4183eccceedb 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp @@ -30,7 +30,7 @@ MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D, DetectedMultilibs Result; findMIPSMultilibs(D, Triple, "", Args, Result); Multilibs = Result.Multilibs; - SelectedMultilib = Result.SelectedMultilib; + SelectedMultilibs = Result.SelectedMultilibs; // Find out the library suffix based on the ABI. LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple); @@ -56,7 +56,7 @@ void MipsLLVMToolChain::AddClangSystemIncludeArgs( const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { - for (const auto &Path : Callback(SelectedMultilib)) + for (const auto &Path : Callback(SelectedMultilibs.back())) addExternCSystemIncludeIfExists(DriverArgs, CC1Args, D.getInstalledDir() + Path); } @@ -68,11 +68,11 @@ Tool *MipsLLVMToolChain::buildLinker() const { std::string MipsLLVMToolChain::computeSysRoot() const { if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot + SelectedMultilib.osSuffix(); + return getDriver().SysRoot + SelectedMultilibs.back().osSuffix(); const std::string InstalledDir(getDriver().getInstalledDir()); std::string SysRootPath = - InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix(); + InstalledDir + "/../sysroot" + SelectedMultilibs.back().osSuffix(); if (llvm::sys::fs::exists(SysRootPath)) return SysRootPath; @@ -96,7 +96,7 @@ void MipsLLVMToolChain::addLibCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { if (const auto &Callback = Multilibs.includeDirsCallback()) { - for (std::string Path : Callback(SelectedMultilib)) { + for (std::string Path : Callback(SelectedMultilibs.back())) { Path = getDriver().getInstalledDir() + Path + "/c++/v1"; if (llvm::sys::fs::exists(Path)) { addSystemInclude(DriverArgs, CC1Args, Path); @@ -112,6 +112,8 @@ void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, "Only -lc++ (aka libxx) is supported in this toolchain."); CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); } @@ -120,7 +122,7 @@ std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, StringRef Component, FileType Type) const { SmallString<128> Path(getDriver().ResourceDir); - llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix, + llvm::sys::path::append(Path, SelectedMultilibs.back().osSuffix(), "lib" + LibSuffix, getOS()); const char *Suffix; switch (Type) { @@ -136,5 +138,5 @@ std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, } llvm::sys::path::append( Path, Twine("libclang_rt." + Component + "-" + "mips" + Suffix)); - return std::string(Path.str()); + return std::string(Path); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h index 31b547c0063c..a968804f2a6e 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h @@ -53,7 +53,6 @@ public: } private: - Multilib SelectedMultilib; std::string LibSuffix; }; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp deleted file mode 100644 index f31466633104..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp +++ /dev/null @@ -1,293 +0,0 @@ -//===--- Myriad.cpp - Myriad 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 "Myriad.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/Options.h" -#include "llvm/Option/ArgList.h" - -using namespace clang::driver; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -using tools::addPathIfExists; - -void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - assert(Inputs.size() == 1); - const InputInfo &II = Inputs[0]; - assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX || - II.getType() == types::TY_PP_CXX); - - if (JA.getKind() == Action::PreprocessJobClass) { - Args.ClaimAllArgs(); - CmdArgs.push_back("-E"); - } else { - assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. - CmdArgs.push_back("-S"); - CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. - } - CmdArgs.push_back("-DMYRIAD2"); - - // Append all -I, -iquote, -isystem paths, defines/undefines, 'f' - // flags, 'g' flags, 'M' flags, optimize flags, warning options, - // mcpu flags, mllvm flags, and Xclang flags. - // These are spelled the same way in clang and moviCompile. - Args.AddAllArgsExcept( - CmdArgs, - {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ, - options::OPT_D, options::OPT_U, options::OPT_f_Group, - options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group, - options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ, - options::OPT_mllvm, options::OPT_Xclang}, - {options::OPT_fno_split_dwarf_inlining}); - Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. - - // If we're producing a dependency file, and assembly is the final action, - // then the name of the target in the dependency file should be the '.o' - // file, not the '.s' file produced by this step. For example, instead of - // /tmp/mumble.s: mumble.c .../someheader.h - // the filename on the lefthand side should be "mumble.o" - if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && - C.getActions().size() == 1 && - C.getActions()[0]->getKind() == Action::AssembleJobClass) { - Arg *A = Args.getLastArg(options::OPT_o); - if (A) { - CmdArgs.push_back("-MT"); - CmdArgs.push_back(Args.MakeArgString(A->getValue())); - } - } - - CmdArgs.push_back(II.getFilename()); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - std::string Exec = - Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Args.MakeArgString(Exec), CmdArgs, - Inputs, Output)); -} - -void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - assert(Inputs.size() == 1); - const InputInfo &II = Inputs[0]; - assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input. - assert(Output.getType() == types::TY_Object); - - CmdArgs.push_back("-no6thSlotCompression"); - const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); - if (CPUArg) - CmdArgs.push_back( - Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue()))); - CmdArgs.push_back("-noSPrefixing"); - CmdArgs.push_back("-a"); // Mystery option. - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) { - A->claim(); - CmdArgs.push_back( - Args.MakeArgString(std::string("-i:") + A->getValue(0))); - } - CmdArgs.push_back(II.getFilename()); - CmdArgs.push_back( - Args.MakeArgString(std::string("-o:") + Output.getFilename())); - - std::string Exec = - Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Args.MakeArgString(Exec), CmdArgs, - Inputs, Output)); -} - -void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const auto &TC = - static_cast<const toolchains::MyriadToolChain &>(getToolChain()); - const llvm::Triple &T = TC.getTriple(); - ArgStringList CmdArgs; - bool UseStartfiles = - !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); - bool UseDefaultLibs = - !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); - // Silence warning if the args contain both -nostdlib and -stdlib=. - Args.getLastArg(options::OPT_stdlib_EQ); - - if (T.getArch() == llvm::Triple::sparc) - CmdArgs.push_back("-EB"); - else // SHAVE assumes little-endian, and sparcel is expressly so. - CmdArgs.push_back("-EL"); - - // The remaining logic is mostly like gnutools::Linker::ConstructJob, - // but we never pass through a --sysroot option and various other bits. - // For example, there are no sanitizers (yet) nor gold linker. - - // Eat some arguments that may be present but have no effect. - Args.ClaimAllArgs(options::OPT_g_Group); - Args.ClaimAllArgs(options::OPT_w); - Args.ClaimAllArgs(options::OPT_static_libgcc); - - if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. - CmdArgs.push_back("-s"); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - if (UseStartfiles) { - // If you want startfiles, it means you want the builtin crti and crtbegin, - // but not crt0. Myriad link commands provide their own crt0.o as needed. - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); - } - - Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_e, options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_r}); - - TC.AddFilePathLibArgs(Args, CmdArgs); - - bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - if (UseDefaultLibs) { - if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(TC, CmdArgs); - if (C.getDriver().CCCIsCXX()) { - if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - } else - CmdArgs.push_back("-lstdc++"); - } - if (T.getOS() == llvm::Triple::RTEMS) { - CmdArgs.push_back("--start-group"); - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lgcc"); // circularly dependent on rtems - // You must provide your own "-L" option to enable finding these. - CmdArgs.push_back("-lrtemscpu"); - CmdArgs.push_back("-lrtemsbsp"); - CmdArgs.push_back("--end-group"); - } else { - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lgcc"); - } - } - if (UseStartfiles) { - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); - } - - std::string Exec = - Args.MakeArgString(TC.GetProgramPath("sparc-myriad-rtems-ld")); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Exec), - CmdArgs, Inputs, Output)); -} - -MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use - // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple. - // This won't work to find gcc. Instead we give the installation detector an - // extra triple, which is preferable to further hacks of the logic that at - // present is based solely on getArch(). In particular, it would be wrong to - // choose the myriad installation when targeting a non-myriad sparc install. - switch (Triple.getArch()) { - default: - D.Diag(clang::diag::err_target_unsupported_arch) - << Triple.getArchName() << "myriad"; - LLVM_FALLTHROUGH; - case llvm::Triple::shave: - return; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - GCCInstallation.init(Triple, Args, {"sparc-myriad-rtems"}); - } - - if (GCCInstallation.isValid()) { - // This directory contains crt{i,n,begin,end}.o as well as libgcc. - // These files are tied to a particular version of gcc. - SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); - addPathIfExists(D, CompilerSupportDir, getFilePaths()); - } - // libstd++ and libc++ must both be found in this one place. - addPathIfExists(D, D.Dir + "/../sparc-myriad-rtems/lib", getFilePaths()); -} - -MyriadToolChain::~MyriadToolChain() {} - -void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) - addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); -} - -void MyriadToolChain::addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - std::string Path(getDriver().getInstalledDir()); - addSystemInclude(DriverArgs, CC1Args, Path + "/../include/c++/v1"); -} - -void MyriadToolChain::addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - StringRef LibDir = GCCInstallation.getParentLibPath(); - const GCCVersion &Version = GCCInstallation.getVersion(); - StringRef TripleStr = GCCInstallation.getTriple().str(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - addLibStdCXXIncludePaths( - LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, - TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args); -} - -// MyriadToolChain handles several triples: -// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf -Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { - // The inherited method works fine if not targeting the SHAVE. - if (!isShaveCompilation(getTriple())) - return ToolChain::SelectTool(JA); - switch (JA.getKind()) { - case Action::PreprocessJobClass: - case Action::CompileJobClass: - if (!Compiler) - Compiler.reset(new tools::SHAVE::Compiler(*this)); - return Compiler.get(); - case Action::AssembleJobClass: - if (!Assembler) - Assembler.reset(new tools::SHAVE::Assembler(*this)); - return Assembler.get(); - default: - return ToolChain::getTool(JA.getKind()); - } -} - -Tool *MyriadToolChain::buildLinker() const { - return new tools::Myriad::Linker(*this); -} - -SanitizerMask MyriadToolChain::getSupportedSanitizers() const { - return SanitizerKind::Address; -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h deleted file mode 100644 index cae574bdcfea..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h +++ /dev/null @@ -1,103 +0,0 @@ -//===--- Myriad.h - Myriad 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H - -#include "Gnu.h" -#include "clang/Driver/Tool.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { - -/// SHAVE tools -- Directly call moviCompile and moviAsm -namespace SHAVE { -class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { -public: - Compiler(const ToolChain &TC) : Tool("moviCompile", "movicompile", TC) {} - - bool hasIntegratedCPP() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("moviAsm", "moviAsm", TC) {} - - bool hasIntegratedCPP() const override { return false; } // not sure. - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace SHAVE - -/// The Myriad toolchain uses tools that are in two different namespaces. -/// The Compiler and Assembler as defined above are in the SHAVE namespace, -/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE, -/// is in the Myriad namespace. -namespace Myriad { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { -public: - Linker(const ToolChain &TC) : Tool("shave::Linker", "ld", TC) {} - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace Myriad -} // end namespace tools - -namespace toolchains { - -/// MyriadToolChain - A tool chain using either clang or the external compiler -/// installed by the Movidius SDK to perform all subcommands. -class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_ELF { -public: - MyriadToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~MyriadToolChain() override; - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - Tool *SelectTool(const JobAction &JA) const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } - SanitizerMask getSupportedSanitizers() const override; - -protected: - Tool *buildLinker() const override; - bool isShaveCompilation(const llvm::Triple &T) const { - return T.getArch() == llvm::Triple::shave; - } - -private: - mutable std::unique_ptr<Tool> Compiler; - mutable std::unique_ptr<Tool> Assembler; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp index 753459cb230b..22f038e5152f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp @@ -31,8 +31,7 @@ void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::NaClToolChain &ToolChain = - static_cast<const toolchains::NaClToolChain &>(getToolChain()); + const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain()); InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(), "nacl-arm-macros.s"); InputInfoList NewInputs; @@ -52,8 +51,7 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::NaClToolChain &ToolChain = - static_cast<const toolchains::NaClToolChain &>(getToolChain()); + const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsStatic = @@ -120,8 +118,7 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); ToolChain.AddFilePathLibArgs(Args, CmdArgs); @@ -308,6 +305,8 @@ void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, // if the value is libc++, and emits an error for other values. GetCXXStdlibType(Args); CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); } void NaClToolChain::addLibCxxIncludePaths( diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h index 5e5fdb583bb6..01d4719e7b92 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h @@ -27,7 +27,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("NaCl::Linker", "linker", TC) {} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp index d1eda14a51f0..240bf5764b9c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -11,6 +11,7 @@ #include "Arch/Mips.h" #include "Arch/Sparc.h" #include "CommonArgs.h" +#include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" @@ -29,13 +30,12 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::NetBSD &ToolChain = - static_cast<const toolchains::NetBSD &>(getToolChain()); + const auto &ToolChain = static_cast<const NetBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple &Triple = ToolChain.getTriple(); + ArgStringList CmdArgs; claimNoWarnArgs(Args); - ArgStringList CmdArgs; // GNU as needs different flags for creating the correct output format // on architectures with different ABIs or optional feature sets. @@ -77,8 +77,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, break; } - case llvm::Triple::sparc: - case llvm::Triple::sparcel: { + case llvm::Triple::sparc: { CmdArgs.push_back("-32"); std::string CPU = getCPUName(D, Args, Triple); CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); @@ -117,29 +116,31 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::NetBSD &ToolChain = - static_cast<const toolchains::NetBSD &>(getToolChain()); + const auto &ToolChain = static_cast<const NetBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple &Triple = ToolChain.getTriple(); - + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool Static = Args.hasArg(options::OPT_static); + const bool Shared = Args.hasArg(options::OPT_shared); + const bool Pie = Args.hasArg(options::OPT_pie); ArgStringList CmdArgs; if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_static)) { + if (Static) { CmdArgs.push_back("-Bstatic"); - if (Args.hasArg(options::OPT_pie)) { + if (Pie) { Args.AddAllArgs(CmdArgs, options::OPT_pie); CmdArgs.push_back("--no-dynamic-linker"); } } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-Bshareable"); - } else { + if (Shared) { + CmdArgs.push_back("-shared"); + } else if (!Args.hasArg(options::OPT_r)) { Args.AddAllArgs(CmdArgs, options::OPT_pie); CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld.elf_so"); @@ -148,7 +149,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Many NetBSD architectures support more than one ABI. // Determine the correct emulation for ld. - switch (ToolChain.getArch()) { + switch (Arch) { case llvm::Triple::x86: CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); @@ -192,13 +193,13 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips64el: if (mips::hasMipsAbiArg(Args, "32")) { CmdArgs.push_back("-m"); - if (ToolChain.getArch() == llvm::Triple::mips64) + if (Arch == llvm::Triple::mips64) CmdArgs.push_back("elf32btsmip"); else CmdArgs.push_back("elf32ltsmip"); } else if (mips::hasMipsAbiArg(Args, "64")) { CmdArgs.push_back("-m"); - if (ToolChain.getArch() == llvm::Triple::mips64) + if (Arch == llvm::Triple::mips64) CmdArgs.push_back("elf64btsmip"); else CmdArgs.push_back("elf64ltsmip"); @@ -215,6 +216,16 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf64ppc"); 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; + case llvm::Triple::sparc: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32_sparc"); @@ -229,37 +240,36 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, break; } + if (Triple.isRISCV()) + CmdArgs.push_back("-X"); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 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, options::OPT_r)) { - if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - } - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) { - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o"))); - } else { - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); - } + const char *crt0 = nullptr; + const char *crtbegin = nullptr; + if (!Shared) + crt0 = "crt0.o"; + + if (Shared || Pie) + crtbegin = "crtbeginS.o"; + else + crtbegin = "crtbegin.o"; + + if (crt0) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } - Args.AddAllArgs(CmdArgs, options::OPT_L); - 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); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_s, options::OPT_t, options::OPT_r}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); @@ -271,35 +281,33 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.getCompilerRTPath())); } - VersionTuple OsVersion = Triple.getOSVersion(); bool useLibgcc = true; - if (OsVersion >= VersionTuple(7) || OsVersion.getMajor() == 0) { - switch (ToolChain.getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - useLibgcc = false; - break; - default: - break; - } + switch (ToolChain.getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::arm: + case llvm::Triple::armeb: + 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::sparc: + case llvm::Triple::sparcv9: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + useLibgcc = false; + break; + default: + break; } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp - bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && - !Args.hasArg(options::OPT_static); + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { @@ -307,16 +315,30 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, CmdArgs); + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); if (useLibgcc) { - if (Args.hasArg(options::OPT_static)) { + if (Static) { // libgcc_eh depends on libc, so resolve as much as possible, // pull in any new requirements from libc and then get the rest // of libgcc. @@ -334,12 +356,13 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, options::OPT_r)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); + const char *crtend = nullptr; + if (Shared || Pie) + crtend = "crtendS.o"; else - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + crtend = "crtend.o"; + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } @@ -363,7 +386,7 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // what all logic is needed to emulate the '=' prefix here. switch (Triple.getArch()) { case llvm::Triple::x86: - getFilePaths().push_back("=/usr/lib/i386"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/i386")); break; case llvm::Triple::arm: case llvm::Triple::armeb: @@ -372,35 +395,35 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) switch (Triple.getEnvironment()) { case llvm::Triple::EABI: case llvm::Triple::GNUEABI: - getFilePaths().push_back("=/usr/lib/eabi"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/eabi")); break; case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: - getFilePaths().push_back("=/usr/lib/eabihf"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/eabihf")); break; default: - getFilePaths().push_back("=/usr/lib/oabi"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/oabi")); break; } break; case llvm::Triple::mips64: case llvm::Triple::mips64el: if (tools::mips::hasMipsAbiArg(Args, "o32")) - getFilePaths().push_back("=/usr/lib/o32"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/o32")); else if (tools::mips::hasMipsAbiArg(Args, "64")) - getFilePaths().push_back("=/usr/lib/64"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/64")); break; case llvm::Triple::ppc: - getFilePaths().push_back("=/usr/lib/powerpc"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/powerpc")); break; case llvm::Triple::sparc: - getFilePaths().push_back("=/usr/lib/sparc"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/sparc")); break; default: break; } - getFilePaths().push_back("=/usr/lib"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } } @@ -411,39 +434,72 @@ Tool *NetBSD::buildAssembler() const { Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); } ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const { - VersionTuple OsVersion = getTriple().getOSVersion(); - if (OsVersion >= VersionTuple(7) || OsVersion.getMajor() == 0) { - switch (getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return ToolChain::CST_Libcxx; - default: - break; - } + switch (getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::arm: + case llvm::Triple::armeb: + 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::sparc: + case llvm::Triple::sparcv9: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return ToolChain::CST_Libcxx; + default: + break; } return ToolChain::CST_Libstdcxx; } +void NetBSD::AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); +} + void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { const std::string Candidates[] = { // directory relative to build tree - getDriver().Dir + "/../include/c++/v1", + concat(getDriver().Dir, "/../include/c++/v1"), // system install with full upstream path - getDriver().SysRoot + "/usr/include/c++/v1", + concat(getDriver().SysRoot, "/usr/include/c++/v1"), // system install from src - getDriver().SysRoot + "/usr/include/c++", + concat(getDriver().SysRoot, "/usr/include/c++"), }; for (const auto &IncludePath : Candidates) { @@ -458,7 +514,7 @@ void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot + "/usr/include/g++", "", "", + addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/g++"), "", "", DriverArgs, CC1Args); } @@ -479,7 +535,6 @@ SanitizerMask NetBSD::getSupportedSanitizers() const { Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; - Res |= SanitizerKind::Function; Res |= SanitizerKind::Leak; Res |= SanitizerKind::SafeStack; Res |= SanitizerKind::Scudo; @@ -512,7 +567,9 @@ void NetBSD::addClangTargetOptions(const ArgList &DriverArgs, getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::aarch64_be || getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::armeb; + getTriple().getArch() == llvm::Triple::armeb || + getTriple().getArch() == llvm::Triple::riscv32 || + getTriple().getArch() == llvm::Triple::riscv64; if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, UseInitArrayDefault)) diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h index 8348554fd149..96303acaa009 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h @@ -17,9 +17,9 @@ namespace clang { namespace driver { namespace tools { -/// netbsd -- Directly call GNU Binutils assembler and linker +/// Directly call GNU Binutils assembler and linker namespace netbsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("netbsd::Assembler", "assembler", TC) {} @@ -31,7 +31,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("netbsd::Linker", "linker", TC) {} @@ -58,6 +58,9 @@ public: CXXStdlibType GetDefaultCXXStdlibType() const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; void addLibCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -65,8 +68,9 @@ public: const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override { - return true; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override { + return UnwindTableLevel::Asynchronous; } llvm::ExceptionHandling GetExceptionModel( diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp new file mode 100644 index 000000000000..1e50c9d71d59 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp @@ -0,0 +1,419 @@ +//===--- OHOS.cpp - OHOS 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 "OHOS.h" +#include "Arch/ARM.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; +using namespace clang::driver::tools::arm; + +using tools::addMultilibFlag; +using tools::addPathIfExists; + +static bool findOHOSMuslMultilibs(const Multilib::flags_list &Flags, + DetectedMultilibs &Result) { + MultilibSet Multilibs; + Multilibs.push_back(Multilib()); + // -mcpu=cortex-a7 + // -mfloat-abi=soft -mfloat-abi=softfp -mfloat-abi=hard + // -mfpu=neon-vfpv4 + Multilibs.push_back( + Multilib("/a7_soft", {}, {}, {"-mcpu=cortex-a7", "-mfloat-abi=soft"})); + + Multilibs.push_back( + Multilib("/a7_softfp_neon-vfpv4", {}, {}, + {"-mcpu=cortex-a7", "-mfloat-abi=softfp", "-mfpu=neon-vfpv4"})); + + Multilibs.push_back( + Multilib("/a7_hard_neon-vfpv4", {}, {}, + {"-mcpu=cortex-a7", "-mfloat-abi=hard", "-mfpu=neon-vfpv4"})); + + if (Multilibs.select(Flags, Result.SelectedMultilibs)) { + Result.Multilibs = Multilibs; + return true; + } + return false; +} + +static bool findOHOSMultilibs(const Driver &D, + const ToolChain &TC, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + Multilib::flags_list Flags; + bool IsA7 = false; + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + IsA7 = A->getValue() == StringRef("cortex-a7"); + addMultilibFlag(IsA7, "-mcpu=cortex-a7", Flags); + + bool IsMFPU = false; + if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) + IsMFPU = A->getValue() == StringRef("neon-vfpv4"); + addMultilibFlag(IsMFPU, "-mfpu=neon-vfpv4", Flags); + + tools::arm::FloatABI ARMFloatABI = getARMFloatABI(D, TargetTriple, Args); + addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Soft), + "-mfloat-abi=soft", Flags); + addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::SoftFP), + "-mfloat-abi=softfp", Flags); + addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Hard), + "-mfloat-abi=hard", Flags); + + return findOHOSMuslMultilibs(Flags, Result); +} + +std::string OHOS::getMultiarchTriple(const llvm::Triple &T) const { + // For most architectures, just use whatever we have rather than trying to be + // clever. + switch (T.getArch()) { + default: + break; + + // We use the existence of '/lib/<triple>' as a directory to detect some + // common linux triples that don't quite match the Clang triple for both + // 32-bit and 64-bit targets. Multiarch fixes its install triples to these + // regardless of what the actual target triple is. + case llvm::Triple::arm: + case llvm::Triple::thumb: + return T.isOSLiteOS() ? "arm-liteos-ohos" : "arm-linux-ohos"; + case llvm::Triple::riscv32: + return "riscv32-linux-ohos"; + case llvm::Triple::riscv64: + return "riscv64-linux-ohos"; + case llvm::Triple::mipsel: + return "mipsel-linux-ohos"; + case llvm::Triple::x86: + return "i686-linux-ohos"; + case llvm::Triple::x86_64: + return "x86_64-linux-ohos"; + case llvm::Triple::aarch64: + return "aarch64-linux-ohos"; + } + return T.str(); +} + +std::string OHOS::getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const { + return getMultiarchTriple(TargetTriple); +} + +static std::string makePath(const std::initializer_list<std::string> &IL) { + SmallString<128> P; + for (const auto &S : IL) + llvm::sys::path::append(P, S); + return static_cast<std::string>(P.str()); +} + +/// OHOS Toolchain +OHOS::OHOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + std::string SysRoot = computeSysRoot(); + + // Select the correct multilib according to the given arguments. + DetectedMultilibs Result; + findOHOSMultilibs(D, *this, Triple, "", Args, Result); + Multilibs = Result.Multilibs; + SelectedMultilibs = Result.SelectedMultilibs; + if (!SelectedMultilibs.empty()) { + SelectedMultilib = SelectedMultilibs.back(); + } + + getFilePaths().clear(); + for (const auto &CandidateLibPath : getArchSpecificLibPaths()) + if (getVFS().exists(CandidateLibPath)) + getFilePaths().push_back(CandidateLibPath); + + getLibraryPaths().clear(); + for (auto &Path : getRuntimePaths()) + if (getVFS().exists(Path)) + getLibraryPaths().push_back(Path); + + // OHOS sysroots contain a library directory for each supported OS + // version as well as some unversioned libraries in the usual multiarch + // directory. Support --target=aarch64-linux-ohosX.Y.Z or + // --target=aarch64-linux-ohosX.Y or --target=aarch64-linux-ohosX + path_list &Paths = getFilePaths(); + std::string SysRootLibPath = makePath({SysRoot, "usr", "lib"}); + std::string MultiarchTriple = getMultiarchTriple(getTriple()); + addPathIfExists(D, makePath({SysRootLibPath, SelectedMultilib.gccSuffix()}), + Paths); + addPathIfExists(D, + makePath({D.Dir, "..", "lib", MultiarchTriple, + SelectedMultilib.gccSuffix()}), + Paths); + + addPathIfExists( + D, + makePath({SysRootLibPath, MultiarchTriple, SelectedMultilib.gccSuffix()}), + Paths); +} + +ToolChain::RuntimeLibType OHOS::GetRuntimeLibType( + const ArgList &Args) const { + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "compiler-rt") + getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name) + << A->getAsString(Args); + } + + return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType +OHOS::GetCXXStdlibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "libc++") + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + + return ToolChain::CST_Libcxx; +} + +void OHOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + const llvm::Triple &Triple = getTriple(); + std::string SysRoot = computeSysRoot(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + addExternCSystemInclude(DriverArgs, CC1Args, + SysRoot + "/usr/include/" + + getMultiarchTriple(Triple)); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); +} + +void OHOS::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: { + std::string IncPath = makePath({getDriver().Dir, "..", "include"}); + std::string IncTargetPath = + makePath({IncPath, getMultiarchTriple(getTriple()), "c++", "v1"}); + if (getVFS().exists(IncTargetPath)) { + addSystemInclude(DriverArgs, CC1Args, makePath({IncPath, "c++", "v1"})); + addSystemInclude(DriverArgs, CC1Args, IncTargetPath); + } + break; + } + + default: + llvm_unreachable("invalid stdlib name"); + } +} + +void OHOS::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); + break; + + case ToolChain::CST_Libstdcxx: + llvm_unreachable("invalid stdlib name"); + } +} + +std::string OHOS::computeSysRoot() const { + std::string SysRoot = + !getDriver().SysRoot.empty() + ? getDriver().SysRoot + : makePath({getDriver().getInstalledDir(), "..", "..", "sysroot"}); + if (!llvm::sys::fs::exists(SysRoot)) + return std::string(); + + std::string ArchRoot = makePath({SysRoot, getMultiarchTriple(getTriple())}); + return llvm::sys::fs::exists(ArchRoot) ? ArchRoot : SysRoot; +} + +ToolChain::path_list OHOS::getRuntimePaths() const { + SmallString<128> P; + path_list Paths; + const Driver &D = getDriver(); + const llvm::Triple &Triple = getTriple(); + + // First try the triple passed to driver as --target=<triple>. + P.assign(D.ResourceDir); + llvm::sys::path::append(P, "lib", D.getTargetTriple(), SelectedMultilib.gccSuffix()); + Paths.push_back(P.c_str()); + + // Second try the normalized triple. + P.assign(D.ResourceDir); + llvm::sys::path::append(P, "lib", Triple.str(), SelectedMultilib.gccSuffix()); + Paths.push_back(P.c_str()); + + // Third try the effective triple. + P.assign(D.ResourceDir); + std::string SysRoot = computeSysRoot(); + llvm::sys::path::append(P, "lib", getMultiarchTriple(Triple), + SelectedMultilib.gccSuffix()); + Paths.push_back(P.c_str()); + + return Paths; +} + +std::string OHOS::getDynamicLinker(const ArgList &Args) const { + const llvm::Triple &Triple = getTriple(); + const llvm::Triple::ArchType Arch = getArch(); + + assert(Triple.isMusl()); + std::string ArchName; + bool IsArm = false; + + switch (Arch) { + case llvm::Triple::arm: + case llvm::Triple::thumb: + ArchName = "arm"; + IsArm = true; + break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + ArchName = "armeb"; + IsArm = true; + break; + default: + ArchName = Triple.getArchName().str(); + } + if (IsArm && + (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)) + ArchName += "hf"; + + return "/lib/ld-musl-" + ArchName + ".so.1"; +} + +std::string OHOS::getCompilerRT(const ArgList &Args, StringRef Component, + FileType Type) const { + SmallString<128> Path(getDriver().ResourceDir); + llvm::sys::path::append(Path, "lib", getMultiarchTriple(getTriple()), + SelectedMultilib.gccSuffix()); + const char *Prefix = + Type == ToolChain::FT_Object ? "" : "lib"; + const char *Suffix; + switch (Type) { + case ToolChain::FT_Object: + Suffix = ".o"; + break; + case ToolChain::FT_Static: + Suffix = ".a"; + break; + case ToolChain::FT_Shared: + Suffix = ".so"; + break; + } + llvm::sys::path::append( + Path, Prefix + Twine("clang_rt.") + Component + Suffix); + return static_cast<std::string>(Path.str()); +} + +void OHOS::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { + CmdArgs.push_back("-z"); + CmdArgs.push_back("now"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("relro"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("max-page-size=4096"); + // .gnu.hash section is not compatible with the MIPS target + if (getArch() != llvm::Triple::mipsel) + CmdArgs.push_back("--hash-style=both"); +#ifdef ENABLE_LINKER_BUILD_ID + CmdArgs.push_back("--build-id"); +#endif + CmdArgs.push_back("--enable-new-dtags"); +} + +SanitizerMask OHOS::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; + Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::Memory; + Res |= SanitizerKind::Vptr; + Res |= SanitizerKind::SafeStack; + Res |= SanitizerKind::Scudo; + // TODO: kASAN for liteos ?? + // TODO: Support TSAN and HWASAN and update mask. + return Res; +} + +// TODO: Make a base class for Linux and OHOS and move this there. +void OHOS::addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + // Add linker option -u__llvm_profile_runtime to cause runtime + // initialization module to be linked in. + if (needsProfileRT(Args)) + CmdArgs.push_back(Args.MakeArgString( + Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); + ToolChain::addProfileRTLibs(Args, CmdArgs); +} + +ToolChain::path_list OHOS::getArchSpecificLibPaths() const { + ToolChain::path_list Paths; + llvm::Triple Triple = getTriple(); + Paths.push_back( + makePath({getDriver().ResourceDir, "lib", getMultiarchTriple(Triple)})); + return Paths; +} + +ToolChain::UnwindLibType OHOS::GetUnwindLibType(const llvm::opt::ArgList &Args) const { + if (Args.getLastArg(options::OPT_unwindlib_EQ)) + return Generic_ELF::GetUnwindLibType(Args); + return GetDefaultUnwindLibType(); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h new file mode 100644 index 000000000000..2a380420922d --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h @@ -0,0 +1,95 @@ +//===--- OHOS.h - OHOS 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OHOS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OHOS_H + +#include "Linux.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY OHOS : public Generic_ELF { +public: + OHOS(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool HasNativeLLVMSupport() const override { return true; } + + bool IsMathErrnoDefault() const override { return false; } + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + // Not add -funwind-tables by default + bool isPICDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { return true; } + bool isPICDefaultForced() const override { return false; } + UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override; + UnwindLibType GetDefaultUnwindLibType() const override { return UNW_CompilerRT; } + + RuntimeLibType + GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; + CXXStdlibType + GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + std::string computeSysRoot() const override; + std::string getDynamicLinker(const llvm::opt::ArgList &Args) const override; + + std::string + getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, + FileType Type = ToolChain::FT_Static) const override; + + const char *getDefaultLinker() const override { + return "ld.lld"; + } + + Tool *buildLinker() const override { + return new tools::gnutools::Linker(*this); + } + Tool *buildAssembler() const override { + return new tools::gnutools::Assembler(*this); + } + + path_list getRuntimePaths() const; + +protected: + std::string getMultiarchTriple(const llvm::Triple &T) const; + std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const override; + void addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const override; + SanitizerMask getSupportedSanitizers() const override; + void addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + path_list getArchSpecificLibPaths() const override; + +private: + Multilib SelectedMultilib; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OHOS_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp index 86a10ce4b0e7..fd6aa4d7e684 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -17,6 +17,7 @@ #include "clang/Driver/SanitizerArgs.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; @@ -29,13 +30,12 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::OpenBSD &ToolChain = - static_cast<const toolchains::OpenBSD &>(getToolChain()); + const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple &Triple = ToolChain.getTriple(); + ArgStringList CmdArgs; claimNoWarnArgs(Args); - ArgStringList CmdArgs; switch (ToolChain.getArch()) { case llvm::Triple::x86: @@ -44,8 +44,7 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--32"); break; - case llvm::Triple::arm: - case llvm::Triple::armeb: { + case llvm::Triple::arm: { StringRef MArch, MCPU; arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); std::string Arch = arm::getARMTargetCPU(MCPU, MArch, Triple); @@ -110,9 +109,15 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::OpenBSD &ToolChain = - static_cast<const toolchains::OpenBSD &>(getToolChain()); + const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool Static = Args.hasArg(options::OPT_static); + const bool Shared = Args.hasArg(options::OPT_shared); + const bool Profiling = Args.hasArg(options::OPT_pg); + const bool Pie = Args.hasArg(options::OPT_pie); + const bool Nopie = Args.hasArg(options::OPT_no_pie, options::OPT_nopie); + const bool Relocatable = Args.hasArg(options::OPT_r); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -123,52 +128,55 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); - if (ToolChain.getArch() == llvm::Triple::mips64) + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (Arch == llvm::Triple::mips64) CmdArgs.push_back("-EB"); - else if (ToolChain.getArch() == llvm::Triple::mips64el) + else if (Arch == llvm::Triple::mips64el) CmdArgs.push_back("-EL"); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { + if (!Args.hasArg(options::OPT_nostdlib) && !Shared && !Relocatable) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_static)) { + if (Static) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); - CmdArgs.push_back("-Bdynamic"); - if (Args.hasArg(options::OPT_shared)) { + if (Shared) { CmdArgs.push_back("-shared"); - } else { + } else if (!Relocatable) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld.so"); } } - if (Args.hasArg(options::OPT_pie)) + if (Pie) CmdArgs.push_back("-pie"); - if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg)) + if (Nopie || Profiling) CmdArgs.push_back("-nopie"); + if (Arch == llvm::Triple::riscv64) + CmdArgs.push_back("-X"); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 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, options::OPT_r)) { const char *crt0 = nullptr; const char *crtbegin = nullptr; - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) + if (!Shared) { + if (Profiling) crt0 = "gcrt0.o"; - else if (Args.hasArg(options::OPT_static) && - !Args.hasArg(options::OPT_nopie)) + else if (Static && !Nopie) crt0 = "rcrt0.o"; else crt0 = "crt0.o"; @@ -184,9 +192,22 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e, - options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_r}); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); + + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, + D.getLTOMode() == LTOK_Thin); + } bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); @@ -195,39 +216,55 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp - bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && - !Args.hasArg(options::OPT_static); + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (Args.hasArg(options::OPT_pg)) + if (Profiling) CmdArgs.push_back("-lm_p"); else CmdArgs.push_back("-lm"); } + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + if (Profiling) + CmdArgs.push_back("-lm_p"); + else + CmdArgs.push_back("-lm"); + } + if (NeedsSanitizerDeps) { CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); } if (NeedsXRayDeps) { CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); - linkXRayRuntimeDeps(ToolChain, CmdArgs); + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); } // FIXME: For some reason GCC passes -lgcc before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lcompiler_rt"); if (Args.hasArg(options::OPT_pthread)) { - if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg)) + if (!Shared && Profiling) CmdArgs.push_back("-lpthread_p"); else CmdArgs.push_back("-lpthread"); } - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) + if (!Shared) { + if (Profiling) CmdArgs.push_back("-lc_p"); else CmdArgs.push_back("-lc"); @@ -239,7 +276,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, options::OPT_r)) { const char *crtend = nullptr; - if (!Args.hasArg(options::OPT_shared)) + if (!Shared) crtend = "crtend.o"; else crtend = "crtendS.o"; @@ -258,16 +295,15 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, SanitizerMask OpenBSD::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; - - // For future use, only UBsan at the moment SanitizerMask Res = ToolChain::getSupportedSanitizers(); - if (IsX86 || IsX86_64) { Res |= SanitizerKind::Vptr; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; } - + if (IsX86_64) { + Res |= SanitizerKind::KernelAddress; + } return Res; } @@ -276,7 +312,7 @@ SanitizerMask OpenBSD::getSupportedSanitizers() const { OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } void OpenBSD::AddClangSystemIncludeArgs( @@ -309,13 +345,14 @@ void OpenBSD::AddClangSystemIncludeArgs( return; } - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); } void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); + concat(getDriver().SysRoot, "/usr/include/c++/v1")); } void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, @@ -323,16 +360,27 @@ void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, bool Profiling = Args.hasArg(options::OPT_pg); CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi"); CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread"); } -std::string OpenBSD::getCompilerRT(const ArgList &Args, - StringRef Component, +std::string OpenBSD::getCompilerRT(const ArgList &Args, StringRef Component, FileType Type) const { - SmallString<128> Path(getDriver().SysRoot); - llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a"); - return std::string(Path.str()); + if (Component == "builtins") { + SmallString<128> Path(getDriver().SysRoot); + llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a"); + return std::string(Path); + } + SmallString<128> P(getDriver().ResourceDir); + std::string CRTBasename = + buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false); + llvm::sys::path::append(P, "lib", CRTBasename); + // Checks if this is the base system case which uses a different location. + if (getVFS().exists(P)) + return std::string(P); + return ToolChain::getCompilerRT(Args, Component, Type); } Tool *OpenBSD::buildAssembler() const { @@ -343,11 +391,12 @@ Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } bool OpenBSD::HasNativeLLVMSupport() const { return true; } -bool OpenBSD::IsUnwindTablesDefault(const ArgList &Args) const { - switch (getArch()) { - case llvm::Triple::arm: - return false; - default: - return true; - } +ToolChain::UnwindTableLevel +OpenBSD::getDefaultUnwindTableLevel(const ArgList &Args) const { + switch (getArch()) { + case llvm::Triple::arm: + return UnwindTableLevel::None; + default: + return UnwindTableLevel::Asynchronous; + } } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h index 2d4c4e34520b..b4350e72d5d2 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h @@ -18,9 +18,9 @@ namespace clang { namespace driver { namespace tools { -/// openbsd -- Directly call GNU Binutils assembler and linker +/// Directly call GNU Binutils assembler and linker namespace openbsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("openbsd::Assembler", "assembler", TC) {} @@ -33,7 +33,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("openbsd::Linker", "linker", TC) {} @@ -82,7 +82,8 @@ public: std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, FileType Type = ToolChain::FT_Static) const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; LangOptions::StackProtectorMode GetDefaultStackProtectorLevel(bool KernelOrKext) const override { diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp index 2fea262fd109..0ed0f91ad166 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp @@ -31,10 +31,10 @@ static bool GlibcSupportsFloat128(const std::string &Linker) { // Since glibc 2.34, the installed .so file is not symlink anymore. But we can // still safely assume it's newer than 2.32. - if (LinkerName.startswith("ld64.so")) + if (LinkerName.starts_with("ld64.so")) return true; - if (!LinkerName.startswith("ld-2.")) + if (!LinkerName.starts_with("ld-2.")) return false; unsigned Minor = (LinkerName[5] - '0') * 10 + (LinkerName[6] - '0'); if (Minor < 32) @@ -49,7 +49,10 @@ PPCLinuxToolChain::PPCLinuxToolChain(const Driver &D, : Linux(D, Triple, Args) { if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { StringRef ABIName = A->getValue(); - if (ABIName == "ieeelongdouble" && !SupportIEEEFloat128(D, Triple, Args)) + + if ((ABIName == "ieeelongdouble" && + !SupportIEEEFloat128(D, Triple, Args)) || + (ABIName == "ibmlongdouble" && !supportIBMLongDouble(D, Args))) D.Diag(diag::warn_drv_unsupported_float_abi_by_lib) << ABIName; } } @@ -67,6 +70,18 @@ void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, Linux::AddClangSystemIncludeArgs(DriverArgs, CC1Args); } +bool PPCLinuxToolChain::supportIBMLongDouble( + const Driver &D, const llvm::opt::ArgList &Args) const { + if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx)) + return true; + + CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args); + if (StdLib == CST_Libstdcxx) + return true; + + return StdLib == CST_Libcxx && !defaultToIEEELongDouble(); +} + bool PPCLinuxToolChain::SupportIEEEFloat128( const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args) const { @@ -78,10 +93,11 @@ bool PPCLinuxToolChain::SupportIEEEFloat128( CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args); bool HasUnsupportedCXXLib = - StdLib == CST_Libcxx || + (StdLib == CST_Libcxx && !defaultToIEEELongDouble()) || (StdLib == CST_Libstdcxx && GCCInstallation.getVersion().isOlderThan(12, 1, 0)); - return GlibcSupportsFloat128(Linux::getDynamicLinker(Args)) && + std::string Linker = Linux::getDynamicLinker(Args); + return GlibcSupportsFloat128((Twine(D.DyldPrefix) + Linker).str()) && !(D.CCCIsCXX() && HasUnsupportedCXXLib); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h index e0318ae8a3a2..63adaff6be9c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h @@ -27,6 +27,8 @@ public: private: bool SupportIEEEFloat128(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args) const; + bool supportIBMLongDouble(const Driver &D, + const llvm::opt::ArgList &Args) const; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp index bcf9147833dd..8ba8b80cfec7 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "PS4CPU.h" -#include "FreeBSD.h" #include "CommonArgs.h" +#include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" @@ -23,8 +23,18 @@ using namespace clang::driver; using namespace clang; using namespace llvm::opt; -void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { +// Helper to paste bits of an option together and return a saved string. +static const char *makeArgString(const ArgList &Args, const char *Prefix, + const char *Base, const char *Suffix) { + // Basically "Prefix + Base + Suffix" all converted to Twine then saved. + return Args.MakeArgString(Twine(StringRef(Prefix), Base) + Suffix); +} + +void tools::PScpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + assert(TC.getTriple().isPS()); + auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC); + if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasFlag(options::OPT_fprofile_generate, @@ -41,14 +51,16 @@ void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, options::OPT_fno_profile_generate, false) || Args.hasArg(options::OPT_fcreate_profile) || Args.hasArg(options::OPT_coverage))) - CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a"); + CmdArgs.push_back(makeArgString( + Args, "--dependent-lib=", PSTC.getProfileRTLibName(), "")); } -void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, +void tools::PScpu::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain()); claimNoWarnArgs(Args); ArgStringList CmdArgs; @@ -62,41 +74,57 @@ void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); + std::string AsName = TC.qualifyPSCmdName("as"); + const char *Exec = Args.MakeArgString(TC.GetProgramPath(AsName.c_str())); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, Output)); } -static void AddPS4SanitizerArgs(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); - if (SanArgs.needsUbsanRt()) { - CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); - } - if (SanArgs.needsAsanRt()) { - CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); - } +void tools::PScpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + assert(TC.getTriple().isPS()); + auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC); + PSTC.addSanitizerArgs(Args, CmdArgs, "--dependent-lib=lib", ".a"); } -void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); +void toolchains::PS4CPU::addSanitizerArgs(const ArgList &Args, + ArgStringList &CmdArgs, + const char *Prefix, + const char *Suffix) const { + auto arg = [&](const char *Name) -> const char * { + return makeArgString(Args, Prefix, Name, Suffix); + }; + const SanitizerArgs &SanArgs = getSanitizerArgs(Args); if (SanArgs.needsUbsanRt()) - CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a"); + CmdArgs.push_back(arg("SceDbgUBSanitizer_stub_weak")); if (SanArgs.needsAsanRt()) - CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a"); + CmdArgs.push_back(arg("SceDbgAddressSanitizer_stub_weak")); } -void tools::PS4cpu::Link::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<const toolchains::FreeBSD &>(getToolChain()); - const Driver &D = ToolChain.getDriver(); +void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args, + ArgStringList &CmdArgs, + const char *Prefix, + const char *Suffix) const { + auto arg = [&](const char *Name) -> const char * { + return makeArgString(Args, Prefix, Name, Suffix); + }; + const SanitizerArgs &SanArgs = getSanitizerArgs(Args); + if (SanArgs.needsUbsanRt()) + CmdArgs.push_back(arg("SceUBSanitizer_nosubmission_stub_weak")); + if (SanArgs.needsAsanRt()) + CmdArgs.push_back(arg("SceAddressSanitizer_nosubmission_stub_weak")); + if (SanArgs.needsTsanRt()) + CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak")); +} + +void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain()); + const Driver &D = TC.getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -116,119 +144,195 @@ void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("--oformat=so"); + CmdArgs.push_back("--shared"); + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 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_nodefaultlibs)) - AddPS4SanitizerArgs(ToolChain, Args, CmdArgs); + const bool UseLTO = D.isUsingLTO(); + const bool UseJMC = + Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false); + const bool IsPS4 = TC.getTriple().isPS4(); + + const char *PS4LTOArgs = ""; + auto AddCodeGenFlag = [&](Twine Flag) { + if (IsPS4) + PS4LTOArgs = Args.MakeArgString(Twine(PS4LTOArgs) + " " + Flag); + else + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag)); + }; + + if (UseLTO) { + // We default to creating the arange section, but LTO does not. Enable it + // here. + AddCodeGenFlag("-generate-arange-section"); + + // This tells LTO to perform JustMyCode instrumentation. + if (UseJMC) + AddCodeGenFlag("-enable-jmc-instrument"); + + if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir)) + AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue()); + + StringRef Parallelism = getLTOParallelism(Args, D); + if (!Parallelism.empty()) { + if (IsPS4) + AddCodeGenFlag(Twine("-threads=") + Parallelism); + else + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism)); + } + + if (IsPS4) { + const char *Prefix = nullptr; + if (D.getLTOMode() == LTOK_Thin) + Prefix = "-lto-thin-debug-options="; + else if (D.getLTOMode() == LTOK_Full) + Prefix = "-lto-debug-options="; + else + llvm_unreachable("new LTO mode?"); + + CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + PS4LTOArgs)); + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) + TC.addSanitizerArgs(Args, CmdArgs, "-l", ""); - Args.AddAllArgs(CmdArgs, options::OPT_L); - 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_r); + if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) { + if (D.getLTOMode() == LTOK_Thin) + CmdArgs.push_back("--lto=thin"); + else if (D.getLTOMode() == LTOK_Full) + CmdArgs.push_back("--lto=full"); + } + + Args.addAllArgs(CmdArgs, + {options::OPT_L, options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); if (Args.hasArg(options::OPT_pthread)) { CmdArgs.push_back("-lpthread"); } + if (UseJMC) { + CmdArgs.push_back("--whole-archive"); + if (IsPS4) + CmdArgs.push_back("-lSceDbgJmc"); + else + CmdArgs.push_back("-lSceJmc_nosubmission"); + CmdArgs.push_back("--no-whole-archive"); + } + if (Args.hasArg(options::OPT_fuse_ld_EQ)) { D.Diag(diag::err_drv_unsupported_opt_for_target) - << "-fuse-ld" << getToolChain().getTriple().str(); + << "-fuse-ld" << TC.getTriple().str(); } - const char *Exec = - Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); + std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName()); + const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str())); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, Output)); } -toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) +toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, StringRef Platform, + const char *EnvVar) : Generic_ELF(D, Triple, Args) { if (Args.hasArg(clang::driver::options::OPT_static)) - D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static" - << "PS4"; - - // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR - // if it exists; otherwise use the driver's installation path, which - // should be <SDK_DIR>/host_tools/bin. - - SmallString<512> PS4SDKDir; - if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { - if (!llvm::sys::fs::exists(EnvValue)) - getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; - PS4SDKDir = EnvValue; - } else { - PS4SDKDir = getDriver().Dir; - llvm::sys::path::append(PS4SDKDir, "/../../"); - } + D.Diag(clang::diag::err_drv_unsupported_opt_for_target) + << "-static" << Platform; - // By default, the driver won't report a warning if it can't find - // PS4's include or lib directories. This behavior could be changed if - // -Weverything or -Winvalid-or-nonexistent-directory options are passed. + // Determine where to find the PS4/PS5 libraries. // If -isysroot was passed, use that as the SDK base path. - std::string PrefixDir; + // If not, we use the EnvVar if it exists; otherwise use the driver's + // installation path, which should be <SDK_DIR>/host_tools/bin. + SmallString<80> Whence; if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - PrefixDir = A->getValue(); - if (!llvm::sys::fs::exists(PrefixDir)) - getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; - } else - PrefixDir = std::string(PS4SDKDir.str()); - - SmallString<512> PS4SDKIncludeDir(PrefixDir); - llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); + SDKRootDir = A->getValue(); + if (!llvm::sys::fs::exists(SDKRootDir)) + D.Diag(clang::diag::warn_missing_sysroot) << SDKRootDir; + Whence = A->getSpelling(); + } else if (const char *EnvValue = getenv(EnvVar)) { + SDKRootDir = EnvValue; + Whence = { "environment variable '", EnvVar, "'" }; + } else { + SDKRootDir = D.Dir + "/../../"; + Whence = "compiler's location"; + } + + SmallString<512> SDKIncludeDir(SDKRootDir); + llvm::sys::path::append(SDKIncludeDir, "target/include"); if (!Args.hasArg(options::OPT_nostdinc) && !Args.hasArg(options::OPT_nostdlibinc) && !Args.hasArg(options::OPT_isysroot) && !Args.hasArg(options::OPT__sysroot_EQ) && - !llvm::sys::fs::exists(PS4SDKIncludeDir)) { - getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) - << "PS4 system headers" << PS4SDKIncludeDir; + !llvm::sys::fs::exists(SDKIncludeDir)) { + D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected) + << Twine(Platform, " system headers").str() << SDKIncludeDir << Whence; } - SmallString<512> PS4SDKLibDir(PS4SDKDir); - llvm::sys::path::append(PS4SDKLibDir, "target/lib"); + SmallString<512> SDKLibDir(SDKRootDir); + llvm::sys::path::append(SDKLibDir, "target/lib"); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs) && !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && !Args.hasArg(options::OPT_emit_ast) && - !llvm::sys::fs::exists(PS4SDKLibDir)) { - getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) - << "PS4 system libraries" << PS4SDKLibDir; + !llvm::sys::fs::exists(SDKLibDir)) { + D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected) + << Twine(Platform, " system libraries").str() << SDKLibDir << Whence; return; } - getFilePaths().push_back(std::string(PS4SDKLibDir.str())); + getFilePaths().push_back(std::string(SDKLibDir)); } -Tool *toolchains::PS4CPU::buildAssembler() const { - return new tools::PS4cpu::Assemble(*this); +void toolchains::PS4PS5Base::AddClangSystemIncludeArgs( + const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + addExternCSystemInclude(DriverArgs, CC1Args, + SDKRootDir + "/target/include"); + addExternCSystemInclude(DriverArgs, CC1Args, + SDKRootDir + "/target/include_common"); } -Tool *toolchains::PS4CPU::buildLinker() const { - return new tools::PS4cpu::Link(*this); +Tool *toolchains::PS4CPU::buildAssembler() const { + return new tools::PScpu::Assembler(*this); } -bool toolchains::PS4CPU::isPICDefault() const { return true; } +Tool *toolchains::PS5CPU::buildAssembler() const { + // PS5 does not support an external assembler. + getDriver().Diag(clang::diag::err_no_external_assembler); + return nullptr; +} -bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; } +Tool *toolchains::PS4PS5Base::buildLinker() const { + return new tools::PScpu::Linker(*this); +} -SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { +SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; @@ -237,10 +341,16 @@ SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { return Res; } -void toolchains::PS4CPU::addClangTargetOptions( +SanitizerMask toolchains::PS5CPU::getSupportedSanitizers() const { + SanitizerMask Res = PS4PS5Base::getSupportedSanitizers(); + Res |= SanitizerKind::Thread; + return Res; +} + +void toolchains::PS4PS5Base::addClangTargetOptions( const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { - // PS4 does not use init arrays. + // PS4/PS5 do not use init arrays. if (DriverArgs.hasArg(options::OPT_fuse_init_array)) { Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array); getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target) @@ -249,6 +359,12 @@ void toolchains::PS4CPU::addClangTargetOptions( CC1Args.push_back("-fno-use-init-array"); + // Default to -fvisibility-global-new-delete=source for PS5. + if (getTriple().isPS5() && + !DriverArgs.hasArg(options::OPT_fvisibility_global_new_delete_EQ, + options::OPT_fvisibility_global_new_delete_hidden)) + CC1Args.push_back("-fvisibility-global-new-delete=source"); + const Arg *A = DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass, options::OPT_fno_visibility_from_dllstorageclass); @@ -281,3 +397,13 @@ void toolchains::PS4CPU::addClangTargetOptions( CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default"); } } + +// PS4 toolchain. +toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : PS4PS5Base(D, Triple, Args, "PS4", "SCE_ORBIS_SDK_DIR") {} + +// PS5 toolchain. +toolchains::PS5CPU::PS5CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : PS4PS5Base(D, Triple, Args, "PS5", "SCE_PROSPERO_SDK_DIR") {} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h index 4bedabaf267c..fee80e77462f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h @@ -18,7 +18,8 @@ namespace clang { namespace driver { namespace tools { -namespace PS4cpu { +namespace PScpu { +// Functions/classes in this namespace support both PS4 and PS5. void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); @@ -26,75 +27,72 @@ void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, void addSanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); -class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: - Assemble(const ToolChain &TC) : Tool("PS4cpu::Assemble", "assembler", TC) {} + Assembler(const ToolChain &TC) : Tool("PScpu::Assembler", "assembler", TC) {} bool hasIntegratedCPP() const override { return false; } void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, + const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Link : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: - Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("PScpu::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, + const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; -} // end namespace PS4cpu +} // namespace PScpu } // namespace tools namespace toolchains { -class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF { +// Common Toolchain base class for PS4 and PS5. +class LLVM_LIBRARY_VISIBILITY PS4PS5Base : public Generic_ELF { public: - PS4CPU(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); + PS4PS5Base(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, StringRef Platform, + const char *EnvVar); + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; // No support for finding a C++ standard library yet. - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override { + } + void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } - bool HasNativeLLVMSupport() const override; - bool isPICDefault() const override; + bool HasNativeLLVMSupport() const override { return true; } + bool isPICDefault() const override { return true; } LangOptions::StackProtectorMode GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return LangOptions::SSPStrong; } - unsigned GetDefaultDwarfVersion() const override { return 4; } llvm::DebuggerKind getDefaultDebuggerTuning() const override { return llvm::DebuggerKind::SCE; } SanitizerMask getSupportedSanitizers() const override; - // PS4 toolchain uses legacy thin LTO API, which is not - // capable of unit splitting. - bool canSplitThinLTOUnit() const override { return false; } - void addClangTargetOptions( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadingKind) const override; + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const override; llvm::DenormalMode getDefaultDenormalModeForType( const llvm::opt::ArgList &DriverArgs, const JobAction &JA, @@ -103,11 +101,73 @@ public: return llvm::DenormalMode::getPreserveSign(); } - bool useRelaxRelocations() const override { return true; } + // Helper methods for PS4/PS5. + virtual const char *getLinkerBaseName() const = 0; + virtual std::string qualifyPSCmdName(StringRef CmdName) const = 0; + virtual void addSanitizerArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const char *Prefix, + const char *Suffix) const = 0; + virtual const char *getProfileRTLibName() const = 0; protected: - Tool *buildAssembler() const override; Tool *buildLinker() const override; + +private: + // We compute the SDK root dir in the ctor, and use it later. + std::string SDKRootDir; +}; + +// PS4-specific Toolchain class. +class LLVM_LIBRARY_VISIBILITY PS4CPU : public PS4PS5Base { +public: + PS4CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + unsigned GetDefaultDwarfVersion() const override { return 4; } + + // PS4 toolchain uses legacy thin LTO API, which is not + // capable of unit splitting. + bool canSplitThinLTOUnit() const override { return false; } + + const char *getLinkerBaseName() const override { return "ld"; } + std::string qualifyPSCmdName(StringRef CmdName) const override { + return Twine("orbis-", CmdName).str(); + } + void addSanitizerArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, const char *Prefix, + const char *Suffix) const override; + const char *getProfileRTLibName() const override { + return "libclang_rt.profile-x86_64.a"; + } + +protected: + Tool *buildAssembler() const override; +}; + +// PS5-specific Toolchain class. +class LLVM_LIBRARY_VISIBILITY PS5CPU : public PS4PS5Base { +public: + PS5CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + unsigned GetDefaultDwarfVersion() const override { return 5; } + + SanitizerMask getSupportedSanitizers() const override; + + const char *getLinkerBaseName() const override { return "lld"; } + std::string qualifyPSCmdName(StringRef CmdName) const override { + return Twine("prospero-", CmdName).str(); + } + void addSanitizerArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, const char *Prefix, + const char *Suffix) const override; + const char *getProfileRTLibName() const override { + return "libclang_rt.profile-x86_64_nosubmission.a"; + } + +protected: + Tool *buildAssembler() const override; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index 714325a2db39..5e4fa4d5331f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -1,4 +1,4 @@ -//===--- RISCVToolchain.cpp - RISCV ToolChain Implementations ---*- C++ -*-===// +//===--- RISCVToolchain.cpp - RISC-V 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. @@ -46,17 +46,17 @@ bool RISCVToolChain::hasGCCToolchain(const Driver &D, return llvm::sys::fs::exists(GCCDir); } -/// RISCV Toolchain +/// RISC-V Toolchain RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); if (GCCInstallation.isValid()) { Multilibs = GCCInstallation.getMultilibs(); - SelectedMultilib = GCCInstallation.getMultilib(); + SelectedMultilibs.assign({GCCInstallation.getMultilib()}); path_list &Paths = getFilePaths(); // Add toolchain/multilib specific file paths. - addMultilibsFilePaths(D, Multilibs, SelectedMultilib, + addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(), GCCInstallation.getInstallPath(), Paths); getFilePaths().push_back(GCCInstallation.getInstallPath().str()); ToolChain::path_list &PPaths = getProgramPaths(); @@ -98,6 +98,12 @@ void RISCVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (DriverArgs.hasArg(options::OPT_nostdinc)) return; + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(getDriver().ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { SmallString<128> Dir(computeSysRoot()); llvm::sys::path::append(Dir, "include"); @@ -135,7 +141,7 @@ std::string RISCVToolChain::computeSysRoot() const { if (!llvm::sys::fs::exists(SysRootDir)) return std::string(); - return std::string(SysRootDir.str()); + return std::string(SysRootDir); } void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -157,6 +163,7 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, } else { CmdArgs.push_back("elf32lriscv"); } + CmdArgs.push_back("-X"); std::string Linker = getToolChain().GetLinkerPath(); @@ -183,19 +190,21 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); // TODO: add C++ includes and libs if compiling C++. if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { - if (ToolChain.ShouldLinkCXXStdlib(Args)) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (D.CCCIsCXX()) { + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } CmdArgs.push_back("--start-group"); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgloss"); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h index 62099bee0404..cec817ef7190 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -1,4 +1,4 @@ -//===--- RISCVToolchain.h - RISCV ToolChain Implementations -----*- C++ -*-===// +//===--- RISCVToolchain.h - RISC-V 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. @@ -22,7 +22,6 @@ public: const llvm::opt::ArgList &Args); static bool hasGCCToolchain(const Driver &D, const llvm::opt::ArgList &Args); - bool IsIntegratedAssemblerDefault() const override { return true; } void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind) const override; @@ -47,7 +46,7 @@ private: namespace tools { namespace RISCV { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("RISCV::Linker", "ld", TC) {} bool hasIntegratedCPP() const override { return false; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h index bb482be68260..dceb0ab03669 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h @@ -15,13 +15,33 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/Triple.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/VersionTuple.h" +#include "llvm/TargetParser/Triple.h" namespace clang { namespace driver { +/// ABI version of device library. +struct DeviceLibABIVersion { + unsigned ABIVersion = 0; + DeviceLibABIVersion(unsigned V) : ABIVersion(V) {} + static DeviceLibABIVersion fromCodeObjectVersion(unsigned CodeObjectVersion) { + if (CodeObjectVersion < 4) + CodeObjectVersion = 4; + return DeviceLibABIVersion(CodeObjectVersion * 100); + } + /// Whether ABI version bc file is requested. + /// ABIVersion is code object version multiplied by 100. Code object v4 + /// and below works with ROCm 5.0 and below which does not have + /// abi_version_*.bc. Code object v5 requires abi_version_500.bc. + bool requiresLibrary() { return ABIVersion >= 500; } + std::string toString() { + assert(ABIVersion % 100 == 0 && "Not supported"); + return Twine(ABIVersion / 100).str(); + } +}; + /// A class to find a viable ROCM installation /// TODO: Generalize to handle libclc. class RocmInstallationDetector { @@ -57,6 +77,9 @@ private: const Driver &D; bool HasHIPRuntime = false; bool HasDeviceLibrary = false; + bool HasHIPStdParLibrary = false; + bool HasRocThrustLibrary = false; + bool HasRocPrimLibrary = false; // Default version if not detected or specified. const unsigned DefaultVersionMajor = 3; @@ -76,6 +99,13 @@ private: std::vector<std::string> RocmDeviceLibPathArg; // HIP runtime path specified by --hip-path. StringRef HIPPathArg; + // HIP Standard Parallel Algorithm acceleration library specified by + // --hipstdpar-path + StringRef HIPStdParPathArg; + // rocThrust algorithm library specified by --hipstdpar-thrust-path + StringRef HIPRocThrustPathArg; + // rocPrim algorithm library specified by --hipstdpar-prim-path + StringRef HIPRocPrimPathArg; // HIP version specified by --hip-version. StringRef HIPVersionArg; // Wheter -nogpulib is specified. @@ -87,6 +117,7 @@ private: SmallString<0> LibPath; SmallString<0> LibDevicePath; SmallString<0> IncludePath; + SmallString<0> SharePath; llvm::StringMap<std::string> LibDeviceMap; // Libraries that are always linked. @@ -107,6 +138,10 @@ private: ConditionalLibrary DenormalsAreZero; ConditionalLibrary CorrectlyRoundedSqrt; + // Maps ABI version to library path. The version number is in the format of + // three digits as used in the ABI version library name. + std::map<unsigned, std::string> ABIVersionMap; + // Cache ROCm installation search paths. SmallVector<Candidate, 4> ROCmSearchDirs; bool PrintROCmSearchDirs; @@ -142,7 +177,12 @@ public: getCommonBitcodeLibs(const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile, bool Wave64, bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, - bool FastRelaxedMath, bool CorrectSqrt) const; + bool FastRelaxedMath, bool CorrectSqrt, + DeviceLibABIVersion ABIVer, bool isOpenMP) const; + /// Check file paths of default bitcode libraries common to AMDGPU based + /// toolchains. \returns false if there are invalid or missing files. + bool checkCommonBitcodeLibs(StringRef GPUArch, StringRef LibDeviceFile, + DeviceLibABIVersion ABIVer) const; /// Check whether we detected a valid HIP runtime. bool hasHIPRuntime() const { return HasHIPRuntime; } @@ -150,6 +190,9 @@ public: /// Check whether we detected a valid ROCm device library. bool hasDeviceLibrary() const { return HasDeviceLibrary; } + /// Check whether we detected a valid HIP STDPAR Acceleration library. + bool hasHIPStdParLibrary() const { return HasHIPStdParLibrary; } + /// Print information about the detected ROCm installation. void print(raw_ostream &OS) const; @@ -214,9 +257,19 @@ public: return CorrectlyRoundedSqrt.get(Enabled); } + StringRef getABIVersionPath(DeviceLibABIVersion ABIVer) const { + auto Loc = ABIVersionMap.find(ABIVer.ABIVersion); + if (Loc == ABIVersionMap.end()) + return StringRef(); + return Loc->second; + } + /// Get libdevice file for given architecture - std::string getLibDeviceFile(StringRef Gpu) const { - return LibDeviceMap.lookup(Gpu); + StringRef getLibDeviceFile(StringRef Gpu) const { + auto Loc = LibDeviceMap.find(Gpu); + if (Loc == LibDeviceMap.end()) + return ""; + return Loc->second; } void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, @@ -226,7 +279,7 @@ public: void detectHIPRuntime(); /// Get the values for --rocm-device-lib-path arguments - std::vector<std::string> getRocmDeviceLibPathArg() const { + ArrayRef<std::string> getRocmDeviceLibPathArg() const { return RocmDeviceLibPathArg; } @@ -236,7 +289,7 @@ public: /// Get the value for --hip-version argument StringRef getHIPVersionArg() const { return HIPVersionArg; } - std::string getHIPVersion() const { return DetectedVersion; } + StringRef getHIPVersion() const { return DetectedVersion; } }; } // end namespace driver diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h index a16ae3ca51fa..d4247ee0557f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h @@ -17,9 +17,6 @@ namespace driver { namespace tools { namespace SPIRV { -void addTranslatorArgs(const llvm::opt::ArgList &InArgs, - llvm::opt::ArgStringList &OutArgs); - void constructTranslateCommand(Compilation &C, const Tool &T, const JobAction &JA, const InputInfo &Output, const InputInfo &Input, @@ -39,7 +36,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("SPIRV::Linker", "spirv-link", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -64,8 +61,9 @@ public: : ToolChain(D, Triple, Args) {} bool useIntegratedAs() const override { return true; } - bool useIntegratedBackend() const override { return false; } + bool IsIntegratedBackendDefault() const override { return false; } + bool IsNonIntegratedBackendSupported() const override { return true; } bool IsMathErrnoDefault() const override { return false; } bool isCrossCompiling() const override { return true; } bool isPICDefault() const override { return false; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp index 24f18b92dd66..200ac46aa534 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp @@ -8,12 +8,16 @@ #include "Solaris.h" #include "CommonArgs.h" +#include "Gnu.h" #include "clang/Basic/LangStandard.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -29,20 +33,50 @@ void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; + // Just call the Gnu version, which enforces gas on Solaris. + gnutools::Assembler::ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput); +} - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); +bool solaris::isLinkerGnuLd(const ToolChain &TC, const ArgList &Args) { + // Only used if targetting Solaris. + const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ); + StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER; + return UseLinker == "bfd" || UseLinker == "gld"; +} - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); +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)) + return false; - for (const auto &II : Inputs) - CmdArgs.push_back(II.getFilename()); + return Args.hasFlag(options::OPT_pie, options::OPT_no_pie, + TC.isPIEDefault(Args)); +} - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Exec, CmdArgs, Inputs, Output)); +// FIXME: Need to handle CLANG_DEFAULT_LINKER here? +std::string solaris::Linker::getLinkerPath(const ArgList &Args) const { + const ToolChain &ToolChain = getToolChain(); + if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { + StringRef UseLinker = A->getValue(); + if (!UseLinker.empty()) { + if (llvm::sys::path::is_absolute(UseLinker) && + llvm::sys::fs::can_execute(UseLinker)) + return std::string(UseLinker); + + // Accept 'bfd' and 'gld' as aliases for the GNU linker. + if (UseLinker == "bfd" || UseLinker == "gld") + // FIXME: Could also use /usr/bin/gld here. + return "/usr/gnu/bin/ld"; + + // Accept 'ld' as alias for the default linker + if (UseLinker != "ld") + ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name) + << A->getAsString(Args); + } + } + + // getDefaultLinker() always returns an absolute path. + return ToolChain.getDefaultLinker(); } void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -50,24 +84,38 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const auto &ToolChain = static_cast<const Solaris &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool IsPIE = getPIE(Args, ToolChain); + const bool LinkerIsGnuLd = isLinkerGnuLd(ToolChain, Args); ArgStringList CmdArgs; - // Demangle C++ names in errors - CmdArgs.push_back("-C"); + // Demangle C++ names in errors. GNU ld already defaults to --demangle. + if (!LinkerIsGnuLd) + CmdArgs.push_back("-C"); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared, + options::OPT_r)) { CmdArgs.push_back("-e"); CmdArgs.push_back("_start"); } + if (IsPIE) { + if (LinkerIsGnuLd) { + CmdArgs.push_back("-pie"); + } else { + CmdArgs.push_back("-z"); + CmdArgs.push_back("type=pie"); + } + } + if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); CmdArgs.push_back("-dn"); } else { - CmdArgs.push_back("-Bdynamic"); - if (Args.hasArg(options::OPT_shared)) { + if (!Args.hasArg(options::OPT_r) && Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-shared"); - } // libpthread has been folded into libc since Solaris 10, no need to do // anything for pthreads. Claim argument to avoid warning. @@ -75,19 +123,50 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_pthreads); } + if (LinkerIsGnuLd) { + // Set the correct linker emulation for 32- and 64-bit Solaris. + switch (Arch) { + case llvm::Triple::x86: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf_i386_sol2"); + break; + case llvm::Triple::x86_64: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf_x86_64_sol2"); + break; + case llvm::Triple::sparc: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf32_sparc_sol2"); + break; + case llvm::Triple::sparcv9: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf64_sparc_sol2"); + break; + default: + break; + } + + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + CmdArgs.push_back("--eh-frame-hdr"); + } else { + // -rdynamic is a no-op with Solaris ld. Claim argument to avoid warning. + Args.ClaimAllArgs(options::OPT_rdynamic); + } + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 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)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi); bool HaveAnsi = false; @@ -102,29 +181,54 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409. if (HaveAnsi || (LangStd && !LangStd->isGNUMode())) values_X = "values-Xc.o"; - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(values_X))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(values_X))); const char *values_xpg = "values-xpg6.o"; // Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409. if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99()) values_xpg = "values-xpg4.o"; - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath(values_xpg))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(values_xpg))); + + const char *crtbegin = nullptr; + if (Args.hasArg(options::OPT_shared) || IsPIE) + crtbegin = "crtbeginS.o"; + else + crtbegin = "crtbegin.o"; + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + // Add crtfastmath.o if available and fast math is enabled. + ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs); } - getToolChain().AddFilePathLibArgs(Args, CmdArgs); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_e, options::OPT_r}); + Args.addAllArgs(CmdArgs, + {options::OPT_L, options::OPT_T_Group, options::OPT_r}); - bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (getToolChain().ShouldLinkCXXStdlib(Args)) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { + // 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); + CmdArgs.push_back("-lm"); + } + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below. + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(getToolChain(), Args, CmdArgs); + addFortranRuntimeLibs(getToolChain(), Args, CmdArgs); + CmdArgs.push_back("-lm"); + } if (Args.hasArg(options::OPT_fstack_protector) || Args.hasArg(options::OPT_fstack_protector_strong) || Args.hasArg(options::OPT_fstack_protector_all)) { @@ -134,30 +238,55 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, } // LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so // forcibly link with libatomic as a workaround. - if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) { - CmdArgs.push_back(getAsNeededOption(getToolChain(), true)); + if (Arch == llvm::Triple::sparc) { + addAsNeededOption(ToolChain, Args, CmdArgs, true); CmdArgs.push_back("-latomic"); - CmdArgs.push_back(getAsNeededOption(getToolChain(), false)); + addAsNeededOption(ToolChain, Args, CmdArgs, false); } + addAsNeededOption(ToolChain, Args, CmdArgs, true); CmdArgs.push_back("-lgcc_s"); + addAsNeededOption(ToolChain, Args, CmdArgs, false); CmdArgs.push_back("-lc"); if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("-lm"); } - if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); + const SanitizerArgs &SA = ToolChain.getSanitizerArgs(Args); + if (NeedsSanitizerDeps) { + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); + + // Work around Solaris/amd64 ld bug when calling __tls_get_addr directly. + // However, ld -z relax=transtls is available since Solaris 11.2, but not + // in Illumos. + if (Arch == llvm::Triple::x86_64 && + (SA.needsAsanRt() || SA.needsStatsRt() || + (SA.needsUbsanRt() && !SA.requiresMinimalRuntime())) && + !LinkerIsGnuLd) { + CmdArgs.push_back("-z"); + CmdArgs.push_back("relax=transtls"); + } + } + // Avoid AsanInitInternal cycle, Issue #64126. + if (ToolChain.getTriple().isX86() && SA.needsSharedRt() && + SA.needsAsanRt()) { + CmdArgs.push_back("-z"); + CmdArgs.push_back("now"); + } } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + const char *crtend = nullptr; + if (Args.hasArg(options::OPT_shared) || IsPIE) + crtend = "crtendS.o"; + else + crtend = "crtend.o"; + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - getToolChain().addProfileRTLibs(Args, CmdArgs); + ToolChain.addProfileRTLibs(Args, CmdArgs); - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + const char *Exec = Args.MakeArgString(getLinkerPath(Args)); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, Inputs, Output)); } @@ -166,13 +295,12 @@ static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) { switch (Triple.getArch()) { case llvm::Triple::x86: case llvm::Triple::sparc: + default: break; case llvm::Triple::x86_64: return "/amd64"; case llvm::Triple::sparcv9: return "/sparcv9"; - default: - llvm_unreachable("Unsupported architecture"); } return ""; } @@ -199,7 +327,7 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, // If we are currently running Clang inside of the requested system root, // add its parent library path to those searched. - if (StringRef(D.Dir).startswith(D.SysRoot)) + if (StringRef(D.Dir).starts_with(D.SysRoot)) addPathIfExists(D, D.Dir + "/../lib", Paths); addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths); @@ -207,7 +335,6 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, SanitizerMask Solaris::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; - const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; SanitizerMask Res = ToolChain::getSupportedSanitizers(); // FIXME: Omit X86_64 until 64-bit support is figured out. if (IsX86) { @@ -215,12 +342,17 @@ SanitizerMask Solaris::getSupportedSanitizers() const { Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; } - if (IsX86 || IsX86_64) - Res |= SanitizerKind::Function; Res |= SanitizerKind::Vptr; return Res; } +const char *Solaris::getDefaultLinker() const { + // FIXME: Only handle Solaris ld and GNU ld here. + return llvm::StringSwitch<const char *>(CLANG_DEFAULT_LINKER) + .Cases("bfd", "gld", "/usr/gnu/bin/ld") + .Default("/usr/bin/ld"); +} + Tool *Solaris::buildAssembler() const { return new tools::solaris::Assembler(*this); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h index fbac92c2c0f3..9ec83b773da4 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h @@ -17,12 +17,11 @@ namespace clang { namespace driver { namespace tools { -/// solaris -- Directly call Solaris assembler and linker +/// Directly call Solaris assembler and linker namespace solaris { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public gnutools::Assembler { public: - Assembler(const ToolChain &TC) - : Tool("solaris::Assembler", "assembler", TC) {} + Assembler(const ToolChain &TC) : gnutools::Assembler(TC) {} bool hasIntegratedCPP() const override { return false; } @@ -32,12 +31,15 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +bool isLinkerGnuLd(const ToolChain &TC, const llvm::opt::ArgList &Args); + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("solaris::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } + std::string getLinkerPath(const llvm::opt::ArgList &Args) const; void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -63,12 +65,8 @@ public: llvm::opt::ArgStringList &CC1Args) const override; SanitizerMask getSupportedSanitizers() const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } - const char *getDefaultLinker() const override { - // clang currently uses Solaris ld-only options. - return "/usr/bin/ld"; - } + const char *getDefaultLinker() const override; protected: Tool *buildAssembler() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp index 1e43796be1ff..39529e0b6b35 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp @@ -33,7 +33,8 @@ VEToolChain::VEToolChain(const Driver &D, const llvm::Triple &Triple, // These are OK. // Default file paths are following: - // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPath) + // ${RESOURCEDIR}/lib/ve-unknown-linux-gnu, (== getArchSpecificLibPaths) + // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPaths) // /lib/../lib64, // /usr/lib/../lib64, // ${BINPATH}/../lib, @@ -46,11 +47,13 @@ VEToolChain::VEToolChain(const Driver &D, const llvm::Triple &Triple, // Add library directories: // ${BINPATH}/../lib/ve-unknown-linux-gnu, (== getStdlibPath) - // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPath) + // ${RESOURCEDIR}/lib/ve-unknown-linux-gnu, (== getArchSpecificLibPaths) + // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPaths) // ${SYSROOT}/opt/nec/ve/lib, - for (auto &Path : getStdlibPaths()) - getFilePaths().push_back(std::move(Path)); - getFilePaths().push_back(getArchSpecificLibPath()); + if (std::optional<std::string> Path = getStdlibPath()) + getFilePaths().push_back(std::move(*Path)); + for (const auto &Path : getArchSpecificLibPaths()) + getFilePaths().push_back(Path); getFilePaths().push_back(computeSysRoot() + "/opt/nec/ve/lib"); } @@ -140,7 +143,15 @@ void VEToolChain::AddCXXStdlibLibArgs(const ArgList &Args, tools::addArchSpecificRPath(*this, Args, CmdArgs); + // Add paths for libc++.so and other shared libraries. + if (std::optional<std::string> Path = getStdlibPath()) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back(Args.MakeArgString(*Path)); + } + CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); // libc++ requires -lpthread under glibc environment diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h index 964b0d0dd8d4..8b9ccaa7fada 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h @@ -26,7 +26,6 @@ protected: Tool *buildLinker() const override; public: - bool IsIntegratedAssemblerDefault() const override { return true; } bool isPICDefault() const override; bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp index 3614272a5f74..0b16b660364f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -8,15 +8,17 @@ #include "WebAssembly.h" #include "CommonArgs.h" +#include "Gnu.h" #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Option/ArgList.h" +#include "llvm/Support/VirtualFileSystem.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -42,8 +44,15 @@ std::string wasm::Linker::getLinkerPath(const ArgList &Args) const { llvm::sys::fs::can_execute(UseLinker)) return std::string(UseLinker); - // Accept 'lld', and 'ld' as aliases for the default linker - if (UseLinker != "lld" && UseLinker != "ld") + // Interpret 'lld' as explicitly requesting `wasm-ld`, so look for that + // linker. Note that for `wasm32-wasip2` this overrides the default linker + // of `wasm-component-ld`. + if (UseLinker == "lld") { + return ToolChain.GetProgramPath("wasm-ld"); + } + + // Allow 'ld' as an alias for the default linker + if (UseLinker != "ld") ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args); } @@ -71,34 +80,56 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("--strip-all"); - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + // On `wasip2` the default linker is `wasm-component-ld` which wraps the + // execution of `wasm-ld`. Find `wasm-ld` and pass it as an argument of where + // to find it to avoid it needing to hunt and rediscover or search `PATH` for + // where it is. + if (llvm::sys::path::stem(Linker).ends_with_insensitive( + "wasm-component-ld")) { + CmdArgs.push_back("--wasm-ld-path"); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetProgramPath("wasm-ld"))); + } + + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); - const char *Crt1 = "crt1.o"; + bool IsCommand = true; + const char *Crt1; const char *Entry = nullptr; - // If crt1-command.o exists, it supports new-style commands, so use it. - // Otherwise, use the old crt1.o. This is a temporary transition measure. - // Once WASI libc no longer needs to support LLVM versions which lack - // support for new-style command, it can make crt1.o the same as - // crt1-command.o. And once LLVM no longer needs to support WASI libc - // versions before that, it can switch to using crt1-command.o. - if (ToolChain.GetFilePath("crt1-command.o") != "crt1-command.o") - Crt1 = "crt1-command.o"; + // When -shared is specified, use the reactor exec model unless + // specified otherwise. + if (Args.hasArg(options::OPT_shared)) + IsCommand = false; if (const Arg *A = Args.getLastArg(options::OPT_mexec_model_EQ)) { StringRef CM = A->getValue(); if (CM == "command") { - // Use default values. + IsCommand = true; } else if (CM == "reactor") { - Crt1 = "crt1-reactor.o"; - Entry = "_initialize"; + IsCommand = false; } else { ToolChain.getDriver().Diag(diag::err_drv_invalid_argument_to_option) << CM << A->getOption().getName(); } } + + if (IsCommand) { + // If crt1-command.o exists, it supports new-style commands, so use it. + // Otherwise, use the old crt1.o. This is a temporary transition measure. + // Once WASI libc no longer needs to support LLVM versions which lack + // support for new-style command, it can make crt1.o the same as + // crt1-command.o. And once LLVM no longer needs to support WASI libc + // versions before that, it can switch to using crt1-command.o. + Crt1 = "crt1.o"; + if (ToolChain.GetFilePath("crt1-command.o") != "crt1-command.o") + Crt1 = "crt1-command.o"; + } else { + Crt1 = "crt1-reactor.o"; + Entry = "_initialize"; + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(Crt1))); if (Entry) { @@ -106,6 +137,9 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Entry)); } + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back(Args.MakeArgString("-shared")); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -124,14 +158,25 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); + // When optimizing, if wasm-opt is available, run it. + std::string WasmOptPath; + if (Args.getLastArg(options::OPT_O_Group)) { + WasmOptPath = ToolChain.GetProgramPath("wasm-opt"); + if (WasmOptPath == "wasm-opt") { + WasmOptPath = {}; + } + } + + if (!WasmOptPath.empty()) { + CmdArgs.push_back("--keep-section=target_features"); + } + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Linker, CmdArgs, Inputs, Output)); - // When optimizing, if wasm-opt is available, run it. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - auto WasmOptPath = ToolChain.GetProgramPath("wasm-opt"); - if (WasmOptPath != "wasm-opt") { + if (!WasmOptPath.empty()) { StringRef OOpt = "s"; if (A->getOption().matches(options::OPT_O4) || A->getOption().matches(options::OPT_Ofast)) @@ -143,13 +188,13 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (OOpt != "0") { const char *WasmOpt = Args.MakeArgString(WasmOptPath); - ArgStringList CmdArgs; - CmdArgs.push_back(Output.getFilename()); - CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); + ArgStringList OptArgs; + OptArgs.push_back(Output.getFilename()); + OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); + OptArgs.push_back("-o"); + OptArgs.push_back(Output.getFilename()); C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, CmdArgs, + JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs, Inputs, Output)); } } @@ -193,6 +238,12 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, } } +const char *WebAssembly::getDefaultLinker() const { + if (getOS() == "wasip2") + return "wasm-component-ld"; + return "wasm-ld"; +} + bool WebAssembly::IsMathErrnoDefault() const { return false; } bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; } @@ -207,8 +258,6 @@ bool WebAssembly::isPIEDefault(const llvm::opt::ArgList &Args) const { bool WebAssembly::isPICDefaultForced() const { return false; } -bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; } - bool WebAssembly::hasBlocksRuntime() const { return false; } // TODO: Support profiling. @@ -302,7 +351,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { StringRef Opt = A->getValue(0); - if (Opt.startswith("-emscripten-cxx-exceptions-allowed")) { + if (Opt.starts_with("-emscripten-cxx-exceptions-allowed")) { // '-mllvm -emscripten-cxx-exceptions-allowed' should be used with // '-mllvm -enable-emscripten-cxx-exceptions' bool EmEHArgExists = false; @@ -329,7 +378,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, } } - if (Opt.startswith("-wasm-enable-sjlj")) { + if (Opt.starts_with("-wasm-enable-sjlj")) { // '-mllvm -wasm-enable-sjlj' is not compatible with // '-mno-exception-handling' if (DriverArgs.hasFlag(options::OPT_mno_exception_handing, @@ -371,7 +420,11 @@ ToolChain::CXXStdlibType WebAssembly::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); - if (Value != "libc++") + if (Value == "libc++") + return ToolChain::CST_Libcxx; + else if (Value == "libstdc++") + return ToolChain::CST_Libstdcxx; + else getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } @@ -417,17 +470,18 @@ void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && - !DriverArgs.hasArg(options::OPT_nostdincxx)) { - if (getTriple().getOS() != llvm::Triple::UnknownOS) { - const std::string MultiarchTriple = - getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/" + MultiarchTriple + - "/c++/v1"); - } - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/c++/v1"); + + if (DriverArgs.hasArg(options::OPT_nostdlibinc, options::OPT_nostdinc, + options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addLibCxxIncludePaths(DriverArgs, CC1Args); + break; + case ToolChain::CST_Libstdcxx: + addLibStdCXXIncludePaths(DriverArgs, CC1Args); + break; } } @@ -437,10 +491,13 @@ void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: - llvm_unreachable("invalid stdlib name"); + CmdArgs.push_back("-lstdc++"); + break; } } @@ -449,9 +506,86 @@ SanitizerMask WebAssembly::getSupportedSanitizers() const { if (getTriple().isOSEmscripten()) { Res |= SanitizerKind::Vptr | SanitizerKind::Leak | SanitizerKind::Address; } + // -fsanitize=function places two words before the function label, which are + // -unsupported. + Res &= ~SanitizerKind::Function; return Res; } Tool *WebAssembly::buildLinker() const { return new tools::wasm::Linker(*this); } + +void WebAssembly::addLibCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + std::string LibPath = SysRoot + "/include"; + const std::string MultiarchTriple = + getMultiarchTriple(D, getTriple(), SysRoot); + bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS); + + std::string Version = detectLibcxxVersion(LibPath); + if (Version.empty()) + return; + + // First add the per-target include path if the OS is known. + if (IsKnownOs) { + std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/" + Version; + addSystemInclude(DriverArgs, CC1Args, TargetDir); + } + + // Second add the generic one. + addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version); +} + +void WebAssembly::addLibStdCXXIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // We cannot use GCCInstallationDetector here as the sysroot usually does + // not contain a full GCC installation. + // Instead, we search the given sysroot for /usr/include/xx, similar + // to how we do it for libc++. + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + std::string LibPath = SysRoot + "/include"; + const std::string MultiarchTriple = + getMultiarchTriple(D, getTriple(), SysRoot); + bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS); + + // This is similar to detectLibcxxVersion() + std::string Version; + { + std::error_code EC; + Generic_GCC::GCCVersion MaxVersion = + Generic_GCC::GCCVersion::Parse("0.0.0"); + SmallString<128> Path(LibPath); + llvm::sys::path::append(Path, "c++"); + for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(Path, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + if (VersionText[0] != 'v') { + auto Version = Generic_GCC::GCCVersion::Parse(VersionText); + if (Version > MaxVersion) + MaxVersion = Version; + } + } + if (MaxVersion.Major > 0) + Version = MaxVersion.Text; + } + + if (Version.empty()) + return; + + // First add the per-target include path if the OS is known. + if (IsKnownOs) { + std::string TargetDir = LibPath + "/c++/" + Version + "/" + MultiarchTriple; + addSystemInclude(DriverArgs, CC1Args, TargetDir); + } + + // Second add the generic one. + addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version); + // Third the backward one. + addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version + "/backward"); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h index b4c3082a089a..76e0ca39bd74 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h @@ -18,7 +18,7 @@ namespace driver { namespace tools { namespace wasm { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: explicit Linker(const ToolChain &TC) : Tool("wasm::Linker", "linker", TC) {} bool isLinkJob() const override { return true; } @@ -47,7 +47,6 @@ private: bool isPICDefault() const override; bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; - bool IsIntegratedAssemblerDefault() const override; bool hasBlocksRuntime() const override; bool SupportsProfiling() const override; bool HasNativeLLVMSupport() const override; @@ -68,13 +67,22 @@ private: llvm::opt::ArgStringList &CmdArgs) const override; SanitizerMask getSupportedSanitizers() const override; - const char *getDefaultLinker() const override { return "wasm-ld"; } + const char *getDefaultLinker() const override; + + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } Tool *buildLinker() const override; std::string getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, StringRef SysRoot) const override; + + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + void addLibStdCXXIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp index 29fa82aec0a9..c95ebabdd30c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp @@ -63,11 +63,10 @@ void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { ArgStringList CmdArgs; + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } if (Args.hasArg(options::OPT_v)) diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h index d9a05da3c678..95359a6e2542 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h @@ -20,7 +20,7 @@ namespace XCore { // For XCore, we do not need to instantiate tools for PreProcess, PreCompile and // Compile. // We simply use "clang -cc1" for those actions. -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("XCore::Assembler", "XCore-as", TC) {} @@ -31,7 +31,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("XCore::Linker", "XCore-ld", TC) {} @@ -57,6 +57,7 @@ protected: Tool *buildLinker() const override; public: + bool IsIntegratedAssemblerDefault() const override { return false; } bool isPICDefault() const override; bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp index f921227076a5..96dbf602e7c1 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp @@ -11,11 +11,17 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/WithColor.h" +using namespace clang; using namespace clang::driver; +using namespace clang::driver::tools; using namespace clang::driver::toolchains; +using namespace llvm; using namespace llvm::opt; -using namespace clang; +using namespace llvm::sys; ZOS::ZOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) {} @@ -31,3 +37,303 @@ void ZOS::addClangTargetOptions(const ArgList &DriverArgs, options::OPT_fno_aligned_allocation)) CC1Args.push_back("-faligned-alloc-unavailable"); } + +void zos::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + // Specify assembler output file. + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + // Specify assembler input file. + // The system assembler on z/OS takes exactly one input file. The driver is + // expected to invoke as(1) separately for each assembler source input file. + if (Inputs.size() != 1) + llvm_unreachable("Invalid number of input files."); + const InputInfo &II = Inputs[0]; + assert((II.isFilename() || II.isNothing()) && "Invalid input."); + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); +} + +static std::string getLEHLQ(const ArgList &Args) { + if (Args.hasArg(options::OPT_mzos_hlq_le_EQ)) { + Arg *LEHLQArg = Args.getLastArg(options::OPT_mzos_hlq_le_EQ); + StringRef HLQ = LEHLQArg->getValue(); + if (!HLQ.empty()) + return HLQ.str(); + } + return "CEE"; +} + +static std::string getClangHLQ(const ArgList &Args) { + if (Args.hasArg(options::OPT_mzos_hlq_clang_EQ)) { + Arg *ClangHLQArg = Args.getLastArg(options::OPT_mzos_hlq_clang_EQ); + StringRef HLQ = ClangHLQArg->getValue(); + if (!HLQ.empty()) + return HLQ.str(); + } + return getLEHLQ(Args); +} + +static std::string getCSSHLQ(const ArgList &Args) { + if (Args.hasArg(options::OPT_mzos_hlq_csslib_EQ)) { + Arg *CsslibHLQArg = Args.getLastArg(options::OPT_mzos_hlq_csslib_EQ); + StringRef HLQ = CsslibHLQArg->getValue(); + if (!HLQ.empty()) + return HLQ.str(); + } + return "SYS1"; +} + +void zos::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + const char *LinkingOutput) const { + const ZOS &ToolChain = static_cast<const ZOS &>(getToolChain()); + ArgStringList CmdArgs; + + const bool IsSharedLib = + Args.hasFlag(options::OPT_shared, options::OPT_static, false); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + SmallString<128> LinkerOptions; + LinkerOptions = "AMODE="; + LinkerOptions += "64"; + LinkerOptions += ",LIST"; + LinkerOptions += ",DYNAM=DLL"; + LinkerOptions += ",MSGLEVEL=4"; + LinkerOptions += ",CASE=MIXED"; + LinkerOptions += ",REUS=RENT"; + + CmdArgs.push_back("-b"); + CmdArgs.push_back(Args.MakeArgString(LinkerOptions)); + + if (!IsSharedLib) { + CmdArgs.push_back("-e"); + CmdArgs.push_back("CELQSTRT"); + + CmdArgs.push_back("-O"); + CmdArgs.push_back("CELQSTRT"); + + CmdArgs.push_back("-u"); + CmdArgs.push_back("CELQMAIN"); + } + + // Generate side file if -shared option is present. + if (IsSharedLib) { + StringRef OutputName = Output.getFilename(); + // Strip away the last file suffix in presence from output name and add + // a new .x suffix. + size_t Suffix = OutputName.find_last_of('.'); + const char *SideDeckName = + Args.MakeArgString(OutputName.substr(0, Suffix) + ".x"); + CmdArgs.push_back("-x"); + CmdArgs.push_back(SideDeckName); + } else { + // We need to direct side file to /dev/null to suppress linker warning when + // the object file contains exported symbols, and -shared or + // -Wl,-x<sidedeck>.x is not specified. + CmdArgs.push_back("-x"); + CmdArgs.push_back("/dev/null"); + } + + // Add archive library search paths. + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); + + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + // Specify linker input file(s) + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + // z/OS tool chain depends on LE data sets and the CSSLIB data set. + // These data sets can have different high level qualifiers (HLQs) + // as each installation can define them differently. + + std::string LEHLQ = getLEHLQ(Args); + std::string CsslibHLQ = getCSSHLQ(Args); + + StringRef ld_env_var = StringRef(getenv("_LD_SYSLIB")).trim(); + if (ld_env_var.empty()) { + CmdArgs.push_back("-S"); + CmdArgs.push_back(Args.MakeArgString("//'" + LEHLQ + ".SCEEBND2'")); + CmdArgs.push_back("-S"); + CmdArgs.push_back(Args.MakeArgString("//'" + CsslibHLQ + ".CSSLIB'")); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + ld_env_var = StringRef(getenv("_LD_SIDE_DECKS")).trim(); + if (ld_env_var.empty()) { + CmdArgs.push_back( + Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS001)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS003)'")); + } else { + SmallVector<StringRef> ld_side_deck; + ld_env_var.split(ld_side_deck, ":"); + for (StringRef ld_loc : ld_side_deck) { + CmdArgs.push_back((ld_loc.str()).c_str()); + } + } + } + // Link libc++ library + if (ToolChain.ShouldLinkCXXStdlib(Args)) { + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + } + + // Specify compiler-rt library path for linker + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); +} + +ToolChain::RuntimeLibType ZOS::GetDefaultRuntimeLibType() const { + return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType ZOS::GetDefaultCXXStdlibType() const { + return ToolChain::CST_Libcxx; +} + +void ZOS::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libstdcxx: + llvm::report_fatal_error("linking libstdc++ is unimplemented on z/OS"); + break; + case ToolChain::CST_Libcxx: { + std::string ClangHLQ = getClangHLQ(Args); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXE)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXS)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXP)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXA)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQXLA)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQUNW)'")); + } break; + } +} + +auto ZOS::buildAssembler() const -> Tool * { return new zos::Assembler(*this); } + +auto ZOS::buildLinker() const -> Tool * { return new zos::Linker(*this); } + +void ZOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + const Driver &D = getDriver(); + + // resolve ResourceDir + std::string ResourceDir(D.ResourceDir); + + // zos_wrappers must take highest precedence + + // - <clang>/lib/clang/<ver>/include/zos_wrappers + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(ResourceDir); + path::append(P, "include", "zos_wrappers"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + + // - <clang>/lib/clang/<ver>/include + SmallString<128> P2(ResourceDir); + path::append(P2, "include"); + addSystemInclude(DriverArgs, CC1Args, P2.str()); + } + + // - /usr/include + if (Arg *SysIncludeArg = + DriverArgs.getLastArg(options::OPT_mzos_sys_include_EQ)) { + StringRef SysInclude = SysIncludeArg->getValue(); + + // fall back to the default include path + if (!SysInclude.empty()) { + + // -mzos-sys-include opton can have colon separated + // list of paths, so we need to parse the value. + StringRef PathLE(SysInclude); + size_t Colon = PathLE.find(':'); + if (Colon == StringRef::npos) { + addSystemInclude(DriverArgs, CC1Args, PathLE.str()); + return; + } + + while (Colon != StringRef::npos) { + SmallString<128> P = PathLE.substr(0, Colon); + addSystemInclude(DriverArgs, CC1Args, P.str()); + PathLE = PathLE.substr(Colon + 1); + Colon = PathLE.find(':'); + } + if (PathLE.size()) + addSystemInclude(DriverArgs, CC1Args, PathLE.str()); + + return; + } + } + + addSystemInclude(DriverArgs, CC1Args, "/usr/include"); +} + +void ZOS::TryAddIncludeFromPath(llvm::SmallString<128> Path, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + if (!getVFS().exists(Path)) { + if (DriverArgs.hasArg(options::OPT_v)) + WithColor::warning(errs(), "Clang") + << "ignoring nonexistent directory \"" << Path << "\"\n"; + if (!DriverArgs.hasArg(options::OPT__HASH_HASH_HASH)) + return; + } + addSystemInclude(DriverArgs, CC1Args, Path); +} + +void ZOS::AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdincxx) || + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + // <install>/bin/../include/c++/v1 + llvm::SmallString<128> InstallBin = + llvm::StringRef(getDriver().getInstalledDir()); + llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1"); + TryAddIncludeFromPath(InstallBin, DriverArgs, CC1Args); + break; + } + case ToolChain::CST_Libstdcxx: + llvm::report_fatal_error( + "picking up libstdc++ headers is unimplemented on z/OS"); + break; + } +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h index 50bff0993561..45204ba0a543 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h @@ -14,6 +14,39 @@ namespace clang { namespace driver { +namespace tools { + +/// Directly call system default assembler and linker. +namespace zos { + +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("zos::Assembler", "assembler", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("zos::Linker", "linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace zos +} // end namespace tools + namespace toolchains { class LLVM_LIBRARY_VISIBILITY ZOS : public ToolChain { @@ -28,11 +61,34 @@ public: } bool isPICDefaultForced() const override { return false; } - bool IsIntegratedAssemblerDefault() const override { return true; } + void TryAddIncludeFromPath(llvm::SmallString<128> Path, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + unsigned GetDefaultDwarfVersion() const override { return 4; } + CXXStdlibType GetDefaultCXXStdlibType() const override; + + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override; void addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const override; + + const char *getDefaultLinker() const override { return "/bin/ld"; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/Types.cpp b/contrib/llvm-project/clang/lib/Driver/Types.cpp index 8f6adc6c2ad1..a7b6b9000e1d 100644 --- a/contrib/llvm-project/clang/lib/Driver/Types.cpp +++ b/contrib/llvm-project/clang/lib/Driver/Types.cpp @@ -42,7 +42,7 @@ static constexpr TypeInfo TypeInfos[] = { #include "clang/Driver/Types.def" #undef TYPE }; -static const unsigned numTypes = llvm::array_lengthof(TypeInfos); +static const unsigned numTypes = std::size(TypeInfos); static const TypeInfo &getInfo(unsigned id) { assert(id > 0 && id - 1 < numTypes && "Invalid Type ID."); @@ -65,16 +65,23 @@ static bool isPreprocessedModuleType(ID Id) { return Id == TY_CXXModule || Id == TY_PP_CXXModule; } +static bool isPreprocessedHeaderUnitType(ID Id) { + return Id == TY_CXXSHeader || Id == TY_CXXUHeader || Id == TY_CXXHUHeader || + Id == TY_PP_CXXHeaderUnit; +} + types::ID types::getPrecompiledType(ID Id) { if (isPreprocessedModuleType(Id)) return TY_ModuleFile; + if (isPreprocessedHeaderUnitType(Id)) + return TY_HeaderUnit; if (onlyPrecompileType(Id)) return TY_PCH; return TY_INVALID; } -const char *types::getTypeTempSuffix(ID Id, bool CLMode) { - if (CLMode) { +const char *types::getTypeTempSuffix(ID Id, bool CLStyle) { + if (CLStyle) { switch (Id) { case TY_Object: case TY_LTO_BC: @@ -126,7 +133,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_Asm: case TY_C: case TY_PP_C: - case TY_CL: case TY_CLCXX: + case TY_CL: case TY_PP_CL: case TY_CLCXX: case TY_PP_CLCXX: case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: case TY_HIP: @@ -139,6 +146,10 @@ bool types::isAcceptedByClang(ID Id) { case TY_CLHeader: case TY_ObjCHeader: case TY_PP_ObjCHeader: case TY_CXXHeader: case TY_PP_CXXHeader: + case TY_CXXSHeader: + case TY_CXXUHeader: + case TY_CXXHUHeader: + case TY_PP_CXXHeaderUnit: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: case TY_CXXModule: case TY_PP_CXXModule: case TY_AST: case TY_ModuleFile: case TY_PCH: @@ -148,6 +159,20 @@ bool types::isAcceptedByClang(ID Id) { } } +bool types::isAcceptedByFlang(ID Id) { + switch (Id) { + default: + return false; + + case TY_Fortran: + case TY_PP_Fortran: + return true; + case TY_LLVM_IR: + case TY_LLVM_BC: + return true; + } +} + bool types::isDerivedFromC(ID Id) { switch (Id) { default: @@ -156,7 +181,9 @@ bool types::isDerivedFromC(ID Id) { case TY_PP_C: case TY_C: case TY_CL: + case TY_PP_CL: case TY_CLCXX: + case TY_PP_CLCXX: case TY_PP_CUDA: case TY_CUDA: case TY_CUDA_DEVICE: @@ -210,8 +237,13 @@ bool types::isCXX(ID Id) { case TY_CXX: case TY_PP_CXX: case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: case TY_CXXHeader: case TY_PP_CXXHeader: + case TY_CXXSHeader: + case TY_CXXUHeader: + case TY_CXXHUHeader: + case TY_PP_CXXHeaderUnit: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: case TY_CXXModule: case TY_PP_CXXModule: + case TY_PP_CLCXX: case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: case TY_HIP: case TY_PP_HIP: @@ -257,15 +289,7 @@ bool types::isHIP(ID Id) { } } -bool types::isFortran(ID Id) { - switch (Id) { - default: - return false; - - case TY_Fortran: case TY_PP_Fortran: - return true; - } -} +bool types::isHLSL(ID Id) { return Id == TY_HLSL; } bool types::isSrcFile(ID Id) { return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID; @@ -273,66 +297,75 @@ bool types::isSrcFile(ID Id) { types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { return llvm::StringSwitch<types::ID>(Ext) - .Case("c", TY_C) - .Case("C", TY_CXX) - .Case("F", TY_Fortran) - .Case("f", TY_PP_Fortran) - .Case("h", TY_CHeader) - .Case("H", TY_CXXHeader) - .Case("i", TY_PP_C) - .Case("m", TY_ObjC) - .Case("M", TY_ObjCXX) - .Case("o", TY_Object) - .Case("S", TY_Asm) - .Case("s", TY_PP_Asm) - .Case("bc", TY_LLVM_BC) - .Case("cc", TY_CXX) - .Case("CC", TY_CXX) - .Case("cl", TY_CL) - .Case("clcpp", TY_CLCXX) - .Case("cp", TY_CXX) - .Case("cu", TY_CUDA) - .Case("hh", TY_CXXHeader) - .Case("ii", TY_PP_CXX) - .Case("ll", TY_LLVM_IR) - .Case("mi", TY_PP_ObjC) - .Case("mm", TY_ObjCXX) - .Case("rs", TY_RenderScript) - .Case("adb", TY_Ada) - .Case("ads", TY_Ada) - .Case("asm", TY_PP_Asm) - .Case("ast", TY_AST) - .Case("ccm", TY_CXXModule) - .Case("cpp", TY_CXX) - .Case("CPP", TY_CXX) - .Case("c++", TY_CXX) - .Case("C++", TY_CXX) - .Case("cui", TY_PP_CUDA) - .Case("cxx", TY_CXX) - .Case("CXX", TY_CXX) - .Case("F90", TY_Fortran) - .Case("f90", TY_PP_Fortran) - .Case("F95", TY_Fortran) - .Case("f95", TY_PP_Fortran) - .Case("for", TY_PP_Fortran) - .Case("FOR", TY_PP_Fortran) - .Case("fpp", TY_Fortran) - .Case("FPP", TY_Fortran) - .Case("gch", TY_PCH) - .Case("hip", TY_HIP) - .Case("hpp", TY_CXXHeader) - .Case("hxx", TY_CXXHeader) - .Case("iim", TY_PP_CXXModule) - .Case("lib", TY_Object) - .Case("mii", TY_PP_ObjCXX) - .Case("obj", TY_Object) - .Case("ifs", TY_IFS) - .Case("pch", TY_PCH) - .Case("pcm", TY_ModuleFile) - .Case("c++m", TY_CXXModule) - .Case("cppm", TY_CXXModule) - .Case("cxxm", TY_CXXModule) - .Default(TY_INVALID); + .Case("c", TY_C) + .Case("C", TY_CXX) + .Case("F", TY_Fortran) + .Case("f", TY_PP_Fortran) + .Case("h", TY_CHeader) + .Case("H", TY_CXXHeader) + .Case("i", TY_PP_C) + .Case("m", TY_ObjC) + .Case("M", TY_ObjCXX) + .Case("o", TY_Object) + .Case("S", TY_Asm) + .Case("s", TY_PP_Asm) + .Case("bc", TY_LLVM_BC) + .Case("cc", TY_CXX) + .Case("CC", TY_CXX) + .Case("cl", TY_CL) + .Case("cli", TY_PP_CL) + .Case("clcpp", TY_CLCXX) + .Case("clii", TY_PP_CLCXX) + .Case("cp", TY_CXX) + .Case("cu", TY_CUDA) + .Case("hh", TY_CXXHeader) + .Case("ii", TY_PP_CXX) + .Case("ll", TY_LLVM_IR) + .Case("mi", TY_PP_ObjC) + .Case("mm", TY_ObjCXX) + .Case("rs", TY_RenderScript) + .Case("adb", TY_Ada) + .Case("ads", TY_Ada) + .Case("asm", TY_PP_Asm) + .Case("ast", TY_AST) + .Case("ccm", TY_CXXModule) + .Case("cpp", TY_CXX) + .Case("CPP", TY_CXX) + .Case("c++", TY_CXX) + .Case("C++", TY_CXX) + .Case("cui", TY_PP_CUDA) + .Case("cxx", TY_CXX) + .Case("CXX", TY_CXX) + .Case("F03", TY_Fortran) + .Case("f03", TY_PP_Fortran) + .Case("F08", TY_Fortran) + .Case("f08", TY_PP_Fortran) + .Case("F90", TY_Fortran) + .Case("f90", TY_PP_Fortran) + .Case("F95", TY_Fortran) + .Case("f95", TY_PP_Fortran) + .Case("for", TY_PP_Fortran) + .Case("FOR", TY_PP_Fortran) + .Case("fpp", TY_Fortran) + .Case("FPP", TY_Fortran) + .Case("gch", TY_PCH) + .Case("hip", TY_HIP) + .Case("hipi", TY_PP_HIP) + .Case("hpp", TY_CXXHeader) + .Case("hxx", TY_CXXHeader) + .Case("iim", TY_PP_CXXModule) + .Case("iih", TY_PP_CXXHeaderUnit) + .Case("lib", TY_Object) + .Case("mii", TY_PP_ObjCXX) + .Case("obj", TY_Object) + .Case("ifs", TY_IFS) + .Case("pch", TY_PCH) + .Case("pcm", TY_ModuleFile) + .Case("c++m", TY_CXXModule) + .Case("cppm", TY_CXXModule) + .Case("cxxm", TY_CXXModule) + .Case("hlsl", TY_HLSL) + .Default(TY_INVALID); } types::ID types::lookupTypeForTypeSpecifier(const char *Name) { diff --git a/contrib/llvm-project/clang/lib/Driver/XRayArgs.cpp b/contrib/llvm-project/clang/lib/Driver/XRayArgs.cpp index 63b575178bd1..8c5134e25013 100644 --- a/contrib/llvm-project/clang/lib/Driver/XRayArgs.cpp +++ b/contrib/llvm-project/clang/lib/Driver/XRayArgs.cpp @@ -22,12 +22,7 @@ using namespace clang; using namespace clang::driver; using namespace llvm::opt; -namespace { -constexpr char XRayInstrumentOption[] = "-fxray-instrument"; -constexpr char XRayInstructionThresholdOption[] = - "-fxray-instruction-threshold="; -constexpr const char *const XRaySupportedModes[] = {"xray-fdr", "xray-basic"}; -} // namespace +constexpr const char *XRaySupportedModes[] = {"xray-fdr", "xray-basic"}; XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { const Driver &D = TC.getDriver(); @@ -35,80 +30,49 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { if (!Args.hasFlag(options::OPT_fxray_instrument, options::OPT_fno_xray_instrument, false)) return; - if (Triple.getOS() == llvm::Triple::Linux) { + XRayInstrument = Args.getLastArg(options::OPT_fxray_instrument); + if (Triple.isMacOSX()) { + switch (Triple.getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::x86_64: + break; + default: + D.Diag(diag::err_drv_unsupported_opt_for_target) + << XRayInstrument->getSpelling() << Triple.str(); + break; + } + } else if (Triple.isOSBinFormatELF()) { switch (Triple.getArch()) { case llvm::Triple::x86_64: case llvm::Triple::arm: case llvm::Triple::aarch64: case llvm::Triple::hexagon: case llvm::Triple::ppc64le: + case llvm::Triple::loongarch64: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: break; default: - D.Diag(diag::err_drv_clang_unsupported) - << (std::string(XRayInstrumentOption) + " on " + Triple.str()); - } - } else if (Triple.isOSFreeBSD() || Triple.isOSOpenBSD() || - Triple.isOSNetBSD() || Triple.isMacOSX()) { - if (Triple.getArch() != llvm::Triple::x86_64) { - D.Diag(diag::err_drv_clang_unsupported) - << (std::string(XRayInstrumentOption) + " on " + Triple.str()); - } - } else if (Triple.getOS() == llvm::Triple::Fuchsia) { - switch (Triple.getArch()) { - case llvm::Triple::x86_64: - case llvm::Triple::aarch64: - break; - default: - D.Diag(diag::err_drv_clang_unsupported) - << (std::string(XRayInstrumentOption) + " on " + Triple.str()); + D.Diag(diag::err_drv_unsupported_opt_for_target) + << XRayInstrument->getSpelling() << Triple.str(); } } else { - D.Diag(diag::err_drv_clang_unsupported) - << (std::string(XRayInstrumentOption) + " on " + Triple.str()); + D.Diag(diag::err_drv_unsupported_opt_for_target) + << XRayInstrument->getSpelling() << Triple.str(); } // Both XRay and -fpatchable-function-entry use // TargetOpcode::PATCHABLE_FUNCTION_ENTER. if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) D.Diag(diag::err_drv_argument_not_allowed_with) - << "-fxray-instrument" << A->getSpelling(); - - XRayInstrument = true; - if (const Arg *A = - Args.getLastArg(options::OPT_fxray_instruction_threshold_, - options::OPT_fxray_instruction_threshold_EQ)) { - StringRef S = A->getValue(); - if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0) - D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; - } - - // By default, the back-end will not emit the lowering for XRay customevent - // calls if the function is not instrumented. In the future we will change - // this default to be the reverse, but in the meantime we're going to - // introduce the new functionality behind a flag. - if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, - options::OPT_fno_xray_always_emit_customevents, false)) - XRayAlwaysEmitCustomEvents = true; - - if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents, - options::OPT_fno_xray_always_emit_typedevents, false)) - XRayAlwaysEmitTypedEvents = true; + << XRayInstrument->getSpelling() << A->getSpelling(); if (!Args.hasFlag(options::OPT_fxray_link_deps, - options::OPT_fnoxray_link_deps, true)) + options::OPT_fno_xray_link_deps, true)) XRayRT = false; - if (Args.hasFlag(options::OPT_fxray_ignore_loops, - options::OPT_fno_xray_ignore_loops, false)) - XRayIgnoreLoops = true; - - XRayFunctionIndex = Args.hasFlag(options::OPT_fxray_function_index, - options::OPT_fno_xray_function_index, true); - auto Bundles = Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); if (Bundles.empty()) @@ -187,21 +151,6 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { Modes.push_back(std::string(M)); } - if (const Arg *A = Args.getLastArg(options::OPT_fxray_function_groups)) { - StringRef S = A->getValue(); - if (S.getAsInteger(0, XRayFunctionGroups) || XRayFunctionGroups < 1) - D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; - } - - if (const Arg *A = - Args.getLastArg(options::OPT_fxray_selected_function_group)) { - StringRef S = A->getValue(); - if (S.getAsInteger(0, XRaySelectedFunctionGroup) || - XRaySelectedFunctionGroup < 0 || - XRaySelectedFunctionGroup >= XRayFunctionGroups) - D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; - } - // Then we want to sort and unique the modes we've collected. llvm::sort(Modes); Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end()); @@ -211,34 +160,52 @@ void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, types::ID InputType) const { if (!XRayInstrument) return; + const Driver &D = TC.getDriver(); + XRayInstrument->render(Args, CmdArgs); - CmdArgs.push_back(XRayInstrumentOption); - - if (XRayAlwaysEmitCustomEvents) - CmdArgs.push_back("-fxray-always-emit-customevents"); - - if (XRayAlwaysEmitTypedEvents) - CmdArgs.push_back("-fxray-always-emit-typedevents"); - - if (XRayIgnoreLoops) - CmdArgs.push_back("-fxray-ignore-loops"); + // By default, the back-end will not emit the lowering for XRay customevent + // calls if the function is not instrumented. In the future we will change + // this default to be the reverse, but in the meantime we're going to + // introduce the new functionality behind a flag. + Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_customevents, + options::OPT_fno_xray_always_emit_customevents); - if (!XRayFunctionIndex) - CmdArgs.push_back("-fno-xray-function-index"); + Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_typedevents, + options::OPT_fno_xray_always_emit_typedevents); + Args.addOptInFlag(CmdArgs, options::OPT_fxray_ignore_loops, + options::OPT_fno_xray_ignore_loops); + Args.addOptOutFlag(CmdArgs, options::OPT_fxray_function_index, + options::OPT_fno_xray_function_index); - if (XRayFunctionGroups > 1) { - CmdArgs.push_back(Args.MakeArgString(Twine("-fxray-function-groups=") + - Twine(XRayFunctionGroups))); + if (const Arg *A = + Args.getLastArg(options::OPT_fxray_instruction_threshold_EQ)) { + int Value; + StringRef S = A->getValue(); + if (S.getAsInteger(0, Value) || Value < 0) + D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; + else + A->render(Args, CmdArgs); } - if (XRaySelectedFunctionGroup != 0) { - CmdArgs.push_back( - Args.MakeArgString(Twine("-fxray-selected-function-group=") + - Twine(XRaySelectedFunctionGroup))); + int XRayFunctionGroups = 1; + int XRaySelectedFunctionGroup = 0; + if (const Arg *A = Args.getLastArg(options::OPT_fxray_function_groups)) { + StringRef S = A->getValue(); + if (S.getAsInteger(0, XRayFunctionGroups) || XRayFunctionGroups < 1) + D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; + if (XRayFunctionGroups > 1) + A->render(Args, CmdArgs); + } + if (const Arg *A = + Args.getLastArg(options::OPT_fxray_selected_function_group)) { + StringRef S = A->getValue(); + if (S.getAsInteger(0, XRaySelectedFunctionGroup) || + XRaySelectedFunctionGroup < 0 || + XRaySelectedFunctionGroup >= XRayFunctionGroups) + D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; + if (XRaySelectedFunctionGroup != 0) + A->render(Args, CmdArgs); } - - CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + - Twine(InstructionThreshold))); for (const auto &Always : AlwaysInstrumentFiles) { SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); |