diff options
Diffstat (limited to 'clang/lib/Driver')
71 files changed, 3987 insertions, 2625 deletions
diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp index eb08bfe9cde5..ead3a23da418 100644 --- a/clang/lib/Driver/Action.cpp +++ b/clang/lib/Driver/Action.cpp @@ -26,6 +26,8 @@ const char *Action::getClassName(ActionClass AC) { 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"; @@ -43,6 +45,8 @@ const char *Action::getClassName(ActionClass AC) { return "clang-offload-unbundler"; case OffloadWrapperJobClass: return "clang-offload-wrapper"; + case OffloadPackagerJobClass: + return "clang-offload-packager"; case LinkerWrapperJobClass: return "clang-linker-wrapper"; case StaticLibJobClass: @@ -52,7 +56,8 @@ const char *Action::getClassName(ActionClass AC) { 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 +70,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 +95,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,6 +197,7 @@ 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(); })) @@ -201,7 +209,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, @@ -220,7 +228,8 @@ OffloadAction::OffloadAction(const HostDependence &HDep, if (auto *A = DDeps.getActions()[i]) { getInputs().push_back(A); A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i], - DDeps.getBoundArchs()[i]); + DDeps.getBoundArchs()[i], + DDeps.getToolChains()[i]); } } @@ -339,6 +348,11 @@ HeaderModulePrecompileJobAction::HeaderModulePrecompileJobAction( : PrecompileJobAction(HeaderModulePrecompileJobClass, Input, OutputType), ModuleName(ModuleName) {} +void ExtractAPIJobAction::anchor() {} + +ExtractAPIJobAction::ExtractAPIJobAction(Action *Inputs, types::ID OutputType) + : JobAction(ExtractAPIJobClass, Inputs, OutputType) {} + void AnalyzeJobAction::anchor() {} AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType) @@ -420,6 +434,12 @@ OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs, types::ID Type) : JobAction(OffloadWrapperJobClass, Inputs, Type) {} +void OffloadPackagerJobAction::anchor() {} + +OffloadPackagerJobAction::OffloadPackagerJobAction(ActionList &Inputs, + types::ID Type) + : JobAction(OffloadPackagerJobClass, Inputs, Type) {} + void LinkerWrapperJobAction::anchor() {} LinkerWrapperJobAction::LinkerWrapperJobAction(ActionList &Inputs, diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index 67d941c6c2ab..b4367a0af81e 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -162,7 +162,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 +192,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 +241,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 +251,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()) diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp index 5ac38c34d112..1898667279cc 100644 --- a/clang/lib/Driver/Distro.cpp +++ b/clang/lib/Driver/Distro.cpp @@ -91,6 +91,7 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) { .Case("hirsute", Distro::UbuntuHirsute) .Case("impish", Distro::UbuntuImpish) .Case("jammy", Distro::UbuntuJammy) + .Case("kinetic", Distro::UbuntuKinetic) .Default(Distro::UnknownDistro); return Version; } @@ -153,6 +154,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; } diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 3bfddeefc7b2..0da32dae2ef6 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -13,6 +13,7 @@ #include "ToolChains/AVR.h" #include "ToolChains/Ananas.h" #include "ToolChains/BareMetal.h" +#include "ToolChains/CSKYToolChain.h" #include "ToolChains/Clang.h" #include "ToolChains/CloudABI.h" #include "ToolChains/Contiki.h" @@ -25,6 +26,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" @@ -59,6 +61,7 @@ #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" @@ -188,12 +191,14 @@ 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), + CheckInputsExist(true), ProbePrecompiled(true), SuppressMissingInputWarning(false) { // Provide a sane fallback if no VFS is specified. if (!this->VFS) @@ -230,6 +235,7 @@ void Driver::setDriverMode(StringRef Value) { .Case("cpp", CPPMode) .Case("cl", CLMode) .Case("flang", FlangMode) + .Case("dxc", DXCMode) .Default(None)) Mode = *M; else @@ -333,11 +339,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 +356,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. @@ -773,76 +782,117 @@ 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; + llvm::SmallVector<StringRef, 4> 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; + } + llvm::copy(OpenMPTargets->getValues(), std::back_inserter(OpenMPTriples)); + } 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. + llvm::DenseSet<StringRef> Archs = + getOffloadArchs(C, C.getArgs(), Action::OFK_OpenMP, nullptr); + 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; + } } - if (HasValidOpenMPRuntime) { - llvm::StringMap<const char *> FoundNormalizedTriples; - for (const char *Val : OpenMPTargets->getValues()) { - llvm::Triple TT(ToolChain::getOpenMPTriple(Val)); - std::string NormalizedName = TT.normalize(); + for (const auto &TripleAndArchs : DerivedArchs) + OpenMPTriples.push_back(TripleAndArchs.first()); + } - // 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 Val : OpenMPTriples) { + llvm::Triple TT(ToolChain::getOpenMPTriple(Val)); + std::string NormalizedName = TT.normalize(); - // Store the current triple so that we can check for duplicates in the - // following iterations. - FoundNormalizedTriples[NormalizedName] = Val; + // 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; + } - // 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."); - } + // Store the current triple so that we can check for duplicates in the + // following iterations. + FoundNormalizedTriples[NormalizedName] = Val; - TC = DeviceTC.get(); - } else - TC = &getToolChain(C.getInputArgs(), TT); - C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP); + // 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."); } - } - } 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.find(TT.getTriple()) != DerivedArchs.end()) + 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; } // @@ -924,7 +974,7 @@ bool Driver::loadConfigFile() { if (llvm::sys::fs::make_absolute(CfgDir).value() != 0) SystemConfigDir.clear(); else - SystemConfigDir = std::string(CfgDir.begin(), CfgDir.end()); + SystemConfigDir = static_cast<std::string>(CfgDir); } } if (CLOptions->hasArg(options::OPT_config_user_dir_EQ)) { @@ -935,7 +985,7 @@ bool Driver::loadConfigFile() { if (llvm::sys::fs::make_absolute(CfgDir).value() != 0) UserConfigDir.clear(); else - UserConfigDir = std::string(CfgDir.begin(), CfgDir.end()); + UserConfigDir = static_cast<std::string>(CfgDir); } } } @@ -1167,9 +1217,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)) { @@ -1189,7 +1236,22 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { T.setEnvironment(llvm::Triple::MSVC); T.setObjectFormat(llvm::Triple::COFF); 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(); + } 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)) @@ -1223,6 +1285,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 +1314,41 @@ 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++2b") || + Std->containsValue("c++2a") || 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)); @@ -1597,6 +1705,19 @@ 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); @@ -1918,6 +2039,13 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { 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)) { @@ -2209,6 +2337,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; @@ -2272,6 +2408,21 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef 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 { @@ -2308,6 +2459,14 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, assert(!Args.hasArg(options::OPT_x) && "-x and /TC or /TP is not allowed"); } + // Warn -x after last input file has no effect + { + 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(); + } + for (Arg *A : Args) { if (A->getOption().getKind() == Option::InputClass) { const char *Value = A->getValue(); @@ -2360,7 +2519,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 +2544,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)) { @@ -2434,6 +2603,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 +2639,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: @@ -2692,6 +2869,7 @@ class OffloadingActionBuilder final { UA->registerDependentActionInfo(ToolChains[0], Arch, AssociatedOffloadKind); } + IsActive = true; return ABRT_Success; } @@ -2771,15 +2949,8 @@ 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(); + CompileDeviceOnly = C.getDriver().offloadDeviceOnly(); EmitLLVM = Args.getLastArg(options::OPT_emit_llvm); EmitAsm = Args.getLastArg(options::OPT_S); FixedCUID = Args.getLastArgValue(options::OPT_cuid_EQ); @@ -2806,7 +2977,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 +2986,28 @@ 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 { + 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; } @@ -3007,7 +3178,7 @@ class OffloadingActionBuilder final { 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); } bool canUseBundlerUnbundler() const override { return true; } @@ -3024,7 +3195,7 @@ class OffloadingActionBuilder final { C.setContainsError(); return StringRef(); } - auto CanId = getCanonicalTargetID(ArchStr.getValue(), Features); + auto CanId = getCanonicalTargetID(*ArchStr, Features); return Args.MakeArgStringRef(CanId); }; @@ -3038,9 +3209,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,7 +3223,7 @@ 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."); if (!Relocatable && CurPhase == phases::Backend && !EmitLLVM && !EmitAsm) { @@ -3108,8 +3282,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); @@ -3152,8 +3325,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.getValue()) { for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { OffloadAction::DeviceDependences DDep; DDep.add(*CudaDeviceActions[I], *ToolChains.front(), GpuArchList[I], @@ -3178,12 +3351,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 +3372,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); @@ -3445,6 +3627,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 +3653,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 @@ -3513,6 +3707,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 +3725,7 @@ public: C.getSingleOffloadToolChain<Action::OFK_Host>(), /*BoundArch=*/StringRef(), Action::OFK_Host); HostAction = UnbundlingHostAction; + recordHostAction(HostAction, InputArg); } assert(HostAction && "Invalid host action!"); @@ -3565,6 +3762,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 +3786,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 +3820,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 +3851,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,7 +3904,8 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args, phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg); if (FinalPhase == phases::Link) { - if (Args.hasArg(options::OPT_emit_llvm)) + // 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) @@ -3830,13 +4049,16 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // Builder to be used to build offloading actions. OffloadingActionBuilder OffloadBuilder(C, Args, Inputs); - // Offload kinds active for this compilation. - unsigned OffloadKinds = Action::OFK_None; - if (C.hasOffloadToolChain<Action::OFK_OpenMP>()) - OffloadKinds |= Action::OFK_OpenMP; + bool UseNewOffloadingDriver = + (C.isOffloadingHostKind(Action::OFK_OpenMP) && + Args.hasFlag(options::OPT_fopenmp_new_driver, + options::OPT_no_offload_new_driver, true)) || + Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false); // Construct the actions to perform. HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr; + ExtractAPIJobAction *ExtractAPIAction = nullptr; ActionList LinkerInputs; ActionList MergerInputs; @@ -3855,14 +4077,14 @@ 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 (!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)) + if (!UseNewOffloadingDriver) Current = OffloadBuilder.addDeviceDependencesToHostAction( Current, InputArg, Phase, PL.back(), FullPL); if (!Current) @@ -3871,7 +4093,10 @@ 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 + if (!(C.getInputArgs().hasArg(options::OPT_hip_link) && + (C.getInputArgs().hasArg(options::OPT_emit_llvm)))) + LinkerInputs.push_back(Current); Current = nullptr; break; } @@ -3897,10 +4122,11 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, 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); + if (Phase == phases::Precompile && ExtractAPIAction) { + ExtractAPIAction->addHeaderInput(Current); + Current = nullptr; + break; + } // FIXME: Should we include any prior module file outputs as inputs of // later actions in the same command line? @@ -3914,15 +4140,22 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, if (auto *HMA = dyn_cast<HeaderModulePrecompileJobAction>(NewCurrent)) HeaderModuleAction = HMA; + else if (auto *EAA = dyn_cast<ExtractAPIJobAction>(NewCurrent)) + ExtractAPIAction = EAA; Current = NewCurrent; // Use the current host action in any of the offloading actions, if // required. - if (!Args.hasArg(options::OPT_fopenmp_new_driver)) + if (!UseNewOffloadingDriver) if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg)) break; + // Try to build the offloading actions and add the result as a dependency + // to the host. + if (UseNewOffloadingDriver) + Current = BuildOffloadingActions(C, Args, I, Current); + if (Current->getType() == types::TY_Nothing) break; } @@ -3932,10 +4165,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)) + if (!UseNewOffloadingDriver) OffloadBuilder.appendTopLevelActions(Actions, Current, InputArg); else if (Current) - Current->propagateHostOffloadInfo(OffloadKinds, + Current->propagateHostOffloadInfo(C.getActiveOffloadKinds(), /*BoundArch=*/nullptr); } @@ -3944,26 +4177,27 @@ 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 (!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)) + if (!UseNewOffloadingDriver) LA = OffloadBuilder.processHostLinkAction(LA); Actions.push_back(LA); } @@ -4043,73 +4277,216 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // 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) { + // 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 (Triple.isNVPTX() && + (Arch == CudaArch::UNKNOWN || !IsNVIDIAGpuArch(Arch))) { + C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch) + << "CUDA" << ArchStr; + return StringRef(); + } else if (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)); + } - // 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); + // 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 llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> +getConflictOffloadArchCombination(const llvm::DenseSet<StringRef> &Archs, + Action::OffloadKind Kind) { + if (Kind != Action::OFK_HIP) + return None; + + 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) 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.find(TC) != KnownArchs.end()) + return KnownArchs.lookup(TC); + + llvm::DenseSet<StringRef> Archs; + for (auto &Arg : Args) { + if (Arg->getOption().matches(options::OPT_offload_arch_EQ)) { + for (StringRef Arch : llvm::split(Arg->getValue(), ",")) + Archs.insert(getCanonicalArchString(C, Args, Arch, TC->getTriple())); + } else if (Arg->getOption().matches(options::OPT_no_offload_arch_EQ)) { + for (StringRef Arch : llvm::split(Arg->getValue(), ",")) { + if (Arch == StringRef("all")) + Archs.clear(); + else + Archs.erase(getCanonicalArchString(C, Args, Arch, TC->getTriple())); + } + } + } + + if (auto ConflictingArchs = getConflictOffloadArchCombination(Archs, Kind)) { + C.getDriver().Diag(clang::diag::err_drv_bad_offload_arch_combo) + << ConflictingArchs->first << ConflictingArchs->second; + C.setContainsError(); + } + + 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); + } + + 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; - } + // 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, C.getArgsForToolChain(TC, "generic", Kind), Kind, TC)) + TCAndArchs.push_back(std::make_pair(TC, Arch)); - auto TC = ToolChains.begin(); - for (Action *&A : DeviceActions) { - A = ConstructPhaseAction(C, Args, Phase, A, Action::OFK_OpenMP); + for (unsigned I = 0, E = TCAndArchs.size(); I != E; ++I) + DeviceActions.push_back(C.MakeAction<InputAction>(*InputArg, InputType)); - 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); + 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; } - ++TC; - } - } - OffloadAction::DeviceDependences DDeps; + auto TCAndArch = TCAndArchs.begin(); + for (Action *&A : DeviceActions) { + A = ConstructPhaseAction(C, Args, Phase, A, Kind); - auto TC = ToolChains.begin(); - for (Action *A : DeviceActions) { - DDeps.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP); - TC++; + if (isa<CompileJobAction>(A) && isa<CompileJobAction>(HostAction) && + Kind == Action::OFK_OpenMP) { + // 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 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; + } } + if (offloadDeviceOnly()) + return C.MakeAction<OffloadAction>(DDeps, types::TY_Nothing); + + Action *OffloadPackager = + C.MakeAction<OffloadPackagerJobAction>(OffloadActions, types::TY_Image); + OffloadAction::DeviceDependences DDep; + DDep.add(*OffloadPackager, *C.getSingleOffloadToolChain<Action::OFK_Host>(), + nullptr, Action::OFK_None); OffloadAction::HostDependence HDep( *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), - /*BoundArch=*/nullptr, DDeps); - return C.MakeAction<OffloadAction>(HDep, DDeps); + /*BoundArch=*/nullptr, isa<CompileJobAction>(HostAction) ? DDep : DDeps); + return C.MakeAction<OffloadAction>( + HDep, isa<CompileJobAction>(HostAction) ? DDep : DDeps); } Action *Driver::ConstructPhaseAction( @@ -4138,10 +4515,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 +4531,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,8 +4549,7 @@ 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; } @@ -4194,7 +4578,7 @@ 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: { @@ -4204,7 +4588,7 @@ Action *Driver::ConstructPhaseAction( 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); @@ -4372,6 +4756,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); @@ -5020,8 +5406,9 @@ InputInfoList Driver::BuildJobsForActionNoCache( // action. std::string OffloadingPrefix = Action::GetOffloadingFileNamePrefix( A->getOffloadingDeviceKind(), TC->getTriple().normalize(), - /*CreatePrefixForHost=*/!!A->getOffloadingHostActiveKinds() && - !AtTopLevel); + /*CreatePrefixForHost=*/isa<OffloadPackagerJobAction>(A) || + !(A->getOffloadingHostActiveKinds() == Action::OFK_None || + AtTopLevel)); if (isa<OffloadWrapperJobAction>(JA)) { if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) BaseInput = FinalOutput->getValue(); @@ -5258,7 +5645,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,12 +5655,20 @@ 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()); assert(Suffix && "All types used for output should have a suffix."); @@ -5519,6 +5915,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::IOS: case llvm::Triple::TvOS: case llvm::Triple::WatchOS: + case llvm::Triple::DriverKit: TC = std::make_unique<toolchains::DarwinClang>(*this, Target, Args); break; case llvm::Triple::DragonFly: @@ -5606,6 +6003,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::PS4: TC = std::make_unique<toolchains::PS4CPU>(*this, Target, Args); break; + case llvm::Triple::PS5: + TC = std::make_unique<toolchains::PS5CPU>(*this, Target, Args); + break; case llvm::Triple::Contiki: TC = std::make_unique<toolchains::Contiki>(*this, Target, Args); break; @@ -5615,6 +6015,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, 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,6 +6064,9 @@ 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, @@ -5725,7 +6131,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 +6141,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; @@ -5829,7 +6237,13 @@ Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { } else { ExcludedFlagsBitmask |= options::CLOption; } - + if (IsDXCMode()) { + // Include DXC and Core options. + IncludedFlagsBitmask |= options::DXCOption; + IncludedFlagsBitmask |= options::CoreOption; + } else { + ExcludedFlagsBitmask |= options::DXCOption; + } return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask); } diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 403fac76f060..68fe90c7a69d 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -14,9 +14,9 @@ #include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/AArch64TargetParser.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/Transforms/Instrumentation/AddressSanitizerOptions.h" @@ -44,7 +44,8 @@ static const SanitizerMask NeedsUnwindTables = 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 | @@ -73,7 +74,8 @@ static const SanitizerMask CFIClasses = SanitizerKind::CFIUnrelatedCast; static const SanitizerMask CompatibleWithMinimalRuntime = TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack | - SanitizerKind::MemTag; + SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap | + SanitizerKind::MemtagGlobals; enum CoverageFeature { CoverageFunc = 1 << 0, @@ -168,14 +170,14 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds, 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 +187,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 +220,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 +235,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->getOption().getName() << toString(S); } TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) { @@ -293,13 +295,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 +369,19 @@ 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; + } + } + // 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 +417,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) @@ -638,20 +653,36 @@ 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); NeedPIE |= !(TC.getTriple().isOSLinux() && TC.getTriple().getArch() == llvm::Triple::x86_64); + } else if (AllAddedKinds & SanitizerKind::KernelMemory) { + MsanUseAfterDtor = false; + MsanParamRetval = Args.hasFlag( + options::OPT_fsanitize_memory_param_retval, + options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval); } 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, @@ -777,7 +808,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, 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. @@ -805,13 +836,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 = @@ -846,12 +877,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, 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. + // globals in ASan is disabled by default on most ELF targets. // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002 - AsanGlobalsDeadStripping = + AsanGlobalsDeadStripping = Args.hasFlag( + options::OPT_fsanitize_address_globals_dead_stripping, + options::OPT_fno_sanitize_address_globals_dead_stripping, !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() || - TC.getTriple().isPS4() || - Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping); + TC.getTriple().isPS()); AsanUseOdrIndicator = Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator, @@ -994,7 +1026,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; @@ -1015,8 +1048,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, // 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))) + !Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize, + true))) return; // Translate available CoverageFeatures to corresponding clang-cc1 flags. @@ -1230,7 +1263,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); } @@ -1319,8 +1353,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/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index d657d21bfcdb..5130eb9b72c1 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -67,8 +67,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, @@ -105,6 +106,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; } @@ -153,6 +182,7 @@ 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) { @@ -327,6 +357,12 @@ Tool *ToolChain::getOffloadWrapper() const { return OffloadWrapper.get(); } +Tool *ToolChain::getOffloadPackager() const { + if (!OffloadPackager) + OffloadPackager.reset(new tools::OffloadPackager(*this)); + return OffloadPackager.get(); +} + Tool *ToolChain::getLinkerWrapper() const { if (!LinkerWrapper) LinkerWrapper.reset(new tools::LinkerWrapper(*this, getLink())); @@ -359,6 +395,7 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::PrecompileJobClass: case Action::HeaderModulePrecompileJobClass: case Action::PreprocessJobClass: + case Action::ExtractAPIJobClass: case Action::AnalyzeJobClass: case Action::MigrateJobClass: case Action::VerifyPCHJobClass: @@ -371,6 +408,8 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::OffloadWrapperJobClass: return getOffloadWrapper(); + case Action::OffloadPackagerJobClass: + return getOffloadPackager(); case Action::LinkerWrapperJobClass: return getLinkerWrapper(); } @@ -903,6 +942,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; @@ -1032,7 +1079,7 @@ SanitizerMask ToolChain::getSupportedSanitizers() const { 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()) Res |= SanitizerKind::CFIICall; if (getTriple().getArch() == llvm::Triple::x86_64 || getTriple().isAArch64(64) || getTriple().isRISCV()) diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index e4bbf498b9cd..878b84a77702 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -98,9 +98,10 @@ 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, + // 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 +116,8 @@ 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"); // Specify linker output file. assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index 43ce33750eba..8718ab53ac1a 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -91,6 +91,7 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { else if (FileName.endswith(Suffix)) BaseName = FileName.drop_back(Suffix.size()); + const StringRef ABIVersionPrefix = "oclc_abi_version_"; if (BaseName == "ocml") { OCML = FilePath; } else if (BaseName == "ockl") { @@ -121,6 +122,12 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { WavefrontSize64.On = FilePath; } else if (BaseName == "oclc_wavefrontsize64_off") { WavefrontSize64.Off = FilePath; + } else if (BaseName.startswith(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 @@ -510,7 +517,7 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, 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"}); @@ -545,7 +552,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. @@ -723,7 +730,7 @@ AMDGPUToolChain::getParsedTargetID(const llvm::opt::ArgList &DriverArgs) const { if (!OptionalGpuArch) return {TargetID.str(), None, None}; - return {TargetID.str(), OptionalGpuArch.getValue().str(), FeatureMap}; + return {TargetID.str(), OptionalGpuArch->str(), FeatureMap}; } void AMDGPUToolChain::checkTargetID( @@ -731,7 +738,7 @@ 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; } } @@ -822,20 +829,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; + auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion( + getAMDGPUCodeObjectVersion(getDriver(), DriverArgs)); + if (!RocmInstallation.checkCommonBitcodeLibs(CanonArch, LibDeviceFile, + ABIVer)) return; - } bool Wave64 = isWave64(DriverArgs, Kind); @@ -858,20 +861,37 @@ void ROCMToolChain::addClangTargetOptions( // Add the generic set of libraries. 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()); }; @@ -884,6 +904,9 @@ RocmInstallationDetector::getCommonBitcodeLibs( AddBCLib(getCorrectlyRoundedSqrtPath(CorrectSqrt)); AddBCLib(getWavefrontSize64Path(Wave64)); AddBCLib(LibDeviceFile); + auto ABIVerPath = getABIVersionPath(ABIVer); + if (!ABIVerPath.empty()) + AddBCLib(ABIVerPath); return BCLibs; } @@ -897,15 +920,17 @@ bool AMDGPUToolChain::shouldSkipArgument(const llvm::opt::Arg *A) const { 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; + 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 +947,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( DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, - FastRelaxedMath, CorrectSqrt); + FastRelaxedMath, CorrectSqrt, ABIVer, isOpenMP); } diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h index 156bfd1fbdb2..ddcc124b25ba 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/clang/lib/Driver/ToolChains/AMDGPU.h @@ -142,7 +142,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/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp index d7cf41e4b660..efcd565b510b 100644 --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp @@ -125,9 +125,8 @@ const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( // 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) { + for (StringRef BCFile : BCLibs) CmdArgs.push_back(Args.MakeArgString(BCFile)); - }); } } @@ -289,15 +288,7 @@ void AMDGPUOpenMPToolChain::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-amdgpu-" + GPUArch; - else - BitcodeSuffix = "amdgcn-" + GPUArch; - - addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, - getTriple()); + addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, GPUArch, getTriple()); } llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( @@ -315,9 +306,10 @@ 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)) { + std::string Arch = BoundArch.str(); + if (BoundArch.empty()) + checkSystemForAMDGPU(Args, *this, Arch); DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch); } diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index 2cf16cf9fdb4..1e866553d826 100644 --- a/clang/lib/Driver/ToolChains/AVR.cpp +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -28,6 +28,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 +63,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 +90,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 +101,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 +121,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 +159,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 +170,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 +208,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 +249,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 +296,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) { @@ -308,49 +366,19 @@ 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); + std::string CPU = getCPUName(D, Args, Triple); + if (CPU.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"); } } @@ -362,11 +390,11 @@ void AVRToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Omit if there is no avr-libc installed. Optional<std::string> AVRLibcRoot = findAVRLibcInstallation(); - if (!AVRLibcRoot.hasValue()) + 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,21 +415,27 @@ void AVRToolChain::addClangTargetOptions( } Tool *AVRToolChain::buildLinker() const { - return new tools::AVR::Linker(getTriple(), *this, LinkStdlib); + return new tools::AVR::Linker(getTriple(), *this); } 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<std::string> AVRLibcRoot = TC.findAVRLibcInstallation(); llvm::Optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU); - std::string Linker = getToolChain().GetProgramPath(getShortName()); + // 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()); + ArgStringList CmdArgs; AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); @@ -415,7 +449,33 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); getToolChain().AddFilePathLibArgs(Args, CmdArgs); - if (SectionAddressData.hasValue()) { + // 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_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); + CmdArgs.push_back( + Args.MakeArgString(Twine("-L") + *AVRLibcRoot + "/lib/" + SubPath)); + CmdArgs.push_back( + Args.MakeArgString("-L" + TC.getGCCInstallPath() + "/" + SubPath)); + LinkStdlib = true; + } + } + if (!LinkStdlib) + D.Diag(diag::warn_drv_avr_stdlib_not_linked); + } + + if (SectionAddressData) { std::string DataSectionArg = std::string("-Tdata=0x") + llvm::utohexstr(SectionAddressData.getValue()); CmdArgs.push_back(Args.MakeArgString(DataSectionArg)); @@ -445,11 +505,15 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--end-group"); + // Add user specified linker script. + Args.AddAllArgs(CmdArgs, options::OPT_T); + // 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)); + if (Linker.find("avr-ld") != std::string::npos) + CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName)); } C.addCommand(std::make_unique<Command>( diff --git a/clang/lib/Driver/ToolChains/AVR.h b/clang/lib/Driver/ToolChains/AVR.h index 2d027957ed76..ab147d852ad7 100644 --- a/clang/lib/Driver/ToolChains/AVR.h +++ b/clang/lib/Driver/ToolChains/AVR.h @@ -31,17 +31,14 @@ public: llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + llvm::Optional<std::string> findAVRLibcInstallation() const; + StringRef getGCCInstallPath() const { return GCCInstallPath; } + 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 @@ -50,9 +47,8 @@ namespace tools { namespace AVR { class LLVM_LIBRARY_VISIBILITY Linker : 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 +59,6 @@ public: protected: const llvm::Triple &Triple; - bool LinkStdlib; }; } // end namespace AVR } // end namespace tools diff --git a/clang/lib/Driver/ToolChains/Ananas.cpp b/clang/lib/Driver/ToolChains/Ananas.cpp index be1476a7636c..40f9e56b38e9 100644 --- a/clang/lib/Driver/ToolChains/Ananas.cpp +++ b/clang/lib/Driver/ToolChains/Ananas.cpp @@ -85,7 +85,8 @@ void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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(ToolChain.GetFilePath("crt0.o"))); } @@ -111,12 +112,15 @@ void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - if (ToolChain.ShouldLinkCXXStdlib(Args)) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lc"); + } - 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) || Args.hasArg(options::OPT_pie)) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); else diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index ca0ca4bf4eea..cf7e201b4972 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -151,6 +151,8 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+"); llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first); + if (Split.first == "native") + ArchKind = llvm::AArch64::getCPUArchKind(llvm::sys::getHostCPUName().str()); if (ArchKind == llvm::AArch64::ArchKind::INVALID || !llvm::AArch64::getArchFeatures(ArchKind, Features)) return false; @@ -222,7 +224,6 @@ 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; @@ -264,13 +265,13 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, 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->getOption().getName() << A->getValue(); } if (Args.getLastArg(options::OPT_mgeneral_regs_only)) { @@ -323,8 +324,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->getOption().getName() << Scope; break; } } @@ -346,28 +347,85 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, Features.push_back("-crc"); } + int V8Version = -1; + int V9Version = -1; + bool HasNoSM4 = false; + bool HasNoSHA3 = false; + bool HasNoSHA2 = false; + bool HasNoAES = false; + bool HasSM4 = false; + bool HasSHA3 = false; + bool HasSHA2 = false; + bool HasAES = false; + bool HasCrypto = false; + bool HasNoCrypto = false; + int FullFP16Pos = -1; + int NoFullFP16Pos = -1; + int FP16FMLPos = -1; + int NoFP16FMLPos = -1; + int ArchFeatPos = -1; + + for (auto I = Features.begin(), E = Features.end(); I != E; I++) { + if (*I == "+v8a") V8Version = 0; + else if (*I == "+v8.1a") V8Version = 1; + else if (*I == "+v8.2a") V8Version = 2; + else if (*I == "+v8.3a") V8Version = 3; + else if (*I == "+v8.4a") V8Version = 4; + else if (*I == "+v8.5a") V8Version = 5; + else if (*I == "+v8.6a") V8Version = 6; + else if (*I == "+v8.7a") V8Version = 7; + else if (*I == "+v8.8a") V8Version = 8; + else if (*I == "+v8.9a") V8Version = 9; + else if (*I == "+v9a") V9Version = 0; + else if (*I == "+v9.1a") V9Version = 1; + else if (*I == "+v9.2a") V9Version = 2; + else if (*I == "+v9.3a") V9Version = 3; + else if (*I == "+v9.4a") V9Version = 4; + else if (*I == "+sm4") HasSM4 = true; + else if (*I == "+sha3") HasSHA3 = true; + else if (*I == "+sha2") HasSHA2 = true; + else if (*I == "+aes") HasAES = true; + else if (*I == "-sm4") HasNoSM4 = true; + else if (*I == "-sha3") HasNoSHA3 = true; + else if (*I == "-sha2") HasNoSHA2 = true; + else if (*I == "-aes") HasNoAES = true; + else if (*I == "+fp16fml") FP16FMLPos = I - Features.begin(); + else if (*I == "-fp16fml") NoFP16FMLPos = I - Features.begin(); + else if (*I == "-fullfp16") NoFullFP16Pos = I - Features.begin(); + else if (*I == "+fullfp16") FullFP16Pos = I - Features.begin(); + // Whichever option comes after (right-most option) will win + else if (*I == "+crypto") { + HasCrypto = true; + HasNoCrypto = false; + } else if (*I == "-crypto") { + HasCrypto = false; + HasNoCrypto = true; + } + // Register the iterator position if this is an architecture feature + if (ArchFeatPos == -1 && (V8Version != -1 || V9Version != -1)) + ArchFeatPos = I - Features.begin(); + } + // 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) { + if (V8Version >= 4) { + // "-fullfp16" "+fullfp16" && "+fp16fml" "+fullfp16" && no "+fullfp16" "-fp16fml" = "+fp16fml" + if (FullFP16Pos > NoFullFP16Pos && FullFP16Pos > FP16FMLPos && FullFP16Pos > NoFP16FMLPos) // 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"); - } + 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) + // "+fp16fml" "-fullfp16" = "-fp16fml" + if (NoFullFP16Pos > FP16FMLPos) Features.push_back("-fp16fml"); - else if (ItRNoFullFP16 > ItRFP16FML) + // "-fullfp16" "+fp16fml" = "+fullfp16" + else if (NoFullFP16Pos < FP16FMLPos) Features.push_back("+fullfp16"); } @@ -376,53 +434,23 @@ fp16_fml_fallthrough: // 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) { + if (V8Version >= 4 || V9Version >= 0) { + if (HasCrypto && !HasNoCrypto) { // 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) + if (!HasNoSM4) Features.push_back("+sm4"); - if (HasSHA3) + if (!HasNoSHA3) Features.push_back("+sha3"); - if (HasSHA2) + if (!HasNoSHA2) Features.push_back("+sha2"); - if (HasAES) + if (!HasNoAES) 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) @@ -433,49 +461,41 @@ fp16_fml_fallthrough: 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) + if (HasCrypto && !HasNoCrypto) { + if (!HasNoSHA2) Features.push_back("+sha2"); - if (HasAES) + if (!HasNoAES) 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) { + if (V8Version == 2 || V8Version == 3) { 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"}); + // FIXME: these insertions should ideally be automated using default + // extensions support from the backend target parser. + if (V8Version >= 6 || V9Version >= 1) + Features.insert(std::next(Features.begin() + ArchFeatPos), + {"+i8mm", "+bf16"}); + + // For Armv8.8-a/Armv9.3-a or later, FEAT_HBC and FEAT_MOPS are enabled by + // default. + if (V8Version >= 8 || V9Version >= 3) + Features.insert(std::next(Features.begin() + ArchFeatPos), + {"+hbc", "+mops"}); 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"); @@ -592,4 +612,7 @@ fp16_fml_fallthrough: // Enabled A53 errata (835769) workaround by default on android Features.push_back("+fix-cortex-a53-835769"); } + + if (Args.getLastArg(options::OPT_mno_bti_at_return_twice)) + Features.push_back("+no-bti-at-return-twice"); } diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.h b/clang/lib/Driver/ToolChains/Arch/AArch64.h index 0cdc2ec725e0..d47c402d4a42 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.h +++ b/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/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 16af9f6d7129..5c49db2f0837 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -121,7 +121,8 @@ static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, 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); + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << A->getValue(); } // Check -mcpu=. Needs ArchName to handle -mcpu=generic. @@ -137,7 +138,8 @@ static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, 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); + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << A->getValue(); } bool arm::useAAPCSForMachO(const llvm::Triple &T) { @@ -320,6 +322,7 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { case llvm::Triple::MacOSX: case llvm::Triple::IOS: case llvm::Triple::TvOS: + case llvm::Triple::DriverKit: // Darwin defaults to "softfp" for v6 and v7. if (Triple.isWatchABI()) return FloatABI::Hard; @@ -434,7 +437,7 @@ static bool hasIntegerMVE(const std::vector<StringRef> &F) { } void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args, ArgStringList &CmdArgs, + const ArgList &Args, std::vector<StringRef> &Features, bool ForAS) { bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); @@ -717,6 +720,15 @@ fp16_fml_fallthrough: } } + // Propagate frame-chain model selection + if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) { + StringRef FrameChainOption = A->getValue(); + if (FrameChainOption.startswith("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 +745,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. @@ -772,8 +794,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 +804,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 +824,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 +879,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->getOption().getName() << Scope; break; } } diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.h b/clang/lib/Driver/ToolChains/Arch/ARM.h index 862a2f2796be..782bdf3d0202 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -66,7 +66,6 @@ void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args, 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); int getARMSubArchVersionNumber(const llvm::Triple &Triple); bool isARMMProfile(const llvm::Triple &Triple); diff --git a/clang/lib/Driver/ToolChains/Arch/CSKY.cpp b/clang/lib/Driver/ToolChains/Arch/CSKY.cpp new file mode 100644 index 000000000000..3a8f92785609 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/CSKY.cpp @@ -0,0 +1,170 @@ +//===--- 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/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/CSKYTargetParser.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +llvm::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 llvm::Optional<llvm::StringRef>(); + } + return llvm::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 llvm::Optional<llvm::StringRef>(); + } + return llvm::Optional<llvm::StringRef>(llvm::CSKY::getArchName(ArchKind)); + } + + return llvm::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 = std::find(Features.begin(), Features.end(), 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/clang/lib/Driver/ToolChains/Arch/CSKY.h b/clang/lib/Driver/ToolChains/Arch/CSKY.h new file mode 100644 index 000000000000..d23da1d66e35 --- /dev/null +++ b/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); + +llvm::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/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 7ad8ca69bed5..8a8ed20986c5 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -198,7 +198,7 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { // Ignore parsing error, just go 3rd step. consumeError(ParseResult.takeError()); else - return llvm::RISCV::computeDefaultABIFromArch(**ParseResult); + return (*ParseResult)->computeDefaultABI(); // 3. Choose a default based on the triple // diff --git a/clang/lib/Driver/ToolChains/Arch/VE.h b/clang/lib/Driver/ToolChains/Arch/VE.h index 531433534914..c47a41df25bc 100644 --- a/clang/lib/Driver/ToolChains/Arch/VE.h +++ b/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/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index bfa008f964e1..cd7c014faa5e 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -84,13 +84,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()) @@ -240,4 +246,20 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, 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->getOption().getName() << Scope; + } + } } diff --git a/clang/lib/Driver/ToolChains/CSKYToolChain.cpp b/clang/lib/Driver/ToolChains/CSKYToolChain.cpp new file mode 100644 index 000000000000..de286faaca6d --- /dev/null +++ b/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(); + SelectedMultilib = GCCInstallation.getMultilib(); + path_list &Paths = getFilePaths(); + // Add toolchain/multilib specific file paths. + addMultilibsFilePaths(D, Multilibs, SelectedMultilib, + GCCInstallation.getInstallPath(), Paths); + getFilePaths().push_back(GCCInstallation.getInstallPath().str() + + SelectedMultilib.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()); + } else { + getProgramPaths().push_back(D.Dir); + } + getFilePaths().push_back(computeSysRoot() + "/lib" + + SelectedMultilib.osSuffix()); +} + +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.str()); +} + +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_e, options::OPT_s, + options::OPT_t, options::OPT_Z_Flag, 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/clang/lib/Driver/ToolChains/CSKYToolChain.h b/clang/lib/Driver/ToolChains/CSKYToolChain.h new file mode 100644 index 000000000000..52b37539cc5f --- /dev/null +++ b/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 : 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/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 7aac977209eb..c9bbdb2ac72e 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -10,6 +10,7 @@ #include "AMDGPU.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" +#include "Arch/CSKY.h" #include "Arch/M68k.h" #include "Arch/Mips.h" #include "Arch/PPC.h" @@ -28,6 +29,8 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Driver/Action.h" #include "clang/Driver/Distro.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" @@ -35,6 +38,7 @@ #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/Config/llvm-config.h" #include "llvm/Option/ArgList.h" @@ -223,12 +227,16 @@ 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); @@ -252,10 +260,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 +279,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; @@ -328,7 +340,7 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - arm::getARMTargetFeatures(D, Triple, Args, CmdArgs, Features, ForAS); + arm::getARMTargetFeatures(D, Triple, Args, Features, ForAS); break; case llvm::Triple::ppc: @@ -347,8 +359,7 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: - aarch64::getAArch64TargetFeatures(D, Triple, Args, CmdArgs, Features, - ForAS); + aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS); break; case llvm::Triple::x86: case llvm::Triple::x86_64: @@ -370,6 +381,10 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, 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; @@ -379,6 +394,9 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::ve: ve::getVETargetFeatures(D, Args, Features); break; + case llvm::Triple::csky: + csky::getCSKYTargetFeatures(D, Triple, Args, CmdArgs, Features); + break; } for (auto Feature : unifyTargetFeatures(Features)) { @@ -450,9 +468,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); @@ -543,6 +561,7 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, case llvm::Triple::riscv64: case llvm::Triple::amdgcn: case llvm::Triple::r600: + case llvm::Triple::csky: return !areOptimizationsEnabled(Args); default: break; @@ -613,10 +632,10 @@ getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { 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()); + bool OmitLeafFP = + Args.hasFlag(options::OPT_momit_leaf_frame_pointer, + options::OPT_mno_omit_leaf_frame_pointer, + Triple.isAArch64() || Triple.isPS() || Triple.isVE()); if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { if (OmitLeafFP) @@ -669,17 +688,24 @@ static void addDebugObjectName(const ArgList &Args, ArgStringList &CmdArgs, } /// 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. @@ -1150,7 +1176,8 @@ static const char *RelocationModelName(llvm::Reloc::Model Model) { } 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,6 +1189,11 @@ 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))); } } @@ -1277,6 +1309,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // 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) && (getToolChain().getTriple().isNVPTX() || getToolChain().getTriple().isAMDGCN())) { if (!Args.hasArg(options::OPT_nobuiltininc)) { @@ -1333,7 +1366,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,12 +1378,12 @@ 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) { llvm::sys::path::replace_extension(P, "gch"); - if (llvm::sys::fs::exists(P)) { + if (D.getVFS().exists(P)) { FoundPCH = true; } } @@ -1453,6 +1487,9 @@ 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); } // FIXME: Move to target hook. @@ -1625,6 +1662,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 = + std::find_if(CmdArgs.rbegin(), CmdArgs.rend(), [](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, @@ -1639,7 +1686,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, const Driver &D = TC.getDriver(); const llvm::Triple &Triple = TC.getEffectiveTriple(); if (!(isAArch64 || (Triple.isArmT32() && Triple.isArmMClass()))) - D.Diag(diag::warn_target_unsupported_branch_protection_option) + D.Diag(diag::warn_incompatible_branch_protection_option) << Triple.getArchName(); StringRef Scope, Key; @@ -1647,18 +1694,17 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, 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->getOption().getName() << Scope; Key = "a_key"; IndirectBranches = 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->getOption().getName() << DiagMsg; if (!isAArch64 && PBP.Key == "b_key") D.Diag(diag::warn_unsupported_branch_protection) << "b-key" << A->getAsString(Args); @@ -1720,6 +1766,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, @@ -1893,6 +1941,8 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(TuneCPU)); } } + + AddUnalignedAccessWarning(CmdArgs); } void Clang::AddMIPSTargetArgs(const ArgList &Args, @@ -2259,10 +2309,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. @@ -2356,7 +2406,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(); @@ -2382,6 +2433,7 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, CDB << ", \"" << escape(Buf) << "\""; } CDB << ", \"" << escape(Input.getFilename()) << "\""; + CDB << ", \"-o\", \"" << escape(Output.getFilename()) << "\""; for (auto &A: Args) { auto &O = A->getOption(); // Skip language selection, which is positional. @@ -2395,6 +2447,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 +2523,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, DefaultIncrementalLinkerCompatible)) CmdArgs.push_back("-mincremental-linker-compatible"); + Args.AddLastArg(CmdArgs, options::OPT_femit_dwarf_unwind_EQ); + // If you add more args here, also add them to the block below that // starts with "// If CollectArgsForIntegratedAssembler() isn't called below". @@ -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 = @@ -2837,6 +2896,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(); @@ -2895,6 +2955,18 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, 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->getOption().getName() << Val; + break; + } + case options::OPT_ffinite_math_only: HonorINFs = false; HonorNaNs = false; @@ -3050,6 +3122,9 @@ 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)); + ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the @@ -3090,12 +3165,6 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, 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 +3182,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 +3201,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"); @@ -3306,9 +3375,8 @@ static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args, !EffectiveTriple.isPPC64()) 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, @@ -3391,6 +3459,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 +3477,24 @@ 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_S, + options::OPT_emit_llvm, + options::OPT_disable_llvm_passes, + options::OPT_fnative_half_type}; + + 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)) + CmdArgs.push_back("-finclude-default-header"); + CmdArgs.push_back("-fallow-half-arguments-and-returns"); +} + static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { bool ARCMTEnabled = false; @@ -3492,20 +3581,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 +3598,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"); @@ -3554,9 +3641,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. @@ -3855,15 +3941,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 +3952,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)) { @@ -3901,22 +3981,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 +3996,8 @@ 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); if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) CmdArgs.push_back("-fdiagnostics-absolute-paths"); @@ -3936,9 +4006,8 @@ 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 }; @@ -4247,8 +4316,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,17 +4325,6 @@ 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(); - } } } @@ -4344,17 +4402,26 @@ 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) && + Args.hasFlag(options::OPT_fopenmp_new_driver, + options::OPT_no_offload_new_driver, true)) || + (JA.isHostOffloading(C.getActiveOffloadKinds()) && + Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false)); + bool IsUsingLTO = D.isUsingLTO(IsDeviceOffloadAction); auto LTOMode = D.getLTOMode(IsDeviceOffloadAction); @@ -4366,11 +4433,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, }(); InputInfo HeaderModuleInput(Inputs[0].getType(), ModuleName, ModuleName); - const InputInfo &Input = - IsHeaderModulePrecompile ? HeaderModuleInput : Inputs[0]; + // 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 = [&]() -> const InputInfo & { + if (IsHeaderModulePrecompile) + return HeaderModuleInput; + if (IsExtractAPI) + return ExtractAPIPlaceholderInput; + return Inputs[0]; + }(); InputInfoList ModuleHeaderInputs; - InputInfoList OpenMPHostInputs; + InputInfoList ExtractAPIInputs; + InputInfoList HostOffloadingInputs; const InputInfo *CudaDeviceInput = nullptr; const InputInfo *OpenMPDeviceInput = nullptr; for (const InputInfo &I : Inputs) { @@ -4385,12 +4463,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, << types::getTypeName(Expected); } ModuleHeaderInputs.push_back(I); + } 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(ExpectedInputType); + } + 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"); } @@ -4534,6 +4620,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 +4636,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"); @@ -4564,10 +4653,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(IsHeaderModulePrecompile ? "-emit-header-module" : "-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); } else { assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && "Invalid action for clang tool."); @@ -4606,8 +4703,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,9 +4714,14 @@ 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)) { + if (IsUsingLTO) { // Only AMDGPU supports device-side LTO. - if (IsDeviceOffloadAction && !Triple.isAMDGPU()) { + if (IsDeviceOffloadAction && + !Args.hasFlag(options::OPT_fopenmp_new_driver, + options::OPT_no_offload_new_driver, true) && + !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) @@ -4717,9 +4817,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); @@ -5008,17 +5107,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } - 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"); @@ -5078,9 +5172,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 +5187,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); @@ -5246,6 +5330,8 @@ 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. @@ -5349,6 +5435,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, types::isLLVMIR(InputType), CmdArgs, DebugInfoKind, DwarfFission); + // This controls whether or not we perform JustMyCode instrumentation. + if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) { + if (TC.getTriple().isOSBinFormatELF()) { + if (DebugInfoKind >= codegenoptions::DebugInfoConstructor) + CmdArgs.push_back("-fjmc"); + else + D.Diag(clang::diag::warn_drv_jmc_requires_debuginfo) << "-fjmc" + << "-g"; + } else { + D.Diag(clang::diag::warn_drv_fjmc_for_elf_only); + } + } + // Add the split debug info name to the command lines here so we // can propagate it to the backend. bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) && @@ -5464,17 +5563,12 @@ 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); if (Arg *A = Args.getLastArg(options::OPT_fsplit_machine_functions, options::OPT_fno_split_machine_functions)) { @@ -5500,11 +5594,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ); - // Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled. - if (RawTriple.isPS4CPU() && + // 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. @@ -5698,7 +5792,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const char *DebugCompilationDir = addDebugCompDirArg(Args, CmdArgs, D.getVFS()); - addDebugPrefixMapArg(D, Args, CmdArgs); + addDebugPrefixMapArg(D, TC, Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, options::OPT_ftemplate_depth_EQ)) { @@ -5721,6 +5815,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Args.hasArg(options::OPT_funstable)) { + CmdArgs.push_back("-funstable"); + if (!Args.hasArg(options::OPT_fno_coroutines_ts)) + CmdArgs.push_back("-fcoroutines-ts"); + CmdArgs.push_back("-fmodules-ts"); + } + if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter)) CmdArgs.push_back("-fexperimental-new-constant-interpreter"); @@ -5746,7 +5847,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); @@ -5820,6 +5921,14 @@ 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)) { @@ -5864,6 +5973,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, << A->getAsString(Args) << TripleStr; } + if (const Arg *A = + Args.getLastArg(options::OPT_mdefault_visibility_export_mapping_EQ)) { + if (Triple.isOSAIX()) + A->render(Args, CmdArgs); + 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)) @@ -5888,6 +6005,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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 (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,13 +6063,6 @@ 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, @@ -5966,6 +6086,10 @@ 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_offload_mandatory)) + CmdArgs.push_back("-fopenmp-offload-mandatory"); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -5980,11 +6104,14 @@ 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.hasArg(options::OPT_offload_new_driver)) + CmdArgs.push_back("--offload-new-driver"); + SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType); const XRayArgs &XRay = TC.getXRayArgs(); @@ -6125,9 +6252,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,19 +6262,17 @@ 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 + if (C.getDriver().IsDXCMode()) + RenderHLSLOptions(Args, CmdArgs, InputType); + if (IsHIP) { if (Args.hasFlag(options::OPT_fhip_new_launch_api, options::OPT_fno_hip_new_launch_api, true)) @@ -6156,9 +6280,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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_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) && + Args.hasArg(options::OPT_offload_new_driver)) + D.Diag(diag::err_drv_no_rdc_new_driver); if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) CmdArgs.push_back("-fgpu-rdc"); if (Args.hasFlag(options::OPT_fgpu_defer_diag, @@ -6172,6 +6301,10 @@ 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())); @@ -6214,9 +6347,8 @@ 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); // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, @@ -6243,15 +6375,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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,10 +6407,8 @@ 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, @@ -6316,8 +6441,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(); @@ -6376,14 +6501,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. @@ -6409,16 +6532,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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"); - - if (Args.hasArg(options::OPT_fno_inline)) - CmdArgs.push_back("-fno-inline"); + Args.addOptInFlag(CmdArgs, options::OPT_fgnu89_inline, + options::OPT_fno_gnu89_inline); - Args.AddLastArg(CmdArgs, options::OPT_finline_functions, - options::OPT_finline_hint_functions, - options::OPT_fno_inline_functions); + 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); + } // FIXME: Find a better way to determine whether the language has modules // support by default, or just assume that all languages do. @@ -6440,8 +6565,8 @@ 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); + if (!CLANG_ENABLE_OPAQUE_POINTERS_INTERNAL) + CmdArgs.push_back("-no-opaque-pointers"); ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, Inputs, CmdArgs, rewriteKind); RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None, @@ -6493,22 +6618,19 @@ 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); // -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 +6653,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 +6691,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,10 +6723,8 @@ 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, @@ -6648,17 +6765,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"); + Args.addOptInFlag(CmdArgs, options::OPT_fapple_pragma_pack, + options::OPT_fno_apple_pragma_pack); if (Args.hasFlag(options::OPT_fxl_pragma_pack, options::OPT_fno_xl_pragma_pack, RawTriple.isOSAIX())) @@ -6673,6 +6781,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (RewriteImports) CmdArgs.push_back("-frewrite-imports"); + if (Args.hasFlag(options::OPT_fdirectives_only, + options::OPT_fno_directives_only, false)) + CmdArgs.push_back("-fdirectives-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 @@ -6871,8 +6983,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Twine("-cuid=") + Twine(CUID))); } - if (IsHIP) + if (IsHIP) { CmdArgs.push_back("-fcuda-allow-variadic-functions"); + Args.AddLastArg(CmdArgs, options::OPT_fgpu_default_stream_EQ); + } if (IsCudaDevice || IsHIPDevice) { StringRef InlineThresh = @@ -6897,50 +7011,29 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - // 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)); - } - } + // Host-side offloading recieves the device object files and embeds it in a + // named section including the associated target triple and architecture. + for (const InputInfo Input : HostOffloadingInputs) + CmdArgs.push_back(Args.MakeArgString("-fembed-offload-object=" + + TC.getInputFilename(Input))); 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); } // 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 = @@ -7041,13 +7134,10 @@ 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"); + Args.addOptInFlag(CmdArgs, options::OPT_fkeep_static_consts, + options::OPT_fno_keep_static_consts); + Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers, + options::OPT_fno_complete_member_pointers); if (!Args.hasFlag(options::OPT_fcxx_static_destructors, options::OPT_fno_cxx_static_destructors, true)) @@ -7127,6 +7217,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, ArrayRef<InputInfo> FrontendInputs = Input; if (IsHeaderModulePrecompile) FrontendInputs = ModuleHeaderInputs; + else if (IsExtractAPI) + FrontendInputs = ExtractAPIInputs; else if (Input.isNothing()) FrontendInputs = {}; @@ -7378,6 +7470,12 @@ 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; } @@ -7473,6 +7571,17 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, } const Driver &D = getToolChain().getDriver(); + + // This controls whether or not we perform JustMyCode instrumentation. + if (Args.hasFlag(options::OPT__SLASH_JMC, options::OPT__SLASH_JMC_, + /*Default=*/false)) { + if (*EmitCodeView && *DebugInfoKind >= codegenoptions::DebugInfoConstructor) + CmdArgs.push_back("-fjmc"); + else + D.Diag(clang::diag::warn_drv_jmc_requires_debuginfo) << "/JMC" + << "'/Zi', '/Z7'"; + } + EHFlags EH = parseClangCLEHFlags(D, Args); if (!isNVPTX && (EH.Synch || EH.Asynch)) { if (types::isCXX(InputType)) @@ -7506,6 +7615,32 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, 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) @@ -7575,6 +7710,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("msvc"); } + if (Args.hasArg(options::OPT__SLASH_kernel)) + CmdArgs.push_back("-fms-kernel"); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { StringRef GuardArgs = A->getValue(); // The only valid options are "cf", "cf,nochecks", "cf-", "ehcont" and @@ -7675,6 +7813,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); const std::string &TripleStr = Triple.getTriple(); + const Optional<llvm::Triple> TargetVariantTriple = + getToolChain().getTargetVariantTriple(); const auto &D = getToolChain().getDriver(); // Don't warn about "clang -w -c foo.s" @@ -7692,6 +7832,10 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // Add the "effective" target triple. CmdArgs.push_back("-triple"); CmdArgs.push_back(Args.MakeArgString(TripleStr)); + if (TargetVariantTriple) { + CmdArgs.push_back("-darwin-target-variant-triple"); + CmdArgs.push_back(Args.MakeArgString(TargetVariantTriple->getTriple())); + } // Set the output mode, we currently only expect to be used as a real // assembler. @@ -7759,7 +7903,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, DebugInfoKind = (WantDebug ? codegenoptions::DebugInfoConstructor : 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. @@ -7774,7 +7919,6 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, 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; @@ -7904,7 +8048,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()); @@ -7935,8 +8079,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; @@ -7997,14 +8143,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,9 +8163,8 @@ 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)); - // All the inputs are encoded as commands. C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::None(), @@ -8039,8 +8182,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; @@ -8092,17 +8237,15 @@ 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"); @@ -8143,54 +8286,107 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs, Inputs, Output)); } +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; + + // Add the output file name. + assert(Output.isFilename() && "Invalid output."); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.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(), Args, Features, false); + llvm::copy_if(Features, std::back_inserter(FeatureArgs), + [](StringRef Arg) { return !Arg.startswith("-target"); }); + + SmallVector<std::string> Parts{ + "file=" + File.str(), + "triple=" + TC->getTripleString(), + "arch=" + Arch.str(), + "kind=" + Kind.str(), + }; + + if (TC->getDriver().isUsingLTO(/* IsOffload */ true)) + 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>( + JA, *this, ResponseFileSupport::None(), + Args.MakeArgString(getToolChain().GetProgramPath(getShortName())), + CmdArgs, Inputs, Output)); +} + void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + const llvm::Triple TheTriple = getToolChain().getTriple(); + auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); ArgStringList CmdArgs; - if (getToolChain().getDriver().isUsingLTO(/* IsOffload */ true)) { - // Pass in target features for each toolchain. - auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); - for (auto &I : - llvm::make_range(OpenMPTCRange.first, OpenMPTCRange.second)) { + // Pass the CUDA path to the linker wrapper tool. + 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 &D = TC->getDriver(); - const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP); - StringRef Arch = TCArgs.getLastArgValue(options::OPT_march_EQ); + // Get the AMDGPU math libraries. + // FIXME: This method is bad, remove once AMDGPU has a proper math library + // (see AMDGCN::OpenMPLinker::constructLLVMLinkCommand). + for (auto &I : llvm::make_range(OpenMPTCRange.first, OpenMPTCRange.second)) { + const ToolChain *TC = I.second; - 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; + if (!TC->getTriple().isAMDGPU() || Args.hasArg(options::OPT_nogpulib)) + continue; - ArgStringList BitcodeLibrary; - addOpenMPDeviceRTL(D, TCArgs, BitcodeLibrary, BitcodeSuffix, - TC->getTriple()); + const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP); + StringRef Arch = TCArgs.getLastArgValue(options::OPT_march_EQ); + const toolchains::ROCMToolChain RocmTC(TC->getDriver(), TC->getTriple(), + TCArgs); - if (!BitcodeLibrary.empty()) - CmdArgs.push_back( - Args.MakeArgString("-target-library=" + TC->getTripleString() + - "-" + Arch + "=" + BitcodeLibrary.back())); - } + SmallVector<std::string, 12> BCLibs = + RocmTC.getCommonDeviceLibNames(TCArgs, Arch.str()); + for (StringRef LibName : BCLibs) + CmdArgs.push_back(Args.MakeArgString( + "-target-library=" + Action::GetOffloadKindName(Action::OFK_OpenMP) + + "-" + TC->getTripleString() + "-" + Arch + "=" + LibName)); + } + + if (D.isUsingLTO(/* IsOffload */ true)) { // Pass in the optimization level to use for LTO. if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { StringRef OOpt; @@ -8210,12 +8406,8 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, } } - // 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(); - CmdArgs.push_back("-host-triple"); - CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString())); + CmdArgs.push_back(Args.MakeArgString(TheTriple.getTriple())); if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-v"); @@ -8246,6 +8438,24 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, if (Args.getLastArg(options::OPT_save_temps_EQ)) 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 (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) { + StringRef Val = Arg->getValue(0); + if (Val.empty()) + CmdArgs.push_back( + Args.MakeArgString(Twine("-device-linker=") + Arg->getValue(1))); + else + CmdArgs.push_back(Args.MakeArgString( + "-device-linker=" + + ToolChain::getOpenMPTriple(Val.drop_front()).getTriple() + "=" + + Arg->getValue(1))); + } + Args.ClaimAllArgs(options::OPT_Xoffload_linker); + // Add the linker arguments to be forwarded by the wrapper. CmdArgs.push_back("-linker-path"); CmdArgs.push_back(LinkCommand->getExecutable()); diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index 79407c9884d5..37263efd57a5 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -170,6 +170,19 @@ public: const char *LinkingOutput) const override; }; +/// Offload binary tool. +class LLVM_LIBRARY_VISIBILITY OffloadPackager final : public Tool { +public: + OffloadPackager(const ToolChain &TC) + : Tool("Offload::Packager", "clang-offload-packager", 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; +}; + /// Linker wrapper tool. class LLVM_LIBRARY_VISIBILITY LinkerWrapper final : public Tool { const Tool *Linker; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 6364cd133e0b..2d53b829b01c 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -143,28 +143,16 @@ void tools::handleTargetFeaturesGroup(const ArgList &Args, } } -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 +243,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(); @@ -424,6 +416,13 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args, 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: if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) @@ -475,9 +474,9 @@ llvm::StringRef tools::getLTOParallelism(const ArgList &Args, const Driver &D) { return LtoJobsArg->getValue(); } -// CloudABI uses -ffunction-sections and -fdata-sections by default. +// CloudABI and PS4/PS5 use -ffunction-sections and -fdata-sections by default. bool tools::isUseSeparateSections(const llvm::Triple &Triple) { - return Triple.getOS() == llvm::Triple::CloudABI; + return Triple.getOS() == llvm::Triple::CloudABI || Triple.isPS(); } void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, @@ -548,6 +547,9 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back( Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism))); + if (!CLANG_ENABLE_OPAQUE_POINTERS_INTERNAL) + CmdArgs.push_back(Args.MakeArgString("-plugin-opt=no-opaque-pointers")); + // If an explicit debugger tuning argument appeared, pass it along. if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { @@ -574,6 +576,13 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back("-plugin-opt=-data-sections"); } + // 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("-plugin-opt=-split-machine-functions"); + } + if (Arg *A = getLastProfileSampleUseArg(Args)) { StringRef FName = A->getValue(); if (!llvm::sys::fs::exists(FName)) @@ -612,15 +621,6 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, 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"); - else - CmdArgs.push_back("-plugin-opt=new-pass-manager"); - } - // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); if (!StatsFile.empty()) @@ -661,6 +661,17 @@ void tools::addOpenMPRuntimeSpecificRPath(const ToolChain &TC, } } +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, Twine("lib") + CLANG_LIBDIR_SUFFIX); + 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. @@ -716,14 +727,53 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, if (IsOffloadingHost) CmdArgs.push_back("-lomptarget"); + if (IsOffloadingHost && TC.getDriver().isUsingLTO(/* IsOffload */ true)) + CmdArgs.push_back("-lomptarget.devicertl"); + addArchSpecificRPath(TC, Args, CmdArgs); if (RTKind == Driver::OMPRT_OMP) addOpenMPRuntimeSpecificRPath(TC, Args, CmdArgs); + addOpenMPRuntimeLibraryPath(TC, Args, CmdArgs); return true; } +void tools::addFortranRuntimeLibs(const ToolChain &TC, + llvm::opt::ArgStringList &CmdArgs) { + if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { + CmdArgs.push_back("Fortran_main.lib"); + CmdArgs.push_back("FortranRuntime.lib"); + CmdArgs.push_back("FortranDecimal.lib"); + } else { + CmdArgs.push_back("-lFortran_main"); + CmdArgs.push_back("-lFortranRuntime"); + CmdArgs.push_back("-lFortranDecimal"); + } +} + +void tools::addFortranRuntimeLibraryPath(const ToolChain &TC, + const llvm::opt::ArgList &Args, + ArgStringList &CmdArgs) { + // NOTE: Generating executables by Flang is considered an "experimental" + // feature and hence this is guarded with a command line option. + // TODO: Make this work unconditionally once Flang is mature enough. + if (!Args.hasArg(options::OPT_flang_experimental_exec)) + return; + + // 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) { @@ -756,7 +806,7 @@ static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, return false; } -static const char *getAsNeededOption(const ToolChain &TC, bool as_needed) { +const char *tools::getAsNeededOption(const ToolChain &TC, bool as_needed) { assert(!TC.getTriple().isOSAIX() && "AIX linker does not support any form of --as-needed option yet."); @@ -771,11 +821,6 @@ static const char *getAsNeededOption(const ToolChain &TC, bool as_needed) { void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { - // Fuchsia never needs these. Any sanitizer runtimes with system - // dependencies use the `.deplibs` feature instead. - if (TC.getTriple().isOSFuchsia()) - return; - // Force linking against the system libraries sanitizers depends on // (see PR15823 why this is necessary). CmdArgs.push_back(getAsNeededOption(TC, false)); @@ -797,6 +842,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 @@ -838,6 +889,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, SharedRuntimes.push_back("hwasan_aliases"); else SharedRuntimes.push_back("hwasan"); + if (!Args.hasArg(options::OPT_shared)) + HelperStaticRuntimes.push_back("hwasan-preinit"); } } @@ -991,6 +1044,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(); } @@ -1233,30 +1299,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)) { @@ -1411,17 +1478,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; } @@ -1449,6 +1511,7 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, 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) @@ -1472,15 +1535,15 @@ 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; } @@ -1492,10 +1555,12 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, 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"); } @@ -1728,8 +1793,13 @@ bool tools::GetSDLFromOffloadArchive( 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()); + llvm::Triple Triple(D.getTargetTriple()); + bool IsMSVC = Triple.isWindowsMSVCEnvironment(); + for (auto Prefix : {"/libdevice/", "/"}) { + if (IsMSVC) + AOBFileNames.push_back(Twine(LPath + Prefix + Lib + ".lib").str()); + AOBFileNames.push_back(Twine(LPath + Prefix + "lib" + Lib + ".a").str()); + } for (auto AOB : AOBFileNames) { if (llvm::sys::fs::exists(AOB)) { @@ -1761,9 +1831,9 @@ bool tools::GetSDLFromOffloadArchive( std::string UnbundleArg("-unbundle"); std::string TypeArg("-type=a"); - std::string InputArg("-inputs=" + ArchiveOfBundles); + std::string InputArg("-input=" + ArchiveOfBundles); std::string OffloadArg("-targets=" + std::string(DeviceTriple)); - std::string OutputArg("-outputs=" + OutputLib); + std::string OutputArg("-output=" + OutputLib); const char *UBProgram = DriverArgs.MakeArgString( T.getToolChain().GetProgramPath("clang-offload-bundler")); @@ -1780,6 +1850,12 @@ bool tools::GetSDLFromOffloadArchive( 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)); + C.addCommand(std::make_unique<Command>( JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs, InputInfo(&JA, C.getArgs().MakeArgString(OutputLib)))); @@ -1908,7 +1984,7 @@ getAMDGPUCodeObjectArgument(const Driver &D, const llvm::opt::ArgList &Args) { void tools::checkAMDGPUCodeObjectVersion(const Driver &D, const llvm::opt::ArgList &Args) { const unsigned MinCodeObjVer = 2; - const unsigned MaxCodeObjVer = 4; + const unsigned MaxCodeObjVer = 5; // Emit warnings for legacy options even if they are overridden. if (Args.hasArg(options::OPT_mno_code_object_v3_legacy)) @@ -2011,11 +2087,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 +2128,17 @@ void tools::addOpenMPDeviceRTL(const Driver &D, << LibOmpTargetName << ArchPrefix; } } +void tools::addHIPRuntimeLibArgs(const ToolChain &TC, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_hip_link) && + !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/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index 646fa76949b7..8e62af70ff7f 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -111,12 +111,29 @@ void addOpenMPRuntimeSpecificRPath(const ToolChain &TC, 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); +/// Adds Fortran runtime libraries to \p CmdArgs. +void addFortranRuntimeLibs(const ToolChain &TC, + 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, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + +const char *getAsNeededOption(const ToolChain &TC, bool as_needed); + llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args); llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args); @@ -157,8 +174,7 @@ void handleTargetFeaturesGroup(const llvm::opt::ArgList &Args, 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. diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 4a9f6d4c4e3e..5e59677947e6 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -447,7 +447,10 @@ 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))); + const char *OutputFileName = Args.MakeArgString(TC.getInputFilename(Output)); + if (std::string(OutputFileName) != std::string(Output.getFilename())) + C.addTempFile(OutputFileName); + CmdArgs.push_back(OutputFileName); for (const auto& II : Inputs) CmdArgs.push_back(Args.MakeArgString(II.getFilename())); @@ -533,8 +536,9 @@ 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)) @@ -606,8 +610,8 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, if (!II.isFilename()) continue; - const char *CubinF = C.addTempFile( - C.getArgs().MakeArgString(getToolChain().getInputFilename(II))); + const char *CubinF = + C.getArgs().MakeArgString(getToolChain().getInputFilename(II)); CmdArgs.push_back(CubinF); } @@ -630,6 +634,45 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, Exec, CmdArgs, Inputs, Output)); } +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); + + // 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(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); +} + /// 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. @@ -650,9 +693,8 @@ CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, 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)) + // extensions. + if (Input.getType() != types::TY_Object) return ToolChain::getInputFilename(Input); // Replace extension for object files with cubin because nvlink relies on @@ -701,32 +743,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,14 +764,7 @@ 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, @@ -835,10 +844,10 @@ 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()) + if (!DAL->hasArg(options::OPT_march_EQ)) DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), - CLANG_OPENMP_NVPTX_DEFAULT_ARCH); + !BoundArch.empty() ? BoundArch + : CLANG_OPENMP_NVPTX_DEFAULT_ARCH); return DAL; } diff --git a/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h index a7e6e84f4902..809a25227ac4 100644 --- a/clang/lib/Driver/ToolChains/Cuda.h +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -124,6 +124,10 @@ class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool { 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 diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index f7da3f187814..0a8a9c6eb6ff 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -209,19 +209,18 @@ 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) 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 +229,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 +259,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 +269,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 +345,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) MachOTC.addPlatformVersionArgs(Args, CmdArgs); else MachOTC.addMinVersionArgs(Args, CmdArgs); @@ -368,7 +371,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"); } @@ -548,12 +553,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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 = @@ -635,6 +635,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(), CmdArgs); + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) addOpenMPRuntime(CmdArgs, getToolChain(), Args); @@ -712,8 +719,28 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + // DriverKit's framework doesn't have the same layout as other frameworks. + // Add missing search paths if necessary. + if (getToolChain().getTriple().getOS() == llvm::Triple::DriverKit) { + if (const Arg *Root = Args.getLastArg(options::OPT_isysroot)) { + // ld64 fixed the implicit -F and -L paths in ld64-605.1+. + if (Version.getMajor() < 605 || + (Version.getMajor() == 605 && Version.getMinor().value_or(0) < 1)) { + + SmallString<128> L(Root->getValue()); + llvm::sys::path::append(L, "System", "DriverKit", "usr", "lib"); + CmdArgs.push_back(Args.MakeArgString(std::string("-L") + L)); + + SmallString<128> F(Root->getValue()); + llvm::sys::path::append(F, "System", "DriverKit"); + llvm::sys::path::append(F, "System", "Library", "Frameworks"); + CmdArgs.push_back(Args.MakeArgString(std::string("-F") + F)); + } + } + } + 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 +896,13 @@ 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; + // Use libstdc++ on old targets (OSX < 10.9 and iOS < 7) + if ((isTargetMacOSBased() && isMacosxVersionLT(10, 9)) || + (isTargetIOSBased() && isIPhoneOSVersionLT(7, 0))) + return ToolChain::CST_Libstdcxx; - return ToolChain::CST_Libstdcxx; + // On all other targets, use libc++ + return ToolChain::CST_Libcxx; } /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. @@ -891,7 +918,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()) return true; else if (isTargetIOSBased()) return !isIPhoneOSVersionLT(3, 2); @@ -979,6 +1006,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,6 +1045,8 @@ 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 @@ -1152,8 +1202,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); @@ -1197,6 +1248,8 @@ StringRef Darwin::getPlatformFamily() const { return "AppleTV"; case DarwinPlatformKind::WatchOS: return "Watch"; + case DarwinPlatformKind::DriverKit: + return "DriverKit"; } llvm_unreachable("Unsupported platform"); } @@ -1228,6 +1281,8 @@ StringRef Darwin::getOSLibraryNameSuffix(bool IgnoreSim) const { case DarwinPlatformKind::WatchOS: return TargetEnvironment == NativeEnvironment || IgnoreSim ? "watchos" : "watchossim"; + case DarwinPlatformKind::DriverKit: + return "driverkit"; } llvm_unreachable("Unsupported platform"); } @@ -1289,7 +1344,6 @@ void Darwin::addProfileRTLibs(const ArgList &Args, addExportedSymbol(CmdArgs, "___llvm_profile_filename"); addExportedSymbol(CmdArgs, "___llvm_profile_raw_version"); } - addExportedSymbol(CmdArgs, "_lprofDirMode"); } // Align __llvm_prf_{cnts,data} sections to the maximum expected page @@ -1385,9 +1439,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()) { @@ -1478,6 +1538,10 @@ struct DarwinPlatform { /// Returns true if the simulator environment can be inferred from the arch. bool canInferSimulatorFromArch() const { return InferSimulatorFromArch; } + const 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) @@ -1498,6 +1562,9 @@ struct DarwinPlatform { case DarwinPlatformKind::WatchOS: Opt = options::OPT_mwatchos_version_min_EQ; break; + case DarwinPlatformKind::DriverKit: + // DriverKit always explicitly provides a version in the triple. + return; } Argument = Args.MakeJoinedArg(nullptr, Opts.getOption(Opt), OSVersion); Args.append(Argument); @@ -1540,6 +1607,16 @@ struct DarwinPlatform { } } } + // 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,12 +1626,14 @@ struct DarwinPlatform { static DarwinPlatform createFromTarget(const llvm::Triple &TT, StringRef OSVersion, Arg *A, + Optional<llvm::Triple> TargetVariantTriple, const 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; } @@ -1625,6 +1704,8 @@ private: return DarwinPlatformKind::TvOS; case llvm::Triple::WatchOS: return DarwinPlatformKind::WatchOS; + case llvm::Triple::DriverKit: + return DarwinPlatformKind::DriverKit; default: llvm_unreachable("Unable to infer Darwin variant"); } @@ -1638,6 +1719,7 @@ private: bool HasOSVersion = true, InferSimulatorFromArch = true; Arg *Argument; StringRef EnvVarName; + Optional<llvm::Triple> TargetVariantTriple; }; /// Returns the deployment target that's specified using the -m<os>-version-min @@ -1693,6 +1775,7 @@ 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, "Missing platform"); @@ -1791,6 +1874,8 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args, return DarwinPlatform::createFromSDK( Darwin::TvOS, Version, /*IsSimulator=*/SDK.startswith("AppleTVSimulator")); + else if (SDK.startswith("DriverKit")) + return DarwinPlatform::createFromSDK(Darwin::DriverKit, Version); return None; }; if (auto Result = CreatePlatformFromSDKName(SDK)) @@ -1827,6 +1912,9 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, case llvm::Triple::WatchOS: OsVersion = Triple.getWatchOSVersion(); break; + case llvm::Triple::DriverKit: + OsVersion = Triple.getDriverKitVersion(); + break; default: llvm_unreachable("Unexpected OS type"); break; @@ -1834,8 +1922,8 @@ 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; } @@ -1847,23 +1935,15 @@ inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, 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 DarwinPlatform::createFromArch(OSTy, @@ -1880,8 +1960,34 @@ Optional<DarwinPlatform> getDeploymentTargetFromTargetArg( Triple.getOS() == llvm::Triple::UnknownOS) return None; std::string OSVersion = getOSVersion(Triple.getOS(), Triple, TheDriver); - return DarwinPlatform::createFromTarget( - Triple, OSVersion, Args.getLastArg(options::OPT_target), SDKInfo); + 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 Catalust. + 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. @@ -2103,19 +2209,27 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { HadExtra || Major >= 10 || 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 >= 100 || Minor >= 100 || Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << OSTarget->getAsString(Args, Opts); } else llvm_unreachable("unknown kind of Darwin platform"); 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()); @@ -2395,6 +2509,8 @@ 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 { llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); } @@ -2422,12 +2538,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,14 +2610,6 @@ 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; } } @@ -2620,6 +2725,8 @@ bool Darwin::isAlignedAllocationUnavailable() const { case WatchOS: // Earlier than 4.0. OS = llvm::Triple::WatchOS; break; + case DriverKit: // Always available. + return false; } return TargetVersion < alignedAllocMinVersion(OS); @@ -2635,6 +2742,12 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, isAlignedAllocationUnavailable()) CC1Args.push_back("-faligned-alloc-unavailable"); + if (TargetVariantTriple) { + CC1Args.push_back("-darwin-target-variant-triple"); + CC1Args.push_back( + DriverArgs.MakeArgString(TargetVariantTriple->getTriple())); + } + if (SDKInfo) { /// Pass the SDK version to the compiler when the SDK information is /// available. @@ -2656,6 +2769,28 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, } else { EmitTargetSDKVersionArg(SDKInfo->getVersion()); } + + /// 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(); + CC1Args.push_back(DriverArgs.MakeArgString(OS.str())); + } else if (const auto *MacOStoMacCatalystMapping = + SDKInfo->getVersionMapping( + DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) { + if (Optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map( + SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(), + None)) { + std::string Arg; + llvm::raw_string_ostream OS(Arg); + OS << "-darwin-target-variant-sdk-version=" << *SDKVersion; + CC1Args.push_back(DriverArgs.MakeArgString(OS.str())); + } + } + } } // Enable compatibility mode for NSItemProviderCompletionHandler in @@ -2691,7 +2826,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() || (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) { for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { Arg *A = *it; @@ -2754,6 +2889,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 && @@ -2801,6 +2942,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 +2959,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 +2993,96 @@ static const char *getPlatformName(Darwin::DarwinPlatformKind Platform, return "tvos"; case Darwin::WatchOS: return "watchos"; + 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 (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())); - return; - } + 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. + 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())); + return; + } - if (SDKInfo) { - VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild(); - CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString())); + if (SDKInfo) { + VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild(); + 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; + 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. diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h index 5e23047a5512..4535d021262e 100644 --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -63,7 +63,7 @@ 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], + const InputInfoList &Inputs, VersionTuple Version, bool LinkerIsLLD) const; public: @@ -147,6 +147,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 Optional<VersionTuple> LinkerVersion; + public: MachO(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); @@ -159,6 +162,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 {} @@ -260,6 +267,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 +299,8 @@ public: IPhoneOS, TvOS, WatchOS, - LastDarwinPlatform = WatchOS + DriverKit, + LastDarwinPlatform = DriverKit }; enum DarwinEnvironmentKind { NativeEnvironment, @@ -310,6 +319,9 @@ public: /// The information about the darwin SDK that was used. mutable Optional<DarwinSDKInfo> SDKInfo; + /// The target variant triple that was specified (if any). + mutable Optional<llvm::Triple> TargetVariantTriple; + CudaInstallationDetector CudaInstallation; RocmInstallationDetector RocmInstallation; @@ -338,7 +350,7 @@ public: bool isKernelStatic() const override { return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) && - !isTargetWatchOS()); + !isTargetWatchOS() && !isTargetDriverKit()); } void addProfileRTLibs(const llvm::opt::ArgList &Args, @@ -424,6 +436,11 @@ public: return TargetPlatform == WatchOS; } + bool isTargetDriverKit() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == DriverKit; + } + bool isTargetMacCatalyst() const { return TargetPlatform == IPhoneOS && TargetEnvironment == MacCatalyst; } @@ -478,6 +495,12 @@ public: : TargetVersion) < VersionTuple(V0, V1, V2); } + /// Returns the darwin target variant triple, the variant of the deployment + /// target for which the code is being compiled. + Optional<llvm::Triple> getTargetVariantTriple() const override { + return TargetVariantTriple; + } + protected: /// Return true if c++17 aligned allocation/deallocation functions are not /// implemented in the c++ standard library of the deployment target we are @@ -527,7 +550,7 @@ 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()) return LangOptions::SSPOn; else if (isTargetMacOSBased() && !isMacosxVersionLT(10, 6)) return LangOptions::SSPOn; diff --git a/clang/lib/Driver/ToolChains/DragonFly.cpp b/clang/lib/Driver/ToolChains/DragonFly.cpp index 9568b47e89e6..8cfec6a6c4e0 100644 --- a/clang/lib/Driver/ToolChains/DragonFly.cpp +++ b/clang/lib/Driver/ToolChains/DragonFly.cpp @@ -91,7 +91,8 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back( @@ -119,7 +120,8 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + 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)) { @@ -158,7 +160,8 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - 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) || Args.hasArg(options::OPT_pie)) CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index c169e3d45793..3368f6785718 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -19,6 +19,14 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +/// 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( @@ -54,21 +62,18 @@ 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; // 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"); @@ -104,12 +109,42 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, 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 (D.getDiags().getDiagnosticOptions().ShowColors) + CmdArgs.push_back("-fcolor-diagnostics"); + // Add other compile options AddOtherOptions(Args, CmdArgs); // Forward -Xflang arguments to -fc1 Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); + // 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); + } + + // 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 { + A->render(Args, CmdArgs); + } + } + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -118,9 +153,11 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, } assert(Input.isFilename() && "Invalid input."); + + 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/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index 05c58a8f43a8..79e3c5cbca5f 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -223,10 +223,12 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::riscv32: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32lriscv"); + CmdArgs.push_back("-X"); break; case llvm::Triple::riscv64: CmdArgs.push_back("-m"); CmdArgs.push_back("elf64lriscv"); + CmdArgs.push_back("-X"); break; default: break; diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp index bd1600d060c8..03ff9fe894c8 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -37,6 +37,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, static_cast<const toolchains::Fuchsia &>(getToolChain()); const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getEffectiveTriple(); + ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -84,6 +86,12 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--hash-style=gnu"); } + if (ToolChain.getArch() == llvm::Triple::aarch64) { + 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)) @@ -106,6 +114,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()); @@ -127,10 +138,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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 +162,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); + + addXRayRuntime(ToolChain, Args, CmdArgs); - if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, CmdArgs); + ToolChain.addProfileRTLibs(Args, CmdArgs); AddRunTimeLibs(ToolChain, D, CmdArgs, Args); diff --git a/clang/lib/Driver/ToolChains/Fuchsia.h b/clang/lib/Driver/ToolChains/Fuchsia.h index c0e69df22821..f9f3bbfa9fbf 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.h +++ b/clang/lib/Driver/ToolChains/Fuchsia.h @@ -75,24 +75,27 @@ 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; + + 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 + 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; diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 7a9570a686f4..f52bb8af5ec9 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -8,6 +8,7 @@ #include "Gnu.h" #include "Arch/ARM.h" +#include "Arch/CSKY.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/RISCV.h" @@ -299,6 +300,8 @@ 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; } @@ -451,11 +454,6 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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,6 +465,8 @@ 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)) CmdArgs.push_back("-shared"); @@ -477,7 +477,8 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); - if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE) { + if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE && + !Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back(Args.MakeArgString(Twine(D.DyldPrefix) + ToolChain.getDynamicLinker(Args))); @@ -560,6 +561,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, Args, CmdArgs); + // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); @@ -577,9 +581,27 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } CmdArgs.push_back("-lm"); } + + // If we are linking for the device all symbols should be bound locally. The + // symbols are already protected which makes this redundant. This is only + // necessary to work around a problem in bfd. + // TODO: Remove this once 'lld' becomes the only linker for offloading. + if (JA.isDeviceOffloading(Action::OFK_OpenMP)) + CmdArgs.push_back("-Bsymbolic"); + // 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. + // AddRuntTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, CmdArgs); + CmdArgs.push_back("-lm"); + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { if (IsStatic || IsStaticPIE) @@ -758,6 +780,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: @@ -1574,6 +1598,68 @@ static bool findMSP430Multilibs(const Driver &D, 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); + llvm::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 = makeMultilib("/hard-fp").flag("+hard-fp"); + auto SoftFpFloat = makeMultilib("/soft-fp").flag("+soft-fp"); + auto SoftFloat = makeMultilib("").flag("+soft"); + auto Arch801 = makeMultilib("/ck801").flag("+march=ck801"); + auto Arch802 = makeMultilib("/ck802").flag("+march=ck802"); + auto Arch803 = makeMultilib("/ck803").flag("+march=ck803"); + // CK804 use the same library as CK803 + auto Arch804 = makeMultilib("/ck803").flag("+march=ck804"); + auto Arch805 = makeMultilib("/ck805").flag("+march=ck805"); + auto Arch807 = makeMultilib("/ck807").flag("+march=ck807"); + auto Arch810 = makeMultilib("").flag("+march=ck810"); + auto Arch810v = makeMultilib("/ck810v").flag("+march=ck810v"); + auto Arch860 = makeMultilib("/ck860").flag("+march=ck860"); + auto Arch860v = makeMultilib("/ck860v").flag("+march=ck860v"); + auto BigEndian = makeMultilib("/big").flag("+EB"); + + MultilibSet CSKYMultilibs = + MultilibSet() + .Maybe(BigEndian) + .Either({Arch801, Arch802, Arch803, Arch804, Arch805, Arch807, + Arch810, Arch810v, Arch860, Arch860v}) + .Either(HardFloat, SoftFpFloat, SoftFloat) + .FilterOut(NonExistent); + + if (CSKYMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = CSKYMultilibs; +} + static void findRISCVBareMetalMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, @@ -1951,7 +2037,7 @@ 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. @@ -2000,7 +2086,7 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { } bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { - if (BiarchSibling.hasValue()) { + if (BiarchSibling) { M = BiarchSibling.getValue(); return true; } @@ -2017,7 +2103,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( // 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"; + std::string PrefixDir = concat(SysRoot, "/usr/gcc"); std::error_code EC; for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), LE; @@ -2039,20 +2125,39 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( 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. - Prefixes.push_back("/opt/rh/gcc-toolset-10/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"); - Prefixes.push_back("/opt/rh/devtoolset-7/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); + // 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")) { + // Find the directory in /opt/rh/ starting with gcc-toolset-* or + // devtoolset-* with the highest version number and add that + // one to our prefixes. + std::string ChosenToolsetDir; + unsigned ChosenToolsetVersion = 0; + std::error_code EC; + for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin("/opt/rh", EC), + LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef ToolsetDir = llvm::sys::path::filename(LI->path()); + unsigned ToolsetVersion; + if ((!ToolsetDir.startswith("gcc-toolset-") && + !ToolsetDir.startswith("devtoolset-")) || + ToolsetDir.substr(ToolsetDir.rfind('-') + 1) + .getAsInteger(10, ToolsetVersion)) + continue; + + if (ToolsetVersion > ChosenToolsetVersion) { + ChosenToolsetVersion = ToolsetVersion; + ChosenToolsetDir = "/opt/rh/" + ToolsetDir.str(); + } + } + + if (ChosenToolsetVersion > 0) + Prefixes.push_back(ChosenToolsetDir + "/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 +2197,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", @@ -2326,6 +2435,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)); @@ -2475,6 +2588,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; @@ -2565,7 +2680,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 +2699,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 +2711,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 +2745,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)) @@ -2726,8 +2841,6 @@ 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: @@ -2735,29 +2848,31 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { case llvm::Triple::avr: case llvm::Triple::bpfel: case llvm::Triple::bpfeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: + case llvm::Triple::csky: + case llvm::Triple::hexagon: + case llvm::Triple::lanai: + case llvm::Triple::m68k: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::msp430: 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; - return false; + case llvm::Triple::systemz: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::ve: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return true; default: return false; } @@ -2800,6 +2915,11 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, D, GCCInstallation.getInstallPath() + SelectedMultilib.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 // any part of the GCC installation in @@ -2918,9 +3038,9 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, // 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")) + if (AddIncludePath(concat(SysRoot, "/usr/local/include"))) return; - if (AddIncludePath(SysRoot + "/usr/include")) + if (AddIncludePath(concat(SysRoot, "/usr/include"))) return; } @@ -2978,6 +3098,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/clang/lib/Driver/ToolChains/HIPAMD.cpp b/clang/lib/Driver/ToolChains/HIPAMD.cpp index 6d553791b394..b31077c1fd3b 100644 --- a/clang/lib/Driver/ToolChains/HIPAMD.cpp +++ b/clang/lib/Driver/ToolChains/HIPAMD.cpp @@ -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,6 +72,36 @@ 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, + /*PostClangLink=*/false); + + 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, @@ -117,17 +147,29 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, addLinkerCompressDebugSectionsOption(TC, Args, LldArgs); + for (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) + LldArgs.push_back(Arg->getValue(1)); + 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, + /*PostClangLink=*/false); + 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 +185,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,6 +199,9 @@ HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple, getProgramPaths().push_back(getDriver().Dir); // Diagnose unsupported sanitizer options only once. + 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) @@ -198,11 +246,11 @@ void HIPAMDToolChain::addClangTargetOptions( CC1Args.push_back("-fapply-global-visibility-to-externs"); } - llvm::for_each(getHIPDeviceLibs(DriverArgs), [&](auto BCFile) { + for (auto BCFile : getHIPDeviceLibs(DriverArgs)) { CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" : "-mlink-bitcode-file"); CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path)); - }); + } } llvm::opt::DerivedArgList * @@ -322,7 +370,7 @@ 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(); if (AsanRTL.empty()) { @@ -363,6 +411,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/clang/lib/Driver/ToolChains/HIPAMD.h b/clang/lib/Driver/ToolChains/HIPAMD.h index cc472a595db9..25d4a998e500 100644 --- a/clang/lib/Driver/ToolChains/HIPAMD.h +++ b/clang/lib/Driver/ToolChains/HIPAMD.h @@ -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 diff --git a/clang/lib/Driver/ToolChains/HIPUtility.cpp b/clang/lib/Driver/ToolChains/HIPUtility.cpp index 1b04a20bacbf..6f8c563c22aa 100644 --- a/clang/lib/Driver/ToolChains/HIPUtility.cpp +++ b/clang/lib/Driver/ToolChains/HIPUtility.cpp @@ -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,14 +68,20 @@ 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); const char *Bundler = Args.MakeArgString( diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp new file mode 100644 index 000000000000..584e00bb7f05 --- /dev/null +++ b/clang/lib/Driver/ToolChains/HLSL.cpp @@ -0,0 +1,183 @@ +//===--- 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/DriverDiagnostic.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/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; +} + +llvm::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 NoneType(); + + 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 NoneType(); + + unsigned long long Major = 0; + if (llvm::getAsUnsignedInteger(Parts[1], 0, Major)) + return NoneType(); + + unsigned long long Minor = 0; + if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library) + Minor = OfflineLibMinor; + else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor)) + return NoneType(); + + // 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 NoneType(); +} + +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 + +/// DirectX Toolchain +HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) {} + +llvm::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_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); + } + // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and + // shader model 6.2. + return DAL; +} diff --git a/clang/lib/Driver/ToolChains/HLSL.h b/clang/lib/Driver/ToolChains/HLSL.h new file mode 100644 index 000000000000..5573b0cc69e2 --- /dev/null +++ b/clang/lib/Driver/ToolChains/HLSL.h @@ -0,0 +1,40 @@ +//===--- 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/ToolChain.h" + +namespace clang { +namespace driver { + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY HLSLToolChain : public ToolChain { +public: + HLSLToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + 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 llvm::Optional<std::string> + parseTargetProfile(StringRef TargetProfile); +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index ba3040636604..9142dba81d54 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -72,23 +72,25 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, (Cpu.back() == 'T' || Cpu.back() == 't' ? Cpu.drop_back(1) : Cpu).str(); HasHVX = false; - // Handle -mhvx, -mhvx=, -mno-hvx. If both present, -mhvx= wins over -mhvx. - auto argOrNull = [&Args](auto FlagOn, auto FlagOff) -> Arg* { - if (Arg *A = Args.getLastArg(FlagOn, FlagOff)) { - if (A->getOption().matches(FlagOn)) - return A; - } - return nullptr; - }; - - Arg *HvxBareA = - argOrNull(options::OPT_mhexagon_hvx, options::OPT_mno_hexagon_hvx); - Arg *HvxVerA = - argOrNull(options::OPT_mhexagon_hvx_EQ, options::OPT_mno_hexagon_hvx); + // Handle -mhvx, -mhvx=, -mno-hvx. If versioned and versionless flags + // are both present, the last one wins. + Arg *HvxEnablingArg = + Args.getLastArg(options::OPT_mhexagon_hvx, options::OPT_mhexagon_hvx_EQ, + options::OPT_mno_hexagon_hvx); + if (HvxEnablingArg) { + if (HvxEnablingArg->getOption().matches(options::OPT_mno_hexagon_hvx)) + HvxEnablingArg = nullptr; + } - if (Arg *A = HvxVerA ? HvxVerA : HvxBareA) { - if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) - HvxVer = StringRef(A->getValue()).lower(); // lower produces std:string + if (HvxEnablingArg) { + // If -mhvx[=] was given, it takes precedence. + if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx, + options::OPT_mhexagon_hvx_EQ)) { + // If the version was given, set HvxVer. Otherwise HvxVer + // will remain equal to the CPU version. + if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) + HvxVer = StringRef(A->getValue()).lower(); + } HasHVX = true; Features.push_back(makeFeature(Twine("hvx") + HvxVer, true)); } else if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx)) { @@ -228,7 +230,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); @@ -549,8 +551,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 @@ -568,7 +569,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) { diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h index 899630555352..c742012444b4 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.h +++ b/clang/lib/Driver/ToolChains/Hexagon.h @@ -94,9 +94,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, diff --git a/clang/lib/Driver/ToolChains/Lanai.h b/clang/lib/Driver/ToolChains/Lanai.h index dc04b0cfe2ee..33701f7cc045 100644 --- a/clang/lib/Driver/ToolChains/Lanai.h +++ b/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/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index af74b108e04e..ceb1a982c3a4 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -97,9 +97,9 @@ std::string Linux::getMultiarchTriple(const Driver &D, 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; } @@ -108,14 +108,14 @@ std::string Linux::getMultiarchTriple(const Driver &D, 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 +124,8 @@ std::string Linux::getMultiarchTriple(const Driver &D, return "powerpc64-linux-gnu"; case llvm::Triple::ppc64le: return "powerpc64le-linux-gnu"; + case llvm::Triple::riscv64: + return "riscv64-linux-gnu"; case llvm::Triple::sparc: return "sparc-linux-gnu"; case llvm::Triple::sparcv9: @@ -221,8 +223,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 (IsMips && !SysRoot.empty()) + if (IsCSKY) + SysRoot = SysRoot + SelectedMultilib.osSuffix(); + + if ((IsMips || IsCSKY) && !SysRoot.empty()) ExtraOpts.push_back("--sysroot=" + SysRoot); // Do not use 'gnu' hash style for Mips targets because .gnu.hash @@ -265,13 +271,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 +285,37 @@ 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++. + // The deprecated -DLLVM_ENABLE_PROJECTS=libcxx configuration installs + // libc++.so in D.Dir+"/../lib/". Detect this path. + // TODO Remove once LLVM_ENABLE_PROJECTS=libcxx is unsupported. + if (StringRef(D.Dir).startswith(SysRoot) && + D.getVFS().exists(D.Dir + "/../lib/libc++.so")) 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 +361,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(); @@ -537,6 +552,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 +588,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 +609,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 +620,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); @@ -658,6 +679,15 @@ void Linux::AddHIPIncludeArgs(const ArgList &DriverArgs, RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); } +void Linux::AddHIPRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.append( + {Args.MakeArgString(StringRef("-L") + RocmInstallation.getLibPath()), + "-rpath", Args.MakeArgString(RocmInstallation.getLibPath())}); + + CmdArgs.push_back("-lamdhip64"); +} + void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (GCCInstallation.isValid()) { @@ -669,8 +699,11 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, } bool Linux::isPIEDefault(const llvm::opt::ArgList &Args) const { - return CLANG_DEFAULT_PIE_ON_LINUX || getTriple().isAndroid() || - getTriple().isMusl() || getSanitizerArgs(Args).requiresPIE(); + // TODO: Remove the special treatment for Flang once its frontend driver can + // generate position independent code. + return !getDriver().IsFlangMode() && + (CLANG_DEFAULT_PIE_ON_LINUX || getTriple().isAndroid() || + getTriple().isMusl() || getSanitizerArgs(Args).requiresPIE()); } bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const { @@ -687,7 +720,7 @@ bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const { } bool Linux::IsMathErrnoDefault() const { - if (getTriple().isAndroid()) + if (getTriple().isAndroid() || getTriple().isMusl()) return false; return Generic_ELF::IsMathErrnoDefault(); } diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index a5648d79d655..188cb1f09788 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/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; diff --git a/clang/lib/Driver/ToolChains/MSP430.cpp b/clang/lib/Driver/ToolChains/MSP430.cpp index 96994ba77fac..bc789853049a 100644 --- a/clang/lib/Driver/ToolChains/MSP430.cpp +++ b/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->getOption().getName() << HWMult; } } diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 18cef288f018..14ebe38ee191 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -40,91 +40,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 +53,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 +60,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 +81,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 +102,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 +110,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 +130,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, 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()) { @@ -655,6 +296,8 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, A.renderAsInput(Args, CmdArgs); } + addHIPRuntimeLibArgs(TC, Args, CmdArgs); + TC.addProfileRTLibs(Args, CmdArgs); std::vector<const char *> Environment; @@ -695,7 +338,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, // 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(); @@ -730,13 +373,12 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) { llvm::StringRef EnvVar(Cursor); if (EnvVar.startswith_insensitive("path=")) { - using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType; 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 +411,29 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); + 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(), VCToolChainPath, + VSLayout) || + llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout); } Tool *MSVCToolChain::buildLinker() const { @@ -802,8 +459,8 @@ bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const { // 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; + return getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm || + getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64; } bool MSVCToolChain::isPICDefault() const { @@ -830,360 +487,60 @@ void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); } +void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") + + RocmInstallation.getLibPath()), + "amdhip64.lib"}); +} + void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { CudaInstallation.print(OS); RocmInstallation.print(OS); } -// 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()); +MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type, + llvm::StringRef SubdirParent) const { + return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(), + SubdirParent); } -#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; -} -#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 >= 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,10 +549,12 @@ 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()); + StringRef ArchName = llvm::archToWindowsSDKArch(getArch()); if (ArchName.empty()) return false; @@ -1313,15 +672,17 @@ 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)) { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, "Include", UCRTVersion, "ucrt"); } @@ -1331,8 +692,9 @@ 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 >= 8) { // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. // Anyway, llvm::sys::path::append is able to manage it. @@ -1348,7 +710,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 +751,13 @@ 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.14 is default, aka 2017, 15.7 - MSVT = VersionTuple(19, 14); + // -fms-compatibility-version=19.20 is default, aka 2019, 16.x + MSVT = VersionTuple(19, 20); } return MSVT; } @@ -1405,8 +768,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 +982,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/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index c842773996ed..f09256ba124e 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -15,6 +15,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/WindowsDriver/MSVCPaths.h" namespace clang { namespace driver { @@ -73,29 +74,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 +96,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,8 +132,9 @@ protected: Tool *buildLinker() const override; Tool *buildAssembler() const override; private: + llvm::Optional<llvm::StringRef> WinSdkDir, WinSdkVersion, WinSysRoot; std::string VCToolChainPath; - ToolsetLayout VSLayout = ToolsetLayout::OlderVS; + llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS; CudaInstallationDetector CudaInstallation; RocmInstallationDetector RocmInstallation; }; diff --git a/clang/lib/Driver/ToolChains/MSVCSetupApi.h b/clang/lib/Driver/ToolChains/MSVCSetupApi.h deleted file mode 100644 index 28e6e3e08e37..000000000000 --- a/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/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 0501f9737404..c4b4f8e9b89b 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -86,7 +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")) + if (StringRef(Lib).startswith("msvcr") || + StringRef(Lib).startswith("ucrt") || + StringRef(Lib).startswith("crtdll")) return; CmdArgs.push_back("-lmsvcrt"); } @@ -216,6 +218,11 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + if (C.getDriver().IsFlangMode()) { + addFortranRuntimeLibraryPath(TC, Args, CmdArgs); + addFortranRuntimeLibs(TC, CmdArgs); + } + // TODO: Add profile stuff here if (TC.ShouldLinkCXXStdlib(Args)) { @@ -476,8 +483,8 @@ bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const { if (ExceptionArg && ExceptionArg->getOption().matches(options::OPT_fseh_exceptions)) return true; - return getArch() == llvm::Triple::x86_64 || - getArch() == llvm::Triple::aarch64; + return getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm || + getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64; } bool toolchains::MinGW::isPICDefault() const { @@ -493,7 +500,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; } diff --git a/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h index c3de19b97724..c9553b4f4652 100644 --- a/clang/lib/Driver/ToolChains/MinGW.h +++ b/clang/lib/Driver/ToolChains/MinGW.h @@ -90,6 +90,8 @@ public: void printVerboseInfo(raw_ostream &OS) const override; + unsigned GetDefaultDwarfVersion() const override { return 4; } + protected: Tool *getTool(Action::ActionClass AC) const override; Tool *buildLinker() const override; diff --git a/clang/lib/Driver/ToolChains/Minix.cpp b/clang/lib/Driver/ToolChains/Minix.cpp index 5bceb9aba3e9..4b8670a79012 100644 --- a/clang/lib/Driver/ToolChains/Minix.cpp +++ b/clang/lib/Driver/ToolChains/Minix.cpp @@ -56,7 +56,8 @@ void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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)) { CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back( @@ -71,7 +72,8 @@ void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().addProfileRTLibs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { if (D.CCCIsCXX()) { if (getToolChain().ShouldLinkCXXStdlib(Args)) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); @@ -79,7 +81,8 @@ void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - 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_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp index 37b1fc5215ff..d1eda14a51f0 100644 --- a/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -236,7 +236,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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(ToolChain.GetFilePath("crt0.o"))); @@ -294,7 +295,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + 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); @@ -330,7 +332,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - 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) || Args.hasArg(options::OPT_pie)) CmdArgs.push_back( Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp index 96abac57764f..54cf3cc89caf 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/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; @@ -113,6 +114,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const toolchains::OpenBSD &ToolChain = static_cast<const toolchains::OpenBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -123,9 +125,12 @@ 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)) { @@ -153,6 +158,9 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-nopie"); + if (Arch == llvm::Triple::riscv64) + CmdArgs.push_back("-X"); + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -160,7 +168,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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)) { const char *crt0 = nullptr; const char *crtbegin = nullptr; if (!Args.hasArg(options::OPT_shared)) { @@ -191,7 +200,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + 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); @@ -234,7 +244,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lcompiler_rt"); } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { const char *crtend = nullptr; if (!Args.hasArg(options::OPT_shared)) crtend = "crtend.o"; @@ -324,12 +335,21 @@ void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, 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.str()); + } + 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.str()); + return ToolChain::getCompilerRT(Args, Component, Type); } Tool *OpenBSD::buildAssembler() const { @@ -339,3 +359,12 @@ Tool *OpenBSD::buildAssembler() const { 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; + } +} diff --git a/clang/lib/Driver/ToolChains/OpenBSD.h b/clang/lib/Driver/ToolChains/OpenBSD.h index 95c10cc62316..2d4c4e34520b 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/clang/lib/Driver/ToolChains/OpenBSD.h @@ -82,6 +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; + LangOptions::StackProtectorMode GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return LangOptions::SSPStrong; diff --git a/clang/lib/Driver/ToolChains/PPCLinux.cpp b/clang/lib/Driver/ToolChains/PPCLinux.cpp index e480d8bd8703..2fea262fd109 100644 --- a/clang/lib/Driver/ToolChains/PPCLinux.cpp +++ b/clang/lib/Driver/ToolChains/PPCLinux.cpp @@ -76,9 +76,11 @@ bool PPCLinuxToolChain::SupportIEEEFloat128( if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx)) return true; + CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args); bool HasUnsupportedCXXLib = - ToolChain::GetCXXStdlibType(Args) == CST_Libcxx && - GCCInstallation.getVersion().isOlderThan(12, 1, 0); + StdLib == CST_Libcxx || + (StdLib == CST_Libstdcxx && + GCCInstallation.getVersion().isOlderThan(12, 1, 0)); return GlibcSupportsFloat128(Linux::getDynamicLinker(Args)) && !(D.CCCIsCXX() && HasUnsupportedCXXLib); diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index bcf9147833dd..35a83d79abfd 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "PS4CPU.h" -#include "FreeBSD.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -23,8 +22,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 +50,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 +73,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 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(arg("SceDbgUBSanitizer_stub_weak")); + if (SanArgs.needsAsanRt()) + CmdArgs.push_back(arg("SceDbgAddressSanitizer_stub_weak")); } -void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); +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("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a"); + CmdArgs.push_back(arg("SceUBSanitizer_nosubmission_stub_weak")); if (SanArgs.needsAsanRt()) - CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a"); + CmdArgs.push_back(arg("SceAddressSanitizer_nosubmission_stub_weak")); + if (SanArgs.needsTsanRt()) + CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_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 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,7 +143,7 @@ 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"); if (Output.isFilename()) { CmdArgs.push_back("-o"); @@ -125,8 +152,8 @@ void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, assert(Output.isNothing() && "Invalid output."); } - if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - AddPS4SanitizerArgs(ToolChain, Args, CmdArgs); + 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); @@ -138,7 +165,7 @@ void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, 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"); @@ -146,89 +173,92 @@ void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, 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"; + D.Diag(clang::diag::err_drv_unsupported_opt_for_target) + << "-static" << Platform; - // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR + // Determine where to find the PS4/PS5 libraries. We use the EnvVar // 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")) { + SmallString<512> SDKDir; + if (const char *EnvValue = getenv(EnvVar)) { if (!llvm::sys::fs::exists(EnvValue)) - getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; - PS4SDKDir = EnvValue; + D.Diag(clang::diag::warn_drv_ps_sdk_dir) << EnvVar << EnvValue; + SDKDir = EnvValue; } else { - PS4SDKDir = getDriver().Dir; - llvm::sys::path::append(PS4SDKDir, "/../../"); + SDKDir = D.Dir; + llvm::sys::path::append(SDKDir, "/../../"); } - // 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 + // By default, the driver won't report a warning if it can't find the + // SDK include or lib directories. This behavior could be changed if // -Weverything or -Winvalid-or-nonexistent-directory options are passed. // If -isysroot was passed, use that as the SDK base path. std::string PrefixDir; 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; + D.Diag(clang::diag::warn_missing_sysroot) << PrefixDir; } else - PrefixDir = std::string(PS4SDKDir.str()); + PrefixDir = std::string(SDKDir.str()); - SmallString<512> PS4SDKIncludeDir(PrefixDir); - llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); + SmallString<512> SDKIncludeDir(PrefixDir); + 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; } - SmallString<512> PS4SDKLibDir(PS4SDKDir); - llvm::sys::path::append(PS4SDKLibDir, "target/lib"); + SmallString<512> SDKLibDir(SDKDir); + 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; return; } - getFilePaths().push_back(std::string(PS4SDKLibDir.str())); + getFilePaths().push_back(std::string(SDKLibDir.str())); } Tool *toolchains::PS4CPU::buildAssembler() const { - return new tools::PS4cpu::Assemble(*this); + return new tools::PScpu::Assembler(*this); } -Tool *toolchains::PS4CPU::buildLinker() const { - return new tools::PS4cpu::Link(*this); +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::isPICDefault() const { return true; } - -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 +267,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) @@ -281,3 +317,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/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h index 4bedabaf267c..954e7d8d8d68 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/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,69 @@ 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 : 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 : 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); // 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, @@ -105,11 +100,71 @@ public: 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; }; +// 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 } // end namespace driver } // end namespace clang diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index 714325a2db39..a048765bc6d3 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -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"); @@ -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(); diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.h b/clang/lib/Driver/ToolChains/RISCVToolchain.h index 62099bee0404..46b94bdb54e0 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.h +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -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; diff --git a/clang/lib/Driver/ToolChains/ROCm.h b/clang/lib/Driver/ToolChains/ROCm.h index bb482be68260..33baaa887043 100644 --- a/clang/lib/Driver/ToolChains/ROCm.h +++ b/clang/lib/Driver/ToolChains/ROCm.h @@ -22,6 +22,26 @@ 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 { @@ -107,6 +127,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 +166,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; } @@ -214,6 +243,13 @@ 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); diff --git a/clang/lib/Driver/ToolChains/SPIRV.h b/clang/lib/Driver/ToolChains/SPIRV.h index a16ae3ca51fa..bb2904f76128 100644 --- a/clang/lib/Driver/ToolChains/SPIRV.h +++ b/clang/lib/Driver/ToolChains/SPIRV.h @@ -64,8 +64,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/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index 4d1af094f481..c75375ac95f7 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -14,6 +14,8 @@ #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/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -82,7 +84,8 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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"))); @@ -122,7 +125,8 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { if (getToolChain().ShouldLinkCXXStdlib(Args)) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_fstack_protector) || @@ -132,21 +136,40 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lssp_nonshared"); CmdArgs.push_back("-lssp"); } + // 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)); + CmdArgs.push_back("-latomic"); + CmdArgs.push_back(getAsNeededOption(getToolChain(), false)); + } CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("-lc"); if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("-lm"); } - if (NeedsSanitizerDeps) + if (NeedsSanitizerDeps) { linkSanitizerRuntimeDeps(getToolChain(), 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. + const SanitizerArgs &SA = getToolChain().getSanitizerArgs(Args); + if (getToolChain().getTriple().getArch() == llvm::Triple::x86_64 && + (SA.needsAsanRt() || SA.needsStatsRt() || + (SA.needsUbsanRt() && !SA.requiresMinimalRuntime()))) + CmdArgs.push_back("-zrelax=transtls"); + } } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); } - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); getToolChain().addProfileRTLibs(Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/VEToolchain.h b/clang/lib/Driver/ToolChains/VEToolchain.h index 964b0d0dd8d4..8b9ccaa7fada 100644 --- a/clang/lib/Driver/ToolChains/VEToolchain.h +++ b/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/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 3614272a5f74..c5e4d569793c 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/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; @@ -371,7 +373,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 +423,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) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addLibCxxIncludePaths(DriverArgs, CC1Args); + break; + case ToolChain::CST_Libstdcxx: + addLibStdCXXIncludePaths(DriverArgs, CC1Args); + break; } } @@ -440,7 +447,8 @@ void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: - llvm_unreachable("invalid stdlib name"); + CmdArgs.push_back("-lstdc++"); + break; } } @@ -455,3 +463,77 @@ SanitizerMask WebAssembly::getSupportedSanitizers() const { 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/clang/lib/Driver/ToolChains/WebAssembly.h b/clang/lib/Driver/ToolChains/WebAssembly.h index b4c3082a089a..5b9b8a0fe4e6 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/clang/lib/Driver/ToolChains/WebAssembly.h @@ -70,11 +70,20 @@ private: const char *getDefaultLinker() const override { return "wasm-ld"; } + 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/clang/lib/Driver/ToolChains/ZOS.h b/clang/lib/Driver/ToolChains/ZOS.h index 50bff0993561..53138306fd41 100644 --- a/clang/lib/Driver/ToolChains/ZOS.h +++ b/clang/lib/Driver/ToolChains/ZOS.h @@ -30,6 +30,8 @@ public: bool IsIntegratedAssemblerDefault() const override { return true; } + unsigned GetDefaultDwarfVersion() const override { return 4; } + void addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const override; diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 8f6adc6c2ad1..66da6fe97059 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -65,9 +65,16 @@ 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; @@ -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: @@ -210,6 +235,10 @@ 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_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: @@ -257,16 +286,6 @@ 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::isSrcFile(ID Id) { return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID; } @@ -323,6 +342,7 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { .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) @@ -332,6 +352,7 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { .Case("c++m", TY_CXXModule) .Case("cppm", TY_CXXModule) .Case("cxxm", TY_CXXModule) + .Case("hlsl", TY_HLSL) .Default(TY_INVALID); } |
