diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Driver/ToolChains')
122 files changed, 15548 insertions, 8619 deletions
diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp index 3000b8416adf..e6126ff62db3 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp @@ -12,7 +12,9 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Path.h" using AIX = clang::driver::toolchains::AIX; @@ -28,6 +30,7 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit(); @@ -36,6 +39,11 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, if (!IsArch32Bit && !IsArch64Bit) llvm_unreachable("Unsupported bit width value."); + if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << D.getTargetTriple(); + } + // Specify the mode in which the as(1) command operates. if (IsArch32Bit) { CmdArgs.push_back("-a32"); @@ -74,6 +82,29 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, Exec, CmdArgs, Inputs, Output)); } +// Determine whether there are any linker options that supply an export list +// (or equivalent information about what to export) being sent to the linker. +static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) { + for (size_t i = 0, Size = CmdArgs.size(); i < Size; ++i) { + llvm::StringRef ArgString(CmdArgs[i]); + + if (ArgString.starts_with("-bE:") || ArgString.starts_with("-bexport:") || + ArgString == "-bexpall" || ArgString == "-bexpfull") + return true; + + // If we split -b option, check the next opt. + if (ArgString == "-b" && i + 1 < Size) { + ++i; + llvm::StringRef ArgNextString(CmdArgs[i]); + if (ArgNextString.starts_with("E:") || + ArgNextString.starts_with("export:") || ArgNextString == "expall" || + ArgNextString == "expfull") + return true; + } + } + return false; +} + void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, @@ -88,6 +119,11 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!(IsArch32Bit || IsArch64Bit)) llvm_unreachable("Unsupported bit width value."); + if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << D.getTargetTriple(); + } + // Force static linking when "-static" is present. if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-bnso"); @@ -98,6 +134,54 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-bnoentry"); } + if (Args.hasFlag(options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr, + false)) { + if (Args.hasArg(options::OPT_shared)) + D.Diag(diag::err_roptr_cannot_build_shared); + + // The `-mxcoff-roptr` option places constants in RO sections as much as + // possible. Then `-bforceimprw` changes such sections to RW if they contain + // imported symbols that need to be resolved. + CmdArgs.push_back("-bforceimprw"); + } + + // PGO instrumentation generates symbols belonging to special sections, and + // the linker needs to place all symbols in a particular section together in + // memory; the AIX linker does that under an option. + if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + false) || + Args.hasFlag(options::OPT_fprofile_generate, + options::OPT_fno_profile_generate, false) || + Args.hasFlag(options::OPT_fprofile_generate_EQ, + options::OPT_fno_profile_generate, false) || + Args.hasFlag(options::OPT_fprofile_instr_generate, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fcs_profile_generate, + options::OPT_fno_profile_generate, false) || + 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:ss"); + + if (Arg *A = + Args.getLastArg(clang::driver::options::OPT_mxcoff_build_id_EQ)) { + StringRef BuildId = A->getValue(); + if (BuildId[0] != '0' || BuildId[1] != 'x' || + BuildId.find_if_not(llvm::isHexDigit, 2) != StringRef::npos) + ToolChain.getDriver().Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << BuildId; + else { + std::string LinkerFlag = "-bdbg:ldrinfo:xcoff_binary_id:0x"; + if (BuildId.size() % 2) // Prepend a 0 if odd number of digits. + LinkerFlag += "0"; + LinkerFlag += BuildId.drop_front(2).lower(); + CmdArgs.push_back(Args.MakeArgString(LinkerFlag)); + } + } + // Specify linker output file. assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { @@ -118,19 +202,19 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-bpD:0x110000000"); } - auto getCrt0Basename = [&Args, IsArch32Bit] { - // Enable gprofiling when "-pg" is specified. - if (Args.hasArg(options::OPT_pg)) - return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o"; - // Enable profiling when "-p" is specified. - else if (Args.hasArg(options::OPT_p)) - return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o"; - else + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_shared, options::OPT_r)) { + auto getCrt0Basename = [&Args, IsArch32Bit] { + if (Arg *A = Args.getLastArgNoClaim(options::OPT_p, options::OPT_pg)) { + // Enable gprofiling when "-pg" is specified. + if (A->getOption().matches(options::OPT_pg)) + return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o"; + // Enable profiling when "-p" is specified. + return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o"; + } return IsArch32Bit ? "crt0.o" : "crt0_64.o"; - }; + }; - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, - options::OPT_shared)) { CmdArgs.push_back( Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename()))); @@ -147,27 +231,109 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Specify linker input file(s). AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - // Add directory to library search path. - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - ToolChain.addProfileRTLibs(Args, CmdArgs); - - if (getToolChain().ShouldLinkCXXStdlib(Args)) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - AddRunTimeLibs(ToolChain, D, CmdArgs, Args); - - // Support POSIX threads if "-pthreads" or "-pthread" is present. - if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread)) - CmdArgs.push_back("-lpthreads"); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, + D.getLTOMode() == LTOK_Thin); + } - if (D.CCCIsCXX()) - CmdArgs.push_back("-lm"); + if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) { + + const char *CreateExportListExec = Args.MakeArgString( + path::parent_path(ToolChain.getDriver().ClangExecutable) + + "/llvm-nm"); + ArgStringList CreateExportCmdArgs; + + std::string CreateExportListPath = + C.getDriver().GetTemporaryPath("CreateExportList", "exp"); + const char *ExportList = + C.addTempFile(C.getArgs().MakeArgString(CreateExportListPath)); + + for (const auto &II : Inputs) + if (II.isFilename()) + CreateExportCmdArgs.push_back(II.getFilename()); + + CreateExportCmdArgs.push_back("--export-symbols"); + CreateExportCmdArgs.push_back("-X"); + if (IsArch32Bit) { + CreateExportCmdArgs.push_back("32"); + } else { + // Must be 64-bit, otherwise asserted already. + CreateExportCmdArgs.push_back("64"); + } + + auto ExpCommand = std::make_unique<Command>( + JA, *this, ResponseFileSupport::None(), CreateExportListExec, + CreateExportCmdArgs, Inputs, Output); + ExpCommand->setRedirectFiles( + {std::nullopt, std::string(ExportList), std::nullopt}); + C.addCommand(std::move(ExpCommand)); + CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-bE:") + ExportList)); + } - CmdArgs.push_back("-lc"); + // Add directory to library search path. + Args.AddAllArgs(CmdArgs, options::OPT_L); + if (!Args.hasArg(options::OPT_r)) { + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + ToolChain.addProfileRTLibs(Args, CmdArgs); + + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + + // Add OpenMP runtime if -fopenmp is specified. + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) { + switch (ToolChain.getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: + CmdArgs.push_back("-lomp"); + break; + case Driver::OMPRT_IOMP5: + CmdArgs.push_back("-liomp5"); + break; + case Driver::OMPRT_GOMP: + CmdArgs.push_back("-lgomp"); + break; + case Driver::OMPRT_Unknown: + // Already diagnosed. + break; + } + } + + // Support POSIX threads if "-pthreads" or "-pthread" is present. + if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread)) + CmdArgs.push_back("-lpthreads"); + + if (D.CCCIsCXX()) + CmdArgs.push_back("-lm"); + + CmdArgs.push_back("-lc"); + + if (Args.hasArgNoClaim(options::OPT_p, options::OPT_pg)) { + CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) + + "/lib/profiled")); + CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) + + "/usr/lib/profiled")); + } + } } + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + CmdArgs.push_back("-lm"); + CmdArgs.push_back("-lpthread"); + } const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, Inputs, Output)); @@ -176,6 +342,10 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, /// AIX - AIX tool chain which can call as(1) and ld(1) directly. AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); + ParseInlineAsmUsingAsmParser = Args.hasFlag( options::OPT_fintegrated_as, options::OPT_fno_integrated_as, true); getLibraryPaths().push_back(getDriver().SysRoot + "/usr/lib"); @@ -201,11 +371,13 @@ void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs, llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); const Driver &D = getDriver(); - // Add the Clang builtin headers (<resource>/include). if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { SmallString<128> P(D.ResourceDir); - path::append(P, "/include"); - addSystemInclude(DriverArgs, CC1Args, P.str()); + // Add the PowerPC intrinsic headers (<resource>/include/ppc_wrappers) + path::append(P, "include", "ppc_wrappers"); + addSystemInclude(DriverArgs, CC1Args, P); + // Add the Clang builtin headers (<resource>/include) + addSystemInclude(DriverArgs, CC1Args, path::parent_path(P.str())); } // Return if -nostdlibinc is specified as a driver option. @@ -218,20 +390,82 @@ void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, UP.str()); } +void AIX::AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + + if (DriverArgs.hasArg(options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdincxx) || + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libstdcxx: + llvm::report_fatal_error( + "picking up libstdc++ headers is unimplemented on AIX"); + case ToolChain::CST_Libcxx: { + llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); + SmallString<128> PathCPP(Sysroot); + llvm::sys::path::append(PathCPP, "opt/IBM/openxlCSDK", "include", "c++", + "v1"); + addSystemInclude(DriverArgs, CC1Args, PathCPP.str()); + // Required in order to suppress conflicting C++ overloads in the system + // libc headers that were used by XL C++. + CC1Args.push_back("-D__LIBC_NO_CPP_MATH_OVERLOADS__"); + return; + } + } + + llvm_unreachable("Unexpected C++ library type; only libc++ is supported."); +} + void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libstdcxx: + llvm::report_fatal_error("linking libstdc++ unimplemented on AIX"); case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); return; - case ToolChain::CST_Libstdcxx: - llvm::report_fatal_error("linking libstdc++ unimplemented on AIX"); } llvm_unreachable("Unexpected C++ library type; only libc++ is supported."); } +void AIX::addClangTargetOptions( + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + Args.AddLastArg(CC1Args, options::OPT_mignore_xcoff_visibility); + Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ); + Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr); + + if (Args.hasFlag(options::OPT_fxl_pragma_pack, + options::OPT_fno_xl_pragma_pack, true)) + CC1Args.push_back("-fxl-pragma-pack"); +} + +void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + if (needsProfileRT(Args)) { + // Add linker option -u__llvm_profile_runtime to cause runtime + // initialization to occur. + CmdArgs.push_back(Args.MakeArgString( + Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); + + if (const auto *A = + Args.getLastArgNoClaim(options::OPT_fprofile_update_EQ)) { + StringRef Val = A->getValue(); + if (Val == "atomic" || Val == "prefer-atomic") + CmdArgs.push_back("-latomic"); + } + } + + ToolChain::addProfileRTLibs(Args, CmdArgs); +} + ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const { return ToolChain::CST_Libcxx; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h index d1ec6d10fb3a..755d87e07ec5 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.h @@ -16,10 +16,10 @@ namespace clang { namespace driver { namespace tools { -/// aix -- Directly call system default assembler and linker. +/// Directly call system default assembler and linker. namespace aix { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("aix::Assembler", "assembler", TC) {} @@ -31,7 +31,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("aix::Linker", "linker", TC) {} @@ -63,16 +63,30 @@ public: return ParseInlineAsmUsingAsmParser; } bool isPICDefault() const override { return true; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return true; } + bool HasNativeLLVMSupport() const override { return true; } void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + void addClangTargetOptions( + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const override; + + void addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + CXXStdlibType GetDefaultCXXStdlibType() const override; RuntimeLibType GetDefaultRuntimeLibType() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp index 4a7413112b55..b3c9d5908654 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -9,20 +9,22 @@ #include "AMDGPU.h" #include "CommonArgs.h" #include "clang/Basic/TargetID.h" +#include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Error.h" -#include "llvm/Support/FileUtilities.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Host.h" +#include <optional> #include <system_error> -#define AMDGPU_ARCH_PROGRAM_NAME "amdgpu-arch" - using namespace clang::driver; using namespace clang::driver::tools; using namespace clang::driver::toolchains; @@ -47,7 +49,7 @@ RocmInstallationDetector::findSPACKPackage(const Candidate &Cand, FileEnd; File != FileEnd && !EC; File.increment(EC)) { llvm::StringRef FileName = llvm::sys::path::filename(File->path()); - if (FileName.startswith(Prefix)) { + if (FileName.starts_with(Prefix)) { SubDirs.push_back(FileName); if (SubDirs.size() > 1) break; @@ -82,15 +84,16 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { !EC && LI != LE; LI = LI.increment(EC)) { StringRef FilePath = LI->path(); StringRef FileName = llvm::sys::path::filename(FilePath); - if (!FileName.endswith(Suffix)) + if (!FileName.ends_with(Suffix)) continue; StringRef BaseName; - if (FileName.endswith(Suffix2)) + if (FileName.ends_with(Suffix2)) BaseName = FileName.drop_back(Suffix2.size()); - else if (FileName.endswith(Suffix)) + else if (FileName.ends_with(Suffix)) BaseName = FileName.drop_back(Suffix.size()); + const StringRef ABIVersionPrefix = "oclc_abi_version_"; if (BaseName == "ocml") { OCML = FilePath; } else if (BaseName == "ockl") { @@ -121,11 +124,17 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { WavefrontSize64.On = FilePath; } else if (BaseName == "oclc_wavefrontsize64_off") { WavefrontSize64.Off = FilePath; + } else if (BaseName.starts_with(ABIVersionPrefix)) { + unsigned ABIVersionNumber; + if (BaseName.drop_front(ABIVersionPrefix.size()) + .getAsInteger(/*Redex=*/0, ABIVersionNumber)) + continue; + ABIVersionMap[ABIVersionNumber] = FilePath.str(); } else { // Process all bitcode filenames that look like // ocl_isa_version_XXX.amdgcn.bc const StringRef DeviceLibPrefix = "oclc_isa_version_"; - if (!BaseName.startswith(DeviceLibPrefix)) + if (!BaseName.starts_with(DeviceLibPrefix)) continue; StringRef IsaVersionNumber = @@ -190,9 +199,10 @@ RocmInstallationDetector::getInstallationPathCandidates() { ROCmSearchDirs.emplace_back(RocmPathArg.str()); DoPrintROCmSearchDirs(); return ROCmSearchDirs; - } else if (const char *RocmPathEnv = ::getenv("ROCM_PATH")) { - if (!StringRef(RocmPathEnv).empty()) { - ROCmSearchDirs.emplace_back(RocmPathEnv); + } else if (std::optional<std::string> RocmPathEnv = + llvm::sys::Process::GetEnv("ROCM_PATH")) { + if (!RocmPathEnv->empty()) { + ROCmSearchDirs.emplace_back(std::move(*RocmPathEnv)); DoPrintROCmSearchDirs(); return ROCmSearchDirs; } @@ -220,7 +230,7 @@ RocmInstallationDetector::getInstallationPathCandidates() { // <rocm_root>/llvm-amdgpu-<rocm_release_string>-<hash>/bin directory. // We only consider the parent directory of llvm-amdgpu package as ROCm // installation candidate for SPACK. - if (ParentName.startswith("llvm-amdgpu-")) { + if (ParentName.starts_with("llvm-amdgpu-")) { auto SPACKPostfix = ParentName.drop_front(strlen("llvm-amdgpu-")).split('-'); auto SPACKReleaseStr = SPACKPostfix.first; @@ -233,7 +243,7 @@ RocmInstallationDetector::getInstallationPathCandidates() { // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin // Some versions of the aomp package install to /opt/rocm/aomp/bin - if (ParentName == "llvm" || ParentName.startswith("aomp")) + if (ParentName == "llvm" || ParentName.starts_with("aomp")) ParentDir = llvm::sys::path::parent_path(ParentDir); return Candidate(ParentDir.str(), /*StrictChecking=*/true); @@ -282,7 +292,7 @@ RocmInstallationDetector::getInstallationPathCandidates() { FileEnd; File != FileEnd && !EC; File.increment(EC)) { llvm::StringRef FileName = llvm::sys::path::filename(File->path()); - if (!FileName.startswith("rocm-")) + if (!FileName.starts_with("rocm-")) continue; if (LatestROCm.empty()) { LatestROCm = FileName.str(); @@ -299,6 +309,11 @@ RocmInstallationDetector::getInstallationPathCandidates() { ROCmSearchDirs.emplace_back(D.SysRoot + "/opt/" + LatestROCm, /*StrictChecking=*/true); + ROCmSearchDirs.emplace_back(D.SysRoot + "/usr/local", + /*StrictChecking=*/true); + ROCmSearchDirs.emplace_back(D.SysRoot + "/usr", + /*StrictChecking=*/true); + DoPrintROCmSearchDirs(); return ROCmSearchDirs; } @@ -314,6 +329,20 @@ RocmInstallationDetector::RocmInstallationDetector( RocmDeviceLibPathArg = Args.getAllArgValues(clang::driver::options::OPT_rocm_device_lib_path_EQ); HIPPathArg = Args.getLastArgValue(clang::driver::options::OPT_hip_path_EQ); + HIPStdParPathArg = + Args.getLastArgValue(clang::driver::options::OPT_hipstdpar_path_EQ); + HasHIPStdParLibrary = + !HIPStdParPathArg.empty() && D.getVFS().exists(HIPStdParPathArg + + "/hipstdpar_lib.hpp"); + HIPRocThrustPathArg = + Args.getLastArgValue(clang::driver::options::OPT_hipstdpar_thrust_path_EQ); + HasRocThrustLibrary = !HIPRocThrustPathArg.empty() && + D.getVFS().exists(HIPRocThrustPathArg + "/thrust"); + HIPRocPrimPathArg = + Args.getLastArgValue(clang::driver::options::OPT_hipstdpar_prim_path_EQ); + HasRocPrimLibrary = !HIPRocPrimPathArg.empty() && + D.getVFS().exists(HIPRocPrimPathArg + "/rocprim"); + if (auto *A = Args.getLastArg(clang::driver::options::OPT_hip_version_EQ)) { HIPVersionArg = A->getValue(); unsigned Major = ~0U; @@ -357,8 +386,9 @@ void RocmInstallationDetector::detectDeviceLibrary() { if (!RocmDeviceLibPathArg.empty()) LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1]; - else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH")) - LibDevicePath = LibPathEnv; + else if (std::optional<std::string> LibPathEnv = + llvm::sys::Process::GetEnv("HIP_DEVICE_LIB_PATH")) + LibDevicePath = std::move(*LibPathEnv); auto &FS = D.getVFS(); if (!LibDevicePath.empty()) { @@ -373,69 +403,57 @@ void RocmInstallationDetector::detectDeviceLibrary() { return; } - // The install path situation in old versions of ROCm is a real mess, and - // use a different install layout. Multiple copies of the device libraries - // exist for each frontend project, and differ depending on which build - // system produced the packages. Standalone OpenCL builds also have a - // different directory structure from the ROCm OpenCL package. - auto &ROCmDirs = getInstallationPathCandidates(); - for (const auto &Candidate : ROCmDirs) { - auto CandidatePath = Candidate.Path; - - // Check device library exists at the given path. - auto CheckDeviceLib = [&](StringRef Path) { - bool CheckLibDevice = (!NoBuiltinLibs || Candidate.StrictChecking); - if (CheckLibDevice && !FS.exists(Path)) - return false; - - scanLibDevicePath(Path); + // Check device library exists at the given path. + auto CheckDeviceLib = [&](StringRef Path, bool StrictChecking) { + bool CheckLibDevice = (!NoBuiltinLibs || StrictChecking); + if (CheckLibDevice && !FS.exists(Path)) + return false; - if (!NoBuiltinLibs) { - // Check that the required non-target libraries are all available. - if (!allGenericLibsValid()) - return false; + scanLibDevicePath(Path); - // Check that we have found at least one libdevice that we can link in - // if -nobuiltinlib hasn't been specified. - if (LibDeviceMap.empty()) - return false; - } - return true; - }; + if (!NoBuiltinLibs) { + // Check that the required non-target libraries are all available. + if (!allGenericLibsValid()) + return false; - // The possible structures are: - // - ${ROCM_ROOT}/amdgcn/bitcode/* - // - ${ROCM_ROOT}/lib/* - // - ${ROCM_ROOT}/lib/bitcode/* - // so try to detect these layouts. - static constexpr std::array<const char *, 2> SubDirsList[] = { - {"amdgcn", "bitcode"}, - {"lib", ""}, - {"lib", "bitcode"}, - }; + // Check that we have found at least one libdevice that we can link in + // if -nobuiltinlib hasn't been specified. + if (LibDeviceMap.empty()) + return false; + } + return true; + }; - // Make a path by appending sub-directories to InstallPath. - auto MakePath = [&](const llvm::ArrayRef<const char *> &SubDirs) { - auto Path = CandidatePath; - for (auto SubDir : SubDirs) - llvm::sys::path::append(Path, SubDir); - return Path; - }; + // Find device libraries in <LLVM_DIR>/lib/clang/<ver>/lib/amdgcn/bitcode + LibDevicePath = D.ResourceDir; + llvm::sys::path::append(LibDevicePath, CLANG_INSTALL_LIBDIR_BASENAME, + "amdgcn", "bitcode"); + HasDeviceLibrary = CheckDeviceLib(LibDevicePath, true); + if (HasDeviceLibrary) + return; - for (auto SubDirs : SubDirsList) { - LibDevicePath = MakePath(SubDirs); - HasDeviceLibrary = CheckDeviceLib(LibDevicePath); - if (HasDeviceLibrary) - return; - } + // Find device libraries in a legacy ROCm directory structure + // ${ROCM_ROOT}/amdgcn/bitcode/* + auto &ROCmDirs = getInstallationPathCandidates(); + for (const auto &Candidate : ROCmDirs) { + LibDevicePath = Candidate.Path; + llvm::sys::path::append(LibDevicePath, "amdgcn", "bitcode"); + HasDeviceLibrary = CheckDeviceLib(LibDevicePath, Candidate.StrictChecking); + if (HasDeviceLibrary) + return; } } void RocmInstallationDetector::detectHIPRuntime() { SmallVector<Candidate, 4> HIPSearchDirs; if (!HIPPathArg.empty()) - HIPSearchDirs.emplace_back(HIPPathArg.str(), /*StrictChecking=*/true); - else + HIPSearchDirs.emplace_back(HIPPathArg.str()); + else if (std::optional<std::string> HIPPathEnv = + llvm::sys::Process::GetEnv("HIP_PATH")) { + if (!HIPPathEnv->empty()) + HIPSearchDirs.emplace_back(std::move(*HIPPathEnv)); + } + if (HIPSearchDirs.empty()) HIPSearchDirs.append(getInstallationPathCandidates()); auto &FS = D.getVFS(); @@ -454,18 +472,41 @@ void RocmInstallationDetector::detectHIPRuntime() { llvm::sys::path::append(IncludePath, "include"); LibPath = InstallPath; llvm::sys::path::append(LibPath, "lib"); - - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = - FS.getBufferForFile(BinPath + "/.hipVersion"); - if (!VersionFile && Candidate.StrictChecking) - continue; - - if (HIPVersionArg.empty() && VersionFile) - if (parseHIPVersionFile((*VersionFile)->getBuffer())) + SharePath = InstallPath; + llvm::sys::path::append(SharePath, "share"); + + // Get parent of InstallPath and append "share" + SmallString<0> ParentSharePath = llvm::sys::path::parent_path(InstallPath); + llvm::sys::path::append(ParentSharePath, "share"); + + auto Append = [](SmallString<0> &path, const Twine &a, const Twine &b = "", + const Twine &c = "", const Twine &d = "") { + SmallString<0> newpath = path; + llvm::sys::path::append(newpath, a, b, c, d); + return newpath; + }; + // If HIP version file can be found and parsed, use HIP version from there. + for (const auto &VersionFilePath : + {Append(SharePath, "hip", "version"), + Append(ParentSharePath, "hip", "version"), + Append(BinPath, ".hipVersion")}) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = + FS.getBufferForFile(VersionFilePath); + if (!VersionFile) continue; + if (HIPVersionArg.empty() && VersionFile) + if (parseHIPVersionFile((*VersionFile)->getBuffer())) + continue; - HasHIPRuntime = true; - return; + HasHIPRuntime = true; + return; + } + // Otherwise, if -rocm-path is specified (no strict checking), use the + // default HIP version or specified by --hip-version. + if (!Candidate.StrictChecking) { + HasHIPRuntime = true; + return; + } } HasHIPRuntime = false; } @@ -478,7 +519,9 @@ void RocmInstallationDetector::print(raw_ostream &OS) const { void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5); + bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5) && + !DriverArgs.hasArg(options::OPT_nohipwrapperinc); + bool HasHipStdPar = DriverArgs.hasArg(options::OPT_hipstdpar); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { // HIP header includes standard library wrapper headers under clang @@ -501,18 +544,66 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, CC1Args.push_back(DriverArgs.MakeArgString(P)); } - if (DriverArgs.hasArg(options::OPT_nogpuinc)) + const auto HandleHipStdPar = [=, &DriverArgs, &CC1Args]() { + StringRef Inc = getIncludePath(); + auto &FS = D.getVFS(); + + if (!hasHIPStdParLibrary()) + if (!HIPStdParPathArg.empty() || + !FS.exists(Inc + "/thrust/system/hip/hipstdpar/hipstdpar_lib.hpp")) { + D.Diag(diag::err_drv_no_hipstdpar_lib); + return; + } + if (!HasRocThrustLibrary && !FS.exists(Inc + "/thrust")) { + D.Diag(diag::err_drv_no_hipstdpar_thrust_lib); + return; + } + if (!HasRocPrimLibrary && !FS.exists(Inc + "/rocprim")) { + D.Diag(diag::err_drv_no_hipstdpar_prim_lib); + return; + } + const char *ThrustPath; + if (HasRocThrustLibrary) + ThrustPath = DriverArgs.MakeArgString(HIPRocThrustPathArg); + else + ThrustPath = DriverArgs.MakeArgString(Inc + "/thrust"); + + const char *HIPStdParPath; + if (hasHIPStdParLibrary()) + HIPStdParPath = DriverArgs.MakeArgString(HIPStdParPathArg); + else + HIPStdParPath = DriverArgs.MakeArgString(StringRef(ThrustPath) + + "/system/hip/hipstdpar"); + + const char *PrimPath; + if (HasRocPrimLibrary) + PrimPath = DriverArgs.MakeArgString(HIPRocPrimPathArg); + else + PrimPath = DriverArgs.MakeArgString(getIncludePath() + "/rocprim"); + + CC1Args.append({"-idirafter", ThrustPath, "-idirafter", PrimPath, + "-idirafter", HIPStdParPath, "-include", + "hipstdpar_lib.hpp"}); + }; + + if (DriverArgs.hasArg(options::OPT_nogpuinc)) { + if (HasHipStdPar) + HandleHipStdPar(); + return; + } if (!hasHIPRuntime()) { D.Diag(diag::err_drv_no_hip_runtime); return; } - CC1Args.push_back("-internal-isystem"); + CC1Args.push_back("-idirafter"); CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); if (UsesRuntimeWrapper) CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"}); + if (HasHipStdPar) + HandleHipStdPar(); } void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -523,9 +614,18 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, std::string Linker = getToolChain().GetProgramPath(getShortName()); ArgStringList CmdArgs; + CmdArgs.push_back("--no-undefined"); + CmdArgs.push_back("-shared"); + addLinkerCompressDebugSectionsOption(getToolChain(), Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_L); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - CmdArgs.push_back("-shared"); + if (C.getDriver().isUsingLTO()) + addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0], + C.getDriver().getLTOMode() == LTOK_Thin); + else if (Args.hasArg(options::OPT_mcpu_EQ)) + CmdArgs.push_back(Args.MakeArgString( + "-plugin-opt=mcpu=" + Args.getLastArgValue(options::OPT_mcpu_EQ))); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); C.addCommand(std::make_unique<Command>( @@ -544,7 +644,7 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D, llvm::StringMap<bool> FeatureMap; auto OptionalGpuArch = parseTargetID(Triple, TargetID, &FeatureMap); if (OptionalGpuArch) { - StringRef GpuArch = OptionalGpuArch.getValue(); + StringRef GpuArch = *OptionalGpuArch; // Iterate through all possible target ID features for the given GPU. // If it is mapped to true, add +feature. // If it is mapped to false, add -feature. @@ -563,8 +663,8 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D, options::OPT_mno_wavefrontsize64, false)) Features.push_back("+wavefrontsize64"); - handleTargetFeaturesGroup( - Args, Features, options::OPT_m_amdgpu_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_amdgpu_Features_Group); } /// AMDGPU Toolchain @@ -596,9 +696,28 @@ AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, if (!DAL) DAL = new DerivedArgList(Args.getBaseArgs()); - for (Arg *A : Args) { - if (!shouldSkipArgument(A)) - DAL->append(A); + for (Arg *A : Args) + DAL->append(A); + + // Replace -mcpu=native with detected GPU. + Arg *LastMCPUArg = DAL->getLastArg(options::OPT_mcpu_EQ); + if (LastMCPUArg && StringRef(LastMCPUArg->getValue()) == "native") { + DAL->eraseArg(options::OPT_mcpu_EQ); + auto GPUsOrErr = getSystemGPUArchs(Args); + if (!GPUsOrErr) { + getDriver().Diag(diag::err_drv_undetermined_gpu_arch) + << llvm::Triple::getArchTypeName(getArch()) + << llvm::toString(GPUsOrErr.takeError()) << "-mcpu"; + } else { + auto &GPUs = *GPUsOrErr; + if (GPUs.size() > 1) { + getDriver().Diag(diag::warn_drv_multi_gpu_arch) + << llvm::Triple::getArchTypeName(getArch()) + << llvm::join(GPUs, ", ") << "-mcpu"; + } + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), + Args.MakeArgString(GPUs.front())); + } } checkTargetID(*DAL); @@ -688,7 +807,7 @@ bool AMDGPUToolChain::isWave64(const llvm::opt::ArgList &DriverArgs, ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : AMDGPUToolChain(D, Triple, Args) { - RocmInstallation.detectDeviceLibrary(); + RocmInstallation->detectDeviceLibrary(); } void AMDGPUToolChain::addClangTargetOptions( @@ -699,8 +818,7 @@ void AMDGPUToolChain::addClangTargetOptions( // supported for the foreseeable future. if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, options::OPT_fvisibility_ms_compat)) { - CC1Args.push_back("-fvisibility"); - CC1Args.push_back("hidden"); + CC1Args.push_back("-fvisibility=hidden"); CC1Args.push_back("-fapply-global-visibility-to-externs"); } } @@ -715,14 +833,14 @@ AMDGPUToolChain::ParsedTargetIDType AMDGPUToolChain::getParsedTargetID(const llvm::opt::ArgList &DriverArgs) const { StringRef TargetID = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ); if (TargetID.empty()) - return {None, None, None}; + return {std::nullopt, std::nullopt, std::nullopt}; llvm::StringMap<bool> FeatureMap; auto OptionalGpuArch = parseTargetID(getTriple(), TargetID, &FeatureMap); if (!OptionalGpuArch) - return {TargetID.str(), None, None}; + return {TargetID.str(), std::nullopt, std::nullopt}; - return {TargetID.str(), OptionalGpuArch.getValue().str(), FeatureMap}; + return {TargetID.str(), OptionalGpuArch->str(), FeatureMap}; } void AMDGPUToolChain::checkTargetID( @@ -730,80 +848,33 @@ void AMDGPUToolChain::checkTargetID( auto PTID = getParsedTargetID(DriverArgs); if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) { getDriver().Diag(clang::diag::err_drv_bad_target_id) - << PTID.OptionalTargetID.getValue(); + << *PTID.OptionalTargetID; } } -llvm::Error -AMDGPUToolChain::detectSystemGPUs(const ArgList &Args, - SmallVector<std::string, 1> &GPUArchs) const { +Expected<SmallVector<std::string>> +AMDGPUToolChain::getSystemGPUArchs(const ArgList &Args) const { + // Detect AMD GPUs availible on the system. std::string Program; if (Arg *A = Args.getLastArg(options::OPT_amdgpu_arch_tool_EQ)) Program = A->getValue(); else - Program = GetProgramPath(AMDGPU_ARCH_PROGRAM_NAME); - llvm::SmallString<64> OutputFile; - llvm::sys::fs::createTemporaryFile("print-system-gpus", "" /* No Suffix */, - OutputFile); - llvm::FileRemover OutputRemover(OutputFile.c_str()); - llvm::Optional<llvm::StringRef> Redirects[] = { - {""}, - OutputFile.str(), - {""}, - }; - - std::string ErrorMessage; - if (int Result = llvm::sys::ExecuteAndWait( - Program.c_str(), {}, {}, Redirects, /* SecondsToWait */ 0, - /*MemoryLimit*/ 0, &ErrorMessage)) { - if (Result > 0) { - ErrorMessage = "Exited with error code " + std::to_string(Result); - } else if (Result == -1) { - ErrorMessage = "Execute failed: " + ErrorMessage; - } else { - ErrorMessage = "Crashed: " + ErrorMessage; - } + Program = GetProgramPath("amdgpu-arch"); - return llvm::createStringError(std::error_code(), - Program + ": " + ErrorMessage); - } - - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf = - llvm::MemoryBuffer::getFile(OutputFile.c_str()); - if (!OutputBuf) { - return llvm::createStringError(OutputBuf.getError(), - "Failed to read stdout of " + Program + - ": " + OutputBuf.getError().message()); - } - - for (llvm::line_iterator LineIt(**OutputBuf); !LineIt.is_at_end(); ++LineIt) { - GPUArchs.push_back(LineIt->str()); - } - return llvm::Error::success(); -} + auto StdoutOrErr = executeToolChainProgram(Program); + if (!StdoutOrErr) + return StdoutOrErr.takeError(); -llvm::Error AMDGPUToolChain::getSystemGPUArch(const ArgList &Args, - std::string &GPUArch) const { - // detect the AMDGPU installed in system SmallVector<std::string, 1> GPUArchs; - auto Err = detectSystemGPUs(Args, GPUArchs); - if (Err) { - return Err; - } - if (GPUArchs.empty()) { + for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n")) + if (!Arch.empty()) + GPUArchs.push_back(Arch.str()); + + if (GPUArchs.empty()) return llvm::createStringError(std::error_code(), "No AMD GPU detected in the system"); - } - GPUArch = GPUArchs[0]; - if (GPUArchs.size() > 1) { - bool AllSame = std::all_of( - GPUArchs.begin(), GPUArchs.end(), - [&](const StringRef &GPUArch) { return GPUArch == GPUArchs.front(); }); - if (!AllSame) - return llvm::createStringError( - std::error_code(), "Multiple AMD GPUs found with different archs"); - } - return llvm::Error::success(); + + return std::move(GPUArchs); } void ROCMToolChain::addClangTargetOptions( @@ -821,20 +892,16 @@ void ROCMToolChain::addClangTargetOptions( if (DriverArgs.hasArg(options::OPT_nogpulib)) return; - if (!RocmInstallation.hasDeviceLibrary()) { - getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; - return; - } - // Get the device name and canonicalize it const StringRef GpuArch = getGPUArch(DriverArgs); auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); - std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); - if (LibDeviceFile.empty()) { - getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch; + StringRef LibDeviceFile = RocmInstallation->getLibDeviceFile(CanonArch); + auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion( + getAMDGPUCodeObjectVersion(getDriver(), DriverArgs)); + if (!RocmInstallation->checkCommonBitcodeLibs(CanonArch, LibDeviceFile, + ABIVer)) return; - } bool Wave64 = isWave64(DriverArgs, Kind); @@ -852,59 +919,75 @@ void ROCMToolChain::addClangTargetOptions( // Add the OpenCL specific bitcode library. llvm::SmallVector<std::string, 12> BCLibs; - BCLibs.push_back(RocmInstallation.getOpenCLPath().str()); + BCLibs.push_back(RocmInstallation->getOpenCLPath().str()); // Add the generic set of libraries. - BCLibs.append(RocmInstallation.getCommonBitcodeLibs( + BCLibs.append(RocmInstallation->getCommonBitcodeLibs( DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, - FastRelaxedMath, CorrectSqrt)); + FastRelaxedMath, CorrectSqrt, ABIVer, false)); - llvm::for_each(BCLibs, [&](StringRef BCFile) { + for (StringRef BCFile : BCLibs) { CC1Args.push_back("-mlink-builtin-bitcode"); CC1Args.push_back(DriverArgs.MakeArgString(BCFile)); - }); + } +} + +bool RocmInstallationDetector::checkCommonBitcodeLibs( + StringRef GPUArch, StringRef LibDeviceFile, + DeviceLibABIVersion ABIVer) const { + if (!hasDeviceLibrary()) { + D.Diag(diag::err_drv_no_rocm_device_lib) << 0; + return false; + } + if (LibDeviceFile.empty()) { + D.Diag(diag::err_drv_no_rocm_device_lib) << 1 << GPUArch; + return false; + } + if (ABIVer.requiresLibrary() && getABIVersionPath(ABIVer).empty()) { + D.Diag(diag::err_drv_no_rocm_device_lib) << 2 << ABIVer.toString(); + return false; + } + return true; } llvm::SmallVector<std::string, 12> RocmInstallationDetector::getCommonBitcodeLibs( const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile, bool Wave64, bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, bool FastRelaxedMath, - bool CorrectSqrt) const { - + bool CorrectSqrt, DeviceLibABIVersion ABIVer, bool isOpenMP = false) const { llvm::SmallVector<std::string, 12> BCLibs; auto AddBCLib = [&](StringRef BCFile) { BCLibs.push_back(BCFile.str()); }; AddBCLib(getOCMLPath()); - AddBCLib(getOCKLPath()); + if (!isOpenMP) + AddBCLib(getOCKLPath()); AddBCLib(getDenormalsAreZeroPath(DAZ)); AddBCLib(getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath)); AddBCLib(getFiniteOnlyPath(FiniteOnly || FastRelaxedMath)); AddBCLib(getCorrectlyRoundedSqrtPath(CorrectSqrt)); AddBCLib(getWavefrontSize64Path(Wave64)); AddBCLib(LibDeviceFile); + auto ABIVerPath = getABIVersionPath(ABIVer); + if (!ABIVerPath.empty()) + AddBCLib(ABIVerPath); return BCLibs; } -bool AMDGPUToolChain::shouldSkipArgument(const llvm::opt::Arg *A) const { - Option O = A->getOption(); - if (O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) - return true; - return false; -} - llvm::SmallVector<std::string, 12> ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, - const std::string &GPUArch) const { + const std::string &GPUArch, + bool isOpenMP) const { auto Kind = llvm::AMDGPU::parseArchAMDGCN(GPUArch); const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); - std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); - if (LibDeviceFile.empty()) { - getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GPUArch; + StringRef LibDeviceFile = RocmInstallation->getLibDeviceFile(CanonArch); + auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion( + getAMDGPUCodeObjectVersion(getDriver(), DriverArgs)); + if (!RocmInstallation->checkCommonBitcodeLibs(CanonArch, LibDeviceFile, + ABIVer)) return {}; - } // If --hip-device-lib is not set, add the default bitcode libraries. // TODO: There are way too many flags that change this. Do we need to check @@ -921,10 +1004,10 @@ ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, options::OPT_fno_fast_math, false); bool CorrectSqrt = DriverArgs.hasFlag( options::OPT_fhip_fp32_correctly_rounded_divide_sqrt, - options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt); + options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt, true); bool Wave64 = isWave64(DriverArgs, Kind); - return RocmInstallation.getCommonBitcodeLibs( + return RocmInstallation->getCommonBitcodeLibs( DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, - FastRelaxedMath, CorrectSqrt); -}
\ No newline at end of file + FastRelaxedMath, CorrectSqrt, ABIVer, isOpenMP); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h index a4bcf315ca76..b3361b1e3607 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.h @@ -16,7 +16,7 @@ #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/TargetParser/TargetParser.h" #include <map> @@ -26,7 +26,7 @@ namespace driver { namespace tools { namespace amdgpu { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("amdgpu::Linker", "ld.lld", TC) {} bool isLinkJob() const override { return true; } @@ -51,7 +51,7 @@ protected: const std::map<options::ID, const StringRef> OptionsDefault; Tool *buildLinker() const override; - const StringRef getOptionDefault(options::ID OptID) const { + StringRef getOptionDefault(options::ID OptID) const { auto opt = OptionsDefault.find(OptID); assert(opt != OptionsDefault.end() && "No Default for Option"); return opt->second; @@ -60,15 +60,15 @@ protected: public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - unsigned GetDefaultDwarfVersion() const override { return 4; } - bool IsIntegratedAssemblerDefault() const override { return true; } - bool IsMathErrnoDefault() const override { return false; } + unsigned GetDefaultDwarfVersion() const override { return 5; } - bool useIntegratedAs() const override { return true; } + bool IsMathErrnoDefault() const override { return false; } bool isCrossCompiling() const override { return true; } - bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } - bool isPICDefaultForced() const override { return false; } + bool isPICDefault() const override { return true; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } + bool isPICDefaultForced() const override { return true; } bool SupportsProfiling() const override { return false; } llvm::opt::DerivedArgList * @@ -97,13 +97,10 @@ public: /// Needed for translating LTO options. const char *getDefaultLinker() const override { return "ld.lld"; } - /// Should skip argument. - bool shouldSkipArgument(const llvm::opt::Arg *Arg) const; - - /// Uses amdgpu_arch tool to get arch of the system GPU. Will return error + /// Uses amdgpu-arch tool to get arch of the system GPU. Will return error /// if unable to find one. - llvm::Error getSystemGPUArch(const llvm::opt::ArgList &Args, - std::string &GPUArch) const; + virtual Expected<SmallVector<std::string>> + getSystemGPUArchs(const llvm::opt::ArgList &Args) const override; protected: /// Check and diagnose invalid target ID specified by -mcpu. @@ -111,9 +108,9 @@ protected: /// The struct type returned by getParsedTargetID. struct ParsedTargetIDType { - Optional<std::string> OptionalTargetID; - Optional<std::string> OptionalGPUArch; - Optional<llvm::StringMap<bool>> OptionalFeatures; + std::optional<std::string> OptionalTargetID; + std::optional<std::string> OptionalGPUArch; + std::optional<llvm::StringMap<bool>> OptionalFeatures; }; /// Get target ID, GPU arch, and target ID features if the target ID is @@ -124,8 +121,6 @@ protected: /// Get GPU arch from -mcpu without checking. StringRef getGPUArch(const llvm::opt::ArgList &DriverArgs) const; - llvm::Error detectSystemGPUs(const llvm::opt::ArgList &Args, - SmallVector<std::string, 1> &GPUArchs) const; }; class LLVM_LIBRARY_VISIBILITY ROCMToolChain : public AMDGPUToolChain { @@ -140,7 +135,8 @@ public: // Returns a list of device library names shared by different languages llvm::SmallVector<std::string, 12> getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, - const std::string &GPUArch) const; + const std::string &GPUArch, + bool isOpenMP = false) const; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp index 135e3694434d..b012b7cb7293 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp @@ -16,6 +16,7 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" +#include "clang/Driver/Tool.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatAdapters.h" @@ -28,199 +29,13 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -namespace { - -static const char *getOutputFileName(Compilation &C, StringRef Base, - const char *Postfix, - const char *Extension) { - const char *OutputFileName; - if (C.getDriver().isSaveTempsEnabled()) { - OutputFileName = - C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension); - } else { - std::string TmpName = - C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension); - OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName)); - } - return OutputFileName; -} - -static void addLLCOptArg(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) { - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - StringRef OOpt = "0"; - if (A->getOption().matches(options::OPT_O4) || - A->getOption().matches(options::OPT_Ofast)) - OOpt = "3"; - else if (A->getOption().matches(options::OPT_O0)) - OOpt = "0"; - else if (A->getOption().matches(options::OPT_O)) { - // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3 - // so we map -Os/-Oz to -O2. - // Only clang supports -Og, and maps it to -O1. - // We map anything else to -O2. - OOpt = llvm::StringSwitch<const char *>(A->getValue()) - .Case("1", "1") - .Case("2", "2") - .Case("3", "3") - .Case("s", "2") - .Case("z", "2") - .Case("g", "1") - .Default("0"); - } - CmdArgs.push_back(Args.MakeArgString("-O" + OOpt)); - } -} - -static bool checkSystemForAMDGPU(const ArgList &Args, const AMDGPUToolChain &TC, - std::string &GPUArch) { - if (auto Err = TC.getSystemGPUArch(Args, GPUArch)) { - std::string ErrMsg = - llvm::formatv("{0}", llvm::fmt_consume(std::move(Err))); - TC.getDriver().Diag(diag::err_drv_undetermined_amdgpu_arch) << ErrMsg; - return false; - } - - return true; -} -} // namespace - -const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( - const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C, - const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, - StringRef SubArchName, StringRef OutputFilePrefix) const { - ArgStringList CmdArgs; - - for (const auto &II : Inputs) - if (II.isFilename()) - CmdArgs.push_back(II.getFilename()); - - if (Args.hasArg(options::OPT_l)) { - auto Lm = Args.getAllArgValues(options::OPT_l); - bool HasLibm = false; - for (auto &Lib : Lm) { - if (Lib == "m") { - HasLibm = true; - break; - } - } - - if (HasLibm) { - SmallVector<std::string, 12> BCLibs = - AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str()); - llvm::for_each(BCLibs, [&](StringRef BCFile) { - CmdArgs.push_back(Args.MakeArgString(BCFile)); - }); - } - } - - // Add an intermediate output file. - CmdArgs.push_back("-o"); - const char *OutputFileName = - getOutputFileName(C, OutputFilePrefix, "-linked", "bc"); - CmdArgs.push_back(OutputFileName); - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, - InputInfo(&JA, Args.MakeArgString(OutputFileName)))); - return OutputFileName; -} - -const char *AMDGCN::OpenMPLinker::constructLlcCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix, const char *InputFileName, - bool OutputIsAsm) const { - // Construct llc command. - ArgStringList LlcArgs; - // The input to llc is the output from opt. - LlcArgs.push_back(InputFileName); - // Pass optimization arg to llc. - addLLCOptArg(Args, LlcArgs); - LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); - LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); - LlcArgs.push_back( - Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj"))); - - for (const Arg *A : Args.filtered(options::OPT_mllvm)) { - LlcArgs.push_back(A->getValue(0)); - } - - // Add output filename - LlcArgs.push_back("-o"); - const char *LlcOutputFile = - getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o"); - LlcArgs.push_back(LlcOutputFile); - const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc")); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), Llc, LlcArgs, Inputs, - InputInfo(&JA, Args.MakeArgString(LlcOutputFile)))); - return LlcOutputFile; -} - -void AMDGCN::OpenMPLinker::constructLldCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const InputInfo &Output, const llvm::opt::ArgList &Args, - const char *InputFileName) const { - // Construct lld command. - // The output from ld.lld is an HSA code object file. - ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", - "-shared", "-o", Output.getFilename(), - InputFileName}; - - const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), Lld, LldArgs, Inputs, - InputInfo(&JA, Args.MakeArgString(Output.getFilename())))); -} - -// For amdgcn the inputs of the linker job are device bitcode and output is -// object file. It calls llvm-link, opt, llc, then lld steps. -void AMDGCN::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const ToolChain &TC = getToolChain(); - assert(getToolChain().getTriple().isAMDGCN() && "Unsupported target"); - - const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC = - static_cast<const toolchains::AMDGPUOpenMPToolChain &>(TC); - - std::string GPUArch = Args.getLastArgValue(options::OPT_march_EQ).str(); - if (GPUArch.empty()) { - if (!checkSystemForAMDGPU(Args, AMDGPUOpenMPTC, GPUArch)) - return; - } - - // Prefix for temporary file name. - std::string Prefix; - for (const auto &II : Inputs) - if (II.isFilename()) - Prefix = llvm::sys::path::stem(II.getFilename()).str() + "-" + GPUArch; - assert(Prefix.length() && "no linker inputs are files "); - - // Each command outputs different files. - const char *LLVMLinkCommand = constructLLVMLinkCommand( - AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix); - - // Produce readable assembly if save-temps is enabled. - if (C.getDriver().isSaveTempsEnabled()) - constructLlcCommand(C, JA, Inputs, Args, GPUArch, Prefix, LLVMLinkCommand, - /*OutputIsAsm=*/true); - const char *LlcCommand = constructLlcCommand(C, JA, Inputs, Args, GPUArch, - Prefix, LLVMLinkCommand); - constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand); -} - AMDGPUOpenMPToolChain::AMDGPUOpenMPToolChain(const Driver &D, const llvm::Triple &Triple, const ToolChain &HostTC, const ArgList &Args) : ROCMToolChain(D, Triple, Args), HostTC(HostTC) { // Lookup binaries into the driver directory, this is used to - // discover the clang-offload-bundler executable. + // discover the 'amdgpu-arch' executable. getProgramPaths().push_back(getDriver().Dir); } @@ -229,11 +44,8 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions( Action::OffloadKind DeviceOffloadingKind) const { HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); - std::string GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ).str(); - if (GPUArch.empty()) { - if (!checkSystemForAMDGPU(DriverArgs, *this, GPUArch)) - return; - } + StringRef GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + assert(!GPUArch.empty() && "Must have an explicit GPU arch."); assert(DeviceOffloadingKind == Action::OFK_OpenMP && "Only OpenMP offloading kinds are supported."); @@ -245,15 +57,15 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions( if (DriverArgs.hasArg(options::OPT_nogpulib)) return; - std::string BitcodeSuffix; - if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime, - options::OPT_fno_openmp_target_new_runtime, false)) - BitcodeSuffix = "new-amdgcn-" + GPUArch; - else - BitcodeSuffix = "amdgcn-" + GPUArch; + for (auto BCFile : getDeviceLibs(DriverArgs)) { + CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" + : "-mlink-bitcode-file"); + CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path)); + } - addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, - getTriple()); + // Link the bitcode library late if we're using device LTO. + if (getDriver().isUsingLTO(/* IsOffload */ true)) + return; } llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( @@ -266,10 +78,33 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( const OptTable &Opts = getDriver().getOpts(); - if (DeviceOffloadKind != Action::OFK_OpenMP) { - for (Arg *A : Args) { - DAL->append(A); + if (DeviceOffloadKind == Action::OFK_OpenMP) { + for (Arg *A : Args) + if (!llvm::is_contained(*DAL, A)) + DAL->append(A); + + if (!DAL->hasArg(options::OPT_march_EQ)) { + StringRef Arch = BoundArch; + if (Arch.empty()) { + auto ArchsOrErr = getSystemGPUArchs(Args); + if (!ArchsOrErr) { + std::string ErrMsg = + llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError())); + getDriver().Diag(diag::err_drv_undetermined_gpu_arch) + << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march"; + Arch = CudaArchToString(CudaArch::HIPDefault); + } else { + Arch = Args.MakeArgString(ArchsOrErr->front()); + } + } + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch); } + + return DAL; + } + + for (Arg *A : Args) { + DAL->append(A); } if (!BoundArch.empty()) { @@ -281,11 +116,6 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( return DAL; } -Tool *AMDGPUOpenMPToolChain::buildLinker() const { - assert(getTriple().isAMDGCN()); - return new tools::AMDGCN::OpenMPLinker(*this); -} - void AMDGPUOpenMPToolChain::addClangWarningOptions( ArgStringList &CC1Args) const { HostTC.addClangWarningOptions(CC1Args); @@ -324,3 +154,24 @@ AMDGPUOpenMPToolChain::computeMSVCVersion(const Driver *D, const ArgList &Args) const { return HostTC.computeMSVCVersion(D, Args); } + +llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> +AMDGPUOpenMPToolChain::getDeviceLibs(const llvm::opt::ArgList &Args) const { + if (Args.hasArg(options::OPT_nogpulib)) + return {}; + + if (!RocmInstallation->hasDeviceLibrary()) { + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; + return {}; + } + + StringRef GpuArch = getProcessorFromTargetID( + getTriple(), Args.getLastArgValue(options::OPT_march_EQ)); + + SmallVector<BitCodeLibraryInfo, 12> BCLibs; + for (auto BCLib : getCommonDeviceLibNames(Args, GpuArch.str(), + /*IsOpenMP=*/true)) + BCLibs.emplace_back(BCLib); + + return BCLibs; +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h index 233256bf7378..2be444a42c55 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h @@ -20,49 +20,6 @@ namespace toolchains { class AMDGPUOpenMPToolChain; } -namespace tools { - -namespace AMDGCN { -// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with -// device library, then compiles it to ISA in a shared object. -class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool { -public: - OpenMPLinker(const ToolChain &TC) - : Tool("AMDGCN::OpenMPLinker", "amdgcn-link", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; - -private: - /// \return llvm-link output file name. - const char *constructLLVMLinkCommand( - const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C, - const JobAction &JA, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix) const; - - /// \return llc output file name. - const char *constructLlcCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix, - const char *InputFileName, - bool OutputIsAsm = false) const; - - void constructLldCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, const InputInfo &Output, - const llvm::opt::ArgList &Args, - const char *InputFileName) const; -}; - -} // end namespace AMDGCN -} // end namespace tools - namespace toolchains { class LLVM_LIBRARY_VISIBILITY AMDGPUOpenMPToolChain final @@ -97,10 +54,10 @@ public: computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override; - const ToolChain &HostTC; + llvm::SmallVector<BitCodeLibraryInfo, 12> + getDeviceLibs(const llvm::opt::ArgList &Args) const override; -protected: - Tool *buildLinker() const override; + const ToolChain &HostTC; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp index f147292038a8..bb5c0e6db997 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.cpp @@ -12,13 +12,12 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/SubtargetFeature.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/TargetParser/SubtargetFeature.h" using namespace clang::driver; using namespace clang::driver::toolchains; @@ -28,9 +27,10 @@ using namespace llvm::opt; namespace { -const struct { +// NOTE: This list has been synchronized with gcc-avr 7.3.0 and avr-libc 2.0.0. +constexpr struct { StringRef Name; - std::string SubPath; + StringRef SubPath; StringRef Family; unsigned DataAddr; } MCUInfo[] = { @@ -62,6 +62,7 @@ const struct { {"attiny261a", "avr25/tiny-stack", "avr25", 0x800060}, {"at86rf401", "avr25", "avr25", 0x800060}, {"ata5272", "avr25", "avr25", 0x800100}, + {"ata6616c", "avr25", "avr25", 0x800100}, {"attiny4313", "avr25", "avr25", 0x800060}, {"attiny44", "avr25", "avr25", 0x800060}, {"attiny44a", "avr25", "avr25", 0x800060}, @@ -88,6 +89,8 @@ const struct { {"at90usb82", "avr35", "avr35", 0x800100}, {"at90usb162", "avr35", "avr35", 0x800100}, {"ata5505", "avr35", "avr35", 0x800100}, + {"ata6617c", "avr35", "avr35", 0x800100}, + {"ata664251", "avr35", "avr35", 0x800100}, {"atmega8u2", "avr35", "avr35", 0x800100}, {"atmega16u2", "avr35", "avr35", 0x800100}, {"atmega32u2", "avr35", "avr35", 0x800100}, @@ -97,6 +100,7 @@ const struct { {"atmega8a", "avr4", "avr4", 0x800060}, {"ata6285", "avr4", "avr4", 0x800100}, {"ata6286", "avr4", "avr4", 0x800100}, + {"ata6612c", "avr4", "avr4", 0x800100}, {"atmega48", "avr4", "avr4", 0x800100}, {"atmega48a", "avr4", "avr4", 0x800100}, {"atmega48pa", "avr4", "avr4", 0x800100}, @@ -116,8 +120,17 @@ const struct { {"at90pwm3", "avr4", "avr4", 0x800100}, {"at90pwm3b", "avr4", "avr4", 0x800100}, {"at90pwm81", "avr4", "avr4", 0x800100}, + {"ata5702m322", "avr5", "avr5", 0x800200}, + {"ata5782", "avr5", "avr5", 0x800200}, {"ata5790", "avr5", "avr5", 0x800100}, + {"ata5790n", "avr5", "avr5", 0x800100}, + {"ata5791", "avr5", "avr5", 0x800100}, {"ata5795", "avr5", "avr5", 0x800100}, + {"ata5831", "avr5", "avr5", 0x800200}, + {"ata6613c", "avr5", "avr5", 0x800100}, + {"ata6614q", "avr5", "avr5", 0x800100}, + {"ata8210", "avr5", "avr5", 0x800200}, + {"ata8510", "avr5", "avr5", 0x800200}, {"atmega16", "avr5", "avr5", 0x800060}, {"atmega16a", "avr5", "avr5", 0x800060}, {"atmega161", "avr5", "avr5", 0x800060}, @@ -145,6 +158,7 @@ const struct { {"atmega324a", "avr5", "avr5", 0x800100}, {"atmega324p", "avr5", "avr5", 0x800100}, {"atmega324pa", "avr5", "avr5", 0x800100}, + {"atmega324pb", "avr5", "avr5", 0x800100}, {"atmega325", "avr5", "avr5", 0x800100}, {"atmega325a", "avr5", "avr5", 0x800100}, {"atmega325p", "avr5", "avr5", 0x800100}, @@ -155,6 +169,7 @@ const struct { {"atmega3250pa", "avr5", "avr5", 0x800100}, {"atmega328", "avr5", "avr5", 0x800100}, {"atmega328p", "avr5", "avr5", 0x800100}, + {"atmega328pb", "avr5", "avr5", 0x800100}, {"atmega329", "avr5", "avr5", 0x800100}, {"atmega329a", "avr5", "avr5", 0x800100}, {"atmega329p", "avr5", "avr5", 0x800100}, @@ -192,6 +207,7 @@ const struct { {"atmega32hvb", "avr5", "avr5", 0x800100}, {"atmega32hvbrevb", "avr5", "avr5", 0x800100}, {"atmega64hve", "avr5", "avr5", 0x800100}, + {"atmega64hve2", "avr5", "avr5", 0x800100}, {"at90can32", "avr5", "avr5", 0x800100}, {"at90can64", "avr5", "avr5", 0x800100}, {"at90pwm161", "avr5", "avr5", 0x800100}, @@ -232,17 +248,22 @@ const struct { {"attiny10", "avrtiny", "avrtiny", 0x800040}, {"attiny20", "avrtiny", "avrtiny", 0x800040}, {"attiny40", "avrtiny", "avrtiny", 0x800040}, + {"attiny102", "avrtiny", "avrtiny", 0x800040}, + {"attiny104", "avrtiny", "avrtiny", 0x800040}, {"atxmega16a4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega16a4u", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega16c4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega16d4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32a4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32a4u", "avrxmega2", "avrxmega2", 0x802000}, + {"atxmega32c3", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32c4", "avrxmega2", "avrxmega2", 0x802000}, + {"atxmega32d3", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32d4", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega32e5", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega16e5", "avrxmega2", "avrxmega2", 0x802000}, {"atxmega8e5", "avrxmega2", "avrxmega2", 0x802000}, + {"atxmega64a3", "avrxmega4", "avrxmega4", 0x802000}, {"atxmega64a3u", "avrxmega4", "avrxmega4", 0x802000}, {"atxmega64a4u", "avrxmega4", "avrxmega4", 0x802000}, {"atxmega64b1", "avrxmega4", "avrxmega4", 0x802000}, @@ -274,6 +295,42 @@ const struct { {"atxmega128a1", "avrxmega7", "avrxmega7", 0x802000}, {"atxmega128a1u", "avrxmega7", "avrxmega7", 0x802000}, {"atxmega128a4u", "avrxmega7", "avrxmega7", 0x802000}, + {"attiny202", "avrxmega3/short-calls", "avrxmega3", 0x803F80}, + {"attiny204", "avrxmega3/short-calls", "avrxmega3", 0x803F80}, + {"attiny212", "avrxmega3/short-calls", "avrxmega3", 0x803F80}, + {"attiny214", "avrxmega3/short-calls", "avrxmega3", 0x803F80}, + {"attiny402", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny404", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny406", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny412", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny414", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny416", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny417", "avrxmega3/short-calls", "avrxmega3", 0x803F00}, + {"attiny804", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny806", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny807", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny814", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny816", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"attiny817", "avrxmega3/short-calls", "avrxmega3", 0x803E00}, + {"atmega808", "avrxmega3/short-calls", "avrxmega3", 0x803C00}, + {"atmega809", "avrxmega3/short-calls", "avrxmega3", 0x803C00}, + {"atmega1608", "avrxmega3", "avrxmega3", 0x803800}, + {"atmega1609", "avrxmega3", "avrxmega3", 0x803800}, + {"atmega3208", "avrxmega3", "avrxmega3", 0x803000}, + {"atmega3209", "avrxmega3", "avrxmega3", 0x803000}, + {"atmega4808", "avrxmega3", "avrxmega3", 0x802800}, + {"atmega4809", "avrxmega3", "avrxmega3", 0x802800}, + {"attiny1604", "avrxmega3", "avrxmega3", 0x803C00}, + {"attiny1606", "avrxmega3", "avrxmega3", 0x803C00}, + {"attiny1607", "avrxmega3", "avrxmega3", 0x803C00}, + {"attiny1614", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1616", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1617", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1624", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1626", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny1627", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny3216", "avrxmega3", "avrxmega3", 0x803800}, + {"attiny3217", "avrxmega3", "avrxmega3", 0x803800}, }; std::string GetMCUSubPath(StringRef MCUName) { @@ -283,21 +340,22 @@ std::string GetMCUSubPath(StringRef MCUName) { return ""; } -llvm::Optional<StringRef> GetMCUFamilyName(StringRef MCUName) { +std::optional<StringRef> GetMCUFamilyName(StringRef MCUName) { for (const auto &MCU : MCUInfo) if (MCU.Name == MCUName) - return Optional<StringRef>(MCU.Family); - return Optional<StringRef>(); + return std::optional<StringRef>(MCU.Family); + return std::nullopt; } -llvm::Optional<unsigned> GetMCUSectionAddressData(StringRef MCUName) { +std::optional<unsigned> GetMCUSectionAddressData(StringRef MCUName) { for (const auto &MCU : MCUInfo) if (MCU.Name == MCUName && MCU.DataAddr > 0) - return Optional<unsigned>(MCU.DataAddr); - return Optional<unsigned>(); + return std::optional<unsigned>(MCU.DataAddr); + return std::nullopt; } const StringRef PossibleAVRLibcLocations[] = { + "/avr", "/usr/avr", "/usr/lib/avr", }; @@ -307,49 +365,18 @@ const StringRef PossibleAVRLibcLocations[] = { /// AVR Toolchain AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args), LinkStdlib(false) { + : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); + if (getCPUName(D, Args, Triple).empty()) + D.Diag(diag::warn_drv_avr_mcu_not_specified); + // Only add default libraries if the user hasn't explicitly opted out. if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs) && - !Args.hasArg(options::OPT_c /* does not apply when not linking */)) { - std::string CPU = getCPUName(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"); } } @@ -360,52 +387,142 @@ void AVRToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; // Omit if there is no avr-libc installed. - Optional<std::string> AVRLibcRoot = findAVRLibcInstallation(); - if (!AVRLibcRoot.hasValue()) + std::optional<std::string> AVRLibcRoot = findAVRLibcInstallation(); + if (!AVRLibcRoot) return; // Add 'avr-libc/include' to clang system include paths if applicable. - std::string AVRInc = AVRLibcRoot.getValue() + "/include"; + std::string AVRInc = *AVRLibcRoot + "/include"; if (llvm::sys::fs::is_directory(AVRInc)) addSystemInclude(DriverArgs, CC1Args, AVRInc); } +void AVRToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { + // By default, use `.ctors` (not `.init_array`), as required by libgcc, which + // runs constructors/destructors on AVR. + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, false)) + CC1Args.push_back("-fno-use-init-array"); + // Use `-fno-use-cxa-atexit` as default, since avr-libc does not support + // `__cxa_atexit()`. + if (!DriverArgs.hasFlag(options::OPT_fuse_cxa_atexit, + options::OPT_fno_use_cxa_atexit, false)) + CC1Args.push_back("-fno-use-cxa-atexit"); +} + Tool *AVRToolChain::buildLinker() const { - return new tools::AVR::Linker(getTriple(), *this, LinkStdlib); + return new tools::AVR::Linker(getTriple(), *this); +} + +std::string +AVRToolChain::getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, + FileType Type = ToolChain::FT_Static) const { + assert(Type == ToolChain::FT_Static && "AVR only supports static libraries"); + // Since AVR can never be a host environment, its compiler-rt library files + // should always have ".a" suffix, even on windows. + SmallString<32> File("/libclang_rt."); + File += Component.str(); + File += ".a"; + // Return the default compiler-rt path appended with + // "avr/libclang_rt.$COMPONENT.a". + SmallString<256> Path(ToolChain::getCompilerRTPath()); + llvm::sys::path::append(Path, "avr"); + llvm::sys::path::append(Path, File.str()); + return std::string(Path); } void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const auto &TC = static_cast<const AVRToolChain &>(getToolChain()); + const Driver &D = getToolChain().getDriver(); + // Compute information about the target AVR. - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - llvm::Optional<StringRef> FamilyName = GetMCUFamilyName(CPU); - llvm::Optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU); + std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); + std::optional<StringRef> FamilyName = GetMCUFamilyName(CPU); + std::optional<std::string> AVRLibcRoot = TC.findAVRLibcInstallation(); + std::optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU); + + // Compute the linker program path, and use GNU "avr-ld" as default. + const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ); + std::string Linker = A ? getToolChain().GetLinkerPath(nullptr) + : getToolChain().GetProgramPath(getShortName()); - std::string Linker = getToolChain().GetProgramPath(getShortName()); ArgStringList CmdArgs; - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); // Enable garbage collection of unused sections. - CmdArgs.push_back("--gc-sections"); + if (!Args.hasArg(options::OPT_r)) + CmdArgs.push_back("--gc-sections"); // Add library search paths before we specify libraries. Args.AddAllArgs(CmdArgs, options::OPT_L); getToolChain().AddFilePathLibArgs(Args, CmdArgs); - if (SectionAddressData.hasValue()) { - std::string DataSectionArg = std::string("-Tdata=0x") + - llvm::utohexstr(SectionAddressData.getValue()); - CmdArgs.push_back(Args.MakeArgString(DataSectionArg)); - } else { - // We do not have an entry for this CPU in the address mapping table yet. - getToolChain().getDriver().Diag( - diag::warn_drv_avr_linker_section_addresses_not_implemented) - << CPU; + // Currently we only support libgcc and compiler-rt. + auto RtLib = TC.GetRuntimeLibType(Args); + assert( + (RtLib == ToolChain::RLT_Libgcc || RtLib == ToolChain::RLT_CompilerRT) && + "unknown runtime library"); + + // Only add default libraries if the user hasn't explicitly opted out. + bool LinkStdlib = false; + if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_r) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + if (!CPU.empty()) { + if (!FamilyName) { + // We do not have an entry for this CPU in the family + // mapping table yet. + D.Diag(diag::warn_drv_avr_family_linking_stdlibs_not_implemented) + << CPU; + } else if (!AVRLibcRoot) { + // No avr-libc found and so no runtime linked. + D.Diag(diag::warn_drv_avr_libc_not_found); + } else { + std::string SubPath = GetMCUSubPath(CPU); + // Add path of avr-libc. + CmdArgs.push_back( + Args.MakeArgString(Twine("-L") + *AVRLibcRoot + "/lib/" + SubPath)); + if (RtLib == ToolChain::RLT_Libgcc) + CmdArgs.push_back(Args.MakeArgString("-L" + TC.getGCCInstallPath() + + "/" + SubPath)); + LinkStdlib = true; + } + } + if (!LinkStdlib) + D.Diag(diag::warn_drv_avr_stdlib_not_linked); + } + + if (!Args.hasArg(options::OPT_r)) { + if (SectionAddressData) { + CmdArgs.push_back( + Args.MakeArgString("--defsym=__DATA_REGION_ORIGIN__=0x" + + Twine::utohexstr(*SectionAddressData))); + } else { + // We do not have an entry for this CPU in the address mapping table + // yet. + D.Diag(diag::warn_drv_avr_linker_section_addresses_not_implemented) + << CPU; + } + } + + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(TC, Args, CmdArgs, Output, *Input, + D.getLTOMode() == LTOK_Thin); } // If the family name is known, we can link with the device-specific libgcc. @@ -414,36 +531,85 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (LinkStdlib) { assert(!CPU.empty() && "CPU name must be known in order to link stdlibs"); + CmdArgs.push_back("--start-group"); + // Add the object file for the CRT. std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o"); CmdArgs.push_back(Args.MakeArgString(CrtFileName)); - CmdArgs.push_back("-lgcc"); + // Link to libgcc. + if (RtLib == ToolChain::RLT_Libgcc) + CmdArgs.push_back("-lgcc"); + + // Link to generic libraries of avr-libc. CmdArgs.push_back("-lm"); CmdArgs.push_back("-lc"); // Add the link library specific to the MCU. CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU)); - // Specify the family name as the emulation mode to use. - // This is almost always required because otherwise avr-ld - // will assume 'avr2' and warn about the program being larger - // than the bare minimum supports. - CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName)); + // Add the relocatable inputs. + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + // We directly use libclang_rt.builtins.a as input file, instead of using + // '-lclang_rt.builtins'. + if (RtLib == ToolChain::RLT_CompilerRT) { + std::string RtLib = + getToolChain().getCompilerRT(Args, "builtins", ToolChain::FT_Static); + if (llvm::sys::fs::exists(RtLib)) + CmdArgs.push_back(Args.MakeArgString(RtLib)); + } + + CmdArgs.push_back("--end-group"); + + // Add avr-libc's linker script to lld by default, if it exists. + if (!Args.hasArg(options::OPT_T) && + Linker.find("avr-ld") == std::string::npos) { + std::string Path(*AVRLibcRoot + "/lib/ldscripts/"); + Path += *FamilyName; + Path += ".x"; + if (llvm::sys::fs::exists(Path)) + CmdArgs.push_back(Args.MakeArgString("-T" + Path)); + } + // Otherwise add user specified linker script to either avr-ld or lld. + else + Args.AddAllArgs(CmdArgs, options::OPT_T); + + if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) + CmdArgs.push_back("--relax"); + } else { + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); } + // Specify the family name as the emulation mode to use. + // This is almost always required because otherwise avr-ld + // will assume 'avr2' and warn about the program being larger + // than the bare minimum supports. + if (Linker.find("avr-ld") != std::string::npos && FamilyName) + CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName)); + C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker), CmdArgs, Inputs, Output)); } -llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const { +std::optional<std::string> AVRToolChain::findAVRLibcInstallation() const { + // Search avr-libc installation according to avr-gcc installation. + std::string GCCParent(GCCInstallation.getParentLibPath()); + std::string Path(GCCParent + "/avr"); + if (llvm::sys::fs::is_directory(Path)) + return Path; + Path = GCCParent + "/../avr"; + if (llvm::sys::fs::is_directory(Path)) + return Path; + + // Search avr-libc installation from possible locations, and return the first + // one that exists, if there is no avr-gcc installed. for (StringRef PossiblePath : PossibleAVRLibcLocations) { std::string Path = getDriver().SysRoot + PossiblePath.str(); - // Return the first avr-libc installation that exists. if (llvm::sys::fs::is_directory(Path)) - return Optional<std::string>(Path); + return Path; } - return llvm::None; + return std::nullopt; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h index f612aa691182..247188b7eaad 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AVR.h @@ -11,8 +11,8 @@ #include "Gnu.h" #include "clang/Driver/InputInfo.h" -#include "clang/Driver/ToolChain.h" #include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" namespace clang { namespace driver { @@ -26,28 +26,33 @@ public: AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + + std::optional<std::string> findAVRLibcInstallation() const; + StringRef getGCCInstallPath() const { return GCCInstallPath; } + std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, + FileType Type) const override; + + bool HasNativeLLVMSupport() const override { return true; } + protected: Tool *buildLinker() const override; private: - /// Whether libgcc, libct, and friends should be linked. - /// - /// This is not done if the user does not specify a - /// microcontroller on the command line. - bool LinkStdlib; - - llvm::Optional<std::string> findAVRLibcInstallation() const; + StringRef GCCInstallPath; }; } // end namespace toolchains namespace tools { namespace AVR { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: - Linker(const llvm::Triple &Triple, const ToolChain &TC, bool LinkStdlib) - : Tool("AVR::Linker", "avr-ld", TC), Triple(Triple), - LinkStdlib(LinkStdlib) {} + Linker(const llvm::Triple &Triple, const ToolChain &TC) + : Tool("AVR::Linker", "avr-ld", TC), Triple(Triple) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } @@ -58,7 +63,6 @@ public: protected: const llvm::Triple &Triple; - bool LinkStdlib; }; } // end namespace AVR } // end namespace tools diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp deleted file mode 100644 index be1476a7636c..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp +++ /dev/null @@ -1,144 +0,0 @@ -//===--- Ananas.cpp - Ananas ToolChain Implementations ------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Ananas.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/InputInfo.h" -#include "clang/Driver/Options.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Support/Path.h" - -using namespace clang::driver; -using namespace clang::driver::tools; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - for (const auto &II : Inputs) - CmdArgs.push_back(II.getFilename()); - - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const ToolChain &ToolChain = getToolChain(); - const Driver &D = ToolChain.getDriver(); - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-Bstatic"); - } else { - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-Bshareable"); - } else { - Args.AddAllArgs(CmdArgs, options::OPT_pie); - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back("/lib/ld-ananas.so"); - } - } - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - } - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o"))); - } else { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); - } - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); - - if (D.isUsingLTO()) { - assert(!Inputs.empty() && "Must have at least one input."); - addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], - D.getLTOMode() == LTOK_Thin); - } - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (ToolChain.ShouldLinkCXXStdlib(Args)) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - CmdArgs.push_back("-lc"); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); - else - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); - } - - const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -// Ananas - Ananas tool chain which can call as(1) and ld(1) directly. - -Ananas::Ananas(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); -} - -Tool *Ananas::buildAssembler() const { - return new tools::ananas::Assembler(*this); -} - -Tool *Ananas::buildLinker() const { return new tools::ananas::Linker(*this); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h deleted file mode 100644 index 72ad3edcf056..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.h +++ /dev/null @@ -1,65 +0,0 @@ -//===--- Ananas.h - Ananas ToolChain Implementations --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H - -#include "Gnu.h" -#include "clang/Driver/Tool.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { - -/// ananas -- Directly call GNU Binutils assembler and linker -namespace ananas { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("ananas::Assembler", "assembler", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { -public: - Linker(const ToolChain &TC) : Tool("ananas::Linker", "linker", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace ananas -} // end namespace tools - -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY Ananas : public Generic_ELF { -public: - Ananas(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index ed8c7e94b013..0cf96bb5c9cb 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -7,12 +7,13 @@ //===----------------------------------------------------------------------===// #include "AArch64.h" +#include "../CommonArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/TargetParser.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/AArch64TargetParser.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -37,6 +38,8 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, CPU = Mcpu.split("+").first.lower(); } + CPU = llvm::AArch64::resolveCPUAlias(CPU); + // Handle CPU name is 'native'. if (CPU == "native") return std::string(llvm::sys::getHostCPUName()); @@ -50,13 +53,17 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, return "apple-m1"; } + if (Triple.isXROS()) { + // The xrOS simulator runs on M1 as well, it should have been covered above. + assert(!Triple.isSimulatorEnvironment() && "xrossim should be mac-like"); + return "apple-a12"; + } // arm64e requires v8.3a and only runs on apple-a12 and later CPUs. if (Triple.isArm64e()) return "apple-a12"; - // Make sure we pick the appropriate Apple CPU if -arch is used or when - // targetting a Darwin OS. - if (Args.getLastArg(options::OPT_arch) || Triple.isOSDarwin()) + // Make sure we pick the appropriate Apple CPU when targetting a Darwin OS. + if (Triple.isOSDarwin()) return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4" : "apple-a7"; @@ -65,71 +72,68 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, // Decode AArch64 features from string like +[no]featureA+[no]featureB+... static bool DecodeAArch64Features(const Driver &D, StringRef text, - std::vector<StringRef> &Features, - llvm::AArch64::ArchKind ArchKind) { + llvm::AArch64::ExtensionSet &Extensions) { SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); for (StringRef Feature : Split) { - StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature); - if (!FeatureName.empty()) - Features.push_back(FeatureName); - else if (Feature == "neon" || Feature == "noneon") + if (Feature == "neon" || Feature == "noneon") { D.Diag(clang::diag::err_drv_no_neon_modifier); - else + continue; + } + if (!Extensions.parseModifier(Feature)) return false; - - // +sve implies +f32mm if the base architecture is v8.6A or v8.7A - // it isn't the case in general that sve implies both f64mm and f32mm - if ((ArchKind == llvm::AArch64::ArchKind::ARMV8_6A || - ArchKind == llvm::AArch64::ArchKind::ARMV8_7A) && Feature == "sve") - Features.push_back("+f32mm"); } + return true; } // Check if the CPU name and feature modifiers in -mcpu are legal. If yes, // decode CPU and feature. static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, - std::vector<StringRef> &Features) { + llvm::AArch64::ExtensionSet &Extensions) { std::pair<StringRef, StringRef> Split = Mcpu.split("+"); CPU = Split.first; - llvm::AArch64::ArchKind ArchKind = llvm::AArch64::ArchKind::ARMV8A; if (CPU == "native") CPU = llvm::sys::getHostCPUName(); if (CPU == "generic") { - Features.push_back("+neon"); + Extensions.enable(llvm::AArch64::AEK_SIMD); } else { - ArchKind = llvm::AArch64::parseCPUArch(CPU); - if (!llvm::AArch64::getArchFeatures(ArchKind, Features)) + const std::optional<llvm::AArch64::CpuInfo> CpuInfo = + llvm::AArch64::parseCpu(CPU); + if (!CpuInfo) return false; - uint64_t Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind); - if (!llvm::AArch64::getExtensionFeatures(Extension, Features)) - return false; - } + Extensions.addCPUDefaults(*CpuInfo); + } - if (Split.second.size() && - !DecodeAArch64Features(D, Split.second, Features, ArchKind)) - return false; + if (Split.second.size() && + !DecodeAArch64Features(D, Split.second, Extensions)) + return false; - return true; + return true; } static bool getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, const ArgList &Args, - std::vector<StringRef> &Features) { + llvm::AArch64::ExtensionSet &Extensions) { std::string MarchLowerCase = March.lower(); std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+"); - llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first); - if (ArchKind == llvm::AArch64::ArchKind::INVALID || - !llvm::AArch64::getArchFeatures(ArchKind, Features) || - (Split.second.size() && - !DecodeAArch64Features(D, Split.second, Features, ArchKind))) + const llvm::AArch64::ArchInfo *ArchInfo = + llvm::AArch64::parseArch(Split.first); + if (Split.first == "native") + ArchInfo = llvm::AArch64::getArchForCpu(llvm::sys::getHostCPUName().str()); + if (!ArchInfo) + return false; + + Extensions.addArchDefaults(*ArchInfo); + + if ((Split.second.size() && + !DecodeAArch64Features(D, Split.second, Extensions))) return false; return true; @@ -138,10 +142,10 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, static bool getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, - std::vector<StringRef> &Features) { + llvm::AArch64::ExtensionSet &Extensions) { StringRef CPU; std::string McpuLowerCase = Mcpu.lower(); - if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features)) + if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Extensions)) return false; return true; @@ -152,17 +156,17 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, const ArgList &Args, std::vector<StringRef> &Features) { std::string MtuneLowerCase = Mtune.lower(); - // Check CPU name is valid - std::vector<StringRef> MtuneFeatures; + // Check CPU name is valid, but ignore any extensions on it. + llvm::AArch64::ExtensionSet Extensions; StringRef Tune; - if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures)) + if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, Extensions)) return false; // Handle CPU name is 'native'. if (MtuneLowerCase == "native") MtuneLowerCase = std::string(llvm::sys::getHostCPUName()); if (MtuneLowerCase == "cyclone" || - StringRef(MtuneLowerCase).startswith("apple")) { + StringRef(MtuneLowerCase).starts_with("apple")) { Features.push_back("+zcm"); Features.push_back("+zcz"); } @@ -174,7 +178,8 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, std::vector<StringRef> &Features) { StringRef CPU; - std::vector<StringRef> DecodedFeature; + // Check CPU name is valid, but ignore any extensions on it. + llvm::AArch64::ExtensionSet DecodedFeature; std::string McpuLowerCase = Mcpu.lower(); if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature)) return false; @@ -189,27 +194,31 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, bool ForAS) { Arg *A; bool success = true; - // Enable NEON by default. - Features.push_back("+neon"); - llvm::StringRef WaMArch = ""; + llvm::StringRef WaMArch; + llvm::AArch64::ExtensionSet Extensions; if (ForAS) for (const auto *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) for (StringRef Value : A->getValues()) - if (Value.startswith("-march=")) + if (Value.starts_with("-march=")) WaMArch = Value.substr(7); // Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or // "-Xassembler -march" is detected. Otherwise it may return false // and causes Clang to error out. - if (WaMArch.size()) - success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Features); + if (!WaMArch.empty()) + success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Extensions); else if ((A = Args.getLastArg(options::OPT_march_EQ))) - success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features); + success = + getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Extensions); else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) - success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features); - else if (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple)) + success = + getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Extensions); + else if (isCPUDeterminedByTriple(Triple)) success = getAArch64ArchFeaturesFromMcpu( - D, getAArch64TargetCPU(Args, Triple, A), Args, Features); + D, getAArch64TargetCPU(Args, Triple, A), Args, Extensions); + else + // Default to 'A' profile if the architecture is not specified. + success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Extensions); if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) success = @@ -217,29 +226,48 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ))) success = getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features); - else if (success && - (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple))) + else if (success && isCPUDeterminedByTriple(Triple)) success = getAArch64MicroArchFeaturesFromMcpu( D, getAArch64TargetCPU(Args, Triple, A), Args, Features); - if (!success) - D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); + if (!success) { + 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; + else + Diag << A->getSpelling() << A->getValue(); + } + // -mgeneral-regs-only disables all floating-point features. if (Args.getLastArg(options::OPT_mgeneral_regs_only)) { - Features.push_back("-fp-armv8"); - Features.push_back("-crypto"); - Features.push_back("-neon"); + Extensions.disable(llvm::AArch64::AEK_FP); + } + + // En/disable crc + if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { + if (A->getOption().matches(options::OPT_mcrc)) + Extensions.enable(llvm::AArch64::AEK_CRC); + else + Extensions.disable(llvm::AArch64::AEK_CRC); } + // At this point all hardware features are decided, so convert the extensions + // set to a feature list. + Extensions.toLLVMFeatureList(Features); + if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { StringRef Mtp = A->getValue(); - if (Mtp == "el3") + if (Mtp == "el3" || Mtp == "tpidr_el3") Features.push_back("+tpidr-el3"); - else if (Mtp == "el2") + else if (Mtp == "el2" || Mtp == "tpidr_el2") Features.push_back("+tpidr-el2"); - else if (Mtp == "el1") + else if (Mtp == "el1" || Mtp == "tpidr_el1") Features.push_back("+tpidr-el1"); - else if (Mtp != "el0") + else if (Mtp == "tpidrro_el0") + Features.push_back("+tpidrro-el0"); + else if (Mtp != "el0" && Mtp != "tpidr_el0") D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args); } @@ -275,8 +303,8 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, DisableComdat = true; continue; } - D.Diag(diag::err_invalid_sls_hardening) - << Scope << A->getAsString(Args); + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Scope; break; } } @@ -290,124 +318,6 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, } } - // En/disable crc - if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { - if (A->getOption().matches(options::OPT_mcrc)) - Features.push_back("+crc"); - else - Features.push_back("-crc"); - } - - // Handle (arch-dependent) fp16fml/fullfp16 relationship. - // FIXME: this fp16fml option handling will be reimplemented after the - // TargetParser rewrite. - const auto ItRNoFullFP16 = std::find(Features.rbegin(), Features.rend(), "-fullfp16"); - const auto ItRFP16FML = std::find(Features.rbegin(), Features.rend(), "+fp16fml"); - if (llvm::is_contained(Features, "+v8.4a")) { - const auto ItRFullFP16 = std::find(Features.rbegin(), Features.rend(), "+fullfp16"); - if (ItRFullFP16 < ItRNoFullFP16 && ItRFullFP16 < ItRFP16FML) { - // Only entangled feature that can be to the right of this +fullfp16 is -fp16fml. - // Only append the +fp16fml if there is no -fp16fml after the +fullfp16. - if (std::find(Features.rbegin(), ItRFullFP16, "-fp16fml") == ItRFullFP16) - Features.push_back("+fp16fml"); - } - else - goto fp16_fml_fallthrough; - } else { -fp16_fml_fallthrough: - // In both of these cases, putting the 'other' feature on the end of the vector will - // result in the same effect as placing it immediately after the current feature. - if (ItRNoFullFP16 < ItRFP16FML) - Features.push_back("-fp16fml"); - else if (ItRNoFullFP16 > ItRFP16FML) - Features.push_back("+fullfp16"); - } - - // FIXME: this needs reimplementation too after the TargetParser rewrite - // - // Context sensitive meaning of Crypto: - // 1) For Arch >= ARMv8.4a: crypto = sm4 + sha3 + sha2 + aes - // 2) For Arch <= ARMv8.3a: crypto = sha2 + aes - const auto ItBegin = Features.begin(); - const auto ItEnd = Features.end(); - const auto ItRBegin = Features.rbegin(); - const auto ItREnd = Features.rend(); - const auto ItRCrypto = std::find(ItRBegin, ItREnd, "+crypto"); - const auto ItRNoCrypto = std::find(ItRBegin, ItREnd, "-crypto"); - const auto HasCrypto = ItRCrypto != ItREnd; - const auto HasNoCrypto = ItRNoCrypto != ItREnd; - const ptrdiff_t PosCrypto = ItRCrypto - ItRBegin; - const ptrdiff_t PosNoCrypto = ItRNoCrypto - ItRBegin; - - bool NoCrypto = false; - if (HasCrypto && HasNoCrypto) { - if (PosNoCrypto < PosCrypto) - NoCrypto = true; - } - - if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd) { - if (HasCrypto && !NoCrypto) { - // Check if we have NOT disabled an algorithm with something like: - // +crypto, -algorithm - // And if "-algorithm" does not occur, we enable that crypto algorithm. - const bool HasSM4 = (std::find(ItBegin, ItEnd, "-sm4") == ItEnd); - const bool HasSHA3 = (std::find(ItBegin, ItEnd, "-sha3") == ItEnd); - const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd); - const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd); - if (HasSM4) - Features.push_back("+sm4"); - if (HasSHA3) - Features.push_back("+sha3"); - if (HasSHA2) - Features.push_back("+sha2"); - if (HasAES) - Features.push_back("+aes"); - } else if (HasNoCrypto) { - // Check if we have NOT enabled a crypto algorithm with something like: - // -crypto, +algorithm - // And if "+algorithm" does not occur, we disable that crypto algorithm. - const bool HasSM4 = (std::find(ItBegin, ItEnd, "+sm4") != ItEnd); - const bool HasSHA3 = (std::find(ItBegin, ItEnd, "+sha3") != ItEnd); - const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd); - const bool HasAES = (std::find(ItBegin, ItEnd, "+aes") != ItEnd); - if (!HasSM4) - Features.push_back("-sm4"); - if (!HasSHA3) - Features.push_back("-sha3"); - if (!HasSHA2) - Features.push_back("-sha2"); - if (!HasAES) - Features.push_back("-aes"); - } - } else { - if (HasCrypto && !NoCrypto) { - const bool HasSHA2 = (std::find(ItBegin, ItEnd, "-sha2") == ItEnd); - const bool HasAES = (std::find(ItBegin, ItEnd, "-aes") == ItEnd); - if (HasSHA2) - Features.push_back("+sha2"); - if (HasAES) - Features.push_back("+aes"); - } else if (HasNoCrypto) { - const bool HasSHA2 = (std::find(ItBegin, ItEnd, "+sha2") != ItEnd); - const bool HasAES = (std::find(ItBegin, ItEnd, "+aes") != ItEnd); - const bool HasV82a = (std::find(ItBegin, ItEnd, "+v8.2a") != ItEnd); - const bool HasV83a = (std::find(ItBegin, ItEnd, "+v8.3a") != ItEnd); - const bool HasV84a = (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd); - if (!HasSHA2) - Features.push_back("-sha2"); - if (!HasAES) - Features.push_back("-aes"); - if (HasV82a || HasV83a || HasV84a) { - Features.push_back("-sm4"); - Features.push_back("-sha3"); - } - } - } - - auto V8_6Pos = llvm::find(Features, "+v8.6a"); - if (V8_6Pos != std::end(Features)) - V8_6Pos = Features.insert(std::next(V8_6Pos), {"+i8mm", "+bf16"}); - if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { if (A->getOption().matches(options::OPT_mno_unaligned_access)) @@ -519,4 +429,22 @@ fp16_fml_fallthrough: if (Args.hasArg(options::OPT_mno_neg_immediates)) Features.push_back("+no-neg-immediates"); + + if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769, + options::OPT_mno_fix_cortex_a53_835769)) { + if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769)) + Features.push_back("+fix-cortex-a53-835769"); + else + Features.push_back("-fix-cortex-a53-835769"); + } else if (Triple.isAndroid() || Triple.isOHOSFamily()) { + // Enabled A53 errata (835769) workaround by default on android + Features.push_back("+fix-cortex-a53-835769"); + } else if (Triple.isOSFuchsia()) { + std::string CPU = getCPUName(D, Args, Triple); + if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") + Features.push_back("+fix-cortex-a53-835769"); + } + + if (Args.getLastArg(options::OPT_mno_bti_at_return_twice)) + Features.push_back("+no-bti-at-return-twice"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 4ab547fabe43..e6ee2f88a84e 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -12,8 +12,8 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/TargetParser.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/ARMTargetParser.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -32,6 +32,20 @@ bool arm::isARMMProfile(const llvm::Triple &Triple) { return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M; } +// On Arm the endianness of the output file is determined by the target and +// can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and +// '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a +// normalized triple so we must handle the flag here. +bool arm::isARMBigEndian(const llvm::Triple &Triple, const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, + options::OPT_mbig_endian)) { + return !A->getOption().matches(options::OPT_mlittle_endian); + } + + return Triple.getArch() == llvm::Triple::armeb || + Triple.getArch() == llvm::Triple::thumbeb; +} + // True if A-profile. bool arm::isARMAProfile(const llvm::Triple &Triple) { llvm::StringRef Arch = Triple.getArchName(); @@ -53,9 +67,9 @@ void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, // Use getValues because -Wa can have multiple arguments // e.g. -Wa,-mcpu=foo,-mcpu=bar for (StringRef Value : A->getValues()) { - if (Value.startswith("-mcpu=")) + if (Value.starts_with("-mcpu=")) CPU = Value.substr(6); - if (Value.startswith("-march=")) + if (Value.starts_with("-march=")) Arch = Value.substr(7); } } @@ -72,25 +86,25 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A, } // Handle -mfpu=. -static unsigned getARMFPUFeatures(const Driver &D, const Arg *A, - const ArgList &Args, StringRef FPU, - std::vector<StringRef> &Features) { - unsigned FPUID = llvm::ARM::parseFPU(FPU); - if (!llvm::ARM::getFPUFeatures(FPUID, Features)) +static llvm::ARM::FPUKind getARMFPUFeatures(const Driver &D, const Arg *A, + const ArgList &Args, StringRef FPU, + std::vector<StringRef> &Features) { + llvm::ARM::FPUKind FPUKind = llvm::ARM::parseFPU(FPU); + if (!llvm::ARM::getFPUFeatures(FPUKind, Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); - return FPUID; + return FPUKind; } // Decode ARM features from string like +[no]featureA+[no]featureB+... static bool DecodeARMFeatures(const Driver &D, StringRef text, StringRef CPU, llvm::ARM::ArchKind ArchKind, std::vector<StringRef> &Features, - unsigned &ArgFPUID) { + llvm::ARM::FPUKind &ArgFPUKind) { SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); for (StringRef Feature : Split) { - if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features, ArgFPUID)) + if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features, ArgFPUKind)) return false; } return true; @@ -112,31 +126,52 @@ static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef ArchName, llvm::StringRef CPUName, std::vector<StringRef> &Features, - const llvm::Triple &Triple, unsigned &ArgFPUID) { + const llvm::Triple &Triple, + llvm::ARM::FPUKind &ArgFPUKind) { std::pair<StringRef, StringRef> Split = ArchName.split("+"); std::string MArch = arm::getARMArch(ArchName, Triple); llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch); if (ArchKind == llvm::ARM::ArchKind::INVALID || - (Split.second.size() && !DecodeARMFeatures(D, Split.second, CPUName, - ArchKind, Features, ArgFPUID))) - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + (Split.second.size() && + !DecodeARMFeatures(D, Split.second, CPUName, ArchKind, Features, + ArgFPUKind))) + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << A->getValue(); } // Check -mcpu=. Needs ArchName to handle -mcpu=generic. static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args, llvm::StringRef CPUName, llvm::StringRef ArchName, std::vector<StringRef> &Features, - const llvm::Triple &Triple, unsigned &ArgFPUID) { + const llvm::Triple &Triple, + llvm::ARM::FPUKind &ArgFPUKind) { std::pair<StringRef, StringRef> Split = CPUName.split("+"); std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); llvm::ARM::ArchKind ArchKind = arm::getLLVMArchKindForARM(CPU, ArchName, Triple); if (ArchKind == llvm::ARM::ArchKind::INVALID || - (Split.second.size() && - !DecodeARMFeatures(D, Split.second, CPU, ArchKind, Features, ArgFPUID))) - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + (Split.second.size() && !DecodeARMFeatures(D, Split.second, CPU, ArchKind, + Features, ArgFPUKind))) + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << A->getValue(); +} + +// If -mfloat-abi=hard or -mhard-float are specified explicitly then check that +// floating point registers are available on the target CPU. +static void checkARMFloatABI(const Driver &D, const ArgList &Args, + bool HasFPRegs) { + if (HasFPRegs) + return; + const Arg *A = + Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ); + if (A && (A->getOption().matches(options::OPT_mhard_float) || + (A->getOption().matches(options::OPT_mfloat_abi_EQ) && + A->getValue() == StringRef("hard")))) + D.Diag(clang::diag::warn_drv_no_floating_point_registers) + << A->getAsString(Args); } bool arm::useAAPCSForMachO(const llvm::Triple &T) { @@ -147,14 +182,35 @@ bool arm::useAAPCSForMachO(const llvm::Triple &T) { T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T); } +// We follow GCC and support when the backend has support for the MRC/MCR +// instructions that are used to set the hard thread pointer ("CP15 C13 +// Thread id"). +bool arm::isHardTPSupported(const llvm::Triple &Triple) { + int Ver = getARMSubArchVersionNumber(Triple); + llvm::ARM::ArchKind AK = llvm::ARM::parseArch(Triple.getArchName()); + return Triple.isARM() || AK == llvm::ARM::ArchKind::ARMV6T2 || + (Ver >= 7 && AK != llvm::ARM::ArchKind::ARMV8MBaseline); +} + // Select mode for reading thread pointer (-mtp=soft/cp15). -arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args) { +arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple, bool ForAS) { if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { arm::ReadTPMode ThreadPointer = llvm::StringSwitch<arm::ReadTPMode>(A->getValue()) - .Case("cp15", ReadTPMode::Cp15) + .Case("cp15", ReadTPMode::TPIDRURO) + .Case("tpidrurw", ReadTPMode::TPIDRURW) + .Case("tpidruro", ReadTPMode::TPIDRURO) + .Case("tpidrprw", ReadTPMode::TPIDRPRW) .Case("soft", ReadTPMode::Soft) .Default(ReadTPMode::Invalid); + if ((ThreadPointer == ReadTPMode::TPIDRURW || + ThreadPointer == ReadTPMode::TPIDRURO || + ThreadPointer == ReadTPMode::TPIDRPRW) && + !isHardTPSupported(Triple) && !ForAS) { + D.Diag(diag::err_target_unsupported_tp_hard) << Triple.getArchName(); + return ReadTPMode::Invalid; + } if (ThreadPointer != ReadTPMode::Invalid) return ThreadPointer; if (StringRef(A->getValue()).empty()) @@ -229,9 +285,9 @@ void arm::setArchNameInTriple(const Driver &D, const ArgList &Args, // There is no assembler equivalent of -mno-thumb, -marm, or -mno-arm. if (Value == "-mthumb") IsThumb = true; - else if (Value.startswith("-march=")) + else if (Value.starts_with("-march=")) WaMArch = Value.substr(7); - else if (Value.startswith("-mcpu=")) + else if (Value.starts_with("-mcpu=")) WaMCPU = Value.substr(6); } } @@ -257,6 +313,11 @@ void arm::setArchNameInTriple(const Driver &D, const ArgList &Args, void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args, llvm::Triple &Triple) { + if (Triple.isOSLiteOS()) { + Triple.setEnvironment(llvm::Triple::OpenHOS); + return; + } + bool isHardFloat = (arm::getARMFloatABI(D, Triple, Args) == arm::FloatABI::Hard); @@ -276,6 +337,8 @@ void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args, Triple.setEnvironment(isHardFloat ? llvm::Triple::MuslEABIHF : llvm::Triple::MuslEABI); break; + case llvm::Triple::OpenHOS: + break; default: { arm::FloatABI DefaultABI = arm::getDefaultFloatABI(Triple); if (DefaultABI != arm::FloatABI::Invalid && @@ -303,6 +366,8 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { case llvm::Triple::MacOSX: case llvm::Triple::IOS: case llvm::Triple::TvOS: + case llvm::Triple::DriverKit: + case llvm::Triple::XROS: // Darwin defaults to "softfp" for v6 and v7. if (Triple.isWatchABI()) return FloatABI::Hard; @@ -314,6 +379,10 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { // FIXME: this is invalid for WindowsCE case llvm::Triple::Win32: + // It is incorrect to select hard float ABI on MachO platforms if the ABI is + // "apcs-gnu". + if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(Triple)) + return FloatABI::Soft; return FloatABI::Hard; case llvm::Triple::NetBSD: @@ -336,10 +405,13 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { } break; + case llvm::Triple::Haiku: case llvm::Triple::OpenBSD: return FloatABI::SoftFP; default: + if (Triple.isOHOSFamily()) + return FloatABI::Soft; switch (Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::MuslEABIHF: @@ -412,15 +484,15 @@ static bool hasIntegerMVE(const std::vector<StringRef> &F) { (NoMVE == F.rend() || std::distance(MVE, NoMVE) > 0); } -void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args, ArgStringList &CmdArgs, - std::vector<StringRef> &Features, bool ForAS) { +llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, + std::vector<StringRef> &Features, + bool ForAS, bool ForMultilib) { bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args); - arm::ReadTPMode ThreadPointer = arm::getReadTPMode(D, Args); - llvm::Optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv, - WaArch; + std::optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv, WaArch; // This vector will accumulate features from the architecture // extension suffixes on -mcpu and -march (e.g. the 'bar' in @@ -457,28 +529,38 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, // We use getValues here because you can have many options per -Wa // We will keep the last one we find for each of these for (StringRef Value : A->getValues()) { - if (Value.startswith("-mfpu=")) { + if (Value.starts_with("-mfpu=")) { WaFPU = std::make_pair(A, Value.substr(6)); - } else if (Value.startswith("-mcpu=")) { + } else if (Value.starts_with("-mcpu=")) { WaCPU = std::make_pair(A, Value.substr(6)); - } else if (Value.startswith("-mhwdiv=")) { + } else if (Value.starts_with("-mhwdiv=")) { WaHDiv = std::make_pair(A, Value.substr(8)); - } else if (Value.startswith("-march=")) { + } else if (Value.starts_with("-march=")) { WaArch = std::make_pair(A, Value.substr(7)); } } } + + // The integrated assembler doesn't implement e_flags setting behavior for + // -meabi=gnu (gcc -mabi={apcs-gnu,atpcs} passes -meabi=gnu to gas). For + // compatibility we accept but warn. + if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) + A->ignoreTargetSpecific(); } - if (ThreadPointer == arm::ReadTPMode::Cp15) - Features.push_back("+read-tp-hard"); + if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRURW) + Features.push_back("+read-tp-tpidrurw"); + if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRURO) + Features.push_back("+read-tp-tpidruro"); + if (getReadTPMode(D, Args, Triple, ForAS) == ReadTPMode::TPIDRPRW) + Features.push_back("+read-tp-tpidrprw"); const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); StringRef ArchName; StringRef CPUName; - unsigned ArchArgFPUID = llvm::ARM::FK_INVALID; - unsigned CPUArgFPUID = llvm::ARM::FK_INVALID; + llvm::ARM::FPUKind ArchArgFPUKind = llvm::ARM::FK_INVALID; + llvm::ARM::FPUKind CPUArgFPUKind = llvm::ARM::FK_INVALID; // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. if (WaCPU) { @@ -498,13 +580,13 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, ArchName = WaArch->second; // This will set any features after the base architecture. checkARMArchName(D, WaArch->first, Args, ArchName, CPUName, - ExtensionFeatures, Triple, ArchArgFPUID); + ExtensionFeatures, Triple, ArchArgFPUKind); // The base architecture was handled in ToolChain::ComputeLLVMTriple because // triple is read only by this point. } else if (ArchArg) { ArchName = ArchArg->getValue(); checkARMArchName(D, ArchArg, Args, ArchName, CPUName, ExtensionFeatures, - Triple, ArchArgFPUID); + Triple, ArchArgFPUKind); } // Add CPU features for generic CPUs @@ -524,9 +606,14 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (CPUArg) checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures, - Triple, CPUArgFPUID); + Triple, CPUArgFPUKind); + + // TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a + // longstanding behavior. + (void)Args.getLastArg(options::OPT_mtune_EQ); + // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. - unsigned FPUID = llvm::ARM::FK_INVALID; + llvm::ARM::FPUKind FPUKind = llvm::ARM::FK_INVALID; const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); if (WaFPU) { if (FPUArg) @@ -534,20 +621,25 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, << FPUArg->getAsString(Args); (void)getARMFPUFeatures(D, WaFPU->first, Args, WaFPU->second, Features); } else if (FPUArg) { - FPUID = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); + FPUKind = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); } else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) { const char *AndroidFPU = "neon"; - FPUID = llvm::ARM::parseFPU(AndroidFPU); - if (!llvm::ARM::getFPUFeatures(FPUID, Features)) + FPUKind = llvm::ARM::parseFPU(AndroidFPU); + if (!llvm::ARM::getFPUFeatures(FPUKind, Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << std::string("-mfpu=") + AndroidFPU; + } else if (ArchArgFPUKind != llvm::ARM::FK_INVALID || + CPUArgFPUKind != llvm::ARM::FK_INVALID) { + FPUKind = + CPUArgFPUKind != llvm::ARM::FK_INVALID ? CPUArgFPUKind : ArchArgFPUKind; + (void)llvm::ARM::getFPUFeatures(FPUKind, Features); } else { if (!ForAS) { std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); llvm::ARM::ArchKind ArchKind = arm::getLLVMArchKindForARM(CPU, ArchName, Triple); - FPUID = llvm::ARM::getDefaultFPU(CPU, ArchKind); - (void)llvm::ARM::getFPUFeatures(FPUID, Features); + FPUKind = llvm::ARM::getDefaultFPU(CPU, ArchKind); + (void)llvm::ARM::getFPUFeatures(FPUKind, Features); } } @@ -598,25 +690,30 @@ fp16_fml_fallthrough: // -march/-mcpu effectively disables the FPU (GCC ignores the -mfpu options in // this case). Note that the ABI can also be set implicitly by the target // selected. + bool HasFPRegs = true; if (ABI == arm::FloatABI::Soft) { llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); // Disable all features relating to hardware FP, not already disabled by the // above call. - Features.insert(Features.end(), {"-dotprod", "-fp16fml", "-bf16", "-mve", - "-mve.fp", "-fpregs"}); - } else if (FPUID == llvm::ARM::FK_NONE || - ArchArgFPUID == llvm::ARM::FK_NONE || - CPUArgFPUID == llvm::ARM::FK_NONE) { + Features.insert(Features.end(), + {"-dotprod", "-fp16fml", "-bf16", "-mve", "-mve.fp"}); + HasFPRegs = false; + FPUKind = llvm::ARM::FK_NONE; + } else if (FPUKind == llvm::ARM::FK_NONE || + ArchArgFPUKind == llvm::ARM::FK_NONE || + CPUArgFPUKind == llvm::ARM::FK_NONE) { // -mfpu=none, -march=armvX+nofp or -mcpu=X+nofp is *very* similar to // -mfloat-abi=soft, only that it should not disable MVE-I. They disable the // FPU, but not the FPU registers, thus MVE-I, which depends only on the // latter, is still supported. Features.insert(Features.end(), {"-dotprod", "-fp16fml", "-bf16", "-mve.fp"}); - if (!hasIntegerMVE(Features)) - Features.emplace_back("-fpregs"); + HasFPRegs = hasIntegerMVE(Features); + FPUKind = llvm::ARM::FK_NONE; } + if (!HasFPRegs) + Features.emplace_back("-fpregs"); // En/disable crc code generation. if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { @@ -697,10 +794,41 @@ fp16_fml_fallthrough: } } + // Propagate frame-chain model selection + if (Arg *A = Args.getLastArg(options::OPT_mframe_chain)) { + StringRef FrameChainOption = A->getValue(); + if (FrameChainOption.starts_with("aapcs")) + Features.push_back("+aapcs-frame-chain"); + if (FrameChainOption == "aapcs+leaf") + Features.push_back("+aapcs-frame-chain-leaf"); + } + // CMSE: Check for target 8M (for -mcmse to be applicable) is performed later. if (Args.getLastArg(options::OPT_mcmse)) Features.push_back("+8msecext"); + if (Arg *A = Args.getLastArg(options::OPT_mfix_cmse_cve_2021_35465, + options::OPT_mno_fix_cmse_cve_2021_35465)) { + if (!Args.getLastArg(options::OPT_mcmse)) + D.Diag(diag::err_opt_not_valid_without_opt) + << A->getOption().getName() << "-mcmse"; + + if (A->getOption().matches(options::OPT_mfix_cmse_cve_2021_35465)) + Features.push_back("+fix-cmse-cve-2021-35465"); + else + 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. @@ -709,39 +837,42 @@ fp16_fml_fallthrough: if (A->getOption().matches(options::OPT_mlong_calls)) Features.push_back("+long-calls"); } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) && - !Triple.isWatchOS()) { - Features.push_back("+long-calls"); + !Triple.isWatchOS() && !Triple.isXROS()) { + Features.push_back("+long-calls"); } // Generate execute-only output (no data access to code sections). // This only makes sense for the compiler, not for the assembler. - if (!ForAS) { + // It's not needed for multilib selection and may hide an unused + // argument diagnostic if the code is always run. + if (!ForAS && !ForMultilib) { // Supported only on ARMv6T2 and ARMv7 and above. - // Cannot be combined with -mno-movt or -mlong-calls + // Cannot be combined with -mno-movt. if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { if (A->getOption().matches(options::OPT_mexecute_only)) { if (getARMSubArchVersionNumber(Triple) < 7 && - llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2) + llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2 && + llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6M) D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); - else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) - D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); - // Long calls create constant pool entries and have not yet been fixed up - // to play nicely with execute-only. Hence, they cannot be used in - // execute-only code for now - else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) { - if (B->getOption().matches(options::OPT_mlong_calls)) - D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); - } + else if (llvm::ARM::parseArch(Triple.getArchName()) == llvm::ARM::ArchKind::ARMV6M) { + if (Arg *PIArg = Args.getLastArg(options::OPT_fropi, options::OPT_frwpi, + options::OPT_fpic, options::OPT_fpie, + options::OPT_fPIC, options::OPT_fPIE)) + D.Diag(diag::err_opt_not_valid_with_opt_on_target) + << A->getAsString(Args) << PIArg->getAsString(Args) << Triple.getArchName(); + } else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) + D.Diag(diag::err_opt_not_valid_with_opt) + << A->getAsString(Args) << B->getAsString(Args); Features.push_back("+execute-only"); } } } // Kernel code has more strict alignment requirements. - if (KernelOrKext) + if (KernelOrKext) { Features.push_back("+strict-align"); - else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, - options::OPT_munaligned_access)) { + } else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, + options::OPT_munaligned_access)) { if (A->getOption().matches(options::OPT_munaligned_access)) { // No v6M core supports unaligned memory access (v6M ARM ARM A3.2). if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) @@ -763,7 +894,8 @@ fp16_fml_fallthrough: // which raises an alignment fault on unaligned accesses. Linux // defaults this bit to 0 and handles it as a system-wide (not // per-process) setting. It is therefore safe to assume that ARMv7+ - // Linux targets support unaligned accesses. The same goes for NaCl. + // Linux targets support unaligned accesses. The same goes for NaCl + // and Windows. // // The above behavior is consistent with GCC. int VersionNum = getARMSubArchVersionNumber(Triple); @@ -771,7 +903,8 @@ fp16_fml_fallthrough: if (VersionNum < 6 || Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) Features.push_back("+strict-align"); - } else if (Triple.isOSLinux() || Triple.isOSNaCl()) { + } else if (Triple.isOSLinux() || Triple.isOSNaCl() || + Triple.isOSWindows()) { if (VersionNum < 7) Features.push_back("+strict-align"); } else @@ -823,8 +956,8 @@ fp16_fml_fallthrough: DisableComdat = true; continue; } - D.Diag(diag::err_invalid_sls_hardening) - << Scope << A->getAsString(Args); + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Scope; break; } } @@ -843,9 +976,15 @@ fp16_fml_fallthrough: } } + if (Args.getLastArg(options::OPT_mno_bti_at_return_twice)) + Features.push_back("+no-bti-at-return-twice"); + + checkARMFloatABI(D, Args, HasFPRegs); + + return FPUKind; } -const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { +std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { std::string MArch; if (!Arch.empty()) MArch = std::string(Arch); @@ -881,7 +1020,7 @@ StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { // We need to return an empty string here on invalid MArch values as the // various places that call this function can't cope with a null result. - return Triple.getARMCPUForArch(MArch); + return llvm::ARM::getARMCPUForArch(Triple, MArch); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. @@ -914,7 +1053,8 @@ llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch, if (ArchKind == llvm::ARM::ArchKind::INVALID) // In case of generic Arch, i.e. "arm", // extract arch from default cpu of the Triple - ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch)); + ArchKind = + llvm::ARM::parseCPUArch(llvm::ARM::getARMCPUForArch(Triple, ARMArch)); } else { // FIXME: horrible hack to get around the fact that Cortex-A7 is only an // armv7k triple if it's actually been specified via "-arch armv7k". diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h index 8e7c10ecd5d6..fa62ac89e3a1 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -11,9 +11,10 @@ #include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" +#include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/TargetParser/ARMTargetParser.h" +#include "llvm/TargetParser/Triple.h" #include <string> #include <vector> @@ -24,7 +25,7 @@ namespace arm { std::string getARMTargetCPU(StringRef CPU, llvm::StringRef Arch, const llvm::Triple &Triple); -const std::string getARMArch(llvm::StringRef Arch, const llvm::Triple &Triple); +std::string getARMArch(llvm::StringRef Arch, const llvm::Triple &Triple); StringRef getARMCPUForMArch(llvm::StringRef Arch, const llvm::Triple &Triple); llvm::ARM::ArchKind getLLVMArchKindForARM(StringRef CPU, StringRef Arch, const llvm::Triple &Triple); @@ -37,7 +38,9 @@ void appendBE8LinkFlag(const llvm::opt::ArgList &Args, enum class ReadTPMode { Invalid, Soft, - Cp15, + TPIDRURW, + TPIDRURO, + TPIDRPRW, }; enum class FloatABI { @@ -53,7 +56,9 @@ FloatABI getARMFloatABI(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); void setFloatABIInTriple(const Driver &D, const llvm::opt::ArgList &Args, llvm::Triple &triple); -ReadTPMode getReadTPMode(const Driver &D, const llvm::opt::ArgList &Args); +bool isHardTPSupported(const llvm::Triple &Triple); +ReadTPMode getReadTPMode(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &Triple, bool ForAS); void setArchNameInTriple(const Driver &D, const llvm::opt::ArgList &Args, types::ID InputType, llvm::Triple &Triple); @@ -61,13 +66,15 @@ bool useAAPCSForMachO(const llvm::Triple &T); void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args, llvm::StringRef &Arch, llvm::StringRef &CPU, bool FromAs = false); -void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - std::vector<llvm::StringRef> &Features, bool ForAS); +llvm::ARM::FPUKind getARMTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features, + bool ForAS, bool ForMultilib = false); int getARMSubArchVersionNumber(const llvm::Triple &Triple); bool isARMMProfile(const llvm::Triple &Triple); bool isARMAProfile(const llvm::Triple &Triple); +bool isARMBigEndian(const llvm::Triple &Triple, const llvm::opt::ArgList &Args); } // end namespace arm } // end namespace tools diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp new file mode 100644 index 000000000000..e94ea12f46dc --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.cpp @@ -0,0 +1,169 @@ +//===--- CSKY.cpp - CSKY Helpers for Tools --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CSKY.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/CSKYTargetParser.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/TargetParser.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +std::optional<llvm::StringRef> +csky::getCSKYArchName(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseArch(A->getValue()); + + if (ArchKind == llvm::CSKY::ArchKind::INVALID) { + D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args); + return std::nullopt; + } + return std::optional<llvm::StringRef>(A->getValue()); + } + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { + llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseCPUArch(A->getValue()); + if (ArchKind == llvm::CSKY::ArchKind::INVALID) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return std::nullopt; + } + return std::optional<llvm::StringRef>(llvm::CSKY::getArchName(ArchKind)); + } + + return std::optional<llvm::StringRef>("ck810"); +} + +csky::FloatABI csky::getCSKYFloatABI(const Driver &D, const ArgList &Args) { + csky::FloatABI ABI = FloatABI::Soft; + if (Arg *A = + Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ)) { + if (A->getOption().matches(options::OPT_msoft_float)) { + ABI = FloatABI::Soft; + } else if (A->getOption().matches(options::OPT_mhard_float)) { + ABI = FloatABI::Hard; + } else { + ABI = llvm::StringSwitch<csky::FloatABI>(A->getValue()) + .Case("soft", FloatABI::Soft) + .Case("softfp", FloatABI::SoftFP) + .Case("hard", FloatABI::Hard) + .Default(FloatABI::Invalid); + if (ABI == FloatABI::Invalid) { + D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); + ABI = FloatABI::Soft; + } + } + } + + return ABI; +} + +// Handle -mfpu=. +static llvm::CSKY::CSKYFPUKind +getCSKYFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args, + StringRef FPU, std::vector<StringRef> &Features) { + + llvm::CSKY::CSKYFPUKind FPUID = + llvm::StringSwitch<llvm::CSKY::CSKYFPUKind>(FPU) + .Case("auto", llvm::CSKY::FK_AUTO) + .Case("fpv2", llvm::CSKY::FK_FPV2) + .Case("fpv2_divd", llvm::CSKY::FK_FPV2_DIVD) + .Case("fpv2_sf", llvm::CSKY::FK_FPV2_SF) + .Case("fpv3", llvm::CSKY::FK_FPV3) + .Case("fpv3_hf", llvm::CSKY::FK_FPV3_HF) + .Case("fpv3_hsf", llvm::CSKY::FK_FPV3_HSF) + .Case("fpv3_sdf", llvm::CSKY::FK_FPV3_SDF) + .Default(llvm::CSKY::FK_INVALID); + if (FPUID == llvm::CSKY::FK_INVALID) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return llvm::CSKY::FK_INVALID; + } + + auto RemoveTargetFPUFeature = + [&Features](ArrayRef<const char *> FPUFeatures) { + for (auto FPUFeature : FPUFeatures) { + auto it = llvm::find(Features, FPUFeature); + if (it != Features.end()) + Features.erase(it); + } + }; + + RemoveTargetFPUFeature({"+fpuv2_sf", "+fpuv2_df", "+fdivdu", "+fpuv3_hi", + "+fpuv3_hf", "+fpuv3_sf", "+fpuv3_df"}); + + if (!llvm::CSKY::getFPUFeatures(FPUID, Features)) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return llvm::CSKY::FK_INVALID; + } + + return FPUID; +} + +void csky::getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, ArgStringList &CmdArgs, + std::vector<llvm::StringRef> &Features) { + llvm::StringRef archName; + llvm::StringRef cpuName; + llvm::CSKY::ArchKind ArchKind = llvm::CSKY::ArchKind::INVALID; + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + ArchKind = llvm::CSKY::parseArch(A->getValue()); + if (ArchKind == llvm::CSKY::ArchKind::INVALID) { + D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args); + return; + } + archName = A->getValue(); + } + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { + llvm::CSKY::ArchKind Kind = llvm::CSKY::parseCPUArch(A->getValue()); + if (Kind == llvm::CSKY::ArchKind::INVALID) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return; + } + if (!archName.empty() && Kind != ArchKind) { + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return; + } + cpuName = A->getValue(); + if (archName.empty()) + archName = llvm::CSKY::getArchName(Kind); + } + + if (archName.empty() && cpuName.empty()) { + archName = "ck810"; + cpuName = "ck810"; + } else if (!archName.empty() && cpuName.empty()) { + cpuName = archName; + } + + csky::FloatABI FloatABI = csky::getCSKYFloatABI(D, Args); + + if (FloatABI == csky::FloatABI::Hard) { + Features.push_back("+hard-float-abi"); + Features.push_back("+hard-float"); + } else if (FloatABI == csky::FloatABI::SoftFP) { + Features.push_back("+hard-float"); + } + + uint64_t Extension = llvm::CSKY::getDefaultExtensions(cpuName); + llvm::CSKY::getExtensionFeatures(Extension, Features); + + if (const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ)) + getCSKYFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h new file mode 100644 index 000000000000..f3730d2cf4a1 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/CSKY.h @@ -0,0 +1,47 @@ +//===--- CSKY.h - CSKY-specific Tool Helpers ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CSKY_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CSKY_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace csky { + +enum class FloatABI { + Invalid, + Soft, + SoftFP, + Hard, +}; + +FloatABI getCSKYFloatABI(const Driver &D, const llvm::opt::ArgList &Args); + +void getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + std::vector<llvm::StringRef> &Features); + +std::optional<llvm::StringRef> getCSKYArchName(const Driver &D, + const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); + +} // end namespace csky +} // namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CSKY_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp new file mode 100644 index 000000000000..31153a67ad28 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp @@ -0,0 +1,232 @@ +//===--- LoongArch.cpp - LoongArch Helpers for Tools ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LoongArch.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Basic/DiagnosticDriver.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/LoongArchTargetParser.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + assert((Triple.getArch() == llvm::Triple::loongarch32 || + Triple.getArch() == llvm::Triple::loongarch64) && + "Unexpected triple"); + bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32; + + // Record -mabi value for later use. + const Arg *MABIArg = Args.getLastArg(options::OPT_mabi_EQ); + StringRef MABIValue; + if (MABIArg) { + MABIValue = MABIArg->getValue(); + } + + // Parse -mfpu value for later use. + const Arg *MFPUArg = Args.getLastArg(options::OPT_mfpu_EQ); + int FPU = -1; + if (MFPUArg) { + StringRef V = MFPUArg->getValue(); + if (V == "64") + FPU = 64; + else if (V == "32") + FPU = 32; + else if (V == "0" || V == "none") + FPU = 0; + else + D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << V; + } + + // Check -m*-float firstly since they have highest priority. + if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float, + options::OPT_msingle_float, + options::OPT_msoft_float)) { + StringRef ImpliedABI; + int ImpliedFPU = -1; + if (A->getOption().matches(options::OPT_mdouble_float)) { + ImpliedABI = IsLA32 ? "ilp32d" : "lp64d"; + ImpliedFPU = 64; + } + if (A->getOption().matches(options::OPT_msingle_float)) { + ImpliedABI = IsLA32 ? "ilp32f" : "lp64f"; + ImpliedFPU = 32; + } + if (A->getOption().matches(options::OPT_msoft_float)) { + ImpliedABI = IsLA32 ? "ilp32s" : "lp64s"; + ImpliedFPU = 0; + } + + // Check `-mabi=` and `-mfpu=` settings and report if they conflict with + // the higher-priority settings implied by -m*-float. + // + // ImpliedABI and ImpliedFPU are guaranteed to have valid values because + // one of the match arms must match if execution can arrive here at all. + if (!MABIValue.empty() && ImpliedABI != MABIValue) + D.Diag(diag::warn_drv_loongarch_conflicting_implied_val) + << MABIArg->getAsString(Args) << A->getAsString(Args) << ImpliedABI; + + if (FPU != -1 && ImpliedFPU != FPU) + D.Diag(diag::warn_drv_loongarch_conflicting_implied_val) + << MFPUArg->getAsString(Args) << A->getAsString(Args) << ImpliedFPU; + + return ImpliedABI; + } + + // If `-mabi=` is specified, use it. + if (!MABIValue.empty()) + return MABIValue; + + // Select abi based on -mfpu=xx. + switch (FPU) { + case 64: + return IsLA32 ? "ilp32d" : "lp64d"; + case 32: + return IsLA32 ? "ilp32f" : "lp64f"; + case 0: + return IsLA32 ? "ilp32s" : "lp64s"; + } + + // Choose a default based on the triple. + // Honor the explicit ABI modifier suffix in triple's environment part if + // present, falling back to {ILP32,LP64}D otherwise. + switch (Triple.getEnvironment()) { + case llvm::Triple::GNUSF: + return IsLA32 ? "ilp32s" : "lp64s"; + case llvm::Triple::GNUF32: + return IsLA32 ? "ilp32f" : "lp64f"; + case llvm::Triple::GNUF64: + // This was originally permitted (and indeed the canonical way) to + // represent the {ILP32,LP64}D ABIs, but in Feb 2023 Loongson decided to + // drop the explicit suffix in favor of unmarked `-gnu` for the + // "general-purpose" ABIs, among other non-technical reasons. + // + // The spec change did not mention whether existing usages of "gnuf64" + // shall remain valid or not, so we are going to continue recognizing it + // for some time, until it is clear that everyone else has migrated away + // from it. + [[fallthrough]]; + case llvm::Triple::GNU: + default: + return IsLA32 ? "ilp32d" : "lp64d"; + } +} + +void loongarch::getLoongArchTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, + std::vector<StringRef> &Features) { + std::string ArchName; + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + ArchName = A->getValue(); + ArchName = postProcessTargetCPUString(ArchName, Triple); + llvm::LoongArch::getArchFeatures(ArchName, Features); + + // Select floating-point features determined by -mdouble-float, + // -msingle-float, -msoft-float and -mfpu. + // Note: -m*-float wins any other options. + if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float, + options::OPT_msingle_float, + options::OPT_msoft_float)) { + if (A->getOption().matches(options::OPT_mdouble_float)) { + Features.push_back("+f"); + Features.push_back("+d"); + } else if (A->getOption().matches(options::OPT_msingle_float)) { + Features.push_back("+f"); + Features.push_back("-d"); + } else /*Soft-float*/ { + Features.push_back("-f"); + Features.push_back("-d"); + } + } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) { + StringRef FPU = A->getValue(); + if (FPU == "64") { + Features.push_back("+f"); + Features.push_back("+d"); + } else if (FPU == "32") { + Features.push_back("+f"); + Features.push_back("-d"); + } else if (FPU == "0" || FPU == "none") { + Features.push_back("-f"); + Features.push_back("-d"); + } else { + D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU; + } + } + + // Select the `ual` feature determined by -m[no-]unaligned-access + // or the alias -m[no-]strict-align. + AddTargetFeature(Args, Features, options::OPT_munaligned_access, + options::OPT_mno_unaligned_access, "ual"); + + // Accept but warn about these TargetSpecific options. + if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) + A->ignoreTargetSpecific(); + if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ)) + A->ignoreTargetSpecific(); + + // Select lsx feature determined by -m[no-]lsx. + if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) { + // LSX depends on 64-bit FPU. + // -m*-float and -mfpu=none/0/32 conflict with -mlsx. + if (A->getOption().matches(options::OPT_mlsx)) { + if (llvm::find(Features, "-d") != Features.end()) + D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lsx); + else /*-mlsx*/ + Features.push_back("+lsx"); + } else /*-mno-lsx*/ { + Features.push_back("-lsx"); + } + } + + // Select lasx feature determined by -m[no-]lasx. + if (const Arg *A = + Args.getLastArg(options::OPT_mlasx, options::OPT_mno_lasx)) { + // LASX depends on 64-bit FPU and LSX. + // -mno-lsx conflicts with -mlasx. + if (A->getOption().matches(options::OPT_mlasx)) { + if (llvm::find(Features, "-d") != Features.end()) + D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lasx); + else if (llvm::find(Features, "-lsx") != Features.end()) + D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination); + else { /*-mlasx*/ + Features.push_back("+lsx"); + Features.push_back("+lasx"); + } + } else /*-mno-lasx*/ + Features.push_back("-lasx"); + } +} + +std::string loongarch::postProcessTargetCPUString(const std::string &CPU, + const llvm::Triple &Triple) { + std::string CPUString = CPU; + if (CPUString == "native") { + CPUString = llvm::sys::getHostCPUName(); + if (CPUString == "generic") + CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64()); + } + if (CPUString.empty()) + CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64()); + return CPUString; +} + +std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + std::string CPU; + // If we have -march, use that. + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + CPU = A->getValue(); + return postProcessTargetCPUString(CPU, Triple); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h new file mode 100644 index 000000000000..d8280cd836f8 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.h @@ -0,0 +1,37 @@ +//===--- LoongArch.h - LoongArch-specific Tool Helpers ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" + +namespace clang { +namespace driver { +namespace tools { +namespace loongarch { +void getLoongArchTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features); + +StringRef getLoongArchABI(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); + +std::string postProcessTargetCPUString(const std::string &CPU, + const llvm::Triple &Triple); + +std::string getLoongArchTargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); +} // end namespace loongarch +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp index 119e24cedbab..963f7a187d63 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.cpp @@ -14,8 +14,8 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Host.h" #include "llvm/Support/Regex.h" +#include "llvm/TargetParser/Host.h" #include <sstream> using namespace clang::driver; @@ -65,13 +65,35 @@ std::string m68k::getM68kTargetCPU(const ArgList &Args) { return ""; } +static void addFloatABIFeatures(const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features) { + Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_m68881); + // Opt out FPU even for newer CPUs. + if (A && A->getOption().matches(options::OPT_msoft_float)) { + Features.push_back("-isa-68881"); + Features.push_back("-isa-68882"); + return; + } + + std::string CPU = m68k::getM68kTargetCPU(Args); + // Only enable M68881 for CPU < 68020 if the related flags are present. + if ((A && (CPU == "M68000" || CPU == "M68010")) || + // Otherwise, by default we assume newer CPUs have M68881/2. + CPU == "M68020") + Features.push_back("+isa-68881"); + else if (CPU == "M68030" || CPU == "M68040" || CPU == "M68060") + // Note that although CPU >= M68040 imply M68882, we still add `isa-68882` + // anyway so that it's easier to add or not add the corresponding macro + // definitions later, in case we want to disable 68881/2 in newer CPUs + // (with -msoft-float, for instance). + Features.push_back("+isa-68882"); +} + void m68k::getM68kTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { - - m68k::FloatABI FloatABI = m68k::getM68kFloatABI(D, Args); - if (FloatABI == m68k::FloatABI::Soft) - Features.push_back("-hard-float"); + addFloatABIFeatures(Args, Features); // Handle '-ffixed-<register>' flags if (Args.hasArg(options::OPT_ffixed_a0)) @@ -105,21 +127,3 @@ void m68k::getM68kTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Args.hasArg(options::OPT_ffixed_d7)) Features.push_back("+reserve-d7"); } - -m68k::FloatABI m68k::getM68kFloatABI(const Driver &D, const ArgList &Args) { - m68k::FloatABI ABI = m68k::FloatABI::Invalid; - if (Arg *A = - Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { - - if (A->getOption().matches(options::OPT_msoft_float)) - ABI = m68k::FloatABI::Soft; - else if (A->getOption().matches(options::OPT_mhard_float)) - ABI = m68k::FloatABI::Hard; - } - - // If unspecified, choose the default based on the platform. - if (ABI == m68k::FloatABI::Invalid) - ABI = m68k::FloatABI::Hard; - - return ABI; -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h index 41d53efb940b..051e7e1af103 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/M68k.h @@ -20,14 +20,6 @@ namespace driver { namespace tools { namespace m68k { -enum class FloatABI { - Invalid, - Soft, - Hard, -}; - -FloatABI getM68kFloatABI(const Driver &D, const llvm::opt::ArgList &Args); - std::string getM68kTargetCPU(const llvm::opt::ArgList &Args); void getM68kTargetFeatures(const Driver &D, const llvm::Triple &Triple, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp index 5a509dbb2bd3..fe9d112b8800 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -39,12 +39,6 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, DefMips64CPU = "mips64r6"; } - // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android). - if (Triple.isAndroid()) { - DefMips32CPU = "mips32"; - DefMips64CPU = "mips64r6"; - } - // MIPS3 is the default for mips64*-unknown-openbsd. if (Triple.isOSOpenBSD()) DefMips64CPU = "mips3"; @@ -227,6 +221,7 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, bool IsN64 = ABIName == "64"; bool IsPIC = false; bool NonPIC = false; + bool HasNaN2008Opt = false; Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, @@ -291,9 +286,10 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { StringRef Val = StringRef(A->getValue()); if (Val == "2008") { - if (mips::getIEEE754Standard(CPUName) & mips::Std2008) + if (mips::getIEEE754Standard(CPUName) & mips::Std2008) { Features.push_back("+nan2008"); - else { + HasNaN2008Opt = true; + } else { Features.push_back("-nan2008"); D.Diag(diag::warn_target_unsupported_nan2008) << CPUName; } @@ -306,7 +302,7 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, } } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) { @@ -327,8 +323,10 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, } } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } + } else if (HasNaN2008Opt) { + Features.push_back("+abs2008"); } AddTargetFeature(Args, Features, options::OPT_msingle_float, @@ -441,7 +439,8 @@ bool mips::isUCLibc(const ArgList &Args) { return A && A->getOption().matches(options::OPT_muclibc); } -bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { +bool mips::isNaN2008(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ)) return llvm::StringSwitch<bool>(NaNArg->getValue()) .Case("2008", true) @@ -449,7 +448,7 @@ bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { .Default(false); // NaN2008 is the default for MIPS32r6/MIPS64r6. - return llvm::StringSwitch<bool>(getCPUName(Args, Triple)) + return llvm::StringSwitch<bool>(getCPUName(D, Args, Triple)) .Cases("mips32r6", "mips64r6", true) .Default(false); } @@ -466,11 +465,6 @@ bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) { bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI) { - if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies && - Triple.getVendor() != llvm::Triple::MipsTechnologies && - !Triple.isAndroid()) - return false; - if (ABIName != "32") return false; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h index 074012f40fe5..62211c711420 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.h @@ -11,8 +11,8 @@ #include "clang/Driver/Driver.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" +#include "llvm/TargetParser/Triple.h" #include <string> #include <vector> @@ -44,7 +44,8 @@ std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value); bool isUCLibc(const llvm::opt::ArgList &Args); -bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +bool isNaN2008(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); bool isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName); bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp index bcaecf4b2d98..ab24d14992cd 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -13,81 +13,83 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting. -std::string ppc::getPPCTargetCPU(const ArgList &Args) { - if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { - StringRef CPUName = A->getValue(); - - if (CPUName == "native") { - std::string CPU = std::string(llvm::sys::getHostCPUName()); - if (!CPU.empty() && CPU != "generic") - return CPU; - else - return ""; - } +static std::string getPPCGenericTargetCPU(const llvm::Triple &T) { + // LLVM may default to generating code for the native CPU, + // but, like gcc, we default to a more generic option for + // each architecture. (except on AIX) + if (T.isOSAIX()) + return "pwr7"; + else if (T.getArch() == llvm::Triple::ppc64le) + return "ppc64le"; + else if (T.getArch() == llvm::Triple::ppc64) + return "ppc64"; + else + return "ppc"; +} - return llvm::StringSwitch<const char *>(CPUName) - .Case("common", "generic") - .Case("440", "440") - .Case("440fp", "440") - .Case("450", "450") - .Case("601", "601") - .Case("602", "602") - .Case("603", "603") - .Case("603e", "603e") - .Case("603ev", "603ev") - .Case("604", "604") - .Case("604e", "604e") - .Case("620", "620") - .Case("630", "pwr3") - .Case("G3", "g3") - .Case("7400", "7400") - .Case("G4", "g4") - .Case("7450", "7450") - .Case("G4+", "g4+") - .Case("750", "750") - .Case("8548", "e500") - .Case("970", "970") - .Case("G5", "g5") - .Case("a2", "a2") - .Case("e500", "e500") - .Case("e500mc", "e500mc") - .Case("e5500", "e5500") - .Case("power3", "pwr3") - .Case("power4", "pwr4") - .Case("power5", "pwr5") - .Case("power5x", "pwr5x") - .Case("power6", "pwr6") - .Case("power6x", "pwr6x") - .Case("power7", "pwr7") - .Case("power8", "pwr8") - .Case("power9", "pwr9") - .Case("power10", "pwr10") - .Case("future", "future") - .Case("pwr3", "pwr3") - .Case("pwr4", "pwr4") - .Case("pwr5", "pwr5") - .Case("pwr5x", "pwr5x") - .Case("pwr6", "pwr6") - .Case("pwr6x", "pwr6x") - .Case("pwr7", "pwr7") - .Case("pwr8", "pwr8") - .Case("pwr9", "pwr9") - .Case("pwr10", "pwr10") - .Case("powerpc", "ppc") - .Case("powerpc64", "ppc64") - .Case("powerpc64le", "ppc64le") - .Default(""); +static std::string normalizeCPUName(StringRef CPUName, const llvm::Triple &T) { + // Clang/LLVM does not actually support code generation + // for the 405 CPU. However, there are uses of this CPU ID + // in projects that previously used GCC and rely on Clang + // accepting it. Clang has always ignored it and passed the + // generic CPU ID to the back end. + if (CPUName == "generic" || CPUName == "405") + return getPPCGenericTargetCPU(T); + + if (CPUName == "native") { + std::string CPU = std::string(llvm::sys::getHostCPUName()); + if (!CPU.empty() && CPU != "generic") + return CPU; + else + return getPPCGenericTargetCPU(T); } - return ""; + return llvm::StringSwitch<const char *>(CPUName) + .Case("common", "generic") + .Case("440fp", "440") + .Case("630", "pwr3") + .Case("G3", "g3") + .Case("G4", "g4") + .Case("G4+", "g4+") + .Case("8548", "e500") + .Case("G5", "g5") + .Case("power3", "pwr3") + .Case("power4", "pwr4") + .Case("power5", "pwr5") + .Case("power5x", "pwr5x") + .Case("power6", "pwr6") + .Case("power6x", "pwr6x") + .Case("power7", "pwr7") + .Case("power8", "pwr8") + .Case("power9", "pwr9") + .Case("power10", "pwr10") + .Case("future", "future") + .Case("powerpc", "ppc") + .Case("powerpc64", "ppc64") + .Case("powerpc64le", "ppc64le") + .Default(CPUName.data()); +} + +/// Get the (LLVM) name of the PowerPC cpu we are tuning for. +std::string ppc::getPPCTuneCPU(const ArgList &Args, const llvm::Triple &T) { + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) + return normalizeCPUName(A->getValue(), T); + return getPPCGenericTargetCPU(T); +} + +/// Get the (LLVM) name of the PowerPC cpu we are targeting. +std::string ppc::getPPCTargetCPU(const Driver &D, const ArgList &Args, + const llvm::Triple &T) { + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) + return normalizeCPUName(A->getValue(), T); + return getPPCGenericTargetCPU(T); } const char *ppc::getPPCAsmModeForCPU(StringRef Name) { @@ -110,7 +112,8 @@ void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe) Features.push_back("+spe"); - handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_ppc_Features_Group); ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); if (FloatABI == ppc::FloatABI::Soft) @@ -125,8 +128,7 @@ ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Tripl const ArgList &Args) { if (Args.getLastArg(options::OPT_msecure_plt)) return ppc::ReadGOTPtrMode::SecurePlt; - if ((Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 13) || - Triple.isOSNetBSD() || Triple.isOSOpenBSD() || Triple.isMusl()) + if (Triple.isPPC32SecurePlt()) return ppc::ReadGOTPtrMode::SecurePlt; else return ppc::ReadGOTPtrMode::Bss; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h index e1c943955e81..ec5b3c8140b6 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/PPC.h @@ -35,7 +35,10 @@ enum class ReadGOTPtrMode { FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args); -std::string getPPCTargetCPU(const llvm::opt::ArgList &Args); +std::string getPPCTargetCPU(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &T); +std::string getPPCTuneCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &T); const char *getPPCAsmModeForCPU(StringRef Name); ReadGOTPtrMode getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 2c2404acc54d..47b29e1577c2 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -1,4 +1,4 @@ -//===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===// +//===--- RISCV.cpp - RISC-V Helpers for Tools -------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,476 +7,69 @@ //===----------------------------------------------------------------------===// #include "RISCV.h" +#include "../Clang.h" +#include "ToolChains/CommonArgs.h" #include "clang/Basic/CharInfo.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" -#include "llvm/ADT/Optional.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/raw_ostream.h" -#include "ToolChains/CommonArgs.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/RISCVTargetParser.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -namespace { -// Represents the major and version number components of a RISC-V extension -struct RISCVExtensionVersion { - StringRef Major; - StringRef Minor; -}; -} // end anonymous namespace - -static StringRef getExtensionTypeDesc(StringRef Ext) { - if (Ext.startswith("sx")) - return "non-standard supervisor-level extension"; - if (Ext.startswith("s")) - return "standard supervisor-level extension"; - if (Ext.startswith("x")) - return "non-standard user-level extension"; - if (Ext.startswith("z")) - return "standard user-level extension"; - return StringRef(); -} - -static StringRef getExtensionType(StringRef Ext) { - if (Ext.startswith("sx")) - return "sx"; - if (Ext.startswith("s")) - return "s"; - if (Ext.startswith("x")) - return "x"; - if (Ext.startswith("z")) - return "z"; - return StringRef(); -} - -// If the extension is supported as experimental, return the version of that -// extension that the compiler currently supports. -static Optional<RISCVExtensionVersion> -isExperimentalExtension(StringRef Ext) { - if (Ext == "b" || Ext == "zba" || Ext == "zbb" || Ext == "zbc" || - Ext == "zbe" || Ext == "zbf" || Ext == "zbm" || Ext == "zbp" || - Ext == "zbr" || Ext == "zbs" || Ext == "zbt" || Ext == "zbproposedc") - return RISCVExtensionVersion{"0", "93"}; - if (Ext == "v" || Ext == "zvamo" || Ext == "zvlsseg") - return RISCVExtensionVersion{"0", "10"}; - if (Ext == "zfh") - return RISCVExtensionVersion{"0", "1"}; - return None; -} - -static bool isSupportedExtension(StringRef Ext) { - // LLVM supports "z" extensions which are marked as experimental. - if (isExperimentalExtension(Ext)) - return true; - - // LLVM does not support "sx", "s" nor "x" extensions. - return false; -} - -// Extensions may have a version number, and may be separated by -// an underscore '_' e.g.: rv32i2_m2. -// Version number is divided into major and minor version numbers, -// separated by a 'p'. If the minor version is 0 then 'p0' can be -// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. -static bool getExtensionVersion(const Driver &D, const ArgList &Args, - StringRef MArch, StringRef Ext, StringRef In, - std::string &Major, std::string &Minor) { - Major = std::string(In.take_while(isDigit)); - In = In.substr(Major.size()); - - if (Major.size() && In.consume_front("p")) { - Minor = std::string(In.take_while(isDigit)); - In = In.substr(Major.size() + 1); - - // Expected 'p' to be followed by minor version number. - if (Minor.empty()) { - std::string Error = - "minor version number missing after 'p' for extension"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return false; - } - } - - // Expected multi-character extension with version number to have no - // subsequent characters (i.e. must either end string or be followed by - // an underscore). - if (Ext.size() > 1 && In.size()) { - std::string Error = - "multi-character extensions must be separated by underscores"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << In; - return false; - } - - // If experimental extension, require use of current version number number - if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { - if (!Args.hasArg(options::OPT_menable_experimental_extensions)) { - std::string Error = - "requires '-menable-experimental-extensions' for experimental extension"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return false; - } else if (Major.empty() && Minor.empty()) { - std::string Error = - "experimental extension requires explicit version number"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return false; - } - auto SupportedVers = *ExperimentalExtension; - if (Major != SupportedVers.Major || Minor != SupportedVers.Minor) { - std::string Error = - "unsupported version number " + Major; - if (!Minor.empty()) - Error += "." + Minor; - Error += " for experimental extension (this compiler supports " - + SupportedVers.Major.str() + "." - + SupportedVers.Minor.str() + ")"; - - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return false; - } - return true; - } - - // Allow extensions to declare no version number - if (Major.empty() && Minor.empty()) - return true; - - // TODO: Handle supported extensions with version number. - std::string Error = "unsupported version number " + Major; - if (!Minor.empty()) - Error += "." + Minor; - Error += " for extension"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext; - - return false; -} - -// Handle other types of extensions other than the standard -// general purpose and standard user-level extensions. -// Parse the ISA string containing non-standard user-level -// extensions, standard supervisor-level extensions and -// non-standard supervisor-level extensions. -// These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a -// canonical order, might have a version number (major, minor) -// and are separated by a single underscore '_'. -// Set the hardware features for the extensions that are supported. -static void getExtensionFeatures(const Driver &D, - const ArgList &Args, - std::vector<StringRef> &Features, - StringRef &MArch, StringRef &Exts) { - if (Exts.empty()) - return; - - // Multi-letter extensions are seperated by a single underscore - // as described in RISC-V User-Level ISA V2.2. - SmallVector<StringRef, 8> Split; - Exts.split(Split, StringRef("_")); - - SmallVector<StringRef, 4> Prefix{"z", "x", "s", "sx"}; - auto I = Prefix.begin(); - auto E = Prefix.end(); - - SmallVector<StringRef, 8> AllExts; - - for (StringRef Ext : Split) { - if (Ext.empty()) { - D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch - << "extension name missing after separator '_'"; - return; - } - - StringRef Type = getExtensionType(Ext); - StringRef Desc = getExtensionTypeDesc(Ext); - auto Pos = Ext.find_if(isDigit); - StringRef Name(Ext.substr(0, Pos)); - StringRef Vers(Ext.substr(Pos)); - - if (Type.empty()) { - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << "invalid extension prefix" << Ext; - return; - } - - // Check ISA extensions are specified in the canonical order. - while (I != E && *I != Type) - ++I; - - if (I == E) { - std::string Error = std::string(Desc); - Error += " not given in canonical order"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return; - } - - // The order is OK, do not advance I to the next prefix - // to allow repeated extension type, e.g.: rv32ixabc_xdef. - - if (Name.size() == Type.size()) { - std::string Error = std::string(Desc); - Error += " name missing after"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Type; - return; - } - - std::string Major, Minor; - if (!getExtensionVersion(D, Args, MArch, Name, Vers, Major, Minor)) - return; - - // Check if duplicated extension. - if (llvm::is_contained(AllExts, Name)) { - std::string Error = "duplicated "; - Error += Desc; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Name; - return; - } - - // Extension format is correct, keep parsing the extensions. - // TODO: Save Type, Name, Major, Minor to avoid parsing them later. - AllExts.push_back(Name); - } - - // Set target features. - // TODO: Hardware features to be handled in Support/TargetParser.cpp. - // TODO: Use version number when setting target features. - for (auto Ext : AllExts) { - if (!isSupportedExtension(Ext)) { - StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext)); - std::string Error = "unsupported "; - Error += Desc; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return; - } - if (Ext == "zvlsseg") { - Features.push_back("+experimental-v"); - Features.push_back("+experimental-zvlsseg"); - } else if (Ext == "zvamo") { - Features.push_back("+experimental-v"); - Features.push_back("+experimental-zvlsseg"); - Features.push_back("+experimental-zvamo"); - } else if (isExperimentalExtension(Ext)) - Features.push_back(Args.MakeArgString("+experimental-" + Ext)); - else - Features.push_back(Args.MakeArgString("+" + Ext)); - } -} - // Returns false if an error is diagnosed. -static bool getArchFeatures(const Driver &D, StringRef MArch, +static bool getArchFeatures(const Driver &D, StringRef Arch, std::vector<StringRef> &Features, const ArgList &Args) { - // RISC-V ISA strings must be lowercase. - if (llvm::any_of(MArch, [](char c) { return isupper(c); })) { - D.Diag(diag::err_drv_invalid_riscv_arch_name) - << MArch << "string must be lowercase"; - return false; - } - - // ISA string must begin with rv32 or rv64. - if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) || - (MArch.size() < 5)) { - D.Diag(diag::err_drv_invalid_riscv_arch_name) - << MArch << "string must begin with rv32{i,e,g} or rv64{i,g}"; - return false; - } - - bool HasRV64 = MArch.startswith("rv64"); + bool EnableExperimentalExtensions = + Args.hasArg(options::OPT_menable_experimental_extensions); + auto ISAInfo = + llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions); + if (!ISAInfo) { + handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) { + D.Diag(diag::err_drv_invalid_riscv_arch_name) + << Arch << ErrMsg.getMessage(); + }); - // The canonical order specified in ISA manual. - // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 - StringRef StdExts = "mafdqlcbjtpvn"; - bool HasF = false, HasD = false; - char Baseline = MArch[4]; - - // First letter should be 'e', 'i' or 'g'. - switch (Baseline) { - default: - D.Diag(diag::err_drv_invalid_riscv_arch_name) - << MArch << "first letter should be 'e', 'i' or 'g'"; - return false; - case 'e': { - StringRef Error; - // Currently LLVM does not support 'e'. - // Extension 'e' is not allowed in rv64. - if (HasRV64) - Error = "standard user-level extension 'e' requires 'rv32'"; - else - Error = "unsupported standard user-level extension 'e'"; - D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch << Error; return false; } - case 'i': - break; - case 'g': - // g = imafd - StdExts = StdExts.drop_front(4); - Features.push_back("+m"); - Features.push_back("+a"); - Features.push_back("+f"); - Features.push_back("+d"); - HasF = true; - HasD = true; - break; - } - - // Skip rvxxx - StringRef Exts = MArch.substr(5); - - // Remove multi-letter standard extensions, non-standard extensions and - // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes. - // Parse them at the end. - // Find the very first occurrence of 's', 'x' or 'z'. - StringRef OtherExts; - size_t Pos = Exts.find_first_of("zsx"); - if (Pos != StringRef::npos) { - OtherExts = Exts.substr(Pos); - Exts = Exts.substr(0, Pos); - } - - std::string Major, Minor; - if (!getExtensionVersion(D, Args, MArch, std::string(1, Baseline), Exts, - Major, Minor)) - return false; - - // Consume the base ISA version number and any '_' between rvxxx and the - // first extension - Exts = Exts.drop_front(Major.size()); - if (!Minor.empty()) - Exts = Exts.drop_front(Minor.size() + 1 /*'p'*/); - Exts.consume_front("_"); - - // TODO: Use version number when setting target features - - auto StdExtsItr = StdExts.begin(); - auto StdExtsEnd = StdExts.end(); - - for (auto I = Exts.begin(), E = Exts.end(); I != E; ) { - char c = *I; - - // Check ISA extensions are specified in the canonical order. - while (StdExtsItr != StdExtsEnd && *StdExtsItr != c) - ++StdExtsItr; - - if (StdExtsItr == StdExtsEnd) { - // Either c contains a valid extension but it was not given in - // canonical order or it is an invalid extension. - StringRef Error; - if (StdExts.contains(c)) - Error = "standard user-level extension not given in canonical order"; - else - Error = "invalid standard user-level extension"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << std::string(1, c); - return false; - } - - // Move to next char to prevent repeated letter. - ++StdExtsItr; - - std::string Next, Major, Minor; - if (std::next(I) != E) - Next = std::string(std::next(I), E); - if (!getExtensionVersion(D, Args, MArch, std::string(1, c), Next, Major, - Minor)) - return false; - - // The order is OK, then push it into features. - // TODO: Use version number when setting target features - switch (c) { - default: - // Currently LLVM supports only "mafdc". - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << "unsupported standard user-level extension" - << std::string(1, c); - return false; - case 'm': - Features.push_back("+m"); - break; - case 'a': - Features.push_back("+a"); - break; - case 'f': - Features.push_back("+f"); - HasF = true; - break; - case 'd': - Features.push_back("+d"); - HasD = true; - break; - case 'c': - Features.push_back("+c"); - break; - case 'b': - Features.push_back("+experimental-b"); - Features.push_back("+experimental-zba"); - Features.push_back("+experimental-zbb"); - Features.push_back("+experimental-zbc"); - Features.push_back("+experimental-zbe"); - Features.push_back("+experimental-zbf"); - Features.push_back("+experimental-zbm"); - Features.push_back("+experimental-zbp"); - Features.push_back("+experimental-zbr"); - Features.push_back("+experimental-zbs"); - Features.push_back("+experimental-zbt"); - break; - case 'v': - Features.push_back("+experimental-v"); - Features.push_back("+experimental-zvlsseg"); - break; - } - // Consume full extension name and version, including any optional '_' - // between this extension and the next - ++I; - I += Major.size(); - if (Minor.size()) - I += Minor.size() + 1 /*'p'*/; - if (*I == '_') - ++I; - } + for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true, + /*IgnoreUnknown=*/false)) + Features.push_back(Args.MakeArgString(Str)); - // Dependency check. - // It's illegal to specify the 'd' (double-precision floating point) - // extension without also specifying the 'f' (single precision - // floating-point) extension. - if (HasD && !HasF) { - D.Diag(diag::err_drv_invalid_riscv_arch_name) - << MArch << "d requires f extension to also be specified"; - return false; - } - - // Additional dependency checks. - // TODO: The 'q' extension requires rv64. - // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. - - // Handle all other types of extensions. - getExtensionFeatures(D, Args, Features, MArch, OtherExts); + if (EnableExperimentalExtensions) + Features.push_back(Args.MakeArgString("+experimental")); return true; } // Get features except standard extension feature -static void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, - const llvm::opt::Arg *A, StringRef Mcpu, +static void getRISCFeaturesFromMcpu(const Driver &D, const Arg *A, + const llvm::Triple &Triple, + StringRef Mcpu, std::vector<StringRef> &Features) { - bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64); - llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu); - if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) || - !llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) { - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + bool Is64Bit = Triple.isRISCV64(); + if (!llvm::RISCV::parseCPU(Mcpu, Is64Bit)) { + // Try inverting Is64Bit in case the CPU is valid, but for the wrong target. + if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit)) + D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target) + << Mcpu << Is64Bit; + else + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Mcpu; } + + if (llvm::RISCV::hasFastUnalignedAccess(Mcpu)) + Features.push_back("+fast-unaligned-access"); } void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, @@ -489,8 +82,13 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, // If users give march and mcpu, get std extension feature from MArch // and other features (ex. mirco architecture feature) from mcpu - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) - getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features); + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + StringRef CPU = A->getValue(); + if (CPU == "native") + CPU = llvm::sys::getHostCPUName(); + + getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features); + } // Handle features corresponding to "-ffixed-X" options if (Args.hasArg(options::OPT_ffixed_x1)) @@ -558,27 +156,30 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, // FreeBSD local, because ld.lld doesn't support relaxations // -mno-relax is default, unless -mrelax is specified. - if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) + if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) { Features.push_back("+relax"); - else + // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing + // into .debug_addr, which is currently not implemented. + Arg *A; + if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None) + D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation) + << A->getAsString(Args); + } else { Features.push_back("-relax"); + } - // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is - // specified. - if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) - Features.push_back("+save-restore"); - else - Features.push_back("-save-restore"); + // -mno-unaligned-access is default, unless -munaligned-access is specified. + AddTargetFeature(Args, Features, options::OPT_munaligned_access, + options::OPT_mno_unaligned_access, "fast-unaligned-access"); // Now add any that the user explicitly requested on the command line, // which may override the defaults. - handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group); + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_riscv_Features_Group); } StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { - assert((Triple.getArch() == llvm::Triple::riscv32 || - Triple.getArch() == llvm::Triple::riscv64) && - "Unexpected triple"); + assert(Triple.isRISCV() && "Unexpected triple"); // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not // configured using `--with-abi=`, then the logic for the default choice is @@ -610,33 +211,22 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { // rv32e -> ilp32e // rv32* -> ilp32 // rv64g | rv64*d -> lp64d + // rv64e -> lp64e // rv64* -> lp64 - StringRef MArch = getRISCVArch(Args, Triple); + StringRef Arch = getRISCVArch(Args, Triple); - if (MArch.startswith_insensitive("rv32")) { - // FIXME: parse `March` to find `D` extension properly - if (MArch.substr(4).contains_insensitive("d") || - MArch.startswith_insensitive("rv32g")) - return "ilp32d"; - else if (MArch.startswith_insensitive("rv32e")) - return "ilp32e"; - else - return "ilp32"; - } else if (MArch.startswith_insensitive("rv64")) { - // FIXME: parse `March` to find `D` extension properly - if (MArch.substr(4).contains_insensitive("d") || - MArch.startswith_insensitive("rv64g")) - return "lp64d"; - else - return "lp64"; - } + auto ParseResult = llvm::RISCVISAInfo::parseArchString( + Arch, /* EnableExperimentalExtension */ true); + // Ignore parsing error, just go 3rd step. + if (!llvm::errorToBool(ParseResult.takeError())) + return (*ParseResult)->computeDefaultABI(); // 3. Choose a default based on the triple // // We deviate from GCC's defaults here: // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only. // - On all other OSs we use the double floating point calling convention. - if (Triple.getArch() == llvm::Triple::riscv32) { + if (Triple.isRISCV32()) { if (Triple.getOS() == llvm::Triple::UnknownOS) return "ilp32"; else @@ -651,9 +241,7 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple) { - assert((Triple.getArch() == llvm::Triple::riscv32 || - Triple.getArch() == llvm::Triple::riscv64) && - "Unexpected triple"); + assert(Triple.isRISCV() && "Unexpected triple"); // GCC's logic around choosing a default `-march=` is complex. If GCC is not // configured using `--with-arch=`, then the logic for the default choice is @@ -687,7 +275,10 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, // 2. Get march (isa string) based on `-mcpu=` if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue()); + StringRef CPU = A->getValue(); + if (CPU == "native") + CPU = llvm::sys::getHostCPUName(); + StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU); // Bypass if target cpu's default march is empty. if (MArch != "") return MArch; @@ -696,6 +287,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, // 3. Choose a default based on `-mabi=` // // ilp32e -> rv32e + // lp64e -> rv64e // ilp32 | ilp32f | ilp32d -> rv32imafdc // lp64 | lp64f | lp64d -> rv64imafdc if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { @@ -703,10 +295,16 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, if (MABI.equals_insensitive("ilp32e")) return "rv32e"; - else if (MABI.startswith_insensitive("ilp32")) + else if (MABI.equals_insensitive("lp64e")) + return "rv64e"; + else if (MABI.starts_with_insensitive("ilp32")) return "rv32imafdc"; - else if (MABI.startswith_insensitive("lp64")) + else if (MABI.starts_with_insensitive("lp64")) { + if (Triple.isAndroid()) + return "rv64imafdcv_zba_zbb_zbs"; + return "rv64imafdc"; + } } // 4. Choose a default based on the triple @@ -714,7 +312,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, // We deviate from GCC's defaults here: // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac` // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`) - if (Triple.getArch() == llvm::Triple::riscv32) { + if (Triple.isRISCV32()) { if (Triple.getOS() == llvm::Triple::UnknownOS) return "rv32imac"; else @@ -722,7 +320,26 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, } else { if (Triple.getOS() == llvm::Triple::UnknownOS) return "rv64imac"; + else if (Triple.isAndroid()) + return "rv64imafdcv_zba_zbb_zbs"; else return "rv64imafdc"; } } + +std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + std::string CPU; + // If we have -mcpu, use that. + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + CPU = A->getValue(); + + // Handle CPU name is 'native'. + if (CPU == "native") + CPU = llvm::sys::getHostCPUName(); + + if (!CPU.empty()) + return CPU; + + return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32"; +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h index d4a519cdab34..fcaf9d57ad13 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.h @@ -1,4 +1,4 @@ -//===--- RISCV.h - RISCV-specific Tool Helpers ------------------*- C++ -*-===// +//===--- RISCV.h - RISC-V-specific Tool Helpers -----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -26,6 +26,8 @@ StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); StringRef getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +std::string getRISCVTargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); } // end namespace riscv } // namespace tools } // end namespace driver diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp index 70ba8eb2a7d0..ae1a4ba78826 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -62,10 +63,6 @@ const char *sparc::getSparcAsmModeForCPU(StringRef Name, .Case("ma2480", "-Aleon") .Case("ma2485", "-Aleon") .Case("ma2x8x", "-Aleon") - .Case("myriad2", "-Aleon") - .Case("myriad2.1", "-Aleon") - .Case("myriad2.2", "-Aleon") - .Case("myriad2.3", "-Aleon") .Case("leon2", "-Av8") .Case("at697e", "-Av8") .Case("at697f", "-Av8") @@ -81,12 +78,14 @@ const char *sparc::getSparcAsmModeForCPU(StringRef Name, sparc::FloatABI sparc::getSparcFloatABI(const Driver &D, const ArgList &Args) { sparc::FloatABI ABI = sparc::FloatABI::Invalid; - if (Arg *A = Args.getLastArg(clang::driver::options::OPT_msoft_float, - options::OPT_mhard_float, + if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mno_fpu, + options::OPT_mhard_float, options::OPT_mfpu, options::OPT_mfloat_abi_EQ)) { - if (A->getOption().matches(clang::driver::options::OPT_msoft_float)) + if (A->getOption().matches(options::OPT_msoft_float) || + A->getOption().matches(options::OPT_mno_fpu)) ABI = sparc::FloatABI::Soft; - else if (A->getOption().matches(options::OPT_mhard_float)) + else if (A->getOption().matches(options::OPT_mhard_float) || + A->getOption().matches(options::OPT_mfpu)) ABI = sparc::FloatABI::Hard; else { ABI = llvm::StringSwitch<sparc::FloatABI>(A->getValue()) @@ -113,9 +112,151 @@ sparc::FloatABI sparc::getSparcFloatABI(const Driver &D, return ABI; } +std::string sparc::getSparcTargetCPU(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) { + StringRef CPUName = A->getValue(); + if (CPUName == "native") { + std::string CPU = std::string(llvm::sys::getHostCPUName()); + if (!CPU.empty() && CPU != "generic") + return CPU; + return ""; + } + return std::string(CPUName); + } + + if (Triple.getArch() == llvm::Triple::sparc && Triple.isOSSolaris()) + return "v9"; + return ""; +} + void sparc::getSparcTargetFeatures(const Driver &D, const ArgList &Args, std::vector<StringRef> &Features) { sparc::FloatABI FloatABI = sparc::getSparcFloatABI(D, Args); if (FloatABI == sparc::FloatABI::Soft) Features.push_back("+soft-float"); + + if (Arg *A = Args.getLastArg(options::OPT_mfsmuld, options::OPT_mno_fsmuld)) { + if (A->getOption().matches(options::OPT_mfsmuld)) + Features.push_back("+fsmuld"); + else + Features.push_back("-fsmuld"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mpopc, options::OPT_mno_popc)) { + if (A->getOption().matches(options::OPT_mpopc)) + Features.push_back("+popc"); + else + Features.push_back("-popc"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mvis, options::OPT_mno_vis)) { + if (A->getOption().matches(options::OPT_mvis)) + Features.push_back("+vis"); + else + Features.push_back("-vis"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mvis2, options::OPT_mno_vis2)) { + if (A->getOption().matches(options::OPT_mvis2)) + Features.push_back("+vis2"); + else + Features.push_back("-vis2"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mvis3, options::OPT_mno_vis3)) { + if (A->getOption().matches(options::OPT_mvis3)) + Features.push_back("+vis3"); + else + Features.push_back("-vis3"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mhard_quad_float, + options::OPT_msoft_quad_float)) { + if (A->getOption().matches(options::OPT_mhard_quad_float)) + Features.push_back("+hard-quad-float"); + else + Features.push_back("-hard-quad-float"); + } + + if (Args.hasArg(options::OPT_ffixed_g1)) + Features.push_back("+reserve-g1"); + + if (Args.hasArg(options::OPT_ffixed_g2)) + Features.push_back("+reserve-g2"); + + if (Args.hasArg(options::OPT_ffixed_g3)) + Features.push_back("+reserve-g3"); + + if (Args.hasArg(options::OPT_ffixed_g4)) + Features.push_back("+reserve-g4"); + + if (Args.hasArg(options::OPT_ffixed_g5)) + Features.push_back("+reserve-g5"); + + if (Args.hasArg(options::OPT_ffixed_g6)) + Features.push_back("+reserve-g6"); + + if (Args.hasArg(options::OPT_ffixed_g7)) + Features.push_back("+reserve-g7"); + + if (Args.hasArg(options::OPT_ffixed_o0)) + Features.push_back("+reserve-o0"); + + if (Args.hasArg(options::OPT_ffixed_o1)) + Features.push_back("+reserve-o1"); + + if (Args.hasArg(options::OPT_ffixed_o2)) + Features.push_back("+reserve-o2"); + + if (Args.hasArg(options::OPT_ffixed_o3)) + Features.push_back("+reserve-o3"); + + if (Args.hasArg(options::OPT_ffixed_o4)) + Features.push_back("+reserve-o4"); + + if (Args.hasArg(options::OPT_ffixed_o5)) + Features.push_back("+reserve-o5"); + + if (Args.hasArg(options::OPT_ffixed_l0)) + Features.push_back("+reserve-l0"); + + if (Args.hasArg(options::OPT_ffixed_l1)) + Features.push_back("+reserve-l1"); + + if (Args.hasArg(options::OPT_ffixed_l2)) + Features.push_back("+reserve-l2"); + + if (Args.hasArg(options::OPT_ffixed_l3)) + Features.push_back("+reserve-l3"); + + if (Args.hasArg(options::OPT_ffixed_l4)) + Features.push_back("+reserve-l4"); + + if (Args.hasArg(options::OPT_ffixed_l5)) + Features.push_back("+reserve-l5"); + + if (Args.hasArg(options::OPT_ffixed_l6)) + Features.push_back("+reserve-l6"); + + if (Args.hasArg(options::OPT_ffixed_l7)) + Features.push_back("+reserve-l7"); + + if (Args.hasArg(options::OPT_ffixed_i0)) + Features.push_back("+reserve-i0"); + + if (Args.hasArg(options::OPT_ffixed_i1)) + Features.push_back("+reserve-i1"); + + if (Args.hasArg(options::OPT_ffixed_i2)) + Features.push_back("+reserve-i2"); + + if (Args.hasArg(options::OPT_ffixed_i3)) + Features.push_back("+reserve-i3"); + + if (Args.hasArg(options::OPT_ffixed_i4)) + Features.push_back("+reserve-i4"); + + if (Args.hasArg(options::OPT_ffixed_i5)) + Features.push_back("+reserve-i5"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h index d12a9a70e264..44658c4259c6 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Sparc.h @@ -28,6 +28,9 @@ enum class FloatABI { FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args); +std::string getSparcTargetCPU(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); + void getSparcTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, std::vector<llvm::StringRef> &Features); const char *getSparcAsmModeForCPU(llvm::StringRef Name, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp index f81bf68172de..588bc3176d73 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -11,7 +11,7 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp index 9dfd37c2106d..b19760898c64 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.cpp @@ -10,7 +10,6 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" using namespace clang::driver; @@ -19,4 +18,9 @@ using namespace clang; using namespace llvm::opt; void ve::getVETargetFeatures(const Driver &D, const ArgList &Args, - std::vector<StringRef> &Features) {} + std::vector<StringRef> &Features) { + if (Args.hasFlag(options::OPT_mvevpu, options::OPT_mno_vevpu, true)) + Features.push_back("+vpu"); + else + Features.push_back("-vpu"); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h index 531433534914..c47a41df25bc 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/VE.h @@ -24,7 +24,7 @@ void getVETargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, std::vector<llvm::StringRef> &Features); } // end namespace ve -} // namespace tools +} // end namespace tools } // end namespace driver } // end namespace clang diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp index 12749c7ec871..53e26a9f8e22 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -11,16 +11,17 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" -#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/Host.h" +#include "llvm/TargetParser/Host.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -std::string x86::getX86TargetCPU(const ArgList &Args, +std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args, const llvm::Triple &Triple) { if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { StringRef CPU = A->getValue(); @@ -29,37 +30,39 @@ std::string x86::getX86TargetCPU(const ArgList &Args, // FIXME: Reject attempts to use -march=native unless the target matches // the host. - // - // FIXME: We should also incorporate the detected target features for use - // with -native. CPU = llvm::sys::getHostCPUName(); if (!CPU.empty() && CPU != "generic") return std::string(CPU); } - if (const Arg *A = Args.getLastArgNoClaim(options::OPT__SLASH_arch)) { + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) { // Mapping built by looking at lib/Basic's X86TargetInfo::initFeatureMap(). - StringRef Arch = A->getValue(); - StringRef CPU; - if (Triple.getArch() == llvm::Triple::x86) { // 32-bit-only /arch: flags. - CPU = llvm::StringSwitch<StringRef>(Arch) - .Case("IA32", "i386") - .Case("SSE", "pentium3") - .Case("SSE2", "pentium4") - .Default(""); + // The keys are case-sensitive; this matches link.exe. + // 32-bit and 64-bit /arch: flags. + llvm::StringMap<StringRef> ArchMap({ + {"AVX", "sandybridge"}, + {"AVX2", "haswell"}, + {"AVX512F", "knl"}, + {"AVX512", "skylake-avx512"}, + }); + if (Triple.getArch() == llvm::Triple::x86) { + // 32-bit-only /arch: flags. + ArchMap.insert({ + {"IA32", "i386"}, + {"SSE", "pentium3"}, + {"SSE2", "pentium4"}, + }); } - if (CPU.empty()) { // 32-bit and 64-bit /arch: flags. - CPU = llvm::StringSwitch<StringRef>(Arch) - .Case("AVX", "sandybridge") - .Case("AVX2", "haswell") - .Case("AVX512F", "knl") - .Case("AVX512", "skylake-avx512") - .Default(""); - } - if (!CPU.empty()) { - A->claim(); - return std::string(CPU); + StringRef CPU = ArchMap.lookup(A->getValue()); + if (CPU.empty()) { + std::vector<StringRef> ValidArchs{ArchMap.keys().begin(), + ArchMap.keys().end()}; + sort(ValidArchs); + D.Diag(diag::warn_drv_invalid_arch_name_with_suggestion) + << A->getValue() << (Triple.getArch() == llvm::Triple::x86) + << join(ValidArchs, ", "); } + return std::string(CPU); } // Select the default CPU if none was given (or detection failed). @@ -77,13 +80,19 @@ std::string x86::getX86TargetCPU(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()) @@ -110,6 +119,15 @@ std::string x86::getX86TargetCPU(const ArgList &Args, void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { + // Claim and report unsupported -mabi=. Note: we don't support "sysv_abi" or + // "ms_abi" as default function attributes. + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mabi_EQ)) { + StringRef DefaultAbi = Triple.isOSWindows() ? "ms" : "sysv"; + if (A->getValue() != DefaultAbi) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << Triple.getTriple(); + } + // If -march=native, autodetect the feature list. if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { if (StringRef(A->getValue()) == "native") { @@ -211,6 +229,27 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, << D.getOpts().getOptionName(LVIOpt); } + for (const Arg *A : Args.filtered(options::OPT_m_x86_AVX10_Features_Group)) { + StringRef Name = A->getOption().getName(); + A->claim(); + + // Skip over "-m". + assert(Name.starts_with("m") && "Invalid feature name."); + Name = Name.substr(1); + + bool IsNegative = Name.consume_front("no-"); + +#ifndef NDEBUG + assert(Name.starts_with("avx10.") && "Invalid AVX10 feature name."); + StringRef Version, Width; + std::tie(Version, Width) = Name.substr(6).split('-'); + assert(Version == "1" && "Invalid AVX10 feature name."); + assert((Width == "256" || Width == "512") && "Invalid AVX10 feature name."); +#endif + + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); + } + // Now add any that the user explicitly requested on the command line, // which may override the defaults. for (const Arg *A : Args.filtered(options::OPT_m_x86_Features_Group, @@ -219,7 +258,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, A->claim(); // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); + assert(Name.starts_with("m") && "Invalid feature name."); Name = Name.substr(1); // Replace -mgeneral-regs-only with -x87, -mmx, -sse @@ -228,9 +267,46 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, continue; } - bool IsNegative = Name.startswith("no-"); + bool IsNegative = Name.starts_with("no-"); + if (A->getOption().matches(options::OPT_mapx_features_EQ) || + A->getOption().matches(options::OPT_mno_apx_features_EQ)) { + + for (StringRef Value : A->getValues()) { + if (Value == "egpr" || Value == "push2pop2" || Value == "ppx" || + Value == "ndd" || Value == "ccmp" || Value == "cf") { + Features.push_back( + Args.MakeArgString((IsNegative ? "-" : "+") + Value)); + continue; + } + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Value; + } + continue; + } if (IsNegative) Name = Name.substr(3); Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } + + // Enable/disable straight line speculation hardening. + if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) { + StringRef Scope = A->getValue(); + if (Scope == "all") { + Features.push_back("+harden-sls-ijmp"); + Features.push_back("+harden-sls-ret"); + } else if (Scope == "return") { + Features.push_back("+harden-sls-ret"); + } else if (Scope == "indirect-jmp") { + Features.push_back("+harden-sls-ijmp"); + } else if (Scope != "none") { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Scope; + } + } + + // -mno-gather, -mno-scatter support + if (Args.hasArg(options::OPT_mno_gather)) + Features.push_back("+prefer-no-gather"); + if (Args.hasArg(options::OPT_mno_scatter)) + Features.push_back("+prefer-no-scatter"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h index 14f0a26c8be4..e07387f3ece3 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/X86.h @@ -11,8 +11,8 @@ #include "clang/Driver/Driver.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" +#include "llvm/TargetParser/Triple.h" #include <string> #include <vector> @@ -21,7 +21,7 @@ namespace driver { namespace tools { namespace x86 { -std::string getX86TargetCPU(const llvm::opt::ArgList &Args, +std::string getX86TargetCPU(const Driver &D, const llvm::opt::ArgList &Args, const llvm::Triple &Triple); void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp index ce73e39d1456..391c47f88bde 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -12,26 +12,27 @@ #include "Gnu.h" #include "clang/Driver/InputInfo.h" +#include "Arch/ARM.h" #include "Arch/RISCV.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/MultilibBuilder.h" #include "clang/Driver/Options.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Path.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" +#include <sstream> + using namespace llvm::opt; using namespace clang; using namespace clang::driver; using namespace clang::driver::tools; using namespace clang::driver::toolchains; -static Multilib makeMultilib(StringRef commonSuffix) { - return Multilib(commonSuffix, commonSuffix, commonSuffix); -} - static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result) { @@ -39,37 +40,41 @@ static bool findRISCVMultilibs(const Driver &D, StringRef Arch = riscv::getRISCVArch(Args, TargetTriple); StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple); - if (TargetTriple.getArch() == llvm::Triple::riscv64) { - Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64"); - Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d") - .flag("+march=rv64imafdc") - .flag("+mabi=lp64d"); + if (TargetTriple.isRISCV64()) { + MultilibBuilder Imac = + MultilibBuilder().flag("-march=rv64imac").flag("-mabi=lp64"); + MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d") + .flag("-march=rv64imafdc") + .flag("-mabi=lp64d"); // Multilib reuse bool UseImafdc = (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc - addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags); - addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags); - addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags); - addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags); + addMultilibFlag((Arch == "rv64imac"), "-march=rv64imac", Flags); + addMultilibFlag(UseImafdc, "-march=rv64imafdc", Flags); + addMultilibFlag(Abi == "lp64", "-mabi=lp64", Flags); + addMultilibFlag(Abi == "lp64d", "-mabi=lp64d", Flags); - Result.Multilibs = MultilibSet().Either(Imac, Imafdc); - return Result.Multilibs.select(Flags, Result.SelectedMultilib); + Result.Multilibs = + MultilibSetBuilder().Either(Imac, Imafdc).makeMultilibSet(); + return Result.Multilibs.select(Flags, Result.SelectedMultilibs); } - if (TargetTriple.getArch() == llvm::Triple::riscv32) { - Multilib Imac = - makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32"); - Multilib I = - makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32"); - Multilib Im = - makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32"); - Multilib Iac = makeMultilib("/rv32iac/ilp32") - .flag("+march=rv32iac") - .flag("+mabi=ilp32"); - Multilib Imafc = makeMultilib("/rv32imafc/ilp32f") - .flag("+march=rv32imafc") - .flag("+mabi=ilp32f"); + if (TargetTriple.isRISCV32()) { + MultilibBuilder Imac = + MultilibBuilder().flag("-march=rv32imac").flag("-mabi=ilp32"); + MultilibBuilder I = MultilibBuilder("/rv32i/ilp32") + .flag("-march=rv32i") + .flag("-mabi=ilp32"); + MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32") + .flag("-march=rv32im") + .flag("-mabi=ilp32"); + MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32") + .flag("-march=rv32iac") + .flag("-mabi=ilp32"); + MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f") + .flag("-march=rv32imafc") + .flag("-mabi=ilp32f"); // Multilib reuse bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i @@ -77,22 +82,23 @@ static bool findRISCVMultilibs(const Driver &D, bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") || (Arch == "rv32gc"); // imafdc,gc => imafc - addMultilibFlag(UseI, "march=rv32i", Flags); - addMultilibFlag(UseIm, "march=rv32im", Flags); - addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags); - addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags); - addMultilibFlag(UseImafc, "march=rv32imafc", Flags); - addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags); - addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags); - - Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc); - return Result.Multilibs.select(Flags, Result.SelectedMultilib); + addMultilibFlag(UseI, "-march=rv32i", Flags); + addMultilibFlag(UseIm, "-march=rv32im", Flags); + addMultilibFlag((Arch == "rv32iac"), "-march=rv32iac", Flags); + addMultilibFlag((Arch == "rv32imac"), "-march=rv32imac", Flags); + addMultilibFlag(UseImafc, "-march=rv32imafc", Flags); + addMultilibFlag(Abi == "ilp32", "-mabi=ilp32", Flags); + addMultilibFlag(Abi == "ilp32f", "-mabi=ilp32f", Flags); + + Result.Multilibs = + MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet(); + return Result.Multilibs.select(Flags, Result.SelectedMultilibs); } return false; } BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) + const ArgList &Args) : ToolChain(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) @@ -101,15 +107,21 @@ BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, findMultilibs(D, Triple, Args); SmallString<128> SysRoot(computeSysRoot()); if (!SysRoot.empty()) { - llvm::sys::path::append(SysRoot, "lib"); - getFilePaths().push_back(std::string(SysRoot)); + for (const Multilib &M : getOrderedMultilibs()) { + SmallString<128> Dir(SysRoot); + llvm::sys::path::append(Dir, M.osSuffix(), "lib"); + getFilePaths().push_back(std::string(Dir)); + getLibraryPaths().push_back(std::string(Dir)); + } } } -/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ? +/// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ? static bool isARMBareMetal(const llvm::Triple &Triple) { if (Triple.getArch() != llvm::Triple::arm && - Triple.getArch() != llvm::Triple::thumb) + Triple.getArch() != llvm::Triple::thumb && + Triple.getArch() != llvm::Triple::armeb && + Triple.getArch() != llvm::Triple::thumbeb) return false; if (Triple.getVendor() != llvm::Triple::UnknownVendor) @@ -125,9 +137,23 @@ static bool isARMBareMetal(const llvm::Triple &Triple) { return true; } +/// Is the triple {aarch64.aarch64_be}-none-elf? +static bool isAArch64BareMetal(const llvm::Triple &Triple) { + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_be) + return false; + + if (Triple.getVendor() != llvm::Triple::UnknownVendor) + return false; + + if (Triple.getOS() != llvm::Triple::UnknownOS) + return false; + + return Triple.getEnvironmentName() == "elf"; +} + static bool isRISCVBareMetal(const llvm::Triple &Triple) { - if (Triple.getArch() != llvm::Triple::riscv32 && - Triple.getArch() != llvm::Triple::riscv64) + if (!Triple.isRISCV()) return false; if (Triple.getVendor() != llvm::Triple::UnknownVendor) @@ -139,50 +165,100 @@ static bool isRISCVBareMetal(const llvm::Triple &Triple) { return Triple.getEnvironmentName() == "elf"; } +/// Is the triple powerpc[64][le]-*-none-eabi? +static bool isPPCBareMetal(const llvm::Triple &Triple) { + return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS && + Triple.getEnvironment() == llvm::Triple::EABI; +} + +static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D, + StringRef MultilibPath, const ArgList &Args, + DetectedMultilibs &Result) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = + D.getVFS().getBufferForFile(MultilibPath); + if (!MB) + return; + Multilib::flags_list Flags = TC.getMultilibFlags(Args); + llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet = + MultilibSet::parseYaml(*MB.get()); + if (ErrorOrMultilibSet.getError()) + return; + Result.Multilibs = ErrorOrMultilibSet.get(); + if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) + return; + D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " "); + std::stringstream ss; + for (const Multilib &Multilib : Result.Multilibs) + ss << "\n" << llvm::join(Multilib.flags(), " "); + D.Diag(clang::diag::note_drv_available_multilibs) << ss.str(); +} + +static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml"; + +// Get the sysroot, before multilib takes effect. +static std::string computeBaseSysRoot(const Driver &D, + const llvm::Triple &Triple) { + if (!D.SysRoot.empty()) + return D.SysRoot; + + SmallString<128> SysRootDir(D.Dir); + llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes"); + + SmallString<128> MultilibPath(SysRootDir); + llvm::sys::path::append(MultilibPath, MultilibFilename); + + // New behaviour: if multilib.yaml is found then use clang-runtimes as the + // sysroot. + if (D.getVFS().exists(MultilibPath)) + return std::string(SysRootDir); + + // Otherwise fall back to the old behaviour of appending the target triple. + llvm::sys::path::append(SysRootDir, D.getTargetTriple()); + return std::string(SysRootDir); +} + void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) { DetectedMultilibs Result; if (isRISCVBareMetal(Triple)) { if (findRISCVMultilibs(D, Triple, Args, Result)) { - SelectedMultilib = Result.SelectedMultilib; + SelectedMultilibs = Result.SelectedMultilibs; Multilibs = Result.Multilibs; } + } else { + llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple)); + llvm::sys::path::append(MultilibPath, MultilibFilename); + findMultilibsFromYAML(*this, D, MultilibPath, Args, Result); + SelectedMultilibs = Result.SelectedMultilibs; + Multilibs = Result.Multilibs; } } bool BareMetal::handlesTarget(const llvm::Triple &Triple) { - return isARMBareMetal(Triple) || isRISCVBareMetal(Triple); + return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) || + isRISCVBareMetal(Triple) || isPPCBareMetal(Triple); } Tool *BareMetal::buildLinker() const { return new tools::baremetal::Linker(*this); } -std::string BareMetal::getCompilerRTPath() const { return getRuntimesDir(); } - -std::string BareMetal::buildCompilerRTBasename(const llvm::opt::ArgList &, - StringRef, FileType, - bool) const { - return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str(); -} - -std::string BareMetal::getRuntimesDir() const { - SmallString<128> Dir(getDriver().ResourceDir); - llvm::sys::path::append(Dir, "lib", "baremetal"); - Dir += SelectedMultilib.gccSuffix(); - return std::string(Dir.str()); +Tool *BareMetal::buildStaticLibTool() const { + return new tools::baremetal::StaticLibTool(*this); } std::string BareMetal::computeSysRoot() const { - if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot + SelectedMultilib.osSuffix(); + return computeBaseSysRoot(getDriver(), getTriple()); +} - SmallString<128> SysRootDir; - llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes", - getDriver().getTargetTriple()); +BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const { + // Get multilibs in reverse order because they're ordered most-specific last. + if (!SelectedMultilibs.empty()) + return llvm::reverse(SelectedMultilibs); - SysRootDir += SelectedMultilib.osSuffix(); - return std::string(SysRootDir); + // No multilibs selected so return a single default multilib. + static const llvm::SmallVector<Multilib> Default = {Multilib()}; + return llvm::reverse(Default); } void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -197,10 +273,14 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, } if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { - SmallString<128> Dir(computeSysRoot()); - if (!Dir.empty()) { - llvm::sys::path::append(Dir, "include"); - addSystemInclude(DriverArgs, CC1Args, Dir.str()); + const SmallString<128> SysRoot(computeSysRoot()); + if (!SysRoot.empty()) { + for (const Multilib &M : getOrderedMultilibs()) { + SmallString<128> Dir(SysRoot); + llvm::sys::path::append(Dir, M.includeSuffix()); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } } } } @@ -211,48 +291,58 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, CC1Args.push_back("-nostdsysteminc"); } -void BareMetal::AddClangCXXStdlibIncludeArgs( - const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc) || - DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) +void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, + options::OPT_nostdincxx)) return; + const Driver &D = getDriver(); std::string SysRoot(computeSysRoot()); if (SysRoot.empty()) return; - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: { + for (const Multilib &M : getOrderedMultilibs()) { SmallString<128> Dir(SysRoot); - llvm::sys::path::append(Dir, "include", "c++", "v1"); - addSystemInclude(DriverArgs, CC1Args, Dir.str()); - break; - } - case ToolChain::CST_Libstdcxx: { - SmallString<128> Dir(SysRoot); - llvm::sys::path::append(Dir, "include", "c++"); - std::error_code EC; - Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; - // Walk the subdirs, and find the one with the newest gcc version: - for (llvm::vfs::directory_iterator - LI = getDriver().getVFS().dir_begin(Dir.str(), EC), - LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); - if (CandidateVersion.Major == -1) - continue; - if (CandidateVersion <= Version) - continue; - Version = CandidateVersion; + llvm::sys::path::append(Dir, M.gccSuffix()); + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + // First check sysroot/usr/include/c++/v1 if it exists. + SmallString<128> TargetDir(Dir); + llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1"); + if (D.getVFS().exists(TargetDir)) { + addSystemInclude(DriverArgs, CC1Args, TargetDir.str()); + break; + } + // Add generic path if nothing else succeeded so far. + llvm::sys::path::append(Dir, "include", "c++", "v1"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + break; + } + case ToolChain::CST_Libstdcxx: { + llvm::sys::path::append(Dir, "include", "c++"); + std::error_code EC; + Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; + // Walk the subdirs, and find the one with the newest gcc version: + for (llvm::vfs::directory_iterator + LI = D.getVFS().dir_begin(Dir.str(), EC), + LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); + if (CandidateVersion.Major == -1) + continue; + if (CandidateVersion <= Version) + continue; + Version = CandidateVersion; + } + if (Version.Major != -1) { + llvm::sys::path::append(Dir, Version.Text); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + break; + } } - if (Version.Major == -1) - return; - llvm::sys::path::append(Dir, Version.Text); - addSystemInclude(DriverArgs, CC1Args, Dir.str()); - break; - } } } @@ -261,6 +351,8 @@ void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: @@ -275,10 +367,14 @@ void BareMetal::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs) const { ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args); switch (RLT) { - case ToolChain::RLT_CompilerRT: - CmdArgs.push_back( - Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName())); + case ToolChain::RLT_CompilerRT: { + const std::string FileName = getCompilerRT(Args, "builtins"); + llvm::StringRef BaseName = llvm::sys::path::filename(FileName); + BaseName.consume_front("lib"); + BaseName.consume_back(".a"); + CmdArgs.push_back(Args.MakeArgString("-l" + BaseName)); return; + } case ToolChain::RLT_Libgcc: CmdArgs.push_back("-lgcc"); return; @@ -286,6 +382,51 @@ void BareMetal::AddLinkRuntimeLib(const ArgList &Args, llvm_unreachable("Unhandled RuntimeLibType."); } +void baremetal::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // ar tool command "llvm-ar <options> <output_file> <input_files>". + ArgStringList CmdArgs; + // Create and insert file members with a deterministic index. + CmdArgs.push_back("rcsD"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) { + if (II.isFilename()) { + CmdArgs.push_back(II.getFilename()); + } + } + + // Delete old output archive file if it already exists before generating a new + // archive file. + const char *OutputFileName = Output.getFilename(); + if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) { + if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) { + D.Diag(diag::err_drv_unable_to_remove_file) << EC.message(); + return; + } + } + + const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath()); + C.addCommand(std::make_unique<Command>(JA, *this, + ResponseFileSupport::AtFileCurCP(), + Exec, CmdArgs, Inputs, Output)); +} + void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -293,22 +434,39 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { ArgStringList CmdArgs; - auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain()); + auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain()); + const llvm::Triple::ArchType Arch = TC.getArch(); + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); CmdArgs.push_back("-Bstatic"); - Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_e, options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_r}); + if (Triple.isARM() || Triple.isThumb()) { + bool IsBigEndian = arm::isARMBigEndian(Triple, Args); + if (IsBigEndian) + arm::appendBE8LinkFlag(Args, CmdArgs, Triple); + CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL"); + } else if (Triple.isAArch64()) { + CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL"); + } + + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_s, options::OPT_t, options::OPT_r}); TC.AddFilePathLibArgs(Args, CmdArgs); - CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); + for (const auto &LibPath : TC.getLibraryPaths()) + CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath))); + + const std::string FileName = TC.getCompilerRT(Args, "builtins"); + llvm::SmallString<128> PathBuf{FileName}; + llvm::sys::path::remove_filename(PathBuf); + CmdArgs.push_back(Args.MakeArgString("-L" + PathBuf)); if (TC.ShouldLinkCXXStdlib(Args)) TC.AddCXXStdlibLibArgs(Args, CmdArgs); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { CmdArgs.push_back("-lc"); CmdArgs.push_back("-lm"); @@ -316,10 +474,45 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, TC.AddLinkRuntimeLib(Args, CmdArgs); } + if (TC.getTriple().isRISCV()) + CmdArgs.push_back("-X"); + + // The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf + // and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and + // arm*-*-*bsd). + if (isARMBareMetal(TC.getTriple())) + CmdArgs.push_back("--target2=rel"); + CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Args.MakeArgString(TC.GetLinkerPath()), - CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output)); +} + +// BareMetal toolchain allows all sanitizers where the compiler generates valid +// code, ignoring all runtime library support issues on the assumption that +// baremetal targets typically implement their own runtime support. +SanitizerMask BareMetal::getSupportedSanitizers() const { + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::aarch64_be; + const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::KernelAddress; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; + Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::Vptr; + Res |= SanitizerKind::SafeStack; + Res |= SanitizerKind::Thread; + Res |= SanitizerKind::Scudo; + if (IsX86_64 || IsAArch64 || IsRISCV64) { + Res |= SanitizerKind::HWAddress; + Res |= SanitizerKind::KernelHWAddress; + } + return Res; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h index d68c43c64c97..67b5aa5998fc 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.h @@ -1,4 +1,4 @@ -//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===// +//===--- BareMetal.h - Bare Metal Tool and ToolChain ------------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -32,24 +32,22 @@ public: protected: Tool *buildLinker() const override; - - std::string buildCompilerRTBasename(const llvm::opt::ArgList &Args, - StringRef Component, - FileType Type = ToolChain::FT_Static, - bool AddArch = true) const override; + Tool *buildStaticLibTool() const override; public: bool useIntegratedAs() const override { return true; } + bool isBareMetal() const override { return true; } bool isCrossCompiling() const override { return true; } + bool HasNativeLLVMSupport() const override { return true; } bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } StringRef getOSLibName() const override { return "baremetal"; } - std::string getCompilerRTPath() const override; - RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; } @@ -59,12 +57,13 @@ public: const char *getDefaultLinker() const override { return "ld.lld"; } - std::string getRuntimesDir() const; - void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -73,6 +72,12 @@ public: void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; std::string computeSysRoot() const override; + SanitizerMask getSupportedSanitizers() const override; + +private: + using OrderedMultilibs = + llvm::iterator_range<llvm::SmallVector<Multilib>::const_reverse_iterator>; + OrderedMultilibs getOrderedMultilibs() const; }; } // namespace toolchains @@ -80,7 +85,21 @@ public: namespace tools { namespace baremetal { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY StaticLibTool : public Tool { +public: + StaticLibTool(const ToolChain &TC) + : Tool("baremetal::StaticLibTool", "llvm-ar", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {} bool isLinkJob() const override { return true; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp new file mode 100644 index 000000000000..feb3bc922920 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.cpp @@ -0,0 +1,204 @@ +//===--- CSKYToolchain.cpp - CSKY ToolChain Implementations ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CSKYToolChain.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/InputInfo.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, + const Multilib &Multilib, + StringRef InstallPath, + ToolChain::path_list &Paths) { + if (const auto &PathsCallback = Multilibs.filePathsCallback()) + for (const auto &Path : PathsCallback(Multilib)) + addPathIfExists(D, InstallPath + Path, Paths); +} + +/// CSKY Toolchain +CSKYToolChain::CSKYToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + GCCInstallation.init(Triple, Args); + if (GCCInstallation.isValid()) { + Multilibs = GCCInstallation.getMultilibs(); + SelectedMultilibs.assign({GCCInstallation.getMultilib()}); + path_list &Paths = getFilePaths(); + // Add toolchain/multilib specific file paths. + addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(), + GCCInstallation.getInstallPath(), Paths); + getFilePaths().push_back(GCCInstallation.getInstallPath().str() + + SelectedMultilibs.back().osSuffix()); + ToolChain::path_list &PPaths = getProgramPaths(); + // Multilib cross-compiler GCC installations put ld in a triple-prefixed + // directory off of the parent of the GCC installation. + PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple().str() + "/bin") + .str()); + PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str()); + getFilePaths().push_back(computeSysRoot() + "/lib" + + SelectedMultilibs.back().osSuffix()); + } else { + getProgramPaths().push_back(D.Dir); + getFilePaths().push_back(computeSysRoot() + "/lib"); + } +} + +Tool *CSKYToolChain::buildLinker() const { + return new tools::CSKY::Linker(*this); +} + +ToolChain::RuntimeLibType CSKYToolChain::GetDefaultRuntimeLibType() const { + return GCCInstallation.isValid() ? ToolChain::RLT_Libgcc + : ToolChain::RLT_CompilerRT; +} + +ToolChain::UnwindLibType +CSKYToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const { + return ToolChain::UNW_None; +} + +void CSKYToolChain::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind) const { + CC1Args.push_back("-nostdsysteminc"); +} + +void CSKYToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { + SmallString<128> Dir(computeSysRoot()); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + SmallString<128> Dir2(computeSysRoot()); + llvm::sys::path::append(Dir2, "sys-include"); + addSystemInclude(DriverArgs, CC1Args, Dir2.str()); + } +} + +void CSKYToolChain::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const GCCVersion &Version = GCCInstallation.getVersion(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text, + TripleStr, Multilib.includeSuffix(), DriverArgs, + CC1Args); +} + +std::string CSKYToolChain::computeSysRoot() const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + + SmallString<128> SysRootDir; + if (GCCInstallation.isValid()) { + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + llvm::sys::path::append(SysRootDir, LibDir, "..", TripleStr); + } else { + // Use the triple as provided to the driver. Unlike the parsed triple + // this has not been normalized to always contain every field. + llvm::sys::path::append(SysRootDir, getDriver().Dir, "..", + getDriver().getTargetTriple()); + } + + if (!llvm::sys::fs::exists(SysRootDir)) + return std::string(); + + return std::string(SysRootDir); +} + +void CSKY::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const ToolChain &ToolChain = getToolChain(); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + CmdArgs.push_back("-m"); + CmdArgs.push_back("cskyelf"); + + std::string Linker = getToolChain().GetLinkerPath(); + + bool WantCRTs = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + + const char *crtbegin, *crtend; + auto RuntimeLib = ToolChain.GetRuntimeLibType(Args); + if (RuntimeLib == ToolChain::RLT_Libgcc) { + crtbegin = "crtbegin.o"; + crtend = "crtend.o"; + } else { + assert(RuntimeLib == ToolChain::RLT_CompilerRT); + crtbegin = ToolChain.getCompilerRTArgString(Args, "crtbegin", + ToolChain::FT_Object); + crtend = + ToolChain.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object); + } + + if (WantCRTs) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + // TODO: add C++ includes and libs if compiling C++. + + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lc"); + if (Args.hasArg(options::OPT_msim)) + CmdArgs.push_back("-lsemi"); + else + CmdArgs.push_back("-lnosys"); + CmdArgs.push_back("--end-group"); + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); + } + + if (WantCRTs) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker), + CmdArgs, Inputs, Output)); +} +// CSKY tools end. diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h new file mode 100644 index 000000000000..a57324a42641 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CSKYToolChain.h @@ -0,0 +1,63 @@ +//===--- CSKYToolchain.h - CSKY ToolChain Implementations -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CSKYTOOLCHAIN_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CSKYTOOLCHAIN_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY CSKYToolChain : public Generic_ELF { +public: + CSKYToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind) const override; + RuntimeLibType GetDefaultRuntimeLibType() const override; + UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + +protected: + Tool *buildLinker() const override; + +private: + std::string computeSysRoot() const override; +}; + +} // end namespace toolchains + +namespace tools { +namespace CSKY { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("CSKY::Linker", "ld", TC) {} + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace CSKY +} // end namespace tools + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CSKYTOOLCHAIN_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp index cb38ab51327c..aa344b3465ab 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp @@ -10,6 +10,8 @@ #include "AMDGPU.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" +#include "Arch/CSKY.h" +#include "Arch/LoongArch.h" #include "Arch/M68k.h" #include "Arch/Mips.h" #include "Arch/PPC.h" @@ -22,29 +24,43 @@ #include "Hexagon.h" #include "MSP430.h" #include "PS4CPU.h" +#include "clang/Basic/CLWarnings.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/HeaderInclude.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/MakeSupport.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Driver/Action.h" #include "clang/Driver/Distro.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/Types.h" #include "clang/Driver/XRayArgs.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/YAMLParser.h" +#include "llvm/TargetParser/ARMTargetParserCommon.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/LoongArchTargetParser.h" +#include "llvm/TargetParser/RISCVTargetParser.h" +#include <cctype> using namespace clang::driver; using namespace clang::driver::tools; @@ -52,8 +68,11 @@ using namespace clang; using namespace llvm::opt; static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { - if (Arg *A = - Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC)) { + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC, + options::OPT_fminimize_whitespace, + options::OPT_fno_minimize_whitespace, + options::OPT_fkeep_system_includes, + options::OPT_fno_keep_system_includes)) { if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) && !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) { D.Diag(clang::diag::err_drv_argument_only_allowed_with) @@ -90,34 +109,6 @@ static void EscapeSpacesAndBackslashes(const char *Arg, } } -// Quote target names for inclusion in GNU Make dependency files. -// Only the characters '$', '#', ' ', '\t' are quoted. -static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) { - for (unsigned i = 0, e = Target.size(); i != e; ++i) { - switch (Target[i]) { - case ' ': - case '\t': - // Escape the preceding backslashes - for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j) - Res.push_back('\\'); - - // Escape the space/tab - Res.push_back('\\'); - break; - case '$': - Res.push_back('$'); - break; - case '#': - Res.push_back('\\'); - break; - default: - break; - } - - Res.push_back(Target[i]); - } -} - /// Apply \a Work on the current tool chain \a RegularToolChain and any other /// offloading tool chain that is associated with the current action \a JA. static void @@ -220,17 +211,21 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, llvm::StringMap<bool> OptionStrings; OptionStrings.insert(std::make_pair("divd", false)); OptionStrings.insert(std::make_pair("divf", false)); + OptionStrings.insert(std::make_pair("divh", false)); OptionStrings.insert(std::make_pair("vec-divd", false)); OptionStrings.insert(std::make_pair("vec-divf", false)); + OptionStrings.insert(std::make_pair("vec-divh", false)); OptionStrings.insert(std::make_pair("sqrtd", false)); OptionStrings.insert(std::make_pair("sqrtf", false)); + OptionStrings.insert(std::make_pair("sqrth", false)); OptionStrings.insert(std::make_pair("vec-sqrtd", false)); OptionStrings.insert(std::make_pair("vec-sqrtf", false)); + OptionStrings.insert(std::make_pair("vec-sqrth", false)); for (unsigned i = 0; i != NumOptions; ++i) { StringRef Val = A->getValue(i); - bool IsDisabled = Val.startswith(DisabledPrefixIn); + bool IsDisabled = Val.starts_with(DisabledPrefixIn); // Ignore the disablement token for string matching. if (IsDisabled) Val = Val.substr(1); @@ -249,10 +244,11 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, D.Diag(diag::err_drv_unknown_argument) << Val; return; } - // The option was specified without a float or double suffix. - // Make sure that the double entry was not already specified. + // The option was specified without a half or float or double suffix. + // Make sure that the double or half entry was not already specified. // The float entry will be checked below. - if (OptionStrings[ValBase.str() + 'd']) { + if (OptionStrings[ValBase.str() + 'd'] || + OptionStrings[ValBase.str() + 'h']) { D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; return; } @@ -267,9 +263,12 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, // Mark the matched option as found. Do not allow duplicate specifiers. OptionIter->second = true; - // If the precision was not specified, also mark the double entry as found. - if (ValBase.back() != 'f' && ValBase.back() != 'd') + // If the precision was not specified, also mark the double and half entry + // as found. + if (ValBase.back() != 'f' && ValBase.back() != 'd' && ValBase.back() != 'h') { OptionStrings[ValBase.str() + 'd'] = true; + OptionStrings[ValBase.str() + 'h'] = true; + } // Build the output string. StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; @@ -302,87 +301,6 @@ static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args, } } -static void getWebAssemblyTargetFeatures(const ArgList &Args, - std::vector<StringRef> &Features) { - handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); -} - -static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args, ArgStringList &CmdArgs, - bool ForAS, bool IsAux = false) { - std::vector<StringRef> Features; - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - mips::getMIPSTargetFeatures(D, Triple, Args, Features); - break; - - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - arm::getARMTargetFeatures(D, Triple, Args, CmdArgs, Features, ForAS); - break; - - case llvm::Triple::ppc: - case llvm::Triple::ppcle: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - ppc::getPPCTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - riscv::getRISCVTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::systemz: - systemz::getSystemZTargetFeatures(D, Args, Features); - break; - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - case llvm::Triple::aarch64_be: - aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS); - break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - x86::getX86TargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::hexagon: - hexagon::getHexagonTargetFeatures(D, Args, Features); - break; - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - getWebAssemblyTargetFeatures(Args, Features); - break; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - sparc::getSparcTargetFeatures(D, Args, Features); - break; - case llvm::Triple::r600: - case llvm::Triple::amdgcn: - amdgpu::getAMDGPUTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::m68k: - m68k::getM68kTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::msp430: - msp430::getMSP430TargetFeatures(D, Args, Features); - break; - case llvm::Triple::ve: - ve::getVETargetFeatures(D, Args, Features); - break; - } - - for (auto Feature : unifyTargetFeatures(Features)) { - CmdArgs.push_back(IsAux ? "-aux-target-feature" : "-target-feature"); - CmdArgs.push_back(Feature.data()); - } -} - static bool shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, const llvm::Triple &Triple) { @@ -401,7 +319,7 @@ shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, } /// Adds exception related arguments to the driver command arguments. There's a -/// master flag, -fexceptions and also language specific flags to enable/disable +/// main flag, -fexceptions and also language specific flags to enable/disable /// C++ and Objective-C exceptions. This makes it possible to for example /// disable C++ exceptions but enable Objective-C exceptions. static bool addExceptionArgs(const ArgList &Args, types::ID InputType, @@ -446,9 +364,9 @@ static bool addExceptionArgs(const ArgList &Args, types::ID InputType, } if (types::isCXX(InputType)) { - // Disable C++ EH by default on XCore and PS4. - bool CXXExceptionsEnabled = - Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU(); + // Disable C++ EH by default on XCore and PS4/PS5. + bool CXXExceptionsEnabled = Triple.getArch() != llvm::Triple::xcore && + !Triple.isPS() && !Triple.isDriverKit(); Arg *ExceptionArg = Args.getLastArg( options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions, options::OPT_fexceptions, options::OPT_fno_exceptions); @@ -469,6 +387,9 @@ static bool addExceptionArgs(const ArgList &Args, types::ID InputType, // So we do not set EH to false. Args.AddLastArg(CmdArgs, options::OPT_fignore_exceptions); + Args.addOptInFlag(CmdArgs, options::OPT_fassume_nothrow_exception_dtor, + options::OPT_fno_assume_nothrow_exception_dtor); + if (EH) CmdArgs.push_back("-fexceptions"); return EH; @@ -490,140 +411,10 @@ static bool ShouldEnableAutolink(const ArgList &Args, const ToolChain &TC, Default); } -// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases -// to the corresponding DebugInfoKind. -static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) { - assert(A.getOption().matches(options::OPT_gN_Group) && - "Not a -g option that specifies a debug-info level"); - if (A.getOption().matches(options::OPT_g0) || - A.getOption().matches(options::OPT_ggdb0)) - return codegenoptions::NoDebugInfo; - if (A.getOption().matches(options::OPT_gline_tables_only) || - A.getOption().matches(options::OPT_ggdb1)) - return codegenoptions::DebugLineTablesOnly; - if (A.getOption().matches(options::OPT_gline_directives_only)) - return codegenoptions::DebugDirectivesOnly; - return codegenoptions::DebugInfoConstructor; -} - -static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { - switch (Triple.getArch()){ - default: - return false; - case llvm::Triple::arm: - case llvm::Triple::thumb: - // ARM Darwin targets require a frame pointer to be always present to aid - // offline debugging via backtraces. - return Triple.isOSDarwin(); - } -} - -static bool useFramePointerForTargetByDefault(const ArgList &Args, - const llvm::Triple &Triple) { - if (Args.hasArg(options::OPT_pg) && !Args.hasArg(options::OPT_mfentry)) - return true; - - switch (Triple.getArch()) { - case llvm::Triple::xcore: - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - case llvm::Triple::msp430: - // XCore never wants frame pointers, regardless of OS. - // WebAssembly never wants frame pointers. - return false; - case llvm::Triple::ppc: - case llvm::Triple::ppcle: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - case llvm::Triple::amdgcn: - case llvm::Triple::r600: - return !areOptimizationsEnabled(Args); - default: - break; - } - - if (Triple.isOSNetBSD()) { - return !areOptimizationsEnabled(Args); - } - - if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI || - Triple.isOSHurd()) { - switch (Triple.getArch()) { - // Don't use a frame pointer on linux if optimizing for certain targets. - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - if (Triple.isAndroid()) - return true; - LLVM_FALLTHROUGH; - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::systemz: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return !areOptimizationsEnabled(Args); - default: - return true; - } - } - - if (Triple.isOSWindows()) { - switch (Triple.getArch()) { - case llvm::Triple::x86: - return !areOptimizationsEnabled(Args); - case llvm::Triple::x86_64: - return Triple.isOSBinFormatMachO(); - case llvm::Triple::arm: - case llvm::Triple::thumb: - // Windows on ARM builds with FPO disabled to aid fast stack walking - return true; - default: - // All other supported Windows ISAs use xdata unwind information, so frame - // pointers are not generally useful. - return false; - } - } - - return true; -} - -static CodeGenOptions::FramePointerKind -getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { - // We have 4 states: - // - // 00) leaf retained, non-leaf retained - // 01) leaf retained, non-leaf omitted (this is invalid) - // 10) leaf omitted, non-leaf retained - // (what -momit-leaf-frame-pointer was designed for) - // 11) leaf omitted, non-leaf omitted - // - // "omit" options taking precedence over "no-omit" options is the only way - // to make 3 valid states representable - Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, - options::OPT_fno_omit_frame_pointer); - bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer); - bool NoOmitFP = - A && A->getOption().matches(options::OPT_fno_omit_frame_pointer); - bool OmitLeafFP = Args.hasFlag(options::OPT_momit_leaf_frame_pointer, - options::OPT_mno_omit_leaf_frame_pointer, - Triple.isAArch64() || Triple.isPS4CPU()); - if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || - (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { - if (OmitLeafFP) - return CodeGenOptions::FramePointerKind::NonLeaf; - return CodeGenOptions::FramePointerKind::All; - } - return CodeGenOptions::FramePointerKind::None; -} - /// Add a CC1 option to specify the debug compilation directory. -static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, - const llvm::vfs::FileSystem &VFS) { +static const char *addDebugCompDirArg(const ArgList &Args, + ArgStringList &CmdArgs, + const llvm::vfs::FileSystem &VFS) { if (Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, options::OPT_fdebug_compilation_dir_EQ)) { if (A->getOption().matches(options::OPT_ffile_compilation_dir_EQ)) @@ -635,20 +426,62 @@ static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, VFS.getCurrentWorkingDirectory()) { CmdArgs.push_back(Args.MakeArgString("-fdebug-compilation-dir=" + *CWD)); } + StringRef Path(CmdArgs.back()); + return Path.substr(Path.find('=') + 1).data(); +} + +static void addDebugObjectName(const ArgList &Args, ArgStringList &CmdArgs, + const char *DebugCompilationDir, + const char *OutputFileName) { + // No need to generate a value for -object-file-name if it was provided. + for (auto *Arg : Args.filtered(options::OPT_Xclang)) + if (StringRef(Arg->getValue()).starts_with("-object-file-name")) + return; + + if (Args.hasArg(options::OPT_object_file_name_EQ)) + return; + + SmallString<128> ObjFileNameForDebug(OutputFileName); + if (ObjFileNameForDebug != "-" && + !llvm::sys::path::is_absolute(ObjFileNameForDebug) && + (!DebugCompilationDir || + llvm::sys::path::is_absolute(DebugCompilationDir))) { + // Make the path absolute in the debug infos like MSVC does. + llvm::sys::fs::make_absolute(ObjFileNameForDebug); + } + // If the object file name is a relative path, then always use Windows + // backslash style as -object-file-name is used for embedding object file path + // in codeview and it can only be generated when targeting on Windows. + // Otherwise, just use native absolute path. + llvm::sys::path::Style Style = + llvm::sys::path::is_absolute(ObjFileNameForDebug) + ? llvm::sys::path::Style::native + : llvm::sys::path::Style::windows_backslash; + llvm::sys::path::remove_dots(ObjFileNameForDebug, /*remove_dot_dot=*/true, + Style); + CmdArgs.push_back( + Args.MakeArgString(Twine("-object-file-name=") + ObjFileNameForDebug)); } /// Add a CC1 and CC1AS option to specify the debug file path prefix map. -static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { - for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, - options::OPT_fdebug_prefix_map_EQ)) { - StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) - D.Diag(diag::err_drv_invalid_argument_to_option) - << Map << A->getOption().getName(); +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 << 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. @@ -657,7 +490,7 @@ static void addMacroPrefixMapArg(const Driver &D, const ArgList &Args, for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fmacro_prefix_map_EQ)) { StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) + if (!Map.contains('=')) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else @@ -672,7 +505,7 @@ static void addCoveragePrefixMapArg(const Driver &D, const ArgList &Args, for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fcoverage_prefix_map_EQ)) { StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) + if (!Map.contains('=')) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else @@ -746,10 +579,10 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input, } static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, - const Driver &D, const InputInfo &Output, - const ArgList &Args, + const JobAction &JA, const InputInfo &Output, + const ArgList &Args, SanitizerArgs &SanArgs, ArgStringList &CmdArgs) { - + const Driver &D = TC.getDriver(); auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate, options::OPT_fprofile_generate_EQ, options::OPT_fno_profile_generate); @@ -757,12 +590,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) PGOGenerateArg = nullptr; - auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate, - options::OPT_fcs_profile_generate_EQ, - options::OPT_fno_profile_generate); - if (CSPGOGenerateArg && - CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) - CSPGOGenerateArg = nullptr; + auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args); auto *ProfileGenerateArg = Args.getLastArg( options::OPT_fprofile_instr_generate, @@ -794,14 +622,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, } if (TC.getTriple().isOSAIX()) { - if (PGOGenerateArg) - if (!D.isUsingLTO(false /*IsDeviceOffloadAction */) || - D.getLTOMode() != LTOK_Full) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) - << PGOGenerateArg->getSpelling() << "-flto"; - if (ProfileGenerateArg) - D.Diag(diag::err_drv_unsupported_opt_for_target) - << ProfileGenerateArg->getSpelling() << TC.getTriple().str(); if (Arg *ProfileSampleUseArg = getLastProfileSampleUseArg(Args)) D.Diag(diag::err_drv_unsupported_opt_for_target) << ProfileSampleUseArg->getSpelling() << TC.getTriple().str(); @@ -869,10 +689,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, options::OPT_fno_test_coverage, false) || Args.hasArg(options::OPT_coverage); bool EmitCovData = TC.needsGCovInstrumentation(Args); - if (EmitCovNotes) - CmdArgs.push_back("-ftest-coverage"); - if (EmitCovData) - CmdArgs.push_back("-fprofile-arcs"); if (Args.hasFlag(options::OPT_fcoverage_mapping, options::OPT_fno_coverage_mapping, false)) { @@ -884,6 +700,17 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, CmdArgs.push_back("-fcoverage-mapping"); } + if (Args.hasFlag(options::OPT_fmcdc_coverage, options::OPT_fno_mcdc_coverage, + false)) { + if (!Args.hasFlag(options::OPT_fcoverage_mapping, + options::OPT_fno_coverage_mapping, false)) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "-fcoverage-mcdc" + << "-fcoverage-mapping"; + + CmdArgs.push_back("-fcoverage-mcdc"); + } + if (Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, options::OPT_fcoverage_compilation_dir_EQ)) { if (A->getOption().matches(options::OPT_ffile_compilation_dir_EQ)) @@ -925,11 +752,30 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, CmdArgs.push_back("-fprofile-update=atomic"); else if (Val != "single") D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; - } else if (TC.getSanitizerArgs().needsTsanRt()) { - CmdArgs.push_back("-fprofile-update=atomic"); + << A->getSpelling() << Val; } + int FunctionGroups = 1; + int SelectedFunctionGroup = 0; + if (const auto *A = Args.getLastArg(options::OPT_fprofile_function_groups)) { + StringRef Val = A->getValue(); + if (Val.getAsInteger(0, FunctionGroups) || FunctionGroups < 1) + D.Diag(diag::err_drv_invalid_int_value) << A->getAsString(Args) << Val; + } + if (const auto *A = + Args.getLastArg(options::OPT_fprofile_selected_function_group)) { + StringRef Val = A->getValue(); + if (Val.getAsInteger(0, SelectedFunctionGroup) || + SelectedFunctionGroup < 0 || SelectedFunctionGroup >= FunctionGroups) + D.Diag(diag::err_drv_invalid_int_value) << A->getAsString(Args) << Val; + } + if (FunctionGroups != 1) + CmdArgs.push_back(Args.MakeArgString("-fprofile-function-groups=" + + Twine(FunctionGroups))); + if (SelectedFunctionGroup != 0) + CmdArgs.push_back(Args.MakeArgString("-fprofile-selected-function-group=" + + Twine(SelectedFunctionGroup))); + // Leave -fprofile-dir= an unused argument unless .gcda emission is // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider // the flag used. There is no -fno-profile-dir, so the user has no @@ -939,36 +785,45 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, Args.hasArg(options::OPT_coverage)) FProfileDir = Args.getLastArg(options::OPT_fprofile_dir); - // Put the .gcno and .gcda files (if needed) next to the object file or - // bitcode file in the case of LTO. - // FIXME: There should be a simpler way to find the object file for this - // input, and this code probably does the wrong thing for commands that - // compile and link all at once. - if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) && - (EmitCovNotes || EmitCovData) && Output.isFilename()) { - SmallString<128> OutputFilename; - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT__SLASH_Fo)) - OutputFilename = FinalOutput->getValue(); - else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) - OutputFilename = FinalOutput->getValue(); - else - OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); - SmallString<128> CoverageFilename = OutputFilename; + // TODO: Don't claim -c/-S to warn about -fsyntax-only -c/-S, -E -c/-S, + // like we warn about -fsyntax-only -E. + (void)(Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)); + + // Put the .gcno and .gcda files (if needed) next to the primary output file, + // or fall back to a file in the current directory for `clang -c --coverage + // d/a.c` in the absence of -o. + if (EmitCovNotes || EmitCovData) { + SmallString<128> CoverageFilename; + if (Arg *DumpDir = Args.getLastArgNoClaim(options::OPT_dumpdir)) { + // Form ${dumpdir}${basename}.gcno. Note that dumpdir may not end with a + // path separator. + CoverageFilename = DumpDir->getValue(); + CoverageFilename += llvm::sys::path::filename(Output.getBaseInput()); + } else if (Arg *FinalOutput = + C.getArgs().getLastArg(options::OPT__SLASH_Fo)) { + CoverageFilename = FinalOutput->getValue(); + } else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) { + CoverageFilename = FinalOutput->getValue(); + } else { + CoverageFilename = llvm::sys::path::filename(Output.getBaseInput()); + } if (llvm::sys::path::is_relative(CoverageFilename)) (void)D.getVFS().makeAbsolute(CoverageFilename); llvm::sys::path::replace_extension(CoverageFilename, "gcno"); - - CmdArgs.push_back("-coverage-notes-file"); - CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + if (EmitCovNotes) { + CmdArgs.push_back( + Args.MakeArgString("-coverage-notes-file=" + CoverageFilename)); + } if (EmitCovData) { if (FProfileDir) { + SmallString<128> Gcno = std::move(CoverageFilename); CoverageFilename = FProfileDir->getValue(); - llvm::sys::path::append(CoverageFilename, OutputFilename); + llvm::sys::path::append(CoverageFilename, Gcno); } llvm::sys::path::replace_extension(CoverageFilename, "gcda"); - CmdArgs.push_back("-coverage-data-file"); - CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + CmdArgs.push_back( + Args.MakeArgString("-coverage-data-file=" + CoverageFilename)); } } } @@ -978,11 +833,7 @@ static bool ContainsCompileAction(const Action *A) { if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A)) return true; - for (const auto &AI : A->inputs()) - if (ContainsCompileAction(AI)) - return true; - - return false; + return llvm::any_of(A->inputs(), ContainsCompileAction); } /// Check if -relax-all should be passed to the internal assembler. @@ -1007,52 +858,12 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { RelaxDefault); } -// Extract the integer N from a string spelled "-dwarf-N", returning 0 -// on mismatch. The StringRef input (rather than an Arg) allows -// for use by the "-Xassembler" option parser. -static unsigned DwarfVersionNum(StringRef ArgValue) { - return llvm::StringSwitch<unsigned>(ArgValue) - .Case("-gdwarf-2", 2) - .Case("-gdwarf-3", 3) - .Case("-gdwarf-4", 4) - .Case("-gdwarf-5", 5) - .Default(0); -} - -// Find a DWARF format version option. -// This function is a complementary for DwarfVersionNum(). -static const Arg *getDwarfNArg(const ArgList &Args) { - return Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, - options::OPT_gdwarf_4, options::OPT_gdwarf_5, - options::OPT_gdwarf); -} - -static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind DebugInfoKind, - unsigned DwarfVersion, - llvm::DebuggerKind DebuggerTuning) { - switch (DebugInfoKind) { - case codegenoptions::DebugDirectivesOnly: - CmdArgs.push_back("-debug-info-kind=line-directives-only"); - break; - case codegenoptions::DebugLineTablesOnly: - CmdArgs.push_back("-debug-info-kind=line-tables-only"); - break; - case codegenoptions::DebugInfoConstructor: - CmdArgs.push_back("-debug-info-kind=constructor"); - break; - case codegenoptions::LimitedDebugInfo: - CmdArgs.push_back("-debug-info-kind=limited"); - break; - case codegenoptions::FullDebugInfo: - CmdArgs.push_back("-debug-info-kind=standalone"); - break; - case codegenoptions::UnusedTypeInfo: - CmdArgs.push_back("-debug-info-kind=unused-types"); - break; - default: - break; - } +static void +RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, + llvm::codegenoptions::DebugInfoKind DebugInfoKind, + unsigned DwarfVersion, + llvm::DebuggerKind DebuggerTuning) { + addDebugInfoKind(CmdArgs, DebugInfoKind); if (DwarfVersion > 0) CmdArgs.push_back( Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion))); @@ -1095,40 +906,31 @@ static void RenderDebugInfoCompressionArgs(const ArgList &Args, StringRef Value = A->getValue(); if (Value == "none") { CmdArgs.push_back("--compress-debug-sections=none"); - } else if (Value == "zlib" || Value == "zlib-gnu") { - if (llvm::zlib::isAvailable()) { + } else if (Value == "zlib") { + if (llvm::compression::zlib::isAvailable()) { + CmdArgs.push_back( + Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); + } else { + D.Diag(diag::warn_debug_compression_unavailable) << "zlib"; + } + } else if (Value == "zstd") { + if (llvm::compression::zstd::isAvailable()) { CmdArgs.push_back( Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); } else { - D.Diag(diag::warn_debug_compression_unavailable); + D.Diag(diag::warn_debug_compression_unavailable) << "zstd"; } } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } -static const char *RelocationModelName(llvm::Reloc::Model Model) { - switch (Model) { - case llvm::Reloc::Static: - return "static"; - case llvm::Reloc::PIC_: - return "pic"; - case llvm::Reloc::DynamicNoPIC: - return "dynamic-no-pic"; - case llvm::Reloc::ROPI: - return "ropi"; - case llvm::Reloc::RWPI: - return "rwpi"; - case llvm::Reloc::ROPI_RWPI: - return "ropi-rwpi"; - } - llvm_unreachable("Unknown Reloc::Model kind"); -} static void handleAMDGPUCodeObjectVersionOptions(const Driver &D, const ArgList &Args, - ArgStringList &CmdArgs) { + ArgStringList &CmdArgs, + bool IsCC1As = false) { // If no version was requested by the user, use the default value from the // back end. This is consistent with the value returned from // getAMDGPUCodeObjectVersion. This lets clang emit IR for amdgpu without @@ -1140,9 +942,53 @@ static void handleAMDGPUCodeObjectVersionOptions(const Driver &D, Args.MakeArgString(Twine("--amdhsa-code-object-version=") + Twine(CodeObjVer))); CmdArgs.insert(CmdArgs.begin() + 1, "-mllvm"); + // -cc1as does not accept -mcode-object-version option. + if (!IsCC1As) + CmdArgs.insert(CmdArgs.begin() + 1, + Args.MakeArgString(Twine("-mcode-object-version=") + + Twine(CodeObjVer))); } } +static bool maybeHasClangPchSignature(const Driver &D, StringRef Path) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MemBuf = + D.getVFS().getBufferForFile(Path); + if (!MemBuf) + return false; + llvm::file_magic Magic = llvm::identify_magic((*MemBuf)->getBuffer()); + if (Magic == llvm::file_magic::unknown) + return false; + // Return true for both raw Clang AST files and object files which may + // contain a __clangast section. + if (Magic == llvm::file_magic::clang_ast) + return true; + Expected<std::unique_ptr<llvm::object::ObjectFile>> Obj = + llvm::object::ObjectFile::createObjectFile(**MemBuf, Magic); + return !Obj.takeError(); +} + +static bool gchProbe(const Driver &D, StringRef Path) { + llvm::ErrorOr<llvm::vfs::Status> Status = D.getVFS().status(Path); + if (!Status) + return false; + + if (Status->isDirectory()) { + std::error_code EC; + for (llvm::vfs::directory_iterator DI = D.getVFS().dir_begin(Path, EC), DE; + !EC && DI != DE; DI = DI.increment(EC)) { + if (maybeHasClangPchSignature(D, DI->path())) + return true; + } + D.Diag(diag::warn_drv_pch_ignoring_gch_dir) << Path; + return false; + } + + if (maybeHasClangPchSignature(D, Path)) + return true; + D.Diag(diag::warn_drv_pch_ignoring_gch_file) << Path; + return false; +} + void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, @@ -1195,7 +1041,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, } else { CmdArgs.push_back("-MT"); SmallString<128> Quoted; - QuoteTarget(A->getValue(), Quoted); + quoteMakeTarget(A->getValue(), Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); } } @@ -1220,7 +1066,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, CmdArgs.push_back("-MT"); SmallString<128> Quoted; - QuoteTarget(DepTarget, Quoted); + quoteMakeTarget(DepTarget, Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); } @@ -1252,9 +1098,38 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, if (JA.isOffloading(Action::OFK_HIP)) getToolChain().AddHIPIncludeArgs(Args, CmdArgs); + // If we are compiling for a GPU target we want to override the system headers + // with ones created by the 'libc' project if present. + if (!Args.hasArg(options::OPT_nostdinc) && + !Args.hasArg(options::OPT_nogpuinc) && + !Args.hasArg(options::OPT_nobuiltininc)) { + // Without an offloading language we will include these headers directly. + // Offloading languages will instead only use the declarations stored in + // the resource directory at clang/lib/Headers/llvm_libc_wrappers. + if ((getToolChain().getTriple().isNVPTX() || + getToolChain().getTriple().isAMDGCN()) && + C.getActiveOffloadKinds() == Action::OFK_None) { + SmallString<128> P(llvm::sys::path::parent_path(D.InstalledDir)); + llvm::sys::path::append(P, "include"); + llvm::sys::path::append(P, "gpu-none-llvm"); + CmdArgs.push_back("-c-isystem"); + CmdArgs.push_back(Args.MakeArgString(P)); + } else if (C.getActiveOffloadKinds() == Action::OFK_OpenMP) { + // TODO: CUDA / HIP include their own headers for some common functions + // implemented here. We'll need to clean those up so they do not conflict. + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + llvm::sys::path::append(P, "llvm_libc_wrappers"); + CmdArgs.push_back("-internal-isystem"); + CmdArgs.push_back(Args.MakeArgString(P)); + } + } + // If we are offloading to a target via OpenMP we need to include the // openmp_wrappers folder which contains alternative system headers. if (JA.isDeviceOffloading(Action::OFK_OpenMP) && + !Args.hasArg(options::OPT_nostdinc) && + !Args.hasArg(options::OPT_nogpuinc) && (getToolChain().getTriple().isNVPTX() || getToolChain().getTriple().isAMDGCN())) { if (!Args.hasArg(options::OPT_nobuiltininc)) { @@ -1311,7 +1186,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, bool RenderedImplicitInclude = false; for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - if (A->getOption().matches(options::OPT_include)) { + if (A->getOption().matches(options::OPT_include) && + D.getProbePrecompiled()) { // Handling of gcc-style gch precompiled headers. bool IsFirstImplicitInclude = !RenderedImplicitInclude; RenderedImplicitInclude = true; @@ -1322,14 +1198,13 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // so that replace_extension does the right thing. P += ".dummy"; llvm::sys::path::replace_extension(P, "pch"); - if (llvm::sys::fs::exists(P)) + if (D.getVFS().exists(P)) FoundPCH = true; if (!FoundPCH) { + // For GCC compat, probe for a file or directory ending in .gch instead. llvm::sys::path::replace_extension(P, "gch"); - if (llvm::sys::fs::exists(P)) { - FoundPCH = true; - } + FoundPCH = gchProbe(D, P.str()); } if (FoundPCH) { @@ -1354,6 +1229,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, } else if (A->getOption().matches(options::OPT_stdlibxx_isystem)) { // Translated to -internal-isystem by the driver, no need to pass to cc1. continue; + } else if (A->getOption().matches(options::OPT_ibuiltininc)) { + // This is used only by the driver. No need to pass to cc1. + continue; } // Not translated, render as usual. @@ -1361,7 +1239,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } - Args.AddAllArgs(CmdArgs, + Args.addAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I_Group, options::OPT_F, options::OPT_index_header_map}); @@ -1431,6 +1309,17 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, addMacroPrefixMapArg(D, Args, CmdArgs); addCoveragePrefixMapArg(D, Args, CmdArgs); + + Args.AddLastArg(CmdArgs, options::OPT_ffile_reproducible, + options::OPT_fno_file_reproducible); + + if (const char *Epoch = std::getenv("SOURCE_DATE_EPOCH")) { + CmdArgs.push_back("-source-date-epoch"); + CmdArgs.push_back(Args.MakeArgString(Epoch)); + } + + Args.addOptInFlag(CmdArgs, options::OPT_fdefine_target_os_macros, + options::OPT_fno_define_target_os_macros); } // FIXME: Move to target hook. @@ -1587,8 +1476,8 @@ void AddAAPCSVolatileBitfieldArgs(const ArgList &Args, ArgStringList &CmdArgs) { } namespace { -void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args, - ArgStringList &CmdArgs) { +void RenderARMABI(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, ArgStringList &CmdArgs) { // Select the ABI to use. // FIXME: Support -meabi. // FIXME: Parts of this are duplicated in the backend, unify this somehow. @@ -1596,18 +1485,85 @@ void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(); } else { - std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); + std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ false); ABIName = llvm::ARM::computeDefaultTargetABI(Triple, CPU).data(); } CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); } + +void AddUnalignedAccessWarning(ArgStringList &CmdArgs) { + auto StrictAlignIter = + llvm::find_if(llvm::reverse(CmdArgs), [](StringRef Arg) { + return Arg == "+strict-align" || Arg == "-strict-align"; + }); + if (StrictAlignIter != CmdArgs.rend() && + StringRef(*StrictAlignIter) == "+strict-align") + CmdArgs.push_back("-Wunaligned-access"); +} +} + +static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs, bool isAArch64) { + const Arg *A = isAArch64 + ? Args.getLastArg(options::OPT_msign_return_address_EQ, + options::OPT_mbranch_protection_EQ) + : Args.getLastArg(options::OPT_mbranch_protection_EQ); + if (!A) + return; + + const Driver &D = TC.getDriver(); + const llvm::Triple &Triple = TC.getEffectiveTriple(); + if (!(isAArch64 || (Triple.isArmT32() && Triple.isArmMClass()))) + D.Diag(diag::warn_incompatible_branch_protection_option) + << Triple.getArchName(); + + StringRef Scope, Key; + bool IndirectBranches, BranchProtectionPAuthLR, GuardedControlStack; + + if (A->getOption().matches(options::OPT_msign_return_address_EQ)) { + Scope = A->getValue(); + if (Scope != "none" && Scope != "non-leaf" && Scope != "all") + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Scope; + Key = "a_key"; + IndirectBranches = false; + BranchProtectionPAuthLR = false; + GuardedControlStack = false; + } else { + StringRef DiagMsg; + llvm::ARM::ParsedBranchProtection PBP; + if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg)) + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << DiagMsg; + if (!isAArch64 && PBP.Key == "b_key") + D.Diag(diag::warn_unsupported_branch_protection) + << "b-key" << A->getAsString(Args); + Scope = PBP.Scope; + Key = PBP.Key; + BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR; + IndirectBranches = PBP.BranchTargetEnforcement; + GuardedControlStack = PBP.GuardedControlStack; + } + + CmdArgs.push_back( + Args.MakeArgString(Twine("-msign-return-address=") + Scope)); + if (!Scope.equals("none")) + CmdArgs.push_back( + Args.MakeArgString(Twine("-msign-return-address-key=") + Key)); + if (BranchProtectionPAuthLR) + CmdArgs.push_back( + Args.MakeArgString(Twine("-mbranch-protection-pauth-lr"))); + if (IndirectBranches) + CmdArgs.push_back("-mbranch-target-enforce"); + if (GuardedControlStack) + CmdArgs.push_back("-mguarded-control-stack"); } void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, bool KernelOrKext) const { - RenderARMABI(Triple, Args, CmdArgs); + RenderARMABI(getToolChain().getDriver(), Triple, Args, CmdArgs); // Determine floating point ABI from the options & target defaults. arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); @@ -1646,6 +1602,11 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, CmdArgs.push_back("-mcmse"); AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); + + // Enable/disable return address signing and indirect branch targets. + CollectARMPACBTIOptions(getToolChain(), Args, CmdArgs, false /*isAArch64*/); + + AddUnalignedAccessWarning(CmdArgs); } void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, @@ -1667,14 +1628,17 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, case llvm::Triple::thumbeb: // Use the effective triple, which takes into account the deployment target. AddARMTargetArgs(EffectiveTriple, Args, CmdArgs, KernelOrKext); - CmdArgs.push_back("-fallow-half-arguments-and-returns"); break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: AddAArch64TargetArgs(Args, CmdArgs); - CmdArgs.push_back("-fallow-half-arguments-and-returns"); + break; + + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + AddLoongArchTargetArgs(Args, CmdArgs); break; case llvm::Triple::mips: @@ -1761,19 +1725,6 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, RenderAArch64ABI(Triple, Args, CmdArgs); - if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769, - options::OPT_mno_fix_cortex_a53_835769)) { - CmdArgs.push_back("-mllvm"); - if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769)) - CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); - else - CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0"); - } else if (Triple.isAndroid()) { - // Enabled A53 errata (835769) workaround by default on android - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); - } - // Forward the -mglobal-merge option for explicit control over the pass. if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, options::OPT_mno_global_merge)) { @@ -1785,57 +1736,66 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, } // Enable/disable return address signing and indirect branch targets. - if (Arg *A = Args.getLastArg(options::OPT_msign_return_address_EQ, - options::OPT_mbranch_protection_EQ)) { - - const Driver &D = getToolChain().getDriver(); - - StringRef Scope, Key; - bool IndirectBranches; - - 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); - Key = "a_key"; - IndirectBranches = false; - } else { - StringRef Err; - llvm::AArch64::ParsedBranchProtection PBP; - if (!llvm::AArch64::parseBranchProtection(A->getValue(), PBP, Err)) - D.Diag(diag::err_invalid_branch_protection) - << Err << A->getAsString(Args); - Scope = PBP.Scope; - Key = PBP.Key; - IndirectBranches = PBP.BranchTargetEnforcement; - } - - CmdArgs.push_back( - Args.MakeArgString(Twine("-msign-return-address=") + Scope)); - CmdArgs.push_back( - Args.MakeArgString(Twine("-msign-return-address-key=") + Key)); - if (IndirectBranches) - CmdArgs.push_back("-mbranch-target-enforce"); - } + CollectARMPACBTIOptions(getToolChain(), Args, CmdArgs, true /*isAArch64*/); // Handle -msve_vector_bits=<bits> if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { StringRef Val = A->getValue(); const Driver &D = getToolChain().getDriver(); if (Val.equals("128") || Val.equals("256") || Val.equals("512") || - Val.equals("1024") || Val.equals("2048")) + Val.equals("1024") || Val.equals("2048") || Val.equals("128+") || + Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") || + Val.equals("2048+")) { + unsigned Bits = 0; + if (Val.ends_with("+")) + Val = Val.substr(0, Val.size() - 1); + else { + bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid; + assert(!Invalid && "Failed to parse value"); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128))); + } + + bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid; + assert(!Invalid && "Failed to parse value"); CmdArgs.push_back( - Args.MakeArgString(llvm::Twine("-msve-vector-bits=") + Val)); + Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128))); // Silently drop requests for vector-length agnostic code as it's implied. - else if (!Val.equals("scalable")) + } else if (!Val.equals("scalable")) // Handle the unsupported values passed to msve-vector-bits. D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { + CmdArgs.push_back("-tune-cpu"); + if (strcmp(A->getValue(), "native") == 0) + CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); + else + CmdArgs.push_back(A->getValue()); + } + + AddUnalignedAccessWarning(CmdArgs); +} + +void Clang::AddLoongArchTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const llvm::Triple &Triple = getToolChain().getTriple(); + + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back( + loongarch::getLoongArchABI(getToolChain().getDriver(), Args, Triple) + .data()); + + // Handle -mtune. + if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { + std::string TuneCPU = A->getValue(); + TuneCPU = loongarch::postProcessTargetCPUString(TuneCPU, Triple); + CmdArgs.push_back("-tune-cpu"); + CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + } } void Clang::AddMIPSTargetArgs(const ArgList &Args, @@ -1878,6 +1838,11 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, } } + if (Args.getLastArg(options::OPT_mfix4300)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mfix4300"); + } + if (Arg *A = Args.getLastArg(options::OPT_G)) { StringRef v = A->getValue(); CmdArgs.push_back("-mllvm"); @@ -1967,7 +1932,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val)); } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } else D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName; } @@ -1983,14 +1948,20 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, void Clang::AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + const llvm::Triple &T = getToolChain().getTriple(); + if (Args.getLastArg(options::OPT_mtune_EQ)) { + CmdArgs.push_back("-tune-cpu"); + std::string CPU = ppc::getPPCTuneCPU(Args, T); + CmdArgs.push_back(Args.MakeArgString(CPU)); + } + // Select the ABI to use. const char *ABIName = nullptr; - const llvm::Triple &T = getToolChain().getTriple(); if (T.isOSBinFormatELF()) { switch (getToolChain().getArch()) { case llvm::Triple::ppc64: { - if ((T.isOSFreeBSD() && T.getOSMajorVersion() >= 13) || - T.isOSOpenBSD() || T.isMusl()) + if (T.isPPC64ELFv2ABI()) ABIName = "elfv2"; else ABIName = "elfv1"; @@ -2004,14 +1975,29 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, } } - bool IEEELongDouble = false; + bool IEEELongDouble = getToolChain().defaultToIEEELongDouble(); + bool VecExtabi = false; for (const Arg *A : Args.filtered(options::OPT_mabi_EQ)) { StringRef V = A->getValue(); - if (V == "ieeelongdouble") + if (V == "ieeelongdouble") { IEEELongDouble = true; - else if (V == "ibmlongdouble") + A->claim(); + } else if (V == "ibmlongdouble") { IEEELongDouble = false; - else if (V != "altivec") + A->claim(); + } else if (V == "vec-default") { + VecExtabi = false; + A->claim(); + } else if (V == "vec-extabi") { + VecExtabi = true; + A->claim(); + } else if (V == "elfv1") { + ABIName = "elfv1"; + A->claim(); + } else if (V == "elfv2") { + ABIName = "elfv2"; + A->claim(); + } else if (V != "altivec") // The ppc64 linux abis are all "altivec" abis by default. Accept and ignore // the option if given as we don't have backend support for any targets // that don't use the altivec abi. @@ -2019,10 +2005,14 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, } if (IEEELongDouble) CmdArgs.push_back("-mabi=ieeelongdouble"); + if (VecExtabi) { + if (!T.isOSAIX()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << "-mabi=vec-extabi" << T.str(); + CmdArgs.push_back("-mabi=vec-extabi"); + } - ppc::FloatABI FloatABI = - ppc::getPPCFloatABI(getToolChain().getDriver(), Args); - + ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); if (FloatABI == ppc::FloatABI::Soft) { // Floating point operations and argument passing are soft. CmdArgs.push_back("-msoft-float"); @@ -2063,6 +2053,12 @@ static void SetRISCVSmallDataLimit(const ToolChain &TC, const ArgList &Args, if (Args.hasArg(options::OPT_G)) { D.Diag(diag::warn_drv_unsupported_sdata); } + } else if (Triple.isAndroid()) { + // GP relaxation is not supported on Android. + SmallDataLimit = "0"; + if (Args.hasArg(options::OPT_G)) { + D.Diag(diag::warn_drv_unsupported_sdata); + } } else if (Arg *A = Args.getLastArg(options::OPT_G)) { SmallDataLimit = A->getValue(); } @@ -2081,18 +2077,57 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args, SetRISCVSmallDataLimit(getToolChain(), Args, CmdArgs); - std::string TuneCPU; - - if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { - StringRef Name = A->getValue(); + if (!Args.hasFlag(options::OPT_mimplicit_float, + options::OPT_mno_implicit_float, true)) + CmdArgs.push_back("-no-implicit-float"); - Name = llvm::RISCV::resolveTuneCPUAlias(Name, Triple.isArch64Bit()); - TuneCPU = std::string(Name); + if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { + CmdArgs.push_back("-tune-cpu"); + if (strcmp(A->getValue(), "native") == 0) + CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); + else + CmdArgs.push_back(A->getValue()); } - if (!TuneCPU.empty()) { - CmdArgs.push_back("-tune-cpu"); - CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + // Handle -mrvv-vector-bits=<bits> + if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) { + StringRef Val = A->getValue(); + const Driver &D = getToolChain().getDriver(); + + // Get minimum VLen from march. + unsigned MinVLen = 0; + StringRef Arch = riscv::getRISCVArch(Args, Triple); + auto ISAInfo = llvm::RISCVISAInfo::parseArchString( + Arch, /*EnableExperimentalExtensions*/ true); + // Ignore parsing error. + if (!errorToBool(ISAInfo.takeError())) + MinVLen = (*ISAInfo)->getMinVLen(); + + // If the value is "zvl", use MinVLen from march. Otherwise, try to parse + // as integer as long as we have a MinVLen. + unsigned Bits = 0; + if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) { + Bits = MinVLen; + } else if (!Val.getAsInteger(10, Bits)) { + // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that + // at least MinVLen. + if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock || + Bits > 65536 || !llvm::isPowerOf2_32(Bits)) + Bits = 0; + } + + // If we got a valid value try to use it. + if (Bits != 0) { + unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock; + CmdArgs.push_back( + Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin))); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin))); + } else if (!Val.equals("scalable")) { + // Handle the unsupported values passed to mrvv-vector-bits. + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } } } @@ -2112,12 +2147,32 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("hard"); } + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { + StringRef Name = A->getValue(); + std::string TuneCPU; + if (Name == "native") + TuneCPU = std::string(llvm::sys::getHostCPUName()); + else + TuneCPU = std::string(Name); + + CmdArgs.push_back("-tune-cpu"); + CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + } } void Clang::AddSystemZTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - bool HasBackchain = Args.hasFlag(options::OPT_mbackchain, - options::OPT_mno_backchain, false); + if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { + CmdArgs.push_back("-tune-cpu"); + if (strcmp(A->getValue(), "native") == 0) + CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); + else + CmdArgs.push_back(A->getValue()); + } + + bool HasBackchain = + Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false); bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack, options::OPT_mno_packed_stack, false); systemz::FloatABI FloatABI = @@ -2173,15 +2228,21 @@ void Clang::AddX86TargetArgs(const ArgList &Args, if (Value == "intel" || Value == "att") { CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); + CmdArgs.push_back(Args.MakeArgString("-inline-asm=" + Value)); } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } else if (D.IsCLMode()) { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-x86-asm-syntax=intel"); } + if (Arg *A = Args.getLastArg(options::OPT_mskip_rax_setup, + options::OPT_mno_skip_rax_setup)) + if (A->getOption().matches(options::OPT_mskip_rax_setup)) + CmdArgs.push_back(Args.MakeArgString("-mskip-rax-setup")); + // Set flags to support MCU ABI. if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) { CmdArgs.push_back("-mfloat-abi"); @@ -2191,10 +2252,10 @@ void Clang::AddX86TargetArgs(const ArgList &Args, // Handle -mtune. - // Default to "generic" unless -march is present or targetting the PS4. + // Default to "generic" unless -march is present or targetting the PS4/PS5. std::string TuneCPU; if (!Args.hasArg(clang::driver::options::OPT_march_EQ) && - !getToolChain().getTriple().isPS4CPU()) + !getToolChain().getTriple().isPS()) TuneCPU = "generic"; // Override based on -mtune. @@ -2222,8 +2283,8 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args, if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-hexagon-small-data-threshold=" + - Twine(G.getValue()))); + CmdArgs.push_back( + Args.MakeArgString("-hexagon-small-data-threshold=" + Twine(*G))); } if (!Args.hasArg(options::OPT_fno_short_enums)) @@ -2253,7 +2314,7 @@ void Clang::AddLanaiTargetArgs(const ArgList &Args, if (Mregparm != 4) { getToolChain().getDriver().Diag( diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } @@ -2263,10 +2324,8 @@ void Clang::AddWebAssemblyTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Default to "hidden" visibility. if (!Args.hasArg(options::OPT_fvisibility_EQ, - options::OPT_fvisibility_ms_compat)) { - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back("hidden"); - } + options::OPT_fvisibility_ms_compat)) + CmdArgs.push_back("-fvisibility=hidden"); } void Clang::AddVETargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { @@ -2288,7 +2347,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, if (!CompilationDatabase) { std::error_code EC; auto File = std::make_unique<llvm::raw_fd_ostream>( - Filename, EC, llvm::sys::fs::OF_TextWithCRLF); + Filename, EC, + llvm::sys::fs::OF_TextWithCRLF | llvm::sys::fs::OF_Append); if (EC) { D.Diag(clang::diag::err_drv_compilationdatabase) << Filename << EC.message(); @@ -2302,7 +2362,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, CWD = "."; CDB << "{ \"directory\": \"" << escape(*CWD) << "\""; CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\""; - CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\""; + if (Output.isFilename()) + CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\""; CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\""; SmallString<128> Buf; Buf = "-x"; @@ -2314,6 +2375,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, CDB << ", \"" << escape(Buf) << "\""; } CDB << ", \"" << escape(Input.getFilename()) << "\""; + if (Output.isFilename()) + CDB << ", \"-o\", \"" << escape(Output.getFilename()) << "\""; for (auto &A: Args) { auto &O = A->getOption(); // Skip language selection, which is positional. @@ -2327,6 +2390,9 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, // Skip inputs. if (O.getKind() == Option::InputClass) continue; + // Skip output. + if (O.getID() == options::OPT_o) + continue; // All other arguments are quoted and appended. ArgStringList ASL; A->render(Args, ASL); @@ -2400,6 +2466,11 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, DefaultIncrementalLinkerCompatible)) CmdArgs.push_back("-mincremental-linker-compatible"); + Args.AddLastArg(CmdArgs, options::OPT_femit_dwarf_unwind_EQ); + + Args.addOptInFlag(CmdArgs, options::OPT_femit_compact_unwind_non_canonical, + options::OPT_fno_emit_compact_unwind_non_canonical); + // If you add more args here, also add them to the block below that // starts with "// If CollectArgsForIntegratedAssembler() isn't called below". @@ -2411,7 +2482,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, bool TakeNextArg = false; bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations(); - bool UseNoExecStack = C.getDefaultToolChain().isNoExecStackDefault(); + bool UseNoExecStack = false; const char *MipsTargetFeature = nullptr; StringRef ImplicitIt; for (const Arg *A : @@ -2429,7 +2500,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, ImplicitIt = A->getValue(); if (!CheckARMImplicitITArg(ImplicitIt)) D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << ImplicitIt; + << A->getSpelling() << ImplicitIt; continue; default: break; @@ -2450,11 +2521,18 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, switch (C.getDefaultToolChain().getArch()) { default: break; + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + if (Value == "--no-type-check") { + CmdArgs.push_back("-mno-type-check"); + continue; + } + break; case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::arm: case llvm::Triple::armeb: - if (Value.startswith("-mimplicit-it=")) { + if (Value.starts_with("-mimplicit-it=")) { // Only store the value; the last value set takes effect. ImplicitIt = Value.split("=").second; if (CheckARMImplicitITArg(ImplicitIt)) @@ -2479,12 +2557,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, CmdArgs.push_back("-use-tcc-in-div"); continue; } - if (Value.startswith("-msoft-float")) { + if (Value.starts_with("-msoft-float")) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+soft-float"); continue; } - if (Value.startswith("-mhard-float")) { + if (Value.starts_with("-mhard-float")) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("-soft-float"); continue; @@ -2521,8 +2599,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, CmdArgs.push_back("-massembler-no-warn"); } else if (Value == "--noexecstack") { UseNoExecStack = true; - } else if (Value.startswith("-compress-debug-sections") || - Value.startswith("--compress-debug-sections") || + } else if (Value.starts_with("-compress-debug-sections") || + Value.starts_with("--compress-debug-sections") || Value == "-nocompress-debug-sections" || Value == "--nocompress-debug-sections") { CmdArgs.push_back(Value.data()); @@ -2532,46 +2610,46 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } else if (Value == "-mrelax-relocations=no" || Value == "--mrelax-relocations=no") { UseRelaxRelocations = false; - } else if (Value.startswith("-I")) { + } else if (Value.starts_with("-I")) { CmdArgs.push_back(Value.data()); // We need to consume the next argument if the current arg is a plain // -I. The next arg will be the include directory. if (Value == "-I") TakeNextArg = true; - } else if (Value.startswith("-gdwarf-")) { + } else if (Value.starts_with("-gdwarf-")) { // "-gdwarf-N" options are not cc1as options. unsigned DwarfVersion = DwarfVersionNum(Value); if (DwarfVersion == 0) { // Send it onward, and let cc1as complain. CmdArgs.push_back(Value.data()); } else { RenderDebugEnablingArgs(Args, CmdArgs, - codegenoptions::DebugInfoConstructor, + llvm::codegenoptions::DebugInfoConstructor, DwarfVersion, llvm::DebuggerKind::Default); } - } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || - Value.startswith("-mhwdiv") || Value.startswith("-march")) { + } else if (Value.starts_with("-mcpu") || Value.starts_with("-mfpu") || + Value.starts_with("-mhwdiv") || Value.starts_with("-march")) { // Do nothing, we'll validate it later. } else if (Value == "-defsym") { - if (A->getNumValues() != 2) { - D.Diag(diag::err_drv_defsym_invalid_format) << Value; - break; - } - const char *S = A->getValue(1); - auto Pair = StringRef(S).split('='); - auto Sym = Pair.first; - auto SVal = Pair.second; - - if (Sym.empty() || SVal.empty()) { - D.Diag(diag::err_drv_defsym_invalid_format) << S; - break; - } - int64_t IVal; - if (SVal.getAsInteger(0, IVal)) { - D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; - break; - } - CmdArgs.push_back(Value.data()); - TakeNextArg = true; + if (A->getNumValues() != 2) { + D.Diag(diag::err_drv_defsym_invalid_format) << Value; + break; + } + const char *S = A->getValue(1); + auto Pair = StringRef(S).split('='); + auto Sym = Pair.first; + auto SVal = Pair.second; + + if (Sym.empty() || SVal.empty()) { + D.Diag(diag::err_drv_defsym_invalid_format) << S; + break; + } + int64_t IVal; + if (SVal.getAsInteger(0, IVal)) { + D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; + break; + } + CmdArgs.push_back(Value.data()); + TakeNextArg = true; } else if (Value == "-fdebug-compilation-dir") { CmdArgs.push_back("-fdebug-compilation-dir"); TakeNextArg = true; @@ -2585,14 +2663,14 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, D.PrintVersion(C, llvm::outs()); } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } if (ImplicitIt.size()) AddARMImplicitITArgs(Args, CmdArgs, ImplicitIt); - if (UseRelaxRelocations) - CmdArgs.push_back("--mrelax-relocations"); + if (!UseRelaxRelocations) + CmdArgs.push_back("-mrelax-relocations=no"); if (UseNoExecStack) CmdArgs.push_back("-mnoexecstack"); if (MipsTargetFeature != nullptr) { @@ -2604,6 +2682,53 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, if (C.getDriver().embedBitcodeEnabled() || C.getDriver().embedBitcodeMarkerOnly()) Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ); + + if (const char *AsSecureLogFile = getenv("AS_SECURE_LOG_FILE")) { + CmdArgs.push_back("-as-secure-log-file"); + CmdArgs.push_back(Args.MakeArgString(AsSecureLogFile)); + } +} + +static StringRef EnumComplexRangeToStr(LangOptions::ComplexRangeKind Range) { + StringRef RangeStr = ""; + switch (Range) { + case LangOptions::ComplexRangeKind::CX_Limited: + return "-fcx-limited-range"; + break; + case LangOptions::ComplexRangeKind::CX_Fortran: + return "-fcx-fortran-rules"; + break; + default: + return RangeStr; + break; + } +} + +static void EmitComplexRangeDiag(const Driver &D, + LangOptions::ComplexRangeKind Range1, + LangOptions::ComplexRangeKind Range2) { + if (Range1 != LangOptions::ComplexRangeKind::CX_Full) + D.Diag(clang::diag::warn_drv_overriding_option) + << EnumComplexRangeToStr(Range1) << EnumComplexRangeToStr(Range2); +} + +static std::string +RenderComplexRangeOption(LangOptions::ComplexRangeKind Range) { + std::string ComplexRangeStr = "-complex-range="; + switch (Range) { + case LangOptions::ComplexRangeKind::CX_Full: + ComplexRangeStr += "full"; + break; + case LangOptions::ComplexRangeKind::CX_Limited: + ComplexRangeStr += "limited"; + break; + case LangOptions::ComplexRangeKind::CX_Fortran: + ComplexRangeStr += "fortran"; + break; + default: + assert(0 && "Unexpected range option"); + } + return ComplexRangeStr; } static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, @@ -2617,6 +2742,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // LLVM flags based on the final state. bool HonorINFs = true; bool HonorNaNs = true; + bool ApproxFunc = false; // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. bool MathErrno = TC.IsMathErrnoDefault(); bool AssociativeMath = false; @@ -2631,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 = @@ -2638,9 +2766,19 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, llvm::DenormalMode DenormalFPMath = DefaultDenormalFPMath; llvm::DenormalMode DenormalFP32Math = DefaultDenormalFP32Math; - StringRef FPContract = ""; + // CUDA and HIP don't rely on the frontend to pass an ffp-contract option. + // If one wasn't given by the user, don't pass it here. + StringRef FPContract; + StringRef LastSeenFfpContractOption; + bool SeenUnsafeMathModeOption = false; + if (!JA.isDeviceOffloading(Action::OFK_Cuda) && + !JA.isOffloading(Action::OFK_HIP)) + FPContract = "on"; bool StrictFPModel = false; - + StringRef Float16ExcessPrecision = ""; + StringRef BFloat16ExcessPrecision = ""; + LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_None; + std::string ComplexRangeStr = ""; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2653,17 +2791,36 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, switch (optID) { default: break; + case options::OPT_fcx_limited_range: { + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Limited); + Range = LangOptions::ComplexRangeKind::CX_Limited; + break; + } + case options::OPT_fno_cx_limited_range: + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full); + Range = LangOptions::ComplexRangeKind::CX_Full; + break; + case options::OPT_fcx_fortran_rules: { + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Fortran); + Range = LangOptions::ComplexRangeKind::CX_Fortran; + break; + } + case options::OPT_fno_cx_fortran_rules: + EmitComplexRangeDiag(D, Range, LangOptions::ComplexRangeKind::CX_Full); + Range = LangOptions::ComplexRangeKind::CX_Full; + break; case options::OPT_ffp_model_EQ: { // If -ffp-model= is seen, reset to fno-fast-math HonorINFs = true; HonorNaNs = true; + ApproxFunc = false; // Turning *off* -ffast-math restores the toolchain default. MathErrno = TC.IsMathErrnoDefault(); AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; // -fno_fast_math restores default denormal and fpcontract handling - FPContract = ""; + FPContract = "on"; DenormalFPMath = llvm::DenormalMode::getIEEE(); // FIXME: The target may have picked a non-IEEE default mode here based on @@ -2673,9 +2830,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, StringRef Val = A->getValue(); if (OFastEnabled && !Val.equals("fast")) { // Only -ffp-model=fast is compatible with OFast, ignore. - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-model=" + Val) - << "-Ofast"; + D.Diag(clang::diag::warn_drv_overriding_option) + << Args.MakeArgString("-ffp-model=" + Val) << "-Ofast"; break; } StrictFPModel = false; @@ -2683,12 +2839,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // ffp-model= is a Driver option, it is entirely rewritten into more // granular options before being passed into cc1. // Use the gcc option in the switch below. - if (!FPModel.empty() && !FPModel.equals(Val)) { - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-model=" + FPModel) - << Args.MakeArgString("-ffp-model=" + Val); - FPContract = ""; - } + if (!FPModel.empty() && !FPModel.equals(Val)) + D.Diag(clang::diag::warn_drv_overriding_option) + << Args.MakeArgString("-ffp-model=" + FPModel) + << Args.MakeArgString("-ffp-model=" + Val); if (Val.equals("fast")) { optID = options::OPT_ffast_math; FPModel = Val; @@ -2696,7 +2850,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, } else if (Val.equals("precise")) { optID = options::OPT_ffp_contract; FPModel = Val; - FPContract = "fast"; + FPContract = "on"; PreciseFPModel = true; } else if (Val.equals("strict")) { StrictFPModel = true; @@ -2707,9 +2861,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, TrappingMath = true; } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; break; - } + } } switch (optID) { @@ -2721,6 +2875,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_fno_honor_infinities: HonorINFs = false; break; case options::OPT_fhonor_nans: HonorNaNs = true; break; case options::OPT_fno_honor_nans: HonorNaNs = false; break; + case options::OPT_fapprox_func: ApproxFunc = true; break; + case options::OPT_fno_approx_func: ApproxFunc = false; break; case options::OPT_fmath_errno: MathErrno = true; break; case options::OPT_fno_math_errno: MathErrno = false; break; case options::OPT_fassociative_math: AssociativeMath = true; break; @@ -2733,9 +2889,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!TrappingMathPresent && !FPExceptionBehavior.empty() && !FPExceptionBehavior.equals("strict")) // Warn that previous value of option is overridden. - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) - << "-ftrapping-math"; + D.Diag(clang::diag::warn_drv_overriding_option) + << Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior) + << "-ftrapping-math"; TrappingMath = true; TrappingMathPresent = true; FPExceptionBehavior = "strict"; @@ -2744,9 +2901,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!TrappingMathPresent && !FPExceptionBehavior.empty() && !FPExceptionBehavior.equals("ignore")) // Warn that previous value of option is overridden. - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) - << "-fno-trapping-math"; + D.Diag(clang::diag::warn_drv_overriding_option) + << Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior) + << "-fno-trapping-math"; TrappingMath = false; TrappingMathPresent = true; FPExceptionBehavior = "ignore"; @@ -2764,6 +2922,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_fdenormal_fp_math_EQ: DenormalFPMath = llvm::parseDenormalFPAttribute(A->getValue()); + DenormalFP32Math = DenormalFPMath; if (!DenormalFPMath.isValid()) { D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); @@ -2782,15 +2941,17 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_ffp_contract: { StringRef Val = A->getValue(); if (PreciseFPModel) { - // -ffp-model=precise enables ffp-contract=fast as a side effect - // the FPContract value has already been set to a string literal - // and the Val string isn't a pertinent value. + // -ffp-model=precise enables ffp-contract=on. + // -ffp-model=precise sets PreciseFPModel to on and Val to + // "precise". FPContract is set. ; - } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) + } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off") || + Val.equals("fast-honor-pragmas")) { FPContract = Val; - else + LastSeenFfpContractOption = Val; + } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; break; } @@ -2807,9 +2968,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!TrappingMathPresent && !FPExceptionBehavior.empty() && !FPExceptionBehavior.equals(Val)) // Warn that previous value of option is overridden. - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) - << Args.MakeArgString("-ffp-exception-behavior=" + Val); + D.Diag(clang::diag::warn_drv_overriding_option) + << Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior) + << Args.MakeArgString("-ffp-exception-behavior=" + Val); TrappingMath = TrappingMathPresent = false; if (Val.equals("ignore") || Val.equals("maytrap")) FPExceptionBehavior = Val; @@ -2818,10 +2980,44 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, TrappingMath = TrappingMathPresent = true; } else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; + break; + } + + // Validate and pass through -ffp-eval-method option. + case options::OPT_ffp_eval_method_EQ: { + StringRef Val = A->getValue(); + if (Val.equals("double") || Val.equals("extended") || + Val.equals("source")) + FPEvalMethod = Val; + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; break; } + case options::OPT_fexcess_precision_EQ: { + StringRef Val = A->getValue(); + const llvm::Triple::ArchType Arch = TC.getArch(); + if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { + if (Val.equals("standard") || Val.equals("fast")) + Float16ExcessPrecision = Val; + // To make it GCC compatible, allow the value of "16" which + // means disable excess precision, the same meaning than clang's + // equivalent value "none". + else if (Val.equals("16")) + Float16ExcessPrecision = "none"; + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } else { + if (!(Val.equals("standard") || Val.equals("fast"))) + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } + BFloat16ExcessPrecision = Float16ExcessPrecision; + break; + } case options::OPT_ffinite_math_only: HonorINFs = false; HonorNaNs = false; @@ -2835,38 +3031,56 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, AssociativeMath = true; ReciprocalMath = true; SignedZeros = false; + ApproxFunc = true; TrappingMath = false; FPExceptionBehavior = ""; + FPContract = "fast"; + SeenUnsafeMathModeOption = true; break; case options::OPT_fno_unsafe_math_optimizations: AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; + ApproxFunc = false; TrappingMath = true; FPExceptionBehavior = "strict"; // The target may have opted to flush by default, so force IEEE. DenormalFPMath = llvm::DenormalMode::getIEEE(); DenormalFP32Math = llvm::DenormalMode::getIEEE(); + if (!JA.isDeviceOffloading(Action::OFK_Cuda) && + !JA.isOffloading(Action::OFK_HIP)) { + if (LastSeenFfpContractOption != "") { + FPContract = LastSeenFfpContractOption; + } else if (SeenUnsafeMathModeOption) + FPContract = "on"; + } break; case options::OPT_Ofast: // If -Ofast is the optimization level, then -ffast-math should be enabled if (!OFastEnabled) continue; - LLVM_FALLTHROUGH; - case options::OPT_ffast_math: + [[fallthrough]]; + case options::OPT_ffast_math: { HonorINFs = false; HonorNaNs = false; MathErrno = false; AssociativeMath = true; ReciprocalMath = true; + ApproxFunc = true; SignedZeros = false; TrappingMath = false; RoundingFPMath = false; + FPExceptionBehavior = ""; // If fast-math is set then set the fp-contract mode to fast. FPContract = "fast"; + SeenUnsafeMathModeOption = true; + // ffast-math enables fortran rules for complex multiplication and + // division. + Range = LangOptions::ComplexRangeKind::CX_Limited; break; + } case options::OPT_fno_fast_math: HonorINFs = true; HonorNaNs = true; @@ -2876,33 +3090,39 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, MathErrno = TC.IsMathErrnoDefault(); AssociativeMath = false; ReciprocalMath = false; + ApproxFunc = false; SignedZeros = true; - TrappingMath = false; - RoundingFPMath = false; // -fno_fast_math restores default denormal and fpcontract handling DenormalFPMath = DefaultDenormalFPMath; DenormalFP32Math = llvm::DenormalMode::getIEEE(); - FPContract = ""; + if (!JA.isDeviceOffloading(Action::OFK_Cuda) && + !JA.isOffloading(Action::OFK_HIP)) { + if (LastSeenFfpContractOption != "") { + FPContract = LastSeenFfpContractOption; + } else if (SeenUnsafeMathModeOption) + FPContract = "on"; + } break; } if (StrictFPModel) { // If -ffp-model=strict has been specified on command line but // subsequent options conflict then emit warning diagnostic. - if (HonorINFs && HonorNaNs && - !AssociativeMath && !ReciprocalMath && - SignedZeros && TrappingMath && RoundingFPMath && - (FPContract.equals("off") || FPContract.empty()) && - DenormalFPMath == llvm::DenormalMode::getIEEE() && - DenormalFP32Math == llvm::DenormalMode::getIEEE()) + if (HonorINFs && HonorNaNs && !AssociativeMath && !ReciprocalMath && + SignedZeros && TrappingMath && RoundingFPMath && !ApproxFunc && + DenormalFPMath == llvm::DenormalMode::getIEEE() && + DenormalFP32Math == llvm::DenormalMode::getIEEE() && + FPContract.equals("off")) // OK: Current Arg doesn't conflict with -ffp-model=strict ; else { StrictFPModel = false; FPModel = ""; - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << "-ffp-model=strict" << - ((A->getNumValues() == 0) ? A->getSpelling() - : Args.MakeArgString(A->getSpelling() + A->getValue())); + auto RHS = (A->getNumValues() == 0) + ? A->getSpelling() + : Args.MakeArgString(A->getSpelling() + A->getValue()); + if (RHS != "-ffp-model=strict") + D.Diag(clang::diag::warn_drv_overriding_option) + << "-ffp-model=strict" << RHS; } } @@ -2916,12 +3136,15 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!HonorNaNs) CmdArgs.push_back("-menable-no-nans"); + if (ApproxFunc) + CmdArgs.push_back("-fapprox-func"); + if (MathErrno) CmdArgs.push_back("-fmath-errno"); - if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && - !TrappingMath) - CmdArgs.push_back("-menable-unsafe-fp-math"); + if (AssociativeMath && ReciprocalMath && !SignedZeros && ApproxFunc && + !TrappingMath) + CmdArgs.push_back("-funsafe-math-optimizations"); if (!SignedZeros) CmdArgs.push_back("-fno-signed-zeros"); @@ -2966,12 +3189,22 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior)); + if (!FPEvalMethod.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-eval-method=" + FPEvalMethod)); + + if (!Float16ExcessPrecision.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffloat16-excess-precision=" + + Float16ExcessPrecision)); + if (!BFloat16ExcessPrecision.empty()) + CmdArgs.push_back(Args.MakeArgString("-fbfloat16-excess-precision=" + + BFloat16ExcessPrecision)); + ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the // individual features enabled by -ffast-math instead of the option itself as // that's consistent with gcc's behaviour. - if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && + if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && ApproxFunc && ReciprocalMath && !SignedZeros && !TrappingMath && !RoundingFPMath) { CmdArgs.push_back("-ffast-math"); if (FPModel.equals("fast")) { @@ -2982,9 +3215,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // Enable -ffp-contract=fast CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); else - D.Diag(clang::diag::warn_drv_overriding_flag_option) - << "-ffp-model=fast" - << Args.MakeArgString("-ffp-contract=" + FPContract); + D.Diag(clang::diag::warn_drv_overriding_option) + << "-ffp-model=fast" + << Args.MakeArgString("-ffp-contract=" + FPContract); } } @@ -3001,17 +3234,24 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow, options::OPT_fstrict_float_cast_overflow, false)) CmdArgs.push_back("-fno-strict-float-cast-overflow"); + + if (Range != LangOptions::ComplexRangeKind::CX_None) + ComplexRangeStr = RenderComplexRangeOption(Range); + if (!ComplexRangeStr.empty()) + CmdArgs.push_back(Args.MakeArgString(ComplexRangeStr)); + if (Args.hasArg(options::OPT_fcx_limited_range)) + CmdArgs.push_back("-fcx-limited-range"); + if (Args.hasArg(options::OPT_fcx_fortran_rules)) + CmdArgs.push_back("-fcx-fortran-rules"); + if (Args.hasArg(options::OPT_fno_cx_limited_range)) + CmdArgs.push_back("-fno-cx-limited-range"); + if (Args.hasArg(options::OPT_fno_cx_fortran_rules)) + CmdArgs.push_back("-fno-cx-fortran-rules"); } static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, const llvm::Triple &Triple, const InputInfo &Input) { - // Enable region store model by default. - CmdArgs.push_back("-analyzer-store=region"); - - // Treat blocks as analysis entry points. - CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); - // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-analyzer-checker=core"); @@ -3029,8 +3269,8 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg"); } - // Disable some unix checkers for PS4. - if (Triple.isPS4CPU()) { + // Disable some unix checkers for PS4/PS5. + if (Triple.isPS()) { CmdArgs.push_back("-analyzer-disable-checker=unix.API"); CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork"); } @@ -3048,7 +3288,7 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, if (types::isCXX(Input.getType())) CmdArgs.push_back("-analyzer-checker=cplusplus"); - if (!Triple.isPS4CPU()) { + if (!Triple.isPS()) { CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets"); @@ -3078,6 +3318,16 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); } +static bool isValidSymbolName(StringRef S) { + if (S.empty()) + return false; + + if (std::isdigit(S[0])) + return false; + + return llvm::all_of(S, [](char C) { return std::isalnum(C) || C == '_'; }); +} + static void RenderSSPOptions(const Driver &D, const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, bool KernelOrKext) { @@ -3104,6 +3354,12 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, StackProtectorLevel = LangOptions::SSPStrong; else if (A->getOption().matches(options::OPT_fstack_protector_all)) StackProtectorLevel = LangOptions::SSPReq; + + if (EffectiveTriple.isBPF() && StackProtectorLevel != LangOptions::SSPOff) { + D.Diag(diag::warn_drv_unsupported_option_for_target) + << A->getSpelling() << EffectiveTriple.getTriple(); + StackProtectorLevel = DefaultStackProtectorLevel; + } } else { StackProtectorLevel = DefaultStackProtectorLevel; } @@ -3116,7 +3372,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, // --param ssp-buffer-size= for (const Arg *A : Args.filtered(options::OPT__param)) { StringRef Str(A->getValue()); - if (Str.startswith("ssp-buffer-size=")) { + if (Str.starts_with("ssp-buffer-size=")) { if (StackProtectorLevel) { CmdArgs.push_back("-stack-protector-buffer-size"); // FIXME: Verify the argument is a valid integer. @@ -3129,14 +3385,42 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, const std::string &TripleStr = EffectiveTriple.getTriple(); if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_EQ)) { StringRef Value = A->getValue(); - if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64()) + if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() && + !EffectiveTriple.isARM() && !EffectiveTriple.isThumb()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; - if (EffectiveTriple.isX86() && Value != "tls" && Value != "global") { + if ((EffectiveTriple.isX86() || EffectiveTriple.isARM() || + EffectiveTriple.isThumb()) && + Value != "tls" && Value != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) << A->getOption().getName() << Value << "tls global"; return; } + if ((EffectiveTriple.isARM() || EffectiveTriple.isThumb()) && + Value == "tls") { + if (!Args.hasArg(options::OPT_mstack_protector_guard_offset_EQ)) { + D.Diag(diag::err_drv_ssp_missing_offset_argument) + << A->getAsString(Args); + return; + } + // Check whether the target subarch supports the hardware TLS register + if (!arm::isHardTPSupported(EffectiveTriple)) { + D.Diag(diag::err_target_unsupported_tp_hard) + << EffectiveTriple.getArchName(); + return; + } + // Check whether the user asked for something other than -mtp=cp15 + if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { + StringRef Value = A->getValue(); + if (Value != "cp15") { + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-mstack-protector-guard=tls"; + return; + } + } + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+read-tp-tpidruro"); + } if (EffectiveTriple.isAArch64() && Value != "sysreg" && Value != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) << A->getOption().getName() << Value << "sysreg global"; @@ -3147,7 +3431,8 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_offset_EQ)) { StringRef Value = A->getValue(); - if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64()) + if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() && + !EffectiveTriple.isARM() && !EffectiveTriple.isThumb()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; int Offset; @@ -3155,6 +3440,12 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value; return; } + if ((EffectiveTriple.isARM() || EffectiveTriple.isThumb()) && + (Offset < 0 || Offset > 0xfffff)) { + D.Diag(diag::err_drv_invalid_int_value) + << A->getOption().getName() << Value; + return; + } A->render(Args, CmdArgs); } @@ -3174,6 +3465,16 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, } A->render(Args, CmdArgs); } + + if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_symbol_EQ)) { + StringRef Value = A->getValue(); + if (!isValidSymbolName(Value)) { + D.Diag(diag::err_drv_argument_only_allowed_with) + << A->getOption().getName() << "legal symbol name"; + return; + } + A->render(Args, CmdArgs); + } } static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args, @@ -3184,12 +3485,11 @@ static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args, return; if (!EffectiveTriple.isX86() && !EffectiveTriple.isSystemZ() && - !EffectiveTriple.isPPC64()) + !EffectiveTriple.isPPC64() && !EffectiveTriple.isAArch64()) return; - if (Args.hasFlag(options::OPT_fstack_clash_protection, - options::OPT_fno_stack_clash_protection, false)) - CmdArgs.push_back("-fstack-clash-protection"); + Args.addOptInFlag(CmdArgs, options::OPT_fstack_clash_protection, + options::OPT_fno_stack_clash_protection); } static void RenderTrivialAutoVarInitOptions(const Driver &D, @@ -3210,7 +3510,7 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D, TrivialAutoVarInit = Val; else D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; break; } } @@ -3229,8 +3529,6 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D, } if (!TrivialAutoVarInit.empty()) { - if (TrivialAutoVarInit == "zero" && !Args.hasArg(options::OPT_enable_trivial_var_init_zero)) - D.Diag(diag::err_drv_trivial_auto_var_init_zero_disabled); CmdArgs.push_back( Args.MakeArgString("-ftrivial-auto-var-init=" + TrivialAutoVarInit)); } @@ -3249,6 +3547,20 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D, CmdArgs.push_back( Args.MakeArgString("-ftrivial-auto-var-init-stop-after=" + Val)); } + + if (Arg *A = Args.getLastArg(options::OPT_ftrivial_auto_var_init_max_size)) { + if (!Args.hasArg(options::OPT_ftrivial_auto_var_init) || + StringRef( + Args.getLastArg(options::OPT_ftrivial_auto_var_init)->getValue()) == + "uninitialized") + D.Diag(diag::err_drv_trivial_auto_var_init_max_size_missing_dependency); + A->claim(); + StringRef Val = A->getValue(); + if (std::stoi(Val.str()) <= 0) + D.Diag(diag::err_drv_trivial_auto_var_init_max_size_invalid_value); + CmdArgs.push_back( + Args.MakeArgString("-ftrivial-auto-var-init-max-size=" + Val)); + } } static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs, @@ -3272,6 +3584,9 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs, if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { std::string CLStdStr = std::string("-cl-std=") + A->getValue(); CmdArgs.push_back(Args.MakeArgString(CLStdStr)); + } else if (Arg *A = Args.getLastArg(options::OPT_cl_ext_EQ)) { + std::string CLExtStr = std::string("-cl-ext=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(CLExtStr)); } for (const auto &Arg : ForwardedArguments) @@ -3287,6 +3602,46 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs, } } +static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs, + types::ID InputType) { + const unsigned ForwardedArguments[] = {options::OPT_dxil_validator_version, + options::OPT_D, + options::OPT_I, + options::OPT_S, + options::OPT_O, + options::OPT_emit_llvm, + options::OPT_emit_obj, + options::OPT_disable_llvm_passes, + options::OPT_fnative_half_type, + options::OPT_hlsl_entrypoint}; + if (!types::isHLSL(InputType)) + return; + for (const auto &Arg : ForwardedArguments) + if (const auto *A = Args.getLastArg(Arg)) + A->renderAsInput(Args, CmdArgs); + // Add the default headers if dxc_no_stdinc is not set. + if (!Args.hasArg(options::OPT_dxc_no_stdinc) && + !Args.hasArg(options::OPT_nostdinc)) + CmdArgs.push_back("-finclude-default-header"); +} + +static void RenderOpenACCOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs, types::ID InputType) { + if (!Args.hasArg(options::OPT_fopenacc)) + return; + + CmdArgs.push_back("-fopenacc"); + + if (Arg *A = Args.getLastArg(options::OPT_openacc_macro_override)) { + StringRef Value = A->getValue(); + int Version; + if (!Value.getAsInteger(10, Version)) + A->renderAsInput(Args, CmdArgs); + else + D.Diag(diag::err_drv_clang_unsupported) << Value; + } +} + static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { bool ARCMTEnabled = false; @@ -3355,7 +3710,7 @@ static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args, Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property); Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_allowlist_dir_path); } } @@ -3373,20 +3728,13 @@ static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, UseBuiltins = false; // Process the -fno-builtin-* options. - for (const auto &Arg : Args) { - const Option &O = Arg->getOption(); - if (!O.matches(options::OPT_fno_builtin_)) - continue; - - Arg->claim(); + for (const Arg *A : Args.filtered(options::OPT_fno_builtin_)) { + A->claim(); // If -fno-builtin is specified, then there's no need to pass the option to // the frontend. - if (!UseBuiltins) - continue; - - StringRef FuncName = Arg->getValue(); - CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName)); + if (UseBuiltins) + A->render(Args, CmdArgs); } // le32-specific flags: @@ -3397,6 +3745,11 @@ static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, } bool Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) { + if (const char *Str = std::getenv("CLANG_MODULE_CACHE_PATH")) { + Twine Path{Str}; + Path.toVector(Result); + return Path.getSingleStringRef() != ""; + } if (llvm::sys::path::cache_directory(Result)) { llvm::sys::path::append(Result, "clang"); llvm::sys::path::append(Result, "ModuleCache"); @@ -3405,10 +3758,14 @@ bool Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) { return false; } -static void RenderModulesOptions(Compilation &C, const Driver &D, +static bool RenderModulesOptions(Compilation &C, const Driver &D, const ArgList &Args, const InputInfo &Input, - const InputInfo &Output, - ArgStringList &CmdArgs, bool &HaveModules) { + const InputInfo &Output, bool HaveStd20, + ArgStringList &CmdArgs) { + bool IsCXX = types::isCXX(Input.getType()); + bool HaveStdCXXModules = IsCXX && HaveStd20; + bool HaveModules = HaveStdCXXModules; + // -fmodules enables the use of precompiled modules (off by default). // Users can pass -fno-cxx-modules to turn off modules support for // C++/Objective-C++ programs. @@ -3416,17 +3773,13 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, options::OPT_fno_cxx_modules, true); - if (AllowedInCXX || !types::isCXX(Input.getType())) { + if (AllowedInCXX || !IsCXX) { CmdArgs.push_back("-fmodules"); HaveClangModules = true; } } HaveModules |= HaveClangModules; - if (Args.hasArg(options::OPT_fmodules_ts)) { - CmdArgs.push_back("-fmodules-ts"); - HaveModules = true; - } // -fmodule-maps enables implicit reading of module map files. By default, // this is enabled if we are using Clang's flavor of precompiled modules. @@ -3435,9 +3788,8 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, CmdArgs.push_back("-fimplicit-module-maps"); // -fmodules-decluse checks that modules used are declared so (off by default) - if (Args.hasFlag(options::OPT_fmodules_decluse, - options::OPT_fno_modules_decluse, false)) - CmdArgs.push_back("-fmodules-decluse"); + Args.addOptInFlag(CmdArgs, options::OPT_fmodules_decluse, + options::OPT_fno_modules_decluse); // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that // all #included headers are part of modules. @@ -3481,12 +3833,6 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, } if (HaveModules) { - // -fprebuilt-module-path specifies where to load the prebuilt module files. - for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) { - CmdArgs.push_back(Args.MakeArgString( - std::string("-fprebuilt-module-path=") + A->getValue())); - A->claim(); - } if (Args.hasFlag(options::OPT_fprebuilt_implicit_modules, options::OPT_fno_prebuilt_implicit_modules, false)) CmdArgs.push_back("-fprebuilt-implicit-modules"); @@ -3519,9 +3865,16 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, // names to precompiled module files (the module is loaded only if used). // The -fmodule-file=<file> form can be used to unconditionally load // precompiled module files (whether used or not). - if (HaveModules) + if (HaveModules || Input.getType() == clang::driver::types::TY_ModuleFile) { Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); - else + + // -fprebuilt-module-path specifies where to load the prebuilt module files. + for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) { + CmdArgs.push_back(Args.MakeArgString( + std::string("-fprebuilt-module-path=") + A->getValue())); + A->claim(); + } + } else Args.ClaimAllArgs(options::OPT_fmodule_file); // When building modules and generating crashdumps, we need to dump a module @@ -3545,38 +3898,59 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); - Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); + if (HaveClangModules) { + Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); - if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { - if (Args.hasArg(options::OPT_fbuild_session_timestamp)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << A->getAsString(Args) << "-fbuild-session-timestamp"; + if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { + if (Args.hasArg(options::OPT_fbuild_session_timestamp)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-fbuild-session-timestamp"; - llvm::sys::fs::file_status Status; - if (llvm::sys::fs::status(A->getValue(), Status)) - D.Diag(diag::err_drv_no_such_file) << A->getValue(); - CmdArgs.push_back( - Args.MakeArgString("-fbuild-session-timestamp=" + - Twine((uint64_t)Status.getLastModificationTime() - .time_since_epoch() - .count()))); - } + llvm::sys::fs::file_status Status; + if (llvm::sys::fs::status(A->getValue(), Status)) + D.Diag(diag::err_drv_no_such_file) << A->getValue(); + CmdArgs.push_back(Args.MakeArgString( + "-fbuild-session-timestamp=" + + Twine((uint64_t)std::chrono::duration_cast<std::chrono::seconds>( + Status.getLastModificationTime().time_since_epoch()) + .count()))); + } - if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { - if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, - options::OPT_fbuild_session_file)) - D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); + if (Args.getLastArg( + options::OPT_fmodules_validate_once_per_build_session)) { + if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, + options::OPT_fbuild_session_file)) + D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); + + Args.AddLastArg(CmdArgs, + options::OPT_fmodules_validate_once_per_build_session); + } + + if (Args.hasFlag(options::OPT_fmodules_validate_system_headers, + options::OPT_fno_modules_validate_system_headers, + ImplicitModules)) + CmdArgs.push_back("-fmodules-validate-system-headers"); Args.AddLastArg(CmdArgs, - options::OPT_fmodules_validate_once_per_build_session); + options::OPT_fmodules_disable_diagnostic_validation); + } else { + Args.ClaimAllArgs(options::OPT_fbuild_session_timestamp); + Args.ClaimAllArgs(options::OPT_fbuild_session_file); + Args.ClaimAllArgs(options::OPT_fmodules_validate_once_per_build_session); + Args.ClaimAllArgs(options::OPT_fmodules_validate_system_headers); + Args.ClaimAllArgs(options::OPT_fno_modules_validate_system_headers); + Args.ClaimAllArgs(options::OPT_fmodules_disable_diagnostic_validation); } - if (Args.hasFlag(options::OPT_fmodules_validate_system_headers, - options::OPT_fno_modules_validate_system_headers, - ImplicitModules)) - CmdArgs.push_back("-fmodules-validate-system-headers"); + // FIXME: We provisionally don't check ODR violations for decls in the global + // module fragment. + CmdArgs.push_back("-fskip-odr-check-in-gmf"); - Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); + // Claim `-fmodule-output` and `-fmodule-output=` to avoid unused warnings. + Args.ClaimAllArgs(options::OPT_fmodule_output); + Args.ClaimAllArgs(options::OPT_fmodule_output_EQ); + + return HaveModules; } static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T, @@ -3611,7 +3985,8 @@ static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T, else CmdArgs.push_back("-fsigned-wchar"); } - } + } else if (T.isOSzOS()) + CmdArgs.push_back("-fno-signed-wchar"); } static void RenderObjCOptions(const ToolChain &TC, const Driver &D, @@ -3736,15 +4111,10 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, options::OPT_fno_caret_diagnostics, CaretDefault)) CmdArgs.push_back("-fno-caret-diagnostics"); - // -fdiagnostics-fixit-info is default, only pass non-default. - if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, - options::OPT_fno_diagnostics_fixit_info)) - CmdArgs.push_back("-fno-diagnostics-fixit-info"); - - // Enable -fdiagnostics-show-option by default. - if (!Args.hasFlag(options::OPT_fdiagnostics_show_option, - options::OPT_fno_diagnostics_show_option, true)) - CmdArgs.push_back("-fno-diagnostics-show-option"); + Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_fixit_info, + options::OPT_fno_diagnostics_fixit_info); + Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_show_option, + options::OPT_fno_diagnostics_show_option); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { @@ -3752,9 +4122,8 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, CmdArgs.push_back(A->getValue()); } - if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, - options::OPT_fno_diagnostics_show_hotness, false)) - CmdArgs.push_back("-fdiagnostics-show-hotness"); + Args.addOptInFlag(CmdArgs, options::OPT_fdiagnostics_show_hotness, + options::OPT_fno_diagnostics_show_hotness); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { @@ -3763,9 +4132,19 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(Opt)); } + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_misexpect_tolerance_EQ)) { + std::string Opt = + std::string("-fdiagnostics-misexpect-tolerance=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } + if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { CmdArgs.push_back("-fdiagnostics-format"); CmdArgs.push_back(A->getValue()); + if (StringRef(A->getValue()) == "sarif" || + StringRef(A->getValue()) == "SARIF") + D.Diag(diag::warn_drv_sarif_format_unstable); } if (const Arg *A = Args.getLastArg( @@ -3782,22 +4161,13 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, // re-parsed to construct this job; claim any possible color diagnostic here // to avoid warn_drv_unused_argument and diagnose bad // OPT_fdiagnostics_color_EQ values. - for (const Arg *A : Args) { - const Option &O = A->getOption(); - if (!O.matches(options::OPT_fcolor_diagnostics) && - !O.matches(options::OPT_fdiagnostics_color) && - !O.matches(options::OPT_fno_color_diagnostics) && - !O.matches(options::OPT_fno_diagnostics_color) && - !O.matches(options::OPT_fdiagnostics_color_EQ)) - continue; - - if (O.matches(options::OPT_fdiagnostics_color_EQ)) { - StringRef Value(A->getValue()); - if (Value != "always" && Value != "never" && Value != "auto") - D.Diag(diag::err_drv_clang_unsupported) - << ("-fdiagnostics-color=" + Value).str(); - } - A->claim(); + Args.getLastArg(options::OPT_fcolor_diagnostics, + options::OPT_fno_color_diagnostics); + if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_color_EQ)) { + StringRef Value(A->getValue()); + if (Value != "always" && Value != "never" && Value != "auto") + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); } if (D.getDiags().getDiagnosticOptions().ShowColors) @@ -3806,9 +4176,11 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, if (Args.hasArg(options::OPT_fansi_escape_codes)) CmdArgs.push_back("-fansi-escape-codes"); - if (!Args.hasFlag(options::OPT_fshow_source_location, - options::OPT_fno_show_source_location)) - CmdArgs.push_back("-fno-show-source-location"); + Args.addOptOutFlag(CmdArgs, options::OPT_fshow_source_location, + options::OPT_fno_show_source_location); + + Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_show_line_numbers, + options::OPT_fno_diagnostics_show_line_numbers); if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) CmdArgs.push_back("-fdiagnostics-absolute-paths"); @@ -3817,14 +4189,11 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, ColumnDefault)) CmdArgs.push_back("-fno-show-column"); - if (!Args.hasFlag(options::OPT_fspell_checking, - options::OPT_fno_spell_checking)) - CmdArgs.push_back("-fno-spell-checking"); + Args.addOptOutFlag(CmdArgs, options::OPT_fspell_checking, + options::OPT_fno_spell_checking); } -enum class DwarfFissionKind { None, Split, Single }; - -static DwarfFissionKind getDebugFissionKind(const Driver &D, +DwarfFissionKind tools::getDebugFissionKind(const Driver &D, const ArgList &Args, Arg *&Arg) { Arg = Args.getLastArg(options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ, options::OPT_gno_split_dwarf); @@ -3841,7 +4210,7 @@ static DwarfFissionKind getDebugFissionKind(const Driver &D, return DwarfFissionKind::Single; D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << Arg->getValue(); + << Arg->getSpelling() << Arg->getValue(); return DwarfFissionKind::None; } @@ -3868,18 +4237,12 @@ static void renderDwarfFormat(const Driver &D, const llvm::Triple &T, DwarfFormatArg->render(Args, CmdArgs); } -static void renderDebugOptions(const ToolChain &TC, const Driver &D, - const llvm::Triple &T, const ArgList &Args, - bool EmitCodeView, bool IRInput, - ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind &DebugInfoKind, - DwarfFissionKind &DwarfFission) { - // These two forms of profiling info can't be used together. - if (const Arg *A1 = Args.getLastArg(options::OPT_fpseudo_probe_for_profiling)) - if (const Arg *A2 = Args.getLastArg(options::OPT_fdebug_info_for_profiling)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << A1->getAsString(Args) << A2->getAsString(Args); - +static void +renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, + const ArgList &Args, bool IRInput, ArgStringList &CmdArgs, + const InputInfo &Output, + llvm::codegenoptions::DebugInfoKind &DebugInfoKind, + DwarfFissionKind &DwarfFission) { if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, options::OPT_fno_debug_info_for_profiling, false) && checkDebugInfoOption( @@ -3914,27 +4277,29 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, } } if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) { - DebugInfoKind = codegenoptions::DebugInfoConstructor; + DebugInfoKind = llvm::codegenoptions::DebugInfoConstructor; // If the last option explicitly specified a debug-info level, use it. if (checkDebugInfoOption(A, Args, D, TC) && A->getOption().matches(options::OPT_gN_Group)) { - DebugInfoKind = DebugLevelToInfoKind(*A); + DebugInfoKind = debugLevelToInfoKind(*A); // For -g0 or -gline-tables-only, drop -gsplit-dwarf. This gets a bit more // complicated if you've disabled inline info in the skeleton CUs // (SplitDWARFInlining) - then there's value in composing split-dwarf and // line-tables-only, so let those compose naturally in that case. - if (DebugInfoKind == codegenoptions::NoDebugInfo || - DebugInfoKind == codegenoptions::DebugDirectivesOnly || - (DebugInfoKind == codegenoptions::DebugLineTablesOnly && + if (DebugInfoKind == llvm::codegenoptions::NoDebugInfo || + DebugInfoKind == llvm::codegenoptions::DebugDirectivesOnly || + (DebugInfoKind == llvm::codegenoptions::DebugLineTablesOnly && SplitDWARFInlining)) DwarfFission = DwarfFissionKind::None; } } // If a debugger tuning argument appeared, remember it. + bool HasDebuggerTuning = false; if (const Arg *A = Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { + HasDebuggerTuning = true; if (checkDebugInfoOption(A, Args, D, TC)) { if (A->getOption().matches(options::OPT_glldb)) DebuggerTuning = llvm::DebuggerKind::LLDB; @@ -3948,29 +4313,23 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, } // If a -gdwarf argument appeared, remember it. - const Arg *GDwarfN = getDwarfNArg(Args); bool EmitDwarf = false; - if (GDwarfN) { - if (checkDebugInfoOption(GDwarfN, Args, D, TC)) - EmitDwarf = true; - else - GDwarfN = nullptr; - } + if (const Arg *A = getDwarfNArg(Args)) + EmitDwarf = checkDebugInfoOption(A, Args, D, TC); - if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) { - if (checkDebugInfoOption(A, Args, D, TC)) - EmitCodeView = true; - } + bool EmitCodeView = false; + if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) + EmitCodeView = checkDebugInfoOption(A, Args, D, TC); // If the user asked for debug info but did not explicitly specify -gcodeview // or -gdwarf, ask the toolchain for the default format. if (!EmitCodeView && !EmitDwarf && - DebugInfoKind != codegenoptions::NoDebugInfo) { + DebugInfoKind != llvm::codegenoptions::NoDebugInfo) { switch (TC.getDefaultDebugFormat()) { - case codegenoptions::DIF_CodeView: + case llvm::codegenoptions::DIF_CodeView: EmitCodeView = true; break; - case codegenoptions::DIF_DWARF: + case llvm::codegenoptions::DIF_DWARF: EmitDwarf = true; break; } @@ -3979,31 +4338,19 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, unsigned RequestedDWARFVersion = 0; // DWARF version requested by the user unsigned EffectiveDWARFVersion = 0; // DWARF version TC can generate. It may // be lower than what the user wanted. - unsigned DefaultDWARFVersion = ParseDebugDefaultVersion(TC, Args); if (EmitDwarf) { - // Start with the platform default DWARF version - RequestedDWARFVersion = TC.GetDefaultDwarfVersion(); - assert(RequestedDWARFVersion && - "toolchain default DWARF version must be nonzero"); - - // If the user specified a default DWARF version, that takes precedence - // over the platform default. - if (DefaultDWARFVersion) - RequestedDWARFVersion = DefaultDWARFVersion; - - // Override with a user-specified DWARF version - if (GDwarfN) - if (auto ExplicitVersion = DwarfVersionNum(GDwarfN->getSpelling())) - RequestedDWARFVersion = ExplicitVersion; + RequestedDWARFVersion = getDwarfVersion(TC, Args); // Clamp effective DWARF version to the max supported by the toolchain. EffectiveDWARFVersion = std::min(RequestedDWARFVersion, TC.getMaxDwarfVersion()); + } else { + Args.ClaimAllArgs(options::OPT_fdebug_default_version); } // -gline-directives-only supported only for the DWARF debug info. if (RequestedDWARFVersion == 0 && - DebugInfoKind == codegenoptions::DebugDirectivesOnly) - DebugInfoKind = codegenoptions::NoDebugInfo; + DebugInfoKind == llvm::codegenoptions::DebugDirectivesOnly) + DebugInfoKind = llvm::codegenoptions::NoDebugInfo; // strict DWARF is set to false by default. But for DBX, we need it to be set // as true by default. @@ -4031,16 +4378,19 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-gno-column-info"); // FIXME: Move backend command line options to the module. - // If -gline-tables-only or -gline-directives-only is the last option it wins. - if (const Arg *A = Args.getLastArg(options::OPT_gmodules)) - if (checkDebugInfoOption(A, Args, D, TC)) { - if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && - DebugInfoKind != codegenoptions::DebugDirectivesOnly) { - DebugInfoKind = codegenoptions::DebugInfoConstructor; + if (Args.hasFlag(options::OPT_gmodules, options::OPT_gno_modules, false)) { + // If -gline-tables-only or -gline-directives-only is the last option it + // wins. + if (checkDebugInfoOption(Args.getLastArg(options::OPT_gmodules), Args, D, + TC)) { + if (DebugInfoKind != llvm::codegenoptions::DebugLineTablesOnly && + DebugInfoKind != llvm::codegenoptions::DebugDirectivesOnly) { + DebugInfoKind = llvm::codegenoptions::DebugInfoConstructor; CmdArgs.push_back("-dwarf-ext-refs"); CmdArgs.push_back("-fmodule-format=obj"); } } + } if (T.isOSBinFormatELF() && SplitDWARFInlining) CmdArgs.push_back("-fsplit-dwarf-inlining"); @@ -4057,13 +4407,13 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug)) (void)checkDebugInfoOption(A, Args, D, TC); - if (DebugInfoKind == codegenoptions::LimitedDebugInfo || - DebugInfoKind == codegenoptions::DebugInfoConstructor) { + if (DebugInfoKind == llvm::codegenoptions::LimitedDebugInfo || + DebugInfoKind == llvm::codegenoptions::DebugInfoConstructor) { if (Args.hasFlag(options::OPT_fno_eliminate_unused_debug_types, options::OPT_feliminate_unused_debug_types, false)) - DebugInfoKind = codegenoptions::UnusedTypeInfo; + DebugInfoKind = llvm::codegenoptions::UnusedTypeInfo; else if (NeedFullDebug) - DebugInfoKind = codegenoptions::FullDebugInfo; + DebugInfoKind = llvm::codegenoptions::FullDebugInfo; } if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source, @@ -4089,29 +4439,30 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, if (EmitCodeView) { CmdArgs.push_back("-gcodeview"); - // Emit codeview type hashes if requested. - if (Args.hasFlag(options::OPT_gcodeview_ghash, - options::OPT_gno_codeview_ghash, false)) { - CmdArgs.push_back("-gcodeview-ghash"); - } - } + Args.addOptInFlag(CmdArgs, options::OPT_gcodeview_ghash, + options::OPT_gno_codeview_ghash); - // Omit inline line tables if requested. - if (Args.hasFlag(options::OPT_gno_inline_line_tables, - options::OPT_ginline_line_tables, false)) { - CmdArgs.push_back("-gno-inline-line-tables"); + Args.addOptOutFlag(CmdArgs, options::OPT_gcodeview_command_line, + options::OPT_gno_codeview_command_line); } + Args.addOptOutFlag(CmdArgs, options::OPT_ginline_line_tables, + options::OPT_gno_inline_line_tables); + // When emitting remarks, we need at least debug lines in the output. if (willEmitRemarks(Args) && - DebugInfoKind <= codegenoptions::DebugDirectivesOnly) - DebugInfoKind = codegenoptions::DebugLineTablesOnly; + DebugInfoKind <= llvm::codegenoptions::DebugDirectivesOnly) + DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly; // Adjust the debug info kind for the given toolchain. TC.adjustDebugInfoKind(DebugInfoKind, Args); + // On AIX, the debugger tuning option can be omitted if it is not explicitly + // set. RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, EffectiveDWARFVersion, - DebuggerTuning); + T.isOSAIX() && !HasDebuggerTuning + ? llvm::DebuggerKind::Default + : DebuggerTuning); // -fdebug-macro turns on macro debug info generation. if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, @@ -4133,12 +4484,27 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, options::OPT_gpubnames) ? "-gpubnames" : "-ggnu-pubnames"); + const auto *SimpleTemplateNamesArg = + 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)) { + const auto &Opt = SimpleTemplateNamesArg->getOption(); + if (Opt.matches(options::OPT_gsimple_template_names)) { + ForwardTemplateParams = true; + CmdArgs.push_back("-gsimple-template-names=simple"); + } + } - if (Args.hasFlag(options::OPT_fdebug_ranges_base_address, - options::OPT_fno_debug_ranges_base_address, false)) { - CmdArgs.push_back("-fdebug-ranges-base-address"); + if (const Arg *A = Args.getLastArg(options::OPT_gsrc_hash_EQ)) { + StringRef v = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-gsrc-hash=" + v)); } + Args.addOptInFlag(CmdArgs, options::OPT_fdebug_ranges_base_address, + options::OPT_fno_debug_ranges_base_address); + // -gdwarf-aranges turns on the emission of the aranges section in the // backend. // Always enabled for SCE tuning. @@ -4150,9 +4516,8 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-generate-arange-section"); } - if (Args.hasFlag(options::OPT_fforce_dwarf_frame, - options::OPT_fno_force_dwarf_frame, false)) - CmdArgs.push_back("-fforce-dwarf-frame"); + Args.addOptInFlag(CmdArgs, options::OPT_fforce_dwarf_frame, + options::OPT_fno_force_dwarf_frame); if (Args.hasFlag(options::OPT_fdebug_types_section, options::OPT_fno_debug_types_section, false)) { @@ -4179,7 +4544,7 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, // Decide how to render forward declarations of template instantiations. // SCE wants full descriptions, others just get them in the name. - if (DebuggerTuning == llvm::DebuggerKind::SCE) + if (ForwardTemplateParams) CmdArgs.push_back("-debug-forward-template-params"); // Do we need to explicitly import anonymous namespaces into the parent @@ -4189,6 +4554,98 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, renderDwarfFormat(D, T, Args, CmdArgs, EffectiveDWARFVersion); RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); + + // This controls whether or not we perform JustMyCode instrumentation. + if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) { + if (TC.getTriple().isOSBinFormatELF() || D.IsCLMode()) { + if (DebugInfoKind >= llvm::codegenoptions::DebugInfoConstructor) + CmdArgs.push_back("-fjmc"); + else if (D.IsCLMode()) + D.Diag(clang::diag::warn_drv_jmc_requires_debuginfo) << "/JMC" + << "'/Zi', '/Z7'"; + else + D.Diag(clang::diag::warn_drv_jmc_requires_debuginfo) << "-fjmc" + << "-g"; + } else { + D.Diag(clang::diag::warn_drv_fjmc_for_elf_only); + } + } + + // Add in -fdebug-compilation-dir if necessary. + const char *DebugCompilationDir = + addDebugCompDirArg(Args, CmdArgs, D.getVFS()); + + addDebugPrefixMapArg(D, TC, Args, CmdArgs); + + // Add the output path to the object file for CodeView debug infos. + if (EmitCodeView && Output.isFilename()) + addDebugObjectName(Args, CmdArgs, DebugCompilationDir, + Output.getFilename()); +} + +static void ProcessVSRuntimeLibrary(const ArgList &Args, + ArgStringList &CmdArgs) { + unsigned RTOptionID = options::OPT__SLASH_MT; + + if (Args.hasArg(options::OPT__SLASH_LDd)) + // The /LDd option implies /MTd. The dependent lib part can be overridden, + // but defining _DEBUG is sticky. + RTOptionID = options::OPT__SLASH_MTd; + + if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) + RTOptionID = A->getOption().getID(); + + if (Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + RTOptionID = llvm::StringSwitch<unsigned>(A->getValue()) + .Case("static", options::OPT__SLASH_MT) + .Case("static_dbg", options::OPT__SLASH_MTd) + .Case("dll", options::OPT__SLASH_MD) + .Case("dll_dbg", options::OPT__SLASH_MDd) + .Default(options::OPT__SLASH_MT); + } + + StringRef FlagForCRT; + switch (RTOptionID) { + case options::OPT__SLASH_MD: + if (Args.hasArg(options::OPT__SLASH_LDd)) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + FlagForCRT = "--dependent-lib=msvcrt"; + break; + case options::OPT__SLASH_MDd: + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + FlagForCRT = "--dependent-lib=msvcrtd"; + break; + case options::OPT__SLASH_MT: + if (Args.hasArg(options::OPT__SLASH_LDd)) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-flto-visibility-public-std"); + FlagForCRT = "--dependent-lib=libcmt"; + break; + case options::OPT__SLASH_MTd: + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-flto-visibility-public-std"); + FlagForCRT = "--dependent-lib=libcmtd"; + break; + default: + llvm_unreachable("Unexpected option ID."); + } + + if (Args.hasArg(options::OPT_fms_omit_default_lib)) { + CmdArgs.push_back("-D_VC_NODEFAULTLIB"); + } else { + CmdArgs.push_back(FlagForCRT.data()); + + // This provides POSIX compatibility (maps 'open' to '_open'), which most + // users want. The /Za flag to cl.exe turns this off, but it's not + // implemented in clang. + CmdArgs.push_back("--dependent-lib=oldnames"); + } } void Clang::ConstructJob(Compilation &C, const JobAction &JA, @@ -4204,50 +4661,57 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = TC.getDriver(); ArgStringList CmdArgs; - // Check number of inputs for sanity. We need at least one input. assert(Inputs.size() >= 1 && "Must have at least one input."); // 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 IsHeaderModulePrecompile = isa<HeaderModulePrecompileJobAction>(JA); + bool IsExtractAPI = isa<ExtractAPIJobAction>(JA); bool IsDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) || JA.isDeviceOffloading(Action::OFK_Host)); + bool IsHostOffloadingAction = + JA.isHostOffloading(Action::OFK_OpenMP) || + (JA.isHostOffloading(C.getActiveOffloadKinds()) && + Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false)); + + bool IsRDCMode = + Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false); bool IsUsingLTO = D.isUsingLTO(IsDeviceOffloadAction); auto LTOMode = D.getLTOMode(IsDeviceOffloadAction); - // A header module compilation doesn't have a main input file, so invent a - // fake one as a placeholder. - const char *ModuleName = [&]{ - auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ); - return ModuleNameArg ? ModuleNameArg->getValue() : ""; - }(); - InputInfo HeaderModuleInput(Inputs[0].getType(), ModuleName, ModuleName); + // Extract API doesn't have a main input file, so invent a fake one as a + // placeholder. + InputInfo ExtractAPIPlaceholderInput(Inputs[0].getType(), "extract-api", + "extract-api"); const InputInfo &Input = - IsHeaderModulePrecompile ? HeaderModuleInput : Inputs[0]; + IsExtractAPI ? ExtractAPIPlaceholderInput : Inputs[0]; - InputInfoList ModuleHeaderInputs; + InputInfoList ExtractAPIInputs; + InputInfoList HostOffloadingInputs; const InputInfo *CudaDeviceInput = nullptr; const InputInfo *OpenMPDeviceInput = nullptr; for (const InputInfo &I : Inputs) { - if (&I == &Input) { - // This is the primary input. - } else if (IsHeaderModulePrecompile && - types::getPrecompiledType(I.getType()) == types::TY_PCH) { - types::ID Expected = HeaderModuleInput.getType(); - if (I.getType() != Expected) { - D.Diag(diag::err_drv_module_header_wrong_kind) + if (&I == &Input || I.getType() == types::TY_Nothing) { + // This is the primary input or contains nothing. + } else if (IsExtractAPI) { + auto ExpectedInputType = ExtractAPIPlaceholderInput.getType(); + if (I.getType() != ExpectedInputType) { + D.Diag(diag::err_drv_extract_api_wrong_kind) << I.getFilename() << types::getTypeName(I.getType()) - << types::getTypeName(Expected); + << types::getTypeName(ExpectedInputType); } - ModuleHeaderInputs.push_back(I); + ExtractAPIInputs.push_back(I); + } else if (IsHostOffloadingAction) { + HostOffloadingInputs.push_back(I); } else if ((IsCuda || IsHIP) && !CudaDeviceInput) { CudaDeviceInput = &I; } else if (IsOpenMPDevice && !OpenMPDeviceInput) { @@ -4317,12 +4781,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString( Twine("-target-sdk-version=") + CudaVersionToString(CTC->CudaInstallation.version()))); + // Unsized function arguments used for variadics were introduced in + // CUDA-9.0. We still do not support generating code that actually uses + // variadic arguments yet, but we do need to allow parsing them as + // recent CUDA headers rely on that. + // https://github.com/llvm/llvm-project/issues/58410 + if (CTC->CudaInstallation.version() >= CudaVersion::CUDA_90) + CmdArgs.push_back("-fcuda-allow-variadic-functions"); } } CmdArgs.push_back("-aux-triple"); CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); + + if (JA.isDeviceOffloading(Action::OFK_HIP) && + getToolChain().getTriple().isAMDGPU()) { + // Device side compilation printf + if (Args.getLastArg(options::OPT_mprintf_kind_EQ)) { + CmdArgs.push_back(Args.MakeArgString( + "-mprintf-kind=" + + Args.getLastArgValue(options::OPT_mprintf_kind_EQ))); + // Force compiler error on invalid conversion specifiers + CmdArgs.push_back( + Args.MakeArgString("-Werror=format-invalid-specifier")); + } + } } + // Unconditionally claim the printf option now to avoid unused diagnostic. + if (const Arg *PF = Args.getLastArg(options::OPT_mprintf_kind_EQ)) + PF->claim(); + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { CmdArgs.push_back("-fsycl-is-device"); @@ -4361,12 +4849,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, TC.addClangWarningOptions(CmdArgs); // FIXME: Subclass ToolChain for SPIR and move this to addClangWarningOptions. - if (Triple.isSPIR()) + if (Triple.isSPIR() || Triple.isSPIRV()) CmdArgs.push_back("-Wspir-compat"); // Select the appropriate action. RewriteKind rewriteKind = RK_None; + bool UnifiedLTO = false; + if (IsUsingLTO) { + UnifiedLTO = Args.hasFlag(options::OPT_funified_lto, + options::OPT_fno_unified_lto, Triple.isPS()); + if (UnifiedLTO) + CmdArgs.push_back("-funified-lto"); + } + // If CollectArgsForIntegratedAssembler() isn't called below, claim the args // it claims when not running an assembler. Otherwise, clang would emit // "argument unused" warnings for assembler flags when e.g. adding "-E" to @@ -4395,6 +4891,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } Args.ClaimAllArgs(options::OPT_Wa_COMMA); Args.ClaimAllArgs(options::OPT_Xassembler); + Args.ClaimAllArgs(options::OPT_femit_dwarf_unwind_EQ); } if (isa<AnalyzeJobAction>(JA)) { @@ -4410,6 +4907,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_rewrite_objc) && !Args.hasArg(options::OPT_g_Group)) CmdArgs.push_back("-P"); + else if (JA.getType() == types::TY_PP_CXXHeaderUnit) + CmdArgs.push_back("-fdirectives-only"); } } else if (isa<AssembleJobAction>(JA)) { CmdArgs.push_back("-emit-obj"); @@ -4422,13 +4921,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (JA.getType() == types::TY_Nothing) CmdArgs.push_back("-fsyntax-only"); else if (JA.getType() == types::TY_ModuleFile) - CmdArgs.push_back(IsHeaderModulePrecompile - ? "-emit-header-module" - : "-emit-module-interface"); + CmdArgs.push_back("-emit-module-interface"); + else if (JA.getType() == types::TY_HeaderUnit) + CmdArgs.push_back("-emit-header-unit"); else CmdArgs.push_back("-emit-pch"); } else if (isa<VerifyPCHJobAction>(JA)) { CmdArgs.push_back("-verify-pch"); + } else if (isa<ExtractAPIJobAction>(JA)) { + assert(JA.getType() == types::TY_API_INFO && + "Extract API actions must generate a API information."); + CmdArgs.push_back("-extract-api"); + if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ)) + ProductNameArg->render(Args, CmdArgs); + if (Arg *ExtractAPIIgnoresFileArg = + Args.getLastArg(options::OPT_extract_api_ignores_EQ)) + ExtractAPIIgnoresFileArg->render(Args, CmdArgs); } else { assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && "Invalid action for clang tool."); @@ -4479,38 +4987,47 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-emit-llvm-uselists"); if (IsUsingLTO) { - if (!IsDeviceOffloadAction) { - if (Args.hasArg(options::OPT_flto)) - CmdArgs.push_back("-flto"); - else { - if (D.getLTOMode() == LTOK_Thin) - CmdArgs.push_back("-flto=thin"); - else - CmdArgs.push_back("-flto=full"); - } - CmdArgs.push_back("-flto-unit"); - } else if (Triple.isAMDGPU()) { - // Only AMDGPU supports device-side LTO - assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); - CmdArgs.push_back(Args.MakeArgString( - Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); - CmdArgs.push_back("-flto-unit"); - } else { + if (IsDeviceOffloadAction && !JA.isDeviceOffloading(Action::OFK_OpenMP) && + !Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false) && + !Triple.isAMDGPU()) { D.Diag(diag::err_drv_unsupported_opt_for_target) << Args.getLastArg(options::OPT_foffload_lto, options::OPT_foffload_lto_EQ) ->getAsString(Args) << Triple.getTriple(); + } else if (Triple.isNVPTX() && !IsRDCMode && + JA.isDeviceOffloading(Action::OFK_Cuda)) { + D.Diag(diag::err_drv_unsupported_opt_for_language_mode) + << Args.getLastArg(options::OPT_foffload_lto, + options::OPT_foffload_lto_EQ) + ->getAsString(Args) + << "-fno-gpu-rdc"; + } else { + assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); + CmdArgs.push_back(Args.MakeArgString( + Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); + // PS4 uses the legacy LTO API, which does not support some of the + // features enabled by -flto-unit. + if (!RawTriple.isPS4() || + (D.getLTOMode() == LTOK_Full) || !UnifiedLTO) + CmdArgs.push_back("-flto-unit"); } } } + Args.AddLastArg(CmdArgs, options::OPT_dumpdir); + if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) { if (!types::isLLVMIR(Input.getType())) D.Diag(diag::err_drv_arg_requires_bitcode_input) << A->getAsString(Args); Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); } + if (Triple.isPPC()) + Args.addOptInFlag(CmdArgs, options::OPT_mregnames, + options::OPT_mno_regnames); + if (Args.getLastArg(options::OPT_fthin_link_bitcode_EQ)) Args.AddLastArg(CmdArgs, options::OPT_fthin_link_bitcode_EQ); @@ -4524,6 +5041,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, !MemProfArg->getOption().matches(options::OPT_fno_memory_profile)) MemProfArg->render(Args, CmdArgs); + if (auto *MemProfUseArg = + Args.getLastArg(options::OPT_fmemory_profile_use_EQ)) { + if (MemProfArg) + D.Diag(diag::err_drv_argument_not_allowed_with) + << MemProfUseArg->getAsString(Args) << MemProfArg->getAsString(Args); + if (auto *PGOInstrArg = Args.getLastArg(options::OPT_fprofile_generate, + options::OPT_fprofile_generate_EQ)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << MemProfUseArg->getAsString(Args) << PGOInstrArg->getAsString(Args); + MemProfUseArg->render(Args, CmdArgs); + } + // Embed-bitcode option. // Only white-listed flags below are allowed to be embedded. if (C.getDriver().embedBitcodeInObject() && !IsUsingLTO && @@ -4538,7 +5067,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // reject options that shouldn't be supported in bitcode // also reject kernel/kext - static const constexpr unsigned kBitcodeOptionBlacklist[] = { + static const constexpr unsigned kBitcodeOptionIgnorelist[] = { options::OPT_mkernel, options::OPT_fapple_kext, options::OPT_ffunction_sections, @@ -4582,14 +5111,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_mllvm, }; for (const auto &A : Args) - if (llvm::find(kBitcodeOptionBlacklist, A->getOption().getID()) != - std::end(kBitcodeOptionBlacklist)) + if (llvm::is_contained(kBitcodeOptionIgnorelist, A->getOption().getID())) 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); @@ -4600,7 +5127,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumbeb: - RenderARMABI(Triple, Args, CmdArgs); + RenderARMABI(D, Triple, Args, CmdArgs); break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: @@ -4639,7 +5166,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::AtFileUTF8(), D.getClangProgramPath(), - CmdArgs, Inputs, Output)); + CmdArgs, Inputs, Output, D.getPrependArg())); return; } @@ -4651,6 +5178,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // cleanup. if (!C.isForDiagnostics()) CmdArgs.push_back("-disable-free"); + CmdArgs.push_back("-clear-ast-before-backend"); #ifdef NDEBUG const bool IsAssertBuild = false; @@ -4658,18 +5186,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const bool IsAssertBuild = true; #endif - // Disable the verification pass in -asserts builds. - if (!IsAssertBuild) + // Disable the verification pass in asserts builds unless otherwise specified. + if (Args.hasFlag(options::OPT_fno_verify_intermediate_code, + options::OPT_fverify_intermediate_code, !IsAssertBuild)) { CmdArgs.push_back("-disable-llvm-verifier"); + } // Discard value names in assert builds unless otherwise specified. if (Args.hasFlag(options::OPT_fdiscard_value_names, options::OPT_fno_discard_value_names, !IsAssertBuild)) { if (Args.hasArg(options::OPT_fdiscard_value_names) && - (std::any_of(Inputs.begin(), Inputs.end(), - [](const clang::driver::InputInfo &II) { - return types::isLLVMIR(II.getType()); - }))) { + llvm::any_of(Inputs, [](const clang::driver::InputInfo &II) { + return types::isLLVMIR(II.getType()); + })) { D.Diag(diag::warn_ignoring_fdiscard_for_bitcode); } CmdArgs.push_back("-discard-value-names"); @@ -4699,13 +5228,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Since we can't access frontend flags through hasArg, let's manually iterate // through them. bool FoundAnalyzerConfig = false; - for (auto Arg : Args.filtered(options::OPT_Xclang)) + for (auto *Arg : Args.filtered(options::OPT_Xclang)) if (StringRef(Arg->getValue()) == "-analyzer-config") { FoundAnalyzerConfig = true; break; } if (!FoundAnalyzerConfig) - for (auto Arg : Args.filtered(options::OPT_Xanalyzer)) + for (auto *Arg : Args.filtered(options::OPT_Xanalyzer)) if (StringRef(Arg->getValue()) == "-analyzer-config") { FoundAnalyzerConfig = true; break; @@ -4722,10 +5251,74 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(std::to_string(FunctionAlignment))); } + // We support -falign-loops=N where N is a power of 2. GCC supports more + // forms. + if (const Arg *A = Args.getLastArg(options::OPT_falign_loops_EQ)) { + unsigned Value = 0; + if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 65536) + TC.getDriver().Diag(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + else if (Value & (Value - 1)) + TC.getDriver().Diag(diag::err_drv_alignment_not_power_of_two) + << A->getAsString(Args) << A->getValue(); + // Treat =0 as unspecified (use the target preference). + if (Value) + CmdArgs.push_back(Args.MakeArgString("-falign-loops=" + + Twine(std::min(Value, 65536u)))); + } + + if (Triple.isOSzOS()) { + // On z/OS some of the system header feature macros need to + // be defined to enable most cross platform projects to build + // successfully. Ths include the libc++ library. A + // complicating factor is that users can define these + // macros to the same or different values. We need to add + // the definition for these macros to the compilation command + // if the user hasn't already defined them. + + auto findMacroDefinition = [&](const std::string &Macro) { + auto MacroDefs = Args.getAllArgValues(options::OPT_D); + return llvm::any_of(MacroDefs, [&](const std::string &M) { + return M == Macro || M.find(Macro + '=') != std::string::npos; + }); + }; + + // _UNIX03_WITHDRAWN is required for libcxx & porting. + if (!findMacroDefinition("_UNIX03_WITHDRAWN")) + CmdArgs.push_back("-D_UNIX03_WITHDRAWN"); + // _OPEN_DEFAULT is required for XL compat + if (!findMacroDefinition("_OPEN_DEFAULT")) + CmdArgs.push_back("-D_OPEN_DEFAULT"); + if (D.CCCIsCXX() || types::isCXX(Input.getType())) { + // _XOPEN_SOURCE=600 is required for libcxx. + if (!findMacroDefinition("_XOPEN_SOURCE")) + CmdArgs.push_back("-D_XOPEN_SOURCE=600"); + } + } + llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(TC, Args); + Arg *LastPICDataRelArg = + Args.getLastArg(options::OPT_mno_pic_data_is_text_relative, + options::OPT_mpic_data_is_text_relative); + bool NoPICDataIsTextRelative = false; + if (LastPICDataRelArg) { + if (LastPICDataRelArg->getOption().matches( + options::OPT_mno_pic_data_is_text_relative)) { + NoPICDataIsTextRelative = true; + if (!PICLevel) + D.Diag(diag::err_drv_argument_only_allowed_with) + << "-mno-pic-data-is-text-relative" + << "-fpic/-fpie"; + } + if (!Triple.isSystemZ()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << (NoPICDataIsTextRelative ? "-mno-pic-data-is-text-relative" + : "-mpic-data-is-text-relative") + << RawTriple.str(); + } bool IsROPI = RelocationModel == llvm::Reloc::ROPI || RelocationModel == llvm::Reloc::ROPI_RWPI; @@ -4754,6 +5347,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); if (IsPIE) CmdArgs.push_back("-pic-is-pie"); + if (NoPICDataIsTextRelative) + CmdArgs.push_back("-mcmodel=medium"); } if (RelocationModel == llvm::Reloc::ROPI || @@ -4810,37 +5405,41 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - Args.AddLastArg(CmdArgs, options::OPT_fveclib); + if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { + StringRef Name = A->getValue(); + if (Name == "SVML") { + if (Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } else if (Name == "LIBMVEC-X86") { + if (Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } else if (Name == "SLEEF" || Name == "ArmPL") { + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_be) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } + A->render(Args, CmdArgs); + } if (Args.hasFlag(options::OPT_fmerge_all_constants, options::OPT_fno_merge_all_constants, false)) CmdArgs.push_back("-fmerge-all-constants"); - if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks, - options::OPT_fdelete_null_pointer_checks, false)) - CmdArgs.push_back("-fno-delete-null-pointer-checks"); + Args.addOptOutFlag(CmdArgs, options::OPT_fdelete_null_pointer_checks, + options::OPT_fno_delete_null_pointer_checks); // LLVM Code Generator Options. - for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file_EQ)) { - StringRef Map = A->getValue(); - if (!llvm::sys::fs::exists(Map)) { - D.Diag(diag::err_drv_no_such_file) << Map; - } else { - A->render(Args, CmdArgs); - A->claim(); - } - } - - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_vec_extabi, - options::OPT_mabi_EQ_vec_default)) { - if (!Triple.isOSAIX()) + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_quadword_atomics)) { + if (!Triple.isOSAIX() || Triple.isPPC32()) D.Diag(diag::err_drv_unsupported_opt_for_target) - << A->getSpelling() << RawTriple.str(); - if (A->getOption().getID() == options::OPT_mabi_EQ_vec_extabi) - CmdArgs.push_back("-mabi=vec-extabi"); - else - CmdArgs.push_back("-mabi=vec-default"); + << A->getSpelling() << RawTriple.str(); + CmdArgs.push_back("-mabi=quadword-atomics"); } if (Arg *A = Args.getLastArg(options::OPT_mlong_double_128)) { @@ -4852,27 +5451,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) { - StringRef v = A->getValue(); - // FIXME: Validate the argument here so we don't produce meaningless errors - // about -fwarn-stack-size=. - if (v.empty()) - D.Diag(diag::err_drv_missing_argument) << A->getSpelling() << 1; + StringRef V = A->getValue(), V1 = V; + unsigned Size; + if (V1.consumeInteger(10, Size) || !V1.empty()) + D.Diag(diag::err_drv_invalid_argument_to_option) + << V << A->getOption().getName(); else - CmdArgs.push_back(Args.MakeArgString("-fwarn-stack-size=" + v)); - A->claim(); + CmdArgs.push_back(Args.MakeArgString("-fwarn-stack-size=" + V)); } - if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables, - true)) - CmdArgs.push_back("-fno-jump-tables"); - - if (Args.hasFlag(options::OPT_fprofile_sample_accurate, - options::OPT_fno_profile_sample_accurate, false)) - CmdArgs.push_back("-fprofile-sample-accurate"); - - if (!Args.hasFlag(options::OPT_fpreserve_as_comments, - options::OPT_fno_preserve_as_comments, true)) - CmdArgs.push_back("-fno-preserve-as-comments"); + Args.addOptOutFlag(CmdArgs, options::OPT_fjump_tables, + options::OPT_fno_jump_tables); + Args.addOptInFlag(CmdArgs, options::OPT_fprofile_sample_accurate, + options::OPT_fno_profile_sample_accurate); + Args.addOptOutFlag(CmdArgs, options::OPT_fpreserve_as_comments, + options::OPT_fno_preserve_as_comments); if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { CmdArgs.push_back("-mregparm"); @@ -4905,8 +5498,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) - CmdArgs.push_back("-fdefault-calling-conv=stdcall"); + if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) { + if (Triple.getArch() == llvm::Triple::m68k) + CmdArgs.push_back("-fdefault-calling-conv=rtdcall"); + else + CmdArgs.push_back("-fdefault-calling-conv=stdcall"); + } if (Args.hasArg(options::OPT_fenable_matrix)) { // enable-matrix is needed by both the LangOpts and by LLVM. @@ -4932,9 +5529,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(FPKeepKindStr && "unknown FramePointerKind"); CmdArgs.push_back(FPKeepKindStr); - if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, - options::OPT_fno_zero_initialized_in_bss, true)) - CmdArgs.push_back("-fno-zero-initialized-in-bss"); + Args.addOptOutFlag(CmdArgs, options::OPT_fzero_initialized_in_bss, + options::OPT_fno_zero_initialized_in_bss); bool OFastEnabled = isOptimizationLevelFast(Args); // If -Ofast is the optimization level, then -fstrict-aliasing should be @@ -4948,31 +5544,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_strict_aliasing, TBAAOnByDefault)) CmdArgs.push_back("-relaxed-aliasing"); if (!Args.hasFlag(options::OPT_fstruct_path_tbaa, - options::OPT_fno_struct_path_tbaa)) + options::OPT_fno_struct_path_tbaa, true)) CmdArgs.push_back("-no-struct-path-tbaa"); - if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, - false)) - CmdArgs.push_back("-fstrict-enums"); - if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return, - true)) - CmdArgs.push_back("-fno-strict-return"); - if (Args.hasFlag(options::OPT_fallow_editor_placeholders, - options::OPT_fno_allow_editor_placeholders, false)) - CmdArgs.push_back("-fallow-editor-placeholders"); - if (Args.hasFlag(options::OPT_fstrict_vtable_pointers, - options::OPT_fno_strict_vtable_pointers, - false)) - CmdArgs.push_back("-fstrict-vtable-pointers"); - if (Args.hasFlag(options::OPT_fforce_emit_vtables, - options::OPT_fno_force_emit_vtables, - false)) - CmdArgs.push_back("-fforce-emit-vtables"); - if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, - options::OPT_fno_optimize_sibling_calls)) - CmdArgs.push_back("-mdisable-tail-calls"); - if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls, - options::OPT_fescaping_block_tail_calls, false)) - CmdArgs.push_back("-fno-escaping-block-tail-calls"); + Args.addOptInFlag(CmdArgs, options::OPT_fstrict_enums, + options::OPT_fno_strict_enums); + Args.addOptOutFlag(CmdArgs, options::OPT_fstrict_return, + options::OPT_fno_strict_return); + Args.addOptInFlag(CmdArgs, options::OPT_fallow_editor_placeholders, + options::OPT_fno_allow_editor_placeholders); + Args.addOptInFlag(CmdArgs, options::OPT_fstrict_vtable_pointers, + options::OPT_fno_strict_vtable_pointers); + Args.addOptInFlag(CmdArgs, options::OPT_fforce_emit_vtables, + options::OPT_fno_force_emit_vtables); + Args.addOptOutFlag(CmdArgs, options::OPT_foptimize_sibling_calls, + options::OPT_fno_optimize_sibling_calls); + Args.addOptOutFlag(CmdArgs, options::OPT_fescaping_block_tail_calls, + options::OPT_fno_escaping_block_tail_calls); Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses, options::OPT_fno_fine_grained_bitfield_accesses); @@ -4980,10 +5567,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables, options::OPT_fno_experimental_relative_cxx_abi_vtables); + Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti, + options::OPT_fno_experimental_omit_vtable_rtti); + // Handle segmented stacks. - if (Args.hasFlag(options::OPT_fsplit_stack, options::OPT_fno_split_stack, - false)) - CmdArgs.push_back("-fsplit-stack"); + Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack, + options::OPT_fno_split_stack); // -fprotect-parens=0 is default. if (Args.hasFlag(options::OPT_fprotect_parens, @@ -5063,9 +5652,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Enable -mconstructor-aliases except on darwin, where we have to work around - // a linker bug (see <rdar://problem/7651567>), and CUDA/AMDGPU device code, - // where aliases aren't supported. - if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX() && !RawTriple.isAMDGPU()) + // a linker bug (see https://openradar.appspot.com/7198997), and CUDA device + // code, where aliases aren't supported. + if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX()) CmdArgs.push_back("-mconstructor-aliases"); // Darwin's kernel doesn't support guard variables; just die if we @@ -5078,14 +5667,28 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mms-bitfields"); } + if (Triple.isWindowsGNUEnvironment()) { + Args.addOptOutFlag(CmdArgs, options::OPT_fauto_import, + options::OPT_fno_auto_import); + } + + if (Args.hasFlag(options::OPT_fms_volatile, options::OPT_fno_ms_volatile, + Triple.isX86() && D.IsCLMode())) + CmdArgs.push_back("-fms-volatile"); + // Non-PIC code defaults to -fdirect-access-external-data while PIC code // defaults to -fno-direct-access-external-data. Pass the option if different // from the default. if (Arg *A = Args.getLastArg(options::OPT_fdirect_access_external_data, - options::OPT_fno_direct_access_external_data)) + options::OPT_fno_direct_access_external_data)) { if (A->getOption().matches(options::OPT_fdirect_access_external_data) != (PICLevel == 0)) A->render(Args, CmdArgs); + } else if (PICLevel == 0 && Triple.isLoongArch()) { + // Some targets default to -fno-direct-access-external-data even for + // -fno-pic. + CmdArgs.push_back("-fno-direct-access-external-data"); + } if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) { CmdArgs.push_back("-fno-plt"); @@ -5100,19 +5703,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Freestanding) CmdArgs.push_back("-ffreestanding"); + Args.AddLastArg(CmdArgs, options::OPT_fno_knr_functions); + // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. + auto SanitizeArgs = TC.getSanitizerArgs(Args); + + bool IsAsyncUnwindTablesDefault = + TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Asynchronous; + bool IsSyncUnwindTablesDefault = + TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Synchronous; + + bool AsyncUnwindTables = Args.hasFlag( + options::OPT_fasynchronous_unwind_tables, + options::OPT_fno_asynchronous_unwind_tables, + (IsAsyncUnwindTablesDefault || SanitizeArgs.needsUnwindTables()) && + !Freestanding); bool UnwindTables = - Args.hasFlag(options::OPT_fasynchronous_unwind_tables, - options::OPT_fno_asynchronous_unwind_tables, - (TC.IsUnwindTablesDefault(Args) || - TC.getSanitizerArgs().needsUnwindTables()) && - !Freestanding); - UnwindTables = Args.hasFlag(options::OPT_funwind_tables, - options::OPT_fno_unwind_tables, UnwindTables); - if (UnwindTables) - CmdArgs.push_back("-munwind-tables"); + Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, + IsSyncUnwindTablesDefault && !Freestanding); + if (AsyncUnwindTables) + CmdArgs.push_back("-funwind-tables=2"); + else if (UnwindTables) + CmdArgs.push_back("-funwind-tables=1"); // Prepare `-aux-target-cpu` and `-aux-target-feature` unless // `--gpu-use-aux-triple-only` is specified. @@ -5121,7 +5735,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &HostArgs = C.getArgsForToolChain(nullptr, StringRef(), Action::OFK_None); std::string HostCPU = - getCPUName(HostArgs, *TC.getAuxTriple(), /*FromAs*/ false); + getCPUName(D, HostArgs, *TC.getAuxTriple(), /*FromAs*/ false); if (!HostCPU.empty()) { CmdArgs.push_back("-aux-target-cpu"); CmdArgs.push_back(Args.MakeArgString(HostCPU)); @@ -5132,20 +5746,78 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind()); - // FIXME: Handle -mtune=. - (void)Args.hasArg(options::OPT_mtune_EQ); - if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { StringRef CM = A->getValue(); - if (CM == "small" || CM == "kernel" || CM == "medium" || CM == "large" || - CM == "tiny") { - if (Triple.isOSAIX() && CM == "medium") - CmdArgs.push_back("-mcmodel=large"); - else - A->render(Args, CmdArgs); + bool Ok = false; + if (Triple.isOSAIX() && CM == "medium") + CM = "large"; + if (Triple.isAArch64(64)) { + Ok = CM == "tiny" || CM == "small" || CM == "large"; + if (CM == "large" && RelocationModel != llvm::Reloc::Static) + D.Diag(diag::err_drv_argument_only_allowed_with) + << A->getAsString(Args) << "-fno-pic"; + } else if (Triple.isLoongArch()) { + if (CM == "extreme" && + Args.hasFlagNoClaim(options::OPT_fplt, options::OPT_fno_plt, false)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-fplt"; + Ok = CM == "normal" || CM == "medium" || CM == "extreme"; + // Convert to LLVM recognizable names. + if (Ok) + CM = llvm::StringSwitch<StringRef>(CM) + .Case("normal", "small") + .Case("extreme", "large") + .Default(CM); + } else if (Triple.isPPC64() || Triple.isOSAIX()) { + Ok = CM == "small" || CM == "medium" || CM == "large"; + } else if (Triple.isRISCV()) { + if (CM == "medlow") + CM = "small"; + else if (CM == "medany") + CM = "medium"; + Ok = CM == "small" || CM == "medium"; + } else if (Triple.getArch() == llvm::Triple::x86_64) { + Ok = llvm::is_contained({"small", "kernel", "medium", "large", "tiny"}, + CM); + } else if (Triple.isNVPTX() || Triple.isAMDGPU()) { + // NVPTX/AMDGPU does not care about the code model and will accept + // whatever works for the host. + Ok = true; + } else if (Triple.isSPARC64()) { + if (CM == "medlow") + CM = "small"; + else if (CM == "medmid") + CM = "medium"; + else if (CM == "medany") + CM = "large"; + Ok = CM == "small" || CM == "medium" || CM == "large"; + } + if (Ok) { + CmdArgs.push_back(Args.MakeArgString("-mcmodel=" + CM)); } else { - D.Diag(diag::err_drv_invalid_argument_to_option) - << CM << A->getOption().getName(); + D.Diag(diag::err_drv_unsupported_option_argument_for_target) + << A->getSpelling() << CM << TripleStr; + } + } + + if (Triple.getArch() == llvm::Triple::x86_64) { + bool IsMediumCM = false; + bool IsLargeCM = false; + if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { + IsMediumCM = StringRef(A->getValue()) == "medium"; + IsLargeCM = StringRef(A->getValue()) == "large"; + } + if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) { + if (!IsMediumCM && !IsLargeCM) { + D.Diag(diag::warn_drv_large_data_threshold_invalid_code_model) + << A->getOption().getRenderName(); + } else { + A->render(Args, CmdArgs); + } + } else if (IsMediumCM) { + CmdArgs.push_back("-mlarge-data-threshold=65536"); + } else if (IsLargeCM) { + CmdArgs.push_back("-mlarge-data-threshold=0"); } } @@ -5162,8 +5834,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_mtls_size_EQ); } + if (isTLSDESCEnabled(TC, Args)) + CmdArgs.push_back("-enable-tlsdesc"); + // Add the target cpu - std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); + std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ false); if (!CPU.empty()) { CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(Args.MakeArgString(CPU)); @@ -5171,40 +5846,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs); - // FIXME: For now we want to demote any errors to warnings, when they have - // been raised for asking the wrong question of scalable vectors, such as - // asking for the fixed number of elements. This may happen because code that - // is not yet ported to work for scalable vectors uses the wrong interfaces, - // whereas the behaviour is actually correct. Emitting a warning helps bring - // up scalable vector support in an incremental way. When scalable vector - // support is stable enough, all uses of wrong interfaces should be considered - // as errors, but until then, we can live with a warning being emitted by the - // compiler. This way, Clang can be used to compile code with scalable vectors - // and identify possible issues. - if (isa<BackendJobAction>(JA)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-treat-scalable-fixed-error-as-warning"); - } - - // These two are potentially updated by AddClangCLArgs. - codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; - bool EmitCodeView = false; - // Add clang-cl arguments. types::ID InputType = Input.getType(); if (D.IsCLMode()) - AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); + AddClangCLArgs(Args, InputType, CmdArgs); + llvm::codegenoptions::DebugInfoKind DebugInfoKind = + llvm::codegenoptions::NoDebugInfo; DwarfFissionKind DwarfFission = DwarfFissionKind::None; - renderDebugOptions(TC, D, RawTriple, Args, EmitCodeView, - types::isLLVMIR(InputType), CmdArgs, DebugInfoKind, - DwarfFission); + renderDebugOptions(TC, D, RawTriple, Args, types::isLLVMIR(InputType), + CmdArgs, Output, DebugInfoKind, DwarfFission); // Add the split debug info name to the command lines here so we // can propagate it to the backend. bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) && (TC.getTriple().isOSBinFormatELF() || - TC.getTriple().isOSBinFormatWasm()) && + TC.getTriple().isOSBinFormatWasm() || + TC.getTriple().isOSBinFormatCOFF()) && (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)); if (SplitDWARF) { @@ -5252,12 +5910,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddAllArgs(CmdArgs, options::OPT_fshow_skipped_includes); - if (D.CCPrintHeaders && !D.CCGenDiagnostics) { + if (D.CCPrintHeadersFormat && !D.CCGenDiagnostics) { CmdArgs.push_back("-header-include-file"); CmdArgs.push_back(!D.CCPrintHeadersFilename.empty() ? D.CCPrintHeadersFilename.c_str() : "-"); CmdArgs.push_back("-sys-header-deps"); + CmdArgs.push_back(Args.MakeArgString( + "-header-include-format=" + + std::string(headerIncludeFormatKindToString(D.CCPrintHeadersFormat)))); + CmdArgs.push_back( + Args.MakeArgString("-header-include-filtering=" + + std::string(headerIncludeFilteringKindToString( + D.CCPrintHeadersFiltering)))); } Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); @@ -5293,7 +5958,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef Val = A->getValue(); if (Triple.isX86() && Triple.isOSBinFormatELF()) { if (Val != "all" && Val != "labels" && Val != "none" && - !Val.startswith("list=")) + !Val.starts_with("list=")) D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); else @@ -5315,27 +5980,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fdata-sections"); } - if (!Args.hasFlag(options::OPT_funique_section_names, - options::OPT_fno_unique_section_names, true)) - CmdArgs.push_back("-fno-unique-section-names"); - - if (Args.hasFlag(options::OPT_funique_internal_linkage_names, - options::OPT_fno_unique_internal_linkage_names, false)) - CmdArgs.push_back("-funique-internal-linkage-names"); - - if (Args.hasFlag(options::OPT_funique_basic_block_section_names, - options::OPT_fno_unique_basic_block_section_names, false)) - CmdArgs.push_back("-funique-basic-block-section-names"); + Args.addOptOutFlag(CmdArgs, options::OPT_funique_section_names, + options::OPT_fno_unique_section_names); + Args.addOptInFlag(CmdArgs, options::OPT_funique_internal_linkage_names, + options::OPT_fno_unique_internal_linkage_names); + Args.addOptInFlag(CmdArgs, options::OPT_funique_basic_block_section_names, + options::OPT_fno_unique_basic_block_section_names); + Args.addOptInFlag(CmdArgs, options::OPT_fconvergent_functions, + options::OPT_fno_convergent_functions); if (Arg *A = Args.getLastArg(options::OPT_fsplit_machine_functions, options::OPT_fno_split_machine_functions)) { - // This codegen pass is only available on x86-elf targets. - if (Triple.isX86() && Triple.isOSBinFormatELF()) { - if (A->getOption().matches(options::OPT_fsplit_machine_functions)) + if (!A->getOption().matches(options::OPT_fno_split_machine_functions)) { + // This codegen pass is only available on x86 and AArch64 ELF targets. + if ((Triple.isX86() || Triple.isAArch64()) && Triple.isOSBinFormatELF()) A->render(Args, CmdArgs); - } else { - D.Diag(diag::err_drv_unsupported_opt_for_target) - << A->getAsString(Args) << TripleStr; + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; } } @@ -5347,15 +6009,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // for sampling, overhead of call arc collection is way too high and there's // no way to collect the output. if (!Triple.isNVPTX() && !Triple.isAMDGCN()) - addPGOAndCoverageFlags(TC, C, D, Output, Args, CmdArgs); + addPGOAndCoverageFlags(TC, C, JA, Output, Args, SanitizeArgs, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ); - // Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled. - if (RawTriple.isPS4CPU() && + if (getLastProfileSampleUseArg(Args) && + Args.hasArg(options::OPT_fsample_profile_use_profi)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-sample-profile-use-profi"); + } + + // Add runtime flag for PS4/PS5 when PGO, coverage, or sanitizers are enabled. + if (RawTriple.isPS() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - PS4cpu::addProfileRTArgs(TC, Args, CmdArgs); - PS4cpu::addSanitizerArgs(TC, CmdArgs); + PScpu::addProfileRTArgs(TC, Args, CmdArgs); + PScpu::addSanitizerArgs(TC, Args, CmdArgs); } // Pass options for controlling the default header search paths. @@ -5417,16 +6085,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_R_Group); - Args.AddAllArgs(CmdArgs, options::OPT_W_Group); + for (const Arg *A : + Args.filtered(options::OPT_W_Group, options::OPT__SLASH_wd)) { + A->claim(); + if (A->getOption().getID() == options::OPT__SLASH_wd) { + unsigned WarningNumber; + if (StringRef(A->getValue()).getAsInteger(10, WarningNumber)) { + D.Diag(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + continue; + } + + if (auto Group = diagGroupFromCLWarningID(WarningNumber)) { + CmdArgs.push_back(Args.MakeArgString( + "-Wno-" + DiagnosticIDs::getWarningOptionForGroup(*Group))); + } + continue; + } + A->render(Args, CmdArgs); + } + + Args.AddAllArgs(CmdArgs, options::OPT_Wsystem_headers_in_module_EQ); + if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) CmdArgs.push_back("-pedantic"); Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); Args.AddLastArg(CmdArgs, options::OPT_w); - // Fixed point flags - if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point, - /*Default=*/false)) - Args.AddLastArg(CmdArgs, options::OPT_ffixed_point); + Args.addOptInFlag(CmdArgs, options::OPT_ffixed_point, + options::OPT_fno_fixed_point); if (Arg *A = Args.getLastArg(options::OPT_fcxx_abi_EQ)) A->render(Args, CmdArgs); @@ -5434,6 +6121,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables, options::OPT_fno_experimental_relative_cxx_abi_vtables); + Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti, + options::OPT_fno_experimental_omit_vtable_rtti); + + if (Arg *A = Args.getLastArg(options::OPT_ffuchsia_api_level_EQ)) + A->render(Args, CmdArgs); + // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} // (-ansi is equivalent to -std=c89 or -std=c++98). // @@ -5476,11 +6169,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs, options::OPT_fno_trigraphs); - - // HIP headers has minimum C++ standard requirements. Therefore set the - // default language standard. - if (IsHIP) - CmdArgs.push_back(IsWindowsMSVC ? "-std=c++14" : "-std=c++11"); } // GCC's behavior for -Wwrite-strings is a bit strange: @@ -5523,31 +6211,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!ShouldEnableAutolink(Args, TC, JA)) CmdArgs.push_back("-fno-autolink"); - // Add in -fdebug-compilation-dir if necessary. - addDebugCompDirArg(Args, CmdArgs, D.getVFS()); + Args.AddLastArg(CmdArgs, options::OPT_ftemplate_depth_EQ); + Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ); - addDebugPrefixMapArg(D, Args, CmdArgs); - - if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, - options::OPT_ftemplate_depth_EQ)) { - CmdArgs.push_back("-ftemplate-depth"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) { - CmdArgs.push_back("-foperator-arrow-depth"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) { - CmdArgs.push_back("-fconstexpr-depth"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) { - CmdArgs.push_back("-fconstexpr-steps"); - CmdArgs.push_back(A->getValue()); - } + Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library); if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter)) CmdArgs.push_back("-fexperimental-new-constant-interpreter"); @@ -5574,7 +6243,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, "standalone", "objc", "swift", "swift-5.0", "swift-4.2", "swift-4.1", }; - if (find(kCFABIs, StringRef(A->getValue())) == std::end(kCFABIs)) + if (!llvm::is_contained(kCFABIs, StringRef(A->getValue()))) D.Diag(diag::err_drv_invalid_cf_runtime_abi) << A->getValue(); else A->render(Args, CmdArgs); @@ -5590,9 +6259,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } - if (Args.hasFlag(options::OPT_fstack_size_section, - options::OPT_fno_stack_size_section, RawTriple.isPS4())) - CmdArgs.push_back("-fstack-size-section"); + Args.addOptInFlag(CmdArgs, options::OPT_fstack_size_section, + options::OPT_fno_stack_size_section); if (Args.hasArg(options::OPT_fstack_usage)) { CmdArgs.push_back("-stack-usage-file"); @@ -5612,25 +6280,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("19"); - if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { - CmdArgs.push_back("-fmacro-backtrace-limit"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) { - CmdArgs.push_back("-ftemplate-backtrace-limit"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) { - CmdArgs.push_back("-fconstexpr-backtrace-limit"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) { - CmdArgs.push_back("-fspell-checking-limit"); - CmdArgs.push_back(A->getValue()); - } + Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_backtrace_limit_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fmacro_backtrace_limit_EQ); + Args.AddLastArg(CmdArgs, options::OPT_ftemplate_backtrace_limit_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fspell_checking_limit_EQ); + Args.AddLastArg(CmdArgs, options::OPT_fcaret_diagnostics_max_lines_EQ); // Pass -fmessage-length=. unsigned MessageLength = 0; @@ -5648,22 +6302,33 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString("-fmessage-length=" + Twine(MessageLength))); + if (Arg *A = Args.getLastArg(options::OPT_frandomize_layout_seed_EQ)) + CmdArgs.push_back( + Args.MakeArgString("-frandomize-layout-seed=" + Twine(A->getValue(0)))); + + if (Arg *A = Args.getLastArg(options::OPT_frandomize_layout_seed_file_EQ)) + CmdArgs.push_back(Args.MakeArgString("-frandomize-layout-seed-file=" + + Twine(A->getValue(0)))); + // -fvisibility= and -fvisibility-ms-compat are of a piece. if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ, options::OPT_fvisibility_ms_compat)) { if (A->getOption().matches(options::OPT_fvisibility_EQ)) { - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back(A->getValue()); + A->render(Args, CmdArgs); } else { assert(A->getOption().matches(options::OPT_fvisibility_ms_compat)); - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back("hidden"); - CmdArgs.push_back("-ftype-visibility"); - CmdArgs.push_back("default"); + CmdArgs.push_back("-fvisibility=hidden"); + CmdArgs.push_back("-ftype-visibility=default"); } + } else if (IsOpenMPDevice) { + // When compiling for the OpenMP device we want protected visibility by + // default. This prevents the device from accidentally preempting code on + // the host, makes the system more robust, and improves performance. + CmdArgs.push_back("-fvisibility=protected"); } - if (!RawTriple.isPS4()) + // PS4/PS5 process these options in addClangTargetOptions. + if (!RawTriple.isPS()) { if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_from_dllstorageclass, options::OPT_fno_visibility_from_dllstorageclass)) { @@ -5677,26 +6342,42 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fvisibility_externs_nodllstorageclass_EQ); } } - - if (const Arg *A = Args.getLastArg(options::OPT_mignore_xcoff_visibility)) { - if (Triple.isOSAIX()) - CmdArgs.push_back("-mignore-xcoff-visibility"); - else - D.Diag(diag::err_drv_unsupported_opt_for_target) - << A->getAsString(Args) << TripleStr; } - if (Args.hasFlag(options::OPT_fvisibility_inlines_hidden, options::OPT_fno_visibility_inlines_hidden, false)) CmdArgs.push_back("-fvisibility-inlines-hidden"); Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var, options::OPT_fno_visibility_inlines_hidden_static_local_var); - Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden); + + // -fvisibility-global-new-delete-hidden is a deprecated spelling of + // -fvisibility-global-new-delete=force-hidden. + if (const Arg *A = + Args.getLastArg(options::OPT_fvisibility_global_new_delete_hidden)) { + D.Diag(diag::warn_drv_deprecated_arg) + << A->getAsString(Args) + << "-fvisibility-global-new-delete=force-hidden"; + } + + if (const Arg *A = + Args.getLastArg(options::OPT_fvisibility_global_new_delete_EQ, + options::OPT_fvisibility_global_new_delete_hidden)) { + if (A->getOption().matches(options::OPT_fvisibility_global_new_delete_EQ)) { + A->render(Args, CmdArgs); + } else { + assert(A->getOption().matches( + options::OPT_fvisibility_global_new_delete_hidden)); + CmdArgs.push_back("-fvisibility-global-new-delete=force-hidden"); + } + } Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); + if (Args.hasFlag(options::OPT_fnew_infallible, + options::OPT_fno_new_infallible, false)) + CmdArgs.push_back("-fnew-infallible"); + if (Args.hasFlag(options::OPT_fno_operator_names, options::OPT_foperator_names, false)) CmdArgs.push_back("-fno-operator-names"); @@ -5705,8 +6386,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs); - Args.AddLastArg(CmdArgs, options::OPT_femulated_tls, - options::OPT_fno_emulated_tls); + Args.AddLastArg(CmdArgs, options::OPT_fzero_call_used_regs_EQ); + + if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, + Triple.hasDefaultEmulatedTLS())) + CmdArgs.push_back("-femulated-tls"); + + Args.addOptInFlag(CmdArgs, options::OPT_fcheck_new, + options::OPT_fno_check_new); + + if (Arg *A = Args.getLastArg(options::OPT_fzero_call_used_regs_EQ)) { + // FIXME: There's no reason for this to be restricted to X86. The backend + // code needs to be changed to include the appropriate function calls + // automatically. + if (!Triple.isX86() && !Triple.isAArch64()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } // AltiVec-like language extensions aren't relevant for assembling. if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) @@ -5737,6 +6433,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_openmp_simd); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_enable_irbuilder); 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.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_number_of_sm_EQ); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_blocks_per_sm_EQ); Args.AddAllArgs(CmdArgs, @@ -5752,12 +6451,30 @@ 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 with NVPTX target, check if full runtime - // is required. - if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime, - options::OPT_fno_openmp_cuda_force_full_runtime, + // When in OpenMP offloading mode, enable debugging on the device. + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); + if (Args.hasFlag(options::OPT_fopenmp_target_debug, + options::OPT_fno_openmp_target_debug, /*Default=*/false)) + CmdArgs.push_back("-fopenmp-target-debug"); + + // When in OpenMP offloading mode, forward assumptions information about + // thread and team counts in the device. + if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, + options::OPT_fno_openmp_assume_teams_oversubscription, + /*Default=*/false)) + CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); + if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, + options::OPT_fno_openmp_assume_threads_oversubscription, /*Default=*/false)) - CmdArgs.push_back("-fopenmp-cuda-force-full-runtime"); + CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); + if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) + CmdArgs.push_back("-fopenmp-assume-no-thread-state"); + if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) + CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); + if (Args.hasArg(options::OPT_fopenmp_offload_mandatory)) + CmdArgs.push_back("-fopenmp-offload-mandatory"); + if (Args.hasArg(options::OPT_fopenmp_force_usm)) + CmdArgs.push_back("-fopenmp-force-usm"); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -5772,10 +6489,16 @@ 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); + Args.addOptOutFlag(CmdArgs, options::OPT_fopenmp_extensions, + options::OPT_fno_openmp_extensions); } - const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); - Sanitize.addArgs(TC, Args, CmdArgs, InputType); + // Forward the new driver to change offloading code generation. + if (Args.hasFlag(options::OPT_offload_new_driver, + options::OPT_no_offload_new_driver, false)) + CmdArgs.push_back("--offload-new-driver"); + + SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType); const XRayArgs &XRay = TC.getXRayArgs(); XRay.addArgs(TC, Args, CmdArgs, InputType); @@ -5791,7 +6514,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) { StringRef S0 = A->getValue(), S = S0; unsigned Size, Offset = 0; - if (!Triple.isAArch64() && !Triple.isRISCV() && !Triple.isX86()) + if (!Triple.isAArch64() && !Triple.isLoongArch() && !Triple.isRISCV() && + !Triple.isX86()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; else if (S.consumeInteger(10, Size) || @@ -5808,6 +6532,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + Args.AddLastArg(CmdArgs, options::OPT_fms_hotpatch); + if (TC.SupportsProfiling()) { Args.AddLastArg(CmdArgs, options::OPT_pg); @@ -5835,6 +6561,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (Arg *A = Args.getLastArgNoClaim(options::OPT_pg)) { + if (TC.getTriple().isOSzOS()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + } + if (Arg *A = Args.getLastArgNoClaim(options::OPT_p)) { + if (!(TC.getTriple().isOSAIX() || TC.getTriple().isOSOpenBSD())) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + } + if (Arg *A = Args.getLastArgNoClaim(options::OPT_p, options::OPT_pg)) { + if (A->getOption().matches(options::OPT_p)) { + A->claim(); + if (TC.getTriple().isOSAIX() && !Args.hasArgNoClaim(options::OPT_pg)) + CmdArgs.push_back("-pg"); + } + } + + // Reject AIX-specific link options on other targets. + if (!TC.getTriple().isOSAIX()) { + for (const Arg *A : Args.filtered(options::OPT_b, options::OPT_K, + options::OPT_mxcoff_build_id_EQ)) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << TripleStr; + } + } + if (Args.getLastArg(options::OPT_fapple_kext) || (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) CmdArgs.push_back("-fapple-kext"); @@ -5846,12 +6601,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ); - Args.AddLastArg(CmdArgs, options::OPT_ftime_trace); - Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); Args.AddLastArg(CmdArgs, options::OPT_malign_double); Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file); + if (const char *Name = C.getTimeTraceFile(&JA)) { + CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name))); + Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); + } + if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { CmdArgs.push_back("-ftrapv-handler"); CmdArgs.push_back(A->getValue()); @@ -5882,20 +6640,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_funroll_loops, options::OPT_fno_unroll_loops); + Args.AddLastArg(CmdArgs, options::OPT_fstrict_flex_arrays_EQ); + Args.AddLastArg(CmdArgs, options::OPT_pthread); - if (Args.hasFlag(options::OPT_mspeculative_load_hardening, - options::OPT_mno_speculative_load_hardening, false)) - CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening")); + Args.addOptInFlag(CmdArgs, options::OPT_mspeculative_load_hardening, + options::OPT_mno_speculative_load_hardening); RenderSSPOptions(D, TC, Args, CmdArgs, KernelOrKext); RenderSCPOptions(TC, Args, CmdArgs); RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs); - // Translate -mstackrealign - if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, - false)) - CmdArgs.push_back(Args.MakeArgString("-mstackrealign")); + Args.AddLastArg(CmdArgs, options::OPT_fswift_async_fp_EQ); + + Args.addOptInFlag(CmdArgs, options::OPT_mstackrealign, + options::OPT_mno_stackrealign); if (Args.hasArg(options::OPT_mstack_alignment)) { StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); @@ -5911,9 +6670,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mstack-probe-size=0"); } - if (!Args.hasFlag(options::OPT_mstack_arg_probe, - options::OPT_mno_stack_arg_probe, true)) - CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe")); + Args.addOptOutFlag(CmdArgs, options::OPT_mstack_arg_probe, + options::OPT_mno_stack_arg_probe); if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, options::OPT_mno_restrict_it)) { @@ -5922,34 +6680,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-arm-restrict-it"); } else { CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-arm-no-restrict-it"); + CmdArgs.push_back("-arm-default-it"); } - } else if (Triple.isOSWindows() && - (Triple.getArch() == llvm::Triple::arm || - Triple.getArch() == llvm::Triple::thumb)) { - // Windows on ARM expects restricted IT blocks - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-arm-restrict-it"); } // Forward -cl options to -cc1 RenderOpenCLOptions(Args, CmdArgs, InputType); + // Forward hlsl options to -cc1 + RenderHLSLOptions(Args, CmdArgs, InputType); + + // Forward OpenACC options to -cc1 + RenderOpenACCOptions(D, Args, CmdArgs, InputType); + if (IsHIP) { if (Args.hasFlag(options::OPT_fhip_new_launch_api, options::OPT_fno_hip_new_launch_api, true)) CmdArgs.push_back("-fhip-new-launch-api"); - if (Args.hasFlag(options::OPT_fgpu_allow_device_init, - options::OPT_fno_gpu_allow_device_init, false)) - CmdArgs.push_back("-fgpu-allow-device-init"); + Args.addOptInFlag(CmdArgs, options::OPT_fgpu_allow_device_init, + options::OPT_fno_gpu_allow_device_init); + Args.AddLastArg(CmdArgs, options::OPT_hipstdpar); + Args.AddLastArg(CmdArgs, options::OPT_hipstdpar_interpose_alloc); + Args.addOptInFlag(CmdArgs, options::OPT_fhip_kernel_arg_name, + options::OPT_fno_hip_kernel_arg_name); } if (IsCuda || IsHIP) { - if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) + if (IsRDCMode) CmdArgs.push_back("-fgpu-rdc"); - if (Args.hasFlag(options::OPT_fgpu_defer_diag, - options::OPT_fno_gpu_defer_diag, false)) - CmdArgs.push_back("-fgpu-defer-diag"); + Args.addOptInFlag(CmdArgs, options::OPT_fgpu_defer_diag, + options::OPT_fno_gpu_defer_diag); if (Args.hasFlag(options::OPT_fgpu_exclude_wrong_side_overloads, options::OPT_fno_gpu_exclude_wrong_side_overloads, false)) { @@ -5958,11 +6718,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + // Forward -nogpulib to -cc1. + if (Args.hasArg(options::OPT_nogpulib)) + CmdArgs.push_back("-nogpulib"); + if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) { CmdArgs.push_back( Args.MakeArgString(Twine("-fcf-protection=") + A->getValue())); } + if (Arg *A = Args.getLastArg(options::OPT_mfunction_return_EQ)) + CmdArgs.push_back( + Args.MakeArgString(Twine("-mfunction-return=") + A->getValue())); + + Args.AddLastArg(CmdArgs, options::OPT_mindirect_branch_cs_prefix); + // Forward -f options with positive and negative forms; we translate these by // hand. Do not propagate PGO options to the GPU-side compilations as the // profile info is for the host-side compilation only. @@ -5997,9 +6767,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } RenderBuiltinOptions(TC, RawTriple, Args, CmdArgs); - if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, - options::OPT_fno_assume_sane_operator_new)) - CmdArgs.push_back("-fno-assume-sane-operator-new"); + Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, + options::OPT_fno_assume_sane_operator_new); + + if (Args.hasFlag(options::OPT_fapinotes, options::OPT_fno_apinotes, false)) + CmdArgs.push_back("-fapinotes"); + if (Args.hasFlag(options::OPT_fapinotes_modules, + options::OPT_fno_apinotes_modules, false)) + CmdArgs.push_back("-fapinotes-modules"); + Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version); // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, @@ -6017,24 +6793,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (TC.IsEncodeExtendedBlockSignatureDefault()) CmdArgs.push_back("-fencode-extended-block-signature"); - if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts, - false) && - types::isCXX(InputType)) { - CmdArgs.push_back("-fcoroutines-ts"); - } + if (Args.hasFlag(options::OPT_fcoro_aligned_allocation, + options::OPT_fno_coro_aligned_allocation, false) && + types::isCXX(InputType)) + CmdArgs.push_back("-fcoro-aligned-allocation"); Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes, options::OPT_fno_double_square_bracket_attributes); - // -faccess-control is default. - if (Args.hasFlag(options::OPT_fno_access_control, - options::OPT_faccess_control, false)) - CmdArgs.push_back("-fno-access-control"); - - // -felide-constructors is the default. - if (Args.hasFlag(options::OPT_fno_elide_constructors, - options::OPT_felide_constructors, false)) - CmdArgs.push_back("-fno-elide-constructors"); + Args.addOptOutFlag(CmdArgs, options::OPT_faccess_control, + options::OPT_fno_access_control); + Args.addOptOutFlag(CmdArgs, options::OPT_felide_constructors, + options::OPT_fno_elide_constructors); ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); @@ -6053,7 +6823,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag( options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, !RawTriple.isOSAIX() && !RawTriple.isOSWindows() && - TC.getArch() != llvm::Triple::xcore && ((RawTriple.getVendor() != llvm::Triple::MipsTechnologies) || RawTriple.hasEnvironment())) || KernelOrKext) @@ -6064,10 +6833,28 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RawTriple.isOSDarwin() && !KernelOrKext)) CmdArgs.push_back("-fregister-global-dtors-with-atexit"); - // -fno-use-line-directives is default. - if (Args.hasFlag(options::OPT_fuse_line_directives, - options::OPT_fno_use_line_directives, false)) - CmdArgs.push_back("-fuse-line-directives"); + Args.addOptInFlag(CmdArgs, options::OPT_fuse_line_directives, + options::OPT_fno_use_line_directives); + + // -fno-minimize-whitespace is default. + if (Args.hasFlag(options::OPT_fminimize_whitespace, + options::OPT_fno_minimize_whitespace, false)) { + types::ID InputType = Inputs[0].getType(); + if (!isDerivedFromC(InputType)) + D.Diag(diag::err_drv_opt_unsupported_input_type) + << "-fminimize-whitespace" << types::getTypeName(InputType); + CmdArgs.push_back("-fminimize-whitespace"); + } + + // -fno-keep-system-includes is default. + if (Args.hasFlag(options::OPT_fkeep_system_includes, + options::OPT_fno_keep_system_includes, false)) { + types::ID InputType = Inputs[0].getType(); + if (!isDerivedFromC(InputType)) + D.Diag(diag::err_drv_opt_unsupported_input_type) + << "-fkeep-system-includes" << types::getTypeName(InputType); + CmdArgs.push_back("-fkeep-system-includes"); + } // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, @@ -6082,6 +6869,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (IsMSVCCompat) CmdArgs.push_back("-fms-compatibility"); + if (Triple.isWindowsMSVCEnvironment() && !D.IsCLMode() && + Args.hasArg(options::OPT_fms_runtime_lib_EQ)) + ProcessVSRuntimeLibrary(Args, CmdArgs); + // Handle -fgcc-version, if present. VersionTuple GNUCVer; if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) { @@ -6090,8 +6881,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef Val = A->getValue(); Val = Val.empty() ? "0" : Val; // Treat "" as 0 or disable. bool Invalid = GNUCVer.tryParse(Val); - unsigned Minor = GNUCVer.getMinor().getValueOr(0); - unsigned Patch = GNUCVer.getSubminor().getValueOr(0); + unsigned Minor = GNUCVer.getMinor().value_or(0); + unsigned Patch = GNUCVer.getSubminor().value_or(0); if (Invalid || GNUCVer.getBuild() || Minor >= 100 || Patch >= 100) { D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); @@ -6133,7 +6924,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, .Case("c++14", "-std=c++14") .Case("c++17", "-std=c++17") .Case("c++20", "-std=c++20") - .Case("c++latest", "-std=c++2b") + // TODO add c++23 and c++26 when MSVC supports it. + .Case("c++latest", "-std=c++26") .Default(""); if (LanguageStandard.empty()) D.Diag(clang::diag::warn_drv_unused_argument) @@ -6150,14 +6942,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(LanguageStandard.data()); } - // -fno-borland-extensions is default. - if (Args.hasFlag(options::OPT_fborland_extensions, - options::OPT_fno_borland_extensions, false)) - CmdArgs.push_back("-fborland-extensions"); + Args.addOptInFlag(CmdArgs, options::OPT_fborland_extensions, + options::OPT_fno_borland_extensions); - // -fno-declspec is default, except for PS4. + // -fno-declspec is default, except for PS4/PS5. if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec, - RawTriple.isPS4())) + RawTriple.isPS())) CmdArgs.push_back("-fdeclspec"); else if (Args.hasArg(options::OPT_fno_declspec)) CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec. @@ -6166,39 +6956,62 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // than 19. if (!Args.hasFlag(options::OPT_fthreadsafe_statics, options::OPT_fno_threadsafe_statics, - !IsWindowsMSVC || IsMSVC2015Compatible)) + !types::isOpenCL(InputType) && + (!IsWindowsMSVC || IsMSVC2015Compatible))) CmdArgs.push_back("-fno-threadsafe-statics"); - // -fno-delayed-template-parsing is default, except when targeting MSVC. - // Many old Windows SDK versions require this to parse. - // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their - // compiler. We should be able to disable this by default at some point. - if (Args.hasFlag(options::OPT_fdelayed_template_parsing, - options::OPT_fno_delayed_template_parsing, IsWindowsMSVC)) - CmdArgs.push_back("-fdelayed-template-parsing"); - // -fgnu-keywords default varies depending on language; only pass if // specified. Args.AddLastArg(CmdArgs, options::OPT_fgnu_keywords, options::OPT_fno_gnu_keywords); - if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline, - false)) - CmdArgs.push_back("-fgnu89-inline"); + Args.addOptInFlag(CmdArgs, options::OPT_fgnu89_inline, + options::OPT_fno_gnu89_inline); - if (Args.hasArg(options::OPT_fno_inline)) - CmdArgs.push_back("-fno-inline"); + const Arg *InlineArg = Args.getLastArg(options::OPT_finline_functions, + options::OPT_finline_hint_functions, + options::OPT_fno_inline_functions); + if (Arg *A = Args.getLastArg(options::OPT_finline, options::OPT_fno_inline)) { + if (A->getOption().matches(options::OPT_fno_inline)) + A->render(Args, CmdArgs); + } else if (InlineArg) { + InlineArg->render(Args, CmdArgs); + } + + Args.AddLastArg(CmdArgs, options::OPT_finline_max_stacksize_EQ); + + // FIXME: Find a better way to determine whether we are in C++20. + bool HaveCxx20 = + Std && + (Std->containsValue("c++2a") || Std->containsValue("gnu++2a") || + Std->containsValue("c++20") || Std->containsValue("gnu++20") || + Std->containsValue("c++2b") || Std->containsValue("gnu++2b") || + Std->containsValue("c++23") || Std->containsValue("gnu++23") || + Std->containsValue("c++2c") || Std->containsValue("gnu++2c") || + Std->containsValue("c++26") || Std->containsValue("gnu++26") || + Std->containsValue("c++latest") || Std->containsValue("gnu++latest")); + bool HaveModules = + RenderModulesOptions(C, D, Args, Input, Output, HaveCxx20, CmdArgs); - Args.AddLastArg(CmdArgs, options::OPT_finline_functions, - options::OPT_finline_hint_functions, - options::OPT_fno_inline_functions); + // -fdelayed-template-parsing is default when targeting MSVC. + // Many old Windows SDK versions require this to parse. + // + // According to + // https://learn.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance?view=msvc-170, + // MSVC actually defaults to -fno-delayed-template-parsing (/Zc:twoPhase- + // with MSVC CLI) if using C++20. So we match the behavior with MSVC here to + // not enable -fdelayed-template-parsing by default after C++20. + // + // FIXME: Given -fdelayed-template-parsing is a source of bugs, we should be + // able to disable this by default at some point. + if (Args.hasFlag(options::OPT_fdelayed_template_parsing, + options::OPT_fno_delayed_template_parsing, + IsWindowsMSVC && !HaveCxx20)) { + if (HaveCxx20) + D.Diag(clang::diag::warn_drv_delayed_template_parsing_after_cxx20); - // FIXME: Find a better way to determine whether the language has modules - // support by default, or just assume that all languages do. - bool HaveModules = - Std && (Std->containsValue("c++2a") || Std->containsValue("c++20") || - Std->containsValue("c++latest")); - RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules); + CmdArgs.push_back("-fdelayed-template-parsing"); + } if (Args.hasFlag(options::OPT_fpch_validate_input_files_content, options::OPT_fno_pch_validate_input_files_content, false)) @@ -6213,9 +7026,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("-fmodules-debuginfo"); - Args.AddLastArg(CmdArgs, options::OPT_flegacy_pass_manager, - options::OPT_fno_legacy_pass_manager); - ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, Inputs, CmdArgs, rewriteKind); RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None, Input, CmdArgs); @@ -6266,22 +7076,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // C++ "sane" operator new. - if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, - options::OPT_fno_assume_sane_operator_new)) - CmdArgs.push_back("-fno-assume-sane-operator-new"); + Args.addOptOutFlag(CmdArgs, options::OPT_fassume_sane_operator_new, + options::OPT_fno_assume_sane_operator_new); + + // -fassume-unique-vtables is on by default. + Args.addOptOutFlag(CmdArgs, options::OPT_fassume_unique_vtables, + options::OPT_fno_assume_unique_vtables); // -frelaxed-template-template-args is off by default, as it is a severe // breaking change until a corresponding change to template partial ordering // is provided. - if (Args.hasFlag(options::OPT_frelaxed_template_template_args, - options::OPT_fno_relaxed_template_template_args, false)) - CmdArgs.push_back("-frelaxed-template-template-args"); + Args.addOptInFlag(CmdArgs, options::OPT_frelaxed_template_template_args, + options::OPT_fno_relaxed_template_template_args); // -fsized-deallocation is off by default, as it is an ABI-breaking change for // most platforms. - if (Args.hasFlag(options::OPT_fsized_deallocation, - options::OPT_fno_sized_deallocation, false)) - CmdArgs.push_back("-fsized-deallocation"); + Args.addOptInFlag(CmdArgs, options::OPT_fsized_deallocation, + options::OPT_fno_sized_deallocation); // -faligned-allocation is on by default in C++17 onwards and otherwise off // by default. @@ -6304,15 +7115,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fconstant-cfstrings is default, and may be subject to argument translation // on Darwin. if (!Args.hasFlag(options::OPT_fconstant_cfstrings, - options::OPT_fno_constant_cfstrings) || + options::OPT_fno_constant_cfstrings, true) || !Args.hasFlag(options::OPT_mconstant_cfstrings, - options::OPT_mno_constant_cfstrings)) + options::OPT_mno_constant_cfstrings, true)) CmdArgs.push_back("-fno-constant-cfstrings"); - // -fno-pascal-strings is default, only pass non-default. - if (Args.hasFlag(options::OPT_fpascal_strings, - options::OPT_fno_pascal_strings, false)) - CmdArgs.push_back("-fpascal-strings"); + Args.addOptInFlag(CmdArgs, options::OPT_fpascal_strings, + options::OPT_fno_pascal_strings); // Honor -fpack-struct= and -fpack-struct, if given. Note that // -fno-pack-struct doesn't apply to -fpack-struct=. @@ -6344,18 +7153,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-Qn"); // -fno-common is the default, set -fcommon only when that flag is set. - if (Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, false)) - CmdArgs.push_back("-fcommon"); + Args.addOptInFlag(CmdArgs, options::OPT_fcommon, options::OPT_fno_common); // -fsigned-bitfields is default, and clang doesn't yet support // -funsigned-bitfields. if (!Args.hasFlag(options::OPT_fsigned_bitfields, - options::OPT_funsigned_bitfields)) + options::OPT_funsigned_bitfields, true)) D.Diag(diag::warn_drv_clang_unsupported) << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args); // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope. - if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope)) + if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope, true)) D.Diag(diag::err_drv_clang_unsupported) << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args); @@ -6377,15 +7185,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderDiagnosticsOptions(D, Args, CmdArgs); - // -fno-asm-blocks is default. - if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, - false)) - CmdArgs.push_back("-fasm-blocks"); + Args.addOptInFlag(CmdArgs, options::OPT_fasm_blocks, + options::OPT_fno_asm_blocks); - // -fgnu-inline-asm is default. - if (!Args.hasFlag(options::OPT_fgnu_inline_asm, - options::OPT_fno_gnu_inline_asm, true)) - CmdArgs.push_back("-fno-gnu-inline-asm"); + Args.addOptOutFlag(CmdArgs, options::OPT_fgnu_inline_asm, + options::OPT_fno_gnu_inline_asm); // Enable vectorization per default according to the optimization level // selected. For optimization levels that want vectorization we use the alias @@ -6421,21 +7225,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-dollars-in-identifiers"); } - // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for - // practical purposes. - if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, - options::OPT_fno_unit_at_a_time)) { - if (A->getOption().matches(options::OPT_fno_unit_at_a_time)) - D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args); - } - - if (Args.hasFlag(options::OPT_fapple_pragma_pack, - options::OPT_fno_apple_pragma_pack, false)) - CmdArgs.push_back("-fapple-pragma-pack"); - - if (Args.hasFlag(options::OPT_fxl_pragma_pack, - options::OPT_fno_xl_pragma_pack, RawTriple.isOSAIX())) - CmdArgs.push_back("-fxl-pragma-pack"); + Args.addOptInFlag(CmdArgs, options::OPT_fapple_pragma_pack, + options::OPT_fno_apple_pragma_pack); // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. if (willEmitRemarks(Args) && checkRemarksOptions(D, Args, Triple)) @@ -6446,6 +7237,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (RewriteImports) CmdArgs.push_back("-frewrite-imports"); + Args.addOptInFlag(CmdArgs, options::OPT_fdirectives_only, + options::OPT_fno_directives_only); + // Enable rewrite includes if the user's asked for it or if we're generating // diagnostics. // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be @@ -6466,6 +7260,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_dM); Args.AddLastArg(CmdArgs, options::OPT_dD); + Args.AddLastArg(CmdArgs, options::OPT_dI); Args.AddLastArg(CmdArgs, options::OPT_fmax_tokens_EQ); @@ -6490,6 +7285,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } + // Turn -fplugin-arg-pluginname-key=value into + // -plugin-arg-pluginname key=value + // GCC has an actual plugin_argument struct with key/value pairs that it + // passes to its plugins, but we don't, so just pass it on as-is. + // + // The syntax for -fplugin-arg- is ambiguous if both plugin name and + // argument key are allowed to contain dashes. GCC therefore only + // allows dashes in the key. We do the same. + for (const Arg *A : Args.filtered(options::OPT_fplugin_arg)) { + auto ArgValue = StringRef(A->getValue()); + auto FirstDashIndex = ArgValue.find('-'); + StringRef PluginName = ArgValue.substr(0, FirstDashIndex); + StringRef Arg = ArgValue.substr(FirstDashIndex + 1); + + A->claim(); + if (FirstDashIndex == StringRef::npos || Arg.empty()) { + if (PluginName.empty()) { + D.Diag(diag::warn_drv_missing_plugin_name) << A->getAsString(Args); + } else { + D.Diag(diag::warn_drv_missing_plugin_arg) + << PluginName << A->getAsString(Args); + } + continue; + } + + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-arg-") + PluginName)); + CmdArgs.push_back(Args.MakeArgString(Arg)); + } + // Forward -fpass-plugin=name.so to -cc1. for (const Arg *A : Args.filtered(options::OPT_fpass_plugin_EQ)) { CmdArgs.push_back( @@ -6497,25 +7321,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } + // Forward --vfsoverlay to -cc1. + for (const Arg *A : Args.filtered(options::OPT_vfsoverlay)) { + CmdArgs.push_back("--vfsoverlay"); + CmdArgs.push_back(A->getValue()); + A->claim(); + } + + Args.addOptInFlag(CmdArgs, options::OPT_fsafe_buffer_usage_suggestions, + options::OPT_fno_safe_buffer_usage_suggestions); + // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); - if (!StatsFile.empty()) + if (!StatsFile.empty()) { CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile)); + if (D.CCPrintInternalStats) + CmdArgs.push_back("-stats-file-append"); + } // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. - // -finclude-default-header flag is for preprocessor, - // do not pass it to other cc1 commands when save-temps is enabled - if (C.getDriver().isSaveTempsEnabled() && - !isa<PreprocessJobAction>(JA)) { - for (auto Arg : Args.filtered(options::OPT_Xclang)) { - Arg->claim(); - if (StringRef(Arg->getValue()) != "-finclude-default-header") - CmdArgs.push_back(Arg->getValue()); + for (auto Arg : Args.filtered(options::OPT_Xclang)) { + Arg->claim(); + // -finclude-default-header flag is for preprocessor, + // do not pass it to other cc1 commands when save-temps is enabled + if (C.getDriver().isSaveTempsEnabled() && + !isa<PreprocessJobAction>(JA)) { + if (StringRef(Arg->getValue()) == "-finclude-default-header") + continue; } - } - else { - Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); + CmdArgs.push_back(Arg->getValue()); } for (const Arg *A : Args.filtered(options::OPT_mllvm)) { A->claim(); @@ -6559,7 +7394,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, auto FRecordSwitches = Args.hasFlag(options::OPT_frecord_command_line, options::OPT_fno_record_command_line, false); - if (FRecordSwitches && !Triple.isOSBinFormatELF()) + if (FRecordSwitches && !Triple.isOSBinFormatELF() && + !Triple.isOSBinFormatXCOFF() && !Triple.isOSBinFormatMachO()) D.Diag(diag::err_drv_unsupported_opt_for_target) << Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args) << TripleStr; @@ -6587,13 +7423,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - // Host-side cuda compilation receives all device-side outputs in a single - // fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary. + // Host-side offloading compilation receives all device-side outputs. Include + // them in the host compilation depending on the target. If the host inputs + // are not empty we use the new-driver scheme, otherwise use the old scheme. if ((IsCuda || IsHIP) && CudaDeviceInput) { + CmdArgs.push_back("-fcuda-include-gpubinary"); + CmdArgs.push_back(CudaDeviceInput->getFilename()); + } else if (!HostOffloadingInputs.empty()) { + if ((IsCuda || IsHIP) && !IsRDCMode) { + assert(HostOffloadingInputs.size() == 1 && "Only one input expected"); CmdArgs.push_back("-fcuda-include-gpubinary"); - CmdArgs.push_back(CudaDeviceInput->getFilename()); - if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) - CmdArgs.push_back("-fgpu-rdc"); + CmdArgs.push_back(HostOffloadingInputs.front().getFilename()); + } else { + for (const InputInfo Input : HostOffloadingInputs) + CmdArgs.push_back(Args.MakeArgString("-fembed-offload-object=" + + TC.getInputFilename(Input))); + } } if (IsCuda) { @@ -6612,10 +7457,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, auto CUID = cast<InputAction>(SourceAction)->getId(); if (!CUID.empty()) CmdArgs.push_back(Args.MakeArgString(Twine("-cuid=") + Twine(CUID))); + + // -ffast-math turns on -fgpu-approx-transcendentals implicitly, but will + // be overriden by -fno-gpu-approx-transcendentals. + bool UseApproxTranscendentals = Args.hasFlag( + options::OPT_ffast_math, options::OPT_fno_fast_math, false); + if (Args.hasFlag(options::OPT_fgpu_approx_transcendentals, + options::OPT_fno_gpu_approx_transcendentals, + UseApproxTranscendentals)) + CmdArgs.push_back("-fgpu-approx-transcendentals"); + } else { + Args.claimAllArgs(options::OPT_fgpu_approx_transcendentals, + options::OPT_fno_gpu_approx_transcendentals); } - if (IsHIP) + if (IsHIP) { CmdArgs.push_back("-fcuda-allow-variadic-functions"); + Args.AddLastArg(CmdArgs, options::OPT_fgpu_default_stream_EQ); + } + + Args.AddLastArg(CmdArgs, options::OPT_foffload_uniform_block, + options::OPT_fno_offload_uniform_block); + + Args.AddLastArg(CmdArgs, options::OPT_foffload_implicit_host_device_templates, + options::OPT_fno_offload_implicit_host_device_templates); if (IsCudaDevice || IsHIPDevice) { StringRef InlineThresh = @@ -6627,13 +7492,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (IsHIPDevice) + Args.addOptOutFlag(CmdArgs, + options::OPT_fhip_fp32_correctly_rounded_divide_sqrt, + options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt); + // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path // to specify the result of the compile phase on the host, so the meaningful - // device declarations can be identified. Also, -fopenmp-is-device is passed - // along to tell the frontend that it is generating code for a device, so that - // only the relevant declarations are emitted. + // device declarations can be identified. Also, -fopenmp-is-target-device is + // passed along to tell the frontend that it is generating code for a device, + // so that only the relevant declarations are emitted. if (IsOpenMPDevice) { - CmdArgs.push_back("-fopenmp-is-device"); + CmdArgs.push_back("-fopenmp-is-target-device"); if (OpenMPDeviceInput) { CmdArgs.push_back("-fopenmp-host-ir-file-path"); CmdArgs.push_back(Args.MakeArgString(OpenMPDeviceInput->getFilename())); @@ -6643,28 +7513,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Triple.isAMDGPU()) { handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs); - if (Args.hasFlag(options::OPT_munsafe_fp_atomics, - options::OPT_mno_unsafe_fp_atomics, /*Default=*/false)) - CmdArgs.push_back("-munsafe-fp-atomics"); + Args.addOptInFlag(CmdArgs, options::OPT_munsafe_fp_atomics, + options::OPT_mno_unsafe_fp_atomics); + Args.addOptOutFlag(CmdArgs, options::OPT_mamdgpu_ieee, + options::OPT_mno_amdgpu_ieee); } // For all the host OpenMP offloading compile jobs we need to pass the targets // information using -fopenmp-targets= option. if (JA.isHostOffloading(Action::OFK_OpenMP)) { - SmallString<128> TargetInfo("-fopenmp-targets="); + SmallString<128> Targets("-fopenmp-targets="); - Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ); - assert(Tgts && Tgts->getNumValues() && - "OpenMP offloading has to have targets specified."); - for (unsigned i = 0; i < Tgts->getNumValues(); ++i) { - if (i) - TargetInfo += ','; - // We need to get the string from the triple because it may be not exactly - // the same as the one we get directly from the arguments. - llvm::Triple T(Tgts->getValue(i)); - TargetInfo += T.getTriple(); - } - CmdArgs.push_back(Args.MakeArgString(TargetInfo.str())); + SmallVector<std::string, 4> Triples; + auto TCRange = C.getOffloadToolChains<Action::OFK_OpenMP>(); + std::transform(TCRange.first, TCRange.second, std::back_inserter(Triples), + [](auto TC) { return TC.second->getTripleString(); }); + CmdArgs.push_back(Args.MakeArgString(Targets + llvm::join(Triples, ","))); } bool VirtualFunctionElimination = @@ -6692,31 +7556,55 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (WholeProgramVTables) { - // Propagate -fwhole-program-vtables if this is an LTO compile. - if (IsUsingLTO) - CmdArgs.push_back("-fwhole-program-vtables"); + // PS4 uses the legacy LTO API, which does not support this feature in + // ThinLTO mode. + bool IsPS4 = getToolChain().getTriple().isPS4(); + // Check if we passed LTO options but they were suppressed because this is a // device offloading action, or we passed device offload LTO options which // were suppressed because this is not the device offload action. + // Check if we are using PS4 in regular LTO mode. // Otherwise, issue an error. - else if (!D.isUsingLTO(!IsDeviceOffloadAction)) + if ((!IsUsingLTO && !D.isUsingLTO(!IsDeviceOffloadAction)) || + (IsPS4 && !UnifiedLTO && (D.getLTOMode() != LTOK_Full))) D.Diag(diag::err_drv_argument_only_allowed_with) << "-fwhole-program-vtables" - << "-flto"; + << ((IsPS4 && !UnifiedLTO) ? "-flto=full" : "-flto"); + + // Propagate -fwhole-program-vtables if this is an LTO compile. + if (IsUsingLTO) + CmdArgs.push_back("-fwhole-program-vtables"); } bool DefaultsSplitLTOUnit = - (WholeProgramVTables || Sanitize.needsLTO()) && - (LTOMode == LTOK_Full || TC.canSplitThinLTOUnit()); + ((WholeProgramVTables || SanitizeArgs.needsLTO()) && + (LTOMode == LTOK_Full || TC.canSplitThinLTOUnit())) || + (!Triple.isPS4() && UnifiedLTO); bool SplitLTOUnit = Args.hasFlag(options::OPT_fsplit_lto_unit, options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit); - if (Sanitize.needsLTO() && !SplitLTOUnit) + if (SanitizeArgs.needsLTO() && !SplitLTOUnit) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fno-split-lto-unit" << "-fsanitize=cfi"; if (SplitLTOUnit) CmdArgs.push_back("-fsplit-lto-unit"); + if (Arg *A = Args.getLastArg(options::OPT_ffat_lto_objects, + options::OPT_fno_fat_lto_objects)) { + if (IsUsingLTO && A->getOption().matches(options::OPT_ffat_lto_objects)) { + assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); + if (!Triple.isOSBinFormatELF()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TC.getTripleString(); + } + CmdArgs.push_back(Args.MakeArgString( + Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); + CmdArgs.push_back("-flto-unit"); + CmdArgs.push_back("-ffat-lto-objects"); + A->render(Args, CmdArgs); + } + } + if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel, options::OPT_fno_global_isel)) { CmdArgs.push_back("-mllvm"); @@ -6765,34 +7653,31 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fforce-enable-int128"); } - if (Args.hasFlag(options::OPT_fkeep_static_consts, - options::OPT_fno_keep_static_consts, false)) - CmdArgs.push_back("-fkeep-static-consts"); - - if (Args.hasFlag(options::OPT_fcomplete_member_pointers, - options::OPT_fno_complete_member_pointers, false)) - CmdArgs.push_back("-fcomplete-member-pointers"); - - if (!Args.hasFlag(options::OPT_fcxx_static_destructors, - options::OPT_fno_cxx_static_destructors, true)) - CmdArgs.push_back("-fno-c++-static-destructors"); + Args.addOptInFlag(CmdArgs, options::OPT_fkeep_static_consts, + options::OPT_fno_keep_static_consts); + Args.addOptInFlag(CmdArgs, options::OPT_fkeep_persistent_storage_variables, + options::OPT_fno_keep_persistent_storage_variables); + Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers, + options::OPT_fno_complete_member_pointers); + Args.addOptOutFlag(CmdArgs, options::OPT_fcxx_static_destructors, + options::OPT_fno_cxx_static_destructors); addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false); if (Arg *A = Args.getLastArg(options::OPT_moutline_atomics, options::OPT_mno_outline_atomics)) { - if (A->getOption().matches(options::OPT_moutline_atomics)) { - // Option -moutline-atomics supported for AArch64 target only. - if (!Triple.isAArch64()) { - D.Diag(diag::warn_drv_moutline_atomics_unsupported_opt) - << Triple.getArchName(); - } else { + // Option -moutline-atomics supported for AArch64 target only. + if (!Triple.isAArch64()) { + D.Diag(diag::warn_drv_moutline_atomics_unsupported_opt) + << Triple.getArchName() << A->getOption().getName(); + } else { + if (A->getOption().matches(options::OPT_moutline_atomics)) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+outline-atomics"); + } else { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-outline-atomics"); } - } else { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-outline-atomics"); } } else if (Triple.isAArch64() && getToolChain().IsAArch64OutlineAtomicsDefault(Args)) { @@ -6800,6 +7685,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("+outline-atomics"); } + if (Triple.isAArch64() && + (Args.hasArg(options::OPT_mno_fmv) || + (Triple.isAndroid() && Triple.isAndroidVersionLT(23)) || + getToolChain().GetRuntimeLibType(Args) != ToolChain::RLT_CompilerRT)) { + // Disable Function Multiversioning on AArch64 target. + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-fmv"); + } + if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig, (TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSBinFormatCOFF()) && @@ -6810,7 +7704,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-faddrsig"); if ((Triple.isOSBinFormatELF() || Triple.isOSBinFormatMachO()) && - (EH || UnwindTables || DebugInfoKind != codegenoptions::NoDebugInfo)) + (EH || UnwindTables || AsyncUnwindTables || + DebugInfoKind != llvm::codegenoptions::NoDebugInfo)) CmdArgs.push_back("-D__GCC_HAVE_DWARF2_CFI_ASM=1"); if (Arg *A = Args.getLastArg(options::OPT_fsymbol_partition_EQ)) { @@ -6843,8 +7738,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, addDashXForInput(Args, Input, CmdArgs); ArrayRef<InputInfo> FrontendInputs = Input; - if (IsHeaderModulePrecompile) - FrontendInputs = ModuleHeaderInputs; + if (IsExtractAPI) + FrontendInputs = ExtractAPIInputs; else if (Input.isNothing()) FrontendInputs = {}; @@ -6857,13 +7752,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (D.CC1Main && !D.CCGenDiagnostics) { // Invoke the CC1 directly in this process - C.addCommand(std::make_unique<CC1Command>(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<CC1Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getPrependArg())); } else { - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getPrependArg())); } // Make the compile command echo its inputs for /showFilenames. @@ -6894,11 +7789,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_emit_llvm); } -Clang::Clang(const ToolChain &TC) +Clang::Clang(const ToolChain &TC, bool HasIntegratedBackend) // CAUTION! The first constructor argument ("clang") is not arbitrary, // as it is for other tools. Some operations on a Tool actually test // whether that tool is Clang based on the Tool's Name as a string. - : Tool("clang", "clang frontend", TC) {} + : Tool("clang", "clang frontend", TC), HasBackend(HasIntegratedBackend) {} Clang::~Clang() {} @@ -7096,66 +7991,20 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { EH.NoUnwindC = true; } + if (Args.hasArg(options::OPT__SLASH_kernel)) { + EH.Synch = false; + EH.NoUnwindC = false; + EH.Asynch = false; + } + return EH; } void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, - ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind *DebugInfoKind, - bool *EmitCodeView) const { - unsigned RTOptionID = options::OPT__SLASH_MT; + ArgStringList &CmdArgs) const { bool isNVPTX = getToolChain().getTriple().isNVPTX(); - if (Args.hasArg(options::OPT__SLASH_LDd)) - // The /LDd option implies /MTd. The dependent lib part can be overridden, - // but defining _DEBUG is sticky. - RTOptionID = options::OPT__SLASH_MTd; - - if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) - RTOptionID = A->getOption().getID(); - - StringRef FlagForCRT; - switch (RTOptionID) { - case options::OPT__SLASH_MD: - if (Args.hasArg(options::OPT__SLASH_LDd)) - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-D_DLL"); - FlagForCRT = "--dependent-lib=msvcrt"; - break; - case options::OPT__SLASH_MDd: - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-D_DLL"); - FlagForCRT = "--dependent-lib=msvcrtd"; - break; - case options::OPT__SLASH_MT: - if (Args.hasArg(options::OPT__SLASH_LDd)) - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-flto-visibility-public-std"); - FlagForCRT = "--dependent-lib=libcmt"; - break; - case options::OPT__SLASH_MTd: - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-flto-visibility-public-std"); - FlagForCRT = "--dependent-lib=libcmtd"; - break; - default: - llvm_unreachable("Unexpected option ID."); - } - - if (Args.hasArg(options::OPT__SLASH_Zl)) { - CmdArgs.push_back("-D_VC_NODEFAULTLIB"); - } else { - CmdArgs.push_back(FlagForCRT.data()); - - // This provides POSIX compatibility (maps 'open' to '_open'), which most - // users want. The /Za flag to cl.exe turns this off, but it's not - // implemented in clang. - CmdArgs.push_back("--dependent-lib=oldnames"); - } + ProcessVSRuntimeLibrary(Args, CmdArgs); if (Arg *ShowIncludes = Args.getLastArg(options::OPT__SLASH_showIncludes, @@ -7178,24 +8027,15 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong))); } - // Emit CodeView if -Z7 or -gline-tables-only are present. - if (Arg *DebugInfoArg = Args.getLastArg(options::OPT__SLASH_Z7, - options::OPT_gline_tables_only)) { - *EmitCodeView = true; - if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7)) - *DebugInfoKind = codegenoptions::DebugInfoConstructor; - else - *DebugInfoKind = codegenoptions::DebugLineTablesOnly; - } else { - *EmitCodeView = false; - } - const Driver &D = getToolChain().getDriver(); + EHFlags EH = parseClangCLEHFlags(D, Args); if (!isNVPTX && (EH.Synch || EH.Asynch)) { if (types::isCXX(InputType)) CmdArgs.push_back("-fcxx-exceptions"); CmdArgs.push_back("-fexceptions"); + if (EH.Asynch) + CmdArgs.push_back("-fasync-exceptions"); } if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC) CmdArgs.push_back("-fexternc-nounwind"); @@ -7206,24 +8046,38 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-P"); } - unsigned VolatileOptionID; - if (getToolChain().getTriple().isX86()) - VolatileOptionID = options::OPT__SLASH_volatile_ms; - else - VolatileOptionID = options::OPT__SLASH_volatile_iso; - - if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group)) - VolatileOptionID = A->getOption().getID(); - - if (VolatileOptionID == options::OPT__SLASH_volatile_ms) - CmdArgs.push_back("-fms-volatile"); - if (Args.hasFlag(options::OPT__SLASH_Zc_dllexportInlines_, options::OPT__SLASH_Zc_dllexportInlines, false)) { CmdArgs.push_back("-fno-dllexport-inlines"); } + if (Args.hasFlag(options::OPT__SLASH_Zc_wchar_t_, + options::OPT__SLASH_Zc_wchar_t, false)) { + CmdArgs.push_back("-fno-wchar"); + } + + if (Args.hasArg(options::OPT__SLASH_kernel)) { + llvm::Triple::ArchType Arch = getToolChain().getArch(); + std::vector<std::string> Values = + Args.getAllArgValues(options::OPT__SLASH_arch); + if (!Values.empty()) { + llvm::SmallSet<std::string, 4> SupportedArches; + if (Arch == llvm::Triple::x86) + SupportedArches.insert("IA32"); + + for (auto &V : Values) + if (!SupportedArches.contains(V)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << std::string("/arch:").append(V) << "/kernel"; + } + + CmdArgs.push_back("-fno-rtti"); + if (Args.hasFlag(options::OPT__SLASH_GR, options::OPT__SLASH_GR_, false)) + D.Diag(diag::err_drv_argument_not_allowed_with) << "/GR" + << "/kernel"; + } + Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg); Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb); if (MostGeneralArg && BestCaseArg) @@ -7250,6 +8104,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-fms-memptr-rep=virtual"); } + if (Args.hasArg(options::OPT_regcall4)) + CmdArgs.push_back("-regcall4"); + // Parse the default calling convention options. if (Arg *CCArg = Args.getLastArg(options::OPT__SLASH_Gd, options::OPT__SLASH_Gr, @@ -7286,6 +8143,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back(DCCFlag); } + if (Args.hasArg(options::OPT__SLASH_Gregcall4)) + CmdArgs.push_back("-regcall4"); + Args.AddLastArg(CmdArgs, options::OPT_vtordisp_mode_EQ); if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) { @@ -7293,7 +8153,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("msvc"); } - if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { + if (Args.hasArg(options::OPT__SLASH_kernel)) + CmdArgs.push_back("-fms-kernel"); + + for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) { StringRef GuardArgs = A->getValue(); // The only valid options are "cf", "cf,nochecks", "cf-", "ehcont" and // "ehcont-". @@ -7312,6 +8175,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, } else { D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << GuardArgs; } + A->claim(); } } @@ -7368,11 +8232,19 @@ void ClangAs::AddX86TargetArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); } else { getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } +void ClangAs::AddLoongArchTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(loongarch::getLoongArchABI(getToolChain().getDriver(), Args, + getToolChain().getTriple()) + .data()); +} + void ClangAs::AddRISCVTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const llvm::Triple &Triple = getToolChain().getTriple(); @@ -7380,6 +8252,12 @@ void ClangAs::AddRISCVTargetArgs(const ArgList &Args, CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName.data()); + + if (Args.hasFlag(options::OPT_mdefault_build_attributes, + options::OPT_mno_default_build_attributes, true)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-riscv-add-build-attributes"); + } } void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, @@ -7411,6 +8289,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-triple"); CmdArgs.push_back(Args.MakeArgString(TripleStr)); + getToolChain().addClangCC1ASTargetOptions(Args, CmdArgs); + // Set the output mode, we currently only expect to be used as a real // assembler. CmdArgs.push_back("-filetype"); @@ -7422,7 +8302,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Clang::getBaseInputName(Args, Input)); // Add the target cpu - std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true); + std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ true); if (!CPU.empty()) { CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(Args.MakeArgString(CPU)); @@ -7438,11 +8318,14 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_I_Group); // Determine the original source input. - const Action *SourceAction = &JA; - while (SourceAction->getKind() != Action::InputClass) { - assert(!SourceAction->getInputs().empty() && "unexpected root action!"); - SourceAction = SourceAction->getInputs()[0]; - } + auto FindSource = [](const Action *S) -> const Action * { + while (S->getKind() != Action::InputClass) { + assert(!S->getInputs().empty() && "unexpected root action!"); + S = S->getInputs()[0]; + } + return S; + }; + const Action *SourceAction = FindSource(&JA); // Forward -g and handle debug info related flags, assuming we are dealing // with an actual assembly file. @@ -7452,14 +8335,12 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, WantDebug = !A->getOption().matches(options::OPT_g0) && !A->getOption().matches(options::OPT_ggdb0); - unsigned DwarfVersion = ParseDebugDefaultVersion(getToolChain(), Args); - if (const Arg *GDwarfN = getDwarfNArg(Args)) - DwarfVersion = DwarfVersionNum(GDwarfN->getSpelling()); + llvm::codegenoptions::DebugInfoKind DebugInfoKind = + llvm::codegenoptions::NoDebugInfo; - if (DwarfVersion == 0) - DwarfVersion = getToolChain().GetDefaultDwarfVersion(); - - codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; + // Add the -fdebug-compilation-dir flag if needed. + const char *DebugCompilationDir = + addDebugCompDirArg(Args, CmdArgs, C.getDriver().getVFS()); if (SourceAction->getType() == types::TY_Asm || SourceAction->getType() == types::TY_PP_Asm) { @@ -7467,12 +8348,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // the guard for source type, however there is a test which asserts // that some assembler invocation receives no -debug-info-kind, // and it's not clear whether that test is just overly restrictive. - DebugInfoKind = (WantDebug ? codegenoptions::DebugInfoConstructor - : codegenoptions::NoDebugInfo); - // Add the -fdebug-compilation-dir flag if needed. - addDebugCompDirArg(Args, CmdArgs, C.getDriver().getVFS()); + DebugInfoKind = (WantDebug ? llvm::codegenoptions::DebugInfoConstructor + : llvm::codegenoptions::NoDebugInfo); - addDebugPrefixMapArg(getToolChain().getDriver(), Args, CmdArgs); + addDebugPrefixMapArg(getToolChain().getDriver(), getToolChain(), Args, + CmdArgs); // Set the AT_producer to the clang version when using the integrated // assembler on assembly source files. @@ -7482,12 +8362,12 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // And pass along -I options Args.AddAllArgs(CmdArgs, options::OPT_I); } + const unsigned DwarfVersion = getDwarfVersion(getToolChain(), Args); RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, llvm::DebuggerKind::Default); renderDwarfFormat(D, Triple, Args, CmdArgs, DwarfVersion); RenderDebugInfoCompressionArgs(Args, CmdArgs, D, getToolChain()); - // Handle -fPIC et al -- the relocation-model affects the assembler // for some targets. llvm::Reloc::Model RelocationModel; @@ -7563,6 +8443,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, } break; + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + AddLoongArchTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::riscv32: case llvm::Triple::riscv64: AddRISCVTargetArgs(Args, CmdArgs); @@ -7581,6 +8466,29 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_mllvm); + if (DebugInfoKind > llvm::codegenoptions::NoDebugInfo && Output.isFilename()) + addDebugObjectName(Args, CmdArgs, DebugCompilationDir, + Output.getFilename()); + + // Fixup any previous commands that use -object-file-name because when we + // generated them, the final .obj name wasn't yet known. + for (Command &J : C.getJobs()) { + if (SourceAction != FindSource(&J.getSource())) + continue; + auto &JArgs = J.getArguments(); + for (unsigned I = 0; I < JArgs.size(); ++I) { + if (StringRef(JArgs[I]).starts_with("-object-file-name=") && + Output.isFilename()) { + ArgStringList NewArgs(JArgs.begin(), JArgs.begin() + I); + addDebugObjectName(Args, NewArgs, DebugCompilationDir, + Output.getFilename()); + NewArgs.append(JArgs.begin() + I + 1, JArgs.end()); + J.replaceArguments(NewArgs); + break; + } + } + } + assert(Output.isFilename() && "Unexpected lipo output."); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -7594,7 +8502,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, } if (Triple.isAMDGPU()) - handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs); + handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs, /*IsCC1As=*/true); assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); @@ -7602,13 +8510,13 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = getToolChain().getDriver().getClangProgramPath(); if (D.CC1Main && !D.CCGenDiagnostics) { // Invoke cc1as directly in this process. - C.addCommand(std::make_unique<CC1Command>(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<CC1Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getPrependArg())); } else { - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileUTF8(), - Exec, CmdArgs, Inputs, Output)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + Output, D.getPrependArg())); } } @@ -7625,8 +8533,10 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, // The bundling command looks like this: // clang-offload-bundler -type=bc // -targets=host-triple,openmp-triple1,openmp-triple2 - // -outputs=input_file - // -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + // -output=output_file + // -input=unbundle_file_host + // -input=unbundle_file_tgt1 + // -input=unbundle_file_tgt2 ArgStringList CmdArgs; @@ -7658,31 +8568,41 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, }); } Triples += Action::GetOffloadKindName(CurKind); - Triples += "-"; - std::string NormalizedTriple = CurTC->getTriple().normalize(); - Triples += NormalizedTriple; - - if (CurDep->getOffloadingArch() != nullptr) { - // If OffloadArch is present it can only appear as the 6th hypen - // sepearated field of Bundle Entry ID. So, pad required number of - // hyphens in Triple. - for (int i = 4 - StringRef(NormalizedTriple).count("-"); i > 0; i--) - Triples += "-"; + Triples += '-'; + Triples += CurTC->getTriple().normalize(); + if ((CurKind == Action::OFK_HIP || CurKind == Action::OFK_Cuda) && + !StringRef(CurDep->getOffloadingArch()).empty()) { + Triples += '-'; Triples += CurDep->getOffloadingArch(); } + + // TODO: Replace parsing of -march flag. Can be done by storing GPUArch + // with each toolchain. + StringRef GPUArchName; + if (CurKind == Action::OFK_OpenMP) { + // Extract GPUArch from -march argument in TC argument list. + for (unsigned ArgIndex = 0; ArgIndex < TCArgs.size(); ArgIndex++) { + auto ArchStr = StringRef(TCArgs.getArgString(ArgIndex)); + auto Arch = ArchStr.starts_with_insensitive("-march="); + if (Arch) { + GPUArchName = ArchStr.substr(7); + Triples += "-"; + break; + } + } + Triples += GPUArchName.str(); + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); // 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(); @@ -7697,14 +8617,18 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, } else { UB += CurTC->getInputFilename(Inputs[I]); } + CmdArgs.push_back(TCArgs.MakeArgString(UB)); } - CmdArgs.push_back(TCArgs.MakeArgString(UB)); - + if (TCArgs.hasFlag(options::OPT_offload_compress, + options::OPT_no_offload_compress, false)) + CmdArgs.push_back("-compress"); + if (TCArgs.hasArg(options::OPT_v)) + CmdArgs.push_back("-verbose"); // All the inputs are encoded as commands. C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::None(), TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), - CmdArgs, None, Output)); + CmdArgs, std::nullopt, Output)); } void OffloadBundler::ConstructJobMultipleOutputs( @@ -7717,8 +8641,10 @@ void OffloadBundler::ConstructJobMultipleOutputs( // The unbundling command looks like this: // clang-offload-bundler -type=bc // -targets=host-triple,openmp-triple1,openmp-triple2 - // -inputs=input_file - // -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + // -input=input_file + // -output=unbundle_file_host + // -output=unbundle_file_tgt1 + // -output=unbundle_file_tgt2 // -unbundle ArgStringList CmdArgs; @@ -7740,68 +8666,112 @@ void OffloadBundler::ConstructJobMultipleOutputs( auto &Dep = DepInfo[I]; Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); - Triples += "-"; - std::string NormalizedTriple = - Dep.DependentToolChain->getTriple().normalize(); - Triples += NormalizedTriple; - - if (!Dep.DependentBoundArch.empty()) { - // If OffloadArch is present it can only appear as the 6th hypen - // sepearated field of Bundle Entry ID. So, pad required number of - // hyphens in Triple. - for (int i = 4 - StringRef(NormalizedTriple).count("-"); i > 0; i--) - Triples += "-"; + Triples += '-'; + Triples += Dep.DependentToolChain->getTriple().normalize(); + if ((Dep.DependentOffloadKind == Action::OFK_HIP || + Dep.DependentOffloadKind == Action::OFK_Cuda) && + !Dep.DependentBoundArch.empty()) { + Triples += '-'; Triples += Dep.DependentBoundArch; } + // TODO: Replace parsing of -march flag. Can be done by storing GPUArch + // with each toolchain. + StringRef GPUArchName; + if (Dep.DependentOffloadKind == Action::OFK_OpenMP) { + // Extract GPUArch from -march argument in TC argument list. + for (unsigned ArgIndex = 0; ArgIndex < TCArgs.size(); ArgIndex++) { + StringRef ArchStr = StringRef(TCArgs.getArgString(ArgIndex)); + auto Arch = ArchStr.starts_with_insensitive("-march="); + if (Arch) { + GPUArchName = ArchStr.substr(7); + Triples += "-"; + break; + } + } + Triples += GPUArchName.str(); + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); // Get bundled file command. CmdArgs.push_back( - TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename())); + TCArgs.MakeArgString(Twine("-input=") + Input.getFilename())); // Get unbundled files command. - SmallString<128> UB; - UB += "-outputs="; for (unsigned I = 0; I < Outputs.size(); ++I) { - if (I) - UB += ','; + SmallString<128> UB; + UB += "-output="; UB += DepInfo[I].DependentToolChain->getInputFilename(Outputs[I]); + CmdArgs.push_back(TCArgs.MakeArgString(UB)); } - CmdArgs.push_back(TCArgs.MakeArgString(UB)); CmdArgs.push_back("-unbundle"); CmdArgs.push_back("-allow-missing-bundles"); + if (TCArgs.hasArg(options::OPT_v)) + CmdArgs.push_back("-verbose"); // All the inputs are encoded as commands. C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport::None(), TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), - CmdArgs, None, Outputs)); + CmdArgs, std::nullopt, Outputs)); } -void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; - const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); - - // Add the "effective" target triple. - CmdArgs.push_back("-target"); - CmdArgs.push_back(Args.MakeArgString(Triple.getTriple())); - // Add the output file name. assert(Output.isFilename() && "Invalid output."); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - // Add inputs. - for (const InputInfo &I : Inputs) { - assert(I.isFilename() && "Invalid input."); - CmdArgs.push_back(I.getFilename()); + // Create the inputs to bundle the needed metadata. + for (const InputInfo &Input : Inputs) { + const Action *OffloadAction = Input.getAction(); + const ToolChain *TC = OffloadAction->getOffloadingToolChain(); + const ArgList &TCArgs = + C.getArgsForToolChain(TC, OffloadAction->getOffloadingArch(), + OffloadAction->getOffloadingDeviceKind()); + StringRef File = C.getArgs().MakeArgString(TC->getInputFilename(Input)); + StringRef Arch = OffloadAction->getOffloadingArch() + ? OffloadAction->getOffloadingArch() + : TCArgs.getLastArgValue(options::OPT_march_EQ); + StringRef Kind = + Action::GetOffloadKindName(OffloadAction->getOffloadingDeviceKind()); + + ArgStringList Features; + SmallVector<StringRef> FeatureArgs; + getTargetFeatures(TC->getDriver(), TC->getTriple(), TCArgs, Features, + false); + llvm::copy_if(Features, std::back_inserter(FeatureArgs), + [](StringRef Arg) { return !Arg.starts_with("-target"); }); + + if (TC->getTriple().isAMDGPU()) { + for (StringRef Feature : llvm::split(Arch.split(':').second, ':')) { + FeatureArgs.emplace_back( + Args.MakeArgString(Feature.take_back() + Feature.drop_back())); + } + } + + // TODO: We need to pass in the full target-id and handle it properly in the + // linker wrapper. + SmallVector<std::string> Parts{ + "file=" + File.str(), + "triple=" + TC->getTripleString(), + "arch=" + Arch.str(), + "kind=" + Kind.str(), + }; + + if (TC->getDriver().isUsingLTO(/* IsOffload */ true) || + TC->getTriple().isAMDGPU()) + for (StringRef Feature : FeatureArgs) + Parts.emplace_back("feature=" + Feature.str()); + + CmdArgs.push_back(Args.MakeArgString("--image=" + llvm::join(Parts, ","))); } C.addCommand(std::make_unique<Command>( @@ -7809,3 +8779,125 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA, 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(); + ArgStringList CmdArgs; + + // 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; + 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 optimization level to use for LTO. + if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { + StringRef OOpt; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "3"; + else if (A->getOption().matches(options::OPT_O)) { + OOpt = A->getValue(); + if (OOpt == "g") + OOpt = "1"; + else if (OOpt == "s" || OOpt == "z") + OOpt = "2"; + } else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + if (!OOpt.empty()) + CmdArgs.push_back(Args.MakeArgString(Twine("--opt-level=O") + OOpt)); + } + + CmdArgs.push_back( + Args.MakeArgString("--host-triple=" + TheTriple.getTriple())); + if (Args.hasArg(options::OPT_v)) + CmdArgs.push_back("--wrapper-verbose"); + + if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) { + if (!A->getOption().matches(options::OPT_g0)) + CmdArgs.push_back("--device-debug"); + } + + // code-object-version=X needs to be passed to clang-linker-wrapper to ensure + // that it is used by lld. + if (const Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) { + CmdArgs.push_back(Args.MakeArgString("-mllvm")); + CmdArgs.push_back(Args.MakeArgString( + Twine("--amdhsa-code-object-version=") + A->getValue())); + } + + for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) + CmdArgs.push_back(Args.MakeArgString("--ptxas-arg=" + A)); + + // Forward remarks passes to the LLVM backend in the wrapper. + if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ)) + CmdArgs.push_back(Args.MakeArgString(Twine("--offload-opt=-pass-remarks=") + + A->getValue())); + if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ)) + CmdArgs.push_back(Args.MakeArgString( + Twine("--offload-opt=-pass-remarks-missed=") + A->getValue())); + if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ)) + CmdArgs.push_back(Args.MakeArgString( + Twine("--offload-opt=-pass-remarks-analysis=") + A->getValue())); + 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 (Arg *A : Args.filtered(options::OPT_Xoffload_linker)) { + StringRef Val = A->getValue(0); + if (Val.empty()) + CmdArgs.push_back( + Args.MakeArgString(Twine("--device-linker=") + A->getValue(1))); + else + CmdArgs.push_back(Args.MakeArgString( + "--device-linker=" + + ToolChain::getOpenMPTriple(Val.drop_front()).getTriple() + "=" + + A->getValue(1))); + } + Args.ClaimAllArgs(options::OPT_Xoffload_linker); + + // Embed bitcode instead of an object in JIT mode. + if (Args.hasFlag(options::OPT_fopenmp_target_jit, + options::OPT_fno_openmp_target_jit, false)) + CmdArgs.push_back("--embed-bitcode"); + + // Forward `-mllvm` arguments to the LLVM invocations if present. + for (Arg *A : Args.filtered(options::OPT_mllvm)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(A->getValue()); + A->claim(); + } + + // Add the linker arguments to be forwarded by the wrapper. + CmdArgs.push_back(Args.MakeArgString(Twine("--linker-path=") + + LinkCommand->getExecutable())); + CmdArgs.push_back("--"); + for (const char *LinkArg : LinkCommand->getArguments()) + CmdArgs.push_back(LinkArg); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("clang-linker-wrapper")); + + // Replace the executable and arguments of the link job with the + // wrapper. + LinkCommand->replaceExecutable(Exec); + LinkCommand->replaceArguments(CmdArgs); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h index d4b4988b4a8c..0f503c4bd1c4 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h @@ -6,17 +6,17 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H #include "MSVC.h" -#include "clang/Basic/DebugInfoOptions.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" #include "clang/Driver/Types.h" -#include "llvm/ADT/Triple.h" +#include "llvm/Frontend/Debug/Options.h" #include "llvm/Option/Option.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" namespace clang { class ObjCRuntime; @@ -26,6 +26,10 @@ namespace tools { /// Clang compiler tool. class LLVM_LIBRARY_VISIBILITY Clang : public Tool { + // Indicates whether this instance has integrated backend using + // internal LLVM infrastructure. + bool HasBackend; + public: static const char *getBaseInputName(const llvm::opt::ArgList &Args, const InputInfo &Input); @@ -53,6 +57,8 @@ private: bool KernelOrKext) const; void AddARM64TargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + void AddLoongArchTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; void AddPPCTargetArgs(const llvm::opt::ArgList &Args, @@ -84,9 +90,7 @@ private: RewriteKind rewrite) const; void AddClangCLArgs(const llvm::opt::ArgList &Args, types::ID InputType, - llvm::opt::ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind *DebugInfoKind, - bool *EmitCodeView) const; + llvm::opt::ArgStringList &CmdArgs) const; mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr; void DumpCompilationDatabase(Compilation &C, StringRef Filename, @@ -99,11 +103,12 @@ private: const InputInfo &Input, const llvm::opt::ArgList &Args) const; public: - Clang(const ToolChain &TC); + Clang(const ToolChain &TC, bool HasIntegratedBackend = true); ~Clang() override; bool hasGoodDiagnostics() const override { return true; } bool hasIntegratedAssembler() const override { return true; } + bool hasIntegratedBackend() const override { return HasBackend; } bool hasIntegratedCPP() const override { return true; } bool canEmitIR() const override { return true; } @@ -118,6 +123,8 @@ class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { public: ClangAs(const ToolChain &TC) : Tool("clang::as", "clang integrated assembler", TC) {} + void AddLoongArchTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; void AddX86TargetArgs(const llvm::opt::ArgList &Args, @@ -152,11 +159,11 @@ public: const char *LinkingOutput) const override; }; -/// Offload wrapper tool. -class LLVM_LIBRARY_VISIBILITY OffloadWrapper final : public Tool { +/// Offload binary tool. +class LLVM_LIBRARY_VISIBILITY OffloadPackager final : public Tool { public: - OffloadWrapper(const ToolChain &TC) - : Tool("offload wrapper", "clang-offload-wrapper", TC) {} + OffloadPackager(const ToolChain &TC) + : Tool("Offload::Packager", "clang-offload-packager", TC) {} bool hasIntegratedCPP() const override { return false; } void ConstructJob(Compilation &C, const JobAction &JA, @@ -165,6 +172,27 @@ public: const char *LinkingOutput) const override; }; +/// Linker wrapper tool. +class LLVM_LIBRARY_VISIBILITY LinkerWrapper final : public Tool { + const Tool *Linker; + +public: + LinkerWrapper(const ToolChain &TC, const Tool *Linker) + : Tool("Offload::Linker", "linker", TC), Linker(Linker) {} + + 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; +}; + +enum class DwarfFissionKind { None, Split, Single }; + +DwarfFissionKind getDebugFissionKind(const Driver &D, + const llvm::opt::ArgList &Args, + llvm::opt::Arg *&Arg); + } // end namespace tools } // end namespace driver diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp deleted file mode 100644 index 9ee46ac857f0..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp +++ /dev/null @@ -1,149 +0,0 @@ -//===--- CloudABI.cpp - CloudABI ToolChain Implementations ------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "CloudABI.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/InputInfo.h" -#include "clang/Driver/Options.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Support/Path.h" - -using namespace clang::driver; -using namespace clang::driver::tools; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const ToolChain &ToolChain = getToolChain(); - const Driver &D = ToolChain.getDriver(); - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - // CloudABI only supports static linkage. - CmdArgs.push_back("-Bstatic"); - CmdArgs.push_back("--no-dynamic-linker"); - - // Provide PIE linker flags in case PIE is default for the architecture. - if (ToolChain.isPIEDefault()) { - CmdArgs.push_back("-pie"); - CmdArgs.push_back("-zrelro"); - } - - CmdArgs.push_back("--eh-frame-hdr"); - CmdArgs.push_back("--gc-sections"); - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); - - if (D.isUsingLTO()) { - assert(!Inputs.empty() && "Must have at least one input."); - addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], - D.getLTOMode() == LTOK_Thin); - } - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (ToolChain.ShouldLinkCXXStdlib(Args)) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lcompiler_rt"); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); - - const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -// CloudABI - CloudABI tool chain which can call ld(1) directly. - -CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - SmallString<128> P(getDriver().Dir); - llvm::sys::path::append(P, "..", getTriple().str(), "lib"); - getFilePaths().push_back(std::string(P.str())); -} - -void CloudABI::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - SmallString<128> P(getDriver().Dir); - llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1"); - addSystemInclude(DriverArgs, CC1Args, P.str()); -} - -void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lunwind"); -} - -Tool *CloudABI::buildLinker() const { - return new tools::cloudabi::Linker(*this); -} - -bool CloudABI::isPIEDefault() const { - // Only enable PIE on architectures that support PC-relative - // addressing. PC-relative addressing is required, as the process - // startup code must be able to relocate itself. - switch (getTriple().getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::x86_64: - return true; - default: - return false; - } -} - -SanitizerMask CloudABI::getSupportedSanitizers() const { - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - Res |= SanitizerKind::SafeStack; - return Res; -} - -SanitizerMask CloudABI::getDefaultSanitizers() const { - return SanitizerKind::SafeStack; -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h deleted file mode 100644 index 98bf23127706..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.h +++ /dev/null @@ -1,70 +0,0 @@ -//===--- CloudABI.h - CloudABI ToolChain Implementations --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H - -#include "Gnu.h" -#include "clang/Driver/Tool.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { - -/// cloudabi -- Directly call GNU Binutils linker -namespace cloudabi { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { -public: - Linker(const ToolChain &TC) : Tool("cloudabi::Linker", "linker", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace cloudabi -} // end namespace tools - -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF { -public: - CloudABI(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - bool HasNativeLLVMSupport() const override { return true; } - - bool IsMathErrnoDefault() const override { return false; } - bool IsObjCNonFragileABIDefault() const override { return true; } - - CXXStdlibType - GetCXXStdlibType(const llvm::opt::ArgList &Args) const override { - return ToolChain::CST_Libcxx; - } - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - bool isPIEDefault() const override; - SanitizerMask getSupportedSanitizers() const override; - SanitizerMask getDefaultSanitizers() const override; - -protected: - Tool *buildLinker() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp index 0ffe95795381..2b916f000336 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -9,15 +9,22 @@ #include "CommonArgs.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" +#include "Arch/CSKY.h" +#include "Arch/LoongArch.h" #include "Arch/M68k.h" #include "Arch/Mips.h" #include "Arch/PPC.h" +#include "Arch/RISCV.h" +#include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "Arch/VE.h" #include "Arch/X86.h" -#include "HIP.h" +#include "HIPAMD.h" #include "Hexagon.h" +#include "MSP430.h" +#include "Solaris.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" @@ -34,10 +41,12 @@ #include "clang/Driver/Util.h" #include "clang/Driver/XRayArgs.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Config/llvm-config.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" @@ -47,39 +56,180 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/TargetParser.h" #include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/YAMLParser.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/TargetParser.h" +#include <optional> using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs) { +static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + if (Args.hasArg(clang::driver::options::OPT_pg) && + !Args.hasArg(clang::driver::options::OPT_mfentry)) + return true; + + if (Triple.isAndroid()) { + switch (Triple.getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::riscv64: + return true; + default: + break; + } + } + + switch (Triple.getArch()) { + case llvm::Triple::xcore: + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + case llvm::Triple::msp430: + // XCore never wants frame pointers, regardless of OS. + // WebAssembly never wants frame pointers. + return false; + case llvm::Triple::ppc: + case llvm::Triple::ppcle: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + case llvm::Triple::amdgcn: + case llvm::Triple::r600: + case llvm::Triple::csky: + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + return !clang::driver::tools::areOptimizationsEnabled(Args); + default: + break; + } + + if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) { + return !clang::driver::tools::areOptimizationsEnabled(Args); + } + + if (Triple.isOSLinux() || Triple.isOSHurd()) { + switch (Triple.getArch()) { + // Don't use a frame pointer on linux if optimizing for certain targets. + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::systemz: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return !clang::driver::tools::areOptimizationsEnabled(Args); + default: + return true; + } + } + + if (Triple.isOSWindows()) { + switch (Triple.getArch()) { + case llvm::Triple::x86: + return !clang::driver::tools::areOptimizationsEnabled(Args); + case llvm::Triple::x86_64: + return Triple.isOSBinFormatMachO(); + case llvm::Triple::arm: + case llvm::Triple::thumb: + // Windows on ARM builds with FPO disabled to aid fast stack walking + return true; + default: + // All other supported Windows ISAs use xdata unwind information, so frame + // pointers are not generally useful. + return false; + } + } + + return true; +} + +static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { + switch (Triple.getArch()) { + default: + return false; + case llvm::Triple::arm: + case llvm::Triple::thumb: + // ARM Darwin targets require a frame pointer to be always present to aid + // offline debugging via backtraces. + return Triple.isOSDarwin(); + } +} + +clang::CodeGenOptions::FramePointerKind +getFramePointerKind(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + // We have 4 states: + // + // 00) leaf retained, non-leaf retained + // 01) leaf retained, non-leaf omitted (this is invalid) + // 10) leaf omitted, non-leaf retained + // (what -momit-leaf-frame-pointer was designed for) + // 11) leaf omitted, non-leaf omitted + // + // "omit" options taking precedence over "no-omit" options is the only way + // to make 3 valid states representable + llvm::opt::Arg *A = + Args.getLastArg(clang::driver::options::OPT_fomit_frame_pointer, + clang::driver::options::OPT_fno_omit_frame_pointer); + + bool OmitFP = A && A->getOption().matches( + clang::driver::options::OPT_fomit_frame_pointer); + bool NoOmitFP = A && A->getOption().matches( + clang::driver::options::OPT_fno_omit_frame_pointer); + bool OmitLeafFP = + Args.hasFlag(clang::driver::options::OPT_momit_leaf_frame_pointer, + clang::driver::options::OPT_mno_omit_leaf_frame_pointer, + Triple.isAArch64() || Triple.isPS() || Triple.isVE() || + (Triple.isAndroid() && Triple.isRISCV64())); + if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || + (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { + if (OmitLeafFP) + return clang::CodeGenOptions::FramePointerKind::NonLeaf; + return clang::CodeGenOptions::FramePointerKind::All; + } + return clang::CodeGenOptions::FramePointerKind::None; +} + +static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs, + const StringRef PluginOptPrefix) { if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ)) - CmdArgs.push_back(Args.MakeArgString(Twine("--plugin-opt=-pass-remarks=") + - A->getValue())); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "-pass-remarks=" + A->getValue())); if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ)) CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=-pass-remarks-missed=") + A->getValue())); + Twine(PluginOptPrefix) + "-pass-remarks-missed=" + A->getValue())); if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ)) CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=-pass-remarks-analysis=") + A->getValue())); + Twine(PluginOptPrefix) + "-pass-remarks-analysis=" + A->getValue())); } static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, const llvm::Triple &Triple, const InputInfo &Input, - const InputInfo &Output) { + const InputInfo &Output, + const StringRef PluginOptPrefix) { StringRef Format = "yaml"; if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) Format = A->getValue(); @@ -93,29 +243,47 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, assert(!F.empty() && "Cannot determine remarks output name."); // Append "opt.ld.<format>" to the end of the file name. - CmdArgs.push_back( - Args.MakeArgString(Twine("--plugin-opt=opt-remarks-filename=") + F + - Twine(".opt.ld.") + Format)); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "opt-remarks-filename=" + F + + ".opt.ld." + Format)); if (const Arg *A = Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=opt-remarks-passes=") + A->getValue())); + Twine(PluginOptPrefix) + "opt-remarks-passes=" + A->getValue())); - CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=opt-remarks-format=") + Format.data())); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "opt-remarks-format=" + Format.data())); } static void renderRemarksHotnessOptions(const ArgList &Args, - ArgStringList &CmdArgs) { + ArgStringList &CmdArgs, + const StringRef PluginOptPrefix) { if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, options::OPT_fno_diagnostics_show_hotness, false)) - CmdArgs.push_back("--plugin-opt=opt-remarks-with-hotness"); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "opt-remarks-with-hotness")); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) - CmdArgs.push_back(Args.MakeArgString( - Twine("--plugin-opt=opt-remarks-hotness-threshold=") + A->getValue())); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + + "opt-remarks-hotness-threshold=" + A->getValue())); +} + +static bool shouldIgnoreUnsupportedTargetFeature(const Arg &TargetFeatureArg, + llvm::Triple T, + StringRef Processor) { + // Warn no-cumode for AMDGCN processors not supporing WGP mode. + if (!T.isAMDGPU()) + return false; + auto GPUKind = T.isAMDGCN() ? llvm::AMDGPU::parseArchAMDGCN(Processor) + : llvm::AMDGPU::parseArchR600(Processor); + auto GPUFeatures = T.isAMDGCN() ? llvm::AMDGPU::getArchAttrAMDGCN(GPUKind) + : llvm::AMDGPU::getArchAttrR600(GPUKind); + if (GPUFeatures & llvm::AMDGPU::FEATURE_WGP) + return false; + return TargetFeatureArg.getOption().matches(options::OPT_mno_cumode); } void tools::addPathIfExists(const Driver &D, const Twine &Path, @@ -124,46 +292,49 @@ void tools::addPathIfExists(const Driver &D, const Twine &Path, Paths.push_back(Path.str()); } -void tools::handleTargetFeaturesGroup(const ArgList &Args, +void tools::handleTargetFeaturesGroup(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, std::vector<StringRef> &Features, OptSpecifier Group) { + std::set<StringRef> Warned; for (const Arg *A : Args.filtered(Group)) { StringRef Name = A->getOption().getName(); A->claim(); // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); + assert(Name.starts_with("m") && "Invalid feature name."); Name = Name.substr(1); - bool IsNegative = Name.startswith("no-"); + auto Proc = getCPUName(D, Args, Triple); + if (shouldIgnoreUnsupportedTargetFeature(*A, Triple, Proc)) { + if (Warned.count(Name) == 0) { + D.getDiags().Report( + clang::diag::warn_drv_unsupported_option_for_processor) + << A->getAsString(Args) << Proc; + Warned.insert(Name); + } + continue; + } + + bool IsNegative = Name.starts_with("no-"); if (IsNegative) Name = Name.substr(3); + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } } -std::vector<StringRef> -tools::unifyTargetFeatures(const std::vector<StringRef> &Features) { - std::vector<StringRef> UnifiedFeatures; - // Find the last of each feature. - llvm::StringMap<unsigned> LastOpt; - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - StringRef Name = Features[I]; - assert(Name[0] == '-' || Name[0] == '+'); - LastOpt[Name.drop_front(1)] = I; +SmallVector<StringRef> +tools::unifyTargetFeatures(ArrayRef<StringRef> Features) { + // Only add a feature if it hasn't been seen before starting from the end. + SmallVector<StringRef> UnifiedFeatures; + llvm::DenseSet<StringRef> UsedFeatures; + for (StringRef Feature : llvm::reverse(Features)) { + if (UsedFeatures.insert(Feature.drop_front()).second) + UnifiedFeatures.insert(UnifiedFeatures.begin(), Feature); } - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - // If this feature was overridden, ignore it. - StringRef Name = Features[I]; - llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1)); - assert(LastI != LastOpt.end()); - unsigned Last = LastI->second; - if (Last != I) - continue; - - UnifiedFeatures.push_back(Name); - } return UnifiedFeatures; } @@ -254,6 +425,10 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, continue; } + // In some error cases, the input could be Nothing; skip those. + if (II.isNothing()) + continue; + // Otherwise, this is a linker input argument. const Arg &A = II.getInputArg(); @@ -262,13 +437,8 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, TC.AddCXXStdlibLibArgs(Args, CmdArgs); else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) TC.AddCCKextLibArgs(Args, CmdArgs); - else if (A.getOption().matches(options::OPT_z)) { - // Pass -z prefix for gcc linker compatibility. - A.claim(); - A.render(Args, CmdArgs); - } else { + else A.renderAsInput(Args, CmdArgs); - } } } @@ -276,17 +446,17 @@ void tools::addLinkerCompressDebugSectionsOption( const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) { // GNU ld supports --compress-debug-sections=none|zlib|zlib-gnu|zlib-gabi - // whereas zlib is an alias to zlib-gabi. Therefore -gz=none|zlib|zlib-gnu - // are translated to --compress-debug-sections=none|zlib|zlib-gnu. - // -gz is not translated since ld --compress-debug-sections option requires an + // whereas zlib is an alias to zlib-gabi and zlib-gnu is obsoleted. Therefore + // -gz=none|zlib are translated to --compress-debug-sections=none|zlib. -gz + // is not translated since ld --compress-debug-sections option requires an // argument. if (const Arg *A = Args.getLastArg(options::OPT_gz_EQ)) { StringRef V = A->getValue(); - if (V == "none" || V == "zlib" || V == "zlib-gnu") + if (V == "none" || V == "zlib" || V == "zstd") CmdArgs.push_back(Args.MakeArgString("--compress-debug-sections=" + V)); else TC.getDriver().Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << V; + << A->getSpelling() << V; } } @@ -305,6 +475,7 @@ void tools::AddTargetFeature(const ArgList &Args, /// Get the (LLVM) name of the AMDGPU gpu we are targeting. static std::string getAMDGPUTargetGPU(const llvm::Triple &T, const ArgList &Args) { + Arg *MArch = Args.getLastArg(options::OPT_march_EQ); if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { auto GPUName = getProcessorFromTargetID(T, A->getValue()); return llvm::StringSwitch<std::string>(GPUName) @@ -317,6 +488,8 @@ static std::string getAMDGPUTargetGPU(const llvm::Triple &T, .Case("aruba", "cayman") .Default(GPUName.str()); } + if (MArch) + return getProcessorFromTargetID(T, MArch->getValue()).str(); return ""; } @@ -346,8 +519,8 @@ static StringRef getWebAssemblyTargetCPU(const ArgList &Args) { return "generic"; } -std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, - bool FromAs) { +std::string tools::getCPUName(const Driver &D, const ArgList &Args, + const llvm::Triple &T, bool FromAs) { Arg *A; switch (T.getArch()) { @@ -395,50 +568,34 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, case llvm::Triple::ppc: case llvm::Triple::ppcle: case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: { - std::string TargetCPUName = ppc::getPPCTargetCPU(Args); - // LLVM may default to generating code for the native CPU, - // but, like gcc, we default to a more generic option for - // each architecture. (except on AIX) - if (!TargetCPUName.empty()) - return TargetCPUName; - - if (T.isOSAIX()) { - unsigned major, minor, unused_micro; - T.getOSVersion(major, minor, unused_micro); - // The minimal arch level moved from pwr4 for AIX7.1 to - // pwr7 for AIX7.2. - TargetCPUName = - (major < 7 || (major == 7 && minor < 2)) ? "pwr4" : "pwr7"; - } else if (T.getArch() == llvm::Triple::ppc64le) - TargetCPUName = "ppc64le"; - else if (T.getArch() == llvm::Triple::ppc64) - TargetCPUName = "ppc64"; - else - TargetCPUName = "ppc"; + case llvm::Triple::ppc64le: + return ppc::getPPCTargetCPU(D, Args, T); - return TargetCPUName; - } + case llvm::Triple::csky: + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + return A->getValue(); + else if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + return A->getValue(); + else + return "ck810"; case llvm::Triple::riscv32: case llvm::Triple::riscv64: + return riscv::getRISCVTargetCPU(Args, T); + + case llvm::Triple::bpfel: + case llvm::Triple::bpfeb: if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(); return ""; - case llvm::Triple::bpfel: - case llvm::Triple::bpfeb: case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: - if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) - return A->getValue(); - if (T.getArch() == llvm::Triple::sparc && T.isOSSolaris()) - return "v9"; - return ""; + return sparc::getSparcTargetCPU(D, Args, T); case llvm::Triple::x86: case llvm::Triple::x86_64: - return x86::getX86TargetCPU(Args, T); + return x86::getX86TargetCPU(D, Args, T); case llvm::Triple::hexagon: return "hexagon" + @@ -457,6 +614,103 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, case llvm::Triple::wasm32: case llvm::Triple::wasm64: return std::string(getWebAssemblyTargetCPU(Args)); + + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + return loongarch::getLoongArchTargetCPU(Args, T); + } +} + +static void getWebAssemblyTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, + std::vector<StringRef> &Features) { + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_wasm_Features_Group); +} + +void tools::getTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, ArgStringList &CmdArgs, + bool ForAS, bool IsAux) { + std::vector<StringRef> Features; + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + mips::getMIPSTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + arm::getARMTargetFeatures(D, Triple, Args, Features, ForAS); + break; + case llvm::Triple::ppc: + case llvm::Triple::ppcle: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + ppc::getPPCTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + riscv::getRISCVTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::systemz: + systemz::getSystemZTargetFeatures(D, Args, Features); + break; + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: + case llvm::Triple::aarch64_be: + aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + x86::getX86TargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::hexagon: + hexagon::getHexagonTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + getWebAssemblyTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + sparc::getSparcTargetFeatures(D, Args, Features); + break; + case llvm::Triple::r600: + case llvm::Triple::amdgcn: + amdgpu::getAMDGPUTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + NVPTX::getNVPTXTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::m68k: + m68k::getM68kTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::msp430: + msp430::getMSP430TargetFeatures(D, Args, Features); + break; + case llvm::Triple::ve: + ve::getVETargetFeatures(D, Args, Features); + break; + case llvm::Triple::csky: + csky::getCSKYTargetFeatures(D, Triple, Args, CmdArgs, Features); + break; + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + loongarch::getLoongArchTargetFeatures(D, Triple, Args, Features); + break; + } + + for (auto Feature : unifyTargetFeatures(Features)) { + CmdArgs.push_back(IsAux ? "-aux-target-feature" : "-target-feature"); + CmdArgs.push_back(Feature.data()); } } @@ -470,22 +724,58 @@ llvm::StringRef tools::getLTOParallelism(const ArgList &Args, const Driver &D) { return LtoJobsArg->getValue(); } -// CloudABI uses -ffunction-sections and -fdata-sections by default. +// PS4/PS5 uses -ffunction-sections and -fdata-sections by default. bool tools::isUseSeparateSections(const llvm::Triple &Triple) { - return Triple.getOS() == llvm::Triple::CloudABI; + return Triple.isPS(); +} + +bool tools::isTLSDESCEnabled(const ToolChain &TC, + const llvm::opt::ArgList &Args) { + const llvm::Triple &Triple = TC.getEffectiveTriple(); + Arg *A = Args.getLastArg(options::OPT_mtls_dialect_EQ); + if (!A) + return Triple.hasDefaultTLSDESC(); + StringRef V = A->getValue(); + bool SupportedArgument = false, EnableTLSDESC = false; + bool Unsupported = !Triple.isOSBinFormatELF(); + if (Triple.isRISCV()) { + SupportedArgument = V == "desc" || V == "trad"; + EnableTLSDESC = V == "desc"; + } else if (Triple.isX86()) { + SupportedArgument = V == "gnu"; + } else { + Unsupported = true; + } + if (Unsupported) { + TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << Triple.getTriple(); + } else if (!SupportedArgument) { + TC.getDriver().Diag(diag::err_drv_unsupported_option_argument_for_target) + << A->getSpelling() << V << Triple.getTriple(); + } + return EnableTLSDESC; } void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO) { + const bool IsOSAIX = ToolChain.getTriple().isOSAIX(); + const bool IsAMDGCN = ToolChain.getTriple().isAMDGCN(); const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath()); const Driver &D = ToolChain.getDriver(); + const bool IsFatLTO = Args.hasArg(options::OPT_ffat_lto_objects); + const bool IsUnifiedLTO = Args.hasArg(options::OPT_funified_lto); if (llvm::sys::path::filename(Linker) != "ld.lld" && - llvm::sys::path::stem(Linker) != "ld.lld") { + llvm::sys::path::stem(Linker) != "ld.lld" && + !ToolChain.getTriple().isOSOpenBSD()) { // Tell the linker to load the plugin. This has to come before - // AddLinkerInputs as gold requires -plugin to come before any -plugin-opt - // that -Wl might forward. - CmdArgs.push_back("-plugin"); + // AddLinkerInputs as gold requires -plugin and AIX ld requires -bplugin to + // come before any -plugin-opt/-bplugin_opt that -Wl might forward. + const char *PluginPrefix = IsOSAIX ? "-bplugin:" : ""; + const char *PluginName = IsOSAIX ? "/libLTO" : "/LLVMgold"; + + if (!IsOSAIX) + CmdArgs.push_back("-plugin"); #if defined(_WIN32) const char *Suffix = ".dll"; @@ -496,19 +786,60 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, #endif SmallString<1024> Plugin; - llvm::sys::path::native( - Twine(D.Dir) + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + Suffix, - Plugin); - CmdArgs.push_back(Args.MakeArgString(Plugin)); + llvm::sys::path::native(Twine(D.Dir) + + "/../" CLANG_INSTALL_LIBDIR_BASENAME + + PluginName + Suffix, + Plugin); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginPrefix) + Plugin)); + } else { + // Tell LLD to find and use .llvm.lto section in regular relocatable object + // files + if (IsFatLTO) + CmdArgs.push_back("--fat-lto-objects"); + } + + const char *PluginOptPrefix = IsOSAIX ? "-bplugin_opt:" : "-plugin-opt="; + const char *ExtraDash = IsOSAIX ? "-" : ""; + const char *ParallelismOpt = IsOSAIX ? "-threads=" : "jobs="; + + // Note, this solution is far from perfect, better to encode it into IR + // metadata, but this may not be worth it, since it looks like aranges is on + // the way out. + if (Args.hasArg(options::OPT_gdwarf_aranges)) { + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "-generate-arange-section")); + } + + // Pass vector library arguments to LTO. + Arg *ArgVecLib = Args.getLastArg(options::OPT_fveclib); + if (ArgVecLib && ArgVecLib->getNumValues() == 1) { + // Map the vector library names from clang front-end to opt front-end. The + // values are taken from the TargetLibraryInfo class command line options. + std::optional<StringRef> OptVal = + llvm::StringSwitch<std::optional<StringRef>>(ArgVecLib->getValue()) + .Case("Accelerate", "Accelerate") + .Case("LIBMVEC", "LIBMVEC-X86") + .Case("MASSV", "MASSV") + .Case("SVML", "SVML") + .Case("SLEEF", "sleefgnuabi") + .Case("Darwin_libsystem_m", "Darwin_libsystem_m") + .Case("ArmPL", "ArmPL") + .Case("none", "none") + .Default(std::nullopt); + + if (OptVal) + CmdArgs.push_back(Args.MakeArgString( + Twine(PluginOptPrefix) + "-vector-library=" + OptVal.value())); } // Try to pass driver level flags relevant to LTO code generation down to // the plugin. // Handle flags for selecting CPU variants. - std::string CPU = getCPUName(Args, ToolChain.getTriple()); + std::string CPU = getCPUName(D, Args, ToolChain.getTriple()); if (!CPU.empty()) - CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "mcpu=" + CPU)); if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { // The optimization level matches @@ -525,48 +856,140 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, OOpt = "2"; } else if (A->getOption().matches(options::OPT_O0)) OOpt = "0"; - if (!OOpt.empty()) - CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt)); + if (!OOpt.empty()) { + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "O" + OOpt)); + if (IsAMDGCN) + CmdArgs.push_back(Args.MakeArgString(Twine("--lto-CGO") + OOpt)); + } } - if (Args.hasArg(options::OPT_gsplit_dwarf)) { + if (Args.hasArg(options::OPT_gsplit_dwarf)) + CmdArgs.push_back(Args.MakeArgString( + Twine(PluginOptPrefix) + "dwo_dir=" + Output.getFilename() + "_dwo")); + + if (IsThinLTO && !IsOSAIX) + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + "thinlto")); + else if (IsThinLTO && IsOSAIX) + CmdArgs.push_back(Args.MakeArgString(Twine("-bdbg:thinlto"))); + + // Matrix intrinsic lowering happens at link time with ThinLTO. Enable + // LowerMatrixIntrinsicsPass, which is transitively called by + // buildThinLTODefaultPipeline under EnableMatrix. + if ((IsThinLTO || IsFatLTO || IsUnifiedLTO) && + Args.hasArg(options::OPT_fenable_matrix)) CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=dwo_dir=") + - Output.getFilename() + "_dwo")); - } - - if (IsThinLTO) - CmdArgs.push_back("-plugin-opt=thinlto"); + Args.MakeArgString(Twine(PluginOptPrefix) + "-enable-matrix")); StringRef Parallelism = getLTOParallelism(Args, D); if (!Parallelism.empty()) - CmdArgs.push_back( - Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism))); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + ParallelismOpt + Parallelism)); + + // Pass down GlobalISel options. + if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel, + options::OPT_fno_global_isel)) { + // Parsing -fno-global-isel explicitly gives architectures that enable GISel + // by default a chance to disable it. + CmdArgs.push_back(Args.MakeArgString( + Twine(PluginOptPrefix) + "-global-isel=" + + (A->getOption().matches(options::OPT_fglobal_isel) ? "1" : "0"))); + } // If an explicit debugger tuning argument appeared, pass it along. - if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, - options::OPT_ggdbN_Group)) { + if (Arg *A = + Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { if (A->getOption().matches(options::OPT_glldb)) - CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=lldb")); else if (A->getOption().matches(options::OPT_gsce)) - CmdArgs.push_back("-plugin-opt=-debugger-tune=sce"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=sce")); else if (A->getOption().matches(options::OPT_gdbx)) - CmdArgs.push_back("-plugin-opt=-debugger-tune=dbx"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=dbx")); else - CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=gdb")); + } + + if (IsOSAIX) { + if (!ToolChain.useIntegratedAs()) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-no-integrated-as=1")); + + // On AIX, clang assumes strict-dwarf is true if any debug option is + // specified, unless it is told explicitly not to assume so. + Arg *A = Args.getLastArg(options::OPT_g_Group); + bool EnableDebugInfo = A && !A->getOption().matches(options::OPT_g0) && + !A->getOption().matches(options::OPT_ggdb0); + if (EnableDebugInfo && Args.hasFlag(options::OPT_gstrict_dwarf, + options::OPT_gno_strict_dwarf, true)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-strict-dwarf=true")); + + for (const Arg *A : Args.filtered_reverse(options::OPT_mabi_EQ)) { + StringRef V = A->getValue(); + if (V == "vec-default") + break; + if (V == "vec-extabi") { + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-vec-extabi")); + break; + } + } } bool UseSeparateSections = isUseSeparateSections(ToolChain.getEffectiveTriple()); if (Args.hasFlag(options::OPT_ffunction_sections, - options::OPT_fno_function_sections, UseSeparateSections)) { - CmdArgs.push_back("-plugin-opt=-function-sections"); - } + options::OPT_fno_function_sections, UseSeparateSections)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=1")); + else if (Args.hasArg(options::OPT_fno_function_sections)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=0")); + bool DataSectionsTurnedOff = false; if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, UseSeparateSections)) { - CmdArgs.push_back("-plugin-opt=-data-sections"); + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=1")); + } else if (Args.hasArg(options::OPT_fno_data_sections)) { + DataSectionsTurnedOff = true; + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=0")); + } + + if (Args.hasArg(options::OPT_mxcoff_roptr) || + Args.hasArg(options::OPT_mno_xcoff_roptr)) { + bool HasRoptr = Args.hasFlag(options::OPT_mxcoff_roptr, + options::OPT_mno_xcoff_roptr, false); + StringRef OptStr = HasRoptr ? "-mxcoff-roptr" : "-mno-xcoff-roptr"; + + if (!IsOSAIX) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << OptStr << ToolChain.getTriple().str(); + + if (HasRoptr) { + // The data sections option is on by default on AIX. We only need to error + // out when -fno-data-sections is specified explicitly to turn off data + // sections. + if (DataSectionsTurnedOff) + D.Diag(diag::err_roptr_requires_data_sections); + + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-mxcoff-roptr")); + } + } + + // Pass an option to enable split machine functions. + if (auto *A = Args.getLastArg(options::OPT_fsplit_machine_functions, + options::OPT_fno_split_machine_functions)) { + if (A->getOption().matches(options::OPT_fsplit_machine_functions)) + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "-split-machine-functions")); } if (Arg *A = getLastProfileSampleUseArg(Args)) { @@ -574,90 +997,126 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, if (!llvm::sys::fs::exists(FName)) D.Diag(diag::err_drv_no_such_file) << FName; else - CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "sample-profile=" + FName)); } - auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate, - options::OPT_fcs_profile_generate_EQ, - options::OPT_fno_profile_generate); - if (CSPGOGenerateArg && - CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) - CSPGOGenerateArg = nullptr; - - auto *ProfileUseArg = getLastProfileUseArg(Args); - - if (CSPGOGenerateArg) { - CmdArgs.push_back(Args.MakeArgString("-plugin-opt=cs-profile-generate")); + if (auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args)) { + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + + "cs-profile-generate")); if (CSPGOGenerateArg->getOption().matches( options::OPT_fcs_profile_generate_EQ)) { SmallString<128> Path(CSPGOGenerateArg->getValue()); llvm::sys::path::append(Path, "default_%m.profraw"); - CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + Path)); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + + "cs-profile-path=" + Path)); } else CmdArgs.push_back( - Args.MakeArgString("-plugin-opt=cs-profile-path=default_%m.profraw")); - } else if (ProfileUseArg) { + Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + + "cs-profile-path=default_%m.profraw")); + } else if (auto *ProfileUseArg = getLastProfileUseArg(Args)) { SmallString<128> Path( ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); if (Path.empty() || llvm::sys::fs::is_directory(Path)) llvm::sys::path::append(Path, "default.profdata"); - CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + - Path)); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + + "cs-profile-path=" + Path)); } - // Pass an option to enable/disable the new pass manager. - if (auto *A = Args.getLastArg(options::OPT_flegacy_pass_manager, - options::OPT_fno_legacy_pass_manager)) { - if (A->getOption().matches(options::OPT_flegacy_pass_manager)) - CmdArgs.push_back("-plugin-opt=legacy-pass-manager"); + // This controls whether or not we perform JustMyCode instrumentation. + if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) { + if (ToolChain.getEffectiveTriple().isOSBinFormatELF()) + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + + "-enable-jmc-instrument")); else - CmdArgs.push_back("-plugin-opt=new-pass-manager"); + D.Diag(clang::diag::warn_drv_fjmc_for_elf_only); + } + + if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, + ToolChain.getTriple().hasDefaultEmulatedTLS())) { + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-emulated-tls")); } + if (isTLSDESCEnabled(ToolChain, Args)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-enable-tlsdesc")); - // Pass an option to enable pseudo probe emission. - if (Args.hasFlag(options::OPT_fpseudo_probe_for_profiling, - options::OPT_fno_pseudo_probe_for_profiling, false)) - CmdArgs.push_back("-plugin-opt=pseudo-probe-for-profiling"); + if (Args.hasFlag(options::OPT_fstack_size_section, + options::OPT_fno_stack_size_section, false)) + CmdArgs.push_back( + Args.MakeArgString(Twine(PluginOptPrefix) + "-stack-size-section")); // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); if (!StatsFile.empty()) CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile)); + Args.MakeArgString(Twine(PluginOptPrefix) + "stats-file=" + StatsFile)); + + // Setup crash diagnostics dir. + if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir)) + CmdArgs.push_back(Args.MakeArgString( + Twine(PluginOptPrefix) + "-crash-diagnostics-dir=" + A->getValue())); - addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true); + addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true, PluginOptPrefix); // Handle remark diagnostics on screen options: '-Rpass-*'. - renderRpassOptions(Args, CmdArgs); + renderRpassOptions(Args, CmdArgs, PluginOptPrefix); // Handle serialized remarks options: '-fsave-optimization-record' // and '-foptimization-record-*'. if (willEmitRemarks(Args)) renderRemarksOptions(Args, CmdArgs, ToolChain.getEffectiveTriple(), Input, - Output); + Output, PluginOptPrefix); // Handle remarks hotness/threshold related options. - renderRemarksHotnessOptions(Args, CmdArgs); + renderRemarksHotnessOptions(Args, CmdArgs, PluginOptPrefix); addMachineOutlinerArgs(D, Args, CmdArgs, ToolChain.getEffectiveTriple(), - /*IsLTO=*/true); + /*IsLTO=*/true, PluginOptPrefix); +} + +/// Adds the '-lcgpu' and '-lmgpu' libraries to the compilation to include the +/// LLVM C library for GPUs. +static void addOpenMPDeviceLibC(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_nogpulib) || Args.hasArg(options::OPT_nolibc)) + return; + + // Check the resource directory for the LLVM libc GPU declarations. If it's + // found we can assume that LLVM was built with support for the GPU libc. + SmallString<256> LibCDecls(TC.getDriver().ResourceDir); + llvm::sys::path::append(LibCDecls, "include", "llvm_libc_wrappers", + "llvm-libc-decls"); + bool HasLibC = llvm::sys::fs::exists(LibCDecls) && + llvm::sys::fs::is_directory(LibCDecls); + if (Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, HasLibC)) { + CmdArgs.push_back("-lcgpu"); + CmdArgs.push_back("-lmgpu"); + } +} + +void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC, + const ArgList &Args, + ArgStringList &CmdArgs) { + // Default to clang lib / lib64 folder, i.e. the same location as device + // runtime. + SmallString<256> DefaultLibPath = + llvm::sys::path::parent_path(TC.getDriver().Dir); + llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME); + CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath)); } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - // Enable -frtlib-add-rpath by default for the case of VE. - const bool IsVE = TC.getTriple().isVE(); - bool DefaultValue = IsVE; if (!Args.hasFlag(options::OPT_frtlib_add_rpath, - options::OPT_fno_rtlib_add_rpath, DefaultValue)) + options::OPT_fno_rtlib_add_rpath, false)) return; - std::string CandidateRPath = TC.getArchSpecificLibPath(); - if (TC.getVFS().exists(CandidateRPath)) { - CmdArgs.push_back("-rpath"); - CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str())); + for (const auto &CandidateRPath : TC.getArchSpecificLibPaths()) { + if (TC.getVFS().exists(CandidateRPath)) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back(Args.MakeArgString(CandidateRPath)); + } } } @@ -700,11 +1159,155 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, if (IsOffloadingHost) CmdArgs.push_back("-lomptarget"); + if (IsOffloadingHost && !Args.hasArg(options::OPT_nogpulib)) + CmdArgs.push_back("-lomptarget.devicertl"); + + if (IsOffloadingHost) + addOpenMPDeviceLibC(TC, Args, CmdArgs); + addArchSpecificRPath(TC, Args, CmdArgs); + addOpenMPRuntimeLibraryPath(TC, Args, CmdArgs); return true; } +/// Determines if --whole-archive is active in the list of arguments. +static bool isWholeArchivePresent(const ArgList &Args) { + bool WholeArchiveActive = false; + for (auto *Arg : Args.filtered(options::OPT_Wl_COMMA)) { + if (Arg) { + for (StringRef ArgValue : Arg->getValues()) { + if (ArgValue == "--whole-archive") + WholeArchiveActive = true; + if (ArgValue == "--no-whole-archive") + WholeArchiveActive = false; + } + } + } + + return WholeArchiveActive; +} + +/// Determine if driver is invoked to create a shared object library (-static) +static bool isSharedLinkage(const ArgList &Args) { + return Args.hasArg(options::OPT_shared); +} + +/// Determine if driver is invoked to create a static object library (-shared) +static bool isStaticLinkage(const ArgList &Args) { + return Args.hasArg(options::OPT_static); +} + +/// Add Fortran runtime libs for MSVC +static void addFortranRuntimeLibsMSVC(const ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + unsigned RTOptionID = options::OPT__SLASH_MT; + if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue()) + .Case("static", options::OPT__SLASH_MT) + .Case("static_dbg", options::OPT__SLASH_MTd) + .Case("dll", options::OPT__SLASH_MD) + .Case("dll_dbg", options::OPT__SLASH_MDd) + .Default(options::OPT__SLASH_MT); + } + switch (RTOptionID) { + case options::OPT__SLASH_MT: + CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static.lib"); + break; + case options::OPT__SLASH_MTd: + CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static_dbg.lib"); + break; + case options::OPT__SLASH_MD: + CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic.lib"); + break; + case options::OPT__SLASH_MDd: + CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic_dbg.lib"); + break; + } +} + +// Add FortranMain runtime lib +static void addFortranMain(const ToolChain &TC, const ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + // 0. Shared-library linkage + // If we are attempting to link a library, we should not add + // -lFortran_main.a to the link line, as the `main` symbol is not + // required for a library and should also be provided by one of + // the translation units of the code that this shared library + // will be linked against eventually. + if (isSharedLinkage(Args) || isStaticLinkage(Args)) { + return; + } + + // 1. MSVC + if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { + addFortranRuntimeLibsMSVC(Args, CmdArgs); + return; + } + + // 2. GNU and similar + const Driver &D = TC.getDriver(); + const char *FortranMainLinkFlag = "-lFortran_main"; + + // Warn if the user added `-lFortran_main` - this library is an implementation + // detail of Flang and should be handled automaticaly by the driver. + for (const char *arg : CmdArgs) { + if (strncmp(arg, FortranMainLinkFlag, strlen(FortranMainLinkFlag)) == 0) + D.Diag(diag::warn_drv_deprecated_custom) + << FortranMainLinkFlag + << "see the Flang driver documentation for correct usage"; + } + + // The --whole-archive option needs to be part of the link line to make + // sure that the main() function from Fortran_main.a is pulled in by the + // linker. However, it shouldn't be used if it's already active. + // TODO: Find an equivalent of `--whole-archive` for Darwin and AIX. + if (!isWholeArchivePresent(Args) && !TC.getTriple().isMacOSX() && + !TC.getTriple().isOSAIX()) { + CmdArgs.push_back("--whole-archive"); + CmdArgs.push_back(FortranMainLinkFlag); + CmdArgs.push_back("--no-whole-archive"); + return; + } + + CmdArgs.push_back(FortranMainLinkFlag); +} + +/// Add Fortran runtime libs +void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + // 1. Link FortranMain + // FortranMain depends on FortranRuntime, so needs to be listed first. If + // -fno-fortran-main has been passed, skip linking Fortran_main.a + if (!Args.hasArg(options::OPT_no_fortran_main)) + addFortranMain(TC, Args, CmdArgs); + + // 2. Link FortranRuntime and FortranDecimal + // These are handled earlier on Windows by telling the frontend driver to + // add the correct libraries to link against as dependents in the object + // file. + if (!TC.getTriple().isKnownWindowsMSVCEnvironment()) { + CmdArgs.push_back("-lFortranRuntime"); + CmdArgs.push_back("-lFortranDecimal"); + } +} + +void tools::addFortranRuntimeLibraryPath(const ToolChain &TC, + const llvm::opt::ArgList &Args, + ArgStringList &CmdArgs) { + // Default to the <driver-path>/../lib directory. This works fine on the + // platforms that we have tested so far. We will probably have to re-fine + // this in the future. In particular, on some platforms, we may need to use + // lib64 instead of lib. + SmallString<256> DefaultLibPath = + llvm::sys::path::parent_path(TC.getDriver().Dir); + llvm::sys::path::append(DefaultLibPath, "lib"); + if (TC.getTriple().isKnownWindowsMSVCEnvironment()) + CmdArgs.push_back(Args.MakeArgString("-libpath:" + DefaultLibPath)); + else + CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath)); +} + static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer, bool IsShared, bool IsWhole) { @@ -725,9 +1328,11 @@ static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer) { + bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args); + // Solaris ld defaults to --export-dynamic behaviour but doesn't support // the option, so don't try to pass it. - if (TC.getTriple().getOS() == llvm::Triple::Solaris) + if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd) return true; SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer)); if (llvm::sys::fs::exists(SanRT + ".syms")) { @@ -737,32 +1342,36 @@ static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, return false; } -static const char *getAsNeededOption(const ToolChain &TC, bool as_needed) { +void tools::addAsNeededOption(const ToolChain &TC, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + bool as_needed) { assert(!TC.getTriple().isOSAIX() && "AIX linker does not support any form of --as-needed option yet."); + bool LinkerIsGnuLd = solaris::isLinkerGnuLd(TC, Args); // While the Solaris 11.2 ld added --as-needed/--no-as-needed as aliases // for the native forms -z ignore/-z record, they are missing in Illumos, // so always use the native form. - if (TC.getTriple().isOSSolaris()) - return as_needed ? "-zignore" : "-zrecord"; - else - return as_needed ? "--as-needed" : "--no-as-needed"; + // GNU ld doesn't support -z ignore/-z record, so don't use them even on + // Solaris. + if (TC.getTriple().isOSSolaris() && !LinkerIsGnuLd) { + CmdArgs.push_back("-z"); + CmdArgs.push_back(as_needed ? "ignore" : "record"); + } else { + CmdArgs.push_back(as_needed ? "--as-needed" : "--no-as-needed"); + } } void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, + const llvm::opt::ArgList &Args, ArgStringList &CmdArgs) { - // Fuchsia never needs these. Any sanitizer runtimes with system - // dependencies use the `.deplibs` feature instead. - if (TC.getTriple().isOSFuchsia()) - return; - // Force linking against the system libraries sanitizers depends on // (see PR15823 why this is necessary). - CmdArgs.push_back(getAsNeededOption(TC, false)); + addAsNeededOption(TC, Args, CmdArgs, false); // There's no libpthread or librt on RTEMS & Android. if (TC.getTriple().getOS() != llvm::Triple::RTEMS && - !TC.getTriple().isAndroid()) { + !TC.getTriple().isAndroid() && !TC.getTriple().isOHOSFamily()) { CmdArgs.push_back("-lpthread"); if (!TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lrt"); @@ -778,6 +1387,12 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, TC.getTriple().isOSNetBSD() || TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lexecinfo"); + // There is no libresolv on Android, FreeBSD, OpenBSD, etc. On musl + // libresolv.a, even if exists, is an empty archive to satisfy POSIX -lresolv + // requirement. + if (TC.getTriple().isOSLinux() && !TC.getTriple().isAndroid() && + !TC.getTriple().isMusl()) + CmdArgs.push_back("-lresolv"); } static void @@ -787,45 +1402,48 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, SmallVectorImpl<StringRef> &NonWholeStaticRuntimes, SmallVectorImpl<StringRef> &HelperStaticRuntimes, SmallVectorImpl<StringRef> &RequiredSymbols) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); // Collect shared runtimes. if (SanArgs.needsSharedRt()) { - if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsAsanRt()) { SharedRuntimes.push_back("asan"); if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid()) HelperStaticRuntimes.push_back("asan-preinit"); } - if (SanArgs.needsMemProfRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsMemProfRt()) { SharedRuntimes.push_back("memprof"); if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid()) HelperStaticRuntimes.push_back("memprof-preinit"); } - if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsUbsanRt()) { if (SanArgs.requiresMinimalRuntime()) SharedRuntimes.push_back("ubsan_minimal"); else SharedRuntimes.push_back("ubsan_standalone"); } - if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) { - if (SanArgs.requiresMinimalRuntime()) - SharedRuntimes.push_back("scudo_minimal"); - else - SharedRuntimes.push_back("scudo"); + if (SanArgs.needsScudoRt()) { + SharedRuntimes.push_back("scudo_standalone"); } - if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes()) + if (SanArgs.needsTsanRt()) SharedRuntimes.push_back("tsan"); - if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsHwasanRt()) { if (SanArgs.needsHwasanAliasesRt()) SharedRuntimes.push_back("hwasan_aliases"); else SharedRuntimes.push_back("hwasan"); + if (!Args.hasArg(options::OPT_shared)) + HelperStaticRuntimes.push_back("hwasan-preinit"); } } // The stats_client library is also statically linked into DSOs. - if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) + if (SanArgs.needsStatsRt()) StaticRuntimes.push_back("stats_client"); + // Always link the static runtime regardless of DSO or executable. + if (SanArgs.needsAsanRt()) + HelperStaticRuntimes.push_back("asan_static"); + // Collect static runtimes. if (Args.hasArg(options::OPT_shared)) { // Don't link static runtimes into DSOs. @@ -835,20 +1453,19 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, // Each static runtime that has a DSO counterpart above is excluded below, // but runtimes that exist only as static are not affected by needsSharedRt. - if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt()) { StaticRuntimes.push_back("asan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("asan_cxx"); } - if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt() && - SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt()) { StaticRuntimes.push_back("memprof"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("memprof_cxx"); } - if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt()) { if (SanArgs.needsHwasanAliasesRt()) { StaticRuntimes.push_back("hwasan_aliases"); if (SanArgs.linkCXXRuntimes()) @@ -859,22 +1476,21 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("hwasan_cxx"); } } - if (SanArgs.needsDfsanRt() && SanArgs.linkRuntimes()) + if (SanArgs.needsDfsanRt()) StaticRuntimes.push_back("dfsan"); - if (SanArgs.needsLsanRt() && SanArgs.linkRuntimes()) + if (SanArgs.needsLsanRt()) StaticRuntimes.push_back("lsan"); - if (SanArgs.needsMsanRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsMsanRt()) { StaticRuntimes.push_back("msan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("msan_cxx"); } - if (!SanArgs.needsSharedRt() && SanArgs.needsTsanRt() && - SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsTsanRt()) { StaticRuntimes.push_back("tsan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("tsan_cxx"); } - if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) { if (SanArgs.requiresMinimalRuntime()) { StaticRuntimes.push_back("ubsan_minimal"); } else { @@ -883,33 +1499,27 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("ubsan_standalone_cxx"); } } - if (SanArgs.needsSafeStackRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsSafeStackRt()) { NonWholeStaticRuntimes.push_back("safestack"); RequiredSymbols.push_back("__safestack_init"); } - if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes())) { - if (SanArgs.needsCfiRt() && SanArgs.linkRuntimes()) + if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt())) { + if (SanArgs.needsCfiRt()) StaticRuntimes.push_back("cfi"); - if (SanArgs.needsCfiDiagRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsCfiDiagRt()) { StaticRuntimes.push_back("cfi_diag"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("ubsan_standalone_cxx"); } } - if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) { + if (SanArgs.needsStatsRt()) { NonWholeStaticRuntimes.push_back("stats"); RequiredSymbols.push_back("__sanitizer_stats_register"); } - if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) { - if (SanArgs.requiresMinimalRuntime()) { - StaticRuntimes.push_back("scudo_minimal"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("scudo_cxx_minimal"); - } else { - StaticRuntimes.push_back("scudo"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("scudo_cxx"); - } + if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt()) { + StaticRuntimes.push_back("scudo_standalone"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("scudo_standalone_cxx"); } } @@ -917,13 +1527,15 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, // C runtime, etc). Returns true if sanitizer system deps need to be linked in. bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols; - collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, - NonWholeStaticRuntimes, HelperStaticRuntimes, - RequiredSymbols); + if (SanArgs.linkRuntimes()) { + collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, + NonWholeStaticRuntimes, HelperStaticRuntimes, + RequiredSymbols); + } - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); // Inject libfuzzer dependencies. if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() && !Args.hasArg(options::OPT_shared)) { @@ -968,6 +1580,19 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) CmdArgs.push_back("--export-dynamic-symbol=__cfi_check"); + if (SanArgs.hasMemTag()) { + if (!TC.getTriple().isAndroid()) { + TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << "-fsanitize=memtag*" << TC.getTriple().str(); + } + CmdArgs.push_back( + Args.MakeArgString("--android-memtag-mode=" + SanArgs.getMemtagMode())); + if (SanArgs.hasMemtagHeap()) + CmdArgs.push_back("--android-memtag-heap"); + if (SanArgs.hasMemtagStack()) + CmdArgs.push_back("--android-memtag-stack"); + } + return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty(); } @@ -976,19 +1601,21 @@ bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args, ArgStringLis return false; if (TC.getXRayArgs().needsXRayRt()) { - CmdArgs.push_back("-whole-archive"); + CmdArgs.push_back("--whole-archive"); CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray")); for (const auto &Mode : TC.getXRayArgs().modeList()) CmdArgs.push_back(TC.getCompilerRTArgString(Args, Mode)); - CmdArgs.push_back("-no-whole-archive"); + CmdArgs.push_back("--no-whole-archive"); return true; } return false; } -void tools::linkXRayRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { - CmdArgs.push_back(getAsNeededOption(TC, false)); +void tools::linkXRayRuntimeDeps(const ToolChain &TC, + const llvm::opt::ArgList &Args, + ArgStringList &CmdArgs) { + addAsNeededOption(TC, Args, CmdArgs, false); CmdArgs.push_back("-lpthread"); if (!TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lrt"); @@ -1017,26 +1644,27 @@ const char *tools::SplitDebugName(const JobAction &JA, const ArgList &Args, F += ".dwo"; }; if (Arg *A = Args.getLastArg(options::OPT_gsplit_dwarf_EQ)) - if (StringRef(A->getValue()) == "single") + if (StringRef(A->getValue()) == "single" && Output.isFilename()) return Args.MakeArgString(Output.getFilename()); - Arg *FinalOutput = Args.getLastArg(options::OPT_o); - if (FinalOutput && Args.hasArg(options::OPT_c)) { - SmallString<128> T(FinalOutput->getValue()); - llvm::sys::path::remove_filename(T); - llvm::sys::path::append(T, llvm::sys::path::stem(FinalOutput->getValue())); - AddPostfix(T); - return Args.MakeArgString(T); + SmallString<128> T; + if (const Arg *A = Args.getLastArg(options::OPT_dumpdir)) { + T = A->getValue(); } else { - // Use the compilation dir. - Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ, - options::OPT_fdebug_compilation_dir_EQ); - SmallString<128> T(A ? A->getValue() : ""); - SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput())); - AddPostfix(F); - T += F; - return Args.MakeArgString(T); + Arg *FinalOutput = Args.getLastArg(options::OPT_o, options::OPT__SLASH_o); + if (FinalOutput && Args.hasArg(options::OPT_c)) { + T = FinalOutput->getValue(); + llvm::sys::path::remove_filename(T); + llvm::sys::path::append(T, + llvm::sys::path::stem(FinalOutput->getValue())); + AddPostfix(T); + return Args.MakeArgString(T); + } } + + T += llvm::sys::path::stem(Input.getBaseInput()); + AddPostfix(T); + return Args.MakeArgString(T); } void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, @@ -1078,6 +1706,17 @@ void tools::claimNoWarnArgs(const ArgList &Args) { Args.ClaimAllArgs(options::OPT_fno_lto); } +Arg *tools::getLastCSProfileGenerateArg(const ArgList &Args) { + auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate, + options::OPT_fcs_profile_generate_EQ, + options::OPT_fno_profile_generate); + if (CSPGOGenerateArg && + CSPGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) + CSPGOGenerateArg = nullptr; + + return CSPGOGenerateArg; +} + Arg *tools::getLastProfileUseArg(const ArgList &Args) { auto *ProfileUseArg = Args.getLastArg( options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, @@ -1107,6 +1746,24 @@ Arg *tools::getLastProfileSampleUseArg(const ArgList &Args) { options::OPT_fauto_profile_EQ); } +const char *tools::RelocationModelName(llvm::Reloc::Model Model) { + switch (Model) { + case llvm::Reloc::Static: + return "static"; + case llvm::Reloc::PIC_: + return "pic"; + case llvm::Reloc::DynamicNoPIC: + return "dynamic-no-pic"; + case llvm::Reloc::ROPI: + return "ropi"; + case llvm::Reloc::RWPI: + return "rwpi"; + case llvm::Reloc::ROPI_RWPI: + return "ropi-rwpi"; + } + llvm_unreachable("Unknown Reloc::Model kind"); +} + /// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then, /// smooshes them together with platform defaults, to decide whether /// this compile should be using PIC mode or not. Returns a tuple of @@ -1116,7 +1773,7 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple(); const llvm::Triple &Triple = ToolChain.getTriple(); - bool PIE = ToolChain.isPIEDefault(); + bool PIE = ToolChain.isPIEDefault(Args); bool PIC = PIE || ToolChain.isPICDefault(); // The Darwin/MachO default to use PIC does not apply when using -static. if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static)) @@ -1152,6 +1809,10 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { } } + // OHOS-specific defaults for PIC/PIE + if (Triple.isOHOSFamily() && Triple.getArch() == llvm::Triple::aarch64) + PIC = true; + // OpenBSD-specific defaults for PIE if (Triple.isOSOpenBSD()) { switch (ToolChain.getArch()) { @@ -1174,10 +1835,6 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { } } - // AMDGPU-specific defaults for PIC. - if (Triple.getArch() == llvm::Triple::amdgcn) - PIC = true; - // The last argument relating to either PIC or PIE wins, and no // other argument is used. If the last argument is any flavor of the // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE @@ -1186,10 +1843,9 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, options::OPT_fpie, options::OPT_fno_pie); - if (Triple.isOSWindows() && LastPICArg && - LastPICArg == - Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, - options::OPT_fPIE, options::OPT_fpie)) { + if (Triple.isOSWindows() && !Triple.isOSCygMing() && LastPICArg && + LastPICArg == Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, + options::OPT_fPIE, options::OPT_fpie)) { ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << LastPICArg->getSpelling() << Triple.str(); if (Triple.getArch() == llvm::Triple::x86_64) @@ -1211,30 +1867,31 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); } else { PIE = PIC = false; - if (EffectiveTriple.isPS4CPU()) { + if (EffectiveTriple.isPS()) { Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ); StringRef Model = ModelArg ? ModelArg->getValue() : ""; if (Model != "kernel") { PIC = true; - ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic) - << LastPICArg->getSpelling(); + ToolChain.getDriver().Diag(diag::warn_drv_ps_force_pic) + << LastPICArg->getSpelling() + << (EffectiveTriple.isPS4() ? "PS4" : "PS5"); } } } } } - // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the - // PIC level would've been set to level 1, force it back to level 2 PIC + // Introduce a Darwin and PS4/PS5-specific hack. If the default is PIC, but + // the PIC level would've been set to level 1, force it back to level 2 PIC // instead. - if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU())) + if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS())) IsPICLevelTwo |= ToolChain.isPICDefault(); // This kernel flags are a trump-card: they will disable PIC/PIE // generation, independent of the argument order. if (KernelOrKext && ((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) && - !EffectiveTriple.isWatchOS())) + !EffectiveTriple.isWatchOS() && !EffectiveTriple.isDriverKit())) PIC = PIE = false; if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { @@ -1352,7 +2009,49 @@ unsigned tools::ParseFunctionAlignment(const ToolChain &TC, return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value; } -unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC, +void tools::addDebugInfoKind( + ArgStringList &CmdArgs, llvm::codegenoptions::DebugInfoKind DebugInfoKind) { + switch (DebugInfoKind) { + case llvm::codegenoptions::DebugDirectivesOnly: + CmdArgs.push_back("-debug-info-kind=line-directives-only"); + break; + case llvm::codegenoptions::DebugLineTablesOnly: + CmdArgs.push_back("-debug-info-kind=line-tables-only"); + break; + case llvm::codegenoptions::DebugInfoConstructor: + CmdArgs.push_back("-debug-info-kind=constructor"); + break; + case llvm::codegenoptions::LimitedDebugInfo: + CmdArgs.push_back("-debug-info-kind=limited"); + break; + case llvm::codegenoptions::FullDebugInfo: + CmdArgs.push_back("-debug-info-kind=standalone"); + break; + case llvm::codegenoptions::UnusedTypeInfo: + CmdArgs.push_back("-debug-info-kind=unused-types"); + break; + default: + break; + } +} + +// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases +// to the corresponding DebugInfoKind. +llvm::codegenoptions::DebugInfoKind tools::debugLevelToInfoKind(const Arg &A) { + assert(A.getOption().matches(options::OPT_gN_Group) && + "Not a -g option that specifies a debug-info level"); + if (A.getOption().matches(options::OPT_g0) || + A.getOption().matches(options::OPT_ggdb0)) + return llvm::codegenoptions::NoDebugInfo; + if (A.getOption().matches(options::OPT_gline_tables_only) || + A.getOption().matches(options::OPT_ggdb1)) + return llvm::codegenoptions::DebugLineTablesOnly; + if (A.getOption().matches(options::OPT_gline_directives_only)) + return llvm::codegenoptions::DebugDirectivesOnly; + return llvm::codegenoptions::DebugInfoConstructor; +} + +static unsigned ParseDebugDefaultVersion(const ToolChain &TC, const ArgList &Args) { const Arg *A = Args.getLastArg(options::OPT_fdebug_default_version); @@ -1367,6 +2066,34 @@ unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC, return Value; } +unsigned tools::DwarfVersionNum(StringRef ArgValue) { + return llvm::StringSwitch<unsigned>(ArgValue) + .Case("-gdwarf-2", 2) + .Case("-gdwarf-3", 3) + .Case("-gdwarf-4", 4) + .Case("-gdwarf-5", 5) + .Default(0); +} + +const Arg *tools::getDwarfNArg(const ArgList &Args) { + return Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, + options::OPT_gdwarf_4, options::OPT_gdwarf_5, + options::OPT_gdwarf); +} + +unsigned tools::getDwarfVersion(const ToolChain &TC, + const llvm::opt::ArgList &Args) { + unsigned DwarfVersion = ParseDebugDefaultVersion(TC, Args); + if (const Arg *GDwarfN = getDwarfNArg(Args)) + if (int N = DwarfVersionNum(GDwarfN->getSpelling())) + DwarfVersion = N; + if (DwarfVersion == 0) { + DwarfVersion = TC.GetDefaultDwarfVersion(); + assert(DwarfVersion && "toolchain default DWARF version must be nonzero"); + } + return DwarfVersion; +} + void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs) { llvm::Reloc::Model RelocationModel; @@ -1389,17 +2116,12 @@ enum class LibGccType { UnspecifiedLibGcc, StaticLibGcc, SharedLibGcc }; static LibGccType getLibGccType(const ToolChain &TC, const Driver &D, const ArgList &Args) { if (Args.hasArg(options::OPT_static_libgcc) || - Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_pie)) + Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_pie) || + // The Android NDK only provides libunwind.a, not libunwind.so. + TC.getTriple().isAndroid()) return LibGccType::StaticLibGcc; if (Args.hasArg(options::OPT_shared_libgcc)) return LibGccType::SharedLibGcc; - // The Android NDK only provides libunwind.a, not libunwind.so. - if (TC.getTriple().isAndroid()) - return LibGccType::StaticLibGcc; - // For MinGW, don't imply a shared libgcc here, we only want to return - // SharedLibGcc if that was explicitly requested. - if (D.CCCIsCXX() && !TC.getTriple().isOSCygMing()) - return LibGccType::SharedLibGcc; return LibGccType::UnspecifiedLibGcc; } @@ -1419,18 +2141,25 @@ static LibGccType getLibGccType(const ToolChain &TC, const Driver &D, static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { ToolChain::UnwindLibType UNW = TC.GetUnwindLibType(Args); + // By default OHOS binaries are linked statically to libunwind. + if (TC.getTriple().isOHOSFamily() && UNW == ToolChain::UNW_CompilerRT) { + CmdArgs.push_back("-l:libunwind.a"); + return; + } + // Targets that don't use unwind libraries. if ((TC.getTriple().isAndroid() && UNW == ToolChain::UNW_Libgcc) || TC.getTriple().isOSIAMCU() || TC.getTriple().isOSBinFormatWasm() || - UNW == ToolChain::UNW_None) + TC.getTriple().isWindowsMSVCEnvironment() || UNW == ToolChain::UNW_None) return; LibGccType LGT = getLibGccType(TC, D, Args); bool AsNeeded = LGT == LibGccType::UnspecifiedLibGcc && + (UNW == ToolChain::UNW_CompilerRT || !D.CCCIsCXX()) && !TC.getTriple().isAndroid() && !TC.getTriple().isOSCygMing() && !TC.getTriple().isOSAIX(); if (AsNeeded) - CmdArgs.push_back(getAsNeededOption(TC, true)); + addAsNeededOption(TC, Args, CmdArgs, true); switch (UNW) { case ToolChain::UNW_None: @@ -1450,30 +2179,32 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-lunwind"); } else if (LGT == LibGccType::StaticLibGcc) { CmdArgs.push_back("-l:libunwind.a"); - } else if (TC.getTriple().isOSCygMing()) { - if (LGT == LibGccType::SharedLibGcc) + } else if (LGT == LibGccType::SharedLibGcc) { + if (TC.getTriple().isOSCygMing()) CmdArgs.push_back("-l:libunwind.dll.a"); else - // Let the linker choose between libunwind.dll.a and libunwind.a - // depending on what's available, and depending on the -static flag - CmdArgs.push_back("-lunwind"); + CmdArgs.push_back("-l:libunwind.so"); } else { - CmdArgs.push_back("-l:libunwind.so"); + // Let the linker choose between libunwind.so and libunwind.a + // depending on what's available, and depending on the -static flag + CmdArgs.push_back("-lunwind"); } break; } if (AsNeeded) - CmdArgs.push_back(getAsNeededOption(TC, false)); + addAsNeededOption(TC, Args, CmdArgs, false); } static void AddLibgcc(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { LibGccType LGT = getLibGccType(TC, D, Args); - if (LGT != LibGccType::SharedLibGcc) + if (LGT == LibGccType::StaticLibGcc || + (LGT == LibGccType::UnspecifiedLibGcc && !D.CCCIsCXX())) CmdArgs.push_back("-lgcc"); AddUnwindLibrary(TC, D, CmdArgs, Args); - if (LGT == LibGccType::SharedLibGcc) + if (LGT == LibGccType::SharedLibGcc || + (LGT == LibGccType::UnspecifiedLibGcc && D.CCCIsCXX())) CmdArgs.push_back("-lgcc"); } @@ -1492,9 +2223,10 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { // Issue error diagnostic if libgcc is explicitly specified // through command line as --rtlib option argument. - if (Args.hasArg(options::OPT_rtlib_EQ)) { + Arg *A = Args.getLastArg(options::OPT_rtlib_EQ); + if (A && A->getValue() != StringRef("platform")) { TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) - << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC"; + << A->getValue() << "MSVC"; } } else AddLibgcc(TC, D, CmdArgs, Args); @@ -1514,35 +2246,49 @@ SmallString<128> tools::getStatsFileName(const llvm::opt::ArgList &Args, const InputInfo &Input, const Driver &D) { const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ); - if (!A) + if (!A && !D.CCPrintInternalStats) return {}; - StringRef SaveStats = A->getValue(); SmallString<128> StatsFile; - if (SaveStats == "obj" && Output.isFilename()) { - StatsFile.assign(Output.getFilename()); - llvm::sys::path::remove_filename(StatsFile); - } else if (SaveStats != "cwd") { - D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; - return {}; - } + if (A) { + StringRef SaveStats = A->getValue(); + if (SaveStats == "obj" && Output.isFilename()) { + StatsFile.assign(Output.getFilename()); + llvm::sys::path::remove_filename(StatsFile); + } else if (SaveStats != "cwd") { + D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; + return {}; + } - StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); - llvm::sys::path::append(StatsFile, BaseName); - llvm::sys::path::replace_extension(StatsFile, "stats"); + StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); + llvm::sys::path::append(StatsFile, BaseName); + llvm::sys::path::replace_extension(StatsFile, "stats"); + } else { + assert(D.CCPrintInternalStats); + StatsFile.assign(D.CCPrintInternalStatReportFilename.empty() + ? "-" + : D.CCPrintInternalStatReportFilename); + } return StatsFile; } -void tools::addMultilibFlag(bool Enabled, const char *const Flag, +void tools::addMultilibFlag(bool Enabled, const StringRef Flag, Multilib::flags_list &Flags) { - Flags.push_back(std::string(Enabled ? "+" : "-") + Flag); + assert(Flag.front() == '-'); + if (Enabled) { + Flags.push_back(Flag.str()); + } else { + Flags.push_back(("!" + Flag.substr(1)).str()); + } } void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args, - ArgStringList &CmdArgs, bool IsLTO) { + ArgStringList &CmdArgs, bool IsLTO, + const StringRef PluginOptPrefix) { auto addArg = [&, IsLTO](const Twine &Arg) { if (IsLTO) { - CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg)); + assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!"); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg)); } else { CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString(Arg)); @@ -1588,28 +2334,325 @@ void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args, } } +/// SDLSearch: Search for Static Device Library +/// The search for SDL bitcode files is consistent with how static host +/// libraries are discovered. That is, the -l option triggers a search for +/// files in a set of directories called the LINKPATH. The host library search +/// procedure looks for a specific filename in the LINKPATH. The filename for +/// a host library is lib<libname>.a or lib<libname>.so. For SDLs, there is an +/// ordered-set of filenames that are searched. We call this ordered-set of +/// filenames as SEARCH-ORDER. Since an SDL can either be device-type specific, +/// architecture specific, or generic across all architectures, a naming +/// convention and search order is used where the file name embeds the +/// architecture name <arch-name> (nvptx or amdgcn) and the GPU device type +/// <device-name> such as sm_30 and gfx906. <device-name> is absent in case of +/// device-independent SDLs. To reduce congestion in host library directories, +/// the search first looks for files in the “libdevice” subdirectory. SDLs that +/// are bc files begin with the prefix “lib”. +/// +/// Machine-code SDLs can also be managed as an archive (*.a file). The +/// convention has been to use the prefix “lib”. To avoid confusion with host +/// archive libraries, we use prefix "libbc-" for the bitcode SDL archives. +/// +static bool SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const SmallVectorImpl<std::string> &LibraryPaths, + StringRef Lib, StringRef Arch, StringRef Target, + bool isBitCodeSDL) { + SmallVector<std::string, 12> SDLs; + + std::string LibDeviceLoc = "/libdevice"; + std::string LibBcPrefix = "/libbc-"; + std::string LibPrefix = "/lib"; + + if (isBitCodeSDL) { + // SEARCH-ORDER for Bitcode SDLs: + // libdevice/libbc-<libname>-<arch-name>-<device-type>.a + // libbc-<libname>-<arch-name>-<device-type>.a + // libdevice/libbc-<libname>-<arch-name>.a + // libbc-<libname>-<arch-name>.a + // libdevice/libbc-<libname>.a + // libbc-<libname>.a + // libdevice/lib<libname>-<arch-name>-<device-type>.bc + // lib<libname>-<arch-name>-<device-type>.bc + // libdevice/lib<libname>-<arch-name>.bc + // lib<libname>-<arch-name>.bc + // libdevice/lib<libname>.bc + // lib<libname>.bc + + for (StringRef Base : {LibBcPrefix, LibPrefix}) { + const auto *Ext = Base.contains(LibBcPrefix) ? ".a" : ".bc"; + + for (auto Suffix : {Twine(Lib + "-" + Arch + "-" + Target).str(), + Twine(Lib + "-" + Arch).str(), Twine(Lib).str()}) { + SDLs.push_back(Twine(LibDeviceLoc + Base + Suffix + Ext).str()); + SDLs.push_back(Twine(Base + Suffix + Ext).str()); + } + } + } else { + // SEARCH-ORDER for Machine-code SDLs: + // libdevice/lib<libname>-<arch-name>-<device-type>.a + // lib<libname>-<arch-name>-<device-type>.a + // libdevice/lib<libname>-<arch-name>.a + // lib<libname>-<arch-name>.a + + const auto *Ext = ".a"; + + for (auto Suffix : {Twine(Lib + "-" + Arch + "-" + Target).str(), + Twine(Lib + "-" + Arch).str()}) { + SDLs.push_back(Twine(LibDeviceLoc + LibPrefix + Suffix + Ext).str()); + SDLs.push_back(Twine(LibPrefix + Suffix + Ext).str()); + } + } + + // The CUDA toolchain does not use a global device llvm-link before the LLVM + // backend generates ptx. So currently, the use of bitcode SDL for nvptx is + // only possible with post-clang-cc1 linking. Clang cc1 has a feature that + // will link libraries after clang compilation while the LLVM IR is still in + // memory. This utilizes a clang cc1 option called “-mlink-builtin-bitcode”. + // This is a clang -cc1 option that is generated by the clang driver. The + // option value must a full path to an existing file. + bool FoundSDL = false; + for (auto LPath : LibraryPaths) { + for (auto SDL : SDLs) { + auto FullName = Twine(LPath + SDL).str(); + if (llvm::sys::fs::exists(FullName)) { + CC1Args.push_back(DriverArgs.MakeArgString(FullName)); + FoundSDL = true; + break; + } + } + if (FoundSDL) + break; + } + return FoundSDL; +} + +/// Search if a user provided archive file lib<libname>.a exists in any of +/// the library paths. If so, add a new command to clang-offload-bundler to +/// unbundle this archive and create a temporary device specific archive. Name +/// of this SDL is passed to the llvm-link tool. +static void GetSDLFromOffloadArchive( + Compilation &C, const Driver &D, const Tool &T, const JobAction &JA, + const InputInfoList &Inputs, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const SmallVectorImpl<std::string> &LibraryPaths, StringRef Lib, + StringRef Arch, StringRef Target, bool isBitCodeSDL) { + + // We don't support bitcode archive bundles for nvptx + if (isBitCodeSDL && Arch.contains("nvptx")) + return; + + bool FoundAOB = false; + std::string ArchiveOfBundles; + + llvm::Triple Triple(D.getTargetTriple()); + bool IsMSVC = Triple.isWindowsMSVCEnvironment(); + auto Ext = IsMSVC ? ".lib" : ".a"; + if (!Lib.starts_with(":") && !Lib.starts_with("-l")) { + if (llvm::sys::fs::exists(Lib)) { + ArchiveOfBundles = Lib; + FoundAOB = true; + } + } else { + Lib.consume_front("-l"); + for (auto LPath : LibraryPaths) { + ArchiveOfBundles.clear(); + auto LibFile = (Lib.starts_with(":") ? Lib.drop_front() + : IsMSVC ? Lib + Ext + : "lib" + Lib + Ext) + .str(); + for (auto Prefix : {"/libdevice/", "/"}) { + auto AOB = Twine(LPath + Prefix + LibFile).str(); + if (llvm::sys::fs::exists(AOB)) { + ArchiveOfBundles = AOB; + FoundAOB = true; + break; + } + } + if (FoundAOB) + break; + } + } + + if (!FoundAOB) + return; + + llvm::file_magic Magic; + auto EC = llvm::identify_magic(ArchiveOfBundles, Magic); + if (EC || Magic != llvm::file_magic::archive) + return; + + StringRef Prefix = isBitCodeSDL ? "libbc-" : "lib"; + std::string OutputLib = + D.GetTemporaryPath(Twine(Prefix + llvm::sys::path::filename(Lib) + "-" + + Arch + "-" + Target) + .str(), + "a"); + + C.addTempFile(C.getArgs().MakeArgString(OutputLib)); + + ArgStringList CmdArgs; + SmallString<128> DeviceTriple; + DeviceTriple += Action::GetOffloadKindName(JA.getOffloadingDeviceKind()); + DeviceTriple += '-'; + std::string NormalizedTriple = T.getToolChain().getTriple().normalize(); + DeviceTriple += NormalizedTriple; + if (!Target.empty()) { + DeviceTriple += '-'; + DeviceTriple += Target; + } + + std::string UnbundleArg("-unbundle"); + std::string TypeArg("-type=a"); + std::string InputArg("-input=" + ArchiveOfBundles); + std::string OffloadArg("-targets=" + std::string(DeviceTriple)); + std::string OutputArg("-output=" + OutputLib); + + const char *UBProgram = DriverArgs.MakeArgString( + T.getToolChain().GetProgramPath("clang-offload-bundler")); + + ArgStringList UBArgs; + UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg)); + UBArgs.push_back(C.getArgs().MakeArgString(TypeArg)); + UBArgs.push_back(C.getArgs().MakeArgString(InputArg)); + UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg)); + UBArgs.push_back(C.getArgs().MakeArgString(OutputArg)); + + // Add this flag to not exit from clang-offload-bundler if no compatible + // code object is found in heterogenous archive library. + std::string AdditionalArgs("-allow-missing-bundles"); + UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs)); + + // Add this flag to treat hip and hipv4 offload kinds as compatible with + // openmp offload kind while extracting code objects from a heterogenous + // archive library. Vice versa is also considered compatible. + std::string HipCompatibleArgs("-hip-openmp-compatible"); + UBArgs.push_back(C.getArgs().MakeArgString(HipCompatibleArgs)); + + C.addCommand(std::make_unique<Command>( + JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs, + InputInfo(&JA, C.getArgs().MakeArgString(OutputLib)))); + + CC1Args.push_back(DriverArgs.MakeArgString(OutputLib)); + + return; +} + +// Wrapper function used by driver for adding SDLs during link phase. +void tools::AddStaticDeviceLibsLinking(Compilation &C, const Tool &T, + const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Arch, StringRef Target, + bool isBitCodeSDL) { + AddStaticDeviceLibs(&C, &T, &JA, &Inputs, C.getDriver(), DriverArgs, CC1Args, + Arch, Target, isBitCodeSDL); +} + +// User defined Static Device Libraries(SDLs) can be passed to clang for +// offloading GPU compilers. Like static host libraries, the use of a SDL is +// specified with the -l command line option. The primary difference between +// host and SDLs is the filenames for SDLs (refer SEARCH-ORDER for Bitcode SDLs +// and SEARCH-ORDER for Machine-code SDLs for the naming convention). +// SDLs are of following types: +// +// * Bitcode SDLs: They can either be a *.bc file or an archive of *.bc files. +// For NVPTX, these libraries are post-clang linked following each +// compilation. For AMDGPU, these libraries are linked one time +// during the application link phase. +// +// * Machine-code SDLs: They are archive files. For AMDGPU, the process for +// machine code SDLs is still in development. But they will be linked +// by the LLVM tool lld. +// +// * Bundled objects that contain both host and device codes: Bundled objects +// may also contain library code compiled from source. For NVPTX, the +// bundle contains cubin. For AMDGPU, the bundle contains bitcode. +// +// For Bitcode and Machine-code SDLs, current compiler toolchains hardcode the +// inclusion of specific SDLs such as math libraries and the OpenMP device +// library libomptarget. +void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T, + const JobAction *JA, + const InputInfoList *Inputs, const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Arch, StringRef Target, + bool isBitCodeSDL) { + + SmallVector<std::string, 8> LibraryPaths; + // Add search directories from LIBRARY_PATH env variable + std::optional<std::string> LibPath = + llvm::sys::Process::GetEnv("LIBRARY_PATH"); + if (LibPath) { + SmallVector<StringRef, 8> Frags; + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; + llvm::SplitString(*LibPath, Frags, EnvPathSeparatorStr); + for (StringRef Path : Frags) + LibraryPaths.emplace_back(Path.trim()); + } + + // Add directories from user-specified -L options + for (std::string Search_Dir : DriverArgs.getAllArgValues(options::OPT_L)) + LibraryPaths.emplace_back(Search_Dir); + + // Add path to lib-debug folders + SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir); + llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME); + LibraryPaths.emplace_back(DefaultLibPath.c_str()); + + // Build list of Static Device Libraries SDLs specified by -l option + llvm::SmallSet<std::string, 16> SDLNames; + static const StringRef HostOnlyArchives[] = { + "omp", "cudart", "m", "gcc", "gcc_s", "pthread", "hip_hcc"}; + for (auto SDLName : DriverArgs.getAllArgValues(options::OPT_l)) { + if (!llvm::is_contained(HostOnlyArchives, SDLName)) { + SDLNames.insert(std::string("-l") + SDLName); + } + } + + for (auto Input : DriverArgs.getAllArgValues(options::OPT_INPUT)) { + auto FileName = StringRef(Input); + // Clang treats any unknown file types as archives and passes them to the + // linker. Files with extension 'lib' are classified as TY_Object by clang + // but they are usually archives. It is OK if the file is not really an + // archive since GetSDLFromOffloadArchive will check the magic of the file + // and only unbundle it if it is really an archive. + const StringRef LibFileExt = ".lib"; + if (!llvm::sys::path::has_extension(FileName) || + types::lookupTypeForExtension( + llvm::sys::path::extension(FileName).drop_front()) == + types::TY_INVALID || + llvm::sys::path::extension(FileName) == LibFileExt) + SDLNames.insert(Input); + } + + // The search stops as soon as an SDL file is found. The driver then provides + // the full filename of the SDL to the llvm-link command. If no SDL is found + // after searching each LINKPATH with SEARCH-ORDER, it is possible that an + // archive file lib<libname>.a exists and may contain bundled object files. + for (auto SDLName : SDLNames) { + // This is the only call to SDLSearch + if (!SDLSearch(D, DriverArgs, CC1Args, LibraryPaths, SDLName, Arch, Target, + isBitCodeSDL)) { + GetSDLFromOffloadArchive(*C, D, *T, *JA, *Inputs, DriverArgs, CC1Args, + LibraryPaths, SDLName, Arch, Target, + isBitCodeSDL); + } + } +} + static llvm::opt::Arg * getAMDGPUCodeObjectArgument(const Driver &D, const llvm::opt::ArgList &Args) { - // The last of -mcode-object-v3, -mno-code-object-v3 and - // -mcode-object-version=<version> wins. - return Args.getLastArg(options::OPT_mcode_object_v3_legacy, - options::OPT_mno_code_object_v3_legacy, - options::OPT_mcode_object_version_EQ); + return Args.getLastArg(options::OPT_mcode_object_version_EQ); } void tools::checkAMDGPUCodeObjectVersion(const Driver &D, const llvm::opt::ArgList &Args) { - const unsigned MinCodeObjVer = 2; - const unsigned MaxCodeObjVer = 4; - - // Emit warnings for legacy options even if they are overridden. - if (Args.hasArg(options::OPT_mno_code_object_v3_legacy)) - D.Diag(diag::warn_drv_deprecated_arg) << "-mno-code-object-v3" - << "-mcode-object-version=2"; - - if (Args.hasArg(options::OPT_mcode_object_v3_legacy)) - D.Diag(diag::warn_drv_deprecated_arg) << "-mcode-object-v3" - << "-mcode-object-version=3"; + const unsigned MinCodeObjVer = 4; + const unsigned MaxCodeObjVer = 5; if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) { if (CodeObjArg->getOption().getID() == @@ -1627,17 +2670,8 @@ void tools::checkAMDGPUCodeObjectVersion(const Driver &D, unsigned tools::getAMDGPUCodeObjectVersion(const Driver &D, const llvm::opt::ArgList &Args) { unsigned CodeObjVer = 4; // default - if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) { - if (CodeObjArg->getOption().getID() == - options::OPT_mno_code_object_v3_legacy) { - CodeObjVer = 2; - } else if (CodeObjArg->getOption().getID() == - options::OPT_mcode_object_v3_legacy) { - CodeObjVer = 3; - } else { - StringRef(CodeObjArg->getValue()).getAsInteger(0, CodeObjVer); - } - } + if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) + StringRef(CodeObjArg->getValue()).getAsInteger(0, CodeObjVer); return CodeObjVer; } @@ -1649,10 +2683,12 @@ bool tools::haveAMDGPUCodeObjectVersionArgument( void tools::addMachineOutlinerArgs(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - const llvm::Triple &Triple, bool IsLTO) { + const llvm::Triple &Triple, bool IsLTO, + const StringRef PluginOptPrefix) { auto addArg = [&, IsLTO](const Twine &Arg) { if (IsLTO) { - CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg)); + assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!"); + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg)); } else { CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString(Arg)); @@ -1665,9 +2701,7 @@ void tools::addMachineOutlinerArgs(const Driver &D, // We only support -moutline in AArch64 and ARM targets right now. If // we're not compiling for these, emit a warning and ignore the flag. // Otherwise, add the proper mllvm flags. - if (!(Triple.isARM() || Triple.isThumb() || - Triple.getArch() == llvm::Triple::aarch64 || - Triple.getArch() == llvm::Triple::aarch64_32)) { + if (!(Triple.isARM() || Triple.isThumb() || Triple.isAArch64())) { D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName(); } else { addArg(Twine("-enable-machine-outliner")); @@ -1685,8 +2719,14 @@ void tools::addOpenMPDeviceRTL(const Driver &D, StringRef BitcodeSuffix, const llvm::Triple &Triple) { SmallVector<StringRef, 8> LibraryPaths; + + // Add path to clang lib / lib64 folder. + SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir); + llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME); + LibraryPaths.emplace_back(DefaultLibPath.c_str()); + // Add user defined library paths from LIBRARY_PATH. - llvm::Optional<std::string> LibPath = + std::optional<std::string> LibPath = llvm::sys::Process::GetEnv("LIBRARY_PATH"); if (LibPath) { SmallVector<StringRef, 8> Frags; @@ -1696,32 +2736,32 @@ void tools::addOpenMPDeviceRTL(const Driver &D, LibraryPaths.emplace_back(Path.trim()); } - // Add path to lib / lib64 folder. - SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir); - llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX); - LibraryPaths.emplace_back(DefaultLibPath.c_str()); - 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"; + 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)) { - std::string LibOmpTargetName(A->getValue()); - if (llvm::sys::fs::exists(LibOmpTargetName)) { + SmallString<128> LibOmpTargetFile(A->getValue()); + if (llvm::sys::fs::exists(LibOmpTargetFile) && + llvm::sys::fs::is_directory(LibOmpTargetFile)) { + llvm::sys::path::append(LibOmpTargetFile, LibOmpTargetName); + } + + if (llvm::sys::fs::exists(LibOmpTargetFile)) { CC1Args.push_back("-mlink-builtin-bitcode"); - CC1Args.push_back(DriverArgs.MakeArgString(LibOmpTargetName)); + CC1Args.push_back(DriverArgs.MakeArgString(LibOmpTargetFile)); } else { D.Diag(diag::err_drv_omp_offload_target_bcruntime_not_found) - << LibOmpTargetName; + << LibOmpTargetFile; } } else { bool FoundBCLibrary = false; - std::string LibOmpTargetName = - "libomptarget-" + BitcodeSuffix.str() + ".bc"; - for (StringRef LibraryPath : LibraryPaths) { SmallString<128> LibOmpTargetFile(LibraryPath); llvm::sys::path::append(LibOmpTargetFile, LibOmpTargetName); @@ -1738,3 +2778,17 @@ void tools::addOpenMPDeviceRTL(const Driver &D, << LibOmpTargetName << ArchPrefix; } } +void tools::addHIPRuntimeLibArgs(const ToolChain &TC, Compilation &C, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) { + if ((C.getActiveOffloadKinds() & Action::OFK_HIP) && + !Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_no_hip_rt)) { + TC.AddHIPRuntimeLibArgs(Args, CmdArgs); + } else { + // Claim "no HIP libraries" arguments if any + for (auto *Arg : Args.filtered(options::OPT_no_hip_rt)) { + Arg->claim(); + } + } +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h index c94c15864661..807867f13a5c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.h @@ -9,11 +9,15 @@ #ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H +#include "clang/Basic/CodeGenOptions.h" #include "clang/Driver/Driver.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Multilib.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" namespace clang { @@ -37,18 +41,32 @@ bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); void linkSanitizerRuntimeDeps(const ToolChain &TC, + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); bool addXRayRuntime(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); -void linkXRayRuntimeDeps(const ToolChain &TC, +void linkXRayRuntimeDeps(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); void AddRunTimeLibs(const ToolChain &TC, const Driver &D, llvm::opt::ArgStringList &CmdArgs, const llvm::opt::ArgList &Args); +void AddStaticDeviceLibsLinking(Compilation &C, const Tool &T, + const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, + StringRef Arch, StringRef Target, + bool isBitCodeSDL); +void AddStaticDeviceLibs(Compilation *C, const Tool *T, const JobAction *JA, + const InputInfoList *Inputs, const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, StringRef Arch, + StringRef Target, bool isBitCodeSDL); + const char *SplitDebugName(const JobAction &JA, const llvm::opt::ArgList &Args, const InputInfo &Input, const InputInfo &Output); @@ -60,14 +78,28 @@ void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO); +const char *RelocationModelName(llvm::Reloc::Model Model); + std::tuple<llvm::Reloc::Model, unsigned, bool> ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args); unsigned ParseFunctionAlignment(const ToolChain &TC, const llvm::opt::ArgList &Args); -unsigned ParseDebugDefaultVersion(const ToolChain &TC, - const llvm::opt::ArgList &Args); +void addDebugInfoKind(llvm::opt::ArgStringList &CmdArgs, + llvm::codegenoptions::DebugInfoKind DebugInfoKind); + +llvm::codegenoptions::DebugInfoKind +debugLevelToInfoKind(const llvm::opt::Arg &A); + +// Extract the integer N from a string spelled "-dwarf-N", returning 0 +// on mismatch. The StringRef input (rather than an Arg) allows +// for use by the "-Xassembler" option parser. +unsigned DwarfVersionNum(StringRef ArgValue); +// Find a DWARF format version option. +// This function is a complementary for DwarfVersionNum(). +const llvm::opt::Arg *getDwarfNArg(const llvm::opt::ArgList &Args); +unsigned getDwarfVersion(const ToolChain &TC, const llvm::opt::ArgList &Args); void AddAssemblerKPIC(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, @@ -75,12 +107,32 @@ void AddAssemblerKPIC(const ToolChain &ToolChain, 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, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + +/// Adds the path for the Fortran runtime libraries to \p CmdArgs. +void addFortranRuntimeLibraryPath(const ToolChain &TC, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + +void addHIPRuntimeLibArgs(const ToolChain &TC, Compilation &C, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + +void addAsNeededOption(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, bool as_needed); + +llvm::opt::Arg *getLastCSProfileGenerateArg(const llvm::opt::ArgList &Args); llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args); llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args); @@ -92,6 +144,9 @@ llvm::StringRef getLTOParallelism(const llvm::opt::ArgList &Args, bool areOptimizationsEnabled(const llvm::opt::ArgList &Args); bool isUseSeparateSections(const llvm::Triple &Triple); +// Parse -mtls-dialect=. Return true if the target supports both general-dynamic +// and TLSDESC, and TLSDESC is requested. +bool isTLSDESCEnabled(const ToolChain &TC, const llvm::opt::ArgList &Args); /// \p EnvVar is split by system delimiter for environment variables. /// If \p ArgName is "-I", "-L", or an empty string, each entry from \p EnvVar @@ -107,8 +162,13 @@ void AddTargetFeature(const llvm::opt::ArgList &Args, llvm::opt::OptSpecifier OnOpt, llvm::opt::OptSpecifier OffOpt, StringRef FeatureName); -std::string getCPUName(const llvm::opt::ArgList &Args, const llvm::Triple &T, - bool FromAs = false); +std::string getCPUName(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &T, bool FromAs = false); + +void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, bool ForAS, + bool IsAux = false); /// Iterate \p Args and convert -mxxx to +xxx and -mno-xxx to -xxx and /// append it to \p Features. @@ -116,13 +176,13 @@ std::string getCPUName(const llvm::opt::ArgList &Args, const llvm::Triple &T, /// Note: Since \p Features may contain default values before calling /// this function, or may be appended with entries to override arguments, /// entries in \p Features are not unique. -void handleTargetFeaturesGroup(const llvm::opt::ArgList &Args, +void handleTargetFeaturesGroup(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, std::vector<StringRef> &Features, llvm::opt::OptSpecifier Group); /// If there are multiple +xxx or -xxx features, keep the last one. -std::vector<StringRef> -unifyTargetFeatures(const std::vector<StringRef> &Features); +SmallVector<StringRef> unifyTargetFeatures(ArrayRef<StringRef> Features); /// Handles the -save-stats option and returns the filename to save statistics /// to. @@ -130,13 +190,13 @@ SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args, const InputInfo &Output, const InputInfo &Input, const Driver &D); -/// \p Flag must be a flag accepted by the driver with its leading '-' removed, -// otherwise '-print-multi-lib' will not emit them correctly. -void addMultilibFlag(bool Enabled, const char *const Flag, +/// \p Flag must be a flag accepted by the driver. +void addMultilibFlag(bool Enabled, const StringRef Flag, Multilib::flags_list &Flags); void addX86AlignBranchArgs(const Driver &D, const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, bool IsLTO); + llvm::opt::ArgStringList &CmdArgs, bool IsLTO, + const StringRef PluginOptPrefix = ""); void checkAMDGPUCodeObjectVersion(const Driver &D, const llvm::opt::ArgList &Args); @@ -149,7 +209,8 @@ bool haveAMDGPUCodeObjectVersionArgument(const Driver &D, void addMachineOutlinerArgs(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - const llvm::Triple &Triple, bool IsLTO); + const llvm::Triple &Triple, bool IsLTO, + const StringRef PluginOptPrefix = ""); void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, @@ -158,4 +219,7 @@ void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs, } // end namespace driver } // end namespace clang +clang::CodeGenOptions::FramePointerKind +getFramePointerKind(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); + #endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp deleted file mode 100644 index 5dda1b1b09fb..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.cpp +++ /dev/null @@ -1,27 +0,0 @@ -//===--- Contiki.cpp - Contiki ToolChain Implementations --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Contiki.h" -#include "CommonArgs.h" - -using namespace clang::driver; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -Contiki::Contiki(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) {} - -SanitizerMask Contiki::getSupportedSanitizers() const { - const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - if (IsX86) - Res |= SanitizerKind::SafeStack; - return Res; -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h deleted file mode 100644 index 627d80bdda09..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Contiki.h +++ /dev/null @@ -1,39 +0,0 @@ -//===--- Contiki.h - Contiki ToolChain Implementations ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H - -#include "Gnu.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY Contiki : public Generic_ELF { -public: - Contiki(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - // No support for finding a C++ standard library yet. - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} - - SanitizerMask getSupportedSanitizers() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp index 07abf4f83f7d..3c5dfba329cf 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp @@ -94,7 +94,8 @@ void tools::CrossWindows::Linker::ConstructJob( CmdArgs.push_back("-m"); switch (TC.getArch()) { default: - llvm_unreachable("unsupported architecture"); + D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str(); + break; case llvm::Triple::arm: case llvm::Triple::thumb: // FIXME: this is incorrect for WinCE @@ -185,7 +186,7 @@ void tools::CrossWindows::Linker::ConstructJob( } } - if (TC.getSanitizerArgs().needsAsanRt()) { + if (TC.getSanitizerArgs(Args).needsAsanRt()) { // TODO handle /MT[d] /MD[d] if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); @@ -213,17 +214,18 @@ CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, const llvm::opt::ArgList &Args) : Generic_GCC(D, T, Args) {} -bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel +CrossWindowsToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const { // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does // not know how to emit them. - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 ? UnwindTableLevel::Asynchronous : UnwindTableLevel::None; } bool CrossWindowsToolChain::isPICDefault() const { return getArch() == llvm::Triple::x86_64; } -bool CrossWindowsToolChain::isPIEDefault() const { +bool CrossWindowsToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { return getArch() == llvm::Triple::x86_64; } @@ -273,8 +275,11 @@ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, void CrossWindowsToolChain:: AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { - if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); + } } clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const { diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h index ffe75332c2e8..c5df55a24296 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.h @@ -20,7 +20,7 @@ namespace driver { namespace tools { namespace CrossWindows { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("CrossWindows::Assembler", "as", TC) {} @@ -32,7 +32,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("CrossWindows::Linker", "ld", TC) {} @@ -54,10 +54,10 @@ public: CrossWindowsToolChain(const Driver &D, const llvm::Triple &T, const llvm::opt::ArgList &Args); - bool IsIntegratedAssemblerDefault() const override { return true; } - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; LangOptions::StackProtectorMode diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp index 769eae14df51..1462576ca870 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.cpp @@ -16,15 +16,17 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" -#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" -#include "llvm/Support/TargetParser.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/TargetParser.h" #include <system_error> using namespace clang::driver; @@ -34,25 +36,6 @@ using namespace clang; using namespace llvm::opt; namespace { -struct CudaVersionInfo { - std::string DetectedVersion; - CudaVersion Version; -}; -// Parses the contents of version.txt in an CUDA installation. It should -// contain one line of the from e.g. "CUDA Version 7.5.2". -CudaVersionInfo parseCudaVersionFile(llvm::StringRef V) { - V = V.trim(); - if (!V.startswith("CUDA Version ")) - return {V.str(), CudaVersion::UNKNOWN}; - V = V.substr(strlen("CUDA Version ")); - SmallVector<StringRef,4> VersionParts; - V.split(VersionParts, '.'); - return {"version.txt: " + V.str() + ".", - VersionParts.size() < 2 - ? CudaVersion::UNKNOWN - : CudaStringToVersion( - join_items(".", VersionParts[0], VersionParts[1]))}; -} CudaVersion getCudaVersion(uint32_t raw_version) { if (raw_version < 7050) @@ -77,15 +60,37 @@ CudaVersion getCudaVersion(uint32_t raw_version) { return CudaVersion::CUDA_110; if (raw_version < 11020) return CudaVersion::CUDA_111; - return CudaVersion::LATEST; + if (raw_version < 11030) + return CudaVersion::CUDA_112; + if (raw_version < 11040) + return CudaVersion::CUDA_113; + if (raw_version < 11050) + return CudaVersion::CUDA_114; + if (raw_version < 11060) + return CudaVersion::CUDA_115; + if (raw_version < 11070) + return CudaVersion::CUDA_116; + if (raw_version < 11080) + return CudaVersion::CUDA_117; + if (raw_version < 11090) + return CudaVersion::CUDA_118; + if (raw_version < 12010) + return CudaVersion::CUDA_120; + if (raw_version < 12020) + return CudaVersion::CUDA_121; + if (raw_version < 12030) + return CudaVersion::CUDA_122; + if (raw_version < 12040) + return CudaVersion::CUDA_123; + return CudaVersion::NEW; } -CudaVersionInfo parseCudaHFile(llvm::StringRef Input) { +CudaVersion parseCudaHFile(llvm::StringRef Input) { // Helper lambda which skips the words if the line starts with them or returns - // None otherwise. + // std::nullopt otherwise. auto StartsWithWords = [](llvm::StringRef Line, - const SmallVector<StringRef, 3> words) -> llvm::Optional<StringRef> { + const SmallVector<StringRef, 3> words) -> std::optional<StringRef> { for (StringRef word : words) { if (!Line.consume_front(word)) return {}; @@ -100,21 +105,27 @@ CudaVersionInfo parseCudaHFile(llvm::StringRef Input) { StartsWithWords(Input.ltrim(), {"#", "define", "CUDA_VERSION"})) { uint32_t RawVersion; Line->consumeInteger(10, RawVersion); - return {"cuda.h: CUDA_VERSION=" + Twine(RawVersion).str() + ".", - getCudaVersion(RawVersion)}; + return getCudaVersion(RawVersion); } // Find next non-empty line. Input = Input.drop_front(Input.find_first_of("\n\r")).ltrim(); } - return {"cuda.h: CUDA_VERSION not found.", CudaVersion::UNKNOWN}; + return CudaVersion::UNKNOWN; } } // namespace void CudaInstallationDetector::WarnIfUnsupportedVersion() { - if (DetectedVersionIsNotSupported) - D.Diag(diag::warn_drv_unknown_cuda_version) - << DetectedVersion - << CudaVersionToString(CudaVersion::LATEST_SUPPORTED); + if (Version > CudaVersion::PARTIALLY_SUPPORTED) { + std::string VersionString = CudaVersionToString(Version); + if (!VersionString.empty()) + VersionString.insert(0, " "); + D.Diag(diag::warn_drv_new_cuda_version) + << VersionString + << (CudaVersion::PARTIALLY_SUPPORTED != CudaVersion::FULLY_SUPPORTED) + << CudaVersionToString(CudaVersion::PARTIALLY_SUPPORTED); + } else if (Version > CudaVersion::FULLY_SUPPORTED) + D.Diag(diag::warn_drv_partially_supported_cuda_version) + << CudaVersionToString(Version); } CudaInstallationDetector::CudaInstallationDetector( @@ -193,44 +204,17 @@ CudaInstallationDetector::CudaInstallationDetector( if (CheckLibDevice && !FS.exists(LibDevicePath)) continue; - // On Linux, we have both lib and lib64 directories, and we need to choose - // based on our triple. On MacOS, we have only a lib directory. - // - // It's sufficient for our purposes to be flexible: If both lib and lib64 - // exist, we choose whichever one matches our triple. Otherwise, if only - // lib exists, we use it. - if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64")) - LibPath = InstallPath + "/lib64"; - else if (FS.exists(InstallPath + "/lib")) - LibPath = InstallPath + "/lib"; - else - continue; - - CudaVersionInfo VersionInfo = {"", CudaVersion::UNKNOWN}; - if (auto VersionFile = FS.getBufferForFile(InstallPath + "/version.txt")) - VersionInfo = parseCudaVersionFile((*VersionFile)->getBuffer()); - // If version file didn't give us the version, try to find it in cuda.h - if (VersionInfo.Version == CudaVersion::UNKNOWN) - if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h")) - VersionInfo = parseCudaHFile((*CudaHFile)->getBuffer()); - // As the last resort, make an educated guess between CUDA-7.0, (which had - // no version.txt file and had old-style libdevice bitcode ) and an unknown - // recent CUDA version (no version.txt, new style bitcode). - if (VersionInfo.Version == CudaVersion::UNKNOWN) { - VersionInfo.Version = (FS.exists(LibDevicePath + "/libdevice.10.bc")) - ? Version = CudaVersion::LATEST - : Version = CudaVersion::CUDA_70; - VersionInfo.DetectedVersion = - "No version found in version.txt or cuda.h."; + Version = CudaVersion::UNKNOWN; + if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h")) + Version = parseCudaHFile((*CudaHFile)->getBuffer()); + // As the last resort, make an educated guess between CUDA-7.0, which had + // old-style libdevice bitcode, and an unknown recent CUDA version. + if (Version == CudaVersion::UNKNOWN) { + Version = FS.exists(LibDevicePath + "/libdevice.10.bc") + ? CudaVersion::NEW + : CudaVersion::CUDA_70; } - Version = VersionInfo.Version; - DetectedVersion = VersionInfo.DetectedVersion; - - // TODO(tra): remove the warning once we have all features of 10.2 - // and 11.0 implemented. - DetectedVersionIsNotSupported = Version > CudaVersion::LATEST_SUPPORTED; - if (Version >= CudaVersion::CUDA_90) { // CUDA-9+ uses single libdevice file for all GPU variants. std::string FilePath = LibDevicePath + "/libdevice.10.bc"; @@ -254,7 +238,7 @@ CudaInstallationDetector::CudaInstallationDetector( // Process all bitcode filenames that look like // libdevice.compute_XX.YY.bc const StringRef LibDeviceName = "libdevice."; - if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) + if (!(FileName.starts_with(LibDeviceName) && FileName.ends_with(".bc"))) continue; StringRef GpuArch = FileName.slice( LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); @@ -319,8 +303,6 @@ void CudaInstallationDetector::AddCudaIncludeArgs( return; } - CC1Args.push_back("-internal-isystem"); - CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); CC1Args.push_back("-include"); CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); } @@ -395,18 +377,20 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { const auto &TC = - static_cast<const toolchains::CudaToolChain &>(getToolChain()); + static_cast<const toolchains::NVPTXToolChain &>(getToolChain()); assert(TC.getTriple().isNVPTX() && "Wrong platform"); StringRef GPUArchName; - // If this is an OpenMP action we need to extract the device architecture - // from the -march=arch option. This option may come from -Xopenmp-target - // flag or the default value. - if (JA.isDeviceOffloading(Action::OFK_OpenMP)) { + // If this is a CUDA action we need to extract the device architecture + // from the Job's associated architecture, otherwise use the -march=arch + // option. This option may come from -Xopenmp-target flag or the default + // value. + if (JA.isDeviceOffloading(Action::OFK_Cuda)) { + GPUArchName = JA.getOffloadingArch(); + } else { GPUArchName = Args.getLastArgValue(options::OPT_march_EQ); assert(!GPUArchName.empty() && "Must have an architecture passed in."); - } else - GPUArchName = JA.getOffloadingArch(); + } // Obtain architecture from the action. CudaArch gpu_arch = StringToCudaArch(GPUArchName); @@ -467,22 +451,38 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--gpu-name"); CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch))); CmdArgs.push_back("--output-file"); - CmdArgs.push_back(Args.MakeArgString(TC.getInputFilename(Output))); - for (const auto& II : Inputs) + std::string OutputFileName = TC.getInputFilename(Output); + + // If we are invoking `nvlink` internally we need to output a `.cubin` file. + // FIXME: This should hopefully be removed if NVIDIA updates their tooling. + if (!C.getInputArgs().getLastArg(options::OPT_c)) { + SmallString<256> Filename(Output.getFilename()); + llvm::sys::path::replace_extension(Filename, "cubin"); + OutputFileName = Filename.str(); + } + if (Output.isFilename() && OutputFileName != Output.getFilename()) + C.addTempFile(Args.MakeArgString(OutputFileName)); + + CmdArgs.push_back(Args.MakeArgString(OutputFileName)); + for (const auto &II : Inputs) CmdArgs.push_back(Args.MakeArgString(II.getFilename())); - for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) + for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) CmdArgs.push_back(Args.MakeArgString(A)); - bool Relocatable = false; + bool Relocatable; if (JA.isOffloading(Action::OFK_OpenMP)) // In OpenMP we need to generate relocatable code. Relocatable = Args.hasFlag(options::OPT_fopenmp_relocatable_target, options::OPT_fnoopenmp_relocatable_target, /*Default=*/true); else if (JA.isOffloading(Action::OFK_Cuda)) - Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, - options::OPT_fno_gpu_rdc, /*Default=*/false); + // In CUDA we generate relocatable code by default. + Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + /*Default=*/false); + else + // Otherwise, we are compiling directly and should create linkable output. + Relocatable = true; if (Relocatable) CmdArgs.push_back("-c"); @@ -518,11 +518,11 @@ static bool shouldIncludePTX(const ArgList &Args, const char *gpu_arch) { // All inputs to this linker must be from CudaDeviceActions, as we need to look // at the Inputs' Actions in order to figure out which GPU architecture they // correspond to. -void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void NVPTX::FatBinary::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const auto &TC = static_cast<const toolchains::CudaToolChain &>(getToolChain()); assert(TC.getTriple().isNVPTX() && "Wrong platform"); @@ -536,7 +536,7 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost) CmdArgs.push_back("-g"); - for (const auto& II : Inputs) { + for (const auto &II : Inputs) { auto *A = II.getAction(); assert(A->getInputs().size() == 1 && "Device offload action is expected to have a single input"); @@ -553,11 +553,12 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *Arch = (II.getType() == types::TY_PP_Asm) ? CudaArchToVirtualArchString(gpu_arch) : gpu_arch_str; - CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") + - Arch + ",file=" + II.getFilename())); + CmdArgs.push_back( + Args.MakeArgString(llvm::Twine("--image=profile=") + Arch + + ",file=" + getToolChain().getInputFilename(II))); } - for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary)) + for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary)) CmdArgs.push_back(Args.MakeArgString(A)); const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary")); @@ -568,36 +569,31 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, Exec, CmdArgs, Inputs, Output)); } -void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { +void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const auto &TC = - static_cast<const toolchains::CudaToolChain &>(getToolChain()); - assert(TC.getTriple().isNVPTX() && "Wrong platform"); - + static_cast<const toolchains::NVPTXToolChain &>(getToolChain()); ArgStringList CmdArgs; - // OpenMP uses nvlink to link cubin files. The result will be embedded in the - // host binary by the host linker. - assert(!JA.isHostOffloading(Action::OFK_OpenMP) && - "CUDA toolchain not expected for an OpenMP host device."); + assert(TC.getTriple().isNVPTX() && "Wrong platform"); + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else - assert(Output.isNothing() && "Invalid output."); + } + if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost) CmdArgs.push_back("-g"); if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-v"); - StringRef GPUArch = - Args.getLastArgValue(options::OPT_march_EQ); - assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas."); + StringRef GPUArch = Args.getLastArgValue(options::OPT_march_EQ); + assert(!GPUArch.empty() && "At least one GPU Arch required for nvlink."); CmdArgs.push_back("-arch"); CmdArgs.push_back(Args.MakeArgString(GPUArch)); @@ -608,14 +604,12 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, // Add paths for the default clang library path. SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(TC.getDriver().Dir); - llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX); + llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME); CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath)); for (const auto &II : Inputs) { - if (II.getType() == types::TY_LLVM_IR || - II.getType() == types::TY_LTO_IR || - II.getType() == types::TY_LTO_BC || - II.getType() == types::TY_LLVM_BC) { + if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || + II.getType() == types::TY_LTO_BC || II.getType() == types::TY_LLVM_BC) { C.getDriver().Diag(diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); continue; @@ -626,56 +620,179 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, if (!II.isFilename()) continue; - const char *CubinF = C.addTempFile( - C.getArgs().MakeArgString(getToolChain().getInputFilename(II))); + // The 'nvlink' application performs RDC-mode linking when given a '.o' + // file and device linking when given a '.cubin' file. We always want to + // perform device linking, so just rename any '.o' files. + // FIXME: This should hopefully be removed if NVIDIA updates their tooling. + auto InputFile = getToolChain().getInputFilename(II); + if (llvm::sys::path::extension(InputFile) != ".cubin") { + // If there are no actions above this one then this is direct input and we + // can copy it. Otherwise the input is internal so a `.cubin` file should + // exist. + if (II.getAction() && II.getAction()->getInputs().size() == 0) { + const char *CubinF = + Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath( + llvm::sys::path::stem(InputFile), "cubin")); + if (llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF))) + continue; - CmdArgs.push_back(CubinF); + CmdArgs.push_back(CubinF); + } else { + SmallString<256> Filename(InputFile); + llvm::sys::path::replace_extension(Filename, "cubin"); + CmdArgs.push_back(Args.MakeArgString(Filename)); + } + } else { + CmdArgs.push_back(Args.MakeArgString(InputFile)); + } } - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("nvlink")); C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8, "--options-file"}, - Exec, CmdArgs, Inputs, Output)); + Args.MakeArgString(getToolChain().GetProgramPath("nvlink")), CmdArgs, + Inputs, Output)); } -/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary, -/// which isn't properly a linker but nonetheless performs the step of stitching -/// together object files from the assembler into a single blob. +void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features) { + if (Args.hasArg(options::OPT_cuda_feature_EQ)) { + StringRef PtxFeature = + Args.getLastArgValue(options::OPT_cuda_feature_EQ, "+ptx42"); + Features.push_back(Args.MakeArgString(PtxFeature)); + return; + } + CudaInstallationDetector CudaInstallation(D, Triple, Args); -CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const ArgList &Args, - const Action::OffloadKind OK) - : ToolChain(D, Triple, Args), HostTC(HostTC), - CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) { - if (CudaInstallation.isValid()) { - CudaInstallation.WarnIfUnsupportedVersion(); - getProgramPaths().push_back(std::string(CudaInstallation.getBinPath())); + // New CUDA versions often introduce new instructions that are only supported + // by new PTX version, so we need to raise PTX level to enable them in NVPTX + // back-end. + const char *PtxFeature = nullptr; + switch (CudaInstallation.version()) { +#define CASE_CUDA_VERSION(CUDA_VER, PTX_VER) \ + case CudaVersion::CUDA_##CUDA_VER: \ + PtxFeature = "+ptx" #PTX_VER; \ + break; + CASE_CUDA_VERSION(123, 83); + CASE_CUDA_VERSION(122, 82); + CASE_CUDA_VERSION(121, 81); + CASE_CUDA_VERSION(120, 80); + CASE_CUDA_VERSION(118, 78); + CASE_CUDA_VERSION(117, 77); + CASE_CUDA_VERSION(116, 76); + CASE_CUDA_VERSION(115, 75); + CASE_CUDA_VERSION(114, 74); + CASE_CUDA_VERSION(113, 73); + CASE_CUDA_VERSION(112, 72); + CASE_CUDA_VERSION(111, 71); + CASE_CUDA_VERSION(110, 70); + CASE_CUDA_VERSION(102, 65); + CASE_CUDA_VERSION(101, 64); + CASE_CUDA_VERSION(100, 63); + CASE_CUDA_VERSION(92, 61); + CASE_CUDA_VERSION(91, 61); + CASE_CUDA_VERSION(90, 60); +#undef CASE_CUDA_VERSION + default: + PtxFeature = "+ptx42"; } + Features.push_back(PtxFeature); +} + +/// NVPTX toolchain. Our assembler is ptxas, and our linker is nvlink. This +/// operates as a stand-alone version of the NVPTX tools without the host +/// toolchain. +NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::Triple &HostTriple, + const ArgList &Args, bool Freestanding = false) + : ToolChain(D, Triple, Args), CudaInstallation(D, HostTriple, Args), + Freestanding(Freestanding) { + if (CudaInstallation.isValid()) + getProgramPaths().push_back(std::string(CudaInstallation.getBinPath())); // Lookup binaries into the driver directory, this is used to - // discover the clang-offload-bundler executable. + // discover the 'nvptx-arch' executable. getProgramPaths().push_back(getDriver().Dir); } -std::string CudaToolChain::getInputFilename(const InputInfo &Input) const { - // Only object files are changed, for example assembly files keep their .s - // extensions. CUDA also continues to use .o as they don't use nvlink but - // fatbinary. - if (!(OK == Action::OFK_OpenMP && Input.getType() == types::TY_Object)) - return ToolChain::getInputFilename(Input); +/// We only need the host triple to locate the CUDA binary utilities, use the +/// system's default triple if not provided. +NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : NVPTXToolChain(D, Triple, llvm::Triple(LLVM_HOST_TRIPLE), Args, + /*Freestanding=*/true) {} - // Replace extension for object files with cubin because nvlink relies on - // these particular file names. - SmallString<256> Filename(ToolChain::getInputFilename(Input)); - llvm::sys::path::replace_extension(Filename, "cubin"); - return std::string(Filename.str()); +llvm::opt::DerivedArgList * +NVPTXToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + DerivedArgList *DAL = + ToolChain::TranslateArgs(Args, BoundArch, DeviceOffloadKind); + if (!DAL) + DAL = new DerivedArgList(Args.getBaseArgs()); + + const OptTable &Opts = getDriver().getOpts(); + + for (Arg *A : Args) + if (!llvm::is_contained(*DAL, A)) + DAL->append(A); + + if (!DAL->hasArg(options::OPT_march_EQ)) + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), + CudaArchToString(CudaArch::CudaDefault)); + + return DAL; +} + +void NVPTXToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + // If we are compiling with a standalone NVPTX toolchain we want to try to + // mimic a standard environment as much as possible. So we enable lowering + // ctor / dtor functions to global symbols that can be registered. + if (Freestanding) + CC1Args.append({"-mllvm", "--nvptx-lower-global-ctor-dtor"}); +} + +bool NVPTXToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const { + const Option &O = A->getOption(); + return (O.matches(options::OPT_gN_Group) && + !O.matches(options::OPT_gmodules)) || + O.matches(options::OPT_g_Flag) || + O.matches(options::OPT_ggdbN_Group) || O.matches(options::OPT_ggdb) || + O.matches(options::OPT_gdwarf) || O.matches(options::OPT_gdwarf_2) || + O.matches(options::OPT_gdwarf_3) || O.matches(options::OPT_gdwarf_4) || + O.matches(options::OPT_gdwarf_5) || + O.matches(options::OPT_gcolumn_info); } +void NVPTXToolChain::adjustDebugInfoKind( + llvm::codegenoptions::DebugInfoKind &DebugInfoKind, + const ArgList &Args) const { + switch (mustEmitDebugInfo(Args)) { + case DisableDebugInfo: + DebugInfoKind = llvm::codegenoptions::NoDebugInfo; + break; + case DebugDirectivesOnly: + DebugInfoKind = llvm::codegenoptions::DebugDirectivesOnly; + break; + case EmitSameDebugInfoAsHost: + // Use same debug info level as the host. + break; + } +} + +/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary, +/// which isn't properly a linker but nonetheless performs the step of stitching +/// together object files from the assembler into a single blob. + +CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const ArgList &Args) + : NVPTXToolChain(D, Triple, HostTC.getTriple(), Args), HostTC(HostTC) {} + void CudaToolChain::addClangTargetOptions( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); @@ -686,11 +803,15 @@ void CudaToolChain::addClangTargetOptions( "Only OpenMP or CUDA offloading kinds are supported for NVIDIA GPUs."); if (DeviceOffloadingKind == Action::OFK_Cuda) { - CC1Args.push_back("-fcuda-is-device"); - - if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, - options::OPT_fno_cuda_approx_transcendentals, false)) - CC1Args.push_back("-fcuda-approx-transcendentals"); + CC1Args.append( + {"-fcuda-is-device", "-mllvm", "-enable-memcpyopt-without-libcalls"}); + + // Unsized function arguments used for variadics were introduced in CUDA-9.0 + // We still do not support generating code that actually uses variadic + // arguments yet, but we do need to allow parsing them as recent CUDA + // headers rely on that. https://github.com/llvm/llvm-project/issues/58410 + if (CudaInstallation.version() >= CudaVersion::CUDA_90) + CC1Args.push_back("-fcuda-allow-variadic-functions"); } if (DriverArgs.hasArg(options::OPT_nogpulib)) @@ -711,29 +832,6 @@ void CudaToolChain::addClangTargetOptions( clang::CudaVersion CudaInstallationVersion = CudaInstallation.version(); - // New CUDA versions often introduce new instructions that are only supported - // by new PTX version, so we need to raise PTX level to enable them in NVPTX - // back-end. - const char *PtxFeature = nullptr; - switch (CudaInstallationVersion) { -#define CASE_CUDA_VERSION(CUDA_VER, PTX_VER) \ - case CudaVersion::CUDA_##CUDA_VER: \ - PtxFeature = "+ptx" #PTX_VER; \ - break; - CASE_CUDA_VERSION(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"}); @@ -751,14 +849,11 @@ void CudaToolChain::addClangTargetOptions( return; } - std::string BitcodeSuffix; - if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime, - options::OPT_fno_openmp_target_new_runtime, false)) - BitcodeSuffix = "new-nvptx-" + GpuArch.str(); - else - BitcodeSuffix = "nvptx-" + GpuArch.str(); + // Link the bitcode library late if we're using device LTO. + if (getDriver().isUsingLTO(/* IsOffload */ true)) + return; - addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, + addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, GpuArch.str(), getTriple()); } } @@ -777,33 +872,6 @@ llvm::DenormalMode CudaToolChain::getDefaultDenormalModeForType( return llvm::DenormalMode::getIEEE(); } -bool CudaToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const { - const Option &O = A->getOption(); - return (O.matches(options::OPT_gN_Group) && - !O.matches(options::OPT_gmodules)) || - O.matches(options::OPT_g_Flag) || - O.matches(options::OPT_ggdbN_Group) || O.matches(options::OPT_ggdb) || - O.matches(options::OPT_gdwarf) || O.matches(options::OPT_gdwarf_2) || - O.matches(options::OPT_gdwarf_3) || O.matches(options::OPT_gdwarf_4) || - O.matches(options::OPT_gdwarf_5) || - O.matches(options::OPT_gcolumn_info); -} - -void CudaToolChain::adjustDebugInfoKind( - codegenoptions::DebugInfoKind &DebugInfoKind, const ArgList &Args) const { - switch (mustEmitDebugInfo(Args)) { - case DisableDebugInfo: - DebugInfoKind = codegenoptions::NoDebugInfo; - break; - case DebugDirectivesOnly: - DebugInfoKind = codegenoptions::DebugDirectivesOnly; - break; - case EmitSameDebugInfoAsHost: - // Use same debug info level as the host. - break; - } -} - void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { // Check our CUDA version if we're going to include the CUDA headers. @@ -816,6 +884,19 @@ void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } +std::string CudaToolChain::getInputFilename(const InputInfo &Input) const { + // Only object files are changed, for example assembly files keep their .s + // extensions. If the user requested device-only compilation don't change it. + if (Input.getType() != types::TY_Object || getDriver().offloadDeviceOnly()) + return ToolChain::getInputFilename(Input); + + // Replace extension for object files with cubin because nvlink relies on + // these particular file names. + SmallString<256> Filename(ToolChain::getInputFilename(Input)); + llvm::sys::path::replace_extension(Filename, "cubin"); + return std::string(Filename); +} + llvm::opt::DerivedArgList * CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, @@ -831,23 +912,27 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, // flags are not duplicated. // Also append the compute capability. if (DeviceOffloadKind == Action::OFK_OpenMP) { - for (Arg *A : Args) { - bool IsDuplicate = false; - for (Arg *DALArg : *DAL) { - if (A == DALArg) { - IsDuplicate = true; - break; + for (Arg *A : Args) + if (!llvm::is_contained(*DAL, A)) + DAL->append(A); + + if (!DAL->hasArg(options::OPT_march_EQ)) { + StringRef Arch = BoundArch; + if (Arch.empty()) { + auto ArchsOrErr = getSystemGPUArchs(Args); + if (!ArchsOrErr) { + std::string ErrMsg = + llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError())); + getDriver().Diag(diag::err_drv_undetermined_gpu_arch) + << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march"; + Arch = CudaArchToString(CudaArch::CudaDefault); + } else { + Arch = Args.MakeArgString(ArchsOrErr->front()); } } - if (!IsDuplicate) - DAL->append(A); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch); } - StringRef Arch = DAL->getLastArgValue(options::OPT_march_EQ); - if (Arch.empty()) - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), - CLANG_OPENMP_NVPTX_DEFAULT_ARCH); - return DAL; } @@ -857,19 +942,51 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, if (!BoundArch.empty()) { DAL->eraseArg(options::OPT_march_EQ); - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), + BoundArch); } return DAL; } +Expected<SmallVector<std::string>> +CudaToolChain::getSystemGPUArchs(const ArgList &Args) const { + // Detect NVIDIA GPUs availible on the system. + std::string Program; + if (Arg *A = Args.getLastArg(options::OPT_nvptx_arch_tool_EQ)) + Program = A->getValue(); + else + Program = GetProgramPath("nvptx-arch"); + + auto StdoutOrErr = executeToolChainProgram(Program); + if (!StdoutOrErr) + return StdoutOrErr.takeError(); + + SmallVector<std::string, 1> GPUArchs; + for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n")) + if (!Arch.empty()) + GPUArchs.push_back(Arch.str()); + + if (GPUArchs.empty()) + return llvm::createStringError(std::error_code(), + "No NVIDIA GPU detected in the system"); + + return std::move(GPUArchs); +} + +Tool *NVPTXToolChain::buildAssembler() const { + return new tools::NVPTX::Assembler(*this); +} + +Tool *NVPTXToolChain::buildLinker() const { + return new tools::NVPTX::Linker(*this); +} + Tool *CudaToolChain::buildAssembler() const { return new tools::NVPTX::Assembler(*this); } Tool *CudaToolChain::buildLinker() const { - if (OK == Action::OFK_OpenMP) - return new tools::NVPTX::OpenMPLinker(*this); - return new tools::NVPTX::Linker(*this); + return new tools::NVPTX::FatBinary(*this); } void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { @@ -884,6 +1001,11 @@ CudaToolChain::GetCXXStdlibType(const ArgList &Args) const { void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); + + if (!DriverArgs.hasArg(options::OPT_nogpuinc) && CudaInstallation.isValid()) + CC1Args.append( + {"-internal-isystem", + DriverArgs.MakeArgString(CudaInstallation.getIncludePath())}); } void CudaToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h index 6ae4415a563a..8a053f3393e1 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Cuda.h @@ -14,7 +14,6 @@ #include "clang/Driver/Multilib.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" -#include "llvm/ADT/Optional.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/VersionTuple.h" #include <bitset> @@ -30,11 +29,8 @@ private: const Driver &D; bool IsValid = false; CudaVersion Version = CudaVersion::UNKNOWN; - std::string DetectedVersion; - bool DetectedVersionIsNotSupported = false; std::string InstallPath; std::string BinPath; - std::string LibPath; std::string LibDevicePath; std::string IncludePath; llvm::StringMap<std::string> LibDeviceMap; @@ -62,15 +58,16 @@ public: void print(raw_ostream &OS) const; /// Get the detected Cuda install's version. - CudaVersion version() const { return Version; } + CudaVersion version() const { + return Version == CudaVersion::NEW ? CudaVersion::PARTIALLY_SUPPORTED + : Version; + } /// Get the detected Cuda installation path. StringRef getInstallPath() const { return InstallPath; } /// Get the detected path to Cuda's bin directory. StringRef getBinPath() const { return BinPath; } /// Get the detected Cuda Include path. StringRef getIncludePath() const { return IncludePath; } - /// Get the detected Cuda library path. - StringRef getLibPath() const { return LibPath; } /// Get the detected Cuda device library path. StringRef getLibDevicePath() const { return LibDevicePath; } /// Get libdevice file for given architecture @@ -84,85 +81,125 @@ namespace tools { namespace NVPTX { // Run ptxas, the NVPTX assembler. -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { - public: - Assembler(const ToolChain &TC) : Tool("NVPTX::Assembler", "ptxas", TC) {} +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("NVPTX::Assembler", "ptxas", TC) {} - bool hasIntegratedCPP() const override { return false; } + bool hasIntegratedCPP() const override { return false; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; // Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX // assembly into a single output file. -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { - public: - Linker(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {} +class LLVM_LIBRARY_VISIBILITY FatBinary : public Tool { +public: + FatBinary(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {} - bool hasIntegratedCPP() const override { return false; } + bool hasIntegratedCPP() const override { return false; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool { - public: - OpenMPLinker(const ToolChain &TC) - : Tool("NVPTX::OpenMPLinker", "nvlink", TC) {} +// Runs nvlink, which links GPU object files ("cubin" files) into a single file. +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("NVPTX::Linker", "nvlink", TC) {} - bool hasIntegratedCPP() const override { return false; } + bool hasIntegratedCPP() const override { return false; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; +void getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features); + } // end namespace NVPTX } // end namespace tools namespace toolchains { -class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain { +class LLVM_LIBRARY_VISIBILITY NVPTXToolChain : public ToolChain { public: - CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const llvm::opt::ArgList &Args, - const Action::OffloadKind OK); + NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::Triple &HostTriple, const llvm::opt::ArgList &Args, + bool Freestanding); - const llvm::Triple *getAuxTriple() const override { - return &HostTC.getTriple(); - } - - std::string getInputFilename(const InputInfo &Input) const override; + NVPTXToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const override; - llvm::DenormalMode getDefaultDenormalModeForType( - const llvm::opt::ArgList &DriverArgs, const JobAction &JA, - const llvm::fltSemantics *FPType = nullptr) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; // Never try to use the integrated assembler with CUDA; always fork out to // ptxas. bool useIntegratedAs() const override { return false; } bool isCrossCompiling() const override { return true; } bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } + + bool IsMathErrnoDefault() const override { return false; } + bool supportsDebugInfoOption(const llvm::opt::Arg *A) const override; - void adjustDebugInfoKind(codegenoptions::DebugInfoKind &DebugInfoKind, + void adjustDebugInfoKind(llvm::codegenoptions::DebugInfoKind &DebugInfoKind, const llvm::opt::ArgList &Args) const override; - bool IsMathErrnoDefault() const override { return false; } + + // NVPTX supports only DWARF2. + unsigned GetDefaultDwarfVersion() const override { return 2; } + unsigned getMaxDwarfVersion() const override { return 2; } + + CudaInstallationDetector CudaInstallation; + +protected: + Tool *buildAssembler() const override; // ptxas. + Tool *buildLinker() const override; // nvlink. + +private: + bool Freestanding = false; +}; + +class LLVM_LIBRARY_VISIBILITY CudaToolChain : public NVPTXToolChain { +public: + CudaToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const llvm::opt::ArgList &Args); + + const llvm::Triple *getAuxTriple() const override { + return &HostTC.getTriple(); + } + + std::string getInputFilename(const InputInfo &Input) const override; + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + + llvm::DenormalMode getDefaultDenormalModeForType( + const llvm::opt::ArgList &DriverArgs, const JobAction &JA, + const llvm::fltSemantics *FPType = nullptr) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -184,19 +221,16 @@ public: computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } - // NVPTX supports only DWARF2. - unsigned getMaxDwarfVersion() const override { return 2; } - const ToolChain &HostTC; - CudaInstallationDetector CudaInstallation; -protected: - Tool *buildAssembler() const override; // ptxas - Tool *buildLinker() const override; // fatbinary (ok, not really a linker) + /// Uses nvptx-arch tool to get arch of the system GPU. Will return error + /// if unable to find one. + virtual Expected<SmallVector<std::string>> + getSystemGPUArchs(const llvm::opt::ArgList &Args) const override; -private: - const Action::OffloadKind OK; +protected: + Tool *buildAssembler() const override; // ptxas + Tool *buildLinker() const override; // fatbinary (ok, not really a linker) }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp index 261f522f6c49..fae8ad1a958a 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp @@ -23,9 +23,10 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/TargetParser.h" #include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/TargetParser.h" +#include "llvm/TargetParser/Triple.h" #include <cstdlib> // ::getenv using namespace clang::driver; @@ -34,7 +35,7 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; -static const VersionTuple minimumMacCatalystDeploymentTarget() { +static VersionTuple minimumMacCatalystDeploymentTarget() { return VersionTuple(13, 1); } @@ -44,7 +45,7 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { // The matching this routine does is fairly pointless, since it is neither the // complete architecture list, nor a reasonable subset. The problem is that - // historically the driver driver accepts this and also ties its -march= + // historically the driver accepts this and also ties its -march= // handling to the architecture name, so we need to be careful before removing // support for it. @@ -52,14 +53,11 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { // translation. return llvm::StringSwitch<llvm::Triple::ArchType>(Str) - .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc) - .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc) - .Case("ppc64", llvm::Triple::ppc64) .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86) .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4", llvm::Triple::x86) .Cases("x86_64", "x86_64h", llvm::Triple::x86_64) - // This is derived from the driver driver. + // This is derived from the driver. .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm) .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm) .Cases("armv7s", "xscale", llvm::Triple::arm) @@ -74,7 +72,8 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { .Default(llvm::Triple::UnknownArch); } -void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { +void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str, + const ArgList &Args) { const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str); llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(Str); T.setArch(Arch); @@ -84,6 +83,17 @@ void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { if (ArchKind == llvm::ARM::ArchKind::ARMV6M || ArchKind == llvm::ARM::ArchKind::ARMV7M || ArchKind == llvm::ARM::ArchKind::ARMV7EM) { + // Don't reject these -version-min= if we have the appropriate triple. + if (T.getOS() == llvm::Triple::IOS) + for (Arg *A : Args.filtered(options::OPT_mios_version_min_EQ)) + A->ignoreTargetSpecific(); + if (T.getOS() == llvm::Triple::WatchOS) + for (Arg *A : Args.filtered(options::OPT_mwatchos_version_min_EQ)) + A->ignoreTargetSpecific(); + if (T.getOS() == llvm::Triple::TvOS) + for (Arg *A : Args.filtered(options::OPT_mtvos_version_min_EQ)) + A->ignoreTargetSpecific(); + T.setOS(llvm::Triple::UnknownOS); T.setObjectFormat(llvm::Triple::MachO); } @@ -94,6 +104,8 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const llvm::Triple &T(getToolChain().getTriple()); + ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs."); @@ -112,7 +124,6 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, // FIXME: at run-time detect assembler capabilities or rely on version // information forwarded by -target-assembler-version. if (Args.hasArg(options::OPT_fno_integrated_as)) { - const llvm::Triple &T(getToolChain().getTriple()); if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7))) CmdArgs.push_back("-Q"); } @@ -130,8 +141,7 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, AddMachOArch(Args, CmdArgs); // Use -force_cpusubtype_ALL on x86 by default. - if (getToolChain().getTriple().isX86() || - Args.hasArg(options::OPT_force__cpusubtype__ALL)) + if (T.isX86() || Args.hasArg(options::OPT_force__cpusubtype__ALL)) CmdArgs.push_back("-force_cpusubtype_ALL"); if (getToolChain().getArch() != llvm::Triple::x86_64 && @@ -209,20 +219,19 @@ static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) { void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs, - unsigned Version[5], bool LinkerIsLLD, - bool LinkerIsLLDDarwinNew) const { + VersionTuple Version, bool LinkerIsLLD, + bool UsePlatformVersion) const { const Driver &D = getToolChain().getDriver(); const toolchains::MachO &MachOTC = getMachOToolChain(); // Newer linkers support -demangle. Pass it if supported and not disabled by // the user. - if ((Version[0] >= 100 || LinkerIsLLD) && + if ((Version >= VersionTuple(100) || LinkerIsLLD) && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("-demangle"); - // FIXME: Pass most of the flags below that check Version if LinkerIsLLD too. - - if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137) + if (Args.hasArg(options::OPT_rdynamic) && + (Version >= VersionTuple(137) || LinkerIsLLD)) CmdArgs.push_back("-export_dynamic"); // If we are using App Extension restrictions, pass a flag to the linker @@ -231,7 +240,8 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, options::OPT_fno_application_extension, false)) CmdArgs.push_back("-application_extension"); - if (D.isUsingLTO() && Version[0] >= 116 && NeedsTempPath(Inputs)) { + if (D.isUsingLTO() && (Version >= VersionTuple(116) || LinkerIsLLD) && + NeedsTempPath(Inputs)) { std::string TmpPathName; if (D.getLTOMode() == LTOK_Full) { // If we are using full LTO, then automatically create a temporary file @@ -260,7 +270,7 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, // clang version won't work anyways. // lld is built at the same revision as clang and statically links in // LLVM libraries, so it doesn't need libLTO.dylib. - if (Version[0] >= 133 && !LinkerIsLLD) { + if (Version >= VersionTuple(133) && !LinkerIsLLD) { // Search for libLTO in <InstalledDir>/../lib/libLTO.dylib StringRef P = llvm::sys::path::parent_path(D.Dir); SmallString<128> LibLTOPath(P); @@ -270,8 +280,11 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath)); } - // ld64 version 262 and above run the deduplicate pass by default. - if (Version[0] >= 262 && shouldLinkerNotDedup(C.getJobs().empty(), Args)) + // ld64 version 262 and above runs the deduplicate pass by default. + // FIXME: lld doesn't dedup by default. Should we pass `--icf=safe` + // if `!shouldLinkerNotDedup()` if LinkerIsLLD here? + if (Version >= VersionTuple(262) && + shouldLinkerNotDedup(C.getJobs().empty(), Args)) CmdArgs.push_back("-no_deduplicate"); // Derived from the "link" spec. @@ -343,7 +356,7 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_init); // Add the deployment target. - if (Version[0] >= 520 || LinkerIsLLDDarwinNew) + if (Version >= VersionTuple(520) || LinkerIsLLD || UsePlatformVersion) MachOTC.addPlatformVersionArgs(Args, CmdArgs); else MachOTC.addMinVersionArgs(Args, CmdArgs); @@ -369,7 +382,9 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, // Check if the toolchain supports bitcode build flow. if (MachOTC.SupportsEmbeddedBitcode()) { CmdArgs.push_back("-bitcode_bundle"); - if (C.getDriver().embedBitcodeMarkerOnly() && Version[0] >= 278) { + // FIXME: Pass this if LinkerIsLLD too, once it implements this flag. + if (C.getDriver().embedBitcodeMarkerOnly() && + Version >= VersionTuple(278)) { CmdArgs.push_back("-bitcode_process_mode"); CmdArgs.push_back("marker"); } @@ -389,6 +404,13 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, } } + if (Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext) || + Args.hasArg(options::OPT_ffreestanding)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-disable-atexit-based-global-dtor-lowering"); + } + Args.AddLastArg(CmdArgs, options::OPT_prebind); Args.AddLastArg(CmdArgs, options::OPT_noprebind); Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding); @@ -438,6 +460,23 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name); Args.AddLastArg(CmdArgs, options::OPT_dylinker); Args.AddLastArg(CmdArgs, options::OPT_Mach); + + if (LinkerIsLLD) { + if (auto *CSPGOGenerateArg = getLastCSProfileGenerateArg(Args)) { + SmallString<128> Path(CSPGOGenerateArg->getNumValues() == 0 + ? "" + : CSPGOGenerateArg->getValue()); + llvm::sys::path::append(Path, "default_%m.profraw"); + CmdArgs.push_back("--cs-profile-generate"); + CmdArgs.push_back(Args.MakeArgString(Twine("--cs-profile-path=") + Path)); + } else if (auto *ProfileUseArg = getLastProfileUseArg(Args)) { + SmallString<128> Path( + ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); + if (Path.empty() || llvm::sys::fs::is_directory(Path)) + llvm::sys::path::append(Path, "default.profdata"); + CmdArgs.push_back(Args.MakeArgString(Twine("--cs-profile-path=") + Path)); + } + } } /// Determine whether we are linking the ObjC runtime. @@ -518,6 +557,8 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, } } +static void AppendPlatformPrefix(SmallString<128> &Path, const llvm::Triple &T); + void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -544,26 +585,25 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("touch")); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, None, Output)); + C.addCommand(std::make_unique<Command>(JA, *this, + ResponseFileSupport::None(), Exec, + CmdArgs, std::nullopt, Output)); return; } - unsigned Version[5] = {0, 0, 0, 0, 0}; - if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { - if (!Driver::GetReleaseVersion(A->getValue(), Version)) - getToolChain().getDriver().Diag(diag::err_drv_invalid_version_number) - << A->getAsString(Args); - } + VersionTuple Version = getMachOToolChain().getLinkerVersion(Args); - bool LinkerIsLLD, LinkerIsLLDDarwinNew; - const char *Exec = Args.MakeArgString( - getToolChain().GetLinkerPath(&LinkerIsLLD, &LinkerIsLLDDarwinNew)); + bool LinkerIsLLD; + const char *Exec = + Args.MakeArgString(getToolChain().GetLinkerPath(&LinkerIsLLD)); + + // xrOS always uses -platform-version. + bool UsePlatformVersion = getToolChain().getTriple().isXROS(); // I'm not sure why this particular decomposition exists in gcc, but // we follow suite for ease of comparison. AddLinkArgs(C, Args, CmdArgs, Inputs, Version, LinkerIsLLD, - LinkerIsLLDDarwinNew); + UsePlatformVersion); if (willEmitRemarks(Args) && checkRemarksOptions(getToolChain().getDriver(), Args, @@ -577,10 +617,6 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (getMachOToolChain().getMachOArchName(Args) == "arm64") { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-enable-machine-outliner"); - - // Outline from linkonceodr functions by default in LTO. - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-enable-linkonceodr-outlining"); } } else { // Disable all outlining behaviour if we have mno-outline. We need to do @@ -591,6 +627,12 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + // Outline from linkonceodr functions by default in LTO, whenever the outliner + // is enabled. Note that the target may enable the machine outliner + // independently of -moutline. + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-linkonceodr-outlining"); + // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Inputs[0], getToolChain().getDriver()); @@ -601,9 +643,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, // It seems that the 'e' option is completely ignored for dynamic executables // (the default), and with static executables, the last one wins, as expected. - Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_u_Group, - options::OPT_e, options::OPT_r}); + Args.addAllArgs(CmdArgs, + {options::OPT_d_Flag, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_u_Group, options::OPT_r}); // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading // members of static archive libraries which implement Objective-C classes or @@ -637,6 +679,13 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, InputFileList.push_back(II.getFilename()); } + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. + if (getToolChain().getDriver().IsFlangMode()) { + addFortranRuntimeLibraryPath(getToolChain(), Args, CmdArgs); + addFortranRuntimeLibs(getToolChain(), Args, CmdArgs); + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) addOpenMPRuntime(CmdArgs, getToolChain(), Args); @@ -714,8 +763,37 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + // Add non-standard, platform-specific search paths, e.g., for DriverKit: + // -L<sysroot>/System/DriverKit/usr/lib + // -F<sysroot>/System/DriverKit/System/Library/Framework + { + bool NonStandardSearchPath = false; + const auto &Triple = getToolChain().getTriple(); + if (Triple.isDriverKit()) { + // ld64 fixed the implicit -F and -L paths in ld64-605.1+. + NonStandardSearchPath = + Version.getMajor() < 605 || + (Version.getMajor() == 605 && Version.getMinor().value_or(0) < 1); + } + + if (NonStandardSearchPath) { + if (auto *Sysroot = Args.getLastArg(options::OPT_isysroot)) { + auto AddSearchPath = [&](StringRef Flag, StringRef SearchPath) { + SmallString<128> P(Sysroot->getValue()); + AppendPlatformPrefix(P, Triple); + llvm::sys::path::append(P, SearchPath); + if (getToolChain().getVFS().exists(P)) { + CmdArgs.push_back(Args.MakeArgString(Flag + P)); + } + }; + AddSearchPath("-L", "/usr/lib"); + AddSearchPath("-F", "/System/Library/Frameworks"); + } + } + } + ResponseFileSupport ResponseSupport; - if (Version[0] >= 705 || LinkerIsLLDDarwinNew) { + if (Version >= VersionTuple(705) || LinkerIsLLD) { ResponseSupport = ResponseFileSupport::AtFileUTF8(); } else { // For older versions of the linker, use the legacy filelist method instead. @@ -729,6 +807,54 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(std::move(Cmd)); } +void darwin::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // libtool <options> <output_file> <input_files> + ArgStringList CmdArgs; + // Create and insert file members with a deterministic index. + CmdArgs.push_back("-static"); + CmdArgs.push_back("-D"); + CmdArgs.push_back("-no_warning_for_no_symbols"); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) { + if (II.isFilename()) { + CmdArgs.push_back(II.getFilename()); + } + } + + // Delete old output archive file if it already exists before generating a new + // archive file. + const auto *OutputFileName = Output.getFilename(); + if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) { + if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) { + D.Diag(diag::err_drv_unable_to_remove_file) << EC.message(); + return; + } + } + + const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath()); + C.addCommand(std::make_unique<Command>(JA, *this, + ResponseFileSupport::AtFileUTF8(), + Exec, CmdArgs, Inputs, Output)); +} + void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -823,13 +949,8 @@ types::ID MachO::LookupTypeForExtension(StringRef Ext) const { bool MachO::HasNativeLLVMSupport() const { return true; } ToolChain::CXXStdlibType Darwin::GetDefaultCXXStdlibType() const { - // Default to use libc++ on OS X 10.9+ and iOS 7+. - if ((isTargetMacOSBased() && !isMacosxVersionLT(10, 9)) || - (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) || - isTargetWatchOSBased()) - return ToolChain::CST_Libcxx; - - return ToolChain::CST_Libstdcxx; + // Always use libc++ by default + return ToolChain::CST_Libcxx; } /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. @@ -838,6 +959,13 @@ ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion); if (isTargetIOSBased()) return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); + if (isTargetXROS()) { + // XROS uses the iOS runtime. + auto T = llvm::Triple(Twine("arm64-apple-") + + llvm::Triple::getOSTypeName(llvm::Triple::XROS) + + TargetVersion.getAsString()); + return ObjCRuntime(ObjCRuntime::iOS, T.getiOSVersion()); + } if (isNonFragile) return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion); @@ -845,7 +973,7 @@ ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { /// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. bool Darwin::hasBlocksRuntime() const { - if (isTargetWatchOSBased()) + if (isTargetWatchOSBased() || isTargetDriverKit() || isTargetXROS()) return true; else if (isTargetIOSBased()) return !isIPhoneOSVersionLT(3, 2); @@ -857,12 +985,12 @@ bool Darwin::hasBlocksRuntime() const { void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void Darwin::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } // This is just a MachO name translation routine and there's no @@ -894,13 +1022,13 @@ static const char *ArmMachOArchNameCPU(StringRef CPU) { // FIXME: Make sure this MachO triple mangling is really necessary. // ARMv5* normalises to ARMv5. - if (Arch.startswith("armv5")) + if (Arch.starts_with("armv5")) Arch = Arch.substr(0, 5); // ARMv6*, except ARMv6M, normalises to ARMv6. - else if (Arch.startswith("armv6") && !Arch.endswith("6m")) + else if (Arch.starts_with("armv6") && !Arch.ends_with("6m")) Arch = Arch.substr(0, 5); // ARMv7A normalises to ARMv7. - else if (Arch.endswith("v7a")) + else if (Arch.ends_with("v7a")) Arch = Arch.substr(0, 5); return Arch.data(); } @@ -933,6 +1061,27 @@ StringRef MachO::getMachOArchName(const ArgList &Args) const { } } +VersionTuple MachO::getLinkerVersion(const llvm::opt::ArgList &Args) const { + if (LinkerVersion) { +#ifndef NDEBUG + VersionTuple NewLinkerVersion; + if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) + (void)NewLinkerVersion.tryParse(A->getValue()); + assert(NewLinkerVersion == LinkerVersion); +#endif + return *LinkerVersion; + } + + VersionTuple NewLinkerVersion; + if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) + if (NewLinkerVersion.tryParse(A->getValue())) + getDriver().Diag(diag::err_drv_invalid_version_number) + << A->getAsString(Args); + + LinkerVersion = NewLinkerVersion; + return *LinkerVersion; +} + Darwin::~Darwin() {} MachO::~MachO() {} @@ -951,8 +1100,12 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, Str += "watchos"; else if (isTargetTvOSBased()) Str += "tvos"; + else if (isTargetDriverKit()) + Str += "driverkit"; else if (isTargetIOSBased() || isTargetMacCatalyst()) Str += "ios"; + else if (isTargetXROS()) + Str += llvm::Triple::getOSTypeName(llvm::Triple::XROS); else Str += "macosx"; Str += getTripleTargetVersion().getAsString(); @@ -982,6 +1135,10 @@ Tool *MachO::getTool(Action::ActionClass AC) const { Tool *MachO::buildLinker() const { return new tools::darwin::Linker(*this); } +Tool *MachO::buildStaticLibTool() const { + return new tools::darwin::StaticLibTool(*this); +} + Tool *MachO::buildAssembler() const { return new tools::darwin::Assembler(*this); } @@ -1031,6 +1188,8 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, // ARC runtime is supported everywhere on arm64e. if (getTriple().isArm64e()) return; + if (isTargetXROS()) + return; ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true); @@ -1041,25 +1200,38 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, SmallString<128> P(getDriver().ClangExecutable); llvm::sys::path::remove_filename(P); // 'clang' llvm::sys::path::remove_filename(P); // 'bin' + llvm::sys::path::append(P, "lib", "arc"); // 'libarclite' usually lives in the same toolchain as 'clang'. However, the // Swift open source toolchains for macOS distribute Clang without libarclite. // In that case, to allow the linker to find 'libarclite', we point to the // 'libarclite' in the XcodeDefault toolchain instead. - if (getXcodeDeveloperPath(P).empty()) { - if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + if (!getVFS().exists(P)) { + auto updatePath = [&](const Arg *A) { // Try to infer the path to 'libarclite' in the toolchain from the // specified SDK path. StringRef XcodePathForSDK = getXcodeDeveloperPath(A->getValue()); - if (!XcodePathForSDK.empty()) { - P = XcodePathForSDK; - llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr"); - } + if (XcodePathForSDK.empty()) + return false; + + P = XcodePathForSDK; + llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr", + "lib", "arc"); + return getVFS().exists(P); + }; + + bool updated = false; + if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) + updated = updatePath(A); + + if (!updated) { + if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) + updatePath(A); } } CmdArgs.push_back("-force_load"); - llvm::sys::path::append(P, "lib", "arc", "libarclite_"); + llvm::sys::path::append(P, "libarclite_"); // Mash in the platform. if (isTargetWatchOSSimulator()) P += "watchsimulator"; @@ -1077,6 +1249,9 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, P += "macosx"; P += ".a"; + if (!getVFS().exists(P)) + getDriver().Diag(clang::diag::err_drv_darwin_sdk_missing_arclite) << P; + CmdArgs.push_back(Args.MakeArgString(P)); } @@ -1102,8 +1277,9 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, DarwinLibName += getOSLibraryNameSuffix(); DarwinLibName += IsShared ? "_dynamic.dylib" : ".a"; SmallString<128> Dir(getDriver().ResourceDir); - llvm::sys::path::append( - Dir, "lib", (Opts & RLO_IsEmbedded) ? "macho_embedded" : "darwin"); + llvm::sys::path::append(Dir, "lib", "darwin"); + if (Opts & RLO_IsEmbedded) + llvm::sys::path::append(Dir, "macho_embedded"); SmallString<128> P(Dir); llvm::sys::path::append(P, DarwinLibName); @@ -1121,7 +1297,7 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, // rpaths. This is currently true from this place, but we need to be // careful if this function is ever called before user's rpaths are emitted. if (Opts & RLO_AddRPath) { - assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); + assert(DarwinLibName.ends_with(".dylib") && "must be a dynamic library"); // Add @executable_path to rpath to support having the dylib copied with // the executable. @@ -1147,6 +1323,10 @@ StringRef Darwin::getPlatformFamily() const { return "AppleTV"; case DarwinPlatformKind::WatchOS: return "Watch"; + case DarwinPlatformKind::DriverKit: + return "DriverKit"; + case DarwinPlatformKind::XROS: + return "XR"; } llvm_unreachable("Unsupported platform"); } @@ -1157,8 +1337,8 @@ StringRef Darwin::getSDKName(StringRef isysroot) { auto EndSDK = llvm::sys::path::rend(isysroot); for (auto IT = BeginSDK; IT != EndSDK; ++IT) { StringRef SDK = *IT; - if (SDK.endswith(".sdk")) - return SDK.slice(0, SDK.size() - 4); + if (SDK.ends_with(".sdk")) + return SDK.slice(0, SDK.size() - 4); } return ""; } @@ -1178,6 +1358,11 @@ StringRef Darwin::getOSLibraryNameSuffix(bool IgnoreSim) const { case DarwinPlatformKind::WatchOS: return TargetEnvironment == NativeEnvironment || IgnoreSim ? "watchos" : "watchossim"; + case DarwinPlatformKind::XROS: + return TargetEnvironment == NativeEnvironment || IgnoreSim ? "xros" + : "xrossim"; + case DarwinPlatformKind::DriverKit: + return "driverkit"; } llvm_unreachable("Unsupported platform"); } @@ -1229,20 +1414,14 @@ void Darwin::addProfileRTLibs(const ArgList &Args, // If we have a symbol export directive and we're linking in the profile // runtime, automatically export symbols necessary to implement some of the // runtime's functionality. - if (hasExportSymbolDirective(Args)) { - if (ForGCOV) { - addExportedSymbol(CmdArgs, "___gcov_dump"); - addExportedSymbol(CmdArgs, "___gcov_reset"); - addExportedSymbol(CmdArgs, "_writeout_fn_list"); - addExportedSymbol(CmdArgs, "_reset_fn_list"); - } else { - addExportedSymbol(CmdArgs, "___llvm_profile_filename"); - addExportedSymbol(CmdArgs, "___llvm_profile_raw_version"); - } - addExportedSymbol(CmdArgs, "_lprofDirMode"); + if (hasExportSymbolDirective(Args) && ForGCOV) { + addExportedSymbol(CmdArgs, "___gcov_dump"); + addExportedSymbol(CmdArgs, "___gcov_reset"); + addExportedSymbol(CmdArgs, "_writeout_fn_list"); + addExportedSymbol(CmdArgs, "_reset_fn_list"); } - // Align __llvm_prf_{cnts,data} sections to the maximum expected page + // Align __llvm_prf_{cnts,bits,data} sections to the maximum expected page // alignment. This allows profile counters to be mmap()'d to disk. Note that // it's not enough to just page-align __llvm_prf_cnts: the following section // must also be page-aligned so that its data is not clobbered by mmap(). @@ -1252,7 +1431,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args, // extra alignment also allows the same binary to be used with/without sync // enabled. if (!ForGCOV) { - for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_data}) { + for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_bitmap, llvm::IPSK_data}) { addSectalignToPage( Args, CmdArgs, "__DATA", llvm::getInstrProfSectionName(IPSK, llvm::Triple::MachO, @@ -1273,7 +1452,7 @@ ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType( const ArgList &Args) const { if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) { StringRef Value = A->getValue(); - if (Value != "compiler-rt") + if (Value != "compiler-rt" && Value != "platform") getDriver().Diag(clang::diag::err_drv_unsupported_rtlib_for_platform) << Value << "darwin"; } @@ -1305,27 +1484,58 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, return; } - const SanitizerArgs &Sanitize = getSanitizerArgs(); - if (Sanitize.needsAsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); - if (Sanitize.needsLsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan"); - if (Sanitize.needsUbsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, - Sanitize.requiresMinimalRuntime() ? "ubsan_minimal" - : "ubsan", - Sanitize.needsSharedRt()); - if (Sanitize.needsTsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); - if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) { - AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false); + const SanitizerArgs &Sanitize = getSanitizerArgs(Args); - // Libfuzzer is written in C++ and requires libcxx. - AddCXXStdlibLibArgs(Args, CmdArgs); + if (!Sanitize.needsSharedRt()) { + const char *sanitizer = nullptr; + if (Sanitize.needsUbsanRt()) { + sanitizer = "UndefinedBehaviorSanitizer"; + } else if (Sanitize.needsAsanRt()) { + sanitizer = "AddressSanitizer"; + } else if (Sanitize.needsTsanRt()) { + sanitizer = "ThreadSanitizer"; + } + if (sanitizer) { + getDriver().Diag(diag::err_drv_unsupported_static_sanitizer_darwin) + << sanitizer; + return; + } } - if (Sanitize.needsStatsRt()) { - AddLinkRuntimeLib(Args, CmdArgs, "stats_client", RLO_AlwaysLink); - AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); + + if (Sanitize.linkRuntimes()) { + if (Sanitize.needsAsanRt()) { + if (Sanitize.needsStableAbi()) { + AddLinkSanitizerLibArgs(Args, CmdArgs, "asan_abi", /*shared=*/false); + } else { + assert(Sanitize.needsSharedRt() && + "Static sanitizer runtimes not supported"); + AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); + } + } + if (Sanitize.needsLsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan"); + if (Sanitize.needsUbsanRt()) { + assert(Sanitize.needsSharedRt() && + "Static sanitizer runtimes not supported"); + AddLinkSanitizerLibArgs( + Args, CmdArgs, + Sanitize.requiresMinimalRuntime() ? "ubsan_minimal" : "ubsan"); + } + if (Sanitize.needsTsanRt()) { + assert(Sanitize.needsSharedRt() && + "Static sanitizer runtimes not supported"); + AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); + } + if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) { + AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false); + + // Libfuzzer is written in C++ and requires libcxx. + AddCXXStdlibLibArgs(Args, CmdArgs); + } + if (Sanitize.needsStatsRt()) { + AddLinkRuntimeLib(Args, CmdArgs, "stats_client", RLO_AlwaysLink); + AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); + } } const XRayArgs &XRay = getXRayArgs(); @@ -1335,9 +1545,15 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, AddLinkRuntimeLib(Args, CmdArgs, "xray-fdr"); } + if (isTargetDriverKit() && !Args.hasArg(options::OPT_nodriverkitlib)) { + CmdArgs.push_back("-framework"); + CmdArgs.push_back("DriverKit"); + } + // Otherwise link libSystem, then the dynamic runtime library, and finally any // target specific static runtime library. - CmdArgs.push_back("-lSystem"); + if (!isTargetDriverKit()) + CmdArgs.push_back("-lSystem"); // Select the dynamic runtime library and the target specific static library. if (isTargetIOSBased()) { @@ -1356,17 +1572,19 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, /// If the macOS SDK version is the same or earlier than the system version, /// then the SDK version is returned. Otherwise the system version is returned. static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) { - unsigned Major, Minor, Micro; llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); if (!SystemTriple.isMacOSX()) return std::string(MacOSSDKVersion); - SystemTriple.getMacOSXVersion(Major, Minor, Micro); - VersionTuple SystemVersion(Major, Minor, Micro); + VersionTuple SystemVersion; + SystemTriple.getMacOSXVersion(SystemVersion); + + unsigned Major, Minor, Micro; bool HadExtra; if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro, HadExtra)) return std::string(MacOSSDKVersion); VersionTuple SDKVersion(Major, Minor, Micro); + if (SDKVersion > SystemVersion) return SystemVersion.getAsString(); return std::string(MacOSSDKVersion); @@ -1379,6 +1597,8 @@ struct DarwinPlatform { enum SourceKind { /// The OS was specified using the -target argument. TargetArg, + /// The OS was specified using the -mtargetos= argument. + MTargetOSArg, /// The OS was specified using the -m<os>-version-min argument. OSVersionArg, /// The OS was specified using the OS_DEPLOYMENT_TARGET environment. @@ -1426,18 +1646,23 @@ struct DarwinPlatform { /// Returns true if the simulator environment can be inferred from the arch. bool canInferSimulatorFromArch() const { return InferSimulatorFromArch; } + const std::optional<llvm::Triple> &getTargetVariantTriple() const { + return TargetVariantTriple; + } + /// Adds the -m<os>-version-min argument to the compiler invocation. void addOSVersionMinArgument(DerivedArgList &Args, const OptTable &Opts) { if (Argument) return; - assert(Kind != TargetArg && Kind != OSVersionArg && "Invalid kind"); + assert(Kind != TargetArg && Kind != MTargetOSArg && Kind != OSVersionArg && + "Invalid kind"); options::ID Opt; switch (Platform) { case DarwinPlatformKind::MacOS: - Opt = options::OPT_mmacosx_version_min_EQ; + Opt = options::OPT_mmacos_version_min_EQ; break; case DarwinPlatformKind::IPhoneOS: - Opt = options::OPT_miphoneos_version_min_EQ; + Opt = options::OPT_mios_version_min_EQ; break; case DarwinPlatformKind::TvOS: Opt = options::OPT_mtvos_version_min_EQ; @@ -1445,6 +1670,12 @@ struct DarwinPlatform { case DarwinPlatformKind::WatchOS: Opt = options::OPT_mwatchos_version_min_EQ; break; + case DarwinPlatformKind::XROS: + // xrOS always explicitly provides a version in the triple. + return; + case DarwinPlatformKind::DriverKit: + // DriverKit always explicitly provides a version in the triple. + return; } Argument = Args.MakeJoinedArg(nullptr, Opts.getOption(Opt), OSVersion); Args.append(Argument); @@ -1455,6 +1686,7 @@ struct DarwinPlatform { std::string getAsString(DerivedArgList &Args, const OptTable &Opts) { switch (Kind) { case TargetArg: + case MTargetOSArg: case OSVersionArg: case InferredFromSDK: case InferredFromArch: @@ -1466,45 +1698,72 @@ struct DarwinPlatform { llvm_unreachable("Unsupported Darwin Source Kind"); } - static DarwinPlatform - createFromTarget(const llvm::Triple &TT, StringRef OSVersion, Arg *A, - const Optional<DarwinSDKInfo> &SDKInfo) { - DarwinPlatform Result(TargetArg, getPlatformFromOS(TT.getOS()), OSVersion, - A); - unsigned Major, Minor, Micro; - TT.getOSVersion(Major, Minor, Micro); - if (Major == 0) - Result.HasOSVersion = false; - - switch (TT.getEnvironment()) { + void setEnvironment(llvm::Triple::EnvironmentType EnvType, + const VersionTuple &OSVersion, + const std::optional<DarwinSDKInfo> &SDKInfo) { + switch (EnvType) { case llvm::Triple::Simulator: - Result.Environment = DarwinEnvironmentKind::Simulator; + Environment = DarwinEnvironmentKind::Simulator; break; case llvm::Triple::MacABI: { + Environment = DarwinEnvironmentKind::MacCatalyst; // The minimum native macOS target for MacCatalyst is macOS 10.15. - auto NativeTargetVersion = VersionTuple(10, 15); - if (Result.HasOSVersion && SDKInfo) { + NativeTargetVersion = VersionTuple(10, 15); + if (HasOSVersion && SDKInfo) { if (const auto *MacCatalystToMacOSMapping = SDKInfo->getVersionMapping( DarwinSDKInfo::OSEnvPair::macCatalystToMacOSPair())) { if (auto MacOSVersion = MacCatalystToMacOSMapping->map( - VersionTuple(Major, Minor, Micro), NativeTargetVersion, - None)) { + OSVersion, NativeTargetVersion, std::nullopt)) { NativeTargetVersion = *MacOSVersion; } } } - Result.Environment = DarwinEnvironmentKind::MacCatalyst; - Result.NativeTargetVersion = NativeTargetVersion; + // 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: break; } + } + + static DarwinPlatform + createFromTarget(const llvm::Triple &TT, StringRef OSVersion, Arg *A, + std::optional<llvm::Triple> TargetVariantTriple, + const std::optional<DarwinSDKInfo> &SDKInfo) { + DarwinPlatform Result(TargetArg, getPlatformFromOS(TT.getOS()), OSVersion, + A); + VersionTuple OsVersion = TT.getOSVersion(); + if (OsVersion.getMajor() == 0) + Result.HasOSVersion = false; + Result.TargetVariantTriple = TargetVariantTriple; + Result.setEnvironment(TT.getEnvironment(), OsVersion, SDKInfo); return Result; } - static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, - Arg *A) { - return DarwinPlatform(OSVersionArg, Platform, A); + static DarwinPlatform + createFromMTargetOS(llvm::Triple::OSType OS, VersionTuple OSVersion, + llvm::Triple::EnvironmentType Environment, Arg *A, + const std::optional<DarwinSDKInfo> &SDKInfo) { + DarwinPlatform Result(MTargetOSArg, getPlatformFromOS(OS), + OSVersion.getAsString(), A); + Result.InferSimulatorFromArch = false; + Result.setEnvironment(Environment, OSVersion, SDKInfo); + return Result; + } + static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, Arg *A, + bool IsSimulator) { + DarwinPlatform Result{OSVersionArg, Platform, A}; + if (IsSimulator) + Result.Environment = DarwinEnvironmentKind::Simulator; + return Result; } static DarwinPlatform createDeploymentTargetEnv(DarwinPlatformKind Platform, StringRef EnvVarName, @@ -1559,6 +1818,10 @@ private: return DarwinPlatformKind::TvOS; case llvm::Triple::WatchOS: return DarwinPlatformKind::WatchOS; + case llvm::Triple::XROS: + return DarwinPlatformKind::XROS; + case llvm::Triple::DriverKit: + return DarwinPlatformKind::DriverKit; default: llvm_unreachable("Unable to infer Darwin variant"); } @@ -1572,15 +1835,16 @@ private: bool HasOSVersion = true, InferSimulatorFromArch = true; Arg *Argument; StringRef EnvVarName; + std::optional<llvm::Triple> TargetVariantTriple; }; /// Returns the deployment target that's specified using the -m<os>-version-min /// argument. -Optional<DarwinPlatform> +std::optional<DarwinPlatform> getDeploymentTargetFromOSVersionArg(DerivedArgList &Args, const Driver &TheDriver) { - Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); - Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ, + Arg *macOSVersion = Args.getLastArg(options::OPT_mmacos_version_min_EQ); + Arg *iOSVersion = Args.getLastArg(options::OPT_mios_version_min_EQ, options::OPT_mios_simulator_version_min_EQ); Arg *TvOSVersion = Args.getLastArg(options::OPT_mtvos_version_min_EQ, @@ -1588,37 +1852,47 @@ getDeploymentTargetFromOSVersionArg(DerivedArgList &Args, Arg *WatchOSVersion = Args.getLastArg(options::OPT_mwatchos_version_min_EQ, options::OPT_mwatchos_simulator_version_min_EQ); - if (OSXVersion) { + if (macOSVersion) { if (iOSVersion || TvOSVersion || WatchOSVersion) { TheDriver.Diag(diag::err_drv_argument_not_allowed_with) - << OSXVersion->getAsString(Args) + << macOSVersion->getAsString(Args) << (iOSVersion ? iOSVersion : TvOSVersion ? TvOSVersion : WatchOSVersion) ->getAsString(Args); } - return DarwinPlatform::createOSVersionArg(Darwin::MacOS, OSXVersion); + return DarwinPlatform::createOSVersionArg(Darwin::MacOS, macOSVersion, + /*IsSimulator=*/false); } else if (iOSVersion) { if (TvOSVersion || WatchOSVersion) { TheDriver.Diag(diag::err_drv_argument_not_allowed_with) << iOSVersion->getAsString(Args) << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); } - return DarwinPlatform::createOSVersionArg(Darwin::IPhoneOS, iOSVersion); + return DarwinPlatform::createOSVersionArg( + Darwin::IPhoneOS, iOSVersion, + iOSVersion->getOption().getID() == + options::OPT_mios_simulator_version_min_EQ); } else if (TvOSVersion) { if (WatchOSVersion) { TheDriver.Diag(diag::err_drv_argument_not_allowed_with) << TvOSVersion->getAsString(Args) << WatchOSVersion->getAsString(Args); } - return DarwinPlatform::createOSVersionArg(Darwin::TvOS, TvOSVersion); + return DarwinPlatform::createOSVersionArg( + Darwin::TvOS, TvOSVersion, + TvOSVersion->getOption().getID() == + options::OPT_mtvos_simulator_version_min_EQ); } else if (WatchOSVersion) - return DarwinPlatform::createOSVersionArg(Darwin::WatchOS, WatchOSVersion); - return None; + return DarwinPlatform::createOSVersionArg( + Darwin::WatchOS, WatchOSVersion, + WatchOSVersion->getOption().getID() == + options::OPT_mwatchos_simulator_version_min_EQ); + return std::nullopt; } /// Returns the deployment target that's specified using the /// OS_DEPLOYMENT_TARGET environment variable. -Optional<DarwinPlatform> +std::optional<DarwinPlatform> getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, const llvm::Triple &Triple) { std::string Targets[Darwin::LastDarwinPlatform + 1]; @@ -1627,10 +1901,11 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, "IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET", "WATCHOS_DEPLOYMENT_TARGET", + "DRIVERKIT_DEPLOYMENT_TARGET", }; - static_assert(llvm::array_lengthof(EnvVars) == Darwin::LastDarwinPlatform + 1, + static_assert(std::size(EnvVars) == Darwin::LastDarwinPlatform + 1, "Missing platform"); - for (const auto &I : llvm::enumerate(llvm::makeArrayRef(EnvVars))) { + for (const auto &I : llvm::enumerate(llvm::ArrayRef(EnvVars))) { if (char *Env = ::getenv(I.value())) Targets[I.index()] = Env; } @@ -1649,11 +1924,11 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, Targets[Darwin::TvOS] = ""; } else { // Don't allow conflicts in any other platform. - unsigned FirstTarget = llvm::array_lengthof(Targets); - for (unsigned I = 0; I != llvm::array_lengthof(Targets); ++I) { + unsigned FirstTarget = std::size(Targets); + for (unsigned I = 0; I != std::size(Targets); ++I) { if (Targets[I].empty()) continue; - if (FirstTarget == llvm::array_lengthof(Targets)) + if (FirstTarget == std::size(Targets)) FirstTarget = I; else TheDriver.Diag(diag::err_drv_conflicting_deployment_targets) @@ -1661,13 +1936,13 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, } } - for (const auto &Target : llvm::enumerate(llvm::makeArrayRef(Targets))) { + for (const auto &Target : llvm::enumerate(llvm::ArrayRef(Targets))) { if (!Target.value().empty()) return DarwinPlatform::createDeploymentTargetEnv( (Darwin::DarwinPlatformKind)Target.index(), EnvVars[Target.index()], Target.value()); } - return None; + return std::nullopt; } /// Returns the SDK name without the optional prefix that ends with a '.' or an @@ -1682,16 +1957,16 @@ static StringRef dropSDKNamePrefix(StringRef SDKName) { /// Tries to infer the deployment target from the SDK specified by -isysroot /// (or SDKROOT). Uses the version specified in the SDKSettings.json file if /// it's available. -Optional<DarwinPlatform> +std::optional<DarwinPlatform> inferDeploymentTargetFromSDK(DerivedArgList &Args, - const Optional<DarwinSDKInfo> &SDKInfo) { + const std::optional<DarwinSDKInfo> &SDKInfo) { const Arg *A = Args.getLastArg(options::OPT_isysroot); if (!A) - return None; + return std::nullopt; StringRef isysroot = A->getValue(); StringRef SDK = Darwin::getSDKName(isysroot); if (!SDK.size()) - return None; + return std::nullopt; std::string Version; if (SDKInfo) { @@ -1706,26 +1981,33 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args, Version = std::string(SDK.slice(StartVer, EndVer + 1)); } if (Version.empty()) - return None; + return std::nullopt; auto CreatePlatformFromSDKName = - [&](StringRef SDK) -> Optional<DarwinPlatform> { - if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator")) + [&](StringRef SDK) -> std::optional<DarwinPlatform> { + if (SDK.starts_with("iPhoneOS") || SDK.starts_with("iPhoneSimulator")) return DarwinPlatform::createFromSDK( Darwin::IPhoneOS, Version, - /*IsSimulator=*/SDK.startswith("iPhoneSimulator")); - else if (SDK.startswith("MacOSX")) + /*IsSimulator=*/SDK.starts_with("iPhoneSimulator")); + else if (SDK.starts_with("MacOSX")) return DarwinPlatform::createFromSDK(Darwin::MacOS, getSystemOrSDKMacOSVersion(Version)); - else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator")) + else if (SDK.starts_with("WatchOS") || SDK.starts_with("WatchSimulator")) return DarwinPlatform::createFromSDK( Darwin::WatchOS, Version, - /*IsSimulator=*/SDK.startswith("WatchSimulator")); - else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator")) + /*IsSimulator=*/SDK.starts_with("WatchSimulator")); + else if (SDK.starts_with("AppleTVOS") || + SDK.starts_with("AppleTVSimulator")) return DarwinPlatform::createFromSDK( Darwin::TvOS, Version, - /*IsSimulator=*/SDK.startswith("AppleTVSimulator")); - return None; + /*IsSimulator=*/SDK.starts_with("AppleTVSimulator")); + else if (SDK.starts_with("XR")) + return DarwinPlatform::createFromSDK( + Darwin::XROS, Version, + /*IsSimulator=*/SDK.contains("Simulator")); + else if (SDK.starts_with("DriverKit")) + return DarwinPlatform::createFromSDK(Darwin::DriverKit, Version); + return std::nullopt; }; if (auto Result = CreatePlatformFromSDKName(SDK)) return Result; @@ -1735,7 +2017,7 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args, std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, const Driver &TheDriver) { - unsigned Major, Minor, Micro; + VersionTuple OsVersion; llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); switch (OS) { case llvm::Triple::Darwin: @@ -1744,19 +2026,30 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, // macos, use the host triple to infer OS version. if (Triple.isMacOSX() && SystemTriple.isMacOSX() && !Triple.getOSMajorVersion()) - SystemTriple.getMacOSXVersion(Major, Minor, Micro); - else if (!Triple.getMacOSXVersion(Major, Minor, Micro)) + SystemTriple.getMacOSXVersion(OsVersion); + else if (!Triple.getMacOSXVersion(OsVersion)) TheDriver.Diag(diag::err_drv_invalid_darwin_version) << Triple.getOSName(); break; case llvm::Triple::IOS: - Triple.getiOSVersion(Major, Minor, Micro); + if (Triple.isMacCatalystEnvironment() && !Triple.getOSMajorVersion()) { + OsVersion = VersionTuple(13, 1); + } else + OsVersion = Triple.getiOSVersion(); break; case llvm::Triple::TvOS: - Triple.getOSVersion(Major, Minor, Micro); + OsVersion = Triple.getOSVersion(); break; case llvm::Triple::WatchOS: - Triple.getWatchOSVersion(Major, Minor, Micro); + OsVersion = Triple.getWatchOSVersion(); + break; + case llvm::Triple::XROS: + OsVersion = Triple.getOSVersion(); + if (!OsVersion.getMajor()) + OsVersion = OsVersion.withMajorReplaced(1); + break; + case llvm::Triple::DriverKit: + OsVersion = Triple.getDriverKitVersion(); break; default: llvm_unreachable("Unexpected OS type"); @@ -1764,67 +2057,118 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, } std::string OSVersion; - llvm::raw_string_ostream(OSVersion) << Major << '.' << Minor << '.' << Micro; + llvm::raw_string_ostream(OSVersion) + << OsVersion.getMajor() << '.' << OsVersion.getMinor().value_or(0) << '.' + << OsVersion.getSubminor().value_or(0); return OSVersion; } /// Tries to infer the target OS from the -arch. -Optional<DarwinPlatform> +std::optional<DarwinPlatform> inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, const llvm::Triple &Triple, const Driver &TheDriver) { llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS; StringRef MachOArchName = Toolchain.getMachOArchName(Args); - if (MachOArchName == "arm64" || MachOArchName == "arm64e") { -#if __arm64__ - // A clang running on an Apple Silicon mac defaults - // to building for mac when building for arm64 rather than - // defaulting to iOS. + if (MachOArchName == "arm64" || MachOArchName == "arm64e") OSTy = llvm::Triple::MacOSX; -#else - OSTy = llvm::Triple::IOS; -#endif - } else if (MachOArchName == "armv7" || MachOArchName == "armv7s") + else if (MachOArchName == "armv7" || MachOArchName == "armv7s") OSTy = llvm::Triple::IOS; else if (MachOArchName == "armv7k" || MachOArchName == "arm64_32") OSTy = llvm::Triple::WatchOS; else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && MachOArchName != "armv7em") OSTy = llvm::Triple::MacOSX; - if (OSTy == llvm::Triple::UnknownOS) - return None; + return std::nullopt; return DarwinPlatform::createFromArch(OSTy, getOSVersion(OSTy, Triple, TheDriver)); } /// Returns the deployment target that's specified using the -target option. -Optional<DarwinPlatform> getDeploymentTargetFromTargetArg( +std::optional<DarwinPlatform> getDeploymentTargetFromTargetArg( DerivedArgList &Args, const llvm::Triple &Triple, const Driver &TheDriver, - const Optional<DarwinSDKInfo> &SDKInfo) { + const std::optional<DarwinSDKInfo> &SDKInfo) { if (!Args.hasArg(options::OPT_target)) - return None; + return std::nullopt; if (Triple.getOS() == llvm::Triple::Darwin || Triple.getOS() == llvm::Triple::UnknownOS) - return None; + return std::nullopt; std::string OSVersion = getOSVersion(Triple.getOS(), Triple, TheDriver); - return DarwinPlatform::createFromTarget( - Triple, OSVersion, Args.getLastArg(options::OPT_target), SDKInfo); + std::optional<llvm::Triple> TargetVariantTriple; + for (const Arg *A : Args.filtered(options::OPT_darwin_target_variant)) { + llvm::Triple TVT(A->getValue()); + // Find a matching <arch>-<vendor> target variant triple that can be used. + if ((Triple.getArch() == llvm::Triple::aarch64 || + TVT.getArchName() == Triple.getArchName()) && + TVT.getArch() == Triple.getArch() && + TVT.getSubArch() == Triple.getSubArch() && + TVT.getVendor() == Triple.getVendor()) { + if (TargetVariantTriple) + continue; + A->claim(); + // Accept a -target-variant triple when compiling code that may run on + // macOS or Mac Catalyst. + if ((Triple.isMacOSX() && TVT.getOS() == llvm::Triple::IOS && + TVT.isMacCatalystEnvironment()) || + (TVT.isMacOSX() && Triple.getOS() == llvm::Triple::IOS && + Triple.isMacCatalystEnvironment())) { + TargetVariantTriple = TVT; + continue; + } + TheDriver.Diag(diag::err_drv_target_variant_invalid) + << A->getSpelling() << A->getValue(); + } + } + return DarwinPlatform::createFromTarget(Triple, OSVersion, + Args.getLastArg(options::OPT_target), + TargetVariantTriple, SDKInfo); } -Optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS, - const ArgList &Args, - const Driver &TheDriver) { +/// Returns the deployment target that's specified using the -mtargetos option. +std::optional<DarwinPlatform> getDeploymentTargetFromMTargetOSArg( + DerivedArgList &Args, const Driver &TheDriver, + const std::optional<DarwinSDKInfo> &SDKInfo) { + auto *A = Args.getLastArg(options::OPT_mtargetos_EQ); + if (!A) + return std::nullopt; + llvm::Triple TT(llvm::Twine("unknown-apple-") + A->getValue()); + switch (TT.getOS()) { + case llvm::Triple::MacOSX: + case llvm::Triple::IOS: + case llvm::Triple::TvOS: + case llvm::Triple::WatchOS: + case llvm::Triple::XROS: + break; + default: + TheDriver.Diag(diag::err_drv_invalid_os_in_arg) + << TT.getOSName() << A->getAsString(Args); + return std::nullopt; + } + + VersionTuple Version = TT.getOSVersion(); + if (!Version.getMajor()) { + TheDriver.Diag(diag::err_drv_invalid_version_number) + << A->getAsString(Args); + return std::nullopt; + } + return DarwinPlatform::createFromMTargetOS(TT.getOS(), Version, + TT.getEnvironment(), A, SDKInfo); +} + +std::optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS, + const ArgList &Args, + const Driver &TheDriver) { const Arg *A = Args.getLastArg(options::OPT_isysroot); if (!A) - return None; + return std::nullopt; StringRef isysroot = A->getValue(); auto SDKInfoOrErr = parseDarwinSDKInfo(VFS, isysroot); if (!SDKInfoOrErr) { llvm::consumeError(SDKInfoOrErr.takeError()); TheDriver.Diag(diag::warn_drv_darwin_sdk_invalid_settings); - return None; + return std::nullopt; } return *SDKInfoOrErr; } @@ -1858,10 +2202,17 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { SDKInfo = parseSDKSettings(getVFS(), Args, getDriver()); // The OS and the version can be specified using the -target argument. - Optional<DarwinPlatform> OSTarget = + std::optional<DarwinPlatform> OSTarget = getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver(), SDKInfo); if (OSTarget) { - Optional<DarwinPlatform> OSVersionArgTarget = + // Disallow mixing -target and -mtargetos=. + if (const auto *MTargetOSArg = Args.getLastArg(options::OPT_mtargetos_EQ)) { + std::string TargetArgStr = OSTarget->getAsString(Args, Opts); + std::string MTargetOSArgStr = MTargetOSArg->getAsString(Args); + getDriver().Diag(diag::err_drv_cannot_mix_options) + << TargetArgStr << MTargetOSArgStr; + } + std::optional<DarwinPlatform> OSVersionArgTarget = getDeploymentTargetFromOSVersionArg(Args, getDriver()); if (OSVersionArgTarget) { unsigned TargetMajor, TargetMinor, TargetMicro; @@ -1887,11 +2238,23 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { std::string OSVersionArg = OSVersionArgTarget->getAsString(Args, Opts); std::string TargetArg = OSTarget->getAsString(Args, Opts); - getDriver().Diag(clang::diag::warn_drv_overriding_flag_option) + getDriver().Diag(clang::diag::warn_drv_overriding_option) << OSVersionArg << TargetArg; } } } + } else if ((OSTarget = getDeploymentTargetFromMTargetOSArg(Args, getDriver(), + SDKInfo))) { + // The OS target can be specified using the -mtargetos= argument. + // Disallow mixing -mtargetos= and -m<os>version-min=. + std::optional<DarwinPlatform> OSVersionArgTarget = + getDeploymentTargetFromOSVersionArg(Args, getDriver()); + if (OSVersionArgTarget) { + std::string MTargetOSArgStr = OSTarget->getAsString(Args, Opts); + std::string OSVersionArgStr = OSVersionArgTarget->getAsString(Args, Opts); + getDriver().Diag(diag::err_drv_cannot_mix_options) + << MTargetOSArgStr << OSVersionArgStr; + } } else { // The OS target can be specified using the -m<os>version-min argument. OSTarget = getDeploymentTargetFromOSVersionArg(Args, getDriver()); @@ -1902,7 +2265,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple()); if (OSTarget) { // Don't infer simulator from the arch when the SDK is also specified. - Optional<DarwinPlatform> SDKTarget = + std::optional<DarwinPlatform> SDKTarget = inferDeploymentTargetFromSDK(Args, SDKInfo); if (SDKTarget) OSTarget->setEnvironment(SDKTarget->getEnvironment()); @@ -1931,17 +2294,20 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { unsigned Major, Minor, Micro; bool HadExtra; + // The major version should not be over this number. + const unsigned MajorVersionLimit = 1000; // Set the tool chain target information. if (Platform == MacOS) { if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, Micro, HadExtra) || - HadExtra || Major < 10 || Major >= 100 || Minor >= 100 || Micro >= 100) + HadExtra || Major < 10 || Major >= MajorVersionLimit || Minor >= 100 || + Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSTarget->getAsString(Args, Opts); } else if (Platform == IPhoneOS) { if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, Micro, HadExtra) || - HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) + HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSTarget->getAsString(Args, Opts); ; @@ -1973,13 +2339,27 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } else if (Platform == TvOS) { if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, Micro, HadExtra) || - HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) + HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSTarget->getAsString(Args, Opts); } else if (Platform == WatchOS) { if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, Micro, HadExtra) || - HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) + HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << OSTarget->getAsString(Args, Opts); + } else if (Platform == DriverKit) { + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || + HadExtra || Major < 19 || Major >= MajorVersionLimit || Minor >= 100 || + Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << OSTarget->getAsString(Args, Opts); + } else if (Platform == XROS) { + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || + HadExtra || Major < 1 || Major >= MajorVersionLimit || Minor >= 100 || + Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSTarget->getAsString(Args, Opts); } else @@ -1988,42 +2368,60 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { DarwinEnvironmentKind Environment = OSTarget->getEnvironment(); // Recognize iOS targets with an x86 architecture as the iOS simulator. if (Environment == NativeEnvironment && Platform != MacOS && - OSTarget->canInferSimulatorFromArch() && getTriple().isX86()) + Platform != DriverKit && OSTarget->canInferSimulatorFromArch() && + getTriple().isX86()) Environment = Simulator; VersionTuple NativeTargetVersion; if (Environment == MacCatalyst) NativeTargetVersion = OSTarget->getNativeTargetVersion(); setTarget(Platform, Environment, Major, Minor, Micro, NativeTargetVersion); + TargetVariantTriple = OSTarget->getTargetVariantTriple(); if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef SDK = getSDKName(A->getValue()); if (SDK.size() > 0) { size_t StartVer = SDK.find_first_of("0123456789"); StringRef SDKName = SDK.slice(0, StartVer); - if (!SDKName.startswith(getPlatformFamily()) && - !dropSDKNamePrefix(SDKName).startswith(getPlatformFamily())) + if (!SDKName.starts_with(getPlatformFamily()) && + !dropSDKNamePrefix(SDKName).starts_with(getPlatformFamily())) getDriver().Diag(diag::warn_incompatible_sysroot) << SDKName << getPlatformFamily(); } } } -// Returns the effective header sysroot path to use. This comes either from -// -isysroot or --sysroot. -llvm::StringRef DarwinClang::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const { - if(DriverArgs.hasArg(options::OPT_isysroot)) - return DriverArgs.getLastArgValue(options::OPT_isysroot); - if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot; - return "/"; +// For certain platforms/environments almost all resources (e.g., headers) are +// located in sub-directories, e.g., for DriverKit they live in +// <SYSROOT>/System/DriverKit/usr/include (instead of <SYSROOT>/usr/include). +static void AppendPlatformPrefix(SmallString<128> &Path, + const llvm::Triple &T) { + if (T.isDriverKit()) { + llvm::sys::path::append(Path, "System", "DriverKit"); + } +} + +// Returns the effective sysroot from either -isysroot or --sysroot, plus the +// platform prefix (if any). +llvm::SmallString<128> +DarwinClang::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const { + llvm::SmallString<128> Path("/"); + if (DriverArgs.hasArg(options::OPT_isysroot)) + Path = DriverArgs.getLastArgValue(options::OPT_isysroot); + else if (!getDriver().SysRoot.empty()) + Path = getDriver().SysRoot; + + if (hasEffectiveTriple()) { + AppendPlatformPrefix(Path, getEffectiveTriple()); + } + return Path; } void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { const Driver &D = getDriver(); - llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); + llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs); bool NoStdInc = DriverArgs.hasArg(options::OPT_nostdinc); bool NoStdlibInc = DriverArgs.hasArg(options::OPT_nostdlibinc); @@ -2108,22 +2506,27 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( // Also check whether this is used for setting library search paths. ToolChain::AddClangCXXStdlibIncludeArgs(DriverArgs, CC1Args); - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) + if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, + options::OPT_nostdincxx)) return; - llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); + llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs); switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: { - // On Darwin, libc++ can be installed in one of the following two places: - // 1. Alongside the compiler in <install>/include/c++/v1 - // 2. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1 + // On Darwin, libc++ can be installed in one of the following places: + // 1. Alongside the compiler in <install>/include/c++/v1 + // 2. Alongside the compiler in <clang-executable-folder>/../include/c++/v1 + // 3. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1 // - // The precendence of paths is as listed above, i.e. we take the first path - // that exists. Also note that we never include libc++ twice -- we take the - // first path that exists and don't send the other paths to CC1 (otherwise + // The precedence of paths is as listed above, i.e. we take the first path + // that exists. Note that we never include libc++ twice -- we take the first + // path that exists and don't send the other paths to CC1 (otherwise // include_next could break). + // + // Also note that in most cases, (1) and (2) are exactly the same path. + // Those two paths will differ only when the `clang` program being run + // is actually a symlink to the real executable. // Check for (1) // Get from '<install>/bin' to '<install>/include/c++/v1'. @@ -2140,7 +2543,20 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( << "\"\n"; } - // Otherwise, check for (2) + // (2) Check for the folder where the executable is located, if different. + if (getDriver().getInstalledDir() != getDriver().Dir) { + InstallBin = llvm::StringRef(getDriver().Dir); + llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1"); + if (getVFS().exists(InstallBin)) { + addSystemInclude(DriverArgs, CC1Args, InstallBin); + return; + } else if (DriverArgs.hasArg(options::OPT_v)) { + llvm::errs() << "ignoring nonexistent directory \"" << InstallBin + << "\"\n"; + } + } + + // Otherwise, check for (3) llvm::SmallString<128> SysrootUsr = Sysroot; llvm::sys::path::append(SysrootUsr, "usr", "include", "c++", "v1"); if (getVFS().exists(SysrootUsr)) { @@ -2164,17 +2580,6 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( switch (arch) { default: break; - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "powerpc-apple-darwin10", - arch == llvm::Triple::ppc64 ? "ppc64" : ""); - IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.0.0", "powerpc-apple-darwin10", - arch == llvm::Triple::ppc64 ? "ppc64" : ""); - break; - case llvm::Triple::x86: case llvm::Triple::x86_64: IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, @@ -2213,6 +2618,7 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( break; } } + void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); @@ -2220,6 +2626,8 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); break; case ToolChain::CST_Libstdcxx: @@ -2274,6 +2682,12 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a"); } else if (isTargetIPhoneOS()) { llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a"); + } else if (isTargetDriverKit()) { + // DriverKit doesn't want extra runtime support. + } else if (isTargetXROSDevice()) { + llvm::sys::path::append( + P, llvm::Twine("libclang_rt.cc_kext_") + + llvm::Triple::getOSTypeName(llvm::Triple::XROS) + ".a"); } else { llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); } @@ -2301,12 +2715,9 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches either the toolchain // triple arch, or the arch being bound. - llvm::Triple::ArchType XarchArch = - tools::darwin::getArchTypeForMachOArchName(A->getValue(0)); - if (!(XarchArch == getArch() || - (!BoundArch.empty() && - XarchArch == - tools::darwin::getArchTypeForMachOArchName(BoundArch)))) + StringRef XarchArch = A->getValue(0); + if (!(XarchArch == getArchName() || + (!BoundArch.empty() && XarchArch == BoundArch))) continue; Arg *OriginalArg = A; @@ -2376,19 +2787,11 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, DAL->AddFlagArg( A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings)); break; - - case options::OPT_fpascal_strings: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings)); - break; - - case options::OPT_fno_pascal_strings: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings)); - break; } } // Add the arch options based on the particular spelling of -arch, to match - // how the driver driver works. + // how the driver works. if (!BoundArch.empty()) { StringRef Name = BoundArch; const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ); @@ -2499,11 +2902,36 @@ bool Darwin::isAlignedAllocationUnavailable() const { case WatchOS: // Earlier than 4.0. OS = llvm::Triple::WatchOS; break; + case XROS: // Always available. + return false; + case DriverKit: // Always available. + return false; } return TargetVersion < alignedAllocMinVersion(OS); } +static bool sdkSupportsBuiltinModules(const Darwin::DarwinPlatformKind &TargetPlatform, const std::optional<DarwinSDKInfo> &SDKInfo) { + if (!SDKInfo) + return false; + + VersionTuple SDKVersion = SDKInfo->getVersion(); + switch (TargetPlatform) { + case Darwin::MacOS: + return SDKVersion >= VersionTuple(99U); + case Darwin::IPhoneOS: + return SDKVersion >= VersionTuple(99U); + case Darwin::TvOS: + return SDKVersion >= VersionTuple(99U); + case Darwin::WatchOS: + return SDKVersion >= VersionTuple(99U); + case Darwin::XROS: + return SDKVersion >= VersionTuple(99U); + default: + return true; + } +} + void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const { @@ -2514,6 +2942,45 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, isAlignedAllocationUnavailable()) CC1Args.push_back("-faligned-alloc-unavailable"); + addClangCC1ASTargetOptions(DriverArgs, CC1Args); + + // Enable compatibility mode for NSItemProviderCompletionHandler in + // Foundation/NSItemProvider.h. + CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking"); + + // Give static local variables in inline functions hidden visibility when + // -fvisibility-inlines-hidden is enabled. + if (!DriverArgs.getLastArgNoClaim( + options::OPT_fvisibility_inlines_hidden_static_local_var, + options::OPT_fno_visibility_inlines_hidden_static_local_var)) + CC1Args.push_back("-fvisibility-inlines-hidden-static-local-var"); + + // Earlier versions of the darwin SDK have the C standard library headers + // all together in the Darwin module. That leads to module cycles with + // the _Builtin_ modules. e.g. <inttypes.h> on darwin includes <stdint.h>. + // The builtin <stdint.h> include-nexts <stdint.h>. When both of those + // darwin headers are in the Darwin module, there's a module cycle Darwin -> + // _Builtin_stdint -> Darwin (i.e. inttypes.h (darwin) -> stdint.h (builtin) -> + // stdint.h (darwin)). This is fixed in later versions of the darwin SDK, + // but until then, the builtin headers need to join the system modules. + // i.e. when the builtin stdint.h is in the Darwin module too, the cycle + // goes away. Note that -fbuiltin-headers-in-system-modules does nothing + // to fix the same problem with C++ headers, and is generally fragile. + if (!sdkSupportsBuiltinModules(TargetPlatform, SDKInfo)) + CC1Args.push_back("-fbuiltin-headers-in-system-modules"); + + if (!DriverArgs.hasArgNoClaim(options::OPT_fdefine_target_os_macros, + options::OPT_fno_define_target_os_macros)) + CC1Args.push_back("-fdefine-target-os-macros"); +} + +void Darwin::addClangCC1ASTargetOptions( + const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1ASArgs) const { + if (TargetVariantTriple) { + CC1ASArgs.push_back("-darwin-target-variant-triple"); + CC1ASArgs.push_back(Args.MakeArgString(TargetVariantTriple->getTriple())); + } + if (SDKInfo) { /// Pass the SDK version to the compiler when the SDK information is /// available. @@ -2521,32 +2988,45 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, std::string Arg; llvm::raw_string_ostream OS(Arg); OS << "-target-sdk-version=" << V; - CC1Args.push_back(DriverArgs.MakeArgString(OS.str())); + CC1ASArgs.push_back(Args.MakeArgString(OS.str())); }; if (isTargetMacCatalyst()) { if (const auto *MacOStoMacCatalystMapping = SDKInfo->getVersionMapping( DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) { - Optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map( - SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(), None); + std::optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map( + SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(), + std::nullopt); EmitTargetSDKVersionArg( SDKVersion ? *SDKVersion : minimumMacCatalystDeploymentTarget()); } } else { EmitTargetSDKVersionArg(SDKInfo->getVersion()); } - } - - // Enable compatibility mode for NSItemProviderCompletionHandler in - // Foundation/NSItemProvider.h. - CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking"); - // Give static local variables in inline functions hidden visibility when - // -fvisibility-inlines-hidden is enabled. - if (!DriverArgs.getLastArgNoClaim( - options::OPT_fvisibility_inlines_hidden_static_local_var, - options::OPT_fno_visibility_inlines_hidden_static_local_var)) - CC1Args.push_back("-fvisibility-inlines-hidden-static-local-var"); + /// Pass the target variant SDK version to the compiler when the SDK + /// information is available and is required for target variant. + if (TargetVariantTriple) { + if (isTargetMacCatalyst()) { + std::string Arg; + llvm::raw_string_ostream OS(Arg); + OS << "-darwin-target-variant-sdk-version=" << SDKInfo->getVersion(); + CC1ASArgs.push_back(Args.MakeArgString(OS.str())); + } else if (const auto *MacOStoMacCatalystMapping = + SDKInfo->getVersionMapping( + DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) { + if (std::optional<VersionTuple> SDKVersion = + MacOStoMacCatalystMapping->map( + SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(), + std::nullopt)) { + std::string Arg; + llvm::raw_string_ostream OS(Arg); + OS << "-darwin-target-variant-sdk-version=" << *SDKVersion; + CC1ASArgs.push_back(Args.MakeArgString(OS.str())); + } + } + } + } } DerivedArgList * @@ -2555,7 +3035,6 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, // First get the generic Apple args, before moving onto Darwin-specific ones. DerivedArgList *DAL = MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind); - const OptTable &Opts = getDriver().getOpts(); // If no architecture is bound, none of the translations here are relevant. if (BoundArch.empty()) @@ -2570,7 +3049,7 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, // FIXME: It would be far better to avoid inserting those -static arguments, // but we can't check the deployment target in the translation code until // it is set here. - if (isTargetWatchOSBased() || + if (isTargetWatchOSBased() || isTargetDriverKit() || isTargetXROS() || (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) { for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { Arg *A = *it; @@ -2587,26 +3066,6 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, } } - if (!Args.getLastArg(options::OPT_stdlib_EQ) && - GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ), - "libc++"); - - // Validate the C++ standard library choice. - CXXStdlibType Type = GetCXXStdlibType(*DAL); - if (Type == ToolChain::CST_Libcxx) { - // Check whether the target provides libc++. - StringRef where; - - // Complain about targeting iOS < 5.0 in any way. - if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0)) - where = "iOS 5.0"; - - if (where != StringRef()) { - getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where; - } - } - auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch); if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) { if (Args.hasFlag(options::OPT_fomit_frame_pointer, @@ -2618,13 +3077,19 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, return DAL; } -bool MachO::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel MachO::getDefaultUnwindTableLevel(const ArgList &Args) const { // Unwind tables are not emitted if -fno-exceptions is supplied (except when // targeting x86_64). - return getArch() == llvm::Triple::x86_64 || - (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj && - Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, - true)); + if (getArch() == llvm::Triple::x86_64 || + (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj && + Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, + true))) + return (getArch() == llvm::Triple::aarch64 || + getArch() == llvm::Triple::aarch64_32) + ? UnwindTableLevel::Synchronous + : UnwindTableLevel::Asynchronous; + + return UnwindTableLevel::None; } bool MachO::UseDwarfDebugFlags() const { @@ -2633,6 +3098,12 @@ bool MachO::UseDwarfDebugFlags() const { return false; } +std::string MachO::GetGlobalDebugPathRemapping() const { + if (const char *S = ::getenv("RC_DEBUG_PREFIX_MAP")) + return S; + return {}; +} + llvm::ExceptionHandling Darwin::GetExceptionModel(const ArgList &Args) const { // Darwin uses SjLj exceptions on ARM. if (getTriple().getArch() != llvm::Triple::arm && @@ -2656,7 +3127,7 @@ bool Darwin::SupportsEmbeddedBitcode() const { bool MachO::isPICDefault() const { return true; } -bool MachO::isPIEDefault() const { return false; } +bool MachO::isPIEDefault(const llvm::opt::ArgList &Args) const { return false; } bool MachO::isPICDefaultForced() const { return (getArch() == llvm::Triple::x86_64 || @@ -2672,6 +3143,8 @@ void Darwin::addMinVersionArgs(const ArgList &Args, ArgStringList &CmdArgs) const { VersionTuple TargetVersion = getTripleTargetVersion(); + assert(!isTargetXROS() && "xrOS always uses -platform-version"); + if (isTargetWatchOS()) CmdArgs.push_back("-watchos_version_min"); else if (isTargetWatchOSSimulator()) @@ -2680,6 +3153,8 @@ void Darwin::addMinVersionArgs(const ArgList &Args, CmdArgs.push_back("-tvos_version_min"); else if (isTargetTvOSSimulator()) CmdArgs.push_back("-tvos_simulator_version_min"); + else if (isTargetDriverKit()) + CmdArgs.push_back("-driverkit_version_min"); else if (isTargetIOSSimulator()) CmdArgs.push_back("-ios_simulator_version_min"); else if (isTargetIOSBased()) @@ -2695,6 +3170,25 @@ void Darwin::addMinVersionArgs(const ArgList &Args, if (!MinTgtVers.empty() && MinTgtVers > TargetVersion) TargetVersion = MinTgtVers; CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + if (TargetVariantTriple) { + assert(isTargetMacOSBased() && "unexpected target"); + VersionTuple VariantTargetVersion; + if (TargetVariantTriple->isMacOSX()) { + CmdArgs.push_back("-macosx_version_min"); + TargetVariantTriple->getMacOSXVersion(VariantTargetVersion); + } else { + assert(TargetVariantTriple->isiOS() && + TargetVariantTriple->isMacCatalystEnvironment() && + "unexpected target variant triple"); + CmdArgs.push_back("-maccatalyst_version_min"); + VariantTargetVersion = TargetVariantTriple->getiOSVersion(); + } + VersionTuple MinTgtVers = + TargetVariantTriple->getMinimumSupportedOSVersion(); + if (MinTgtVers.getMajor() && MinTgtVers > VariantTargetVersion) + VariantTargetVersion = MinTgtVers; + CmdArgs.push_back(Args.MakeArgString(VariantTargetVersion.getAsString())); + } } static const char *getPlatformName(Darwin::DarwinPlatformKind Platform, @@ -2710,58 +3204,100 @@ static const char *getPlatformName(Darwin::DarwinPlatformKind Platform, return "tvos"; case Darwin::WatchOS: return "watchos"; + case Darwin::XROS: + return "xros"; + case Darwin::DriverKit: + return "driverkit"; } llvm_unreachable("invalid platform"); } void Darwin::addPlatformVersionArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { - // -platform_version <platform> <target_version> <sdk_version> - // Both the target and SDK version support only up to 3 components. - CmdArgs.push_back("-platform_version"); - std::string PlatformName = getPlatformName(TargetPlatform, TargetEnvironment); - if (TargetEnvironment == Darwin::Simulator) - PlatformName += "-simulator"; - CmdArgs.push_back(Args.MakeArgString(PlatformName)); - VersionTuple TargetVersion = getTripleTargetVersion().withoutBuild(); - VersionTuple MinTgtVers = getEffectiveTriple().getMinimumSupportedOSVersion(); - if (!MinTgtVers.empty() && MinTgtVers > TargetVersion) - TargetVersion = MinTgtVers; - CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + auto EmitPlatformVersionArg = + [&](const VersionTuple &TV, Darwin::DarwinPlatformKind TargetPlatform, + Darwin::DarwinEnvironmentKind TargetEnvironment, + const llvm::Triple &TT) { + // -platform_version <platform> <target_version> <sdk_version> + // Both the target and SDK version support only up to 3 components. + CmdArgs.push_back("-platform_version"); + std::string PlatformName = + getPlatformName(TargetPlatform, TargetEnvironment); + if (TargetEnvironment == Darwin::Simulator) + PlatformName += "-simulator"; + CmdArgs.push_back(Args.MakeArgString(PlatformName)); + VersionTuple TargetVersion = TV.withoutBuild(); + if ((TargetPlatform == Darwin::IPhoneOS || + TargetPlatform == Darwin::TvOS) && + getTriple().getArchName() == "arm64e" && + TargetVersion.getMajor() < 14) { + // arm64e slice is supported on iOS/tvOS 14+ only. + TargetVersion = VersionTuple(14, 0); + } + VersionTuple MinTgtVers = TT.getMinimumSupportedOSVersion(); + if (!MinTgtVers.empty() && MinTgtVers > TargetVersion) + TargetVersion = MinTgtVers; + CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + + if (TargetPlatform == IPhoneOS && TargetEnvironment == MacCatalyst) { + // Mac Catalyst programs must use the appropriate iOS SDK version + // that corresponds to the macOS SDK version used for the compilation. + std::optional<VersionTuple> iOSSDKVersion; + if (SDKInfo) { + if (const auto *MacOStoMacCatalystMapping = + SDKInfo->getVersionMapping( + DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) { + iOSSDKVersion = MacOStoMacCatalystMapping->map( + SDKInfo->getVersion().withoutBuild(), + minimumMacCatalystDeploymentTarget(), std::nullopt); + } + } + CmdArgs.push_back(Args.MakeArgString( + (iOSSDKVersion ? *iOSSDKVersion + : minimumMacCatalystDeploymentTarget()) + .getAsString())); + return; + } - if (isTargetMacCatalyst()) { - // Mac Catalyst programs must use the appropriate iOS SDK version - // that corresponds to the macOS SDK version used for the compilation. - Optional<VersionTuple> iOSSDKVersion; - if (SDKInfo) { - if (const auto *MacOStoMacCatalystMapping = SDKInfo->getVersionMapping( - DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) { - iOSSDKVersion = MacOStoMacCatalystMapping->map( - SDKInfo->getVersion().withoutBuild(), - minimumMacCatalystDeploymentTarget(), None); - } - } - CmdArgs.push_back(Args.MakeArgString( - (iOSSDKVersion ? *iOSSDKVersion : minimumMacCatalystDeploymentTarget()) - .getAsString())); + if (SDKInfo) { + VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild(); + if (!SDKVersion.getMinor()) + SDKVersion = VersionTuple(SDKVersion.getMajor(), 0); + CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString())); + } else { + // Use an SDK version that's matching the deployment target if the SDK + // version is missing. This is preferred over an empty SDK version + // (0.0.0) as the system's runtime might expect the linked binary to + // contain a valid SDK version in order for the binary to work + // correctly. It's reasonable to use the deployment target version as + // a proxy for the SDK version because older SDKs don't guarantee + // support for deployment targets newer than the SDK versions, so that + // rules out using some predetermined older SDK version, which leaves + // the deployment target version as the only reasonable choice. + CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + } + }; + EmitPlatformVersionArg(getTripleTargetVersion(), TargetPlatform, + TargetEnvironment, getEffectiveTriple()); + if (!TargetVariantTriple) return; - } - - if (SDKInfo) { - VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild(); - CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString())); + Darwin::DarwinPlatformKind Platform; + Darwin::DarwinEnvironmentKind Environment; + VersionTuple TargetVariantVersion; + if (TargetVariantTriple->isMacOSX()) { + TargetVariantTriple->getMacOSXVersion(TargetVariantVersion); + Platform = Darwin::MacOS; + Environment = Darwin::NativeEnvironment; } else { - // Use an SDK version that's matching the deployment target if the SDK - // version is missing. This is preferred over an empty SDK version (0.0.0) - // as the system's runtime might expect the linked binary to contain a - // valid SDK version in order for the binary to work correctly. It's - // reasonable to use the deployment target version as a proxy for the - // SDK version because older SDKs don't guarantee support for deployment - // targets newer than the SDK versions, so that rules out using some - // predetermined older SDK version, which leaves the deployment target - // version as the only reasonable choice. - CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + assert(TargetVariantTriple->isiOS() && + TargetVariantTriple->isMacCatalystEnvironment() && + "unexpected target variant triple"); + TargetVariantVersion = TargetVariantTriple->getiOSVersion(); + Platform = Darwin::IPhoneOS; + Environment = Darwin::MacCatalyst; } + EmitPlatformVersionArg(TargetVariantVersion, Platform, Environment, + *TargetVariantTriple); } // Add additional link args for the -dynamiclib option. @@ -2866,7 +3402,7 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, } void Darwin::CheckObjCARC() const { - if (isTargetIOSBased() || isTargetWatchOSBased() || + if (isTargetIOSBased() || isTargetWatchOSBased() || isTargetXROS() || (isTargetMacOSBased() && !isMacosxVersionLT(10, 6))) return; getDriver().Diag(diag::err_arc_unsupported_on_toolchain); @@ -2882,7 +3418,6 @@ SanitizerMask Darwin::getSupportedSanitizers() const { Res |= SanitizerKind::Leak; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; - Res |= SanitizerKind::Function; Res |= SanitizerKind::ObjCCast; // Prior to 10.9, macOS shipped a version of the C++ standard library without @@ -2892,16 +3427,15 @@ SanitizerMask Darwin::getSupportedSanitizers() const { !(isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0))) Res |= SanitizerKind::Vptr; - if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) { + if ((IsX86_64 || IsAArch64) && + (isTargetMacOSBased() || isTargetIOSSimulator() || + isTargetTvOSSimulator() || isTargetWatchOSSimulator())) { Res |= SanitizerKind::Thread; - } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) { - if (IsX86_64) - Res |= SanitizerKind::Thread; } return Res; } void Darwin::printVerboseInfo(raw_ostream &OS) const { - CudaInstallation.print(OS); - RocmInstallation.print(OS); + CudaInstallation->print(OS); + RocmInstallation->print(OS); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h index 4de122c8d513..5e60b0841d6d 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H #include "Cuda.h" +#include "LazyDetector.h" #include "ROCm.h" #include "clang/Basic/DarwinSDKInfo.h" #include "clang/Basic/LangOptions.h" @@ -28,7 +29,8 @@ namespace tools { namespace darwin { llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str); -void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str); +void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str, + const llvm::opt::ArgList &Args); class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool { virtual void anchor(); @@ -63,8 +65,8 @@ class LLVM_LIBRARY_VISIBILITY Linker : public MachOTool { bool NeedsTempPath(const InputInfoList &Inputs) const; void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - const InputInfoList &Inputs, unsigned Version[5], - bool LinkerIsLLD, bool LinkerIsLLDDarwinNew) const; + const InputInfoList &Inputs, VersionTuple Version, + bool LinkerIsLLD, bool UsePlatformVersion) const; public: Linker(const ToolChain &TC) : MachOTool("darwin::Linker", "linker", TC) {} @@ -78,6 +80,20 @@ public: const char *LinkingOutput) const override; }; +class LLVM_LIBRARY_VISIBILITY StaticLibTool : public MachOTool { +public: + StaticLibTool(const ToolChain &TC) + : MachOTool("darwin::StaticLibTool", "static-lib-linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool { public: Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", TC) {} @@ -125,6 +141,7 @@ class LLVM_LIBRARY_VISIBILITY MachO : public ToolChain { protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + Tool *buildStaticLibTool() const override; Tool *getTool(Action::ActionClass AC) const override; private: @@ -132,6 +149,9 @@ private: mutable std::unique_ptr<tools::darwin::Dsymutil> Dsymutil; mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug; + /// The version of the linker known to be available in the tool chain. + mutable std::optional<VersionTuple> LinkerVersion; + public: MachO(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); @@ -144,6 +164,10 @@ public: /// example, Apple treats different ARM variations as distinct architectures. StringRef getMachOArchName(const llvm::opt::ArgList &Args) const; + /// Get the version of the linker known to be available for a particular + /// compiler invocation (via the `-mlinker-version=` arg). + VersionTuple getLinkerVersion(const llvm::opt::ArgList &Args) const; + /// Add the linker arguments to link the ARC runtime library. virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const {} @@ -216,10 +240,6 @@ public: // expected to use /usr/include/Block.h. return true; } - bool IsIntegratedAssemblerDefault() const override { - // Default integrated assembler to on for Apple's MachO targets. - return true; - } bool IsMathErrnoDefault() const override { return false; } @@ -232,19 +252,21 @@ public: bool UseObjCMixedDispatch() const override { return true; } - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; } bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; bool SupportsProfiling() const override; bool UseDwarfDebugFlags() const override; + std::string GetGlobalDebugPathRemapping() const override; llvm::ExceptionHandling GetExceptionModel(const llvm::opt::ArgList &Args) const override { @@ -276,7 +298,9 @@ public: IPhoneOS, TvOS, WatchOS, - LastDarwinPlatform = WatchOS + DriverKit, + XROS, + LastDarwinPlatform = DriverKit }; enum DarwinEnvironmentKind { NativeEnvironment, @@ -293,10 +317,13 @@ public: mutable VersionTuple OSTargetVersion; /// The information about the darwin SDK that was used. - mutable Optional<DarwinSDKInfo> SDKInfo; + mutable std::optional<DarwinSDKInfo> SDKInfo; + + /// The target variant triple that was specified (if any). + mutable std::optional<llvm::Triple> TargetVariantTriple; - CudaInstallationDetector CudaInstallation; - RocmInstallationDetector RocmInstallation; + LazyDetector<CudaInstallationDetector> CudaInstallation; + LazyDetector<RocmInstallationDetector> RocmInstallation; private: void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; @@ -323,7 +350,7 @@ public: bool isKernelStatic() const override { return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) && - !isTargetWatchOS()); + !isTargetWatchOS() && !isTargetDriverKit()); } void addProfileRTLibs(const llvm::opt::ArgList &Args, @@ -379,6 +406,16 @@ public: return isTargetIPhoneOS() || isTargetIOSSimulator(); } + bool isTargetXROSDevice() const { + return TargetPlatform == XROS && TargetEnvironment == NativeEnvironment; + } + + bool isTargetXROSSimulator() const { + return TargetPlatform == XROS && TargetEnvironment == Simulator; + } + + bool isTargetXROS() const { return TargetPlatform == XROS; } + bool isTargetTvOS() const { assert(TargetInitialized && "Target not initialized!"); return TargetPlatform == TvOS && TargetEnvironment == NativeEnvironment; @@ -409,6 +446,11 @@ public: return TargetPlatform == WatchOS; } + bool isTargetDriverKit() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == DriverKit; + } + bool isTargetMacCatalyst() const { return TargetPlatform == IPhoneOS && TargetEnvironment == MacCatalyst; } @@ -473,6 +515,10 @@ protected: llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + void addClangCC1ASTargetOptions( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1ASArgs) const override; + StringRef getPlatformFamily() const; StringRef getOSLibraryNameSuffix(bool IgnoreSim = false) const override; @@ -512,7 +558,8 @@ public: GetDefaultStackProtectorLevel(bool KernelOrKext) const override { // Stack protectors default to on for user code on 10.5, // and for everything in 10.6 and beyond - if (isTargetIOSBased() || isTargetWatchOSBased()) + if (isTargetIOSBased() || isTargetWatchOSBased() || isTargetDriverKit() || + isTargetXROS()) return LangOptions::SSPOn; else if (isTargetMacOSBased() && !isMacosxVersionLT(10, 6)) return LangOptions::SSPOn; @@ -590,7 +637,8 @@ private: llvm::StringRef ArchDir, llvm::StringRef BitDir) const; - llvm::StringRef GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const; + llvm::SmallString<128> + GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp index 9568b47e89e6..9942fc632e0a 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -19,21 +20,19 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; -/// DragonFly Tools - -// For now, DragonFly Assemble does just about the same as for -// FreeBSD, but this may change soon. void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - claimNoWarnArgs(Args); + const auto &ToolChain = static_cast<const DragonFly &>(getToolChain()); ArgStringList CmdArgs; + claimNoWarnArgs(Args); + // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct as in the base system to assemble 32-bit code. - if (getToolChain().getArch() == llvm::Triple::x86) + if (ToolChain.getArch() == llvm::Triple::x86) CmdArgs.push_back("--32"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -44,7 +43,7 @@ void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as")); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -55,21 +54,27 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); + const auto &ToolChain = static_cast<const DragonFly &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool Static = Args.hasArg(options::OPT_static); + const bool Shared = Args.hasArg(options::OPT_shared); + const bool Profiling = Args.hasArg(options::OPT_pg); + const bool Pie = Args.hasArg(options::OPT_pie); ArgStringList CmdArgs; if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_static)) { + if (Static) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("-Bshareable"); - else { + if (Shared) + CmdArgs.push_back("-shared"); + else if (!Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); } @@ -79,75 +84,92 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct ld in the base system to link 32-bit code. - if (getToolChain().getArch() == llvm::Triple::x86) { + if (Arch == llvm::Triple::x86) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); } + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("gcrt1.o"))); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + const char *crt1 = nullptr; + const char *crtbegin = nullptr; + if (!Shared) { + if (Profiling) + crt1 = "gcrt1.o"; else { - if (Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("Scrt1.o"))); + if (Pie) + crt1 = "Scrt1.o"; else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); + crt1 = "crt1.o"; } } - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); + + if (Shared || Pie) + crtbegin = "crtbeginS.o"; else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - } + crtbegin = "crtbegin.o"; - Args.AddAllArgs(CmdArgs, - {options::OPT_L, options::OPT_T_Group, options::OPT_e}); + if (crt1) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_s, options::OPT_t, options::OPT_r}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - CmdArgs.push_back("-L/usr/lib/gcc80"); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - if (!Args.hasArg(options::OPT_static)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { + if (!Static) { CmdArgs.push_back("-rpath"); CmdArgs.push_back("/usr/lib/gcc80"); } + // Use the static OpenMP runtime with -static-openmp + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + if (D.CCCIsCXX()) { - if (getToolChain().ShouldLinkCXXStdlib(Args)) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); CmdArgs.push_back("-lm"); } if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); - if (!Args.hasArg(options::OPT_nolibc)) { + if (!Args.hasArg(options::OPT_nolibc)) CmdArgs.push_back("-lc"); - } - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_static_libgcc)) { + if (Static || Args.hasArg(options::OPT_static_libgcc)) { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("-lgcc_eh"); } else { if (Args.hasArg(options::OPT_shared_libgcc)) { CmdArgs.push_back("-lgcc_pic"); - if (!Args.hasArg(options::OPT_shared)) + if (!Shared) CmdArgs.push_back("-lgcc"); } else { CmdArgs.push_back("-lgcc"); @@ -158,19 +180,21 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + const char *crtend = nullptr; + if (Shared || Pie) + crtend ="crtendS.o"; else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); + crtend = "crtend.o"; + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } - getToolChain().addProfileRTLibs(Args, CmdArgs); + ToolChain.addProfileRTLibs(Args, CmdArgs); - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -188,8 +212,35 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); - getFilePaths().push_back("/usr/lib"); - getFilePaths().push_back("/usr/lib/gcc80"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/gcc80")); +} + +void DragonFly::AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); +} + +void DragonFly::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/c++/8.0"), "", "", + DriverArgs, CC1Args); } Tool *DragonFly::buildAssembler() const { diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h index 3ed5acefaefb..715f6b45519b 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.h @@ -16,9 +16,10 @@ namespace clang { namespace driver { namespace tools { -/// dragonfly -- Directly call GNU Binutils assembler and linker + +/// Directly call GNU Binutils assembler and linker namespace dragonfly { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("dragonfly::Assembler", "assembler", TC) {} @@ -31,7 +32,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("dragonfly::Linker", "linker", TC) {} @@ -55,6 +56,13 @@ public: bool IsMathErrnoDefault() const override { return false; } + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp index 1bfad6115d51..03d68c3df7fb 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp @@ -6,11 +6,17 @@ // //===----------------------------------------------------------------------===// - #include "Flang.h" +#include "Arch/RISCV.h" #include "CommonArgs.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/Driver/Options.h" +#include "llvm/Frontend/Debug/Options.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/RISCVISAInfo.h" +#include "llvm/TargetParser/RISCVTargetParser.h" #include <cassert> @@ -19,54 +25,653 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -void Flang::AddFortranDialectOptions(const ArgList &Args, +/// Add -x lang to \p CmdArgs for \p Input. +static void addDashXForInput(const ArgList &Args, const InputInfo &Input, + ArgStringList &CmdArgs) { + CmdArgs.push_back("-x"); + // Map the driver type to the frontend type. + CmdArgs.push_back(types::getTypeName(Input.getType())); +} + +void Flang::addFortranDialectOptions(const ArgList &Args, ArgStringList &CmdArgs) const { - Args.AddAllArgs( - CmdArgs, {options::OPT_ffixed_form, options::OPT_ffree_form, - options::OPT_ffixed_line_length_EQ, options::OPT_fopenmp, - options::OPT_fopenacc, options::OPT_finput_charset_EQ, - options::OPT_fimplicit_none, options::OPT_fno_implicit_none, - options::OPT_fbackslash, options::OPT_fno_backslash, - options::OPT_flogical_abbreviations, - options::OPT_fno_logical_abbreviations, - options::OPT_fxor_operator, options::OPT_fno_xor_operator, - options::OPT_falternative_parameter_statement, - options::OPT_fdefault_real_8, options::OPT_fdefault_integer_8, - options::OPT_fdefault_double_8, options::OPT_flarge_sizes}); -} - -void Flang::AddPreprocessingOptions(const ArgList &Args, + Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form, + options::OPT_ffree_form, + options::OPT_ffixed_line_length_EQ, + options::OPT_fopenmp, + options::OPT_fopenmp_version_EQ, + options::OPT_fopenacc, + options::OPT_finput_charset_EQ, + options::OPT_fimplicit_none, + options::OPT_fno_implicit_none, + options::OPT_fbackslash, + options::OPT_fno_backslash, + options::OPT_flogical_abbreviations, + options::OPT_fno_logical_abbreviations, + options::OPT_fxor_operator, + options::OPT_fno_xor_operator, + options::OPT_falternative_parameter_statement, + options::OPT_fdefault_real_8, + options::OPT_fdefault_integer_8, + options::OPT_fdefault_double_8, + options::OPT_flarge_sizes, + options::OPT_fno_automatic}); +} + +void Flang::addPreprocessingOptions(const ArgList &Args, ArgStringList &CmdArgs) const { - Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I, - options::OPT_cpp, options::OPT_nocpp}); + Args.addAllArgs(CmdArgs, + {options::OPT_P, options::OPT_D, options::OPT_U, + options::OPT_I, options::OPT_cpp, options::OPT_nocpp}); +} + +/// @C shouldLoopVersion +/// +/// Check if Loop Versioning should be enabled. +/// We look for the last of one of the following: +/// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride. +/// Loop versioning is disabled if the last option is +/// -fno-version-loops-for-stride. +/// Loop versioning is enabled if the last option is one of: +/// -floop-versioning +/// -Ofast +/// -O4 +/// -O3 +/// For all other cases, loop versioning is is disabled. +/// +/// The gfortran compiler automatically enables the option for -O3 or -Ofast. +/// +/// @return true if loop-versioning should be enabled, otherwise false. +static bool shouldLoopVersion(const ArgList &Args) { + const Arg *LoopVersioningArg = Args.getLastArg( + options::OPT_Ofast, options::OPT_O, options::OPT_O4, + options::OPT_floop_versioning, options::OPT_fno_loop_versioning); + if (!LoopVersioningArg) + return false; + + if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning)) + return false; + + if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning)) + return true; + + if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) || + LoopVersioningArg->getOption().matches(options::OPT_O4)) + return true; + + if (LoopVersioningArg->getOption().matches(options::OPT_O)) { + StringRef S(LoopVersioningArg->getValue()); + unsigned OptLevel = 0; + // Note -Os or Oz woould "fail" here, so return false. Which is the + // desiered behavior. + if (S.getAsInteger(10, OptLevel)) + return false; + + return OptLevel > 2; + } + + llvm_unreachable("We should not end up here"); + return false; } -void Flang::AddOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { - Args.AddAllArgs(CmdArgs, +void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { + Args.addAllArgs(CmdArgs, {options::OPT_module_dir, options::OPT_fdebug_module_writer, options::OPT_fintrinsic_modules_path, options::OPT_pedantic, - options::OPT_std_EQ, options::OPT_W_Joined}); + options::OPT_std_EQ, options::OPT_W_Joined, + options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ, + options::OPT_funderscoring, options::OPT_fno_underscoring}); + + llvm::codegenoptions::DebugInfoKind DebugInfoKind; + if (Args.hasArg(options::OPT_gN_Group)) { + Arg *gNArg = Args.getLastArg(options::OPT_gN_Group); + DebugInfoKind = debugLevelToInfoKind(*gNArg); + } else if (Args.hasArg(options::OPT_g_Flag)) { + DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly; + } else { + DebugInfoKind = llvm::codegenoptions::NoDebugInfo; + } + addDebugInfoKind(CmdArgs, DebugInfoKind); +} + +void Flang::addCodegenOptions(const ArgList &Args, + ArgStringList &CmdArgs) const { + Arg *stackArrays = + Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays, + options::OPT_fno_stack_arrays); + if (stackArrays && + !stackArrays->getOption().matches(options::OPT_fno_stack_arrays)) + CmdArgs.push_back("-fstack-arrays"); + + if (shouldLoopVersion(Args)) + CmdArgs.push_back("-fversion-loops-for-stride"); + + Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir, + options::OPT_flang_deprecated_no_hlfir, + options::OPT_flang_experimental_polymorphism, + options::OPT_fno_ppc_native_vec_elem_order, + options::OPT_fppc_native_vec_elem_order}); +} + +void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { + // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of + // (RelocationModel, PICLevel, IsPIE). + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Args); + + if (auto *RMName = RelocationModelName(RelocationModel)) { + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back(RMName); + } + if (PICLevel > 0) { + CmdArgs.push_back("-pic-level"); + CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); + if (IsPIE) + CmdArgs.push_back("-pic-is-pie"); + } +} + +void Flang::AddAArch64TargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Handle -msve_vector_bits=<bits> + if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { + StringRef Val = A->getValue(); + const Driver &D = getToolChain().getDriver(); + if (Val.equals("128") || Val.equals("256") || Val.equals("512") || + Val.equals("1024") || Val.equals("2048") || Val.equals("128+") || + Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") || + Val.equals("2048+")) { + unsigned Bits = 0; + if (Val.ends_with("+")) + Val = Val.substr(0, Val.size() - 1); + else { + [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); + assert(!Invalid && "Failed to parse value"); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128))); + } + + [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); + assert(!Invalid && "Failed to parse value"); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128))); + // Silently drop requests for vector-length agnostic code as it's implied. + } else if (!Val.equals("scalable")) + // Handle the unsupported values passed to msve-vector-bits. + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } +} + +void Flang::AddRISCVTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const llvm::Triple &Triple = getToolChain().getTriple(); + // Handle -mrvv-vector-bits=<bits> + if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) { + StringRef Val = A->getValue(); + const Driver &D = getToolChain().getDriver(); + + // Get minimum VLen from march. + unsigned MinVLen = 0; + StringRef Arch = riscv::getRISCVArch(Args, Triple); + auto ISAInfo = llvm::RISCVISAInfo::parseArchString( + Arch, /*EnableExperimentalExtensions*/ true); + // Ignore parsing error. + if (!errorToBool(ISAInfo.takeError())) + MinVLen = (*ISAInfo)->getMinVLen(); + + // If the value is "zvl", use MinVLen from march. Otherwise, try to parse + // as integer as long as we have a MinVLen. + unsigned Bits = 0; + if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) { + Bits = MinVLen; + } else if (!Val.getAsInteger(10, Bits)) { + // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that + // at least MinVLen. + if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock || + Bits > 65536 || !llvm::isPowerOf2_32(Bits)) + Bits = 0; + } + + // If we got a valid value try to use it. + if (Bits != 0) { + unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock; + CmdArgs.push_back( + Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin))); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin))); + } else if (!Val.equals("scalable")) { + // Handle the unsupported values passed to mrvv-vector-bits. + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } + } +} + +static void addVSDefines(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + + unsigned ver = 0; + const VersionTuple vt = TC.computeMSVCVersion(nullptr, Args); + ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(0) * 100000 + + vt.getSubminor().value_or(0); + CmdArgs.push_back(Args.MakeArgString("-D_MSC_VER=" + Twine(ver / 100000))); + CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver))); + CmdArgs.push_back(Args.MakeArgString("-D_WIN32")); + + llvm::Triple triple = TC.getTriple(); + if (triple.isAArch64()) { + CmdArgs.push_back("-D_M_ARM64=1"); + } else if (triple.isX86() && triple.isArch32Bit()) { + CmdArgs.push_back("-D_M_IX86=600"); + } else if (triple.isX86() && triple.isArch64Bit()) { + CmdArgs.push_back("-D_M_X64=100"); + } else { + llvm_unreachable( + "Flang on Windows only supports X86_32, X86_64 and AArch64"); + } +} + +static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + assert(TC.getTriple().isKnownWindowsMSVCEnvironment() && + "can only add VS runtime library on Windows!"); + // if -fno-fortran-main has been passed, skip linking Fortran_main.a + bool LinkFortranMain = !Args.hasArg(options::OPT_no_fortran_main); + if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { + CmdArgs.push_back(Args.MakeArgString( + "--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins"))); + } + unsigned RTOptionID = options::OPT__SLASH_MT; + if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue()) + .Case("static", options::OPT__SLASH_MT) + .Case("static_dbg", options::OPT__SLASH_MTd) + .Case("dll", options::OPT__SLASH_MD) + .Case("dll_dbg", options::OPT__SLASH_MDd) + .Default(options::OPT__SLASH_MT); + } + switch (RTOptionID) { + case options::OPT__SLASH_MT: + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("--dependent-lib=libcmt"); + if (LinkFortranMain) + CmdArgs.push_back("--dependent-lib=Fortran_main.static.lib"); + CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib"); + CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib"); + break; + case options::OPT__SLASH_MTd: + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("--dependent-lib=libcmtd"); + if (LinkFortranMain) + CmdArgs.push_back("--dependent-lib=Fortran_main.static_dbg.lib"); + CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib"); + CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib"); + break; + case options::OPT__SLASH_MD: + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + CmdArgs.push_back("--dependent-lib=msvcrt"); + if (LinkFortranMain) + CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic.lib"); + CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib"); + CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib"); + break; + case options::OPT__SLASH_MDd: + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_DLL"); + CmdArgs.push_back("--dependent-lib=msvcrtd"); + if (LinkFortranMain) + CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib"); + CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib"); + CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib"); + break; + } +} + +void Flang::AddAMDGPUTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + if (Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) { + StringRef Val = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val)); + } +} + +void Flang::addTargetOptions(const ArgList &Args, + ArgStringList &CmdArgs) const { + const ToolChain &TC = getToolChain(); + const llvm::Triple &Triple = TC.getEffectiveTriple(); + const Driver &D = TC.getDriver(); + + std::string CPU = getCPUName(D, Args, Triple); + if (!CPU.empty()) { + CmdArgs.push_back("-target-cpu"); + CmdArgs.push_back(Args.MakeArgString(CPU)); + } + + // Add the target features. + switch (TC.getArch()) { + default: + break; + case llvm::Triple::aarch64: + getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); + AddAArch64TargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::r600: + case llvm::Triple::amdgcn: + getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); + AddAMDGPUTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::riscv64: + getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); + AddRISCVTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::x86_64: + getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); + break; + } + + if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { + StringRef Name = A->getValue(); + if (Name == "SVML") { + if (Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } else if (Name == "LIBMVEC-X86") { + if (Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } else if (Name == "SLEEF" || Name == "ArmPL") { + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_be) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Name << Triple.getArchName(); + } + + if (Triple.isOSDarwin()) { + // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these + // here incase they are added someday + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (A->getValue() == StringRef{"Accelerate"}) { + CmdArgs.push_back("-framework"); + CmdArgs.push_back("Accelerate"); + } + } + } + A->render(Args, CmdArgs); + } + + if (Triple.isKnownWindowsMSVCEnvironment()) { + processVSRuntimeLibrary(TC, Args, CmdArgs); + addVSDefines(TC, Args, CmdArgs); + } + + // TODO: Add target specific flags, ABI, mtune option etc. +} + +void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, + const JobAction &JA, const ArgList &Args, + ArgStringList &CmdArgs) const { + bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); + bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) || + JA.isHostOffloading(C.getActiveOffloadKinds()); + + // Skips the primary input file, which is the input file that the compilation + // proccess will be executed upon (e.g. the host bitcode file) and + // adds other secondary input (e.g. device bitcode files for embedding to the + // -fembed-offload-object argument or the host IR file for proccessing + // during device compilation to the fopenmp-host-ir-file-path argument via + // OpenMPDeviceInput). This is condensed logic from the ConstructJob + // function inside of the Clang driver for pushing on further input arguments + // needed for offloading during various phases of compilation. + for (size_t i = 1; i < Inputs.size(); ++i) { + if (Inputs[i].getType() == types::TY_Nothing) { + // contains nothing, so it's skippable + } else if (IsHostOffloadingAction) { + CmdArgs.push_back( + Args.MakeArgString("-fembed-offload-object=" + + getToolChain().getInputFilename(Inputs[i]))); + } else if (IsOpenMPDevice) { + if (Inputs[i].getFilename()) { + CmdArgs.push_back("-fopenmp-host-ir-file-path"); + CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename())); + } else { + llvm_unreachable("missing openmp host-ir file for device offloading"); + } + } else { + llvm_unreachable( + "unexpectedly given multiple inputs or given unknown input"); + } + } + + if (IsOpenMPDevice) { + // -fopenmp-is-target-device is passed along to tell the frontend that it is + // generating code for a device, so that only the relevant code is emitted. + CmdArgs.push_back("-fopenmp-is-target-device"); + + // When in OpenMP offloading mode, enable debugging on the device. + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); + if (Args.hasFlag(options::OPT_fopenmp_target_debug, + options::OPT_fno_openmp_target_debug, /*Default=*/false)) + CmdArgs.push_back("-fopenmp-target-debug"); + + // When in OpenMP offloading mode, forward assumptions information about + // thread and team counts in the device. + if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, + options::OPT_fno_openmp_assume_teams_oversubscription, + /*Default=*/false)) + CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); + if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, + options::OPT_fno_openmp_assume_threads_oversubscription, + /*Default=*/false)) + CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); + if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) + CmdArgs.push_back("-fopenmp-assume-no-thread-state"); + if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) + CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); + if (Args.hasArg(options::OPT_nogpulib)) + CmdArgs.push_back("-nogpulib"); + } +} + +static void addFloatingPointOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + StringRef FPContract; + bool HonorINFs = true; + bool HonorNaNs = true; + bool ApproxFunc = false; + bool SignedZeros = true; + bool AssociativeMath = false; + bool ReciprocalMath = false; + + if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { + const StringRef Val = A->getValue(); + if (Val == "fast" || Val == "off") { + FPContract = Val; + } else if (Val == "on") { + // Warn instead of error because users might have makefiles written for + // gfortran (which accepts -ffp-contract=on) + D.Diag(diag::warn_drv_unsupported_option_for_flang) + << Val << A->getOption().getName() << "off"; + FPContract = "off"; + } else + // Clang's "fast-honor-pragmas" option is not supported because it is + // non-standard + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } + + for (const Arg *A : Args) { + auto optId = A->getOption().getID(); + switch (optId) { + // if this isn't an FP option, skip the claim below + default: + continue; + + case options::OPT_fhonor_infinities: + HonorINFs = true; + break; + case options::OPT_fno_honor_infinities: + HonorINFs = false; + break; + case options::OPT_fhonor_nans: + HonorNaNs = true; + break; + case options::OPT_fno_honor_nans: + HonorNaNs = false; + break; + case options::OPT_fapprox_func: + ApproxFunc = true; + break; + case options::OPT_fno_approx_func: + ApproxFunc = false; + break; + case options::OPT_fsigned_zeros: + SignedZeros = true; + break; + case options::OPT_fno_signed_zeros: + SignedZeros = false; + break; + case options::OPT_fassociative_math: + AssociativeMath = true; + break; + case options::OPT_fno_associative_math: + AssociativeMath = false; + break; + case options::OPT_freciprocal_math: + ReciprocalMath = true; + break; + case options::OPT_fno_reciprocal_math: + ReciprocalMath = false; + break; + case options::OPT_Ofast: + [[fallthrough]]; + case options::OPT_ffast_math: + HonorINFs = false; + HonorNaNs = false; + AssociativeMath = true; + ReciprocalMath = true; + ApproxFunc = true; + SignedZeros = false; + FPContract = "fast"; + break; + case options::OPT_fno_fast_math: + HonorINFs = true; + HonorNaNs = true; + AssociativeMath = false; + ReciprocalMath = false; + ApproxFunc = false; + SignedZeros = true; + // -fno-fast-math should undo -ffast-math so I return FPContract to the + // default. It is important to check it is "fast" (the default) so that + // --ffp-contract=off -fno-fast-math --> -ffp-contract=off + if (FPContract == "fast") + FPContract = ""; + break; + } + + // If we handled this option claim it + A->claim(); + } + + if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && + ApproxFunc && !SignedZeros && + (FPContract == "fast" || FPContract == "")) { + CmdArgs.push_back("-ffast-math"); + return; + } + + if (!FPContract.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + + if (!HonorINFs) + CmdArgs.push_back("-menable-no-infs"); + + if (!HonorNaNs) + CmdArgs.push_back("-menable-no-nans"); + + if (ApproxFunc) + CmdArgs.push_back("-fapprox-func"); + + if (!SignedZeros) + CmdArgs.push_back("-fno-signed-zeros"); + + if (AssociativeMath && !SignedZeros) + CmdArgs.push_back("-mreassociate"); + + if (ReciprocalMath) + CmdArgs.push_back("-freciprocal-math"); +} + +static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, + const InputInfo &Input) { + StringRef Format = "yaml"; + if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) + Format = A->getValue(); + + CmdArgs.push_back("-opt-record-file"); + + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + CmdArgs.push_back(A->getValue()); + } else { + SmallString<128> F; + + if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { + if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) + F = FinalOutput->getValue(); + } + + if (F.empty()) { + // Use the input filename. + F = llvm::sys::path::stem(Input.getBaseInput()); + } + + SmallString<32> Extension; + Extension += "opt."; + Extension += Format; + + llvm::sys::path::replace_extension(F, Extension); + CmdArgs.push_back(Args.MakeArgString(F)); + } + + if (const Arg *A = + Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { + CmdArgs.push_back("-opt-record-passes"); + CmdArgs.push_back(A->getValue()); + } + + if (!Format.empty()) { + CmdArgs.push_back("-opt-record-format"); + CmdArgs.push_back(Format.data()); + } } void Flang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const auto &TC = getToolChain(); - // TODO: Once code-generation is available, this will need to be commented - // out. - // const llvm::Triple &Triple = TC.getEffectiveTriple(); - // const std::string &TripleStr = Triple.getTriple(); + const llvm::Triple &Triple = TC.getEffectiveTriple(); + const std::string &TripleStr = Triple.getTriple(); + const Driver &D = TC.getDriver(); ArgStringList CmdArgs; + DiagnosticsEngine &Diags = D.getDiags(); // Invoke ourselves in -fc1 mode. CmdArgs.push_back("-fc1"); - // TODO: Once code-generation is available, this will need to be commented - // out. // Add the "effective" target triple. - // CmdArgs.push_back("-triple"); - // CmdArgs.push_back(Args.MakeArgString(TripleStr)); + CmdArgs.push_back("-triple"); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); if (isa<PreprocessJobAction>(JA)) { CmdArgs.push_back("-E"); @@ -98,27 +703,122 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor (i.e. skip when dealing with e.g. binary files). if (types::getPreprocessedType(InputType) != types::TY_INVALID) - AddPreprocessingOptions(Args, CmdArgs); + addPreprocessingOptions(Args, CmdArgs); - AddFortranDialectOptions(Args, CmdArgs); + addFortranDialectOptions(Args, CmdArgs); + + // Color diagnostics are parsed by the driver directly from argv and later + // re-parsed to construct this job; claim any possible color diagnostic here + // to avoid warn_drv_unused_argument. + Args.getLastArg(options::OPT_fcolor_diagnostics, + options::OPT_fno_color_diagnostics); + if (Diags.getDiagnosticOptions().ShowColors) + CmdArgs.push_back("-fcolor-diagnostics"); + + // LTO mode is parsed by the Clang driver library. + LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false); + assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); + if (LTOMode == LTOK_Full) + CmdArgs.push_back("-flto=full"); + else if (LTOMode == LTOK_Thin) { + Diags.Report( + Diags.getCustomDiagID(DiagnosticsEngine::Warning, + "the option '-flto=thin' is a work in progress")); + CmdArgs.push_back("-flto=thin"); + } + + // -fPIC and related options. + addPicOptions(Args, CmdArgs); + + // Floating point related options + addFloatingPointOptions(D, Args, CmdArgs); + + // Add target args, features, etc. + addTargetOptions(Args, CmdArgs); + + // Add Codegen options + addCodegenOptions(Args, CmdArgs); + + // Add R Group options + Args.AddAllArgs(CmdArgs, options::OPT_R_Group); + + // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. + if (willEmitRemarks(Args)) + renderRemarksOptions(Args, CmdArgs, Input); // Add other compile options - AddOtherOptions(Args, CmdArgs); + addOtherOptions(Args, CmdArgs); + + // Offloading related options + addOffloadOptions(C, Inputs, JA, Args, CmdArgs); // Forward -Xflang arguments to -fc1 Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); + CodeGenOptions::FramePointerKind FPKeepKind = + getFramePointerKind(Args, Triple); + + const char *FPKeepKindStr = nullptr; + switch (FPKeepKind) { + case CodeGenOptions::FramePointerKind::None: + FPKeepKindStr = "-mframe-pointer=none"; + break; + case CodeGenOptions::FramePointerKind::NonLeaf: + FPKeepKindStr = "-mframe-pointer=non-leaf"; + break; + case CodeGenOptions::FramePointerKind::All: + FPKeepKindStr = "-mframe-pointer=all"; + break; + } + assert(FPKeepKindStr && "unknown FramePointerKind"); + CmdArgs.push_back(FPKeepKindStr); + + // Forward -mllvm options to the LLVM option parser. In practice, this means + // forwarding to `-fc1` as that's where the LLVM parser is run. + for (const Arg *A : Args.filtered(options::OPT_mllvm)) { + A->claim(); + A->render(Args, CmdArgs); + } + + for (const Arg *A : Args.filtered(options::OPT_mmlir)) { + A->claim(); + A->render(Args, CmdArgs); + } + + // Remove any unsupported gfortran diagnostic options + for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) { + A->claim(); + D.Diag(diag::warn_drv_unsupported_diag_option_for_flang) + << A->getOption().getName(); + } + + // Optimization level for CodeGen. + if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O4)) { + CmdArgs.push_back("-O3"); + D.Diag(diag::warn_O4_is_O3); + } else if (A->getOption().matches(options::OPT_Ofast)) { + CmdArgs.push_back("-O3"); + } else { + A->render(Args, CmdArgs); + } + } + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } assert(Input.isFilename() && "Invalid input."); + + if (Args.getLastArg(options::OPT_save_temps_EQ)) + Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); + + addDashXForInput(Args, Input, CmdArgs); + CmdArgs.push_back(Input.getFilename()); - const auto& D = C.getDriver(); // TODO: Replace flang-new with flang once the new driver replaces the // throwaway driver const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC)); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h index efbdbe854e24..ec2e545a1d0b 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h @@ -29,7 +29,7 @@ private: /// /// \param [in] Args The list of input driver arguments /// \param [out] CmdArgs The list of output command arguments - void AddFortranDialectOptions(const llvm::opt::ArgList &Args, + void addFortranDialectOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; /// Extract preprocessing options from the driver arguments and add them to @@ -37,14 +37,71 @@ private: /// /// \param [in] Args The list of input driver arguments /// \param [out] CmdArgs The list of output command arguments - void AddPreprocessingOptions(const llvm::opt::ArgList &Args, + void addPreprocessingOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + + /// Extract PIC options from the driver arguments and add them to + /// the command arguments. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addPicOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Extract target options from the driver arguments and add them to + /// the command arguments. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addTargetOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Add specific options for AArch64 target. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Add specific options for AMDGPU target. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void AddAMDGPUTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Add specific options for RISC-V target. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void AddRISCVTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Extract offload options from the driver arguments and add them to + /// the command arguments. + /// \param [in] C The current compilation for the driver invocation + /// \param [in] Inputs The input infomration on the current file inputs + /// \param [in] JA The job action + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addOffloadOptions(Compilation &C, const InputInfoList &Inputs, + const JobAction &JA, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + /// Extract options for code generation from the driver arguments and add them + /// to the command arguments. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addCodegenOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + /// Extract other compilation options from the driver arguments and add them /// to the command arguments. /// /// \param [in] Args The list of input driver arguments /// \param [out] CmdArgs The list of output command arguments - void AddOtherOptions(const llvm::opt::ArgList &Args, + void addOtherOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; public: diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp index 5dcf74dabf4f..b7c9e0e51cdb 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -11,6 +11,7 @@ #include "Arch/Mips.h" #include "Arch/Sparc.h" #include "CommonArgs.h" +#include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" @@ -29,13 +30,16 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; + const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain()); const auto &D = getToolChain().getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); + ArgStringList CmdArgs; + + claimNoWarnArgs(Args); // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. - switch (getToolChain().getArch()) { + switch (ToolChain.getArch()) { default: break; case llvm::Triple::x86: @@ -51,7 +55,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); @@ -59,7 +63,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mabi"); CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - if (getToolChain().getTriple().isLittleEndian()) + if (Triple.isLittleEndian()) CmdArgs.push_back("-EL"); else CmdArgs.push_back("-EB"); @@ -70,39 +74,27 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: { - arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); + arm::FloatABI ABI = arm::getARMFloatABI(ToolChain, Args); if (ABI == arm::FloatABI::Hard) CmdArgs.push_back("-mfpu=vfp"); else CmdArgs.push_back("-mfpu=softvfp"); - switch (getToolChain().getTriple().getEnvironment()) { - case llvm::Triple::GNUEABIHF: - case llvm::Triple::GNUEABI: - case llvm::Triple::EABI: - CmdArgs.push_back("-meabi=5"); - break; - - default: - CmdArgs.push_back("-matpcs"); - } + CmdArgs.push_back("-meabi=5"); break; } - case llvm::Triple::sparc: - case llvm::Triple::sparcel: case llvm::Triple::sparcv9: { - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back( - sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + std::string CPU = getCPUName(D, Args, Triple); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } } @@ -110,7 +102,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fdebug_prefix_map_EQ)) { StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) + if (!Map.contains('=')) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else { @@ -128,7 +120,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as")); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -139,13 +131,12 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(getToolChain()); + const auto &ToolChain = static_cast<const FreeBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsPIE = !Args.hasArg(options::OPT_shared) && - (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); + (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault(Args)); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -169,16 +160,14 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-Bshareable"); - } else { + CmdArgs.push_back("-shared"); + } else if (!Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld-elf.so.1"); } const llvm::Triple &T = ToolChain.getTriple(); - if (T.getOSMajorVersion() >= 9) { - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || T.isX86()) - CmdArgs.push_back("--hash-style=both"); - } + if (Arch == llvm::Triple::arm || T.isX86()) + CmdArgs.push_back("--hash-style=both"); CmdArgs.push_back("--enable-new-dtags"); } @@ -220,13 +209,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("elf64ltsmip_fbsd"); break; - case llvm::Triple::riscv32: - CmdArgs.push_back("-m"); - CmdArgs.push_back("elf32lriscv"); - break; case llvm::Triple::riscv64: CmdArgs.push_back("-m"); CmdArgs.push_back("elf64lriscv"); + CmdArgs.push_back("-X"); break; default: break; @@ -240,14 +226,14 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) @@ -275,16 +261,20 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); - Args.AddAllArgs(CmdArgs, options::OPT_r); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); - addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, D.getLTOMode() == LTOK_Thin); } @@ -293,9 +283,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - bool Profiling = Args.hasArg(options::OPT_pg) && - ToolChain.getTriple().getOSMajorVersion() < 14; - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + unsigned Major = ToolChain.getTriple().getOSMajorVersion(); + bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14; + 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); @@ -309,10 +300,27 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-lm"); } + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + if (Profiling) + CmdArgs.push_back("-lm_p"); + else + CmdArgs.push_back("-lm"); + } + if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, CmdArgs); + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding // the default system libraries. Just mimic this for now. if (Profiling) @@ -358,11 +366,14 @@ void freebsd::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)) { + const char *crtend = nullptr; if (Args.hasArg(options::OPT_shared) || IsPIE) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); + crtend = "crtendS.o"; else - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + crtend = "crtend.o"; + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } @@ -382,64 +393,71 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall // back to '/usr/lib' if it doesn't exist. - if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() || - Triple.isPPC32()) && - D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); + if (Triple.isArch32Bit() && + D.getVFS().exists(concat(getDriver().SysRoot, "/usr/lib32/crt1.o"))) + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib32")); else - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } -ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { - if (getTriple().getOSMajorVersion() >= 10) - return ToolChain::CST_Libcxx; - return ToolChain::CST_Libstdcxx; -} +void FreeBSD::AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); -unsigned FreeBSD::GetDefaultDwarfVersion() const { - if (getTriple().getOSMajorVersion() < 12) - return 2; - return 4; + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); } void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); -} - -void FreeBSD::addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot + "/usr/include/c++/4.2", "", "", - DriverArgs, CC1Args); + concat(getDriver().SysRoot, "/usr/include/c++/v1")); } void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - CXXStdlibType Type = GetCXXStdlibType(Args); - bool Profiling = - Args.hasArg(options::OPT_pg) && getTriple().getOSMajorVersion() < 14; - - switch (Type) { - case ToolChain::CST_Libcxx: - CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); - break; + unsigned Major = getTriple().getOSMajorVersion(); + bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14; - case ToolChain::CST_Libstdcxx: - CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); - break; - } + CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); } void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void FreeBSD::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } Tool *FreeBSD::buildAssembler() const { @@ -448,26 +466,16 @@ Tool *FreeBSD::buildAssembler() const { Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } -llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const { - // FreeBSD uses SjLj exceptions on ARM oabi. - switch (getTriple().getEnvironment()) { - case llvm::Triple::GNUEABIHF: - case llvm::Triple::GNUEABI: - case llvm::Triple::EABI: - return llvm::ExceptionHandling::None; - default: - if (getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::thumb) - return llvm::ExceptionHandling::SjLj; - return llvm::ExceptionHandling::None; - } -} - bool FreeBSD::HasNativeLLVMSupport() const { return true; } -bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; } +ToolChain::UnwindTableLevel +FreeBSD::getDefaultUnwindTableLevel(const ArgList &Args) const { + return UnwindTableLevel::Asynchronous; +} -bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } +bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const { + return getSanitizerArgs(Args).requiresPIE(); +} SanitizerMask FreeBSD::getSupportedSanitizers() const { const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64; @@ -479,12 +487,11 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const { Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Vptr; - if (IsX86_64 || IsMIPS64) { + if (IsAArch64 || IsX86_64 || IsMIPS64) { Res |= SanitizerKind::Leak; Res |= SanitizerKind::Thread; } - if (IsX86 || IsX86_64) { - Res |= SanitizerKind::Function; + if (IsAArch64 || IsX86 || IsX86_64) { Res |= SanitizerKind::SafeStack; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; @@ -492,18 +499,7 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const { if (IsAArch64 || IsX86_64) { Res |= SanitizerKind::KernelAddress; Res |= SanitizerKind::KernelMemory; - } - if (IsX86_64) { Res |= SanitizerKind::Memory; } return Res; } - -void FreeBSD::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args, - Action::OffloadKind) const { - if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, - getTriple().getOSMajorVersion() >= 12)) - CC1Args.push_back("-fno-use-init-array"); -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h index abc0876cef26..7ab63905ed4f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.h @@ -17,9 +17,9 @@ namespace clang { namespace driver { namespace tools { -/// freebsd -- Directly call GNU Binutils assembler and linker +/// Directly call GNU Binutils assembler and linker namespace freebsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("freebsd::Assembler", "assembler", TC) {} @@ -32,7 +32,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("freebsd::Linker", "linker", TC) {} @@ -58,12 +58,19 @@ public: bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } - CXXStdlibType GetDefaultCXXStdlibType() const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void - addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, @@ -71,19 +78,14 @@ public: void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - llvm::ExceptionHandling - GetExceptionModel(const llvm::opt::ArgList &Args) const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; - bool isPIEDefault() const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; - unsigned GetDefaultDwarfVersion() const override; + unsigned GetDefaultDwarfVersion() const override { return 4; } // Until dtrace (via CTF) and LLDB can deal with distributed debug info, // FreeBSD defaults to standalone/full debug info. bool GetDefaultStandaloneDebug() const override { return true; } - void - addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const override; protected: Tool *buildAssembler() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp index fd9804a7f353..14b838500bec 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -12,6 +12,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/MultilibBuilder.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" @@ -33,10 +34,11 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::Fuchsia &ToolChain = - static_cast<const toolchains::Fuchsia &>(getToolChain()); + const auto &ToolChain = static_cast<const Fuchsia &>(getToolChain()); const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getEffectiveTriple(); + ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -53,6 +55,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-z"); CmdArgs.push_back("now"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("start-stop-visibility=hidden"); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); if (llvm::sys::path::filename(Exec).equals_insensitive("ld.lld") || llvm::sys::path::stem(Exec).equals_insensitive("ld.lld")) { @@ -60,6 +65,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("rodynamic"); CmdArgs.push_back("-z"); CmdArgs.push_back("separate-loadable-segments"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("rel"); CmdArgs.push_back("--pack-dyn-relocs=relr"); } @@ -82,6 +89,14 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--hash-style=gnu"); } + if (ToolChain.getArch() == llvm::Triple::aarch64) { + CmdArgs.push_back("--execute-only"); + + std::string CPU = getCPUName(D, Args, Triple); + if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") + CmdArgs.push_back("--fix-cortex-a53-843419"); + } + CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) @@ -89,9 +104,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, else if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-shared"); - const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(); + const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args); - if (!Args.hasArg(options::OPT_shared)) { + if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) { std::string Dyld = D.DyldPrefix; if (SanArgs.needsAsanRt() && SanArgs.needsSharedRt()) Dyld += "asan/"; @@ -104,32 +119,42 @@ 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()); - 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("Scrt1.o"))); } } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); ToolChain.AddFilePathLibArgs(Args, CmdArgs); if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); - addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, D.getLTOMode() == LTOK_Thin); } - 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)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-Bdynamic"); @@ -149,11 +174,14 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + // Note that Fuchsia never needs to link in sanitizer runtime deps. Any + // sanitizer runtimes with system dependencies use the `.deplibs` feature + // instead. + addSanitizerRuntimes(ToolChain, Args, CmdArgs); - if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, CmdArgs); + addXRayRuntime(ToolChain, Args, CmdArgs); + + ToolChain.addProfileRTLibs(Args, CmdArgs); AddRunTimeLibs(ToolChain, D, CmdArgs, Args); @@ -168,7 +196,53 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lc"); } - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + C.addCommand(std::make_unique<Command>(JA, *this, + ResponseFileSupport::AtFileCurCP(), + Exec, CmdArgs, Inputs, Output)); +} + +void fuchsia::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // ar tool command "llvm-ar <options> <output_file> <input_files>". + ArgStringList CmdArgs; + // Create and insert file members with a deterministic index. + CmdArgs.push_back("rcsD"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) { + if (II.isFilename()) { + CmdArgs.push_back(II.getFilename()); + } + } + + // Delete old output archive file if it already exists before generating a new + // archive file. + const char *OutputFileName = Output.getFilename(); + if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) { + if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) { + D.Diag(diag::err_drv_unable_to_remove_file) << EC.message(); + return; + } + } + + const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath()); + C.addCommand(std::make_unique<Command>(JA, *this, + ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); } @@ -184,98 +258,82 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, if (!D.SysRoot.empty()) { SmallString<128> P(D.SysRoot); llvm::sys::path::append(P, "lib"); - getFilePaths().push_back(std::string(P.str())); + getFilePaths().push_back(std::string(P)); } auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> { std::vector<std::string> FP; - SmallString<128> P(getStdlibPath()); - llvm::sys::path::append(P, M.gccSuffix()); - FP.push_back(std::string(P.str())); + if (std::optional<std::string> Path = getStdlibPath()) { + SmallString<128> P(*Path); + llvm::sys::path::append(P, M.gccSuffix()); + FP.push_back(std::string(P)); + } return FP; }; Multilibs.push_back(Multilib()); // Use the noexcept variant with -fno-exceptions to avoid the extra overhead. - Multilibs.push_back(Multilib("noexcept", {}, {}, 1) - .flag("-fexceptions") - .flag("+fno-exceptions")); + Multilibs.push_back(MultilibBuilder("noexcept", {}, {}) + .flag("-fexceptions", /*Disallow=*/true) + .flag("-fno-exceptions") + .makeMultilib()); // ASan has higher priority because we always want the instrumentated version. - Multilibs.push_back(Multilib("asan", {}, {}, 2) - .flag("+fsanitize=address")); + Multilibs.push_back(MultilibBuilder("asan", {}, {}) + .flag("-fsanitize=address") + .makeMultilib()); // Use the asan+noexcept variant with ASan and -fno-exceptions. - Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3) - .flag("+fsanitize=address") - .flag("-fexceptions") - .flag("+fno-exceptions")); + Multilibs.push_back(MultilibBuilder("asan+noexcept", {}, {}) + .flag("-fsanitize=address") + .flag("-fexceptions", /*Disallow=*/true) + .flag("-fno-exceptions") + .makeMultilib()); // HWASan has higher priority because we always want the instrumentated // version. - Multilibs.push_back( - Multilib("hwasan", {}, {}, 4).flag("+fsanitize=hwaddress")); + Multilibs.push_back(MultilibBuilder("hwasan", {}, {}) + .flag("-fsanitize=hwaddress") + .makeMultilib()); // Use the hwasan+noexcept variant with HWASan and -fno-exceptions. - Multilibs.push_back(Multilib("hwasan+noexcept", {}, {}, 5) - .flag("+fsanitize=hwaddress") - .flag("-fexceptions") - .flag("+fno-exceptions")); - // Use the relative vtables ABI. - // TODO: Remove these multilibs once relative vtables are enabled by default - // for Fuchsia. - Multilibs.push_back(Multilib("relative-vtables", {}, {}, 6) - .flag("+fexperimental-relative-c++-abi-vtables")); - Multilibs.push_back(Multilib("relative-vtables+noexcept", {}, {}, 7) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("-fexceptions") - .flag("+fno-exceptions")); - Multilibs.push_back(Multilib("relative-vtables+asan", {}, {}, 8) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("+fsanitize=address")); - Multilibs.push_back(Multilib("relative-vtables+asan+noexcept", {}, {}, 9) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("+fsanitize=address") - .flag("-fexceptions") - .flag("+fno-exceptions")); - Multilibs.push_back(Multilib("relative-vtables+hwasan", {}, {}, 10) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("+fsanitize=hwaddress")); - Multilibs.push_back(Multilib("relative-vtables+hwasan+noexcept", {}, {}, 11) - .flag("+fexperimental-relative-c++-abi-vtables") - .flag("+fsanitize=hwaddress") - .flag("-fexceptions") - .flag("+fno-exceptions")); + Multilibs.push_back(MultilibBuilder("hwasan+noexcept", {}, {}) + .flag("-fsanitize=hwaddress") + .flag("-fexceptions", /*Disallow=*/true) + .flag("-fno-exceptions") + .makeMultilib()); // Use Itanium C++ ABI for the compat multilib. - Multilibs.push_back(Multilib("compat", {}, {}, 12).flag("+fc++-abi=itanium")); + Multilibs.push_back(MultilibBuilder("compat", {}, {}) + .flag("-fc++-abi=itanium") + .makeMultilib()); Multilibs.FilterOut([&](const Multilib &M) { std::vector<std::string> RD = FilePaths(M); - return std::all_of(RD.begin(), RD.end(), [&](std::string P) { - return !getVFS().exists(P); - }); + return llvm::all_of(RD, [&](std::string P) { return !getVFS().exists(P); }); }); Multilib::flags_list Flags; - addMultilibFlag( - Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true), - "fexceptions", Flags); - addMultilibFlag(getSanitizerArgs().needsAsanRt(), "fsanitize=address", Flags); - addMultilibFlag(getSanitizerArgs().needsHwasanRt(), "fsanitize=hwaddress", + bool Exceptions = + Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true); + addMultilibFlag(Exceptions, "-fexceptions", Flags); + addMultilibFlag(!Exceptions, "-fno-exceptions", Flags); + addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "-fsanitize=address", Flags); + addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), + "-fsanitize=hwaddress", Flags); - addMultilibFlag( - Args.hasFlag(options::OPT_fexperimental_relative_cxx_abi_vtables, - options::OPT_fno_experimental_relative_cxx_abi_vtables, - /*default=*/false), - "fexperimental-relative-c++-abi-vtables", Flags); addMultilibFlag(Args.getLastArgValue(options::OPT_fcxx_abi_EQ) == "itanium", - "fc++-abi=itanium", Flags); + "-fc++-abi=itanium", Flags); Multilibs.setFilePathsCallback(FilePaths); - if (Multilibs.select(Flags, SelectedMultilib)) - if (!SelectedMultilib.isDefault()) + if (Multilibs.select(Flags, SelectedMultilibs)) { + // Ensure that -print-multi-directory only outputs one multilib directory. + Multilib LastSelected = SelectedMultilibs.back(); + SelectedMultilibs = {LastSelected}; + + if (!SelectedMultilibs.back().isDefault()) if (const auto &PathsCallback = Multilibs.filePathsCallback()) - for (const auto &Path : PathsCallback(SelectedMultilib)) + for (const auto &Path : PathsCallback(SelectedMultilibs.back())) // Prepend the multilib path to ensure it takes the precedence. getFilePaths().insert(getFilePaths().begin(), Path); + } } std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, @@ -288,6 +346,10 @@ Tool *Fuchsia::buildLinker() const { return new tools::fuchsia::Linker(*this); } +Tool *Fuchsia::buildStaticLibTool() const { + return new tools::fuchsia::StaticLibTool(*this); +} + ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType( const ArgList &Args) const { if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) { @@ -358,8 +420,8 @@ void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) + if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, + options::OPT_nostdincxx)) return; const Driver &D = getDriver(); @@ -400,6 +462,8 @@ void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); break; case ToolChain::CST_Libstdcxx: @@ -426,24 +490,14 @@ SanitizerMask Fuchsia::getDefaultSanitizers() const { SanitizerMask Res; switch (getTriple().getArch()) { case llvm::Triple::aarch64: + case llvm::Triple::riscv64: Res |= SanitizerKind::ShadowCallStack; break; case llvm::Triple::x86_64: Res |= SanitizerKind::SafeStack; break; default: - // TODO: Enable SafeStack on RISC-V once tested. break; } return Res; } - -void Fuchsia::addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const { - // Add linker option -u__llvm_profile_runtime to cause runtime - // initialization module to be linked in. - if (needsProfileRT(Args)) - CmdArgs.push_back(Args.MakeArgString( - Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); - ToolChain::addProfileRTLibs(Args, CmdArgs); -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h index 07adf9b7101d..619968f58502 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.h @@ -18,7 +18,21 @@ namespace clang { namespace driver { namespace tools { namespace fuchsia { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY StaticLibTool : public Tool { +public: + StaticLibTool(const ToolChain &TC) + : Tool("fuchsia::StaticLibTool", "llvm-ar", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("fuchsia::Linker", "ld.lld", TC) {} @@ -41,20 +55,21 @@ public: const llvm::opt::ArgList &Args); bool HasNativeLLVMSupport() const override { return true; } - bool IsIntegratedAssemblerDefault() const override { return true; } bool IsMathErrnoDefault() const override { return false; } - bool useRelaxRelocations() const override { return true; }; RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; } CXXStdlibType GetDefaultCXXStdlibType() const override { return ToolChain::CST_Libcxx; } - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override { - return true; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override { + return UnwindTableLevel::Asynchronous; } bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return true; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return true; + } bool isPICDefaultForced() const override { return false; } llvm::DebuggerKind getDefaultDebuggerTuning() const override { return llvm::DebuggerKind::GDB; @@ -71,32 +86,33 @@ public: SanitizerMask getSupportedSanitizers() const override; SanitizerMask getDefaultSanitizers() const override; - void addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - 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; + Tool *buildStaticLibTool() const override; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp index da39f29e4619..e5e1b1d77269 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp @@ -8,6 +8,8 @@ #include "Gnu.h" #include "Arch/ARM.h" +#include "Arch/CSKY.h" +#include "Arch/LoongArch.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/RISCV.h" @@ -19,14 +21,18 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/MultilibBuilder.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Twine.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Path.h" -#include "llvm/Support/TargetParser.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/TargetParser.h" #include <system_error> using namespace clang::driver; @@ -82,7 +88,7 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, RenderExtraToolArgs(JA, CmdArgs); - // If using a driver driver, force the arch. + // If using a driver, force the arch. if (getToolChain().getTriple().isOSDarwin()) { CmdArgs.push_back("-arch"); CmdArgs.push_back( @@ -112,11 +118,11 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, break; } + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { - assert(Output.isNothing() && "Unexpected output"); CmdArgs.push_back("-fsyntax-only"); } @@ -215,30 +221,6 @@ void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, // The types are (hopefully) good enough. } -// On Arm the endianness of the output file is determined by the target and -// can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and -// '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a -// normalized triple so we must handle the flag here. -static bool isArmBigEndian(const llvm::Triple &Triple, - const ArgList &Args) { - bool IsBigEndian = false; - switch (Triple.getArch()) { - case llvm::Triple::armeb: - case llvm::Triple::thumbeb: - IsBigEndian = true; - LLVM_FALLTHROUGH; - case llvm::Triple::arm: - case llvm::Triple::thumb: - if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, - options::OPT_mbig_endian)) - IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian); - break; - default: - break; - } - return IsBigEndian; -} - static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { switch (T.getArch()) { case llvm::Triple::x86: @@ -253,7 +235,8 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { case llvm::Triple::thumb: case llvm::Triple::armeb: case llvm::Triple::thumbeb: - return isArmBigEndian(T, Args) ? "armelfb_linux_eabi" : "armelf_linux_eabi"; + return tools::arm::isARMBigEndian(T, Args) ? "armelfb_linux_eabi" + : "armelf_linux_eabi"; case llvm::Triple::m68k: return "m68kelf"; case llvm::Triple::ppc: @@ -277,6 +260,10 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { return "elf32_sparc"; case llvm::Triple::sparcv9: return "elf64_sparc"; + case llvm::Triple::loongarch32: + return "elf32loongarch"; + case llvm::Triple::loongarch64: + return "elf64loongarch"; case llvm::Triple::mips: return "elf32btsmip"; case llvm::Triple::mipsel: @@ -299,32 +286,20 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { return "elf_x86_64"; case llvm::Triple::ve: return "elf64ve"; + case llvm::Triple::csky: + return "cskyelf_linux"; default: return nullptr; } } -static bool getPIE(const ArgList &Args, const ToolChain &TC) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_r) || Args.hasArg(options::OPT_static_pie)) - return false; - - Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, - options::OPT_nopie); - if (!A) - return TC.isPIEDefault(); - return A->getOption().matches(options::OPT_pie); -} - static bool getStaticPIE(const ArgList &Args, const ToolChain &TC) { bool HasStaticPIE = Args.hasArg(options::OPT_static_pie); - // -no-pie is an alias for -nopie. So, handling -nopie takes care of - // -no-pie as well. - if (HasStaticPIE && Args.hasArg(options::OPT_nopie)) { + if (HasStaticPIE && Args.hasArg(options::OPT_no_pie)) { const Driver &D = TC.getDriver(); const llvm::opt::OptTable &Opts = D.getOpts(); - const char *StaticPIEName = Opts.getOptionName(options::OPT_static_pie); - const char *NoPIEName = Opts.getOptionName(options::OPT_nopie); + StringRef StaticPIEName = Opts.getOptionName(options::OPT_static_pie); + StringRef NoPIEName = Opts.getOptionName(options::OPT_nopie); D.Diag(diag::err_drv_cannot_mix_options) << StaticPIEName << NoPIEName; } return HasStaticPIE; @@ -388,17 +363,16 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Generic_ELF, so the static_cast might return a reference to a invalid // instance (see PR45061). Ideally, the Linker constructor needs to take a // Generic_ELF instead. - const toolchains::Generic_ELF &ToolChain = - static_cast<const toolchains::Generic_ELF &>(getToolChain()); + const auto &ToolChain = static_cast<const Generic_ELF &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool isOHOSFamily = ToolChain.getTriple().isOHOSFamily(); const bool isAndroid = ToolChain.getTriple().isAndroid(); const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); const bool IsVE = ToolChain.getTriple().isVE(); - const bool IsPIE = getPIE(Args, ToolChain); const bool IsStaticPIE = getStaticPIE(Args, ToolChain); const bool IsStatic = getStatic(Args); const bool HasCRTBeginEndFiles = @@ -418,49 +392,26 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - if (IsPIE) - CmdArgs.push_back("-pie"); - - if (IsStaticPIE) { - CmdArgs.push_back("-static"); - CmdArgs.push_back("-pie"); - CmdArgs.push_back("--no-dynamic-linker"); - CmdArgs.push_back("-z"); - CmdArgs.push_back("text"); - } - - if (ToolChain.isNoExecStackDefault()) { - CmdArgs.push_back("-z"); - CmdArgs.push_back("noexecstack"); - } - - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); - if (Triple.isARM() || Triple.isThumb() || Triple.isAArch64()) { - bool IsBigEndian = isArmBigEndian(Triple, Args); + if (Triple.isARM() || Triple.isThumb()) { + bool IsBigEndian = arm::isARMBigEndian(Triple, Args); if (IsBigEndian) arm::appendBE8LinkFlag(Args, CmdArgs, Triple); - IsBigEndian = IsBigEndian || Arch == llvm::Triple::aarch64_be; CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL"); + } else if (Triple.isAArch64()) { + CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL"); } // Most Android ARM64 targets should enable the linker fix for erratum // 843419. Only non-Cortex-A53 devices are allowed to skip this flag. - if (Arch == llvm::Triple::aarch64 && isAndroid) { - std::string CPU = getCPUName(Args, Triple); + if (Arch == llvm::Triple::aarch64 && (isAndroid || isOHOSFamily)) { + std::string CPU = getCPUName(D, Args, Triple); if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") CmdArgs.push_back("--fix-cortex-a53-843419"); } - // Android does not allow shared text relocations. Emit a warning if the - // user's code contains any. - if (isAndroid) - CmdArgs.push_back("--warn-shared-textrel"); - ToolChain.addExtraOpts(CmdArgs); CmdArgs.push_back("--eh-frame-hdr"); @@ -472,22 +423,29 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(diag::err_target_unknown_triple) << Triple.str(); return; } + if (Triple.isRISCV()) + CmdArgs.push_back("-X"); - if (IsStatic) { - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || - Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb) - CmdArgs.push_back("-Bstatic"); - else - CmdArgs.push_back("-static"); - } else if (Args.hasArg(options::OPT_shared)) { + const bool IsShared = Args.hasArg(options::OPT_shared); + if (IsShared) CmdArgs.push_back("-shared"); - } - - if (!IsStatic) { + bool IsPIE = false; + if (IsStaticPIE) { + CmdArgs.push_back("-static"); + CmdArgs.push_back("-pie"); + CmdArgs.push_back("--no-dynamic-linker"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("text"); + } else if (IsStatic) { + CmdArgs.push_back("-static"); + } else if (!Args.hasArg(options::OPT_r)) { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); - - if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE) { + if (!IsShared) { + IsPIE = Args.hasFlag(options::OPT_pie, options::OPT_no_pie, + ToolChain.isPIEDefault(Args)); + if (IsPIE) + CmdArgs.push_back("-pie"); CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back(Args.MakeArgString(Twine(D.DyldPrefix) + ToolChain.getDynamicLinker(Args))); @@ -497,7 +455,8 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { if (!isAndroid && !IsIAMCU) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { @@ -534,10 +493,10 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (P.empty()) { const char *crtbegin; - if (IsStatic) - crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared)) + if (Args.hasArg(options::OPT_shared)) crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; + else if (IsStatic) + crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; else if (IsPIE || IsStaticPIE) crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; else @@ -549,16 +508,28 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Add crtfastmath.o if available and fast math is enabled. ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs); + + if (isAndroid && Args.hasFlag(options::OPT_fandroid_pad_segment, + options::OPT_fno_android_pad_segment, false)) + CmdArgs.push_back( + Args.MakeArgString(ToolChain.GetFilePath("crt_pad_segment.o"))); } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); ToolChain.AddFilePathLibArgs(Args, CmdArgs); if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); - addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, D.getLTOMode() == LTOK_Thin); } @@ -569,11 +540,15 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + addHIPRuntimeLibArgs(ToolChain, C, Args, CmdArgs); + // The profile runtime also needs access to system libraries. getToolChain().addProfileRTLibs(Args, CmdArgs); if (D.CCCIsCXX() && - !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); @@ -585,19 +560,30 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } CmdArgs.push_back("-lm"); } + // Silence warnings when linking C code with a C++ '-stdlib' argument. Args.ClaimAllArgs(options::OPT_stdlib_EQ); - if (!Args.hasArg(options::OPT_nostdlib)) { + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { if (IsStatic || IsStaticPIE) CmdArgs.push_back("--start-group"); if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, CmdArgs); + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); @@ -617,7 +603,19 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddRunTimeLibs(ToolChain, D, CmdArgs, Args); - if (WantPthread && !isAndroid) + // LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so + // forcibly link with libatomic as a workaround. + // TODO: Issue #41880 and D118021. + if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) { + CmdArgs.push_back("--push-state"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-latomic"); + CmdArgs.push_back("--pop-state"); + } + + // We don't need libpthread neither for bionic (Android) nor for musl, + // (used by OHOS as runtime library). + if (WantPthread && !isAndroid && !isOHOSFamily) CmdArgs.push_back("-lpthread"); if (Args.hasArg(options::OPT_fsplit_stack)) @@ -694,6 +692,10 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, unsigned PICLevel; bool IsPIE; const char *DefaultAssembler = "as"; + // Enforce GNU as on Solaris; the native assembler's input syntax isn't fully + // compatible. + if (getToolChain().getTriple().isOSSolaris()) + DefaultAssembler = "gas"; std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(getToolChain(), Args); @@ -702,20 +704,16 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, CmdArgs.push_back("--compress-debug-sections"); } else { StringRef Value = A->getValue(); - if (Value == "none" || Value == "zlib" || Value == "zlib-gnu") { + if (Value == "none" || Value == "zlib" || Value == "zstd") { CmdArgs.push_back( Args.MakeArgString("--compress-debug-sections=" + Twine(Value))); } else { D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + << A->getSpelling() << Value; } } } - if (getToolChain().isNoExecStackDefault()) { - CmdArgs.push_back("--noexecstack"); - } - switch (getToolChain().getArch()) { default: break; @@ -734,32 +732,32 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, CmdArgs.push_back("-a32"); CmdArgs.push_back("-mppc"); CmdArgs.push_back("-mbig-endian"); - CmdArgs.push_back( - ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); + CmdArgs.push_back(ppc::getPPCAsmModeForCPU( + getCPUName(D, Args, getToolChain().getTriple()))); break; } case llvm::Triple::ppcle: { CmdArgs.push_back("-a32"); CmdArgs.push_back("-mppc"); CmdArgs.push_back("-mlittle-endian"); - CmdArgs.push_back( - ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); + CmdArgs.push_back(ppc::getPPCAsmModeForCPU( + getCPUName(D, Args, getToolChain().getTriple()))); break; } case llvm::Triple::ppc64: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); CmdArgs.push_back("-mbig-endian"); - CmdArgs.push_back( - ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); + CmdArgs.push_back(ppc::getPPCAsmModeForCPU( + getCPUName(D, Args, getToolChain().getTriple()))); break; } case llvm::Triple::ppc64le: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); CmdArgs.push_back("-mlittle-endian"); - CmdArgs.push_back( - ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); + CmdArgs.push_back(ppc::getPPCAsmModeForCPU( + getCPUName(D, Args, getToolChain().getTriple()))); break; } case llvm::Triple::riscv32: @@ -770,12 +768,14 @@ 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: case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); + std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); CmdArgs.push_back( sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); @@ -783,7 +783,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, } case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); + std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); CmdArgs.push_back( sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); @@ -794,7 +794,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, case llvm::Triple::thumb: case llvm::Triple::thumbeb: { const llvm::Triple &Triple2 = getToolChain().getTriple(); - CmdArgs.push_back(isArmBigEndian(Triple2, Args) ? "-EB" : "-EL"); + CmdArgs.push_back(arm::isARMBigEndian(Triple2, Args) ? "-EB" : "-EL"); switch (Triple2.getSubArch()) { case llvm::Triple::ARMSubArch_v7: CmdArgs.push_back("-mfpu=neon"); @@ -823,6 +823,11 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, normalizeCPUNamesForAssembler(Args, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); + // The integrated assembler doesn't implement e_flags setting behavior for + // -meabi=gnu (gcc -mabi={apcs-gnu,atpcs} passes -meabi=gnu to gas). For + // compatibility we accept but warn. + if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) + A->ignoreTargetSpecific(); break; } case llvm::Triple::aarch64: @@ -834,6 +839,13 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, break; } + // TODO: handle loongarch32. + case llvm::Triple::loongarch64: { + StringRef ABIName = + loongarch::getLoongArchABI(D, Args, getToolChain().getTriple()); + CmdArgs.push_back(Args.MakeArgString("-mabi=" + ABIName)); + break; + } case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -931,7 +943,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fdebug_prefix_map_EQ)) { StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) + if (!Map.contains('=')) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else { @@ -950,6 +962,17 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); + if (Arg *A = Args.getLastArg(options::OPT_g_Flag, options::OPT_gN_Group, + options::OPT_gdwarf_2, options::OPT_gdwarf_3, + options::OPT_gdwarf_4, options::OPT_gdwarf_5, + options::OPT_gdwarf)) + if (!A->getOption().matches(options::OPT_g0)) { + Args.AddLastArg(CmdArgs, options::OPT_g_Flag); + + unsigned DwarfVersion = getDwarfVersion(getToolChain(), Args); + CmdArgs.push_back(Args.MakeArgString("-gdwarf-" + Twine(DwarfVersion))); + } + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(DefaultAssembler)); C.addCommand(std::make_unique<Command>(JA, *this, @@ -1013,46 +1036,47 @@ static bool isMSP430(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::msp430; } -static Multilib makeMultilib(StringRef commonSuffix) { - return Multilib(commonSuffix, commonSuffix, commonSuffix); -} - static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // Check for Code Sourcery toolchain multilibs MultilibSet CSMipsMultilibs; { - auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16"); + auto MArchMips16 = MultilibBuilder("/mips16").flag("-m32").flag("-mips16"); auto MArchMicroMips = - makeMultilib("/micromips").flag("+m32").flag("+mmicromips"); + MultilibBuilder("/micromips").flag("-m32").flag("-mmicromips"); - auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips"); + auto MArchDefault = MultilibBuilder("") + .flag("-mips16", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); - auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + auto UCLibc = MultilibBuilder("/uclibc").flag("-muclibc"); - auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float"); + auto SoftFloat = MultilibBuilder("/soft-float").flag("-msoft-float"); - auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + auto Nan2008 = MultilibBuilder("/nan2008").flag("-mnan=2008"); - auto DefaultFloat = - makeMultilib("").flag("-msoft-float").flag("-mnan=2008"); + auto DefaultFloat = MultilibBuilder("") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true); - auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + auto BigEndian = + MultilibBuilder("").flag("-EB").flag("-EL", /*Disallow=*/true); - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + auto LittleEndian = + MultilibBuilder("/el").flag("-EL").flag("-EB", /*Disallow=*/true); // Note that this one's osSuffix is "" - auto MAbi64 = makeMultilib("") + auto MAbi64 = MultilibBuilder("") .gccSuffix("/64") .includeSuffix("/64") - .flag("+mabi=n64") - .flag("-mabi=n32") - .flag("-m32"); + .flag("-mabi=n64") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-m32", /*Disallow=*/true); CSMipsMultilibs = - MultilibSet() + MultilibSetBuilder() .Either(MArchMips16, MArchMicroMips, MArchDefault) .Maybe(UCLibc) .Either(SoftFloat, Nan2008, DefaultFloat) @@ -1062,10 +1086,11 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, .Maybe(MAbi64) .FilterOut("/mips16.*/64") .FilterOut("/micromips.*/64") + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector<std::string> Dirs({"/include"}); - if (StringRef(M.includeSuffix()).startswith("/uclibc")) + if (StringRef(M.includeSuffix()).starts_with("/uclibc")) Dirs.push_back( "/../../../../mips-linux-gnu/libc/uclibc/usr/include"); else @@ -1076,20 +1101,27 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, MultilibSet DebianMipsMultilibs; { - Multilib MAbiN32 = - Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32"); + MultilibBuilder MAbiN32 = + MultilibBuilder().gccSuffix("/n32").includeSuffix("/n32").flag( + "-mabi=n32"); - Multilib M64 = Multilib() - .gccSuffix("/64") - .includeSuffix("/64") - .flag("+m64") - .flag("-m32") - .flag("-mabi=n32"); + MultilibBuilder M64 = MultilibBuilder() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("-m64") + .flag("-m32", /*Disallow=*/true) + .flag("-mabi=n32", /*Disallow=*/true); - Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32"); + MultilibBuilder M32 = MultilibBuilder() + .gccSuffix("/32") + .flag("-m64", /*Disallow=*/true) + .flag("-m32") + .flag("-mabi=n32", /*Disallow=*/true); - DebianMipsMultilibs = - MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); + DebianMipsMultilibs = MultilibSetBuilder() + .Either(M32, M64, MAbiN32) + .makeMultilibSet() + .FilterOut(NonExistent); } // Sort candidates. Toolchain that best meets the directories tree goes first. @@ -1098,7 +1130,7 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, if (CSMipsMultilibs.size() < DebianMipsMultilibs.size()) std::iter_swap(Candidates, Candidates + 1); for (const MultilibSet *Candidate : Candidates) { - if (Candidate->select(Flags, Result.SelectedMultilib)) { + if (Candidate->select(Flags, Result.SelectedMultilibs)) { if (Candidate == &DebianMipsMultilibs) Result.BiarchSibling = Multilib(); Result.Multilibs = *Candidate; @@ -1114,25 +1146,32 @@ static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path, DetectedMultilibs &Result) { MultilibSet AndroidMipsMultilibs = - MultilibSet() - .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) - .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) + MultilibSetBuilder() + .Maybe(MultilibBuilder("/mips-r2", {}, {}).flag("-march=mips32r2")) + .Maybe(MultilibBuilder("/mips-r6", {}, {}).flag("-march=mips32r6")) + .makeMultilibSet() .FilterOut(NonExistent); MultilibSet AndroidMipselMultilibs = - MultilibSet() - .Either(Multilib().flag("+march=mips32"), - Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), - Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + MultilibSetBuilder() + .Either(MultilibBuilder().flag("-march=mips32"), + MultilibBuilder("/mips-r2", "", "/mips-r2") + .flag("-march=mips32r2"), + MultilibBuilder("/mips-r6", "", "/mips-r6") + .flag("-march=mips32r6")) + .makeMultilibSet() .FilterOut(NonExistent); MultilibSet AndroidMips64elMultilibs = - MultilibSet() - .Either( - Multilib().flag("+march=mips64r6"), - Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"), - Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), - Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + MultilibSetBuilder() + .Either(MultilibBuilder().flag("-march=mips64r6"), + MultilibBuilder("/32/mips-r1", "", "/mips-r1") + .flag("-march=mips32"), + MultilibBuilder("/32/mips-r2", "", "/mips-r2") + .flag("-march=mips32r2"), + MultilibBuilder("/32/mips-r6", "", "/mips-r6") + .flag("-march=mips32r6")) + .makeMultilibSet() .FilterOut(NonExistent); MultilibSet *MS = &AndroidMipsMultilibs; @@ -1140,7 +1179,7 @@ static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path, MS = &AndroidMipselMultilibs; else if (VFS.exists(Path + "/32")) MS = &AndroidMips64elMultilibs; - if (MS->select(Flags, Result.SelectedMultilib)) { + if (MS->select(Flags, Result.SelectedMultilibs)) { Result.Multilibs = *MS; return true; } @@ -1153,18 +1192,20 @@ static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, // Musl toolchain multilibs MultilibSet MuslMipsMultilibs; { - auto MArchMipsR2 = makeMultilib("") + auto MArchMipsR2 = MultilibBuilder("") .osSuffix("/mips-r2-hard-musl") - .flag("+EB") - .flag("-EL") - .flag("+march=mips32r2"); + .flag("-EB") + .flag("-EL", /*Disallow=*/true) + .flag("-march=mips32r2"); - auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl") - .flag("-EB") - .flag("+EL") - .flag("+march=mips32r2"); + auto MArchMipselR2 = MultilibBuilder("/mipsel-r2-hard-musl") + .flag("-EB", /*Disallow=*/true) + .flag("-EL") + .flag("-march=mips32r2"); - MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2); + MuslMipsMultilibs = MultilibSetBuilder() + .Either(MArchMipsR2, MArchMipselR2) + .makeMultilibSet(); // Specify the callback that computes the include directories. MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) { @@ -1172,7 +1213,7 @@ static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, {"/../sysroot" + M.osSuffix() + "/usr/include"}); }); } - if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) { + if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilibs)) { Result.Multilibs = MuslMipsMultilibs; return true; } @@ -1185,48 +1226,54 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, // CodeScape MTI toolchain v1.2 and early. MultilibSet MtiMipsMultilibsV1; { - auto MArchMips32 = makeMultilib("/mips32") - .flag("+m32") + auto MArchMips32 = MultilibBuilder("/mips32") + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true) + .flag("-march=mips32"); + + auto MArchMicroMips = MultilibBuilder("/micromips") + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mmicromips"); + + auto MArchMips64r2 = MultilibBuilder("/mips64r2") + .flag("-m32", /*Disallow=*/true) + .flag("-m64") + .flag("-march=mips64r2"); + + auto MArchMips64 = MultilibBuilder("/mips64") + .flag("-m32", /*Disallow=*/true) .flag("-m64") - .flag("-mmicromips") - .flag("+march=mips32"); - - auto MArchMicroMips = makeMultilib("/micromips") - .flag("+m32") - .flag("-m64") - .flag("+mmicromips"); + .flag("-march=mips64r2", /*Disallow=*/true); - auto MArchMips64r2 = makeMultilib("/mips64r2") - .flag("-m32") - .flag("+m64") - .flag("+march=mips64r2"); + auto MArchDefault = MultilibBuilder("") + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true) + .flag("-march=mips32r2"); - auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag( - "-march=mips64r2"); + auto Mips16 = MultilibBuilder("/mips16").flag("-mips16"); - auto MArchDefault = makeMultilib("") - .flag("+m32") - .flag("-m64") - .flag("-mmicromips") - .flag("+march=mips32r2"); + auto UCLibc = MultilibBuilder("/uclibc").flag("-muclibc"); - auto Mips16 = makeMultilib("/mips16").flag("+mips16"); + auto MAbi64 = MultilibBuilder("/64") + .flag("-mabi=n64") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-m32", /*Disallow=*/true); - auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + auto BigEndian = + MultilibBuilder("").flag("-EB").flag("-EL", /*Disallow=*/true); - auto MAbi64 = - makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + auto LittleEndian = + MultilibBuilder("/el").flag("-EL").flag("-EB", /*Disallow=*/true); - auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + auto SoftFloat = MultilibBuilder("/sof").flag("-msoft-float"); - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); - - auto SoftFloat = makeMultilib("/sof").flag("+msoft-float"); - - auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + auto Nan2008 = MultilibBuilder("/nan2008").flag("-mnan=2008"); MtiMipsMultilibsV1 = - MultilibSet() + MultilibSetBuilder() .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, MArchDefault) .Maybe(UCLibc) @@ -1243,10 +1290,11 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, .Maybe(SoftFloat) .Maybe(Nan2008) .FilterOut(".*sof/nan2008") + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector<std::string> Dirs({"/include"}); - if (StringRef(M.includeSuffix()).startswith("/uclibc")) + if (StringRef(M.includeSuffix()).starts_with("/uclibc")) Dirs.push_back("/../../../../sysroot/uclibc/usr/include"); else Dirs.push_back("/../../../../sysroot/usr/include"); @@ -1257,80 +1305,87 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, // CodeScape IMG toolchain starting from v1.3. MultilibSet MtiMipsMultilibsV2; { - auto BeHard = makeMultilib("/mips-r2-hard") - .flag("+EB") + auto BeHard = MultilibBuilder("/mips-r2-hard") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-muclibc", /*Disallow=*/true); + auto BeSoft = MultilibBuilder("/mips-r2-soft") + .flag("-EB") .flag("-msoft-float") - .flag("-mnan=2008") - .flag("-muclibc"); - auto BeSoft = makeMultilib("/mips-r2-soft") - .flag("+EB") - .flag("+msoft-float") - .flag("-mnan=2008"); - auto ElHard = makeMultilib("/mipsel-r2-hard") - .flag("+EL") + .flag("-mnan=2008", /*Disallow=*/true); + auto ElHard = MultilibBuilder("/mipsel-r2-hard") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-muclibc", /*Disallow=*/true); + auto ElSoft = MultilibBuilder("/mipsel-r2-soft") + .flag("-EL") .flag("-msoft-float") - .flag("-mnan=2008") - .flag("-muclibc"); - auto ElSoft = makeMultilib("/mipsel-r2-soft") - .flag("+EL") - .flag("+msoft-float") - .flag("-mnan=2008") - .flag("-mmicromips"); - auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008") - .flag("+EB") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("-muclibc"); - auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008") - .flag("+EL") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("-muclibc") - .flag("-mmicromips"); - auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc") - .flag("+EB") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("+muclibc"); - auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc") - .flag("+EL") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("+muclibc"); - auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc") - .flag("+EB") - .flag("-msoft-float") - .flag("-mnan=2008") - .flag("+muclibc"); - auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc") - .flag("+EL") - .flag("-msoft-float") - .flag("-mnan=2008") - .flag("+muclibc"); - auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008") - .flag("+EL") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("+mmicromips"); - auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft") - .flag("+EL") - .flag("+msoft-float") - .flag("-mnan=2008") - .flag("+mmicromips"); - - auto O32 = - makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); - auto N32 = - makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); - auto N64 = - makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); + auto BeHardNan = MultilibBuilder("/mips-r2-hard-nan2008") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-muclibc", /*Disallow=*/true); + auto ElHardNan = MultilibBuilder("/mipsel-r2-hard-nan2008") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-muclibc", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); + auto BeHardNanUclibc = MultilibBuilder("/mips-r2-hard-nan2008-uclibc") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-muclibc"); + auto ElHardNanUclibc = MultilibBuilder("/mipsel-r2-hard-nan2008-uclibc") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-muclibc"); + auto BeHardUclibc = MultilibBuilder("/mips-r2-hard-uclibc") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-muclibc"); + auto ElHardUclibc = MultilibBuilder("/mipsel-r2-hard-uclibc") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-muclibc"); + auto ElMicroHardNan = MultilibBuilder("/micromipsel-r2-hard-nan2008") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mnan=2008") + .flag("-mmicromips"); + auto ElMicroSoft = MultilibBuilder("/micromipsel-r2-soft") + .flag("-EL") + .flag("-msoft-float") + .flag("-mnan=2008", /*Disallow=*/true) + .flag("-mmicromips"); + + auto O32 = MultilibBuilder("/lib") + .osSuffix("") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-mabi=n64", /*Disallow=*/true); + auto N32 = MultilibBuilder("/lib32") + .osSuffix("") + .flag("-mabi=n32") + .flag("-mabi=n64", /*Disallow=*/true); + auto N64 = MultilibBuilder("/lib64") + .osSuffix("") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-mabi=n64"); MtiMipsMultilibsV2 = - MultilibSet() + MultilibSetBuilder() .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan, BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc, ElHardUclibc, ElMicroHardNan, ElMicroSoft}) .Either(O32, N32, N64) + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector<std::string>({"/../../../../sysroot" + @@ -1342,8 +1397,8 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, {"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()}); }); } - for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { - if (Candidate->select(Flags, Result.SelectedMultilib)) { + for (auto *Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { + if (Candidate->select(Flags, Result.SelectedMultilibs)) { Result.Multilibs = *Candidate; return true; } @@ -1357,18 +1412,24 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, // CodeScape IMG toolchain v1.2 and early. MultilibSet ImgMultilibsV1; { - auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32"); + auto Mips64r6 = MultilibBuilder("/mips64r6") + .flag("-m64") + .flag("-m32", /*Disallow=*/true); - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + auto LittleEndian = + MultilibBuilder("/el").flag("-EL").flag("-EB", /*Disallow=*/true); - auto MAbi64 = - makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + auto MAbi64 = MultilibBuilder("/64") + .flag("-mabi=n64") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-m32", /*Disallow=*/true); ImgMultilibsV1 = - MultilibSet() + MultilibSetBuilder() .Maybe(Mips64r6) .Maybe(MAbi64) .Maybe(LittleEndian) + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector<std::string>( @@ -1379,51 +1440,58 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, // CodeScape IMG toolchain starting from v1.3. MultilibSet ImgMultilibsV2; { - auto BeHard = makeMultilib("/mips-r6-hard") - .flag("+EB") + auto BeHard = MultilibBuilder("/mips-r6-hard") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); + auto BeSoft = MultilibBuilder("/mips-r6-soft") + .flag("-EB") .flag("-msoft-float") - .flag("-mmicromips"); - auto BeSoft = makeMultilib("/mips-r6-soft") - .flag("+EB") - .flag("+msoft-float") - .flag("-mmicromips"); - auto ElHard = makeMultilib("/mipsel-r6-hard") - .flag("+EL") + .flag("-mmicromips", /*Disallow=*/true); + auto ElHard = MultilibBuilder("/mipsel-r6-hard") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mmicromips", /*Disallow=*/true); + auto ElSoft = MultilibBuilder("/mipsel-r6-soft") + .flag("-EL") .flag("-msoft-float") - .flag("-mmicromips"); - auto ElSoft = makeMultilib("/mipsel-r6-soft") - .flag("+EL") - .flag("+msoft-float") - .flag("-mmicromips"); - auto BeMicroHard = makeMultilib("/micromips-r6-hard") - .flag("+EB") + .flag("-mmicromips", /*Disallow=*/true); + auto BeMicroHard = MultilibBuilder("/micromips-r6-hard") + .flag("-EB") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mmicromips"); + auto BeMicroSoft = MultilibBuilder("/micromips-r6-soft") + .flag("-EB") .flag("-msoft-float") - .flag("+mmicromips"); - auto BeMicroSoft = makeMultilib("/micromips-r6-soft") - .flag("+EB") - .flag("+msoft-float") - .flag("+mmicromips"); - auto ElMicroHard = makeMultilib("/micromipsel-r6-hard") - .flag("+EL") + .flag("-mmicromips"); + auto ElMicroHard = MultilibBuilder("/micromipsel-r6-hard") + .flag("-EL") + .flag("-msoft-float", /*Disallow=*/true) + .flag("-mmicromips"); + auto ElMicroSoft = MultilibBuilder("/micromipsel-r6-soft") + .flag("-EL") .flag("-msoft-float") - .flag("+mmicromips"); - auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft") - .flag("+EL") - .flag("+msoft-float") - .flag("+mmicromips"); - - auto O32 = - makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); - auto N32 = - makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); - auto N64 = - makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + .flag("-mmicromips"); + + auto O32 = MultilibBuilder("/lib") + .osSuffix("") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-mabi=n64", /*Disallow=*/true); + auto N32 = MultilibBuilder("/lib32") + .osSuffix("") + .flag("-mabi=n32") + .flag("-mabi=n64", /*Disallow=*/true); + auto N64 = MultilibBuilder("/lib64") + .osSuffix("") + .flag("-mabi=n32", /*Disallow=*/true) + .flag("-mabi=n64"); ImgMultilibsV2 = - MultilibSet() + MultilibSetBuilder() .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft, ElMicroHard, ElMicroSoft}) .Either(O32, N32, N64) + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector<std::string>({"/../../../../sysroot" + @@ -1435,8 +1503,8 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, {"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()}); }); } - for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) { - if (Candidate->select(Flags, Result.SelectedMultilib)) { + for (auto *Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) { + if (Candidate->select(Flags, Result.SelectedMultilibs)) { Result.Multilibs = *Candidate; return true; } @@ -1457,30 +1525,30 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); Multilib::flags_list Flags; - addMultilibFlag(TargetTriple.isMIPS32(), "m32", Flags); - addMultilibFlag(TargetTriple.isMIPS64(), "m64", Flags); - addMultilibFlag(isMips16(Args), "mips16", Flags); - addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); + addMultilibFlag(TargetTriple.isMIPS32(), "-m32", Flags); + addMultilibFlag(TargetTriple.isMIPS64(), "-m64", Flags); + addMultilibFlag(isMips16(Args), "-mips16", Flags); + addMultilibFlag(CPUName == "mips32", "-march=mips32", Flags); addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || CPUName == "mips32r5" || CPUName == "p5600", - "march=mips32r2", Flags); - addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); - addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); + "-march=mips32r2", Flags); + addMultilibFlag(CPUName == "mips32r6", "-march=mips32r6", Flags); + addMultilibFlag(CPUName == "mips64", "-march=mips64", Flags); addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || CPUName == "mips64r5" || CPUName == "octeon" || CPUName == "octeon+", - "march=mips64r2", Flags); - addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); - addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); - addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags); - addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", + "-march=mips64r2", Flags); + addMultilibFlag(CPUName == "mips64r6", "-march=mips64r6", Flags); + addMultilibFlag(isMicroMips(Args), "-mmicromips", Flags); + addMultilibFlag(tools::mips::isUCLibc(Args), "-muclibc", Flags); + addMultilibFlag(tools::mips::isNaN2008(D, Args, TargetTriple), "-mnan=2008", Flags); - addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); - addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); - addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags); - addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags); - addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); - addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); + addMultilibFlag(ABIName == "n32", "-mabi=n32", Flags); + addMultilibFlag(ABIName == "n64", "-mabi=n64", Flags); + addMultilibFlag(isSoftFloatABI(Args), "-msoft-float", Flags); + addMultilibFlag(!isSoftFloatABI(Args), "-mhard-float", Flags); + addMultilibFlag(isMipsEL(TargetArch), "-EL", Flags); + addMultilibFlag(!isMipsEL(TargetArch), "-EB", Flags); if (TargetTriple.isAndroid()) return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent, @@ -1509,7 +1577,7 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, Result.Multilibs.push_back(Default); Result.Multilibs.FilterOut(NonExistent); - if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) { + if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) { Result.BiarchSibling = Multilib(); return true; } @@ -1523,22 +1591,23 @@ static void findAndroidArmMultilibs(const Driver &D, DetectedMultilibs &Result) { // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb. FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); - Multilib ArmV7Multilib = makeMultilib("/armv7-a") - .flag("+march=armv7-a") - .flag("-mthumb"); - Multilib ThumbMultilib = makeMultilib("/thumb") - .flag("-march=armv7-a") - .flag("+mthumb"); - Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb") - .flag("+march=armv7-a") - .flag("+mthumb"); - Multilib DefaultMultilib = makeMultilib("") - .flag("-march=armv7-a") - .flag("-mthumb"); + MultilibBuilder ArmV7Multilib = MultilibBuilder("/armv7-a") + .flag("-march=armv7-a") + .flag("-mthumb", /*Disallow=*/true); + MultilibBuilder ThumbMultilib = MultilibBuilder("/thumb") + .flag("-march=armv7-a", /*Disallow=*/true) + .flag("-mthumb"); + MultilibBuilder ArmV7ThumbMultilib = + MultilibBuilder("/armv7-a/thumb").flag("-march=armv7-a").flag("-mthumb"); + MultilibBuilder DefaultMultilib = + MultilibBuilder("") + .flag("-march=armv7-a", /*Disallow=*/true) + .flag("-mthumb", /*Disallow=*/true); MultilibSet AndroidArmMultilibs = - MultilibSet() - .Either(ThumbMultilib, ArmV7Multilib, - ArmV7ThumbMultilib, DefaultMultilib) + MultilibSetBuilder() + .Either(ThumbMultilib, ArmV7Multilib, ArmV7ThumbMultilib, + DefaultMultilib) + .makeMultilibSet() .FilterOut(NonExistent); Multilib::flags_list Flags; @@ -1552,10 +1621,10 @@ static void findAndroidArmMultilibs(const Driver &D, bool IsArmV7Mode = (IsArmArch || IsThumbArch) && (llvm::ARM::parseArchVersion(Arch) == 7 || (IsArmArch && Arch == "" && IsV7SubArch)); - addMultilibFlag(IsArmV7Mode, "march=armv7-a", Flags); - addMultilibFlag(IsThumbMode, "mthumb", Flags); + addMultilibFlag(IsArmV7Mode, "-march=armv7-a", Flags); + addMultilibFlag(IsThumbMode, "-mthumb", Flags); - if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib)) + if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilibs)) Result.Multilibs = AndroidArmMultilibs; } @@ -1564,24 +1633,210 @@ static bool findMSP430Multilibs(const Driver &D, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); - Multilib WithoutExceptions = makeMultilib("/430").flag("-exceptions"); - Multilib WithExceptions = makeMultilib("/430/exceptions").flag("+exceptions"); + MultilibBuilder WithoutExceptions = + MultilibBuilder("/430").flag("-exceptions", /*Disallow=*/true); + MultilibBuilder WithExceptions = + MultilibBuilder("/430/exceptions").flag("-exceptions"); // FIXME: when clang starts to support msp430x ISA additional logic // to select between multilib must be implemented - // Multilib MSP430xMultilib = makeMultilib("/large"); + // MultilibBuilder MSP430xMultilib = MultilibBuilder("/large"); - Result.Multilibs.push_back(WithoutExceptions); - Result.Multilibs.push_back(WithExceptions); + Result.Multilibs.push_back(WithoutExceptions.makeMultilib()); + Result.Multilibs.push_back(WithExceptions.makeMultilib()); Result.Multilibs.FilterOut(NonExistent); Multilib::flags_list Flags; addMultilibFlag(Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, false), - "exceptions", Flags); - if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) + "-exceptions", Flags); + if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) + return true; + + return false; +} + +static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + + tools::csky::FloatABI TheFloatABI = tools::csky::getCSKYFloatABI(D, Args); + std::optional<llvm::StringRef> Res = + tools::csky::getCSKYArchName(D, Args, TargetTriple); + + if (!Res) + return; + auto ARCHName = *Res; + + Multilib::flags_list Flags; + addMultilibFlag(TheFloatABI == tools::csky::FloatABI::Hard, "-hard-fp", + Flags); + addMultilibFlag(TheFloatABI == tools::csky::FloatABI::SoftFP, "-soft-fp", + Flags); + addMultilibFlag(TheFloatABI == tools::csky::FloatABI::Soft, "-soft", Flags); + addMultilibFlag(ARCHName == "ck801", "-march=ck801", Flags); + addMultilibFlag(ARCHName == "ck802", "-march=ck802", Flags); + addMultilibFlag(ARCHName == "ck803", "-march=ck803", Flags); + addMultilibFlag(ARCHName == "ck804", "-march=ck804", Flags); + addMultilibFlag(ARCHName == "ck805", "-march=ck805", Flags); + addMultilibFlag(ARCHName == "ck807", "-march=ck807", Flags); + addMultilibFlag(ARCHName == "ck810", "-march=ck810", Flags); + addMultilibFlag(ARCHName == "ck810v", "-march=ck810v", Flags); + addMultilibFlag(ARCHName == "ck860", "-march=ck860", Flags); + addMultilibFlag(ARCHName == "ck860v", "-march=ck860v", Flags); + + bool isBigEndian = false; + if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, + options::OPT_mbig_endian)) + isBigEndian = !A->getOption().matches(options::OPT_mlittle_endian); + addMultilibFlag(isBigEndian, "-EB", Flags); + + auto HardFloat = MultilibBuilder("/hard-fp").flag("-hard-fp"); + auto SoftFpFloat = MultilibBuilder("/soft-fp").flag("-soft-fp"); + auto SoftFloat = MultilibBuilder("").flag("-soft"); + auto Arch801 = MultilibBuilder("/ck801").flag("-march=ck801"); + auto Arch802 = MultilibBuilder("/ck802").flag("-march=ck802"); + auto Arch803 = MultilibBuilder("/ck803").flag("-march=ck803"); + // CK804 use the same library as CK803 + auto Arch804 = MultilibBuilder("/ck803").flag("-march=ck804"); + auto Arch805 = MultilibBuilder("/ck805").flag("-march=ck805"); + auto Arch807 = MultilibBuilder("/ck807").flag("-march=ck807"); + auto Arch810 = MultilibBuilder("").flag("-march=ck810"); + auto Arch810v = MultilibBuilder("/ck810v").flag("-march=ck810v"); + auto Arch860 = MultilibBuilder("/ck860").flag("-march=ck860"); + auto Arch860v = MultilibBuilder("/ck860v").flag("-march=ck860v"); + auto BigEndian = MultilibBuilder("/big").flag("-EB"); + + MultilibSet CSKYMultilibs = + MultilibSetBuilder() + .Maybe(BigEndian) + .Either({Arch801, Arch802, Arch803, Arch804, Arch805, Arch807, + Arch810, Arch810v, Arch860, Arch860v}) + .Either(HardFloat, SoftFpFloat, SoftFloat) + .makeMultilibSet() + .FilterOut(NonExistent); + + if (CSKYMultilibs.select(Flags, Result.SelectedMultilibs)) + Result.Multilibs = CSKYMultilibs; +} + +/// Extend the multi-lib re-use selection mechanism for RISC-V. +/// This function will try to re-use multi-lib if they are compatible. +/// Definition of compatible: +/// - ABI must be the same. +/// - multi-lib is a subset of current arch, e.g. multi-lib=march=rv32im +/// is a subset of march=rv32imc. +/// - march that contains atomic extension can't reuse multi-lib that +/// doesn't have atomic, vice versa. e.g. multi-lib=march=rv32im and +/// march=rv32ima are not compatible, because software and hardware +/// atomic operation can't work together correctly. +static bool +selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch, + const Multilib::flags_list &Flags, + llvm::SmallVectorImpl<Multilib> &SelectedMultilibs) { + // Try to find the perfect matching multi-lib first. + if (RISCVMultilibSet.select(Flags, SelectedMultilibs)) return true; + Multilib::flags_list NewFlags; + std::vector<MultilibBuilder> NewMultilibs; + + llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> ParseResult = + llvm::RISCVISAInfo::parseArchString( + Arch, /*EnableExperimentalExtension=*/true, + /*ExperimentalExtensionVersionCheck=*/false); + // Ignore any error here, we assume it will be handled in another place. + if (llvm::errorToBool(ParseResult.takeError())) + return false; + + auto &ISAInfo = *ParseResult; + + addMultilibFlag(ISAInfo->getXLen() == 32, "-m32", NewFlags); + addMultilibFlag(ISAInfo->getXLen() == 64, "-m64", NewFlags); + + // Collect all flags except march=* + for (StringRef Flag : Flags) { + if (Flag.starts_with("!march=") || Flag.starts_with("-march=")) + continue; + + NewFlags.push_back(Flag.str()); + } + + llvm::StringSet<> AllArchExts; + // Reconstruct multi-lib list, and break march option into separated + // extension. e.g. march=rv32im -> +i +m + for (const auto &M : RISCVMultilibSet) { + bool Skip = false; + + MultilibBuilder NewMultilib = + MultilibBuilder(M.gccSuffix(), M.osSuffix(), M.includeSuffix()); + for (StringRef Flag : M.flags()) { + // Add back all flags except -march. + if (!Flag.consume_front("-march=")) { + NewMultilib.flag(Flag); + continue; + } + + // Break down -march into individual extension. + llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> MLConfigParseResult = + llvm::RISCVISAInfo::parseArchString( + Flag, /*EnableExperimentalExtension=*/true, + /*ExperimentalExtensionVersionCheck=*/false); + // Ignore any error here, we assume it will handled in another place. + if (llvm::errorToBool(MLConfigParseResult.takeError())) { + // We might get a parsing error if rv32e in the list, we could just skip + // that and process the rest of multi-lib configs. + Skip = true; + continue; + } + auto &MLConfigISAInfo = *MLConfigParseResult; + + const llvm::RISCVISAInfo::OrderedExtensionMap &MLConfigArchExts = + MLConfigISAInfo->getExtensions(); + for (auto MLConfigArchExt : MLConfigArchExts) { + auto ExtName = MLConfigArchExt.first; + NewMultilib.flag(Twine("-", ExtName).str()); + + if (AllArchExts.insert(ExtName).second) { + addMultilibFlag(ISAInfo->hasExtension(ExtName), + Twine("-", ExtName).str(), NewFlags); + } + } + + // Check the XLEN explicitly. + if (MLConfigISAInfo->getXLen() == 32) { + NewMultilib.flag("-m32"); + NewMultilib.flag("-m64", /*Disallow*/ true); + } else { + NewMultilib.flag("-m32", /*Disallow*/ true); + NewMultilib.flag("-m64"); + } + + // Atomic extension must be explicitly checked, soft and hard atomic + // operation never co-work correctly. + if (!MLConfigISAInfo->hasExtension("a")) + NewMultilib.flag("-a", /*Disallow*/ true); + } + + if (Skip) + continue; + + NewMultilibs.emplace_back(NewMultilib); + } + + // Build an internal used only multi-lib list, used for checking any + // compatible multi-lib. + MultilibSet NewRISCVMultilibs = + MultilibSetBuilder().Either(NewMultilibs).makeMultilibSet(); + + if (NewRISCVMultilibs.select(NewFlags, SelectedMultilibs)) + for (const Multilib &NewSelectedM : SelectedMultilibs) + for (const auto &M : RISCVMultilibSet) + // Look up the corresponding multi-lib entry in original multi-lib set. + if (M.gccSuffix() == NewSelectedM.gccSuffix()) + return true; + return false; } @@ -1601,17 +1856,19 @@ static void findRISCVBareMetalMultilibs(const Driver &D, {"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"}, {"rv64imafdc", "lp64d"}}; - std::vector<Multilib> Ms; + std::vector<MultilibBuilder> Ms; for (auto Element : RISCVMultilibSet) { // multilib path rule is ${march}/${mabi} Ms.emplace_back( - makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str()) - .flag(Twine("+march=", Element.march).str()) - .flag(Twine("+mabi=", Element.mabi).str())); + MultilibBuilder( + (Twine(Element.march) + "/" + Twine(Element.mabi)).str()) + .flag(Twine("-march=", Element.march).str()) + .flag(Twine("-mabi=", Element.mabi).str())); } MultilibSet RISCVMultilibs = - MultilibSet() - .Either(ArrayRef<Multilib>(Ms)) + MultilibSetBuilder() + .Either(Ms) + .makeMultilibSet() .FilterOut(NonExistent) .setFilePathsCallback([](const Multilib &M) { return std::vector<std::string>( @@ -1620,22 +1877,22 @@ static void findRISCVBareMetalMultilibs(const Driver &D, "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()}); }); - Multilib::flags_list Flags; llvm::StringSet<> Added_ABIs; StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); StringRef MArch = tools::riscv::getRISCVArch(Args, TargetTriple); for (auto Element : RISCVMultilibSet) { addMultilibFlag(MArch == Element.march, - Twine("march=", Element.march).str().c_str(), Flags); + Twine("-march=", Element.march).str().c_str(), Flags); if (!Added_ABIs.count(Element.mabi)) { Added_ABIs.insert(Element.mabi); addMultilibFlag(ABIName == Element.mabi, - Twine("mabi=", Element.mabi).str().c_str(), Flags); + Twine("-mabi=", Element.mabi).str().c_str(), Flags); } } - if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) + if (selectRISCVMultilib(RISCVMultilibs, MArch, Flags, + Result.SelectedMultilibs)) Result.Multilibs = RISCVMultilibs; } @@ -1646,33 +1903,38 @@ static void findRISCVMultilibs(const Driver &D, return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result); FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); - Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32"); - Multilib Ilp32f = - makeMultilib("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f"); - Multilib Ilp32d = - makeMultilib("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d"); - Multilib Lp64 = makeMultilib("lib64/lp64").flag("+m64").flag("+mabi=lp64"); - Multilib Lp64f = makeMultilib("lib64/lp64f").flag("+m64").flag("+mabi=lp64f"); - Multilib Lp64d = makeMultilib("lib64/lp64d").flag("+m64").flag("+mabi=lp64d"); + MultilibBuilder Ilp32 = + MultilibBuilder("lib32/ilp32").flag("-m32").flag("-mabi=ilp32"); + MultilibBuilder Ilp32f = + MultilibBuilder("lib32/ilp32f").flag("-m32").flag("-mabi=ilp32f"); + MultilibBuilder Ilp32d = + MultilibBuilder("lib32/ilp32d").flag("-m32").flag("-mabi=ilp32d"); + MultilibBuilder Lp64 = + MultilibBuilder("lib64/lp64").flag("-m64").flag("-mabi=lp64"); + MultilibBuilder Lp64f = + MultilibBuilder("lib64/lp64f").flag("-m64").flag("-mabi=lp64f"); + MultilibBuilder Lp64d = + MultilibBuilder("lib64/lp64d").flag("-m64").flag("-mabi=lp64d"); MultilibSet RISCVMultilibs = - MultilibSet() + MultilibSetBuilder() .Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d}) + .makeMultilibSet() .FilterOut(NonExistent); Multilib::flags_list Flags; bool IsRV64 = TargetTriple.getArch() == llvm::Triple::riscv64; StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); - addMultilibFlag(!IsRV64, "m32", Flags); - addMultilibFlag(IsRV64, "m64", Flags); - addMultilibFlag(ABIName == "ilp32", "mabi=ilp32", Flags); - addMultilibFlag(ABIName == "ilp32f", "mabi=ilp32f", Flags); - addMultilibFlag(ABIName == "ilp32d", "mabi=ilp32d", Flags); - addMultilibFlag(ABIName == "lp64", "mabi=lp64", Flags); - addMultilibFlag(ABIName == "lp64f", "mabi=lp64f", Flags); - addMultilibFlag(ABIName == "lp64d", "mabi=lp64d", Flags); + addMultilibFlag(!IsRV64, "-m32", Flags); + addMultilibFlag(IsRV64, "-m64", Flags); + addMultilibFlag(ABIName == "ilp32", "-mabi=ilp32", Flags); + addMultilibFlag(ABIName == "ilp32f", "-mabi=ilp32f", Flags); + addMultilibFlag(ABIName == "ilp32d", "-mabi=ilp32d", Flags); + addMultilibFlag(ABIName == "lp64", "-mabi=lp64", Flags); + addMultilibFlag(ABIName == "lp64f", "-mabi=lp64f", Flags); + addMultilibFlag(ABIName == "lp64d", "-mabi=lp64d", Flags); - if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) + if (RISCVMultilibs.select(Flags, Result.SelectedMultilibs)) Result.Multilibs = RISCVMultilibs; } @@ -1681,7 +1943,7 @@ static bool findBiarchMultilibs(const Driver &D, StringRef Path, const ArgList &Args, bool NeedsBiarchSuffix, DetectedMultilibs &Result) { - Multilib Default; + MultilibBuilder DefaultBuilder; // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit @@ -1692,7 +1954,7 @@ static bool findBiarchMultilibs(const Driver &D, StringRef Suff64 = "/64"; // Solaris uses platform-specific suffixes instead of /64. - if (TargetTriple.getOS() == llvm::Triple::Solaris) { + if (TargetTriple.isOSSolaris()) { switch (TargetTriple.getArch()) { case llvm::Triple::x86: case llvm::Triple::x86_64: @@ -1707,24 +1969,33 @@ static bool findBiarchMultilibs(const Driver &D, } } - Multilib Alt64 = Multilib() + Multilib Alt64 = MultilibBuilder() .gccSuffix(Suff64) .includeSuffix(Suff64) - .flag("-m32") - .flag("+m64") - .flag("-mx32"); - Multilib Alt32 = Multilib() + .flag("-m32", /*Disallow=*/true) + .flag("-m64") + .flag("-mx32", /*Disallow=*/true) + .makeMultilib(); + Multilib Alt32 = MultilibBuilder() .gccSuffix("/32") .includeSuffix("/32") - .flag("+m32") - .flag("-m64") - .flag("-mx32"); - Multilib Altx32 = Multilib() + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mx32", /*Disallow=*/true) + .makeMultilib(); + Multilib Altx32 = MultilibBuilder() .gccSuffix("/x32") .includeSuffix("/x32") - .flag("-m32") - .flag("-m64") - .flag("+mx32"); + .flag("-m32", /*Disallow=*/true) + .flag("-m64", /*Disallow=*/true) + .flag("-mx32") + .makeMultilib(); + Multilib Alt32sparc = MultilibBuilder() + .gccSuffix("/sparcv8plus") + .includeSuffix("/sparcv8plus") + .flag("-m32") + .flag("-m64", /*Disallow=*/true) + .makeMultilib(); // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a. FilterNonExistent NonExistent( @@ -1736,10 +2007,14 @@ static bool findBiarchMultilibs(const Driver &D, const bool IsX32 = TargetTriple.isX32(); if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) Want = WANT64; + if (TargetTriple.isArch32Bit() && !NonExistent(Alt32sparc)) + Want = WANT64; else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32)) Want = WANT64; else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64)) Want = WANT32; + else if (TargetTriple.isArch64Bit() && !NonExistent(Alt32sparc)) + Want = WANT64; else { if (TargetTriple.isArch32Bit()) Want = NeedsBiarchSuffix ? WANT64 : WANT32; @@ -1750,31 +2025,42 @@ static bool findBiarchMultilibs(const Driver &D, } if (Want == WANT32) - Default.flag("+m32").flag("-m64").flag("-mx32"); + DefaultBuilder.flag("-m32") + .flag("-m64", /*Disallow=*/true) + .flag("-mx32", /*Disallow=*/true); else if (Want == WANT64) - Default.flag("-m32").flag("+m64").flag("-mx32"); + DefaultBuilder.flag("-m32", /*Disallow=*/true) + .flag("-m64") + .flag("-mx32", /*Disallow=*/true); else if (Want == WANTX32) - Default.flag("-m32").flag("-m64").flag("+mx32"); + DefaultBuilder.flag("-m32", /*Disallow=*/true) + .flag("-m64", /*Disallow=*/true) + .flag("-mx32"); else return false; + Multilib Default = DefaultBuilder.makeMultilib(); + Result.Multilibs.push_back(Default); Result.Multilibs.push_back(Alt64); Result.Multilibs.push_back(Alt32); Result.Multilibs.push_back(Altx32); + Result.Multilibs.push_back(Alt32sparc); Result.Multilibs.FilterOut(NonExistent); Multilib::flags_list Flags; - addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags); - addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); - addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags); + addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "-m64", Flags); + addMultilibFlag(TargetTriple.isArch32Bit(), "-m32", Flags); + addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "-mx32", Flags); - if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) + if (!Result.Multilibs.select(Flags, Result.SelectedMultilibs)) return false; - if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 || - Result.SelectedMultilib == Altx32) + if (Result.SelectedMultilibs.back() == Alt64 || + Result.SelectedMultilibs.back() == Alt32 || + Result.SelectedMultilibs.back() == Altx32 || + Result.SelectedMultilibs.back() == Alt32sparc) Result.BiarchSibling = Default; return true; @@ -1790,8 +2076,15 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, StringRef RHSPatchSuffix) const { if (Major != RHSMajor) return Major < RHSMajor; - if (Minor != RHSMinor) + if (Minor != RHSMinor) { + // Note that versions without a specified minor sort higher than those with + // a minor. + if (RHSMinor == -1) + return true; + if (Minor == -1) + return false; return Minor < RHSMinor; + } if (Patch != RHSPatch) { // Note that versions without a specified patch sort higher than those with // a patch. @@ -1827,45 +2120,72 @@ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { std::pair<StringRef, StringRef> First = VersionText.split('.'); std::pair<StringRef, StringRef> Second = First.second.split('.'); - GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; - if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) - return BadVersion; - GoodVersion.MajorStr = First.first.str(); - if (First.second.empty()) - return GoodVersion; + StringRef MajorStr = First.first; StringRef MinorStr = Second.first; - if (Second.second.empty()) { - if (size_t EndNumber = MinorStr.find_first_not_of("0123456789")) { - GoodVersion.PatchSuffix = std::string(MinorStr.substr(EndNumber)); - MinorStr = MinorStr.slice(0, EndNumber); - } - } - if (MinorStr.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) - return BadVersion; - GoodVersion.MinorStr = MinorStr.str(); + StringRef PatchStr = Second.second; - // First look for a number prefix and parse that if present. Otherwise just - // stash the entire patch string in the suffix, and leave the number - // unspecified. This covers versions strings such as: - // 5 (handled above) + GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; + + // Parse version number strings such as: + // 5 // 4.4 // 4.4-patched // 4.4.0 // 4.4.x // 4.4.2-rc4 // 4.4.x-patched - // And retains any patch number it finds. - StringRef PatchText = Second.second; - if (!PatchText.empty()) { - if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { - // Try to parse the number and any suffix. - if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || - GoodVersion.Patch < 0) - return BadVersion; - GoodVersion.PatchSuffix = std::string(PatchText.substr(EndNumber)); + // 10-win32 + // Split on '.', handle 1, 2 or 3 such segments. Each segment must contain + // purely a number, except for the last one, where a non-number suffix + // is stored in PatchSuffix. The third segment is allowed to not contain + // a number at all. + + auto TryParseLastNumber = [&](StringRef Segment, int &Number, + std::string &OutStr) -> bool { + // Look for a number prefix and parse that, and split out any trailing + // string into GoodVersion.PatchSuffix. + + if (size_t EndNumber = Segment.find_first_not_of("0123456789")) { + StringRef NumberStr = Segment.slice(0, EndNumber); + if (NumberStr.getAsInteger(10, Number) || Number < 0) + return false; + OutStr = NumberStr; + GoodVersion.PatchSuffix = Segment.substr(EndNumber); + return true; } + return false; + }; + auto TryParseNumber = [](StringRef Segment, int &Number) -> bool { + if (Segment.getAsInteger(10, Number) || Number < 0) + return false; + return true; + }; + + if (MinorStr.empty()) { + // If no minor string, major is the last segment + if (!TryParseLastNumber(MajorStr, GoodVersion.Major, GoodVersion.MajorStr)) + return BadVersion; + return GoodVersion; + } + + if (!TryParseNumber(MajorStr, GoodVersion.Major)) + return BadVersion; + GoodVersion.MajorStr = MajorStr; + + if (PatchStr.empty()) { + // If no patch string, minor is the last segment + if (!TryParseLastNumber(MinorStr, GoodVersion.Minor, GoodVersion.MinorStr)) + return BadVersion; + return GoodVersion; } + if (!TryParseNumber(MinorStr, GoodVersion.Minor)) + return BadVersion; + GoodVersion.MinorStr = MinorStr; + + // For the last segment, tolerate a missing number. + std::string DummyStr; + TryParseLastNumber(PatchStr, GoodVersion.Patch, DummyStr); return GoodVersion; } @@ -1894,8 +2214,7 @@ static llvm::StringRef getGCCToolchainDir(const ArgList &Args, /// necessary because the driver doesn't store the final version of the target /// triple. void Generic_GCC::GCCInstallationDetector::init( - const llvm::Triple &TargetTriple, const ArgList &Args, - ArrayRef<std::string> ExtraTripleAliases) { + const llvm::Triple &TargetTriple, const ArgList &Args) { llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); @@ -1904,10 +2223,48 @@ void Generic_GCC::GCCInstallationDetector::init( // The compatible GCC triples for this particular architecture. SmallVector<StringRef, 16> CandidateTripleAliases; SmallVector<StringRef, 16> CandidateBiarchTripleAliases; + // Add some triples that we want to check first. + CandidateTripleAliases.push_back(TargetTriple.str()); + std::string TripleNoVendor = TargetTriple.getArchName().str() + "-" + + TargetTriple.getOSAndEnvironmentName().str(); + if (TargetTriple.getVendor() == llvm::Triple::UnknownVendor) + CandidateTripleAliases.push_back(TripleNoVendor); + CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, CandidateTripleAliases, CandidateBiarchLibDirs, CandidateBiarchTripleAliases); + // If --gcc-install-dir= is specified, skip filesystem detection. + if (const Arg *A = + Args.getLastArg(clang::driver::options::OPT_gcc_install_dir_EQ); + A && A->getValue()[0]) { + StringRef InstallDir = A->getValue(); + if (!ScanGCCForMultilibs(TargetTriple, Args, InstallDir, false)) { + D.Diag(diag::err_drv_invalid_gcc_install_dir) << InstallDir; + } else { + (void)InstallDir.consume_back("/"); + StringRef VersionText = llvm::sys::path::filename(InstallDir); + StringRef TripleText = + llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir)); + + Version = GCCVersion::Parse(VersionText); + GCCTriple.setTriple(TripleText); + GCCInstallPath = std::string(InstallDir); + GCCParentLibPath = GCCInstallPath + "/../../.."; + IsValid = true; + } + return; + } + + // If --gcc-triple is specified use this instead of trying to + // auto-detect a triple. + if (const Arg *A = + Args.getLastArg(clang::driver::options::OPT_gcc_triple_EQ)) { + StringRef GCCTriple = A->getValue(); + CandidateTripleAliases.clear(); + CandidateTripleAliases.push_back(GCCTriple); + } + // Compute the set of prefixes for our search. SmallVector<std::string, 8> Prefixes; StringRef GCCToolchainDir = getGCCToolchainDir(Args, D.SysRoot); @@ -1943,9 +2300,6 @@ void Generic_GCC::GCCInstallationDetector::init( // may pick the libraries for x86_64-pc-linux-gnu even when exact matching // triple x86_64-gentoo-linux-gnu is present. GentooTestTriples.push_back(TargetTriple.str()); - // Check rest of triples. - GentooTestTriples.append(ExtraTripleAliases.begin(), - ExtraTripleAliases.end()); GentooTestTriples.append(CandidateTripleAliases.begin(), CandidateTripleAliases.end()); if (ScanGentooConfigs(TargetTriple, Args, GentooTestTriples, @@ -1962,19 +2316,12 @@ void Generic_GCC::GCCInstallationDetector::init( if (!VFS.exists(Prefix)) continue; for (StringRef Suffix : CandidateLibDirs) { - const std::string LibDir = Prefix + Suffix.str(); + const std::string LibDir = concat(Prefix, Suffix); if (!VFS.exists(LibDir)) continue; // Maybe filter out <libdir>/gcc and <libdir>/gcc-cross. bool GCCDirExists = VFS.exists(LibDir + "/gcc"); bool GCCCrossDirExists = VFS.exists(LibDir + "/gcc-cross"); - // Try to match the exact target triple first. - ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, TargetTriple.str(), - false, GCCDirExists, GCCCrossDirExists); - // Try rest of possible triples. - for (StringRef Candidate : ExtraTripleAliases) // Try these first. - ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, false, - GCCDirExists, GCCCrossDirExists); for (StringRef Candidate : CandidateTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, false, GCCDirExists, GCCCrossDirExists); @@ -2011,8 +2358,8 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { } bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { - if (BiarchSibling.hasValue()) { - M = BiarchSibling.getValue(); + if (BiarchSibling) { + M = *BiarchSibling; return true; } return false; @@ -2021,14 +2368,21 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( const llvm::Triple &TargetTriple, SmallVectorImpl<std::string> &Prefixes, StringRef SysRoot) { - if (TargetTriple.getOS() == llvm::Triple::Solaris) { + + if (TargetTriple.isOSHaiku()) { + Prefixes.push_back(concat(SysRoot, "/boot/system/develop/tools")); + return; + } + + if (TargetTriple.isOSSolaris()) { // Solaris is a special case. // The GCC installation is under // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/ // so we need to find those /usr/gcc/*/lib/gcc libdirs and go with // /usr/gcc/<version> as a prefix. - std::string PrefixDir = SysRoot.str() + "/usr/gcc"; + SmallVector<std::pair<GCCVersion, std::string>, 8> SolarisPrefixes; + std::string PrefixDir = concat(SysRoot, "/usr/gcc"); std::error_code EC; for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), LE; @@ -2045,14 +2399,27 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( if (!D.getVFS().exists(CandidateLibPath)) continue; - Prefixes.push_back(CandidatePrefix); + SolarisPrefixes.emplace_back( + std::make_pair(CandidateVersion, CandidatePrefix)); } + // Sort in reverse order so GCCInstallationDetector::init picks the latest. + std::sort(SolarisPrefixes.rbegin(), SolarisPrefixes.rend()); + for (auto p : SolarisPrefixes) + Prefixes.emplace_back(p.second); return; } - // Non-Solaris is much simpler - most systems just go with "/usr". - if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux) { - // Yet, still look for RHEL devtoolsets. + // For Linux, if --sysroot is not specified, look for RHEL/CentOS devtoolsets + // and gcc-toolsets. + if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux && + D.getVFS().exists("/opt/rh")) { + // TODO: We may want to remove this, since the functionality + // can be achieved using config files. + Prefixes.push_back("/opt/rh/gcc-toolset-12/root/usr"); + Prefixes.push_back("/opt/rh/gcc-toolset-11/root/usr"); + Prefixes.push_back("/opt/rh/gcc-toolset-10/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-12/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-11/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-10/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-9/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-8/root/usr"); @@ -2062,7 +2429,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); } - Prefixes.push_back(SysRoot.str() + "/usr"); + + // Fall back to /usr which is used by most non-Solaris systems. + Prefixes.push_back(concat(SysRoot, "/usr")); } /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( @@ -2074,30 +2443,38 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( // Declare a bunch of static data sets that we'll select between below. These // are specifically designed to always refer to string literals to avoid any // lifetime or initialization issues. + // + // The *Triples variables hard code some triples so that, for example, + // --target=aarch64 (incomplete triple) can detect lib/aarch64-linux-gnu. + // They are not needed when the user has correct LLVM_DEFAULT_TARGET_TRIPLE + // and always uses the full --target (e.g. --target=aarch64-linux-gnu). The + // lists should shrink over time. Please don't add more elements to *Triples. static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux", - "aarch64-suse-linux", "aarch64-linux-android"}; + "aarch64-suse-linux"}; static const char *const AArch64beLibDirs[] = {"/lib"}; static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", "aarch64_be-linux-gnu"}; static const char *const ARMLibDirs[] = {"/lib"}; - static const char *const ARMTriples[] = {"arm-linux-gnueabi", - "arm-linux-androideabi"}; + static const char *const ARMTriples[] = {"arm-linux-gnueabi"}; static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", "armv7hl-redhat-linux-gnueabi", "armv6hl-suse-linux-gnueabi", "armv7hl-suse-linux-gnueabi"}; static const char *const ARMebLibDirs[] = {"/lib"}; - static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", - "armeb-linux-androideabi"}; + static const char *const ARMebTriples[] = {"armeb-linux-gnueabi"}; static const char *const ARMebHFTriples[] = { "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; static const char *const AVRLibDirs[] = {"/lib"}; static const char *const AVRTriples[] = {"avr"}; + static const char *const 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", @@ -2105,31 +2482,32 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "x86_64-redhat-linux", "x86_64-suse-linux", "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux", "x86_64-unknown-linux", - "x86_64-amazon-linux", "x86_64-linux-android"}; + "x86_64-amazon-linux"}; static const char *const X32Triples[] = {"x86_64-linux-gnux32", "x86_64-pc-linux-gnux32"}; static const char *const X32LibDirs[] = {"/libx32", "/lib"}; static const char *const X86LibDirs[] = {"/lib32", "/lib"}; static const char *const X86Triples[] = { - "i586-linux-gnu", "i686-linux-gnu", - "i686-pc-linux-gnu", "i386-redhat-linux6E", - "i686-redhat-linux", "i386-redhat-linux", - "i586-suse-linux", "i686-montavista-linux", - "i686-linux-android", "i686-gnu", + "i586-linux-gnu", "i686-linux-gnu", "i686-pc-linux-gnu", + "i386-redhat-linux6E", "i686-redhat-linux", "i386-redhat-linux", + "i586-suse-linux", "i686-montavista-linux", }; + static const char *const LoongArch64LibDirs[] = {"/lib64", "/lib"}; + static const char *const LoongArch64Triples[] = { + "loongarch64-linux-gnu", "loongarch64-unknown-linux-gnu"}; + static const char *const M68kLibDirs[] = {"/lib"}; static const char *const M68kTriples[] = { "m68k-linux-gnu", "m68k-unknown-linux-gnu", "m68k-suse-linux"}; - static const char *const MIPSLibDirs[] = {"/lib"}; + static const char *const MIPSLibDirs[] = {"/libo32", "/lib"}; static const char *const MIPSTriples[] = { "mips-linux-gnu", "mips-mti-linux", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6-linux-gnu"}; - static const char *const MIPSELLibDirs[] = {"/lib"}; + static const char *const MIPSELLibDirs[] = {"/libo32", "/lib"}; static const char *const MIPSELTriples[] = { - "mipsel-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6el-linux-gnu", - "mipsel-linux-android"}; + "mipsel-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6el-linux-gnu"}; static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64Triples[] = { @@ -2140,8 +2518,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64el-linux-gnuabi64", - "mipsisa64r6el-linux-gnu", "mipsisa64r6el-linux-gnuabi64", - "mips64el-linux-android"}; + "mipsisa64r6el-linux-gnu", "mipsisa64r6el-linux-gnuabi64"}; static const char *const MIPSN32LibDirs[] = {"/lib32"}; static const char *const MIPSN32Triples[] = {"mips64-linux-gnuabin32", @@ -2181,9 +2558,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const RISCV64LibDirs[] = {"/lib64", "/lib"}; static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu", "riscv64-linux-gnu", - "riscv64-unknown-elf", - "riscv64-redhat-linux", - "riscv64-suse-linux"}; + "riscv64-unknown-elf"}; static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", @@ -2201,16 +2576,14 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( using std::begin; using std::end; - if (TargetTriple.getOS() == llvm::Triple::Solaris) { + if (TargetTriple.isOSSolaris()) { static const char *const SolarisLibDirs[] = {"/lib"}; static const char *const SolarisSparcV8Triples[] = { - "sparc-sun-solaris2.11", "sparc-sun-solaris2.12"}; + "sparc-sun-solaris2.11"}; static const char *const SolarisSparcV9Triples[] = { - "sparcv9-sun-solaris2.11", "sparcv9-sun-solaris2.12"}; - static const char *const SolarisX86Triples[] = {"i386-pc-solaris2.11", - "i386-pc-solaris2.12"}; - static const char *const SolarisX86_64Triples[] = {"x86_64-pc-solaris2.11", - "x86_64-pc-solaris2.12"}; + "sparcv9-sun-solaris2.11"}; + static const char *const SolarisX86Triples[] = {"i386-pc-solaris2.11"}; + static const char *const SolarisX86_64Triples[] = {"x86_64-pc-solaris2.11"}; LibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); BiarchLibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); switch (TargetTriple.getArch()) { @@ -2248,9 +2621,6 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const AArch64AndroidTriples[] = { "aarch64-linux-android"}; static const char *const ARMAndroidTriples[] = {"arm-linux-androideabi"}; - static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; - static const char *const MIPS64ELAndroidTriples[] = { - "mips64el-linux-android"}; static const char *const X86AndroidTriples[] = {"i686-linux-android"}; static const char *const X86_64AndroidTriples[] = {"x86_64-linux-android"}; @@ -2265,22 +2635,6 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); TripleAliases.append(begin(ARMAndroidTriples), end(ARMAndroidTriples)); break; - case llvm::Triple::mipsel: - LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - TripleAliases.append(begin(MIPSELAndroidTriples), - end(MIPSELAndroidTriples)); - BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), - end(MIPS64ELAndroidTriples)); - break; - case llvm::Triple::mips64el: - LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - TripleAliases.append(begin(MIPS64ELAndroidTriples), - end(MIPS64ELAndroidTriples)); - BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - BiarchTripleAliases.append(begin(MIPSELAndroidTriples), - end(MIPSELAndroidTriples)); - break; case llvm::Triple::x86_64: LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); TripleAliases.append(begin(X86_64AndroidTriples), @@ -2303,6 +2657,23 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( return; } + if (TargetTriple.isOSHurd()) { + switch (TargetTriple.getArch()) { + case llvm::Triple::x86_64: + LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + TripleAliases.push_back("x86_64-gnu"); + break; + case llvm::Triple::x86: + LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + TripleAliases.push_back("i686-gnu"); + break; + default: + break; + } + + return; + } + switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); @@ -2319,7 +2690,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); - if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::EABIHF) { TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); } else { TripleAliases.append(begin(ARMTriples), end(ARMTriples)); @@ -2328,7 +2701,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( case llvm::Triple::armeb: case llvm::Triple::thumbeb: LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); - if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::EABIHF) { TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); } else { TripleAliases.append(begin(ARMebTriples), end(ARMebTriples)); @@ -2338,6 +2713,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( LibDirs.append(begin(AVRLibDirs), end(AVRLibDirs)); TripleAliases.append(begin(AVRTriples), end(AVRTriples)); break; + case llvm::Triple::csky: + LibDirs.append(begin(CSKYLibDirs), end(CSKYLibDirs)); + TripleAliases.append(begin(CSKYTriples), end(CSKYTriples)); + break; case llvm::Triple::x86_64: if (TargetTriple.isX32()) { LibDirs.append(begin(X32LibDirs), end(X32LibDirs)); @@ -2365,6 +2744,11 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( BiarchTripleAliases.append(begin(X32Triples), end(X32Triples)); } break; + // TODO: Handle loongarch32. + case llvm::Triple::loongarch64: + LibDirs.append(begin(LoongArch64LibDirs), end(LoongArch64LibDirs)); + TripleAliases.append(begin(LoongArch64Triples), end(LoongArch64Triples)); + break; case llvm::Triple::m68k: LibDirs.append(begin(M68kLibDirs), end(M68kLibDirs)); TripleAliases.append(begin(M68kTriples), end(M68kTriples)); @@ -2466,10 +2850,6 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( break; } - // Always append the drivers target triple to the end, in case it doesn't - // match any of our aliases. - TripleAliases.push_back(TargetTriple.str()); - // Also include the multiarch variant if it's different. if (TargetTriple.str() != BiarchTriple.str()) BiarchTripleAliases.push_back(BiarchTriple.str()); @@ -2487,6 +2867,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { // It should also work without multilibs in a simplified toolchain. findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); + } else if (TargetTriple.isCSKY()) { + findCSKYMultilibs(D, TargetTriple, Path, Args, Detected); } else if (TargetTriple.isMIPS()) { if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) return false; @@ -2502,7 +2884,9 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( } Multilibs = Detected.Multilibs; - SelectedMultilib = Detected.SelectedMultilib; + SelectedMultilib = Detected.SelectedMultilibs.empty() + ? Multilib() + : Detected.SelectedMultilibs.back(); BiarchSibling = Detected.BiarchSibling; return true; @@ -2577,7 +2961,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( const llvm::Triple &TargetTriple, const ArgList &Args, const SmallVectorImpl<StringRef> &CandidateTriples, const SmallVectorImpl<StringRef> &CandidateBiarchTriples) { - if (!D.getVFS().exists(D.SysRoot + GentooConfigDir)) + if (!D.getVFS().exists(concat(D.SysRoot, GentooConfigDir))) return false; for (StringRef CandidateTriple : CandidateTriples) { @@ -2596,8 +2980,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( const llvm::Triple &TargetTriple, const ArgList &Args, StringRef CandidateTriple, bool NeedsBiarchSuffix) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = - D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/config-" + - CandidateTriple.str()); + D.getVFS().getBufferForFile(concat(D.SysRoot, GentooConfigDir, + "/config-" + CandidateTriple.str())); if (File) { SmallVector<StringRef, 2> Lines; File.get()->getBuffer().split(Lines, "\n"); @@ -2608,8 +2992,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( continue; // Process the config file pointed to by CURRENT. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ConfigFile = - D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/" + - Line.str()); + D.getVFS().getBufferForFile( + concat(D.SysRoot, GentooConfigDir, "/" + Line)); std::pair<StringRef, StringRef> ActiveVersion = Line.rsplit('-'); // List of paths to scan for libraries. SmallVector<StringRef, 4> GentooScanPaths; @@ -2642,7 +3026,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( // Scan all paths for GCC libraries. for (const auto &GentooScanPath : GentooScanPaths) { - std::string GentooPath = D.SysRoot + std::string(GentooScanPath); + std::string GentooPath = concat(D.SysRoot, GentooScanPath); if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, NeedsBiarchSuffix)) @@ -2697,21 +3081,26 @@ Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); } void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { // Print the information about how we detected the GCC installation. GCCInstallation.print(OS); - CudaInstallation.print(OS); - RocmInstallation.print(OS); + CudaInstallation->print(OS); + RocmInstallation->print(OS); } -bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel +Generic_GCC::getDefaultUnwindTableLevel(const ArgList &Args) const { switch (getArch()) { case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: case llvm::Triple::ppc: case llvm::Triple::ppcle: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + case llvm::Triple::x86: case llvm::Triple::x86_64: - return true; + return UnwindTableLevel::Asynchronous; default: - return false; + return UnwindTableLevel::None; } } @@ -2727,7 +3116,9 @@ bool Generic_GCC::isPICDefault() const { } } -bool Generic_GCC::isPIEDefault() const { return false; } +bool Generic_GCC::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool Generic_GCC::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); @@ -2735,40 +3126,12 @@ bool Generic_GCC::isPICDefaultForced() const { bool Generic_GCC::IsIntegratedAssemblerDefault() const { switch (getTriple().getArch()) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::avr: - case llvm::Triple::bpfel: - case llvm::Triple::bpfeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::ppc: - case llvm::Triple::ppcle: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - case llvm::Triple::systemz: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::msp430: - case llvm::Triple::m68k: - return true; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - if (getTriple().isOSFreeBSD() || getTriple().isOSOpenBSD() || - getTriple().isOSSolaris()) - return true; + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + case llvm::Triple::xcore: return false; default: - return false; + return true; } } @@ -2794,6 +3157,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, path_list &Paths) { // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { + assert(!SelectedMultilibs.empty()); const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = std::string(GCCInstallation.getParentLibPath()); @@ -2801,13 +3165,19 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, // Sourcery CodeBench MIPS toolchain holds some libraries under // a biarch-like suffix of the GCC installation. if (const auto &PathsCallback = Multilibs.filePathsCallback()) - for (const auto &Path : PathsCallback(SelectedMultilib)) + for (const auto &Path : PathsCallback(SelectedMultilibs.back())) addPathIfExists(D, GCCInstallation.getInstallPath() + Path, Paths); // Add lib/gcc/$triple/$version, with an optional /multilib suffix. - addPathIfExists( - D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(), - Paths); + addPathIfExists(D, + GCCInstallation.getInstallPath() + + SelectedMultilibs.back().gccSuffix(), + Paths); + + // Add lib/gcc/$triple/$libdir + // For GCC built with --enable-version-specific-runtime-libs. + addPathIfExists(D, GCCInstallation.getInstallPath() + "/../" + OSLibDir, + Paths); // GCC cross compiling toolchains will install target libraries which ship // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as @@ -2829,7 +3199,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, // Clang diverges from GCC's behavior. addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + - SelectedMultilib.osSuffix(), + SelectedMultilibs.back().osSuffix(), Paths); // If the GCC installation we found is inside of the sysroot, we want to @@ -2841,7 +3211,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D, // the cross. Note that GCC does include some of these directories in some // configurations but this seems somewhere between questionable and simply // a bug. - if (StringRef(LibPath).startswith(SysRoot)) + if (StringRef(LibPath).starts_with(SysRoot)) addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); } } @@ -2902,34 +3272,53 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { const Driver &D = getDriver(); std::string SysRoot = computeSysRoot(); - std::string Target = getTripleString(); + if (SysRoot.empty()) + SysRoot = llvm::sys::path::get_separator(); - auto AddIncludePath = [&](std::string Path) { + auto AddIncludePath = [&](StringRef Path, bool TargetDirRequired = false) { std::string Version = detectLibcxxVersion(Path); if (Version.empty()) return false; // First add the per-target include path if it exists. - std::string TargetDir = Path + "/" + Target + "/c++/" + Version; - if (D.getVFS().exists(TargetDir)) - addSystemInclude(DriverArgs, CC1Args, TargetDir); + bool TargetDirExists = false; + std::optional<std::string> TargetIncludeDir = getTargetSubDirPath(Path); + if (TargetIncludeDir) { + SmallString<128> TargetDir(*TargetIncludeDir); + llvm::sys::path::append(TargetDir, "c++", Version); + if (D.getVFS().exists(TargetDir)) { + addSystemInclude(DriverArgs, CC1Args, TargetDir); + TargetDirExists = true; + } + } + if (TargetDirRequired && !TargetDirExists) + return false; // Second add the generic one. - addSystemInclude(DriverArgs, CC1Args, Path + "/c++/" + Version); + SmallString<128> GenericDir(Path); + llvm::sys::path::append(GenericDir, "c++", Version); + addSystemInclude(DriverArgs, CC1Args, GenericDir); return true; }; - // Android never uses the libc++ headers installed alongside the toolchain, - // which are generally incompatible with the NDK libraries anyway. - if (!getTriple().isAndroid()) - if (AddIncludePath(getDriver().Dir + "/../include")) - return; + // Android only uses the libc++ headers installed alongside the toolchain if + // they contain an Android-specific target include path, otherwise they're + // incompatible with the NDK libraries. + SmallString<128> DriverIncludeDir(getDriver().Dir); + llvm::sys::path::append(DriverIncludeDir, "..", "include"); + if (AddIncludePath(DriverIncludeDir, + /*TargetDirRequired=*/getTriple().isAndroid())) + return; // If this is a development, non-installed, clang, libcxx will // not be found at ../include/c++ but it likely to be found at // one of the following two locations: - if (AddIncludePath(SysRoot + "/usr/local/include")) + SmallString<128> UsrLocalIncludeDir(SysRoot); + llvm::sys::path::append(UsrLocalIncludeDir, "usr", "local", "include"); + if (AddIncludePath(UsrLocalIncludeDir)) return; - if (AddIncludePath(SysRoot + "/usr/include")) + SmallString<128> UsrIncludeDir(SysRoot); + llvm::sys::path::append(UsrIncludeDir, "usr", "include"); + if (AddIncludePath(UsrIncludeDir)) return; } @@ -2987,6 +3376,15 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths( TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args)) return true; + // Try /gcc/$triple/$version/include/c++/ (gcc --print-multiarch is not + // empty). Like above but for GCC built with + // --enable-version-specific-runtime-libs. + if (addLibStdCXXIncludePaths(LibDir.str() + "/gcc/" + TripleStr + "/" + + Version.Text + "/include/c++/", + TripleStr, Multilib.includeSuffix(), DriverArgs, + CC1Args)) + return true; + // Detect Debian g++-multiarch-incdir.diff. if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text, DebianMultiarch, Multilib.includeSuffix(), diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h index 40fd756a5653..0b664a182d75 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H #include "Cuda.h" +#include "LazyDetector.h" #include "ROCm.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" @@ -22,12 +23,12 @@ struct DetectedMultilibs { /// The set of multilibs that the detected installation supports. MultilibSet Multilibs; - /// The primary multilib appropriate for the given flags. - Multilib SelectedMultilib; + /// The multilibs appropriate for the given flags. + llvm::SmallVector<Multilib> SelectedMultilibs; /// On Biarch systems, this corresponds to the default multilib when /// targeting the non-default multilib. Otherwise, it is empty. - llvm::Optional<Multilib> BiarchSibling; + std::optional<Multilib> BiarchSibling; }; bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, @@ -201,7 +202,7 @@ public: Multilib SelectedMultilib; /// On Biarch systems, this corresponds to the default multilib when /// targeting the non-default multilib. Otherwise, it is empty. - llvm::Optional<Multilib> BiarchSibling; + std::optional<Multilib> BiarchSibling; GCCVersion Version; @@ -217,8 +218,7 @@ public: public: explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} - void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, - ArrayRef<std::string> ExtraTripleAliases = None); + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); /// Check whether we detected a valid GCC install. bool isValid() const { return IsValid; } @@ -286,8 +286,8 @@ public: protected: GCCInstallationDetector GCCInstallation; - CudaInstallationDetector CudaInstallation; - RocmInstallationDetector RocmInstallation; + LazyDetector<CudaInstallationDetector> CudaInstallation; + LazyDetector<RocmInstallationDetector> RocmInstallation; public: Generic_GCC(const Driver &D, const llvm::Triple &Triple, @@ -296,9 +296,10 @@ public: void printVerboseInfo(raw_ostream &OS) const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; bool IsIntegratedAssemblerDefault() const override; llvm::opt::DerivedArgList * diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp deleted file mode 100644 index c4e840de86e1..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIP.cpp +++ /dev/null @@ -1,458 +0,0 @@ -//===--- HIP.cpp - HIP Tool and ToolChain Implementations -------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "HIP.h" -#include "AMDGPU.h" -#include "CommonArgs.h" -#include "clang/Basic/Cuda.h" -#include "clang/Basic/TargetID.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/InputInfo.h" -#include "clang/Driver/Options.h" -#include "llvm/Support/Alignment.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/TargetParser.h" - -using namespace clang::driver; -using namespace clang::driver::toolchains; -using namespace clang::driver::tools; -using namespace clang; -using namespace llvm::opt; - -#if defined(_WIN32) || defined(_WIN64) -#define NULL_FILE "nul" -#else -#define NULL_FILE "/dev/null" -#endif - -namespace { -const unsigned HIPCodeObjectAlign = 4096; -} // namespace - -void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const InputInfo &Output, - const llvm::opt::ArgList &Args) const { - // Construct lld command. - // The output from ld.lld is an HSA code object file. - ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", "-shared", - "-plugin-opt=-amdgpu-internalize-symbols"}; - - auto &TC = getToolChain(); - auto &D = TC.getDriver(); - assert(!Inputs.empty() && "Must have at least one input."); - bool IsThinLTO = D.getLTOMode(/*IsOffload=*/true) == LTOK_Thin; - addLTOOptions(TC, Args, LldArgs, Output, Inputs[0], IsThinLTO); - - // Extract all the -m options - std::vector<llvm::StringRef> Features; - amdgpu::getAMDGPUTargetFeatures(D, TC.getTriple(), Args, Features); - - // Add features to mattr such as cumode - std::string MAttrString = "-plugin-opt=-mattr="; - for (auto OneFeature : unifyTargetFeatures(Features)) { - MAttrString.append(Args.MakeArgString(OneFeature)); - if (OneFeature != Features.back()) - MAttrString.append(","); - } - if (!Features.empty()) - LldArgs.push_back(Args.MakeArgString(MAttrString)); - - // ToDo: Remove this option after AMDGPU backend supports ISA-level linking. - // Since AMDGPU backend currently does not support ISA-level linking, all - // called functions need to be imported. - if (IsThinLTO) - LldArgs.push_back(Args.MakeArgString("-plugin-opt=-force-import-all")); - - for (const Arg *A : Args.filtered(options::OPT_mllvm)) { - LldArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0))); - } - - if (C.getDriver().isSaveTempsEnabled()) - LldArgs.push_back("-save-temps"); - - addLinkerCompressDebugSectionsOption(TC, Args, LldArgs); - - LldArgs.append({"-o", Output.getFilename()}); - for (auto Input : Inputs) - LldArgs.push_back(Input.getFilename()); - - if (Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize, - false)) - llvm::for_each(TC.getHIPDeviceLibs(Args), [&](StringRef BCFile) { - LldArgs.push_back(Args.MakeArgString(BCFile)); - }); - - const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Lld, LldArgs, Inputs, Output)); -} - -// Construct a clang-offload-bundler command to bundle code objects for -// different GPU's into a HIP fat binary. -void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, - StringRef OutputFileName, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, const Tool& T) { - // Construct clang-offload-bundler command to bundle object files for - // for different GPU archs. - ArgStringList BundlerArgs; - BundlerArgs.push_back(Args.MakeArgString("-type=o")); - BundlerArgs.push_back( - Args.MakeArgString("-bundle-align=" + Twine(HIPCodeObjectAlign))); - - // ToDo: Remove the dummy host binary entry which is required by - // clang-offload-bundler. - std::string BundlerTargetArg = "-targets=host-x86_64-unknown-linux"; - std::string BundlerInputArg = "-inputs=" NULL_FILE; - - // For 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 - // offload kind in bundle ID is 'hipv4'. - std::string OffloadKind = "hip"; - if (getAMDGPUCodeObjectVersion(C.getDriver(), Args) >= 4) - OffloadKind = OffloadKind + "v4"; - for (const auto &II : Inputs) { - const auto* A = II.getAction(); - BundlerTargetArg = BundlerTargetArg + "," + OffloadKind + - "-amdgcn-amd-amdhsa--" + - StringRef(A->getOffloadingArch()).str(); - BundlerInputArg = BundlerInputArg + "," + II.getFilename(); - } - BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg)); - BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg)); - - std::string Output = std::string(OutputFileName); - auto BundlerOutputArg = - Args.MakeArgString(std::string("-outputs=").append(Output)); - BundlerArgs.push_back(BundlerOutputArg); - - const char *Bundler = Args.MakeArgString( - T.getToolChain().GetProgramPath("clang-offload-bundler")); - C.addCommand(std::make_unique<Command>( - JA, T, ResponseFileSupport::None(), Bundler, BundlerArgs, Inputs, - InputInfo(&JA, Args.MakeArgString(Output)))); -} - -/// Add Generated HIP Object File which has device images embedded into the -/// host to the argument list for linking. Using MC directives, embed the -/// device code and also define symbols required by the code generation so that -/// the image can be retrieved at runtime. -void AMDGCN::Linker::constructGenerateObjFileFromHIPFatBinary( - Compilation &C, const InputInfo &Output, - const InputInfoList &Inputs, const ArgList &Args, - const JobAction &JA) const { - const ToolChain &TC = getToolChain(); - std::string Name = - std::string(llvm::sys::path::stem(Output.getFilename())); - - // Create Temp Object File Generator, - // Offload Bundled file and Bundled Object file. - // Keep them if save-temps is enabled. - const char *McinFile; - const char *BundleFile; - if (C.getDriver().isSaveTempsEnabled()) { - McinFile = C.getArgs().MakeArgString(Name + ".mcin"); - BundleFile = C.getArgs().MakeArgString(Name + ".hipfb"); - } else { - auto TmpNameMcin = C.getDriver().GetTemporaryPath(Name, "mcin"); - McinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin)); - auto TmpNameFb = C.getDriver().GetTemporaryPath(Name, "hipfb"); - BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameFb)); - } - constructHIPFatbinCommand(C, JA, BundleFile, Inputs, Args, *this); - - // Create a buffer to write the contents of the temp obj generator. - std::string ObjBuffer; - llvm::raw_string_ostream ObjStream(ObjBuffer); - - // Add MC directives to embed target binaries. We ensure that each - // section and image is 16-byte aligned. This is not mandatory, but - // increases the likelihood of data to be aligned with a cache block - // in several main host machines. - ObjStream << "# HIP Object Generator\n"; - ObjStream << "# *** Automatically generated by Clang ***\n"; - ObjStream << " .protected __hip_fatbin\n"; - ObjStream << " .type __hip_fatbin,@object\n"; - ObjStream << " .section .hip_fatbin,\"a\",@progbits\n"; - ObjStream << " .globl __hip_fatbin\n"; - ObjStream << " .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign)) - << "\n"; - ObjStream << "__hip_fatbin:\n"; - ObjStream << " .incbin \"" << BundleFile << "\"\n"; - ObjStream.flush(); - - // Dump the contents of the temp object file gen if the user requested that. - // We support this option to enable testing of behavior with -###. - if (C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script)) - llvm::errs() << ObjBuffer; - - // Open script file and write the contents. - std::error_code EC; - llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None); - - if (EC) { - C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); - return; - } - - Objf << ObjBuffer; - - ArgStringList McArgs{"-o", Output.getFilename(), - McinFile, "--filetype=obj"}; - const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc")); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Mc, McArgs, 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. -void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - if (Inputs.size() > 0 && - Inputs[0].getType() == types::TY_Image && - JA.getType() == types::TY_Object) - return constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, Args, JA); - - if (JA.getType() == types::TY_HIP_FATBIN) - return constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, Args, *this); - - return constructLldCommand(C, JA, Inputs, Output, Args); -} - -HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const ArgList &Args) - : ROCMToolChain(D, Triple, Args), HostTC(HostTC) { - // Lookup binaries into the driver directory, this is used to - // discover the clang-offload-bundler executable. - getProgramPaths().push_back(getDriver().Dir); -} - -void HIPToolChain::addClangTargetOptions( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadingKind) const { - HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); - - assert(DeviceOffloadingKind == Action::OFK_HIP && - "Only HIP offloading kinds are supported for GPUs."); - - CC1Args.push_back("-fcuda-is-device"); - - if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, - options::OPT_fno_cuda_approx_transcendentals, false)) - CC1Args.push_back("-fcuda-approx-transcendentals"); - - if (!DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, - false)) - CC1Args.append({"-mllvm", "-amdgpu-internalize-symbols"}); - - StringRef MaxThreadsPerBlock = - DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ); - if (!MaxThreadsPerBlock.empty()) { - std::string ArgStr = - std::string("--gpu-max-threads-per-block=") + MaxThreadsPerBlock.str(); - CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr)); - } - - CC1Args.push_back("-fcuda-allow-variadic-functions"); - - // Default to "hidden" visibility, as object level linking will not be - // supported for the foreseeable future. - if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, - options::OPT_fvisibility_ms_compat)) { - CC1Args.append({"-fvisibility", "hidden"}); - CC1Args.push_back("-fapply-global-visibility-to-externs"); - } - - llvm::for_each(getHIPDeviceLibs(DriverArgs), [&](StringRef BCFile) { - CC1Args.push_back("-mlink-builtin-bitcode"); - CC1Args.push_back(DriverArgs.MakeArgString(BCFile)); - }); -} - -llvm::opt::DerivedArgList * -HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, - StringRef BoundArch, - Action::OffloadKind DeviceOffloadKind) const { - DerivedArgList *DAL = - HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); - if (!DAL) - DAL = new DerivedArgList(Args.getBaseArgs()); - - const OptTable &Opts = getDriver().getOpts(); - - for (Arg *A : Args) { - if (!shouldSkipArgument(A)) - DAL->append(A); - } - - if (!BoundArch.empty()) { - DAL->eraseArg(options::OPT_mcpu_EQ); - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), BoundArch); - checkTargetID(*DAL); - } - - return DAL; -} - -Tool *HIPToolChain::buildLinker() const { - assert(getTriple().getArch() == llvm::Triple::amdgcn); - return new tools::AMDGCN::Linker(*this); -} - -void HIPToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { - HostTC.addClangWarningOptions(CC1Args); -} - -ToolChain::CXXStdlibType -HIPToolChain::GetCXXStdlibType(const ArgList &Args) const { - return HostTC.GetCXXStdlibType(Args); -} - -void HIPToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); -} - -void HIPToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, - ArgStringList &CC1Args) const { - HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); -} - -void HIPToolChain::AddIAMCUIncludeArgs(const ArgList &Args, - ArgStringList &CC1Args) const { - HostTC.AddIAMCUIncludeArgs(Args, CC1Args); -} - -void HIPToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); -} - -SanitizerMask HIPToolChain::getSupportedSanitizers() const { - // The HIPToolChain only supports sanitizers in the sense that it allows - // sanitizer arguments on the command line if they are supported by the host - // toolchain. The HIPToolChain will actually ignore any command line - // arguments for any of these "supported" sanitizers. That means that no - // sanitization of device code is actually supported at this time. - // - // This behavior is necessary because the host and device toolchains - // invocations often share the command line, so the device toolchain must - // tolerate flags meant only for the host toolchain. - return HostTC.getSupportedSanitizers(); -} - -VersionTuple HIPToolChain::computeMSVCVersion(const Driver *D, - const ArgList &Args) const { - return HostTC.computeMSVCVersion(D, Args); -} - -llvm::SmallVector<std::string, 12> -HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { - llvm::SmallVector<std::string, 12> BCLibs; - if (DriverArgs.hasArg(options::OPT_nogpulib)) - return {}; - ArgStringList LibraryPaths; - - // Find in --hip-device-lib-path and HIP_LIBRARY_PATH. - for (auto Path : RocmInstallation.getRocmDeviceLibPathArg()) - LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); - - addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH"); - - // Maintain compatability with --hip-device-lib. - auto BCLibArgs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ); - if (!BCLibArgs.empty()) { - llvm::for_each(BCLibArgs, [&](StringRef BCName) { - StringRef FullName; - for (std::string LibraryPath : LibraryPaths) { - SmallString<128> Path(LibraryPath); - llvm::sys::path::append(Path, BCName); - FullName = Path; - if (llvm::sys::fs::exists(FullName)) { - BCLibs.push_back(FullName.str()); - return; - } - } - getDriver().Diag(diag::err_drv_no_such_file) << BCName; - }); - } else { - if (!RocmInstallation.hasDeviceLibrary()) { - getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; - return {}; - } - StringRef GpuArch = getGPUArch(DriverArgs); - assert(!GpuArch.empty() && "Must have an explicit GPU arch."); - - // If --hip-device-lib is not set, add the default bitcode libraries. - if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize, - options::OPT_fno_gpu_sanitize, false)) { - auto AsanRTL = RocmInstallation.getAsanRTLPath(); - if (AsanRTL.empty()) { - unsigned DiagID = getDriver().getDiags().getCustomDiagID( - DiagnosticsEngine::Error, - "AMDGPU address sanitizer runtime library (asanrtl) is not found. " - "Please install ROCm device library which supports address " - "sanitizer"); - getDriver().Diag(DiagID); - return {}; - } else - BCLibs.push_back(AsanRTL.str()); - } - - // Add the HIP specific bitcode library. - BCLibs.push_back(RocmInstallation.getHIPPath().str()); - - // Add common device libraries like ocml etc. - BCLibs.append(getCommonDeviceLibNames(DriverArgs, GpuArch.str())); - - // Add instrument lib. - auto InstLib = - DriverArgs.getLastArgValue(options::OPT_gpu_instrument_lib_EQ); - if (InstLib.empty()) - return BCLibs; - if (llvm::sys::fs::exists(InstLib)) - BCLibs.push_back(InstLib.str()); - else - getDriver().Diag(diag::err_drv_no_such_file) << InstLib; - } - - return BCLibs; -} - -void HIPToolChain::checkTargetID(const llvm::opt::ArgList &DriverArgs) const { - auto PTID = getParsedTargetID(DriverArgs); - if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) { - getDriver().Diag(clang::diag::err_drv_bad_target_id) - << PTID.OptionalTargetID.getValue(); - return; - } - - assert(PTID.OptionalFeatures && "Invalid return from getParsedTargetID"); - auto &FeatureMap = PTID.OptionalFeatures.getValue(); - // Sanitizer is not supported with xnack-. - if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize, - options::OPT_fno_gpu_sanitize, false)) { - auto Loc = FeatureMap.find("xnack"); - if (Loc != FeatureMap.end() && !Loc->second) { - auto &Diags = getDriver().getDiags(); - auto DiagID = Diags.getCustomDiagID( - DiagnosticsEngine::Error, - "'-fgpu-sanitize' is not compatible with offload arch '%0'. " - "Use an offload arch without 'xnack-' instead"); - Diags.Report(DiagID) << PTID.OptionalTargetID.getValue(); - } - } -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp new file mode 100644 index 000000000000..ccb36a6c846c --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp @@ -0,0 +1,434 @@ +//===--- HIPAMD.cpp - HIP Tool and ToolChain Implementations ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "HIPAMD.h" +#include "AMDGPU.h" +#include "CommonArgs.h" +#include "HIPUtility.h" +#include "clang/Basic/Cuda.h" +#include "clang/Basic/TargetID.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/InputInfo.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/TargetParser/TargetParser.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +#if defined(_WIN32) || defined(_WIN64) +#define NULL_FILE "nul" +#else +#define NULL_FILE "/dev/null" +#endif + +static bool shouldSkipSanitizeOption(const ToolChain &TC, + const llvm::opt::ArgList &DriverArgs, + StringRef TargetID, + const llvm::opt::Arg *A) { + // For actions without targetID, do nothing. + if (TargetID.empty()) + return false; + Option O = A->getOption(); + if (!O.matches(options::OPT_fsanitize_EQ)) + return false; + + if (!DriverArgs.hasFlag(options::OPT_fgpu_sanitize, + options::OPT_fno_gpu_sanitize, true)) + return true; + + auto &Diags = TC.getDriver().getDiags(); + + // For simplicity, we only allow -fsanitize=address + SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false); + if (K != SanitizerKind::Address) + return true; + + llvm::StringMap<bool> FeatureMap; + auto OptionalGpuArch = parseTargetID(TC.getTriple(), TargetID, &FeatureMap); + + assert(OptionalGpuArch && "Invalid Target ID"); + (void)OptionalGpuArch; + auto Loc = FeatureMap.find("xnack"); + if (Loc == FeatureMap.end() || !Loc->second) { + Diags.Report( + clang::diag::warn_drv_unsupported_option_for_offload_arch_req_feature) + << A->getAsString(DriverArgs) << TargetID << "xnack+"; + return true; + } + return false; +} + +void AMDGCN::Linker::constructLlvmLinkCommand(Compilation &C, + const JobAction &JA, + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args) const { + // Construct llvm-link command. + // The output from llvm-link is a bitcode file. + ArgStringList LlvmLinkArgs; + + assert(!Inputs.empty() && "Must have at least one input."); + + LlvmLinkArgs.append({"-o", Output.getFilename()}); + for (auto Input : Inputs) + LlvmLinkArgs.push_back(Input.getFilename()); + + // Look for archive of bundled bitcode in arguments, and add temporary files + // for the extracted archive of bitcode to inputs. + auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ); + AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LlvmLinkArgs, "amdgcn", + TargetID, /*IsBitCodeSDL=*/true); + + const char *LlvmLink = + Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + LlvmLink, LlvmLinkArgs, Inputs, + Output)); +} + +void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args) const { + // Construct lld command. + // The output from ld.lld is an HSA code object file. + ArgStringList LldArgs{"-flavor", + "gnu", + "-m", + "elf64_amdgpu", + "--no-undefined", + "-shared", + "-plugin-opt=-amdgpu-internalize-symbols"}; + if (Args.hasArg(options::OPT_hipstdpar)) + LldArgs.push_back("-plugin-opt=-amdgpu-enable-hipstdpar"); + + auto &TC = getToolChain(); + auto &D = TC.getDriver(); + assert(!Inputs.empty() && "Must have at least one input."); + bool IsThinLTO = D.getLTOMode(/*IsOffload=*/true) == LTOK_Thin; + addLTOOptions(TC, Args, LldArgs, Output, Inputs[0], IsThinLTO); + + // Extract all the -m options + std::vector<llvm::StringRef> Features; + amdgpu::getAMDGPUTargetFeatures(D, TC.getTriple(), Args, Features); + + // Add features to mattr such as cumode + std::string MAttrString = "-plugin-opt=-mattr="; + for (auto OneFeature : unifyTargetFeatures(Features)) { + MAttrString.append(Args.MakeArgString(OneFeature)); + if (OneFeature != Features.back()) + MAttrString.append(","); + } + if (!Features.empty()) + LldArgs.push_back(Args.MakeArgString(MAttrString)); + + // ToDo: Remove this option after AMDGPU backend supports ISA-level linking. + // Since AMDGPU backend currently does not support ISA-level linking, all + // called functions need to be imported. + if (IsThinLTO) + LldArgs.push_back(Args.MakeArgString("-plugin-opt=-force-import-all")); + + if (C.getDriver().isSaveTempsEnabled()) + LldArgs.push_back("-save-temps"); + + addLinkerCompressDebugSectionsOption(TC, Args, LldArgs); + + // Given that host and device linking happen in separate processes, the device + // linker doesn't always have the visibility as to which device symbols are + // needed by a program, especially for the device symbol dependencies that are + // introduced through the host symbol resolution. + // For example: host_A() (A.obj) --> host_B(B.obj) --> device_kernel_B() + // (B.obj) In this case, the device linker doesn't know that A.obj actually + // depends on the kernel functions in B.obj. When linking to static device + // library, the device linker may drop some of the device global symbols if + // they aren't referenced. As a workaround, we are adding to the + // --whole-archive flag such that all global symbols would be linked in. + LldArgs.push_back("--whole-archive"); + + for (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) { + StringRef ArgVal = Arg->getValue(1); + auto SplitArg = ArgVal.split("-mllvm="); + if (!SplitArg.second.empty()) { + LldArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=") + SplitArg.second)); + } else { + LldArgs.push_back(Args.MakeArgString(ArgVal)); + } + Arg->claim(); + } + + LldArgs.append({"-o", Output.getFilename()}); + for (auto Input : Inputs) + LldArgs.push_back(Input.getFilename()); + + // Look for archive of bundled bitcode in arguments, and add temporary files + // for the extracted archive of bitcode to inputs. + auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ); + AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LldArgs, "amdgcn", + TargetID, /*IsBitCodeSDL=*/true); + + LldArgs.push_back("--no-whole-archive"); + + const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Lld, LldArgs, Inputs, Output)); +} + +// For amdgcn the inputs of the linker job are device bitcode and output is +// 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, + const ArgList &Args, + const char *LinkingOutput) const { + if (Inputs.size() > 0 && + Inputs[0].getType() == types::TY_Image && + JA.getType() == types::TY_Object) + return HIP::constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, + Args, JA, *this); + + if (JA.getType() == types::TY_HIP_FATBIN) + 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); +} + +HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const ArgList &Args) + : ROCMToolChain(D, Triple, Args), HostTC(HostTC) { + // Lookup binaries into the driver directory, this is used to + // discover the clang-offload-bundler executable. + getProgramPaths().push_back(getDriver().Dir); + + // 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) + D.getDiags().Report(clang::diag::warn_drv_unsupported_option_for_target) + << A->getAsString(Args) << getTriple().str(); + } +} + +void HIPAMDToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); + + assert(DeviceOffloadingKind == Action::OFK_HIP && + "Only HIP offloading kinds are supported for GPUs."); + + CC1Args.push_back("-fcuda-is-device"); + + if (!DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + false)) + CC1Args.append({"-mllvm", "-amdgpu-internalize-symbols"}); + if (DriverArgs.hasArgNoClaim(options::OPT_hipstdpar)) + CC1Args.append({"-mllvm", "-amdgpu-enable-hipstdpar"}); + + StringRef MaxThreadsPerBlock = + DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ); + if (!MaxThreadsPerBlock.empty()) { + std::string ArgStr = + (Twine("--gpu-max-threads-per-block=") + MaxThreadsPerBlock).str(); + CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr)); + } + + CC1Args.push_back("-fcuda-allow-variadic-functions"); + + // Default to "hidden" visibility, as object level linking will not be + // supported for the foreseeable future. + if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, + options::OPT_fvisibility_ms_compat)) { + CC1Args.append({"-fvisibility=hidden"}); + CC1Args.push_back("-fapply-global-visibility-to-externs"); + } + + for (auto BCFile : getDeviceLibs(DriverArgs)) { + CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" + : "-mlink-bitcode-file"); + CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path)); + } +} + +llvm::opt::DerivedArgList * +HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + DerivedArgList *DAL = + HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); + if (!DAL) + DAL = new DerivedArgList(Args.getBaseArgs()); + + const OptTable &Opts = getDriver().getOpts(); + + for (Arg *A : Args) { + if (!shouldSkipSanitizeOption(*this, Args, BoundArch, A)) + DAL->append(A); + } + + if (!BoundArch.empty()) { + DAL->eraseArg(options::OPT_mcpu_EQ); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), BoundArch); + checkTargetID(*DAL); + } + + return DAL; +} + +Tool *HIPAMDToolChain::buildLinker() const { + assert(getTriple().getArch() == llvm::Triple::amdgcn); + return new tools::AMDGCN::Linker(*this); +} + +void HIPAMDToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { + HostTC.addClangWarningOptions(CC1Args); +} + +ToolChain::CXXStdlibType +HIPAMDToolChain::GetCXXStdlibType(const ArgList &Args) const { + return HostTC.GetCXXStdlibType(Args); +} + +void HIPAMDToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} + +void HIPAMDToolChain::AddClangCXXStdlibIncludeArgs( + const ArgList &Args, ArgStringList &CC1Args) const { + HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); +} + +void HIPAMDToolChain::AddIAMCUIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { + HostTC.AddIAMCUIncludeArgs(Args, CC1Args); +} + +void HIPAMDToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); +} + +SanitizerMask HIPAMDToolChain::getSupportedSanitizers() const { + // The HIPAMDToolChain only supports sanitizers in the sense that it allows + // sanitizer arguments on the command line if they are supported by the host + // toolchain. The HIPAMDToolChain will actually ignore any command line + // arguments for any of these "supported" sanitizers. That means that no + // sanitization of device code is actually supported at this time. + // + // This behavior is necessary because the host and device toolchains + // invocations often share the command line, so the device toolchain must + // tolerate flags meant only for the host toolchain. + return HostTC.getSupportedSanitizers(); +} + +VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D, + const ArgList &Args) const { + return HostTC.computeMSVCVersion(D, Args); +} + +llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> +HIPAMDToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { + llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs; + if (DriverArgs.hasArg(options::OPT_nogpulib)) + return {}; + ArgStringList LibraryPaths; + + // Find in --hip-device-lib-path and HIP_LIBRARY_PATH. + for (StringRef Path : RocmInstallation->getRocmDeviceLibPathArg()) + LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); + + addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH"); + + // Maintain compatability with --hip-device-lib. + auto BCLibArgs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ); + if (!BCLibArgs.empty()) { + llvm::for_each(BCLibArgs, [&](StringRef BCName) { + StringRef FullName; + for (StringRef LibraryPath : LibraryPaths) { + SmallString<128> Path(LibraryPath); + llvm::sys::path::append(Path, BCName); + FullName = Path; + if (llvm::sys::fs::exists(FullName)) { + BCLibs.push_back(FullName); + return; + } + } + getDriver().Diag(diag::err_drv_no_such_file) << BCName; + }); + } else { + if (!RocmInstallation->hasDeviceLibrary()) { + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; + return {}; + } + StringRef GpuArch = getGPUArch(DriverArgs); + assert(!GpuArch.empty() && "Must have an explicit GPU arch."); + + // If --hip-device-lib is not set, add the default bitcode libraries. + if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize, + options::OPT_fno_gpu_sanitize, true) && + getSanitizerArgs(DriverArgs).needsAsanRt()) { + auto AsanRTL = RocmInstallation->getAsanRTLPath(); + if (AsanRTL.empty()) { + unsigned DiagID = getDriver().getDiags().getCustomDiagID( + DiagnosticsEngine::Error, + "AMDGPU address sanitizer runtime library (asanrtl) is not found. " + "Please install ROCm device library which supports address " + "sanitizer"); + getDriver().Diag(DiagID); + return {}; + } else + BCLibs.emplace_back(AsanRTL, /*ShouldInternalize=*/false); + } + + // Add the HIP specific bitcode library. + BCLibs.push_back(RocmInstallation->getHIPPath()); + + // Add common device libraries like ocml etc. + for (StringRef N : getCommonDeviceLibNames(DriverArgs, GpuArch.str())) + BCLibs.emplace_back(N); + + // Add instrument lib. + auto InstLib = + DriverArgs.getLastArgValue(options::OPT_gpu_instrument_lib_EQ); + if (InstLib.empty()) + return BCLibs; + if (llvm::sys::fs::exists(InstLib)) + BCLibs.push_back(InstLib); + else + getDriver().Diag(diag::err_drv_no_such_file) << InstLib; + } + + return BCLibs; +} + +void HIPAMDToolChain::checkTargetID( + const llvm::opt::ArgList &DriverArgs) const { + auto PTID = getParsedTargetID(DriverArgs); + if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) { + getDriver().Diag(clang::diag::err_drv_bad_target_id) + << *PTID.OptionalTargetID; + } +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIP.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h index 3cced0a320dc..d81a9733014c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIP.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.h @@ -1,4 +1,4 @@ -//===--- HIP.h - HIP ToolChain Implementations ------------------*- C++ -*-===// +//===--- HIPAMD.h - HIP 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. @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPAMD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPAMD_H -#include "clang/Driver/ToolChain.h" -#include "clang/Driver/Tool.h" #include "AMDGPU.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" namespace clang { namespace driver { @@ -19,14 +19,9 @@ namespace driver { namespace tools { namespace AMDGCN { - // Construct command for creating HIP fatbin. - void constructHIPFatbinCommand(Compilation &C, const JobAction &JA, - StringRef OutputFileName, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, const Tool& T); - // Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with // device library, then compiles it to ISA in a shared object. -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("AMDGCN::Linker", "amdgcn-link", TC) {} @@ -38,17 +33,13 @@ public: const char *LinkingOutput) const override; private: - void constructLldCommand(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const InputInfo &Output, const llvm::opt::ArgList &Args) const; - - // Construct command for creating Object from HIP fatbin. - void constructGenerateObjFileFromHIPFatBinary(Compilation &C, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - const JobAction &JA) const; + void constructLlvmLinkCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args) const; }; } // end namespace AMDGCN @@ -56,10 +47,10 @@ private: namespace toolchains { -class LLVM_LIBRARY_VISIBILITY HIPToolChain final : public ROCMToolChain { +class LLVM_LIBRARY_VISIBILITY HIPAMDToolChain final : public ROCMToolChain { public: - HIPToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const llvm::opt::ArgList &Args); + HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const llvm::opt::ArgList &Args); const llvm::Triple *getAuxTriple() const override { return &HostTC.getTriple(); @@ -68,9 +59,10 @@ public: llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void @@ -83,8 +75,8 @@ public: llvm::opt::ArgStringList &CC1Args) const override; void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - llvm::SmallVector<std::string, 12> - getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override; + llvm::SmallVector<BitCodeLibraryInfo, 12> + getDeviceLibs(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; @@ -92,7 +84,7 @@ public: computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override; - unsigned GetDefaultDwarfVersion() const override { return 4; } + unsigned GetDefaultDwarfVersion() const override { return 5; } const ToolChain &HostTC; void checkTargetID(const llvm::opt::ArgList &DriverArgs) const override; @@ -105,4 +97,4 @@ protected: } // end namespace driver } // end namespace clang -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPAMD_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp new file mode 100644 index 000000000000..a144b28057f4 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp @@ -0,0 +1,288 @@ +//===--- HIPSPV.cpp - HIPSPV ToolChain Implementation -----------*- 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 "HIPSPV.h" +#include "CommonArgs.h" +#include "HIPUtility.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/InputInfo.h" +#include "clang/Driver/Options.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +// Convenience function for creating temporary file for both modes of +// isSaveTempsEnabled(). +static const char *getTempFile(Compilation &C, StringRef Prefix, + StringRef Extension) { + if (C.getDriver().isSaveTempsEnabled()) { + return C.getArgs().MakeArgString(Prefix + "." + Extension); + } + auto TmpFile = C.getDriver().GetTemporaryPath(Prefix, Extension); + return C.addTempFile(C.getArgs().MakeArgString(TmpFile)); +} + +// Locates HIP pass plugin. +static std::string findPassPlugin(const Driver &D, + const llvm::opt::ArgList &Args) { + StringRef Path = Args.getLastArgValue(options::OPT_hipspv_pass_plugin_EQ); + if (!Path.empty()) { + if (llvm::sys::fs::exists(Path)) + return Path.str(); + D.Diag(diag::err_drv_no_such_file) << Path; + } + + StringRef hipPath = Args.getLastArgValue(options::OPT_hip_path_EQ); + if (!hipPath.empty()) { + SmallString<128> PluginPath(hipPath); + llvm::sys::path::append(PluginPath, "lib", "libLLVMHipSpvPasses.so"); + if (llvm::sys::fs::exists(PluginPath)) + return PluginPath.str().str(); + PluginPath.assign(hipPath); + llvm::sys::path::append(PluginPath, "lib", "llvm", + "libLLVMHipSpvPasses.so"); + if (llvm::sys::fs::exists(PluginPath)) + return PluginPath.str().str(); + } + + return std::string(); +} + +void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( + Compilation &C, const JobAction &JA, const InputInfoList &Inputs, + const InputInfo &Output, const llvm::opt::ArgList &Args) const { + + assert(!Inputs.empty() && "Must have at least one input."); + std::string Name = std::string(llvm::sys::path::stem(Output.getFilename())); + const char *TempFile = getTempFile(C, Name + "-link", "bc"); + + // Link LLVM bitcode. + ArgStringList LinkArgs{}; + for (auto Input : Inputs) + LinkArgs.push_back(Input.getFilename()); + LinkArgs.append({"-o", TempFile}); + const char *LlvmLink = + Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + LlvmLink, LinkArgs, Inputs, Output)); + + // Post-link HIP lowering. + + // Run LLVM IR passes to lower/expand/emulate HIP code that does not translate + // to SPIR-V (E.g. dynamic shared memory). + auto PassPluginPath = findPassPlugin(C.getDriver(), Args); + if (!PassPluginPath.empty()) { + const char *PassPathCStr = C.getArgs().MakeArgString(PassPluginPath); + const char *OptOutput = getTempFile(C, Name + "-lower", "bc"); + ArgStringList OptArgs{TempFile, "-load-pass-plugin", + PassPathCStr, "-passes=hip-post-link-passes", + "-o", OptOutput}; + const char *Opt = Args.MakeArgString(getToolChain().GetProgramPath("opt")); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::None(), Opt, OptArgs, Inputs, Output)); + TempFile = OptOutput; + } + + // Emit SPIR-V binary. + + llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.1", + "--spirv-ext=+all"}; + InputInfo TrInput = InputInfo(types::TY_LLVM_BC, TempFile, ""); + SPIRV::constructTranslateCommand(C, *this, JA, Output, TrInput, TrArgs); +} + +void HIPSPV::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + if (Inputs.size() > 0 && Inputs[0].getType() == types::TY_Image && + JA.getType() == types::TY_Object) + return HIP::constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, + Args, JA, *this); + + if (JA.getType() == types::TY_HIP_FATBIN) + return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, + Args, *this); + + constructLinkAndEmitSpirvCommand(C, JA, Inputs, Output, Args); +} + +HIPSPVToolChain::HIPSPVToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const ArgList &Args) + : ToolChain(D, Triple, Args), HostTC(HostTC) { + // Lookup binaries into the driver directory, this is used to + // discover the clang-offload-bundler executable. + getProgramPaths().push_back(getDriver().Dir); +} + +void HIPSPVToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); + + assert(DeviceOffloadingKind == Action::OFK_HIP && + "Only HIP offloading kinds are supported for GPUs."); + + CC1Args.append( + {"-fcuda-is-device", "-fcuda-allow-variadic-functions", + // A crude workaround for llvm-spirv which does not handle the + // autovectorized code well (vector reductions, non-i{8,16,32,64} types). + // TODO: Allow autovectorization when SPIR-V backend arrives. + "-mllvm", "-vectorize-loops=false", "-mllvm", "-vectorize-slp=false"}); + + // Default to "hidden" visibility, as object level linking will not be + // supported for the foreseeable future. + if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, + options::OPT_fvisibility_ms_compat)) + CC1Args.append( + {"-fvisibility=hidden", "-fapply-global-visibility-to-externs"}); + + llvm::for_each(getDeviceLibs(DriverArgs), + [&](const BitCodeLibraryInfo &BCFile) { + CC1Args.append({"-mlink-builtin-bitcode", + DriverArgs.MakeArgString(BCFile.Path)}); + }); +} + +Tool *HIPSPVToolChain::buildLinker() const { + assert(getTriple().getArch() == llvm::Triple::spirv64); + return new tools::HIPSPV::Linker(*this); +} + +void HIPSPVToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { + HostTC.addClangWarningOptions(CC1Args); +} + +ToolChain::CXXStdlibType +HIPSPVToolChain::GetCXXStdlibType(const ArgList &Args) const { + return HostTC.GetCXXStdlibType(Args); +} + +void HIPSPVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} + +void HIPSPVToolChain::AddClangCXXStdlibIncludeArgs( + const ArgList &Args, ArgStringList &CC1Args) const { + HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); +} + +void HIPSPVToolChain::AddIAMCUIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { + HostTC.AddIAMCUIncludeArgs(Args, CC1Args); +} + +void HIPSPVToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nogpuinc)) + return; + + StringRef hipPath = DriverArgs.getLastArgValue(options::OPT_hip_path_EQ); + if (hipPath.empty()) { + getDriver().Diag(diag::err_drv_hipspv_no_hip_path) << 1 << "'-nogpuinc'"; + return; + } + SmallString<128> P(hipPath); + llvm::sys::path::append(P, "include"); + CC1Args.append({"-isystem", DriverArgs.MakeArgString(P)}); +} + +llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> +HIPSPVToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { + llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> BCLibs; + if (DriverArgs.hasArg(options::OPT_nogpulib)) + return {}; + + ArgStringList LibraryPaths; + // Find device libraries in --hip-device-lib-path and HIP_DEVICE_LIB_PATH. + auto HipDeviceLibPathArgs = DriverArgs.getAllArgValues( + // --hip-device-lib-path is alias to this option. + clang::driver::options::OPT_rocm_device_lib_path_EQ); + for (auto Path : HipDeviceLibPathArgs) + LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); + + StringRef HipPath = DriverArgs.getLastArgValue(options::OPT_hip_path_EQ); + if (!HipPath.empty()) { + SmallString<128> Path(HipPath); + llvm::sys::path::append(Path, "lib", "hip-device-lib"); + LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); + } + + addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH"); + + // Maintain compatability with --hip-device-lib. + auto BCLibArgs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ); + if (!BCLibArgs.empty()) { + llvm::for_each(BCLibArgs, [&](StringRef BCName) { + StringRef FullName; + for (std::string LibraryPath : LibraryPaths) { + SmallString<128> Path(LibraryPath); + llvm::sys::path::append(Path, BCName); + FullName = Path; + if (llvm::sys::fs::exists(FullName)) { + BCLibs.emplace_back(FullName.str()); + return; + } + } + getDriver().Diag(diag::err_drv_no_such_file) << BCName; + }); + } else { + // Search device library named as 'hipspv-<triple>.bc'. + auto TT = getTriple().normalize(); + std::string BCName = "hipspv-" + TT + ".bc"; + for (auto *LibPath : LibraryPaths) { + SmallString<128> Path(LibPath); + llvm::sys::path::append(Path, BCName); + if (llvm::sys::fs::exists(Path)) { + BCLibs.emplace_back(Path.str().str()); + return BCLibs; + } + } + getDriver().Diag(diag::err_drv_no_hipspv_device_lib) + << 1 << ("'" + TT + "' target"); + return {}; + } + + return BCLibs; +} + +SanitizerMask HIPSPVToolChain::getSupportedSanitizers() const { + // The HIPSPVToolChain only supports sanitizers in the sense that it allows + // sanitizer arguments on the command line if they are supported by the host + // toolchain. The HIPSPVToolChain will actually ignore any command line + // arguments for any of these "supported" sanitizers. That means that no + // sanitization of device code is actually supported at this time. + // + // This behavior is necessary because the host and device toolchains + // invocations often share the command line, so the device toolchain must + // tolerate flags meant only for the host toolchain. + return HostTC.getSupportedSanitizers(); +} + +VersionTuple HIPSPVToolChain::computeMSVCVersion(const Driver *D, + const ArgList &Args) const { + return HostTC.computeMSVCVersion(D, Args); +} + +void HIPSPVToolChain::adjustDebugInfoKind( + llvm::codegenoptions::DebugInfoKind &DebugInfoKind, + const llvm::opt::ArgList &Args) const { + // Debug info generation is disabled for SPIRV-LLVM-Translator + // which currently aborts on the presence of DW_OP_LLVM_convert. + // TODO: Enable debug info when the SPIR-V backend arrives. + DebugInfoKind = llvm::codegenoptions::NoDebugInfo; +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h new file mode 100644 index 000000000000..ecd82e7052e4 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.h @@ -0,0 +1,102 @@ +//===--- HIPSPV.h - HIP 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_HIPSPV_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPSPV_H + +#include "SPIRV.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace HIPSPV { + +// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with +// device library, then compiles it to SPIR-V in a shared object. +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("HIPSPV::Linker", "hipspv-link", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; + +private: + void constructLinkAndEmitSpirvCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args) const; +}; + +} // namespace HIPSPV +} // namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY HIPSPVToolChain final : public ToolChain { +public: + HIPSPVToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const llvm::opt::ArgList &Args); + + const llvm::Triple *getAuxTriple() const override { + return &HostTC.getTriple(); + } + + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1Args) const override; + void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + llvm::SmallVector<BitCodeLibraryInfo, 12> + getDeviceLibs(const llvm::opt::ArgList &Args) const override; + + SanitizerMask getSupportedSanitizers() const override; + + VersionTuple + computeMSVCVersion(const Driver *D, + const llvm::opt::ArgList &Args) const override; + + void adjustDebugInfoKind(llvm::codegenoptions::DebugInfoKind &DebugInfoKind, + const llvm::opt::ArgList &Args) const override; + bool IsMathErrnoDefault() const override { return false; } + bool useIntegratedAs() const override { return true; } + bool isCrossCompiling() const override { return true; } + bool isPICDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } + bool isPICDefaultForced() const override { return false; } + bool SupportsProfiling() const override { return false; } + + const ToolChain &HostTC; + +protected: + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPSPV_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp new file mode 100644 index 000000000000..f692458b775d --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.cpp @@ -0,0 +1,179 @@ +//===--- HIPUtility.cpp - Common HIP Tool Chain Utilities -------*- 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 "HIPUtility.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Path.h" +#include "llvm/TargetParser/Triple.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace llvm::opt; + +#if defined(_WIN32) || defined(_WIN64) +#define NULL_FILE "nul" +#else +#define NULL_FILE "/dev/null" +#endif + +namespace { +const unsigned HIPCodeObjectAlign = 4096; +} // namespace + +// Constructs a triple string for clang offload bundler. +static std::string normalizeForBundler(const llvm::Triple &T, + bool HasTargetID) { + return HasTargetID ? (T.getArchName() + "-" + T.getVendorName() + "-" + + T.getOSName() + "-" + T.getEnvironmentName()) + .str() + : T.normalize(); +} + +// Construct a clang-offload-bundler command to bundle code objects for +// different devices into a HIP fat binary. +void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, + llvm::StringRef OutputFileName, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + const Tool &T) { + // Construct clang-offload-bundler command to bundle object files for + // for different GPU archs. + ArgStringList BundlerArgs; + BundlerArgs.push_back(Args.MakeArgString("-type=o")); + BundlerArgs.push_back( + Args.MakeArgString("-bundle-align=" + Twine(HIPCodeObjectAlign))); + + // ToDo: Remove the dummy host binary entry which is required by + // clang-offload-bundler. + std::string BundlerTargetArg = "-targets=host-x86_64-unknown-linux"; + // 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 + // offload kind in bundle ID is 'hipv4'. + std::string OffloadKind = "hip"; + auto &TT = T.getToolChain().getTriple(); + if (TT.isAMDGCN() && getAMDGPUCodeObjectVersion(C.getDriver(), Args) >= 4) + OffloadKind = OffloadKind + "v4"; + for (const auto &II : Inputs) { + const auto *A = II.getAction(); + auto ArchStr = llvm::StringRef(A->getOffloadingArch()); + BundlerTargetArg += + "," + OffloadKind + "-" + normalizeForBundler(TT, !ArchStr.empty()); + if (!ArchStr.empty()) + BundlerTargetArg += "-" + ArchStr.str(); + } + 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("-output=").append(Output)); + BundlerArgs.push_back(BundlerOutputArg); + + if (Args.hasFlag(options::OPT_offload_compress, + options::OPT_no_offload_compress, false)) + BundlerArgs.push_back("-compress"); + if (Args.hasArg(options::OPT_v)) + BundlerArgs.push_back("-verbose"); + + const char *Bundler = Args.MakeArgString( + T.getToolChain().GetProgramPath("clang-offload-bundler")); + C.addCommand(std::make_unique<Command>( + JA, T, ResponseFileSupport::None(), Bundler, BundlerArgs, Inputs, + InputInfo(&JA, Args.MakeArgString(Output)))); +} + +/// Add Generated HIP Object File which has device images embedded into the +/// host to the argument list for linking. Using MC directives, embed the +/// device code and also define symbols required by the code generation so that +/// the image can be retrieved at runtime. +void HIP::constructGenerateObjFileFromHIPFatBinary( + Compilation &C, const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, const JobAction &JA, const Tool &T) { + const ToolChain &TC = T.getToolChain(); + std::string Name = std::string(llvm::sys::path::stem(Output.getFilename())); + + // Create Temp Object File Generator, + // Offload Bundled file and Bundled Object file. + // Keep them if save-temps is enabled. + const char *McinFile; + const char *BundleFile; + if (C.getDriver().isSaveTempsEnabled()) { + McinFile = C.getArgs().MakeArgString(Name + ".mcin"); + BundleFile = C.getArgs().MakeArgString(Name + ".hipfb"); + } else { + auto TmpNameMcin = C.getDriver().GetTemporaryPath(Name, "mcin"); + McinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin)); + auto TmpNameFb = C.getDriver().GetTemporaryPath(Name, "hipfb"); + BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameFb)); + } + HIP::constructHIPFatbinCommand(C, JA, BundleFile, Inputs, Args, T); + + // Create a buffer to write the contents of the temp obj generator. + std::string ObjBuffer; + llvm::raw_string_ostream ObjStream(ObjBuffer); + + auto HostTriple = + C.getSingleOffloadToolChain<Action::OFK_Host>()->getTriple(); + + // Add MC directives to embed target binaries. We ensure that each + // section and image is 16-byte aligned. This is not mandatory, but + // increases the likelihood of data to be aligned with a cache block + // in several main host machines. + ObjStream << "# HIP Object Generator\n"; + ObjStream << "# *** Automatically generated by Clang ***\n"; + if (HostTriple.isWindowsMSVCEnvironment()) { + ObjStream << " .section .hip_fatbin, \"dw\"\n"; + } else { + ObjStream << " .protected __hip_fatbin\n"; + ObjStream << " .type __hip_fatbin,@object\n"; + ObjStream << " .section .hip_fatbin,\"a\",@progbits\n"; + } + ObjStream << " .globl __hip_fatbin\n"; + ObjStream << " .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign)) + << "\n"; + ObjStream << "__hip_fatbin:\n"; + ObjStream << " .incbin "; + llvm::sys::printArg(ObjStream, BundleFile, /*Quote=*/true); + ObjStream << "\n"; + if (HostTriple.isOSLinux() && HostTriple.isOSBinFormatELF()) + ObjStream << " .section .note.GNU-stack, \"\", @progbits\n"; + ObjStream.flush(); + + // Dump the contents of the temp object file gen if the user requested that. + // We support this option to enable testing of behavior with -###. + if (C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script)) + llvm::errs() << ObjBuffer; + + // Open script file and write the contents. + std::error_code EC; + llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None); + + if (EC) { + C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return; + } + + Objf << ObjBuffer; + + ArgStringList McArgs{"-triple", Args.MakeArgString(HostTriple.normalize()), + "-o", Output.getFilename(), + McinFile, "--filetype=obj"}; + const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc")); + C.addCommand(std::make_unique<Command>(JA, T, ResponseFileSupport::None(), Mc, + McArgs, Inputs, Output)); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.h new file mode 100644 index 000000000000..29e5a922024a --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPUtility.h @@ -0,0 +1,35 @@ +//===--- HIPUtility.h - Common HIP Tool Chain Utilities ---------*- 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_HIPUTILITY_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPUTILITY_H + +#include "clang/Driver/Tool.h" + +namespace clang { +namespace driver { +namespace tools { +namespace HIP { + +// Construct command for creating HIP fatbin. +void constructHIPFatbinCommand(Compilation &C, const JobAction &JA, + StringRef OutputFileName, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, const Tool &T); + +// Construct command for creating Object from HIP fatbin. +void constructGenerateObjFileFromHIPFatBinary( + Compilation &C, const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, const JobAction &JA, const Tool &T); + +} // namespace HIP +} // namespace tools +} // namespace driver +} // namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPUTILITY_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp new file mode 100644 index 000000000000..c6ad862b2294 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.cpp @@ -0,0 +1,259 @@ +//===--- HLSL.cpp - HLSL ToolChain Implementations --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "HLSL.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Job.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TargetParser/Triple.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; +using namespace llvm; + +namespace { + +const unsigned OfflineLibMinor = 0xF; + +bool isLegalShaderModel(Triple &T) { + if (T.getOS() != Triple::OSType::ShaderModel) + return false; + + auto Version = T.getOSVersion(); + if (Version.getBuild()) + return false; + if (Version.getSubminor()) + return false; + + auto Kind = T.getEnvironment(); + + switch (Kind) { + default: + return false; + case Triple::EnvironmentType::Vertex: + case Triple::EnvironmentType::Hull: + case Triple::EnvironmentType::Domain: + case Triple::EnvironmentType::Geometry: + case Triple::EnvironmentType::Pixel: + case Triple::EnvironmentType::Compute: { + VersionTuple MinVer(4, 0); + return MinVer <= Version; + } break; + case Triple::EnvironmentType::Library: { + VersionTuple SM6x(6, OfflineLibMinor); + if (Version == SM6x) + return true; + + VersionTuple MinVer(6, 3); + return MinVer <= Version; + } break; + case Triple::EnvironmentType::Amplification: + case Triple::EnvironmentType::Mesh: { + VersionTuple MinVer(6, 5); + return MinVer <= Version; + } break; + } + return false; +} + +std::optional<std::string> tryParseProfile(StringRef Profile) { + // [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor] + SmallVector<StringRef, 3> Parts; + Profile.split(Parts, "_"); + if (Parts.size() != 3) + return std::nullopt; + + Triple::EnvironmentType Kind = + StringSwitch<Triple::EnvironmentType>(Parts[0]) + .Case("ps", Triple::EnvironmentType::Pixel) + .Case("vs", Triple::EnvironmentType::Vertex) + .Case("gs", Triple::EnvironmentType::Geometry) + .Case("hs", Triple::EnvironmentType::Hull) + .Case("ds", Triple::EnvironmentType::Domain) + .Case("cs", Triple::EnvironmentType::Compute) + .Case("lib", Triple::EnvironmentType::Library) + .Case("ms", Triple::EnvironmentType::Mesh) + .Case("as", Triple::EnvironmentType::Amplification) + .Default(Triple::EnvironmentType::UnknownEnvironment); + if (Kind == Triple::EnvironmentType::UnknownEnvironment) + return std::nullopt; + + unsigned long long Major = 0; + if (llvm::getAsUnsignedInteger(Parts[1], 0, Major)) + return std::nullopt; + + unsigned long long Minor = 0; + if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library) + Minor = OfflineLibMinor; + else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor)) + return std::nullopt; + + // dxil-unknown-shadermodel-hull + llvm::Triple T; + T.setArch(Triple::ArchType::dxil); + T.setOSName(Triple::getOSTypeName(Triple::OSType::ShaderModel).str() + + VersionTuple(Major, Minor).getAsString()); + T.setEnvironment(Kind); + if (isLegalShaderModel(T)) + return T.getTriple(); + else + return std::nullopt; +} + +bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) { + VersionTuple Version; + if (Version.tryParse(ValVersionStr) || Version.getBuild() || + Version.getSubminor() || !Version.getMinor()) { + D.Diag(diag::err_drv_invalid_format_dxil_validator_version) + << ValVersionStr; + return false; + } + + uint64_t Major = Version.getMajor(); + uint64_t Minor = *Version.getMinor(); + if (Major == 0 && Minor != 0) { + D.Diag(diag::err_drv_invalid_empty_dxil_validator_version) << ValVersionStr; + return false; + } + VersionTuple MinVer(1, 0); + if (Version < MinVer) { + D.Diag(diag::err_drv_invalid_range_dxil_validator_version) << ValVersionStr; + return false; + } + return true; +} + +} // namespace + +void tools::hlsl::Validator::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + std::string DxvPath = getToolChain().GetProgramPath("dxv"); + assert(DxvPath != "dxv" && "cannot find dxv"); + + ArgStringList CmdArgs; + assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Unexpected verify input"); + // Grabbing the output of the earlier cc1 run. + CmdArgs.push_back(Input.getFilename()); + // Use the same name as output. + CmdArgs.push_back("-o"); + CmdArgs.push_back(Input.getFilename()); + + const char *Exec = Args.MakeArgString(DxvPath); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs, Input)); +} + +/// DirectX Toolchain +HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { + if (Args.hasArg(options::OPT_dxc_validator_path_EQ)) + getProgramPaths().push_back( + Args.getLastArgValue(options::OPT_dxc_validator_path_EQ).str()); +} + +Tool *clang::driver::toolchains::HLSLToolChain::getTool( + Action::ActionClass AC) const { + switch (AC) { + case Action::BinaryAnalyzeJobClass: + if (!Validator) + Validator.reset(new tools::hlsl::Validator(*this)); + return Validator.get(); + default: + return ToolChain::getTool(AC); + } +} + +std::optional<std::string> +clang::driver::toolchains::HLSLToolChain::parseTargetProfile( + StringRef TargetProfile) { + return tryParseProfile(TargetProfile); +} + +DerivedArgList * +HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + + const OptTable &Opts = getDriver().getOpts(); + + for (Arg *A : Args) { + if (A->getOption().getID() == options::OPT_dxil_validator_version) { + StringRef ValVerStr = A->getValue(); + std::string ErrorMsg; + if (!isLegalValidatorVersion(ValVerStr, getDriver())) + continue; + } + if (A->getOption().getID() == options::OPT_dxc_entrypoint) { + DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint), + A->getValue()); + A->claim(); + continue; + } + if (A->getOption().getID() == options::OPT__SLASH_O) { + StringRef OStr = A->getValue(); + if (OStr == "d") { + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0)); + A->claim(); + continue; + } else { + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr); + A->claim(); + continue; + } + } + if (A->getOption().getID() == options::OPT_emit_pristine_llvm) { + // Translate fcgl into -S -emit-llvm and -disable-llvm-passes. + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S)); + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_llvm)); + DAL->AddFlagArg(nullptr, + Opts.getOption(options::OPT_disable_llvm_passes)); + A->claim(); + continue; + } + DAL->append(A); + } + + // Add default validator version if not set. + // TODO: remove this once read validator version from validator. + if (!DAL->hasArg(options::OPT_dxil_validator_version)) { + const StringRef DefaultValidatorVer = "1.7"; + DAL->AddSeparateArg(nullptr, + Opts.getOption(options::OPT_dxil_validator_version), + DefaultValidatorVer); + } + if (!DAL->hasArg(options::OPT_O_Group)) { + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3"); + } + // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and + // shader model 6.2. + // See: https://github.com/llvm/llvm-project/issues/57876 + return DAL; +} + +bool HLSLToolChain::requiresValidation(DerivedArgList &Args) const { + if (Args.getLastArg(options::OPT_dxc_disable_validation)) + return false; + + std::string DxvPath = GetProgramPath("dxv"); + if (DxvPath != "dxv") + return true; + + getDriver().Diag(diag::warn_drv_dxc_missing_dxv); + return false; +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h new file mode 100644 index 000000000000..7b775b897431 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/HLSL.h @@ -0,0 +1,63 @@ +//===--- HLSL.h - HLSL ToolChain Implementations ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { + +namespace tools { + +namespace hlsl { +class LLVM_LIBRARY_VISIBILITY Validator : public Tool { +public: + Validator(const ToolChain &TC) : Tool("hlsl::Validator", "dxv", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // namespace hlsl +} // namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY HLSLToolChain : public ToolChain { +public: + HLSLToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + Tool *getTool(Action::ActionClass AC) const override; + + bool isPICDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } + bool isPICDefaultForced() const override { return false; } + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + static std::optional<std::string> parseTargetProfile(StringRef TargetProfile); + bool requiresValidation(llvm::opt::DerivedArgList &Args) const; + +private: + mutable std::unique_ptr<tools::hlsl::Validator> Validator; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HLSL_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp index a79f0f7622ad..e0d94035823f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.cpp @@ -8,27 +8,272 @@ #include "Haiku.h" #include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "llvm/Support/Path.h" using namespace clang::driver; +using namespace clang::driver::tools; using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; +void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const auto &ToolChain = static_cast<const Haiku &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool Static = Args.hasArg(options::OPT_static); + const bool Shared = Args.hasArg(options::OPT_shared); + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + // Silence warning for "clang -pie foo.o -o foo" + Args.ClaimAllArgs(options::OPT_pie); + + // -rdynamic is a no-op with Haiku. Claim argument to avoid warning. + Args.ClaimAllArgs(options::OPT_rdynamic); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + CmdArgs.push_back("--eh-frame-hdr"); + if (Static) { + CmdArgs.push_back("-Bstatic"); + } else { + if (Shared) + CmdArgs.push_back("-shared"); + CmdArgs.push_back("--enable-new-dtags"); + } + + CmdArgs.push_back("-shared"); + + if (!Shared) + CmdArgs.push_back("--no-undefined"); + + if (Arch == llvm::Triple::riscv64) + CmdArgs.push_back("-X"); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o"))); + if (!Shared) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("start_dyn.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("init_term_dyn.o"))); + } + + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_s, options::OPT_t, options::OPT_r}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, + D.getLTOMode() == LTOK_Thin); + } + + addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { + // Use the static OpenMP runtime with -static-openmp + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + + if (D.CCCIsCXX() && ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + } + + CmdArgs.push_back("-lgcc"); + + CmdArgs.push_back("--push-state"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("--pop-state"); + + CmdArgs.push_back("-lroot"); + + CmdArgs.push_back("-lgcc"); + + CmdArgs.push_back("--push-state"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("--pop-state"); + } + + // No need to do anything for pthreads. Claim argument to avoid warning. + Args.claimAllArgs(options::OPT_pthread, options::OPT_pthreads); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + + ToolChain.addProfileRTLibs(Args, CmdArgs); + + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + C.addCommand(std::make_unique<Command>(JA, *this, + ResponseFileSupport::AtFileCurCP(), + Exec, CmdArgs, Inputs, Output)); +} + /// Haiku - Haiku tool chain which can call as(1) and ld(1) directly. Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { + GCCInstallation.init(Triple, Args); + + getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/lib")); + getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/develop/lib")); + + if (GCCInstallation.isValid()) + getFilePaths().push_back(GCCInstallation.getInstallPath().str()); +} + +void Haiku::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Add dirs specified via 'configure --with-c-include-dirs'. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (!CIncludeDirs.empty()) { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/non-packaged/develop/headers")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/app")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/device")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/drivers")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/game")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/interface")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/kernel")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/locale")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/mail")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/media")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/midi")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/midi2")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/net")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/opengl")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/storage")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/support")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/translation")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/graphics")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/input_server")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/mail_daemon")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/registrar")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/screen_saver")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/add-ons/tracker")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/be_apps/Deskbar")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/be_apps/NetPositive")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/os/be_apps/Tracker")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/3rdparty")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/bsd")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/glibc")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/gnu")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers/posix")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, + "/boot/system/develop/headers")); } void Haiku::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/system/develop/headers/c++/v1"); + concat(getDriver().SysRoot, "/boot/system/develop/headers/c++/v1")); } -void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot + "/system/develop/headers/c++", - getTriple().str(), "", DriverArgs, CC1Args); -} +Tool *Haiku::buildLinker() const { return new tools::haiku::Linker(*this); } + +bool Haiku::HasNativeLLVMSupport() const { return true; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h index 2bc98322bebf..a34f76e22284 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Haiku.h @@ -15,6 +15,25 @@ namespace clang { namespace driver { +namespace tools { + +/// Directly call GNU Binutils assembler and linker +namespace haiku { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("haiku::Linker", "linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace haiku +} // end namespace tools + namespace toolchains { class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF { @@ -22,16 +41,27 @@ public: Haiku(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - bool isPIEDefault() const override { - return getTriple().getArch() == llvm::Triple::x86_64; - } + bool HasNativeLLVMSupport() const override; - void addLibCxxIncludePaths( + bool IsMathErrnoDefault() const override { return false; } + bool IsObjCNonFragileABIDefault() const override { return true; } + bool isPICDefault() const override { return true; } + + const char *getDefaultLinker() const override { return "ld.lld"; } + + void AddClangSystemIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void addLibStdCxxIncludePaths( + void addLibCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + + unsigned GetDefaultDwarfVersion() const override { return 4; } + + bool GetDefaultStandaloneDebug() const override { return true; } + +protected: + Tool *buildLinker() const override; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp index 314d0efce441..d1eed931be5f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -26,8 +26,8 @@ using namespace clang; using namespace llvm::opt; // Default hvx-length for various versions. -static StringRef getDefaultHvxLength(StringRef Cpu) { - return llvm::StringSwitch<StringRef>(Cpu) +static StringRef getDefaultHvxLength(StringRef HvxVer) { + return llvm::StringSwitch<StringRef>(HvxVer) .Case("v60", "64b") .Case("v62", "64b") .Case("v65", "64b") @@ -40,7 +40,7 @@ static void handleHVXWarnings(const Driver &D, const ArgList &Args) { StringRef Val = A->getValue(); if (!Val.equals_insensitive("64b") && !Val.equals_insensitive("128b")) D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; + << A->getSpelling() << Val; } } @@ -51,49 +51,119 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, // Handle HVX warnings. handleHVXWarnings(D, Args); - // Add the +hvx* features based on commandline flags. - StringRef HVXFeature, HVXLength; - - // Handle -mhvx, -mhvx=, -mno-hvx. - if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx, - options::OPT_mhexagon_hvx, - options::OPT_mhexagon_hvx_EQ)) { - if (A->getOption().matches(options::OPT_mno_hexagon_hvx)) - return; - if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) { - HasHVX = true; - HVXFeature = Cpu = A->getValue(); - HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower()); - } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) { - HasHVX = true; - HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu); + auto makeFeature = [&Args](Twine T, bool Enable) -> StringRef { + const std::string &S = T.str(); + StringRef Opt(S); + if (Opt.ends_with("=")) + Opt = Opt.drop_back(1); + if (Opt.starts_with("mno-")) + Opt = Opt.drop_front(4); + else if (Opt.starts_with("m")) + Opt = Opt.drop_front(1); + return Args.MakeArgString(Twine(Enable ? "+" : "-") + Twine(Opt)); + }; + + auto withMinus = [](StringRef S) -> std::string { + return "-" + S.str(); + }; + + // Drop tiny core suffix for HVX version. + std::string HvxVer = + (Cpu.back() == 'T' || Cpu.back() == 't' ? Cpu.drop_back(1) : Cpu).str(); + HasHVX = false; + + // 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 (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(); } - Features.push_back(HVXFeature); + HasHVX = true; + Features.push_back(makeFeature(Twine("hvx") + HvxVer, true)); + } else if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx)) { + // If there was an explicit -mno-hvx, add -hvx to target features. + Features.push_back(makeFeature(A->getOption().getName(), false)); } + StringRef HvxLen = getDefaultHvxLength(HvxVer); + // Handle -mhvx-length=. if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) { // These flags are valid only if HVX in enabled. if (!HasHVX) - D.Diag(diag::err_drv_invalid_hvx_length); + D.Diag(diag::err_drv_needs_hvx) << withMinus(A->getOption().getName()); else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ)) - HVXLength = A->getValue(); + HvxLen = A->getValue(); } - // Default hvx-length based on Cpu. - else if (HasHVX) - HVXLength = getDefaultHvxLength(Cpu); - - if (!HVXLength.empty()) { - HVXFeature = - Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower()); - Features.push_back(HVXFeature); + + if (HasHVX) { + StringRef L = makeFeature(Twine("hvx-length") + HvxLen.lower(), true); + Features.push_back(L); + } + + unsigned HvxVerNum; + // getAsInteger returns 'true' on error. + if (StringRef(HvxVer).drop_front(1).getAsInteger(10, HvxVerNum)) + HvxVerNum = 0; + + // Handle HVX floating point flags. + auto checkFlagHvxVersion = + [&](auto FlagOn, auto FlagOff, + unsigned MinVerNum) -> std::optional<StringRef> { + // Return an std::optional<StringRef>: + // - std::nullopt indicates a verification failure, or that the flag was not + // present in Args. + // - Otherwise the returned value is that name of the feature to add + // to Features. + Arg *A = Args.getLastArg(FlagOn, FlagOff); + if (!A) + return std::nullopt; + + StringRef OptName = A->getOption().getName(); + if (A->getOption().matches(FlagOff)) + return makeFeature(OptName, false); + + if (!HasHVX) { + D.Diag(diag::err_drv_needs_hvx) << withMinus(OptName); + return std::nullopt; + } + if (HvxVerNum < MinVerNum) { + D.Diag(diag::err_drv_needs_hvx_version) + << withMinus(OptName) << ("v" + std::to_string(HvxVerNum)); + return std::nullopt; + } + return makeFeature(OptName, true); + }; + + if (auto F = checkFlagHvxVersion(options::OPT_mhexagon_hvx_qfloat, + options::OPT_mno_hexagon_hvx_qfloat, 68)) { + Features.push_back(*F); + } + if (auto F = checkFlagHvxVersion(options::OPT_mhexagon_hvx_ieee_fp, + options::OPT_mno_hexagon_hvx_ieee_fp, 68)) { + Features.push_back(*F); } } // Hexagon target features. -void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args, +void hexagon::getHexagonTargetFeatures(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args, std::vector<StringRef> &Features) { - handleTargetFeaturesGroup(Args, Features, + handleTargetFeaturesGroup(D, Triple, Args, Features, options::OPT_m_hexagon_Features_Group); bool UseLongCalls = false; @@ -117,7 +187,7 @@ void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args, handleHVXTargetFeatures(D, Args, Features, Cpu, HasHVX); if (HexagonToolChain::isAutoHVXEnabled(Args) && !HasHVX) - D.Diag(diag::warn_drv_vectorize_needs_hvx); + D.Diag(diag::warn_drv_needs_hvx) << "auto-vectorization"; } // Hexagon tools start. @@ -146,16 +216,24 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, "-mcpu=hexagon" + toolchains::HexagonToolChain::GetTargetCPUVersion(Args))); + addSanitizerRuntimes(HTC, Args, CmdArgs); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { - assert(Output.isNothing() && "Unexpected output"); CmdArgs.push_back("-fsyntax-only"); } + if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_ieee_fp, + options::OPT_mno_hexagon_hvx_ieee_fp)) { + if (A->getOption().matches(options::OPT_mhexagon_hvx_ieee_fp)) + CmdArgs.push_back("-mhvx-ieee-fp"); + } + 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); @@ -223,6 +301,9 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, bool UseShared = IsShared && !IsStatic; StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); + bool NeedsSanitizerDeps = addSanitizerRuntimes(HTC, Args, CmdArgs); + bool NeedsXRayDeps = addXRayRuntime(HTC, Args, CmdArgs); + //---------------------------------------------------------------------------- // Silence warnings for various options //---------------------------------------------------------------------------- @@ -262,8 +343,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, CmdArgs.push_back("-pie"); if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { - CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue()))); - UseG0 = G.getValue() == 0; + CmdArgs.push_back(Args.MakeArgString("-G" + Twine(*G))); + UseG0 = *G == 0; } CmdArgs.push_back("-o"); @@ -282,19 +363,31 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString(StringRef("-L") + D.SysRoot + "/usr/lib")); - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_u_Group}); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_u_Group}); AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (NeedsSanitizerDeps) { + linkSanitizerRuntimeDeps(HTC, Args, CmdArgs); + + CmdArgs.push_back("-lunwind"); + } + if (NeedsXRayDeps) + linkXRayRuntimeDeps(HTC, Args, CmdArgs); + CmdArgs.push_back("-lclang_rt.builtins-hexagon"); - CmdArgs.push_back("-lc"); + if (!Args.hasArg(options::OPT_nolibc)) + CmdArgs.push_back("-lc"); } if (D.CCCIsCXX()) { if (HTC.ShouldLinkCXXStdlib(Args)) HTC.AddCXXStdlibLibArgs(Args, CmdArgs); } + const ToolChain::path_list &LibPaths = HTC.getFilePaths(); + for (const auto &LibPath : LibPaths) + CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); + Args.ClaimAllArgs(options::OPT_L); return; } @@ -353,13 +446,13 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, const ToolChain::path_list &LibPaths = HTC.getFilePaths(); for (const auto &LibPath : LibPaths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); + Args.ClaimAllArgs(options::OPT_L); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_u_Group}); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_u_Group}); AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); @@ -378,7 +471,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, if (!IsShared) { for (StringRef Lib : OsLibs) CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); - CmdArgs.push_back("-lc"); + if (!Args.hasArg(options::OPT_nolibc)) + CmdArgs.push_back("-lc"); } CmdArgs.push_back("-lgcc"); @@ -433,8 +527,8 @@ std::string HexagonToolChain::getHexagonTargetDir( return InstalledDir; } -Optional<unsigned> HexagonToolChain::getSmallDataThreshold( - const ArgList &Args) { +std::optional<unsigned> +HexagonToolChain::getSmallDataThreshold(const ArgList &Args) { StringRef Gn = ""; if (Arg *A = Args.getLastArg(options::OPT_G)) { Gn = A->getValue(); @@ -447,7 +541,16 @@ Optional<unsigned> HexagonToolChain::getSmallDataThreshold( if (!Gn.getAsInteger(10, G)) return G; - return None; + return std::nullopt; +} + +std::string HexagonToolChain::getCompilerRTPath() const { + SmallString<128> Dir(getDriver().SysRoot); + llvm::sys::path::append(Dir, "usr", "lib"); + if (!SelectedMultilibs.empty()) { + Dir += SelectedMultilibs.back().gccSuffix(); + } + return std::string(Dir); } void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, @@ -458,8 +561,7 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, // -L Args //---------------------------------------------------------------------------- for (Arg *A : Args.filtered(options::OPT_L)) - for (const char *Value : A->getValues()) - LibPaths.push_back(Value); + llvm::append_range(LibPaths, A->getValues()); //---------------------------------------------------------------------------- // Other standard paths @@ -470,14 +572,14 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), D.PrefixDirs); - if (llvm::find(RootDirs, TargetDir) == RootDirs.end()) + if (!llvm::is_contained(RootDirs, TargetDir)) RootDirs.push_back(TargetDir); bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); // 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) { @@ -522,6 +624,8 @@ void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args, switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); break; @@ -687,17 +791,17 @@ bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) { // Returns the default CPU for Hexagon. This is the default compilation target // if no Hexagon processor is selected at the command-line. // -const StringRef HexagonToolChain::GetDefaultCPU() { +StringRef HexagonToolChain::GetDefaultCPU() { return "hexagonv60"; } -const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { +StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { Arg *CpuArg = nullptr; if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) CpuArg = A; StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); - if (CPU.startswith("hexagon")) + if (CPU.starts_with("hexagon")) return CPU.substr(sizeof("hexagon") - 1); return CPU; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h index c32cb7f09591..e35a224dced4 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.h @@ -20,7 +20,7 @@ namespace hexagon { // For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile // and Compile. // We simply use "clang -cc1" for those actions. -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("hexagon::Assembler", "hexagon-as", TC) {} @@ -35,7 +35,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("hexagon::Linker", "hexagon-ld", TC) {} @@ -50,7 +50,8 @@ public: const char *LinkingOutput) const override; }; -void getHexagonTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, +void getHexagonTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, std::vector<StringRef> &Features); } // end namespace hexagon. @@ -94,9 +95,6 @@ public: llvm::opt::ArgStringList &CmdArgs) const override; StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } - bool IsIntegratedAssemblerDefault() const override { - return true; - } std::string getHexagonTargetDir( const std::string &InstalledDir, @@ -104,12 +102,14 @@ public: void getHexagonLibraryPaths(const llvm::opt::ArgList &Args, ToolChain::path_list &LibPaths) const; + std::string getCompilerRTPath() const override; + static bool isAutoHVXEnabled(const llvm::opt::ArgList &Args); - static const StringRef GetDefaultCPU(); - static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); + static StringRef GetDefaultCPU(); + static StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); - static Optional<unsigned> getSmallDataThreshold( - const llvm::opt::ArgList &Args); + static std::optional<unsigned> + getSmallDataThreshold(const llvm::opt::ArgList &Args); }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp index 48b9ccadf36f..0bc114b90ffc 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hurd.cpp @@ -30,13 +30,21 @@ using tools::addPathIfExists; std::string Hurd::getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, StringRef SysRoot) const { - if (TargetTriple.getArch() == llvm::Triple::x86) { + switch (TargetTriple.getArch()) { + default: + break; + + case llvm::Triple::x86: // We use the existence of '/lib/<triple>' as a directory to detect some // common hurd triples that don't quite match the Clang triple for both // 32-bit and 64-bit targets. Multiarch fixes its install triples to these // regardless of what the actual target triple is. if (D.getVFS().exists(SysRoot + "/lib/i386-gnu")) return "i386-gnu"; + break; + + case llvm::Triple::x86_64: + return "x86_64-gnu"; } // For most architectures, just use whatever we have rather than trying to be @@ -65,7 +73,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); - SelectedMultilib = GCCInstallation.getMultilib(); + SelectedMultilibs.assign({GCCInstallation.getMultilib()}); std::string SysRoot = computeSysRoot(); ToolChain::path_list &PPaths = getProgramPaths(); @@ -92,7 +100,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // those searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) { + if (StringRef(D.Dir).starts_with(SysRoot)) { addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); } @@ -110,7 +118,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) + if (StringRef(D.Dir).starts_with(SysRoot)) addPathIfExists(D, D.Dir + "/../lib", Paths); addPathIfExists(D, SysRoot + "/lib", Paths); @@ -126,8 +134,14 @@ Tool *Hurd::buildAssembler() const { } std::string Hurd::getDynamicLinker(const ArgList &Args) const { - if (getArch() == llvm::Triple::x86) + switch (getArch()) { + case llvm::Triple::x86: return "/lib/ld.so"; + case llvm::Triple::x86_64: + return "/lib/ld-x86-64.so.1"; + default: + break; + } llvm_unreachable("unsupported architecture"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h index dc04b0cfe2ee..33701f7cc045 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Lanai.h @@ -29,8 +29,6 @@ public: void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override {} - - bool IsIntegratedAssemblerDefault() const override { return true; } }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h new file mode 100644 index 000000000000..813d00a87bb8 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/LazyDetector.h @@ -0,0 +1,45 @@ +//===--- LazyDetector.h - Lazy ToolChain Detection --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LAZYDETECTOR_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LAZYDETECTOR_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include <optional> + +namespace clang { + +/// Simple wrapper for toolchain detector with costly initialization. This +/// delays the creation of the actual detector until its first usage. + +template <class T> class LazyDetector { + const driver::Driver &D; + llvm::Triple Triple; + const llvm::opt::ArgList &Args; + + std::optional<T> Detector; + +public: + LazyDetector(const driver::Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : D(D), Triple(Triple), Args(Args) {} + T *operator->() { + if (!Detector) + Detector.emplace(D, Triple, Args); + return &*Detector; + } + const T *operator->() const { + return const_cast<T const *>( + const_cast<LazyDetector &>(*this).operator->()); + } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LAZYDETECTOR_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp index c9360fc67165..4300a2bdff17 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp @@ -8,6 +8,7 @@ #include "Linux.h" #include "Arch/ARM.h" +#include "Arch/LoongArch.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/RISCV.h" @@ -60,12 +61,16 @@ std::string Linux::getMultiarchTriple(const Driver &D, case llvm::Triple::thumb: if (IsAndroid) return "arm-linux-androideabi"; - if (TargetEnvironment == llvm::Triple::GNUEABIHF) + if (TargetEnvironment == llvm::Triple::GNUEABIHF || + TargetEnvironment == llvm::Triple::MuslEABIHF || + TargetEnvironment == llvm::Triple::EABIHF) return "arm-linux-gnueabihf"; return "arm-linux-gnueabi"; case llvm::Triple::armeb: case llvm::Triple::thumbeb: - if (TargetEnvironment == llvm::Triple::GNUEABIHF) + if (TargetEnvironment == llvm::Triple::GNUEABIHF || + TargetEnvironment == llvm::Triple::MuslEABIHF || + TargetEnvironment == llvm::Triple::EABIHF) return "armeb-linux-gnueabihf"; return "armeb-linux-gnueabi"; case llvm::Triple::x86: @@ -85,37 +90,66 @@ std::string Linux::getMultiarchTriple(const Driver &D, case llvm::Triple::aarch64_be: return "aarch64_be-linux-gnu"; + case llvm::Triple::loongarch64: { + const char *Libc; + const char *FPFlavor; + + if (TargetTriple.isGNUEnvironment()) { + Libc = "gnu"; + } else if (TargetTriple.isMusl()) { + Libc = "musl"; + } else { + return TargetTriple.str(); + } + + switch (TargetEnvironment) { + default: + return TargetTriple.str(); + case llvm::Triple::GNUSF: + FPFlavor = "sf"; + break; + case llvm::Triple::GNUF32: + FPFlavor = "f32"; + break; + case llvm::Triple::GNU: + case llvm::Triple::GNUF64: + // This was going to be "f64" in an earlier Toolchain Conventions + // revision, but starting from Feb 2023 the F64 ABI variants are + // unmarked in their canonical forms. + FPFlavor = ""; + break; + } + + return (Twine("loongarch64-linux-") + Libc + FPFlavor).str(); + } + case llvm::Triple::m68k: return "m68k-linux-gnu"; case llvm::Triple::mips: return IsMipsR6 ? "mipsisa32r6-linux-gnu" : "mips-linux-gnu"; case llvm::Triple::mipsel: - if (IsAndroid) - return "mipsel-linux-android"; return IsMipsR6 ? "mipsisa32r6el-linux-gnu" : "mipsel-linux-gnu"; case llvm::Triple::mips64: { std::string MT = std::string(IsMipsR6 ? "mipsisa64r6" : "mips64") + "-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64"); - if (D.getVFS().exists(SysRoot + "/lib/" + MT)) + if (D.getVFS().exists(concat(SysRoot, "/lib", MT))) return MT; - if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu")) + if (D.getVFS().exists(concat(SysRoot, "/lib/mips64-linux-gnu"))) return "mips64-linux-gnu"; break; } case llvm::Triple::mips64el: { - if (IsAndroid) - return "mips64el-linux-android"; std::string MT = std::string(IsMipsR6 ? "mipsisa64r6el" : "mips64el") + "-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64"); - if (D.getVFS().exists(SysRoot + "/lib/" + MT)) + if (D.getVFS().exists(concat(SysRoot, "/lib", MT))) return MT; - if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu")) + if (D.getVFS().exists(concat(SysRoot, "/lib/mips64el-linux-gnu"))) return "mips64el-linux-gnu"; break; } case llvm::Triple::ppc: - if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe")) + if (D.getVFS().exists(concat(SysRoot, "/lib/powerpc-linux-gnuspe"))) return "powerpc-linux-gnuspe"; return "powerpc-linux-gnu"; case llvm::Triple::ppcle: @@ -124,6 +158,10 @@ std::string Linux::getMultiarchTriple(const Driver &D, return "powerpc64-linux-gnu"; case llvm::Triple::ppc64le: return "powerpc64le-linux-gnu"; + case llvm::Triple::riscv64: + if (IsAndroid) + return "riscv64-linux-android"; + return "riscv64-linux-gnu"; case llvm::Triple::sparc: return "sparc-linux-gnu"; case llvm::Triple::sparcv9: @@ -179,7 +217,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); - SelectedMultilib = GCCInstallation.getMultilib(); + SelectedMultilibs.assign({GCCInstallation.getMultilib()}); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); ToolChain::path_list &PPaths = getProgramPaths(); @@ -206,8 +244,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("max-page-size=4096"); } - if (GCCInstallation.getParentLibPath().find("opt/rh/devtoolset") != - StringRef::npos) + if (GCCInstallation.getParentLibPath().contains("opt/rh/")) // With devtoolset on RHEL, we want to add a bin directory that is relative // to the detected gcc install, because if we are using devtoolset gcc then // we want to use other tools from devtoolset (e.g. ld) instead of the @@ -222,8 +259,12 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) const bool IsMips = Triple.isMIPS(); const bool IsHexagon = Arch == llvm::Triple::hexagon; const bool IsRISCV = Triple.isRISCV(); + const bool IsCSKY = Triple.isCSKY(); - if (IsMips && !SysRoot.empty()) + if (IsCSKY && !SelectedMultilibs.empty()) + SysRoot = SysRoot + SelectedMultilibs.back().osSuffix(); + + if ((IsMips || IsCSKY) && !SysRoot.empty()) ExtraOpts.push_back("--sysroot=" + SysRoot); // Do not use 'gnu' hash style for Mips targets because .gnu.hash @@ -233,25 +274,18 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // Android loader does not support .gnu.hash until API 23. // Hexagon linker/loader does not support .gnu.hash if (!IsMips && !IsHexagon) { - if (Distro.IsRedhat() || Distro.IsOpenSUSE() || Distro.IsAlpineLinux() || - (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick) || - (IsAndroid && !Triple.isAndroidVersionLT(23))) - ExtraOpts.push_back("--hash-style=gnu"); - - if (Distro.IsDebian() || Distro.IsOpenSUSE() || - Distro == Distro::UbuntuLucid || Distro == Distro::UbuntuJaunty || - Distro == Distro::UbuntuKarmic || + if (Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid || + Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic || (IsAndroid && Triple.isAndroidVersionLT(23))) ExtraOpts.push_back("--hash-style=both"); + else + ExtraOpts.push_back("--hash-style=gnu"); } #ifdef ENABLE_LINKER_BUILD_ID ExtraOpts.push_back("--build-id"); #endif - if (IsAndroid || Distro.IsOpenSUSE()) - ExtraOpts.push_back("--enable-new-dtags"); - // The selection of paths to try here is designed to match the patterns which // the GCC driver itself uses, as this is part of the GCC-compatible driver. // This was determined by running GCC in a fake filesystem, creating all @@ -262,52 +296,48 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) const std::string OSLibDir = std::string(getOSLibDir(Triple, Args)); const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); + // mips32: Debian multilib, we use /libo32, while in other case, /lib is + // 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, 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 // version as well as some unversioned libraries in the usual multiarch // directory. - unsigned Major; - unsigned Minor; - unsigned Micro; - Triple.getEnvironmentVersion(Major, Minor, Micro); - addPathIfExists(D, - SysRoot + "/usr/lib/" + MultiarchTriple + "/" + - llvm::to_string(Major), - Paths); + addPathIfExists( + D, + 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)) - addPathIfExists(D, D.Dir + "/../lib", 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 { @@ -316,6 +346,12 @@ ToolChain::RuntimeLibType Linux::GetDefaultRuntimeLibType() const { return Generic_ELF::GetDefaultRuntimeLibType(); } +unsigned Linux::GetDefaultDwarfVersion() const { + if (getTriple().isAndroid()) + return 4; + return ToolChain::GetDefaultDwarfVersion(); +} + ToolChain::CXXStdlibType Linux::GetDefaultCXXStdlibType() const { if (getTriple().isAndroid()) return ToolChain::CST_Libcxx; @@ -347,6 +383,21 @@ std::string Linux::computeSysRoot() const { return AndroidSysRootPath; } + if (getTriple().isCSKY()) { + // CSKY toolchains use different names for sysroot folder. + if (!GCCInstallation.isValid()) + return std::string(); + // GCCInstallation.getInstallPath() = + // $GCCToolchainPath/lib/gcc/csky-linux-gnuabiv2/6.3.0 + // Path = $GCCToolchainPath/csky-linux-gnuabiv2/libc + std::string Path = (GCCInstallation.getInstallPath() + "/../../../../" + + GCCInstallation.getTriple().str() + "/libc") + .str(); + if (getVFS().exists(Path)) + return Path; + return std::string(); + } + if (!GCCInstallation.isValid() || !getTriple().isMIPS()) return std::string(); @@ -379,9 +430,17 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { const Distro Distro(getDriver().getVFS(), Triple); - if (Triple.isAndroid()) + if (Triple.isAndroid()) { + if (getSanitizerArgs(Args).needsHwasanRt() && + !Triple.isAndroidVersionLT(34) && Triple.isArch64Bit()) { + // On Android 14 and newer, there is a special linker_hwasan64 that + // allows to run HWASan binaries on non-HWASan system images. This + // is also available on HWASan system images, so we can just always + // use that instead. + return "/system/bin/linker_hwasan64"; + } return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; - + } if (Triple.isMusl()) { std::string ArchName; bool IsArm = false; @@ -410,6 +469,9 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { (Triple.getEnvironment() == llvm::Triple::MuslEABIHF || tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)) ArchName += "hf"; + if (Arch == llvm::Triple::ppc && + Triple.getSubArch() == llvm::Triple::PPCSubArch_spe) + ArchName = "powerpc-sf"; return "/lib/ld-musl-" + ArchName + ".so.1"; } @@ -441,6 +503,22 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3"; break; } + case llvm::Triple::loongarch32: { + LibDir = "lib32"; + Loader = + ("ld-linux-loongarch-" + + tools::loongarch::getLoongArchABI(getDriver(), Args, Triple) + ".so.1") + .str(); + break; + } + case llvm::Triple::loongarch64: { + LibDir = "lib64"; + Loader = + ("ld-linux-loongarch-" + + tools::loongarch::getLoongArchABI(getDriver(), Args, Triple) + ".so.1") + .str(); + break; + } case llvm::Triple::m68k: LibDir = "lib"; Loader = "ld.so.1"; @@ -449,7 +527,7 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: { - bool IsNaN2008 = tools::mips::isNaN2008(Args, Triple); + bool IsNaN2008 = tools::mips::isNaN2008(getDriver(), Args, Triple); LibDir = "lib" + tools::mips::getMipsABILibSuffix(Args, Triple); @@ -520,6 +598,11 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { } case llvm::Triple::ve: return "/opt/nec/ve/lib/ld-linux-ve.so.1"; + case llvm::Triple::csky: { + LibDir = "lib"; + Loader = "ld.so.1"; + break; + } } if (Distro == Distro::Exherbo && @@ -551,7 +634,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; // LOCAL_INCLUDE_DIR - addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); + addSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/local/include")); // TOOL_INCLUDE_DIR AddMultilibIncludeArgs(DriverArgs, CC1Args); @@ -572,9 +655,10 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // /usr/include. std::string MultiarchIncludeDir = getMultiarchTriple(D, getTriple(), SysRoot); if (!MultiarchIncludeDir.empty() && - D.getVFS().exists(SysRoot + "/usr/include/" + MultiarchIncludeDir)) - addExternCSystemInclude(DriverArgs, CC1Args, - SysRoot + "/usr/include/" + MultiarchIncludeDir); + D.getVFS().exists(concat(SysRoot, "/usr/include", MultiarchIncludeDir))) + addExternCSystemInclude( + DriverArgs, CC1Args, + concat(SysRoot, "/usr/include", MultiarchIncludeDir)); if (getTriple().getOS() == llvm::Triple::RTEMS) return; @@ -582,9 +666,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Add an include of '/include' directly. This isn't provided by default by // system GCCs, but is often used with cross-compiling GCCs, and harmless to // add even when Clang is acting as-if it were a system compiler. - addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); + addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/include")); - addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); + addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/include")); if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl()) addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); @@ -633,12 +717,25 @@ void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void Linux::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); +} + +void Linux::AddHIPRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.push_back( + Args.MakeArgString(StringRef("-L") + RocmInstallation->getLibPath())); + + if (Args.hasFlag(options::OPT_frtlib_add_rpath, + options::OPT_fno_rtlib_add_rpath, false)) + CmdArgs.append( + {"-rpath", Args.MakeArgString(RocmInstallation->getLibPath())}); + + CmdArgs.push_back("-lamdhip64"); } void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, @@ -651,9 +748,9 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, } } -bool Linux::isPIEDefault() const { - return (getTriple().isAndroid() && !getTriple().isAndroidVersionLT(16)) || - getTriple().isMusl() || getSanitizerArgs().requiresPIE(); +bool Linux::isPIEDefault(const llvm::opt::ArgList &Args) const { + return CLANG_DEFAULT_PIE_ON_LINUX || getTriple().isAndroid() || + getTriple().isMusl() || getSanitizerArgs(Args).requiresPIE(); } bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const { @@ -669,12 +766,8 @@ bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const { return true; } -bool Linux::isNoExecStackDefault() const { - return getTriple().isAndroid(); -} - bool Linux::IsMathErrnoDefault() const { - if (getTriple().isAndroid()) + if (getTriple().isAndroid() || getTriple().isMusl()) return false; return Generic_ELF::IsMathErrnoDefault(); } @@ -692,8 +785,10 @@ SanitizerMask Linux::getSupportedSanitizers() const { getTriple().getArch() == llvm::Triple::thumb || getTriple().getArch() == llvm::Triple::armeb || getTriple().getArch() == llvm::Triple::thumbeb; + const bool IsLoongArch64 = getTriple().getArch() == llvm::Triple::loongarch64; const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64; const bool IsSystemZ = getTriple().getArch() == llvm::Triple::systemz; + const bool IsHexagon = getTriple().getArch() == llvm::Triple::hexagon; SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; @@ -704,24 +799,28 @@ SanitizerMask Linux::getSupportedSanitizers() const { Res |= SanitizerKind::Memory; Res |= SanitizerKind::Vptr; Res |= SanitizerKind::SafeStack; - if (IsX86_64 || IsMIPS64 || IsAArch64) + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsLoongArch64) Res |= SanitizerKind::DataFlow; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 || - IsRISCV64 || IsSystemZ) + IsRISCV64 || IsSystemZ || IsHexagon || IsLoongArch64) Res |= SanitizerKind::Leak; - if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ) + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ || + IsLoongArch64 || IsRISCV64) Res |= SanitizerKind::Thread; - if (IsX86_64) + if (IsX86_64 || IsSystemZ) Res |= SanitizerKind::KernelMemory; - if (IsX86 || IsX86_64) - Res |= SanitizerKind::Function; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || - IsPowerPC64) + IsPowerPC64 || IsHexagon || IsLoongArch64 || IsRISCV64) Res |= SanitizerKind::Scudo; - if (IsX86_64 || IsAArch64) { + if (IsX86_64 || IsAArch64 || IsRISCV64) { Res |= SanitizerKind::HWAddress; + } + if (IsX86_64 || IsAArch64) { Res |= SanitizerKind::KernelHWAddress; } + // Work around "Cannot represent a difference across sections". + if (getTriple().getArch() == llvm::Triple::ppc64) + Res &= ~SanitizerKind::Function; return Res; } @@ -758,3 +857,9 @@ void Linux::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { for (const auto &Opt : ExtraOpts) CmdArgs.push_back(Opt.c_str()); } + +const char *Linux::getDefaultLinker() const { + if (getTriple().isAndroid()) + return "ld.lld"; + return Generic_ELF::getDefaultLinker(); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h index 169a37c44072..524391743090 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.h @@ -37,14 +37,16 @@ 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; + unsigned GetDefaultDwarfVersion() const override; CXXStdlibType GetDefaultCXXStdlibType() const override; bool IsAArch64OutlineAtomicsDefault(const llvm::opt::ArgList &Args) const override; - bool isPIEDefault() const override; - bool isNoExecStackDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool IsMathErrnoDefault() const override; SanitizerMask getSupportedSanitizers() const override; void addProfileRTLibs(const llvm::opt::ArgList &Args, @@ -61,6 +63,8 @@ public: const llvm::opt::ArgList &DriverArgs, const JobAction &JA, const llvm::fltSemantics *FPType = nullptr) const override; + const char *getDefaultLinker() const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp index 96994ba77fac..07e875c64960 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.cpp @@ -101,7 +101,7 @@ void msp430::getMSP430TargetFeatures(const Driver &D, const ArgList &Args, Features.push_back("+hwmultf5"); } else { D.Diag(clang::diag::err_drv_unsupported_option_argument) - << HWMultArg->getAsString(Args) << HWMult; + << HWMultArg->getSpelling() << HWMult; } } @@ -142,7 +142,7 @@ std::string MSP430ToolChain::computeSysRoot() const { else llvm::sys::path::append(Dir, getDriver().Dir, ".."); - return std::string(Dir.str()); + return std::string(Dir); } void MSP430ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -166,7 +166,7 @@ void MSP430ToolChain::addClangTargetOptions(const ArgList &DriverArgs, return; const StringRef MCU = MCUArg->getValue(); - if (MCU.startswith("msp430i")) { + if (MCU.starts_with("msp430i")) { // 'i' should be in lower case as it's defined in TI MSP430-GCC headers CC1Args.push_back(DriverArgs.MakeArgString( "-D__MSP430i" + MCU.drop_front(7).upper() + "__")); @@ -279,8 +279,7 @@ void msp430::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_r, options::OPT_g_Group)) CmdArgs.push_back("--gc-sections"); - Args.AddAllArgs(CmdArgs, { - options::OPT_e, + Args.addAllArgs(CmdArgs, { options::OPT_n, options::OPT_s, options::OPT_t, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h index 9d247ca3a896..a224c6375411 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSP430.h @@ -37,7 +37,9 @@ public: Action::OffloadKind) const override; bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return true; } UnwindLibType @@ -57,7 +59,7 @@ private: namespace tools { namespace msp430 { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("MSP430::Linker", "msp430-elf-ld", TC) {} bool hasIntegratedCPP() const override { return false; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp index 0dc94a4c6c7d..396522225158 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.cpp @@ -18,17 +18,16 @@ #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Host.h" #include <cstdio> #ifdef _WIN32 @@ -40,23 +39,6 @@ #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> - -#include "MSVCSetupApi.h" -#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; @@ -70,294 +52,6 @@ static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) { return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0; } -// Defined below. -// Forward declare this so there aren't too many things above the constructor. -static bool getSystemRegistryString(const char *keyPath, const char *valueName, - std::string &value, std::string *phValue); - -static std::string getHighestNumericTupleInDirectory(llvm::vfs::FileSystem &VFS, - StringRef Directory) { - std::string Highest; - llvm::VersionTuple HighestTuple; - - std::error_code EC; - for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC), - DirEnd; - !EC && DirIt != DirEnd; DirIt.increment(EC)) { - auto Status = VFS.status(DirIt->path()); - if (!Status || !Status->isDirectory()) - continue; - StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); - llvm::VersionTuple Tuple; - if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error. - continue; - if (Tuple > HighestTuple) { - HighestTuple = Tuple; - Highest = CandidateName.str(); - } - } - - return Highest; -} - -// Check command line arguments to try and find a toolchain. -static bool -findVCToolChainViaCommandLine(llvm::vfs::FileSystem &VFS, const ArgList &Args, - std::string &Path, - MSVCToolChain::ToolsetLayout &VSLayout) { - // Don't validate the input; trust the value supplied by the user. - // The primary motivation is to prevent unnecessary file and registry access. - if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir, - options::OPT__SLASH_winsysroot)) { - if (A->getOption().getID() == options::OPT__SLASH_winsysroot) { - llvm::SmallString<128> ToolsPath(A->getValue()); - llvm::sys::path::append(ToolsPath, "VC", "Tools", "MSVC"); - std::string VCToolsVersion; - if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion)) - VCToolsVersion = A->getValue(); - else - VCToolsVersion = getHighestNumericTupleInDirectory(VFS, ToolsPath); - llvm::sys::path::append(ToolsPath, VCToolsVersion); - Path = std::string(ToolsPath.str()); - } else { - Path = A->getValue(); - } - VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; - return true; - } - return false; -} - -// Check various environment variables to try and find a toolchain. -static bool -findVCToolChainViaEnvironment(llvm::vfs::FileSystem &VFS, std::string &Path, - MSVCToolChain::ToolsetLayout &VSLayout) { - // These variables are typically set by vcvarsall.bat - // when launching a developer command prompt. - if (llvm::Optional<std::string> VCToolsInstallDir = - llvm::sys::Process::GetEnv("VCToolsInstallDir")) { - // This is only set by newer Visual Studios, and it leads straight to - // the toolchain directory. - Path = std::move(*VCToolsInstallDir); - VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; - return true; - } - if (llvm::Optional<std::string> VCInstallDir = - llvm::sys::Process::GetEnv("VCINSTALLDIR")) { - // If the previous variable isn't set but this one is, then we've found - // an older Visual Studio. This variable is set by newer Visual Studios too, - // so this check has to appear second. - // In older Visual Studios, the VC directory is the toolchain. - Path = std::move(*VCInstallDir); - VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; - return true; - } - - // We couldn't find any VC environment variables. Let's walk through PATH and - // see if it leads us to a VC toolchain bin directory. If it does, pick the - // first one that we find. - if (llvm::Optional<std::string> PathEnv = - llvm::sys::Process::GetEnv("PATH")) { - llvm::SmallVector<llvm::StringRef, 8> PathEntries; - llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator); - for (llvm::StringRef PathEntry : PathEntries) { - if (PathEntry.empty()) - continue; - - llvm::SmallString<256> ExeTestPath; - - // If cl.exe doesn't exist, then this definitely isn't a VC toolchain. - ExeTestPath = PathEntry; - llvm::sys::path::append(ExeTestPath, "cl.exe"); - if (!VFS.exists(ExeTestPath)) - continue; - - // cl.exe existing isn't a conclusive test for a VC toolchain; clang also - // has a cl.exe. So let's check for link.exe too. - ExeTestPath = PathEntry; - llvm::sys::path::append(ExeTestPath, "link.exe"); - if (!VFS.exists(ExeTestPath)) - continue; - - // whatever/VC/bin --> old toolchain, VC dir is toolchain dir. - llvm::StringRef TestPath = PathEntry; - bool IsBin = - llvm::sys::path::filename(TestPath).equals_insensitive("bin"); - if (!IsBin) { - // Strip any architecture subdir like "amd64". - TestPath = llvm::sys::path::parent_path(TestPath); - IsBin = llvm::sys::path::filename(TestPath).equals_insensitive("bin"); - } - if (IsBin) { - llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath); - llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath); - if (ParentFilename.equals_insensitive("VC")) { - Path = std::string(ParentPath); - VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; - return true; - } - if (ParentFilename.equals_insensitive("x86ret") || - ParentFilename.equals_insensitive("x86chk") || - ParentFilename.equals_insensitive("amd64ret") || - ParentFilename.equals_insensitive("amd64chk")) { - Path = std::string(ParentPath); - VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal; - return true; - } - - } else { - // This could be a new (>=VS2017) toolchain. If it is, we should find - // path components with these prefixes when walking backwards through - // the path. - // Note: empty strings match anything. - llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "", - "MSVC", "Tools", "VC"}; - - auto It = llvm::sys::path::rbegin(PathEntry); - auto End = llvm::sys::path::rend(PathEntry); - for (llvm::StringRef Prefix : ExpectedPrefixes) { - if (It == End) - goto NotAToolChain; - if (!It->startswith_insensitive(Prefix)) - goto NotAToolChain; - ++It; - } - - // We've found a new toolchain! - // Back up 3 times (/bin/Host/arch) to get the root path. - llvm::StringRef ToolChainPath(PathEntry); - for (int i = 0; i < 3; ++i) - ToolChainPath = llvm::sys::path::parent_path(ToolChainPath); - - Path = std::string(ToolChainPath); - VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; - return true; - } - - NotAToolChain: - continue; - } - } - return false; -} - -// Query the Setup Config server for installs, then pick the newest version -// and find its default VC toolchain. -// This is the preferred way to discover new Visual Studios, as they're no -// longer listed in the registry. -static bool -findVCToolChainViaSetupConfig(llvm::vfs::FileSystem &VFS, std::string &Path, - MSVCToolChain::ToolsetLayout &VSLayout) { -#if !defined(USE_MSVC_SETUP_API) - return false; -#else - // FIXME: This really should be done once in the top-level program's main - // function, as it may have already been initialized with a different - // threading model otherwise. - llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded); - HRESULT HR; - - // _com_ptr_t will throw a _com_error if a COM calls fail. - // The LLVM coding standards forbid exception handling, so we'll have to - // stop them from being thrown in the first place. - // The destructor will put the regular error handler back when we leave - // this scope. - struct SuppressCOMErrorsRAII { - static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {} - - SuppressCOMErrorsRAII() { _set_com_error_handler(handler); } - - ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); } - - } COMErrorSuppressor; - - ISetupConfigurationPtr Query; - HR = Query.CreateInstance(__uuidof(SetupConfiguration)); - if (FAILED(HR)) - return false; - - IEnumSetupInstancesPtr EnumInstances; - HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances); - if (FAILED(HR)) - return false; - - ISetupInstancePtr Instance; - HR = EnumInstances->Next(1, &Instance, nullptr); - if (HR != S_OK) - return false; - - ISetupInstancePtr NewestInstance; - Optional<uint64_t> NewestVersionNum; - do { - bstr_t VersionString; - uint64_t VersionNum; - HR = Instance->GetInstallationVersion(VersionString.GetAddress()); - if (FAILED(HR)) - continue; - HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum); - if (FAILED(HR)) - continue; - if (!NewestVersionNum || (VersionNum > NewestVersionNum)) { - NewestInstance = Instance; - NewestVersionNum = VersionNum; - } - } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK); - - if (!NewestInstance) - return false; - - bstr_t VCPathWide; - HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress()); - if (FAILED(HR)) - return false; - - std::string VCRootPath; - llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath); - - llvm::SmallString<256> ToolsVersionFilePath(VCRootPath); - llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build", - "Microsoft.VCToolsVersion.default.txt"); - - auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath); - if (!ToolsVersionFile) - return false; - - llvm::SmallString<256> ToolchainPath(VCRootPath); - llvm::sys::path::append(ToolchainPath, "Tools", "MSVC", - ToolsVersionFile->get()->getBuffer().rtrim()); - auto Status = VFS.status(ToolchainPath); - if (!Status || !Status->isDirectory()) - return false; - - Path = std::string(ToolchainPath.str()); - VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; - return true; -#endif -} - -// Look in the registry for Visual Studio installs, and use that to get -// a toolchain path. VS2017 and newer don't get added to the registry. -// So if we find something here, we know that it's an older version. -static bool findVCToolChainViaRegistry(std::string &Path, - MSVCToolChain::ToolsetLayout &VSLayout) { - std::string VSInstallPath; - if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)", - "InstallDir", VSInstallPath, nullptr) || - getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)", - "InstallDir", VSInstallPath, nullptr)) { - if (!VSInstallPath.empty()) { - llvm::SmallString<256> VCPath(llvm::StringRef( - VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)"))); - llvm::sys::path::append(VCPath, "VC"); - - Path = std::string(VCPath.str()); - VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; - return true; - } - } - return false; -} - // Try to find Exe from a Visual Studio distribution. This first tries to find // an installed copy of Visual Studio and, failing that, looks in the PATH, // making sure that whatever executable that's found is not a same-named exe @@ -365,8 +59,8 @@ static bool findVCToolChainViaRegistry(std::string &Path, static std::string FindVisualStudioExecutable(const ToolChain &TC, const char *Exe) { const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC); - SmallString<128> FilePath(MSVC.getSubDirectoryPath( - toolchains::MSVCToolChain::SubDirectoryType::Bin)); + SmallString<128> FilePath( + MSVC.getSubDirectoryPath(llvm::SubDirectoryType::Bin)); llvm::sys::path::append(FilePath, Exe); return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe); } @@ -386,7 +80,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(std::string("-out:") + Output.getFilename())); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && - !C.getDriver().IsCLMode()) { + !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { CmdArgs.push_back("-defaultlib:libcmt"); CmdArgs.push_back("-defaultlib:oldnames"); } @@ -396,17 +90,29 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, // the environment variable is set however, assume the user knows what // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that // over env vars. + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir, + options::OPT__SLASH_winsysroot)) { + // cl.exe doesn't find the DIA SDK automatically, so this too requires + // explicit flags and doesn't automatically look in "DIA SDK" relative + // to the path we found for VCToolChainPath. + llvm::SmallString<128> DIAPath(A->getValue()); + if (A->getOption().getID() == options::OPT__SLASH_winsysroot) + llvm::sys::path::append(DIAPath, "DIA SDK"); + + // The DIA SDK always uses the legacy vc arch, even in new MSVC versions. + llvm::sys::path::append(DIAPath, "lib", + llvm::archToLegacyVCArch(TC.getArch())); + CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath)); + } if (!llvm::sys::Process::GetEnv("LIB") || Args.getLastArg(options::OPT__SLASH_vctoolsdir, 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, @@ -423,6 +129,16 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); } + if (C.getDriver().IsFlangMode()) { + addFortranRuntimeLibraryPath(TC, Args, CmdArgs); + addFortranRuntimeLibs(TC, Args, CmdArgs); + + // Inform the MSVC linker that we're generating a console application, i.e. + // one with `main` as the "user-defined" entry point. The `main` function is + // defined in flang's runtime libraries. + CmdArgs.push_back("/subsystem:console"); + } + // Add the compiler-rt library directories to libpath if they exist to help // the linker find the various sanitizer, builtin, and profiling runtimes. for (const auto &LibPath : TC.getLibraryPaths()) { @@ -442,6 +158,11 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7)) CmdArgs.push_back("-debug"); + // If we specify /hotpatch, let the linker add padding in front of each + // function, like MSVC does. + if (Args.hasArg(options::OPT_fms_hotpatch, options::OPT__SLASH_hotpatch)) + CmdArgs.push_back("-functionpadmin"); + // Pass on /Brepro if it was passed to the compiler. // Note that /Brepro maps to -mno-incremental-linker-compatible. bool DefaultIncrementalLinkerCompatible = @@ -461,7 +182,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName)); } - if (TC.getSanitizerArgs().needsFuzzer()) { + if (TC.getSanitizerArgs(Args).needsFuzzer()) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back( Args.MakeArgString(std::string("-wholearchive:") + @@ -472,10 +193,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-incremental:no")); } - if (TC.getSanitizerArgs().needsAsanRt()) { + if (TC.getSanitizerArgs(Args).needsAsanRt()) { CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); - if (TC.getSanitizerArgs().needsSharedRt() || + if (TC.getSanitizerArgs(Args).needsSharedRt() || Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); @@ -506,7 +227,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); // Control Flow Guard checks - if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { + for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) { StringRef GuardArgs = A->getValue(); if (GuardArgs.equals_insensitive("cf") || GuardArgs.equals_insensitive("cf,nochecks")) { @@ -548,6 +269,26 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args); } + StringRef Linker = + Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER); + if (Linker.empty()) + Linker = "link"; + // We need to translate 'lld' into 'lld-link'. + else if (Linker.equals_insensitive("lld")) + Linker = "lld-link"; + + if (Linker == "lld-link") { + for (Arg *A : Args.filtered(options::OPT_vfsoverlay)) + CmdArgs.push_back( + Args.MakeArgString(std::string("/vfsoverlay:") + A->getValue())); + + if (C.getDriver().isUsingLTO() && + Args.hasFlag(options::OPT_gsplit_dwarf, options::OPT_gno_split_dwarf, + false)) + CmdArgs.push_back(Args.MakeArgString(Twine("/dwodir:") + + Output.getFilename() + "_dwo")); + } + // Add filenames, libraries, and other linker inputs. for (const auto &Input : Inputs) { if (Input.isFilename()) { @@ -561,7 +302,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (A.getOption().matches(options::OPT_l)) { StringRef Lib = A.getValue(); const char *LinkLibArg; - if (Lib.endswith(".lib")) + if (Lib.ends_with(".lib")) LinkLibArg = Args.MakeArgString(Lib); else LinkLibArg = Args.MakeArgString(Lib + ".lib"); @@ -574,21 +315,15 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, A.renderAsInput(Args, CmdArgs); } + addHIPRuntimeLibArgs(TC, C, Args, CmdArgs); + TC.addProfileRTLibs(Args, CmdArgs); std::vector<const char *> Environment; - // We need to special case some linker paths. In the case of lld, we need to - // translate 'lld' into 'lld-link', and in the case of the regular msvc + // We need to special case some linker paths. In the case of the regular msvc // linker, we need to use a special search algorithm. llvm::SmallString<128> linkPath; - StringRef Linker - = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER); - if (Linker.empty()) - Linker = "link"; - if (Linker.equals_insensitive("lld")) - Linker = "lld-link"; - if (Linker.equals_insensitive("link")) { // If we're using the MSVC linker, it's not sufficient to just use link // from the program PATH, because other environments like GnuWin32 install @@ -608,13 +343,18 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + // Clang handles passing the proper asan libs to the linker, which goes + // against link.exe's /INFERASANLIBS which automatically finds asan libs. + if (TC.getSanitizerArgs(Args).needsAsanRt()) + CmdArgs.push_back("/INFERASANLIBS:NO"); + #ifdef _WIN32 // When cross-compiling with VS2017 or newer, link.exe expects to have // its containing bin directory at the top of PATH, followed by the // native target bin directory. // e.g. when compiling for x86 on an x64 host, PATH should start with: // /bin/Hostx64/x86;/bin/Hostx64/x64 - // This doesn't attempt to handle ToolsetLayout::DevDivInternal. + // This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal. if (TC.getIsVS2017OrNewer() && llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) { auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch(); @@ -648,14 +388,13 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, // find it. for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) { llvm::StringRef EnvVar(Cursor); - if (EnvVar.startswith_insensitive("path=")) { - using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType; + if (EnvVar.starts_with_insensitive("path=")) { constexpr size_t PrefixLen = 5; // strlen("path=") Environment.push_back(Args.MakeArgString( EnvVar.substr(0, PrefixLen) + - TC.getSubDirectoryPath(SubDirectoryType::Bin) + + TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) + llvm::Twine(llvm::sys::EnvPathSeparator) + - TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) + + TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin, HostArch) + (EnvVar.size() > PrefixLen ? llvm::Twine(llvm::sys::EnvPathSeparator) + EnvVar.substr(PrefixLen) @@ -688,14 +427,29 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); + std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion; + if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir)) + VCToolsDir = A->getValue(); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion)) + VCToolsVersion = A->getValue(); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir)) + WinSdkDir = A->getValue(); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion)) + WinSdkVersion = A->getValue(); + if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot)) + WinSysRoot = A->getValue(); + // Check the command line first, that's the user explicitly telling us what to // use. Check the environment next, in case we're being invoked from a VS // command prompt. Failing that, just try to find the newest Visual Studio // version we can and use its default VC toolchain. - findVCToolChainViaCommandLine(getVFS(), Args, VCToolChainPath, VSLayout) || - findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, VSLayout) || - findVCToolChainViaSetupConfig(getVFS(), VCToolChainPath, VSLayout) || - findVCToolChainViaRegistry(VCToolChainPath, VSLayout); + llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion, + WinSysRoot, VCToolChainPath, VSLayout) || + llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath, + VSLayout) || + llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolsVersion, + VCToolChainPath, VSLayout) || + llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout); } Tool *MSVCToolChain::buildLinker() const { @@ -709,453 +463,104 @@ Tool *MSVCToolChain::buildAssembler() const { return nullptr; } -bool MSVCToolChain::IsIntegratedAssemblerDefault() const { - return true; -} - -bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel +MSVCToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const { // Don't emit unwind tables by default for MachO targets. if (getTriple().isOSBinFormatMachO()) - return false; + return UnwindTableLevel::None; // All non-x86_32 Windows targets require unwind tables. However, LLVM // doesn't know how to generate them for all targets, so only enable // the ones that are actually implemented. - return getArch() == llvm::Triple::x86_64 || - getArch() == llvm::Triple::aarch64; + if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm || + getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64) + return UnwindTableLevel::Asynchronous; + + return UnwindTableLevel::None; } bool MSVCToolChain::isPICDefault() const { - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::aarch64; } -bool MSVCToolChain::isPIEDefault() const { +bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { return false; } bool MSVCToolChain::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::aarch64; } void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); -} - -void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { - CudaInstallation.print(OS); - RocmInstallation.print(OS); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } -// 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 ""; - } +void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") + + RocmInstallation->getLibPath()), + "amdhip64.lib"}); } -// 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 ""; - } +void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { + CudaInstallation->print(OS); + RocmInstallation->print(OS); } -// 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 ""; - } +std::string +MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type, + llvm::StringRef SubdirParent) const { + return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(), + SubdirParent); } -// 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, +MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type, 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()); -} - -#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 + return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch, + ""); } // Find the most recent version of Universal CRT or Windows 10 SDK. // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include // directory by name and uses the last one of the list. // So we compare entry names lexicographically to find the greatest one. -static bool getWindows10SDKVersionFromPath(llvm::vfs::FileSystem &VFS, - const std::string &SDKPath, - std::string &SDKVersion) { - llvm::SmallString<128> IncludePath(SDKPath); - llvm::sys::path::append(IncludePath, "Include"); - SDKVersion = getHighestNumericTupleInDirectory(VFS, IncludePath); - return !SDKVersion.empty(); -} - -static bool getWindowsSDKDirViaCommandLine(llvm::vfs::FileSystem &VFS, - const ArgList &Args, - std::string &Path, int &Major, - std::string &Version) { - if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir, - options::OPT__SLASH_winsysroot)) { - // Don't validate the input; trust the value supplied by the user. - // The motivation is to prevent unnecessary file and registry access. - llvm::VersionTuple SDKVersion; - if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion)) - SDKVersion.tryParse(A->getValue()); - - if (A->getOption().getID() == options::OPT__SLASH_winsysroot) { - llvm::SmallString<128> SDKPath(A->getValue()); - llvm::sys::path::append(SDKPath, "Windows Kits"); - if (!SDKVersion.empty()) - llvm::sys::path::append(SDKPath, Twine(SDKVersion.getMajor())); - else - llvm::sys::path::append( - SDKPath, getHighestNumericTupleInDirectory(VFS, SDKPath)); - Path = std::string(SDKPath.str()); - } else { - Path = A->getValue(); - } - - if (!SDKVersion.empty()) { - Major = SDKVersion.getMajor(); - Version = SDKVersion.getAsString(); - } else if (getWindows10SDKVersionFromPath(VFS, Path, Version)) { - Major = 10; - } - return true; - } - return false; -} - -/// Get Windows SDK installation directory. -static bool getWindowsSDKDir(llvm::vfs::FileSystem &VFS, const ArgList &Args, - std::string &Path, int &Major, - std::string &WindowsSDKIncludeVersion, - std::string &WindowsSDKLibVersion) { - // Trust /winsdkdir and /winsdkversion if present. - if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, - WindowsSDKIncludeVersion)) { - WindowsSDKLibVersion = WindowsSDKIncludeVersion; - return true; - } - - // FIXME: Try env vars (%WindowsSdkDir%, %UCRTVersion%) before going to registry. - - // Try the Windows registry. - std::string RegistrySDKVersion; - if (!getSystemRegistryString( - "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", - "InstallationFolder", Path, &RegistrySDKVersion)) - return false; - if (Path.empty() || RegistrySDKVersion.empty()) - return false; - - WindowsSDKIncludeVersion.clear(); - WindowsSDKLibVersion.clear(); - Major = 0; - std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major); - if (Major <= 7) - return true; - if (Major == 8) { - // Windows SDK 8.x installs libraries in a folder whose names depend on the - // version of the OS you're targeting. By default choose the newest, which - // usually corresponds to the version of the OS you've installed the SDK on. - const char *Tests[] = {"winv6.3", "win8", "win7"}; - for (const char *Test : Tests) { - llvm::SmallString<128> TestPath(Path); - llvm::sys::path::append(TestPath, "Lib", Test); - if (VFS.exists(TestPath)) { - WindowsSDKLibVersion = Test; - break; - } - } - return !WindowsSDKLibVersion.empty(); - } - if (Major == 10) { - if (!getWindows10SDKVersionFromPath(VFS, Path, WindowsSDKIncludeVersion)) - return false; - WindowsSDKLibVersion = WindowsSDKIncludeVersion; - return true; - } - // Unsupported SDK version - return false; -} - // Gets the library path required to link against the Windows SDK. -bool MSVCToolChain::getWindowsSDKLibraryPath( - const ArgList &Args, std::string &path) const { +bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args, + std::string &path) const { std::string sdkPath; int sdkMajor = 0; std::string windowsSDKIncludeVersion; std::string windowsSDKLibVersion; path.clear(); - if (!getWindowsSDKDir(getVFS(), Args, sdkPath, sdkMajor, - windowsSDKIncludeVersion, windowsSDKLibVersion)) + if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot, + sdkPath, sdkMajor, windowsSDKIncludeVersion, + windowsSDKLibVersion)) return false; llvm::SmallString<128> libPath(sdkPath); llvm::sys::path::append(libPath, "Lib"); - if (sdkMajor >= 8) { - llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", - llvmArchToWindowsSDKArch(getArch())); - } else { - switch (getArch()) { - // In Windows SDK 7.x, x86 libraries are directly in the Lib folder. - case llvm::Triple::x86: - break; - case llvm::Triple::x86_64: - llvm::sys::path::append(libPath, "x64"); - break; - case llvm::Triple::arm: - // It is not necessary to link against Windows SDK 7.x when targeting ARM. - return false; - default: - return false; - } - } - - path = std::string(libPath.str()); - return true; + if (sdkMajor >= 10) + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + windowsSDKLibVersion = *WinSdkVersion; + if (sdkMajor >= 8) + llvm::sys::path::append(libPath, windowsSDKLibVersion, "um"); + return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(), + path); } -// Check if the Include path of a specified version of Visual Studio contains -// specific header files. If not, they are probably shipped with Universal CRT. bool MSVCToolChain::useUniversalCRT() const { - llvm::SmallString<128> TestPath( - getSubDirectoryPath(SubDirectoryType::Include)); - llvm::sys::path::append(TestPath, "stdlib.h"); - return !getVFS().exists(TestPath); -} - -static bool getUniversalCRTSdkDir(llvm::vfs::FileSystem &VFS, - const ArgList &Args, std::string &Path, - std::string &UCRTVersion) { - // If /winsdkdir is passed, use it as location for the UCRT too. - // FIXME: Should there be a dedicated /ucrtdir to override /winsdkdir? - int Major; - if (getWindowsSDKDirViaCommandLine(VFS, Args, Path, Major, UCRTVersion)) - return true; - - // FIXME: Try env vars (%UniversalCRTSdkDir%, %UCRTVersion%) before going to - // registry. - - // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry - // for the specific key "KitsRoot10". So do we. - if (!getSystemRegistryString( - "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10", - Path, nullptr)) - return false; - - return getWindows10SDKVersionFromPath(VFS, Path, UCRTVersion); + return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS()); } bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args, @@ -1164,28 +569,26 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args, std::string UCRTVersion; Path.clear(); - if (!getUniversalCRTSdkDir(getVFS(), Args, UniversalCRTSdkPath, UCRTVersion)) + if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion, + WinSysRoot, UniversalCRTSdkPath, + UCRTVersion)) return false; - StringRef ArchName = llvmArchToWindowsSDKArch(getArch()); + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + UCRTVersion = *WinSdkVersion; + + StringRef ArchName = llvm::archToWindowsSDKArch(getArch()); if (ArchName.empty()) return false; llvm::SmallString<128> LibPath(UniversalCRTSdkPath); llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName); - Path = std::string(LibPath.str()); + Path = std::string(LibPath); return true; } -static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) { - unsigned Major, Minor, Micro; - Triple.getEnvironmentVersion(Major, Minor, Micro); - if (Major || Minor || Micro) - return VersionTuple(Major, Minor, Micro); - return VersionTuple(); -} - static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) { VersionTuple Version; #ifdef _WIN32 @@ -1263,6 +666,19 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, AddSystemIncludesFromEnv(Var); } + // Add DIA SDK include if requested. + if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir, + options::OPT__SLASH_winsysroot)) { + // cl.exe doesn't find the DIA SDK automatically, so this too requires + // explicit flags and doesn't automatically look in "DIA SDK" relative + // to the path we found for VCToolChainPath. + llvm::SmallString<128> DIASDKPath(A->getValue()); + if (A->getOption().getID() == options::OPT__SLASH_winsysroot) + llvm::sys::path::append(DIASDKPath, "DIA SDK"); + AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, std::string(DIASDKPath), + "include"); + } + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; @@ -1280,15 +696,20 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // the correct include paths first. if (!VCToolChainPath.empty()) { addSystemInclude(DriverArgs, CC1Args, - getSubDirectoryPath(SubDirectoryType::Include)); - addSystemInclude(DriverArgs, CC1Args, - getSubDirectoryPath(SubDirectoryType::Include, "atlmfc")); + getSubDirectoryPath(llvm::SubDirectoryType::Include)); + addSystemInclude( + DriverArgs, CC1Args, + getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc")); if (useUniversalCRT()) { std::string UniversalCRTSdkPath; std::string UCRTVersion; - if (getUniversalCRTSdkDir(getVFS(), DriverArgs, UniversalCRTSdkPath, - UCRTVersion)) { + if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion, + WinSysRoot, UniversalCRTSdkPath, + UCRTVersion)) { + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + UCRTVersion = *WinSdkVersion; AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath, "Include", UCRTVersion, "ucrt"); } @@ -1298,8 +719,13 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, int major = 0; std::string windowsSDKIncludeVersion; std::string windowsSDKLibVersion; - if (getWindowsSDKDir(getVFS(), DriverArgs, WindowsSDKDir, major, - windowsSDKIncludeVersion, windowsSDKLibVersion)) { + if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot, + WindowsSDKDir, major, windowsSDKIncludeVersion, + windowsSDKLibVersion)) { + if (major >= 10) + if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) && + WinSdkVersion.has_value()) + windowsSDKIncludeVersion = windowsSDKLibVersion = *WinSdkVersion; if (major >= 8) { // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10. // Anyway, llvm::sys::path::append is able to manage it. @@ -1312,6 +738,15 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "Include", windowsSDKIncludeVersion, "winrt"); + if (major >= 10) { + llvm::VersionTuple Tuple; + if (!Tuple.tryParse(windowsSDKIncludeVersion) && + Tuple.getSubminor().value_or(0) >= 17134) { + AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, + "Include", windowsSDKIncludeVersion, + "cppwinrt"); + } + } } else { AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir, "Include"); @@ -1345,14 +780,18 @@ VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D, bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment(); VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args); if (MSVT.empty()) - MSVT = getMSVCVersionFromTriple(getTriple()); + 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.33 is default, aka 2022, 17.3 + // NOTE: when changing this value, also update + // clang/docs/CommandGuide/clang.rst and clang/docs/UsersManual.rst + // accordingly. + MSVT = VersionTuple(19, 33); } return MSVT; } @@ -1363,8 +802,8 @@ MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args, // The MSVC version doesn't care about the architecture, even though it // may look at the triple internally. VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args); - MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0), - MSVT.getSubminor().getValueOr(0)); + MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().value_or(0), + MSVT.getSubminor().value_or(0)); // For the rest of the triple, however, a computed architecture name may // be needed. @@ -1577,7 +1016,7 @@ void MSVCToolChain::addClangTargetOptions( Action::OffloadKind DeviceOffloadKind) const { // MSVC STL kindly allows removing all usages of typeid by defining // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti - if (DriverArgs.hasArg(options::OPT_fno_rtti, options::OPT_frtti, - /*Default=*/false)) + if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti, + /*Default=*/false)) CC1Args.push_back("-D_HAS_STATIC_RTTI=0"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h index 19d94c5c606e..48369e030aad 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVC.h @@ -11,10 +11,12 @@ #include "AMDGPU.h" #include "Cuda.h" -#include "clang/Basic/DebugInfoOptions.h" +#include "LazyDetector.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/Frontend/Debug/Options.h" +#include "llvm/WindowsDriver/MSVCPaths.h" namespace clang { namespace driver { @@ -22,7 +24,7 @@ namespace tools { /// Visual studio tools. namespace visualstudio { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("visualstudio::Linker", "linker", TC) {} @@ -49,18 +51,19 @@ public: TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; - bool IsIntegratedAssemblerDefault() const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; /// Set CodeView as the default debug info format for non-MachO binary /// formats, and to DWARF otherwise. Users can use -gcodeview and -gdwarf to /// override the default. - codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override { - return getTriple().isOSBinFormatMachO() ? codegenoptions::DIF_DWARF - : codegenoptions::DIF_CodeView; + llvm::codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override { + return getTriple().isOSBinFormatMachO() + ? llvm::codegenoptions::DIF_DWARF + : llvm::codegenoptions::DIF_CodeView; } /// Set the debugger tuning to "default", since we're definitely not tuning @@ -69,29 +72,19 @@ public: return llvm::DebuggerKind::Default; } - enum class SubDirectoryType { - Bin, - Include, - Lib, - }; - std::string getSubDirectoryPath(SubDirectoryType Type, - llvm::StringRef SubdirParent, + unsigned GetDefaultDwarfVersion() const override { + return 4; + } + + 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; @@ -105,6 +98,9 @@ public: void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPRuntimeLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + bool getWindowsSDKLibraryPath( const llvm::opt::ArgList &Args, std::string &path) const; bool getUniversalCRTLibraryPath(const llvm::opt::ArgList &Args, @@ -138,10 +134,11 @@ protected: Tool *buildLinker() const override; Tool *buildAssembler() const override; private: + std::optional<llvm::StringRef> WinSdkDir, WinSdkVersion, WinSysRoot; std::string VCToolChainPath; - ToolsetLayout VSLayout = ToolsetLayout::OlderVS; - CudaInstallationDetector CudaInstallation; - RocmInstallationDetector RocmInstallation; + llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS; + LazyDetector<CudaInstallationDetector> CudaInstallation; + LazyDetector<RocmInstallationDetector> RocmInstallation; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h deleted file mode 100644 index a890b85fd5e9..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MSVCSetupApi.h +++ /dev/null @@ -1,514 +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 - -// 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 diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp index 7ba729f36bd8..067758c05e97 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/contrib/llvm-project/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).starts_with("msvcr") || + StringRef(Lib).starts_with("ucrt") || + StringRef(Lib).starts_with("crtdll")) return; CmdArgs.push_back("-lmsvcrt"); } @@ -98,7 +100,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { const ToolChain &TC = getToolChain(); const Driver &D = TC.getDriver(); - const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); + const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args); ArgStringList CmdArgs; @@ -133,7 +135,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("arm64pe"); break; default: - llvm_unreachable("Unsupported target architecture."); + D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str(); } Arg *SubsysArg = @@ -164,6 +166,24 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--enable-auto-image-base"); } + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + + if (!Args.hasFlag(options::OPT_fauto_import, options::OPT_fno_auto_import, + true)) + CmdArgs.push_back("--disable-auto-import"); + + if (Arg *A = Args.getLastArg(options::OPT_mguard_EQ)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs == "none") + CmdArgs.push_back("--no-guard-cf"); + else if (GuardArgs == "cf" || GuardArgs == "cf-nochecks") + CmdArgs.push_back("--guard-cf"); + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << GuardArgs; + } + CmdArgs.push_back("-o"); const char *OutputFile = Output.getFilename(); // GCC implicitly adds an .exe extension if it is given an output file name @@ -176,13 +196,21 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, } else CmdArgs.push_back(OutputFile); - Args.AddAllArgs(CmdArgs, options::OPT_e); // FIXME: add -N, -n flags Args.AddLastArg(CmdArgs, options::OPT_r); Args.AddLastArg(CmdArgs, options::OPT_s); Args.AddLastArg(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_u_Group); - Args.AddLastArg(CmdArgs, options::OPT_Z_Flag); + + // Add asan_dynamic as the first import lib before other libs. This allows + // asan to be initialized as early as possible to increase its instrumentation + // coverage to include other user DLLs which has not been built with asan. + if (Sanitize.needsAsanRt() && !Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + // MinGW always links against a shared MSVCRT. + CmdArgs.push_back( + TC.getCompilerRTArgString(Args, "asan_dynamic", ToolChain::FT_Shared)); + } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) { @@ -213,6 +241,17 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + addLTOOptions(TC, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } + + if (C.getDriver().IsFlangMode()) { + addFortranRuntimeLibraryPath(TC, Args, CmdArgs); + addFortranRuntimeLibs(TC, Args, CmdArgs); + } + // TODO: Add profile stuff here if (TC.ShouldLinkCXXStdlib(Args)) { @@ -327,10 +366,20 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, Exec, CmdArgs, Inputs, Output)); } +static bool isCrossCompiling(const llvm::Triple &T, bool RequireArchMatch) { + llvm::Triple HostTriple(llvm::Triple::normalize(LLVM_HOST_TRIPLE)); + if (HostTriple.getOS() != llvm::Triple::Win32) + return true; + if (RequireArchMatch && HostTriple.getArch() != T.getArch()) + return true; + return false; +} + // Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple. static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, - std::string &Ver) { - auto Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0"); + std::string &Ver, + toolchains::Generic_GCC::GCCVersion &Version) { + Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0"); std::error_code EC; for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { @@ -348,31 +397,51 @@ static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, return Ver.size(); } -void toolchains::MinGW::findGccLibDir() { - llvm::SmallVector<llvm::SmallString<32>, 2> Archs; - Archs.emplace_back(getTriple().getArchName()); - Archs[0] += "-w64-mingw32"; - Archs.emplace_back("mingw32"); - if (Arch.empty()) - Arch = std::string(Archs[0].str()); +static llvm::Triple getLiteralTriple(const Driver &D, const llvm::Triple &T) { + llvm::Triple LiteralTriple(D.getTargetTriple()); + // The arch portion of the triple may be overridden by -m32/-m64. + LiteralTriple.setArchName(T.getArchName()); + return LiteralTriple; +} + +void toolchains::MinGW::findGccLibDir(const llvm::Triple &LiteralTriple) { + llvm::SmallVector<llvm::SmallString<32>, 5> SubdirNames; + SubdirNames.emplace_back(LiteralTriple.str()); + SubdirNames.emplace_back(getTriple().str()); + SubdirNames.emplace_back(getTriple().getArchName()); + SubdirNames.back() += "-w64-mingw32"; + SubdirNames.emplace_back(getTriple().getArchName()); + SubdirNames.back() += "-w64-mingw32ucrt"; + SubdirNames.emplace_back("mingw32"); + if (SubdirName.empty()) { + SubdirName = getTriple().getArchName(); + SubdirName += "-w64-mingw32"; + } // lib: Arch Linux, Ubuntu, Windows // lib64: openSUSE Linux for (StringRef CandidateLib : {"lib", "lib64"}) { - for (StringRef CandidateArch : Archs) { + for (StringRef CandidateSysroot : SubdirNames) { llvm::SmallString<1024> LibDir(Base); - llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch); - if (findGccVersion(LibDir, GccLibDir, Ver)) { - Arch = std::string(CandidateArch); + llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot); + if (findGccVersion(LibDir, GccLibDir, Ver, GccVer)) { + SubdirName = std::string(CandidateSysroot); return; } } } } -llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() { - llvm::SmallVector<llvm::SmallString<32>, 2> Gccs; - Gccs.emplace_back(getTriple().getArchName()); - Gccs[0] += "-w64-mingw32-gcc"; +static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &LiteralTriple, + const llvm::Triple &T) { + llvm::SmallVector<llvm::SmallString<32>, 5> Gccs; + Gccs.emplace_back(LiteralTriple.str()); + Gccs.back() += "-gcc"; + Gccs.emplace_back(T.str()); + Gccs.back() += "-gcc"; + Gccs.emplace_back(T.getArchName()); + Gccs.back() += "-w64-mingw32-gcc"; + Gccs.emplace_back(T.getArchName()); + Gccs.back() += "-w64-mingw32ucrt-gcc"; Gccs.emplace_back("mingw32-gcc"); // Please do not add "gcc" here for (StringRef CandidateGcc : Gccs) @@ -381,60 +450,98 @@ llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() { return make_error_code(std::errc::no_such_file_or_directory); } -llvm::ErrorOr<std::string> toolchains::MinGW::findClangRelativeSysroot() { - llvm::SmallVector<llvm::SmallString<32>, 2> Subdirs; - Subdirs.emplace_back(getTriple().str()); - Subdirs.emplace_back(getTriple().getArchName()); - Subdirs[1] += "-w64-mingw32"; - StringRef ClangRoot = - llvm::sys::path::parent_path(getDriver().getInstalledDir()); +static llvm::ErrorOr<std::string> +findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple, + const llvm::Triple &T, std::string &SubdirName) { + llvm::SmallVector<llvm::SmallString<32>, 4> Subdirs; + Subdirs.emplace_back(LiteralTriple.str()); + Subdirs.emplace_back(T.str()); + Subdirs.emplace_back(T.getArchName()); + Subdirs.back() += "-w64-mingw32"; + Subdirs.emplace_back(T.getArchName()); + Subdirs.back() += "-w64-mingw32ucrt"; + StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir()); StringRef Sep = llvm::sys::path::get_separator(); for (StringRef CandidateSubdir : Subdirs) { if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) { - Arch = std::string(CandidateSubdir); + SubdirName = std::string(CandidateSubdir); return (ClangRoot + Sep + CandidateSubdir).str(); } } return make_error_code(std::errc::no_such_file_or_directory); } +static bool looksLikeMinGWSysroot(const std::string &Directory) { + StringRef Sep = llvm::sys::path::get_separator(); + if (!llvm::sys::fs::exists(Directory + Sep + "include" + Sep + "_mingw.h")) + return false; + if (!llvm::sys::fs::exists(Directory + Sep + "lib" + Sep + "libkernel32.a")) + return false; + return true; +} + toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); + std::string InstallBase = + std::string(llvm::sys::path::parent_path(getDriver().getInstalledDir())); + // The sequence for detecting a sysroot here should be kept in sync with + // the testTriple function below. + llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple()); if (getDriver().SysRoot.size()) Base = getDriver().SysRoot; // Look for <clang-bin>/../<triplet>; if found, use <clang-bin>/.. as the // base as it could still be a base for a gcc setup with libgcc. - else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot()) + else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot( + getDriver(), LiteralTriple, getTriple(), SubdirName)) Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); - else if (llvm::ErrorOr<std::string> GPPName = findGcc()) + // If the install base of Clang seems to have mingw sysroot files directly + // in the toplevel include and lib directories, use this as base instead of + // looking for a triple prefixed GCC in the path. + else if (looksLikeMinGWSysroot(InstallBase)) + Base = InstallBase; + else if (llvm::ErrorOr<std::string> GPPName = + findGcc(LiteralTriple, getTriple())) Base = std::string(llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get()))); else - Base = std::string( - llvm::sys::path::parent_path(getDriver().getInstalledDir())); + Base = InstallBase; Base += llvm::sys::path::get_separator(); - findGccLibDir(); + findGccLibDir(LiteralTriple); + TripleDirName = SubdirName; // GccLibDir must precede Base/lib so that the // correct crtbegin.o ,cetend.o would be found. getFilePaths().push_back(GccLibDir); + + // openSUSE/Fedora + std::string CandidateSubdir = SubdirName + "/sys-root/mingw"; + if (getDriver().getVFS().exists(Base + CandidateSubdir)) + SubdirName = CandidateSubdir; + + getFilePaths().push_back( + (Base + SubdirName + llvm::sys::path::get_separator() + "lib").str()); + + // Gentoo getFilePaths().push_back( - (Base + Arch + llvm::sys::path::get_separator() + "lib").str()); - getFilePaths().push_back(Base + "lib"); - // openSUSE - getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib"); + (Base + SubdirName + llvm::sys::path::get_separator() + "mingw/lib").str()); + + // Only include <base>/lib if we're not cross compiling (not even for + // windows->windows to a different arch), or if the sysroot has been set + // (where we presume the user has pointed it at an arch specific + // subdirectory). + if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/true) || + getDriver().SysRoot.size()) + getFilePaths().push_back(Base + "lib"); NativeLLVMSupport = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER) .equals_insensitive("lld"); } -bool toolchains::MinGW::IsIntegratedAssemblerDefault() const { return true; } - Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const { switch (AC) { case Action::PreprocessJobClass: @@ -462,30 +569,36 @@ bool toolchains::MinGW::HasNativeLLVMSupport() const { return NativeLLVMSupport; } -bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const { +ToolChain::UnwindTableLevel +toolchains::MinGW::getDefaultUnwindTableLevel(const ArgList &Args) const { Arg *ExceptionArg = Args.getLastArg(options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions, options::OPT_fdwarf_exceptions); if (ExceptionArg && ExceptionArg->getOption().matches(options::OPT_fseh_exceptions)) - return true; - return getArch() == llvm::Triple::x86_64 || - getArch() == llvm::Triple::aarch64; + return UnwindTableLevel::Asynchronous; + + if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm || + getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64) + return UnwindTableLevel::Asynchronous; + return UnwindTableLevel::None; } bool toolchains::MinGW::isPICDefault() const { - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::aarch64; } -bool toolchains::MinGW::isPIEDefault() const { return false; } - -bool toolchains::MinGW::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64; +bool toolchains::MinGW::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; } +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; } @@ -501,17 +614,17 @@ SanitizerMask toolchains::MinGW::getSupportedSanitizers() const { void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); + CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args); } void toolchains::MinGW::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); + RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); } void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const { - CudaInstallation.print(OS); - RocmInstallation.print(OS); + CudaInstallation->print(OS); + RocmInstallation->print(OS); } // Include directories for various hosts: @@ -554,6 +667,12 @@ void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const { // /usr/include/c++/4.8/backward // /usr/x86_64-w64-mingw32/include +// Fedora +// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/x86_64-w64-mingw32ucrt +// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/backward +// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include +// /usr/lib/gcc/x86_64-w64-mingw32ucrt/12.2.1/include-fixed + void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc)) @@ -568,49 +687,159 @@ void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; - if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) { - // openSUSE - addSystemInclude(DriverArgs, CC1Args, - Base + Arch + "/sys-root/mingw/include"); - } + addSystemInclude(DriverArgs, CC1Args, + Base + SubdirName + llvm::sys::path::get_separator() + + "include"); + // Gentoo addSystemInclude(DriverArgs, CC1Args, - Base + Arch + llvm::sys::path::get_separator() + "include"); - addSystemInclude(DriverArgs, CC1Args, Base + "include"); + Base + SubdirName + llvm::sys::path::get_separator() + "usr/include"); + + // Only include <base>/include if we're not cross compiling (but do allow it + // if we're on Windows and building for Windows on another architecture), + // or if the sysroot has been set (where we presume the user has pointed it + // at an arch specific subdirectory). + if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/false) || + getDriver().SysRoot.size()) + addSystemInclude(DriverArgs, CC1Args, Base + "include"); +} + +void toolchains::MinGW::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { + if (Arg *A = DriverArgs.getLastArg(options::OPT_mguard_EQ)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs == "none") { + // Do nothing. + } else if (GuardArgs == "cf") { + // Emit CFG instrumentation and the table of address-taken functions. + CC1Args.push_back("-cfguard"); + } else if (GuardArgs == "cf-nochecks") { + // Emit only the table of address-taken functions. + CC1Args.push_back("-cfguard-no-checks"); + } else { + getDriver().Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << GuardArgs; + } + } + + CC1Args.push_back("-fno-use-init-array"); + + for (auto Opt : {options::OPT_mthreads, options::OPT_mwindows, + options::OPT_mconsole, options::OPT_mdll}) { + if (Arg *A = DriverArgs.getLastArgNoClaim(Opt)) + A->ignoreTargetSpecific(); + } } void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) + if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, + options::OPT_nostdincxx)) return; StringRef Slash = llvm::sys::path::get_separator(); switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: - addSystemInclude(DriverArgs, CC1Args, Base + Arch + Slash + "include" + - Slash + "c++" + Slash + "v1"); + case ToolChain::CST_Libcxx: { + std::string TargetDir = (Base + "include" + Slash + getTripleString() + + Slash + "c++" + Slash + "v1") + .str(); + if (getDriver().getVFS().exists(TargetDir)) + addSystemInclude(DriverArgs, CC1Args, TargetDir); + addSystemInclude(DriverArgs, CC1Args, + Base + SubdirName + Slash + "include" + Slash + "c++" + + Slash + "v1"); addSystemInclude(DriverArgs, CC1Args, Base + "include" + Slash + "c++" + Slash + "v1"); break; + } case ToolChain::CST_Libstdcxx: - llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases; + llvm::SmallVector<llvm::SmallString<1024>, 7> CppIncludeBases; CppIncludeBases.emplace_back(Base); - llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++"); + llvm::sys::path::append(CppIncludeBases[0], SubdirName, "include", "c++"); CppIncludeBases.emplace_back(Base); - llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver); + llvm::sys::path::append(CppIncludeBases[1], SubdirName, "include", "c++", + Ver); CppIncludeBases.emplace_back(Base); llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver); CppIncludeBases.emplace_back(GccLibDir); llvm::sys::path::append(CppIncludeBases[3], "include", "c++"); + CppIncludeBases.emplace_back(GccLibDir); + llvm::sys::path::append(CppIncludeBases[4], "include", + "g++-v" + GccVer.Text); + CppIncludeBases.emplace_back(GccLibDir); + llvm::sys::path::append(CppIncludeBases[5], "include", + "g++-v" + GccVer.MajorStr + "." + GccVer.MinorStr); + CppIncludeBases.emplace_back(GccLibDir); + llvm::sys::path::append(CppIncludeBases[6], "include", + "g++-v" + GccVer.MajorStr); for (auto &CppIncludeBase : CppIncludeBases) { addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); CppIncludeBase += Slash; - addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + TripleDirName); addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); } break; } } + +static bool testTriple(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) { + // If an explicit sysroot is set, that will be used and we shouldn't try to + // detect anything else. + std::string SubdirName; + if (D.SysRoot.size()) + return true; + llvm::Triple LiteralTriple = getLiteralTriple(D, Triple); + std::string InstallBase = + std::string(llvm::sys::path::parent_path(D.getInstalledDir())); + if (llvm::ErrorOr<std::string> TargetSubdir = + findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName)) + return true; + // If the install base itself looks like a mingw sysroot, we'll use that + // - don't use any potentially unrelated gcc to influence what triple to use. + if (looksLikeMinGWSysroot(InstallBase)) + return false; + if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, Triple)) + return true; + // If we neither found a colocated sysroot or a matching gcc executable, + // conclude that we can't know if this is the correct spelling of the triple. + return false; +} + +static llvm::Triple adjustTriple(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) { + // First test if the original triple can find a sysroot with the triple + // name. + if (testTriple(D, Triple, Args)) + return Triple; + llvm::SmallVector<llvm::StringRef, 3> Archs; + // If not, test a couple other possible arch names that might be what was + // intended. + if (Triple.getArch() == llvm::Triple::x86) { + Archs.emplace_back("i386"); + Archs.emplace_back("i586"); + Archs.emplace_back("i686"); + } else if (Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb) { + Archs.emplace_back("armv7"); + } + for (auto A : Archs) { + llvm::Triple TestTriple(Triple); + TestTriple.setArchName(A); + if (testTriple(D, TestTriple, Args)) + return TestTriple; + } + // If none was found, just proceed with the original value. + return Triple; +} + +void toolchains::MinGW::fixTripleArch(const Driver &D, llvm::Triple &Triple, + const ArgList &Args) { + if (Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb) + Triple = adjustTriple(D, Triple, Args); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h index 2f1559fcf34c..a9963d8d06c2 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MinGW.h @@ -11,6 +11,7 @@ #include "Cuda.h" #include "Gnu.h" +#include "LazyDetector.h" #include "ROCm.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" @@ -20,7 +21,7 @@ namespace clang { namespace driver { namespace tools { -/// MinGW -- Directly call GNU Binutils assembler and linker +/// Directly call GNU Binutils assembler and linker namespace MinGW { class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: @@ -34,7 +35,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("MinGW::Linker", "linker", TC) {} @@ -60,12 +61,15 @@ public: MinGW(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); + static void fixTripleArch(const Driver &D, llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + bool HasNativeLLVMSupport() const override; - bool IsIntegratedAssemblerDefault() const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; SanitizerMask getSupportedSanitizers() const override; @@ -76,6 +80,10 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -87,24 +95,26 @@ 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; Tool *buildAssembler() const override; private: - CudaInstallationDetector CudaInstallation; - RocmInstallationDetector RocmInstallation; + LazyDetector<CudaInstallationDetector> CudaInstallation; + LazyDetector<RocmInstallationDetector> RocmInstallation; std::string Base; std::string GccLibDir; + clang::driver::toolchains::Generic_GCC::GCCVersion GccVer; std::string Ver; - std::string Arch; + std::string SubdirName; + std::string TripleDirName; mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; mutable std::unique_ptr<tools::gcc::Compiler> Compiler; - void findGccLibDir(); - llvm::ErrorOr<std::string> findGcc(); - llvm::ErrorOr<std::string> findClangRelativeSysroot(); + void findGccLibDir(const llvm::Triple &LiteralTriple); bool NativeLLVMSupport; }; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp deleted file mode 100644 index 5bceb9aba3e9..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.cpp +++ /dev/null @@ -1,113 +0,0 @@ -//===--- Minix.cpp - Minix ToolChain Implementations ------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Minix.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/InputInfo.h" -#include "clang/Driver/Options.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Support/VirtualFileSystem.h" - -using namespace clang::driver; -using namespace clang; -using namespace llvm::opt; - -void tools::minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - for (const auto &II : Inputs) - CmdArgs.push_back(II.getFilename()); - - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); - ArgStringList CmdArgs; - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - } - - Args.AddAllArgs(CmdArgs, - {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - getToolChain().addProfileRTLibs(Args, CmdArgs); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) { - if (getToolChain().ShouldLinkCXXStdlib(Args)) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-lm"); - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lCompilerRT-Generic"); - CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib"); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - } - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Exec, CmdArgs, Inputs, Output)); -} - -/// Minix - Minix tool chain which can call as(1) and ld(1) directly. - -toolchains::Minix::Minix(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().Dir + "/../lib"); - getFilePaths().push_back("/usr/lib"); -} - -Tool *toolchains::Minix::buildAssembler() const { - return new tools::minix::Assembler(*this); -} - -Tool *toolchains::Minix::buildLinker() const { - return new tools::minix::Linker(*this); -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h deleted file mode 100644 index af8d59c5085a..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Minix.h +++ /dev/null @@ -1,64 +0,0 @@ -//===--- Minix.h - Minix ToolChain Implementations --------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H - -#include "Gnu.h" -#include "clang/Driver/Tool.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { -/// minix -- Directly call GNU Binutils assembler and linker -namespace minix { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("minix::Assembler", "assembler", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { -public: - Linker(const ToolChain &TC) : Tool("minix::Linker", "linker", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace minix -} // end namespace tools - -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF { -public: - Minix(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp index 41b7b839f3b3..4183eccceedb 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp @@ -30,7 +30,7 @@ MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D, DetectedMultilibs Result; findMIPSMultilibs(D, Triple, "", Args, Result); Multilibs = Result.Multilibs; - SelectedMultilib = Result.SelectedMultilib; + SelectedMultilibs = Result.SelectedMultilibs; // Find out the library suffix based on the ABI. LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple); @@ -56,7 +56,7 @@ void MipsLLVMToolChain::AddClangSystemIncludeArgs( const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { - for (const auto &Path : Callback(SelectedMultilib)) + for (const auto &Path : Callback(SelectedMultilibs.back())) addExternCSystemIncludeIfExists(DriverArgs, CC1Args, D.getInstalledDir() + Path); } @@ -68,11 +68,11 @@ Tool *MipsLLVMToolChain::buildLinker() const { std::string MipsLLVMToolChain::computeSysRoot() const { if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot + SelectedMultilib.osSuffix(); + return getDriver().SysRoot + SelectedMultilibs.back().osSuffix(); const std::string InstalledDir(getDriver().getInstalledDir()); std::string SysRootPath = - InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix(); + InstalledDir + "/../sysroot" + SelectedMultilibs.back().osSuffix(); if (llvm::sys::fs::exists(SysRootPath)) return SysRootPath; @@ -96,7 +96,7 @@ void MipsLLVMToolChain::addLibCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { if (const auto &Callback = Multilibs.includeDirsCallback()) { - for (std::string Path : Callback(SelectedMultilib)) { + for (std::string Path : Callback(SelectedMultilibs.back())) { Path = getDriver().getInstalledDir() + Path + "/c++/v1"; if (llvm::sys::fs::exists(Path)) { addSystemInclude(DriverArgs, CC1Args, Path); @@ -112,6 +112,8 @@ void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, "Only -lc++ (aka libxx) is supported in this toolchain."); CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); } @@ -120,7 +122,7 @@ std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, StringRef Component, FileType Type) const { SmallString<128> Path(getDriver().ResourceDir); - llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix, + llvm::sys::path::append(Path, SelectedMultilibs.back().osSuffix(), "lib" + LibSuffix, getOS()); const char *Suffix; switch (Type) { @@ -136,5 +138,5 @@ std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, } llvm::sys::path::append( Path, Twine("libclang_rt." + Component + "-" + "mips" + Suffix)); - return std::string(Path.str()); + return std::string(Path); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h index 31b547c0063c..a968804f2a6e 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.h @@ -53,7 +53,6 @@ public: } private: - Multilib SelectedMultilib; std::string LibSuffix; }; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp deleted file mode 100644 index f31466633104..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.cpp +++ /dev/null @@ -1,293 +0,0 @@ -//===--- Myriad.cpp - Myriad ToolChain Implementations ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Myriad.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/Options.h" -#include "llvm/Option/ArgList.h" - -using namespace clang::driver; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -using tools::addPathIfExists; - -void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - assert(Inputs.size() == 1); - const InputInfo &II = Inputs[0]; - assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX || - II.getType() == types::TY_PP_CXX); - - if (JA.getKind() == Action::PreprocessJobClass) { - Args.ClaimAllArgs(); - CmdArgs.push_back("-E"); - } else { - assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. - CmdArgs.push_back("-S"); - CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. - } - CmdArgs.push_back("-DMYRIAD2"); - - // Append all -I, -iquote, -isystem paths, defines/undefines, 'f' - // flags, 'g' flags, 'M' flags, optimize flags, warning options, - // mcpu flags, mllvm flags, and Xclang flags. - // These are spelled the same way in clang and moviCompile. - Args.AddAllArgsExcept( - CmdArgs, - {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ, - options::OPT_D, options::OPT_U, options::OPT_f_Group, - options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group, - options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ, - options::OPT_mllvm, options::OPT_Xclang}, - {options::OPT_fno_split_dwarf_inlining}); - Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. - - // If we're producing a dependency file, and assembly is the final action, - // then the name of the target in the dependency file should be the '.o' - // file, not the '.s' file produced by this step. For example, instead of - // /tmp/mumble.s: mumble.c .../someheader.h - // the filename on the lefthand side should be "mumble.o" - if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && - C.getActions().size() == 1 && - C.getActions()[0]->getKind() == Action::AssembleJobClass) { - Arg *A = Args.getLastArg(options::OPT_o); - if (A) { - CmdArgs.push_back("-MT"); - CmdArgs.push_back(Args.MakeArgString(A->getValue())); - } - } - - CmdArgs.push_back(II.getFilename()); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - std::string Exec = - Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Args.MakeArgString(Exec), CmdArgs, - Inputs, Output)); -} - -void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - assert(Inputs.size() == 1); - const InputInfo &II = Inputs[0]; - assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input. - assert(Output.getType() == types::TY_Object); - - CmdArgs.push_back("-no6thSlotCompression"); - const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); - if (CPUArg) - CmdArgs.push_back( - Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue()))); - CmdArgs.push_back("-noSPrefixing"); - CmdArgs.push_back("-a"); // Mystery option. - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) { - A->claim(); - CmdArgs.push_back( - Args.MakeArgString(std::string("-i:") + A->getValue(0))); - } - CmdArgs.push_back(II.getFilename()); - CmdArgs.push_back( - Args.MakeArgString(std::string("-o:") + Output.getFilename())); - - std::string Exec = - Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Args.MakeArgString(Exec), CmdArgs, - Inputs, Output)); -} - -void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const auto &TC = - static_cast<const toolchains::MyriadToolChain &>(getToolChain()); - const llvm::Triple &T = TC.getTriple(); - ArgStringList CmdArgs; - bool UseStartfiles = - !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); - bool UseDefaultLibs = - !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); - // Silence warning if the args contain both -nostdlib and -stdlib=. - Args.getLastArg(options::OPT_stdlib_EQ); - - if (T.getArch() == llvm::Triple::sparc) - CmdArgs.push_back("-EB"); - else // SHAVE assumes little-endian, and sparcel is expressly so. - CmdArgs.push_back("-EL"); - - // The remaining logic is mostly like gnutools::Linker::ConstructJob, - // but we never pass through a --sysroot option and various other bits. - // For example, there are no sanitizers (yet) nor gold linker. - - // Eat some arguments that may be present but have no effect. - Args.ClaimAllArgs(options::OPT_g_Group); - Args.ClaimAllArgs(options::OPT_w); - Args.ClaimAllArgs(options::OPT_static_libgcc); - - if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. - CmdArgs.push_back("-s"); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - if (UseStartfiles) { - // If you want startfiles, it means you want the builtin crti and crtbegin, - // but not crt0. Myriad link commands provide their own crt0.o as needed. - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); - } - - Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_e, options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_r}); - - TC.AddFilePathLibArgs(Args, CmdArgs); - - bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - if (UseDefaultLibs) { - if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(TC, CmdArgs); - if (C.getDriver().CCCIsCXX()) { - if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - } else - CmdArgs.push_back("-lstdc++"); - } - if (T.getOS() == llvm::Triple::RTEMS) { - CmdArgs.push_back("--start-group"); - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lgcc"); // circularly dependent on rtems - // You must provide your own "-L" option to enable finding these. - CmdArgs.push_back("-lrtemscpu"); - CmdArgs.push_back("-lrtemsbsp"); - CmdArgs.push_back("--end-group"); - } else { - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lgcc"); - } - } - if (UseStartfiles) { - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); - } - - std::string Exec = - Args.MakeArgString(TC.GetProgramPath("sparc-myriad-rtems-ld")); - C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Exec), - CmdArgs, Inputs, Output)); -} - -MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use - // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple. - // This won't work to find gcc. Instead we give the installation detector an - // extra triple, which is preferable to further hacks of the logic that at - // present is based solely on getArch(). In particular, it would be wrong to - // choose the myriad installation when targeting a non-myriad sparc install. - switch (Triple.getArch()) { - default: - D.Diag(clang::diag::err_target_unsupported_arch) - << Triple.getArchName() << "myriad"; - LLVM_FALLTHROUGH; - case llvm::Triple::shave: - return; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - GCCInstallation.init(Triple, Args, {"sparc-myriad-rtems"}); - } - - if (GCCInstallation.isValid()) { - // This directory contains crt{i,n,begin,end}.o as well as libgcc. - // These files are tied to a particular version of gcc. - SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); - addPathIfExists(D, CompilerSupportDir, getFilePaths()); - } - // libstd++ and libc++ must both be found in this one place. - addPathIfExists(D, D.Dir + "/../sparc-myriad-rtems/lib", getFilePaths()); -} - -MyriadToolChain::~MyriadToolChain() {} - -void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) - addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); -} - -void MyriadToolChain::addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - std::string Path(getDriver().getInstalledDir()); - addSystemInclude(DriverArgs, CC1Args, Path + "/../include/c++/v1"); -} - -void MyriadToolChain::addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - StringRef LibDir = GCCInstallation.getParentLibPath(); - const GCCVersion &Version = GCCInstallation.getVersion(); - StringRef TripleStr = GCCInstallation.getTriple().str(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - addLibStdCXXIncludePaths( - LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, - TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args); -} - -// MyriadToolChain handles several triples: -// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf -Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { - // The inherited method works fine if not targeting the SHAVE. - if (!isShaveCompilation(getTriple())) - return ToolChain::SelectTool(JA); - switch (JA.getKind()) { - case Action::PreprocessJobClass: - case Action::CompileJobClass: - if (!Compiler) - Compiler.reset(new tools::SHAVE::Compiler(*this)); - return Compiler.get(); - case Action::AssembleJobClass: - if (!Assembler) - Assembler.reset(new tools::SHAVE::Assembler(*this)); - return Assembler.get(); - default: - return ToolChain::getTool(JA.getKind()); - } -} - -Tool *MyriadToolChain::buildLinker() const { - return new tools::Myriad::Linker(*this); -} - -SanitizerMask MyriadToolChain::getSupportedSanitizers() const { - return SanitizerKind::Address; -} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h deleted file mode 100644 index cae574bdcfea..000000000000 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Myriad.h +++ /dev/null @@ -1,103 +0,0 @@ -//===--- Myriad.h - Myriad ToolChain Implementations ------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H - -#include "Gnu.h" -#include "clang/Driver/Tool.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { - -/// SHAVE tools -- Directly call moviCompile and moviAsm -namespace SHAVE { -class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { -public: - Compiler(const ToolChain &TC) : Tool("moviCompile", "movicompile", TC) {} - - bool hasIntegratedCPP() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("moviAsm", "moviAsm", TC) {} - - bool hasIntegratedCPP() const override { return false; } // not sure. - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace SHAVE - -/// The Myriad toolchain uses tools that are in two different namespaces. -/// The Compiler and Assembler as defined above are in the SHAVE namespace, -/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE, -/// is in the Myriad namespace. -namespace Myriad { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { -public: - Linker(const ToolChain &TC) : Tool("shave::Linker", "ld", TC) {} - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace Myriad -} // end namespace tools - -namespace toolchains { - -/// MyriadToolChain - A tool chain using either clang or the external compiler -/// installed by the Movidius SDK to perform all subcommands. -class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_ELF { -public: - MyriadToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~MyriadToolChain() override; - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - Tool *SelectTool(const JobAction &JA) const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } - SanitizerMask getSupportedSanitizers() const override; - -protected: - Tool *buildLinker() const override; - bool isShaveCompilation(const llvm::Triple &T) const { - return T.getArch() == llvm::Triple::shave; - } - -private: - mutable std::unique_ptr<Tool> Compiler; - mutable std::unique_ptr<Tool> Assembler; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp index 753459cb230b..22f038e5152f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp @@ -31,8 +31,7 @@ void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::NaClToolChain &ToolChain = - static_cast<const toolchains::NaClToolChain &>(getToolChain()); + const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain()); InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(), "nacl-arm-macros.s"); InputInfoList NewInputs; @@ -52,8 +51,7 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::NaClToolChain &ToolChain = - static_cast<const toolchains::NaClToolChain &>(getToolChain()); + const auto &ToolChain = static_cast<const NaClToolChain &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsStatic = @@ -120,8 +118,7 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); ToolChain.AddFilePathLibArgs(Args, CmdArgs); @@ -308,6 +305,8 @@ void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, // if the value is libc++, and emits an error for other values. GetCXXStdlibType(Args); CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); } void NaClToolChain::addLibCxxIncludePaths( diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h index 5e5fdb583bb6..01d4719e7b92 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.h @@ -27,7 +27,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("NaCl::Linker", "linker", TC) {} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp index 1ce5a2a203c2..240bf5764b9c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -11,6 +11,7 @@ #include "Arch/Mips.h" #include "Arch/Sparc.h" #include "CommonArgs.h" +#include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" @@ -29,12 +30,16 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - claimNoWarnArgs(Args); + const auto &ToolChain = static_cast<const NetBSD &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); ArgStringList CmdArgs; + claimNoWarnArgs(Args); + // GNU as needs different flags for creating the correct output format // on architectures with different ABIs or optional feature sets. - switch (getToolChain().getArch()) { + switch (ToolChain.getArch()) { case llvm::Triple::x86: CmdArgs.push_back("--32"); break; @@ -44,8 +49,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::thumbeb: { StringRef MArch, MCPU; arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); - std::string Arch = - arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple()); + std::string Arch = arm::getARMTargetCPU(MCPU, MArch, Triple); CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); break; } @@ -56,7 +60,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); @@ -64,29 +68,28 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mabi"); CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - if (getToolChain().getTriple().isLittleEndian()) + if (Triple.isLittleEndian()) CmdArgs.push_back("-EL"); else CmdArgs.push_back("-EB"); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } - case llvm::Triple::sparc: - case llvm::Triple::sparcel: { + case llvm::Triple::sparc: { CmdArgs.push_back("-32"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + std::string CPU = getCPUName(D, Args, Triple); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + std::string CPU = getCPUName(D, Args, Triple); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } @@ -102,7 +105,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as"))); + const char *Exec = Args.MakeArgString((ToolChain.GetProgramPath("as"))); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -113,27 +116,31 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::NetBSD &ToolChain = - static_cast<const toolchains::NetBSD &>(getToolChain()); + const auto &ToolChain = static_cast<const NetBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool Static = Args.hasArg(options::OPT_static); + const bool Shared = Args.hasArg(options::OPT_shared); + const bool Pie = Args.hasArg(options::OPT_pie); ArgStringList CmdArgs; if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_static)) { + if (Static) { CmdArgs.push_back("-Bstatic"); - if (Args.hasArg(options::OPT_pie)) { + if (Pie) { Args.AddAllArgs(CmdArgs, options::OPT_pie); CmdArgs.push_back("--no-dynamic-linker"); } } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-Bshareable"); - } else { + if (Shared) { + CmdArgs.push_back("-shared"); + } else if (!Args.hasArg(options::OPT_r)) { Args.AddAllArgs(CmdArgs, options::OPT_pie); CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld.elf_so"); @@ -142,7 +149,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Many NetBSD architectures support more than one ABI. // Determine the correct emulation for ld. - switch (ToolChain.getArch()) { + switch (Arch) { case llvm::Triple::x86: CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); @@ -150,7 +157,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::arm: case llvm::Triple::thumb: CmdArgs.push_back("-m"); - switch (ToolChain.getTriple().getEnvironment()) { + switch (Triple.getEnvironment()) { case llvm::Triple::EABI: case llvm::Triple::GNUEABI: CmdArgs.push_back("armelf_nbsd_eabi"); @@ -168,7 +175,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::thumbeb: arm::appendBE8LinkFlag(Args, CmdArgs, ToolChain.getEffectiveTriple()); CmdArgs.push_back("-m"); - switch (ToolChain.getTriple().getEnvironment()) { + switch (Triple.getEnvironment()) { case llvm::Triple::EABI: case llvm::Triple::GNUEABI: CmdArgs.push_back("armelfb_nbsd_eabi"); @@ -186,13 +193,13 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips64el: if (mips::hasMipsAbiArg(Args, "32")) { CmdArgs.push_back("-m"); - if (ToolChain.getArch() == llvm::Triple::mips64) + if (Arch == llvm::Triple::mips64) CmdArgs.push_back("elf32btsmip"); else CmdArgs.push_back("elf32ltsmip"); } else if (mips::hasMipsAbiArg(Args, "64")) { CmdArgs.push_back("-m"); - if (ToolChain.getArch() == llvm::Triple::mips64) + if (Arch == llvm::Triple::mips64) CmdArgs.push_back("elf64btsmip"); else CmdArgs.push_back("elf64ltsmip"); @@ -209,6 +216,16 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf64ppc"); break; + case llvm::Triple::riscv32: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf32lriscv"); + break; + + case llvm::Triple::riscv64: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf64lriscv"); + break; + case llvm::Triple::sparc: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32_sparc"); @@ -223,94 +240,105 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, break; } + if (Triple.isRISCV()) + CmdArgs.push_back("-X"); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - } - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) { - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o"))); - } else { - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); - } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + const char *crt0 = nullptr; + const char *crtbegin = nullptr; + if (!Shared) + crt0 = "crt0.o"; + + if (Shared || Pie) + crtbegin = "crtbeginS.o"; + else + crtbegin = "crtbegin.o"; + + if (crt0) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt0))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); - Args.AddAllArgs(CmdArgs, options::OPT_r); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_s, options::OPT_t, options::OPT_r}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); - bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); + bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(); + const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args); if (SanArgs.needsSharedRt()) { CmdArgs.push_back("-rpath"); - CmdArgs.push_back(Args.MakeArgString( - ToolChain.getCompilerRTPath().c_str())); + CmdArgs.push_back(Args.MakeArgString(ToolChain.getCompilerRTPath())); } - unsigned Major, Minor, Micro; - ToolChain.getTriple().getOSVersion(Major, Minor, Micro); bool useLibgcc = true; - if (Major >= 7 || Major == 0) { - switch (ToolChain.getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - useLibgcc = false; - break; - default: - break; - } + switch (ToolChain.getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + useLibgcc = false; + break; + default: + break; } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp - bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && - !Args.hasArg(options::OPT_static); - addOpenMPRuntime(CmdArgs, getToolChain(), Args, StaticOpenMP); + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, CmdArgs); + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); if (useLibgcc) { - if (Args.hasArg(options::OPT_static)) { + if (Static) { // libgcc_eh depends on libc, so resolve as much as possible, // pull in any new requirements from libc and then get the rest // of libgcc. @@ -326,13 +354,15 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + const char *crtend = nullptr; + if (Shared || Pie) + crtend = "crtendS.o"; else - CmdArgs.push_back( - Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + crtend = "crtend.o"; + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } @@ -356,7 +386,7 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // what all logic is needed to emulate the '=' prefix here. switch (Triple.getArch()) { case llvm::Triple::x86: - getFilePaths().push_back("=/usr/lib/i386"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/i386")); break; case llvm::Triple::arm: case llvm::Triple::armeb: @@ -365,35 +395,35 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) switch (Triple.getEnvironment()) { case llvm::Triple::EABI: case llvm::Triple::GNUEABI: - getFilePaths().push_back("=/usr/lib/eabi"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/eabi")); break; case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: - getFilePaths().push_back("=/usr/lib/eabihf"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/eabihf")); break; default: - getFilePaths().push_back("=/usr/lib/oabi"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/oabi")); break; } break; case llvm::Triple::mips64: case llvm::Triple::mips64el: if (tools::mips::hasMipsAbiArg(Args, "o32")) - getFilePaths().push_back("=/usr/lib/o32"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/o32")); else if (tools::mips::hasMipsAbiArg(Args, "64")) - getFilePaths().push_back("=/usr/lib/64"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/64")); break; case llvm::Triple::ppc: - getFilePaths().push_back("=/usr/lib/powerpc"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/powerpc")); break; case llvm::Triple::sparc: - getFilePaths().push_back("=/usr/lib/sparc"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib/sparc")); break; default: break; } - getFilePaths().push_back("=/usr/lib"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } } @@ -404,40 +434,72 @@ Tool *NetBSD::buildAssembler() const { Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); } ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const { - unsigned Major, Minor, Micro; - getTriple().getOSVersion(Major, Minor, Micro); - if (Major >= 7 || Major == 0) { - switch (getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return ToolChain::CST_Libcxx; - default: - break; - } + switch (getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return ToolChain::CST_Libcxx; + default: + break; } return ToolChain::CST_Libstdcxx; } +void NetBSD::AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); +} + void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { const std::string Candidates[] = { // directory relative to build tree - getDriver().Dir + "/../include/c++/v1", + concat(getDriver().Dir, "/../include/c++/v1"), // system install with full upstream path - getDriver().SysRoot + "/usr/include/c++/v1", + concat(getDriver().SysRoot, "/usr/include/c++/v1"), // system install from src - getDriver().SysRoot + "/usr/include/c++", + concat(getDriver().SysRoot, "/usr/include/c++"), }; for (const auto &IncludePath : Candidates) { @@ -452,7 +514,7 @@ void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot + "/usr/include/g++", "", "", + addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/g++"), "", "", DriverArgs, CC1Args); } @@ -473,7 +535,6 @@ SanitizerMask NetBSD::getSupportedSanitizers() const { Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; - Res |= SanitizerKind::Function; Res |= SanitizerKind::Leak; Res |= SanitizerKind::SafeStack; Res |= SanitizerKind::Scudo; @@ -496,18 +557,19 @@ SanitizerMask NetBSD::getSupportedSanitizers() const { void NetBSD::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { - const SanitizerArgs &SanArgs = getSanitizerArgs(); + const SanitizerArgs &SanArgs = getSanitizerArgs(DriverArgs); if (SanArgs.hasAnySanitizer()) CC1Args.push_back("-D_REENTRANT"); - unsigned Major, Minor, Micro; - getTriple().getOSVersion(Major, Minor, Micro); + VersionTuple OsVersion = getTriple().getOSVersion(); bool UseInitArrayDefault = - Major >= 9 || Major == 0 || - getTriple().getArch() == llvm::Triple::aarch64 || - getTriple().getArch() == llvm::Triple::aarch64_be || - getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::armeb; + OsVersion >= VersionTuple(9) || OsVersion.getMajor() == 0 || + getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::aarch64_be || + getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::armeb || + getTriple().getArch() == llvm::Triple::riscv32 || + getTriple().getArch() == llvm::Triple::riscv64; if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, UseInitArrayDefault)) diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h index 8348554fd149..96303acaa009 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.h @@ -17,9 +17,9 @@ namespace clang { namespace driver { namespace tools { -/// netbsd -- Directly call GNU Binutils assembler and linker +/// Directly call GNU Binutils assembler and linker namespace netbsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("netbsd::Assembler", "assembler", TC) {} @@ -31,7 +31,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("netbsd::Linker", "linker", TC) {} @@ -58,6 +58,9 @@ public: CXXStdlibType GetDefaultCXXStdlibType() const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; void addLibCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -65,8 +68,9 @@ public: const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override { - return true; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override { + return UnwindTableLevel::Asynchronous; } llvm::ExceptionHandling GetExceptionModel( diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp new file mode 100644 index 000000000000..1e50c9d71d59 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.cpp @@ -0,0 +1,419 @@ +//===--- OHOS.cpp - OHOS ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "OHOS.h" +#include "Arch/ARM.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; +using namespace clang::driver::tools::arm; + +using tools::addMultilibFlag; +using tools::addPathIfExists; + +static bool findOHOSMuslMultilibs(const Multilib::flags_list &Flags, + DetectedMultilibs &Result) { + MultilibSet Multilibs; + Multilibs.push_back(Multilib()); + // -mcpu=cortex-a7 + // -mfloat-abi=soft -mfloat-abi=softfp -mfloat-abi=hard + // -mfpu=neon-vfpv4 + Multilibs.push_back( + Multilib("/a7_soft", {}, {}, {"-mcpu=cortex-a7", "-mfloat-abi=soft"})); + + Multilibs.push_back( + Multilib("/a7_softfp_neon-vfpv4", {}, {}, + {"-mcpu=cortex-a7", "-mfloat-abi=softfp", "-mfpu=neon-vfpv4"})); + + Multilibs.push_back( + Multilib("/a7_hard_neon-vfpv4", {}, {}, + {"-mcpu=cortex-a7", "-mfloat-abi=hard", "-mfpu=neon-vfpv4"})); + + if (Multilibs.select(Flags, Result.SelectedMultilibs)) { + Result.Multilibs = Multilibs; + return true; + } + return false; +} + +static bool findOHOSMultilibs(const Driver &D, + const ToolChain &TC, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + Multilib::flags_list Flags; + bool IsA7 = false; + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + IsA7 = A->getValue() == StringRef("cortex-a7"); + addMultilibFlag(IsA7, "-mcpu=cortex-a7", Flags); + + bool IsMFPU = false; + if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) + IsMFPU = A->getValue() == StringRef("neon-vfpv4"); + addMultilibFlag(IsMFPU, "-mfpu=neon-vfpv4", Flags); + + tools::arm::FloatABI ARMFloatABI = getARMFloatABI(D, TargetTriple, Args); + addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Soft), + "-mfloat-abi=soft", Flags); + addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::SoftFP), + "-mfloat-abi=softfp", Flags); + addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Hard), + "-mfloat-abi=hard", Flags); + + return findOHOSMuslMultilibs(Flags, Result); +} + +std::string OHOS::getMultiarchTriple(const llvm::Triple &T) const { + // For most architectures, just use whatever we have rather than trying to be + // clever. + switch (T.getArch()) { + default: + break; + + // We use the existence of '/lib/<triple>' as a directory to detect some + // common linux triples that don't quite match the Clang triple for both + // 32-bit and 64-bit targets. Multiarch fixes its install triples to these + // regardless of what the actual target triple is. + case llvm::Triple::arm: + case llvm::Triple::thumb: + return T.isOSLiteOS() ? "arm-liteos-ohos" : "arm-linux-ohos"; + case llvm::Triple::riscv32: + return "riscv32-linux-ohos"; + case llvm::Triple::riscv64: + return "riscv64-linux-ohos"; + case llvm::Triple::mipsel: + return "mipsel-linux-ohos"; + case llvm::Triple::x86: + return "i686-linux-ohos"; + case llvm::Triple::x86_64: + return "x86_64-linux-ohos"; + case llvm::Triple::aarch64: + return "aarch64-linux-ohos"; + } + return T.str(); +} + +std::string OHOS::getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const { + return getMultiarchTriple(TargetTriple); +} + +static std::string makePath(const std::initializer_list<std::string> &IL) { + SmallString<128> P; + for (const auto &S : IL) + llvm::sys::path::append(P, S); + return static_cast<std::string>(P.str()); +} + +/// OHOS Toolchain +OHOS::OHOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + std::string SysRoot = computeSysRoot(); + + // Select the correct multilib according to the given arguments. + DetectedMultilibs Result; + findOHOSMultilibs(D, *this, Triple, "", Args, Result); + Multilibs = Result.Multilibs; + SelectedMultilibs = Result.SelectedMultilibs; + if (!SelectedMultilibs.empty()) { + SelectedMultilib = SelectedMultilibs.back(); + } + + getFilePaths().clear(); + for (const auto &CandidateLibPath : getArchSpecificLibPaths()) + if (getVFS().exists(CandidateLibPath)) + getFilePaths().push_back(CandidateLibPath); + + getLibraryPaths().clear(); + for (auto &Path : getRuntimePaths()) + if (getVFS().exists(Path)) + getLibraryPaths().push_back(Path); + + // OHOS sysroots contain a library directory for each supported OS + // version as well as some unversioned libraries in the usual multiarch + // directory. Support --target=aarch64-linux-ohosX.Y.Z or + // --target=aarch64-linux-ohosX.Y or --target=aarch64-linux-ohosX + path_list &Paths = getFilePaths(); + std::string SysRootLibPath = makePath({SysRoot, "usr", "lib"}); + std::string MultiarchTriple = getMultiarchTriple(getTriple()); + addPathIfExists(D, makePath({SysRootLibPath, SelectedMultilib.gccSuffix()}), + Paths); + addPathIfExists(D, + makePath({D.Dir, "..", "lib", MultiarchTriple, + SelectedMultilib.gccSuffix()}), + Paths); + + addPathIfExists( + D, + makePath({SysRootLibPath, MultiarchTriple, SelectedMultilib.gccSuffix()}), + Paths); +} + +ToolChain::RuntimeLibType OHOS::GetRuntimeLibType( + const ArgList &Args) const { + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "compiler-rt") + getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name) + << A->getAsString(Args); + } + + return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType +OHOS::GetCXXStdlibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "libc++") + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + + return ToolChain::CST_Libcxx; +} + +void OHOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + const llvm::Triple &Triple = getTriple(); + std::string SysRoot = computeSysRoot(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + addExternCSystemInclude(DriverArgs, CC1Args, + SysRoot + "/usr/include/" + + getMultiarchTriple(Triple)); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); +} + +void OHOS::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + std::string IncPath = makePath({getDriver().Dir, "..", "include"}); + std::string IncTargetPath = + makePath({IncPath, getMultiarchTriple(getTriple()), "c++", "v1"}); + if (getVFS().exists(IncTargetPath)) { + addSystemInclude(DriverArgs, CC1Args, makePath({IncPath, "c++", "v1"})); + addSystemInclude(DriverArgs, CC1Args, IncTargetPath); + } + break; + } + + default: + llvm_unreachable("invalid stdlib name"); + } +} + +void OHOS::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); + break; + + case ToolChain::CST_Libstdcxx: + llvm_unreachable("invalid stdlib name"); + } +} + +std::string OHOS::computeSysRoot() const { + std::string SysRoot = + !getDriver().SysRoot.empty() + ? getDriver().SysRoot + : makePath({getDriver().getInstalledDir(), "..", "..", "sysroot"}); + if (!llvm::sys::fs::exists(SysRoot)) + return std::string(); + + std::string ArchRoot = makePath({SysRoot, getMultiarchTriple(getTriple())}); + return llvm::sys::fs::exists(ArchRoot) ? ArchRoot : SysRoot; +} + +ToolChain::path_list OHOS::getRuntimePaths() const { + SmallString<128> P; + path_list Paths; + const Driver &D = getDriver(); + const llvm::Triple &Triple = getTriple(); + + // First try the triple passed to driver as --target=<triple>. + P.assign(D.ResourceDir); + llvm::sys::path::append(P, "lib", D.getTargetTriple(), SelectedMultilib.gccSuffix()); + Paths.push_back(P.c_str()); + + // Second try the normalized triple. + P.assign(D.ResourceDir); + llvm::sys::path::append(P, "lib", Triple.str(), SelectedMultilib.gccSuffix()); + Paths.push_back(P.c_str()); + + // Third try the effective triple. + P.assign(D.ResourceDir); + std::string SysRoot = computeSysRoot(); + llvm::sys::path::append(P, "lib", getMultiarchTriple(Triple), + SelectedMultilib.gccSuffix()); + Paths.push_back(P.c_str()); + + return Paths; +} + +std::string OHOS::getDynamicLinker(const ArgList &Args) const { + const llvm::Triple &Triple = getTriple(); + const llvm::Triple::ArchType Arch = getArch(); + + assert(Triple.isMusl()); + std::string ArchName; + bool IsArm = false; + + switch (Arch) { + case llvm::Triple::arm: + case llvm::Triple::thumb: + ArchName = "arm"; + IsArm = true; + break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + ArchName = "armeb"; + IsArm = true; + break; + default: + ArchName = Triple.getArchName().str(); + } + if (IsArm && + (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)) + ArchName += "hf"; + + return "/lib/ld-musl-" + ArchName + ".so.1"; +} + +std::string OHOS::getCompilerRT(const ArgList &Args, StringRef Component, + FileType Type) const { + SmallString<128> Path(getDriver().ResourceDir); + llvm::sys::path::append(Path, "lib", getMultiarchTriple(getTriple()), + SelectedMultilib.gccSuffix()); + const char *Prefix = + Type == ToolChain::FT_Object ? "" : "lib"; + const char *Suffix; + switch (Type) { + case ToolChain::FT_Object: + Suffix = ".o"; + break; + case ToolChain::FT_Static: + Suffix = ".a"; + break; + case ToolChain::FT_Shared: + Suffix = ".so"; + break; + } + llvm::sys::path::append( + Path, Prefix + Twine("clang_rt.") + Component + Suffix); + return static_cast<std::string>(Path.str()); +} + +void OHOS::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { + CmdArgs.push_back("-z"); + CmdArgs.push_back("now"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("relro"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("max-page-size=4096"); + // .gnu.hash section is not compatible with the MIPS target + if (getArch() != llvm::Triple::mipsel) + CmdArgs.push_back("--hash-style=both"); +#ifdef ENABLE_LINKER_BUILD_ID + CmdArgs.push_back("--build-id"); +#endif + CmdArgs.push_back("--enable-new-dtags"); +} + +SanitizerMask OHOS::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; + Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::Memory; + Res |= SanitizerKind::Vptr; + Res |= SanitizerKind::SafeStack; + Res |= SanitizerKind::Scudo; + // TODO: kASAN for liteos ?? + // TODO: Support TSAN and HWASAN and update mask. + return Res; +} + +// TODO: Make a base class for Linux and OHOS and move this there. +void OHOS::addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + // Add linker option -u__llvm_profile_runtime to cause runtime + // initialization module to be linked in. + if (needsProfileRT(Args)) + CmdArgs.push_back(Args.MakeArgString( + Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); + ToolChain::addProfileRTLibs(Args, CmdArgs); +} + +ToolChain::path_list OHOS::getArchSpecificLibPaths() const { + ToolChain::path_list Paths; + llvm::Triple Triple = getTriple(); + Paths.push_back( + makePath({getDriver().ResourceDir, "lib", getMultiarchTriple(Triple)})); + return Paths; +} + +ToolChain::UnwindLibType OHOS::GetUnwindLibType(const llvm::opt::ArgList &Args) const { + if (Args.getLastArg(options::OPT_unwindlib_EQ)) + return Generic_ELF::GetUnwindLibType(Args); + return GetDefaultUnwindLibType(); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h new file mode 100644 index 000000000000..2a380420922d --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OHOS.h @@ -0,0 +1,95 @@ +//===--- OHOS.h - OHOS ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OHOS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OHOS_H + +#include "Linux.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY OHOS : public Generic_ELF { +public: + OHOS(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool HasNativeLLVMSupport() const override { return true; } + + bool IsMathErrnoDefault() const override { return false; } + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + // Not add -funwind-tables by default + bool isPICDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { return true; } + bool isPICDefaultForced() const override { return false; } + UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override; + UnwindLibType GetDefaultUnwindLibType() const override { return UNW_CompilerRT; } + + RuntimeLibType + GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; + CXXStdlibType + GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + std::string computeSysRoot() const override; + std::string getDynamicLinker(const llvm::opt::ArgList &Args) const override; + + std::string + getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, + FileType Type = ToolChain::FT_Static) const override; + + const char *getDefaultLinker() const override { + return "ld.lld"; + } + + Tool *buildLinker() const override { + return new tools::gnutools::Linker(*this); + } + Tool *buildAssembler() const override { + return new tools::gnutools::Assembler(*this); + } + + path_list getRuntimePaths() const; + +protected: + std::string getMultiarchTriple(const llvm::Triple &T) const; + std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const override; + void addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const override; + SanitizerMask getSupportedSanitizers() const override; + void addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + path_list getArchSpecificLibPaths() const override; + +private: + Multilib SelectedMultilib; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OHOS_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp index 89828fbb6f5f..fd6aa4d7e684 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "OpenBSD.h" +#include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/Sparc.h" #include "CommonArgs.h" @@ -16,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; @@ -28,16 +30,28 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - claimNoWarnArgs(Args); + const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); ArgStringList CmdArgs; - switch (getToolChain().getArch()) { + claimNoWarnArgs(Args); + + switch (ToolChain.getArch()) { case llvm::Triple::x86: // When building 32-bit code on OpenBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. CmdArgs.push_back("--32"); break; + case llvm::Triple::arm: { + StringRef MArch, MCPU; + arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); + std::string Arch = arm::getARMTargetCPU(MCPU, MArch, Triple); + CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); + break; + } + case llvm::Triple::ppc: CmdArgs.push_back("-mppc"); CmdArgs.push_back("-many"); @@ -45,9 +59,9 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + std::string CPU = getCPUName(D, Args, Triple); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } @@ -55,17 +69,20 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + + CmdArgs.push_back("-march"); + CmdArgs.push_back(CPUName.data()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - if (getToolChain().getTriple().isLittleEndian()) + if (Triple.isLittleEndian()) CmdArgs.push_back("-EL"); else CmdArgs.push_back("-EB"); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } @@ -81,7 +98,7 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as")); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -92,9 +109,15 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::OpenBSD &ToolChain = - static_cast<const toolchains::OpenBSD &>(getToolChain()); - const Driver &D = getToolChain().getDriver(); + const auto &ToolChain = static_cast<const OpenBSD &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool Static = Args.hasArg(options::OPT_static); + const bool Shared = Args.hasArg(options::OPT_shared); + const bool Profiling = Args.hasArg(options::OPT_pg); + const bool Pie = Args.hasArg(options::OPT_pie); + const bool Nopie = Args.hasArg(options::OPT_no_pie, options::OPT_nopie); + const bool Relocatable = Args.hasArg(options::OPT_r); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -105,51 +128,55 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); - if (ToolChain.getArch() == llvm::Triple::mips64) + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (Arch == llvm::Triple::mips64) CmdArgs.push_back("-EB"); - else if (ToolChain.getArch() == llvm::Triple::mips64el) + else if (Arch == llvm::Triple::mips64el) CmdArgs.push_back("-EL"); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { + if (!Args.hasArg(options::OPT_nostdlib) && !Shared && !Relocatable) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_static)) { + if (Static) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); - CmdArgs.push_back("-Bdynamic"); - if (Args.hasArg(options::OPT_shared)) { + if (Shared) { CmdArgs.push_back("-shared"); - } else { + } else if (!Relocatable) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld.so"); } } - if (Args.hasArg(options::OPT_pie)) + if (Pie) CmdArgs.push_back("-pie"); - if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg)) + if (Nopie || Profiling) CmdArgs.push_back("-nopie"); + if (Arch == llvm::Triple::riscv64) + CmdArgs.push_back("-X"); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { const char *crt0 = nullptr; const char *crtbegin = nullptr; - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) + if (!Shared) { + if (Profiling) crt0 = "gcrt0.o"; - else if (Args.hasArg(options::OPT_static) && - !Args.hasArg(options::OPT_nopie)) + else if (Static && !Nopie) crt0 = "rcrt0.o"; else crt0 = "crt0.o"; @@ -165,49 +192,79 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e, - options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_r}); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); + + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + // Find the first filename InputInfo object. + auto Input = llvm::find_if( + Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); }); + if (Input == Inputs.end()) + // For a very rare case, all of the inputs to the linker are + // InputArg. If that happens, just use the first InputInfo. + Input = Inputs.begin(); + + addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input, + D.getLTOMode() == LTOK_Thin); + } bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); 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); + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (Args.hasArg(options::OPT_pg)) + if (Profiling) CmdArgs.push_back("-lm_p"); else CmdArgs.push_back("-lm"); } + + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRunTimeLibs). + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranRuntimeLibs(ToolChain, Args, CmdArgs); + if (Profiling) + CmdArgs.push_back("-lm_p"); + else + CmdArgs.push_back("-lm"); + } + if (NeedsSanitizerDeps) { CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); } if (NeedsXRayDeps) { CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins")); - linkXRayRuntimeDeps(ToolChain, CmdArgs); + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); } // FIXME: For some reason GCC passes -lgcc before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lcompiler_rt"); if (Args.hasArg(options::OPT_pthread)) { - if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg)) + if (!Shared && Profiling) CmdArgs.push_back("-lpthread_p"); else CmdArgs.push_back("-lpthread"); } - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) + if (!Shared) { + if (Profiling) CmdArgs.push_back("-lc_p"); else CmdArgs.push_back("-lc"); @@ -216,9 +273,10 @@ 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)) + if (!Shared) crtend = "crtend.o"; else crtend = "crtendS.o"; @@ -237,16 +295,15 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, SanitizerMask OpenBSD::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; - - // For future use, only UBsan at the moment SanitizerMask Res = ToolChain::getSupportedSanitizers(); - if (IsX86 || IsX86_64) { Res |= SanitizerKind::Vptr; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; } - + if (IsX86_64) { + Res |= SanitizerKind::KernelAddress; + } return Res; } @@ -255,7 +312,7 @@ SanitizerMask OpenBSD::getSupportedSanitizers() const { OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } void OpenBSD::AddClangSystemIncludeArgs( @@ -288,13 +345,14 @@ void OpenBSD::AddClangSystemIncludeArgs( return; } - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); } void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); + concat(getDriver().SysRoot, "/usr/include/c++/v1")); } void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, @@ -302,16 +360,27 @@ void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, bool Profiling = Args.hasArg(options::OPT_pg); CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi"); CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread"); } -std::string OpenBSD::getCompilerRT(const ArgList &Args, - StringRef Component, +std::string OpenBSD::getCompilerRT(const ArgList &Args, StringRef Component, FileType Type) const { - SmallString<128> Path(getDriver().SysRoot); - llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a"); - return std::string(Path.str()); + if (Component == "builtins") { + SmallString<128> Path(getDriver().SysRoot); + llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a"); + return std::string(Path); + } + SmallString<128> P(getDriver().ResourceDir); + std::string CRTBasename = + buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false); + llvm::sys::path::append(P, "lib", CRTBasename); + // Checks if this is the base system case which uses a different location. + if (getVFS().exists(P)) + return std::string(P); + return ToolChain::getCompilerRT(Args, Component, Type); } Tool *OpenBSD::buildAssembler() const { @@ -321,3 +390,13 @@ Tool *OpenBSD::buildAssembler() const { Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } bool OpenBSD::HasNativeLLVMSupport() const { return true; } + +ToolChain::UnwindTableLevel +OpenBSD::getDefaultUnwindTableLevel(const ArgList &Args) const { + switch (getArch()) { + case llvm::Triple::arm: + return UnwindTableLevel::None; + default: + return UnwindTableLevel::Asynchronous; + } +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h index 4932ed5c609c..b4350e72d5d2 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.h @@ -18,9 +18,9 @@ namespace clang { namespace driver { namespace tools { -/// openbsd -- Directly call GNU Binutils assembler and linker +/// Directly call GNU Binutils assembler and linker namespace openbsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("openbsd::Assembler", "assembler", TC) {} @@ -33,7 +33,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("openbsd::Linker", "linker", TC) {} @@ -59,7 +59,9 @@ public: bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } - bool isPIEDefault() const override { return true; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return true; + } RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; @@ -80,6 +82,9 @@ public: std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, FileType Type = ToolChain::FT_Static) const override; + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override; + LangOptions::StackProtectorMode GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return LangOptions::SSPStrong; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCFreeBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCFreeBSD.cpp new file mode 100644 index 000000000000..8d381c4f1437 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCFreeBSD.cpp @@ -0,0 +1,28 @@ +//===-- PPCFreeBSD.cpp - PowerPC 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 "PPCFreeBSD.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver::toolchains; +using namespace llvm::opt; + +void PPCFreeBSDToolChain::AddClangSystemIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) && + !DriverArgs.hasArg(options::OPT_nobuiltininc)) { + const Driver &D = getDriver(); + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include", "ppc_wrappers"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + FreeBSD::AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCFreeBSD.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCFreeBSD.h new file mode 100644 index 000000000000..d5d9cf4e83a0 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCFreeBSD.h @@ -0,0 +1,33 @@ +//===--- PPCFreeBSD.h - PowerPC 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_PPC_FREEBSD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PPC_FREEBSD_H + +#include "FreeBSD.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY PPCFreeBSDToolChain : public FreeBSD { +public: + PPCFreeBSDToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : FreeBSD(D, Triple, Args) {} + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PPC_FREEBSD_H diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp index af2e3a21a0af..0ed0f91ad166 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.cpp @@ -8,11 +8,54 @@ #include "PPCLinux.h" #include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +using namespace clang::driver; using namespace clang::driver::toolchains; using namespace llvm::opt; +using namespace llvm::sys; + +// Glibc older than 2.32 doesn't fully support IEEE float128. Here we check +// glibc version by looking at dynamic linker name. +static bool GlibcSupportsFloat128(const std::string &Linker) { + llvm::SmallVector<char, 16> Path; + + // Resolve potential symlinks to linker. + if (fs::real_path(Linker, Path)) + return false; + llvm::StringRef LinkerName = + path::filename(llvm::StringRef(Path.data(), Path.size())); + + // Since glibc 2.34, the installed .so file is not symlink anymore. But we can + // still safely assume it's newer than 2.32. + if (LinkerName.starts_with("ld64.so")) + return true; + + if (!LinkerName.starts_with("ld-2.")) + return false; + unsigned Minor = (LinkerName[5] - '0') * 10 + (LinkerName[6] - '0'); + if (Minor < 32) + return false; + + return true; +} + +PPCLinuxToolChain::PPCLinuxToolChain(const Driver &D, + const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Linux(D, Triple, Args) { + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { + StringRef ABIName = A->getValue(); + + if ((ABIName == "ieeelongdouble" && + !SupportIEEEFloat128(D, Triple, Args)) || + (ABIName == "ibmlongdouble" && !supportIBMLongDouble(D, Args))) + D.Diag(diag::warn_drv_unsupported_float_abi_by_lib) << ABIName; + } +} void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { @@ -26,3 +69,35 @@ void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, Linux::AddClangSystemIncludeArgs(DriverArgs, CC1Args); } + +bool PPCLinuxToolChain::supportIBMLongDouble( + const Driver &D, const llvm::opt::ArgList &Args) const { + if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx)) + return true; + + CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args); + if (StdLib == CST_Libstdcxx) + return true; + + return StdLib == CST_Libcxx && !defaultToIEEELongDouble(); +} + +bool PPCLinuxToolChain::SupportIEEEFloat128( + const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) const { + if (!Triple.isLittleEndian() || !Triple.isPPC64()) + return false; + + if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx)) + return true; + + CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args); + bool HasUnsupportedCXXLib = + (StdLib == CST_Libcxx && !defaultToIEEELongDouble()) || + (StdLib == CST_Libstdcxx && + GCCInstallation.getVersion().isOlderThan(12, 1, 0)); + + std::string Linker = Linux::getDynamicLinker(Args); + return GlibcSupportsFloat128((Twine(D.DyldPrefix) + Linker).str()) && + !(D.CCCIsCXX() && HasUnsupportedCXXLib); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h index b3ef7b61dc3a..63adaff6be9c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PPCLinux.h @@ -18,12 +18,17 @@ namespace toolchains { class LLVM_LIBRARY_VISIBILITY PPCLinuxToolChain : public Linux { public: PPCLinuxToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args) - : Linux(D, Triple, Args) {} + const llvm::opt::ArgList &Args); void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + +private: + bool SupportIEEEFloat128(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) const; + bool supportIBMLongDouble(const Driver &D, + const llvm::opt::ArgList &Args) const; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp index 383b0c50d410..8ba8b80cfec7 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "PS4CPU.h" -#include "FreeBSD.h" #include "CommonArgs.h" +#include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" @@ -23,10 +23,18 @@ using namespace clang::driver; using namespace clang; using namespace llvm::opt; -using clang::driver::tools::AddLinkerInputs; +// 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); -void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasFlag(options::OPT_fprofile_generate, @@ -43,14 +51,16 @@ void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, options::OPT_fno_profile_generate, false) || Args.hasArg(options::OPT_fcreate_profile) || Args.hasArg(options::OPT_coverage))) - CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a"); + CmdArgs.push_back(makeArgString( + Args, "--dependent-lib=", PSTC.getProfileRTLibName(), "")); } -void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, +void tools::PScpu::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain()); claimNoWarnArgs(Args); ArgStringList CmdArgs; @@ -64,40 +74,57 @@ void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); + std::string AsName = TC.qualifyPSCmdName("as"); + const char *Exec = Args.MakeArgString(TC.GetProgramPath(AsName.c_str())); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, Output)); } -static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); - if (SanArgs.needsUbsanRt()) { - CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); - } - if (SanArgs.needsAsanRt()) { - CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); - } +void tools::PScpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + assert(TC.getTriple().isPS()); + auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC); + PSTC.addSanitizerArgs(Args, CmdArgs, "--dependent-lib=lib", ".a"); } -void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, - ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); +void toolchains::PS4CPU::addSanitizerArgs(const ArgList &Args, + ArgStringList &CmdArgs, + const char *Prefix, + const char *Suffix) const { + auto arg = [&](const char *Name) -> const char * { + return makeArgString(Args, Prefix, Name, Suffix); + }; + const SanitizerArgs &SanArgs = getSanitizerArgs(Args); if (SanArgs.needsUbsanRt()) - CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a"); + CmdArgs.push_back(arg("SceDbgUBSanitizer_stub_weak")); if (SanArgs.needsAsanRt()) - CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a"); + CmdArgs.push_back(arg("SceDbgAddressSanitizer_stub_weak")); } -void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(getToolChain()); - const Driver &D = ToolChain.getDriver(); +void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args, + ArgStringList &CmdArgs, + const char *Prefix, + const char *Suffix) const { + auto arg = [&](const char *Name) -> const char * { + return makeArgString(Args, Prefix, Name, Suffix); + }; + const SanitizerArgs &SanArgs = getSanitizerArgs(Args); + if (SanArgs.needsUbsanRt()) + CmdArgs.push_back(arg("SceUBSanitizer_nosubmission_stub_weak")); + if (SanArgs.needsAsanRt()) + CmdArgs.push_back(arg("SceAddressSanitizer_nosubmission_stub_weak")); + if (SanArgs.needsTsanRt()) + CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak")); +} + +void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain()); + const Driver &D = TC.getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -117,119 +144,195 @@ void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("--oformat=so"); + CmdArgs.push_back("--shared"); + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } - if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - AddPS4SanitizerArgs(ToolChain, CmdArgs); + const bool UseLTO = D.isUsingLTO(); + const bool UseJMC = + Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false); + const bool IsPS4 = TC.getTriple().isPS4(); - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_r); + const char *PS4LTOArgs = ""; + auto AddCodeGenFlag = [&](Twine Flag) { + if (IsPS4) + PS4LTOArgs = Args.MakeArgString(Twine(PS4LTOArgs) + " " + Flag); + else + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag)); + }; + + if (UseLTO) { + // We default to creating the arange section, but LTO does not. Enable it + // here. + AddCodeGenFlag("-generate-arange-section"); + + // This tells LTO to perform JustMyCode instrumentation. + if (UseJMC) + AddCodeGenFlag("-enable-jmc-instrument"); + + if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir)) + AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue()); + + StringRef Parallelism = getLTOParallelism(Args, D); + if (!Parallelism.empty()) { + if (IsPS4) + AddCodeGenFlag(Twine("-threads=") + Parallelism); + else + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism)); + } + + if (IsPS4) { + const char *Prefix = nullptr; + if (D.getLTOMode() == LTOK_Thin) + Prefix = "-lto-thin-debug-options="; + else if (D.getLTOMode() == LTOK_Full) + Prefix = "-lto-debug-options="; + else + llvm_unreachable("new LTO mode?"); + + CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + PS4LTOArgs)); + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) + TC.addSanitizerArgs(Args, CmdArgs, "-l", ""); + + if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) { + if (D.getLTOMode() == LTOK_Thin) + CmdArgs.push_back("--lto=thin"); + else if (D.getLTOMode() == LTOK_Full) + CmdArgs.push_back("--lto=full"); + } + + Args.addAllArgs(CmdArgs, + {options::OPT_L, options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); if (Args.hasArg(options::OPT_pthread)) { CmdArgs.push_back("-lpthread"); } + if (UseJMC) { + CmdArgs.push_back("--whole-archive"); + if (IsPS4) + CmdArgs.push_back("-lSceDbgJmc"); + else + CmdArgs.push_back("-lSceJmc_nosubmission"); + CmdArgs.push_back("--no-whole-archive"); + } + if (Args.hasArg(options::OPT_fuse_ld_EQ)) { D.Diag(diag::err_drv_unsupported_opt_for_target) - << "-fuse-ld" << getToolChain().getTriple().str(); + << "-fuse-ld" << TC.getTriple().str(); } - const char *Exec = - Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); + std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName()); + const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str())); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, Output)); } -toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) +toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, StringRef Platform, + const char *EnvVar) : Generic_ELF(D, Triple, Args) { if (Args.hasArg(clang::driver::options::OPT_static)) - D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static" - << "PS4"; - - // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR - // if it exists; otherwise use the driver's installation path, which - // should be <SDK_DIR>/host_tools/bin. - - SmallString<512> PS4SDKDir; - if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { - if (!llvm::sys::fs::exists(EnvValue)) - getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; - PS4SDKDir = EnvValue; - } else { - PS4SDKDir = getDriver().Dir; - llvm::sys::path::append(PS4SDKDir, "/../../"); - } + D.Diag(clang::diag::err_drv_unsupported_opt_for_target) + << "-static" << Platform; - // By default, the driver won't report a warning if it can't find - // PS4's include or lib directories. This behavior could be changed if - // -Weverything or -Winvalid-or-nonexistent-directory options are passed. + // Determine where to find the PS4/PS5 libraries. // If -isysroot was passed, use that as the SDK base path. - std::string PrefixDir; + // If not, we use the EnvVar if it exists; otherwise use the driver's + // installation path, which should be <SDK_DIR>/host_tools/bin. + SmallString<80> Whence; if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - PrefixDir = A->getValue(); - if (!llvm::sys::fs::exists(PrefixDir)) - getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; - } else - PrefixDir = std::string(PS4SDKDir.str()); - - SmallString<512> PS4SDKIncludeDir(PrefixDir); - llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); + SDKRootDir = A->getValue(); + if (!llvm::sys::fs::exists(SDKRootDir)) + D.Diag(clang::diag::warn_missing_sysroot) << SDKRootDir; + Whence = A->getSpelling(); + } else if (const char *EnvValue = getenv(EnvVar)) { + SDKRootDir = EnvValue; + Whence = { "environment variable '", EnvVar, "'" }; + } else { + SDKRootDir = D.Dir + "/../../"; + Whence = "compiler's location"; + } + + SmallString<512> SDKIncludeDir(SDKRootDir); + llvm::sys::path::append(SDKIncludeDir, "target/include"); if (!Args.hasArg(options::OPT_nostdinc) && !Args.hasArg(options::OPT_nostdlibinc) && !Args.hasArg(options::OPT_isysroot) && !Args.hasArg(options::OPT__sysroot_EQ) && - !llvm::sys::fs::exists(PS4SDKIncludeDir)) { - getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) - << "PS4 system headers" << PS4SDKIncludeDir; + !llvm::sys::fs::exists(SDKIncludeDir)) { + D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected) + << Twine(Platform, " system headers").str() << SDKIncludeDir << Whence; } - SmallString<512> PS4SDKLibDir(PS4SDKDir); - llvm::sys::path::append(PS4SDKLibDir, "target/lib"); + SmallString<512> SDKLibDir(SDKRootDir); + llvm::sys::path::append(SDKLibDir, "target/lib"); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs) && !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && !Args.hasArg(options::OPT_emit_ast) && - !llvm::sys::fs::exists(PS4SDKLibDir)) { - getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) - << "PS4 system libraries" << PS4SDKLibDir; + !llvm::sys::fs::exists(SDKLibDir)) { + D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected) + << Twine(Platform, " system libraries").str() << SDKLibDir << Whence; return; } - getFilePaths().push_back(std::string(PS4SDKLibDir.str())); + getFilePaths().push_back(std::string(SDKLibDir)); } -Tool *toolchains::PS4CPU::buildAssembler() const { - return new tools::PS4cpu::Assemble(*this); +void toolchains::PS4PS5Base::AddClangSystemIncludeArgs( + const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(D.ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + addExternCSystemInclude(DriverArgs, CC1Args, + SDKRootDir + "/target/include"); + addExternCSystemInclude(DriverArgs, CC1Args, + SDKRootDir + "/target/include_common"); } -Tool *toolchains::PS4CPU::buildLinker() const { - return new tools::PS4cpu::Link(*this); +Tool *toolchains::PS4CPU::buildAssembler() const { + return new tools::PScpu::Assembler(*this); } -bool toolchains::PS4CPU::isPICDefault() const { return true; } +Tool *toolchains::PS5CPU::buildAssembler() const { + // PS5 does not support an external assembler. + getDriver().Diag(clang::diag::err_no_external_assembler); + return nullptr; +} -bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; } +Tool *toolchains::PS4PS5Base::buildLinker() const { + return new tools::PScpu::Linker(*this); +} -SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { +SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; @@ -238,10 +341,16 @@ SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { return Res; } -void toolchains::PS4CPU::addClangTargetOptions( +SanitizerMask toolchains::PS5CPU::getSupportedSanitizers() const { + SanitizerMask Res = PS4PS5Base::getSupportedSanitizers(); + Res |= SanitizerKind::Thread; + return Res; +} + +void toolchains::PS4PS5Base::addClangTargetOptions( const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { - // PS4 does not use init arrays. + // PS4/PS5 do not use init arrays. if (DriverArgs.hasArg(options::OPT_fuse_init_array)) { Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array); getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target) @@ -250,6 +359,12 @@ void toolchains::PS4CPU::addClangTargetOptions( CC1Args.push_back("-fno-use-init-array"); + // Default to -fvisibility-global-new-delete=source for PS5. + if (getTriple().isPS5() && + !DriverArgs.hasArg(options::OPT_fvisibility_global_new_delete_EQ, + options::OPT_fvisibility_global_new_delete_hidden)) + CC1Args.push_back("-fvisibility-global-new-delete=source"); + const Arg *A = DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass, options::OPT_fno_visibility_from_dllstorageclass); @@ -282,3 +397,13 @@ void toolchains::PS4CPU::addClangTargetOptions( CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default"); } } + +// PS4 toolchain. +toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : PS4PS5Base(D, Triple, Args, "PS4", "SCE_ORBIS_SDK_DIR") {} + +// PS5 toolchain. +toolchains::PS5CPU::PS5CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : PS4PS5Base(D, Triple, Args, "PS5", "SCE_PROSPERO_SDK_DIR") {} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h index 5f5d0e57d4ea..fee80e77462f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.h @@ -18,61 +18,66 @@ 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); -void addSanitizerArgs(const ToolChain &TC, llvm::opt::ArgStringList &CmdArgs); +void addSanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); -class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: - Assemble(const ToolChain &TC) : Tool("PS4cpu::Assemble", "assembler", TC) {} + Assembler(const ToolChain &TC) : Tool("PScpu::Assembler", "assembler", TC) {} bool hasIntegratedCPP() const override { return false; } void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, + const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Link : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: - Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("PScpu::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, + const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; -} // end namespace PS4cpu +} // namespace PScpu } // namespace tools namespace toolchains { -class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF { +// Common Toolchain base class for PS4 and PS5. +class LLVM_LIBRARY_VISIBILITY PS4PS5Base : public Generic_ELF { public: - PS4CPU(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); + PS4PS5Base(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, StringRef Platform, + const char *EnvVar); + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; // No support for finding a C++ standard library yet. - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override { + } + void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } - bool HasNativeLLVMSupport() const override; - bool isPICDefault() const override; + bool HasNativeLLVMSupport() const override { return true; } + bool isPICDefault() const override { return true; } LangOptions::StackProtectorMode GetDefaultStackProtectorLevel(bool KernelOrKext) const override { @@ -85,14 +90,9 @@ public: 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, @@ -101,11 +101,73 @@ public: return llvm::DenormalMode::getPreserveSign(); } - bool useRelaxRelocations() const override { return true; } + // Helper methods for PS4/PS5. + virtual const char *getLinkerBaseName() const = 0; + virtual std::string qualifyPSCmdName(StringRef CmdName) const = 0; + virtual void addSanitizerArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const char *Prefix, + const char *Suffix) const = 0; + virtual const char *getProfileRTLibName() const = 0; protected: - Tool *buildAssembler() const override; Tool *buildLinker() const override; + +private: + // We compute the SDK root dir in the ctor, and use it later. + std::string SDKRootDir; +}; + +// PS4-specific Toolchain class. +class LLVM_LIBRARY_VISIBILITY PS4CPU : public PS4PS5Base { +public: + PS4CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + unsigned GetDefaultDwarfVersion() const override { return 4; } + + // PS4 toolchain uses legacy thin LTO API, which is not + // capable of unit splitting. + bool canSplitThinLTOUnit() const override { return false; } + + const char *getLinkerBaseName() const override { return "ld"; } + std::string qualifyPSCmdName(StringRef CmdName) const override { + return Twine("orbis-", CmdName).str(); + } + void addSanitizerArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, const char *Prefix, + const char *Suffix) const override; + const char *getProfileRTLibName() const override { + return "libclang_rt.profile-x86_64.a"; + } + +protected: + Tool *buildAssembler() const override; +}; + +// PS5-specific Toolchain class. +class LLVM_LIBRARY_VISIBILITY PS5CPU : public PS4PS5Base { +public: + PS5CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + unsigned GetDefaultDwarfVersion() const override { return 5; } + + SanitizerMask getSupportedSanitizers() const override; + + const char *getLinkerBaseName() const override { return "lld"; } + std::string qualifyPSCmdName(StringRef CmdName) const override { + return Twine("prospero-", CmdName).str(); + } + void addSanitizerArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, const char *Prefix, + const char *Suffix) const override; + const char *getProfileRTLibName() const override { + return "libclang_rt.profile-x86_64_nosubmission.a"; + } + +protected: + Tool *buildAssembler() const override; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index 714325a2db39..5e4fa4d5331f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -1,4 +1,4 @@ -//===--- RISCVToolchain.cpp - RISCV ToolChain Implementations ---*- C++ -*-===// +//===--- RISCVToolchain.cpp - RISC-V ToolChain Implementations --*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -46,17 +46,17 @@ bool RISCVToolChain::hasGCCToolchain(const Driver &D, return llvm::sys::fs::exists(GCCDir); } -/// RISCV Toolchain +/// RISC-V Toolchain RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); if (GCCInstallation.isValid()) { Multilibs = GCCInstallation.getMultilibs(); - SelectedMultilib = GCCInstallation.getMultilib(); + SelectedMultilibs.assign({GCCInstallation.getMultilib()}); path_list &Paths = getFilePaths(); // Add toolchain/multilib specific file paths. - addMultilibsFilePaths(D, Multilibs, SelectedMultilib, + addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(), GCCInstallation.getInstallPath(), Paths); getFilePaths().push_back(GCCInstallation.getInstallPath().str()); ToolChain::path_list &PPaths = getProgramPaths(); @@ -98,6 +98,12 @@ void RISCVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (DriverArgs.hasArg(options::OPT_nostdinc)) return; + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> Dir(getDriver().ResourceDir); + llvm::sys::path::append(Dir, "include"); + addSystemInclude(DriverArgs, CC1Args, Dir.str()); + } + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { SmallString<128> Dir(computeSysRoot()); llvm::sys::path::append(Dir, "include"); @@ -135,7 +141,7 @@ std::string RISCVToolChain::computeSysRoot() const { if (!llvm::sys::fs::exists(SysRootDir)) return std::string(); - return std::string(SysRootDir.str()); + return std::string(SysRootDir); } void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -157,6 +163,7 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, } else { CmdArgs.push_back("elf32lriscv"); } + CmdArgs.push_back("-X"); std::string Linker = getToolChain().GetLinkerPath(); @@ -183,19 +190,21 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); // TODO: add C++ includes and libs if compiling C++. if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { - if (ToolChain.ShouldLinkCXXStdlib(Args)) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (D.CCCIsCXX()) { + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } CmdArgs.push_back("--start-group"); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgloss"); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h index 62099bee0404..cec817ef7190 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -1,4 +1,4 @@ -//===--- RISCVToolchain.h - RISCV ToolChain Implementations -----*- C++ -*-===// +//===--- RISCVToolchain.h - RISC-V ToolChain Implementations ----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -22,7 +22,6 @@ public: const llvm::opt::ArgList &Args); static bool hasGCCToolchain(const Driver &D, const llvm::opt::ArgList &Args); - bool IsIntegratedAssemblerDefault() const override { return true; } void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind) const override; @@ -47,7 +46,7 @@ private: namespace tools { namespace RISCV { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("RISCV::Linker", "ld", TC) {} bool hasIntegratedCPP() const override { return false; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h index bb482be68260..dceb0ab03669 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/ROCm.h @@ -15,13 +15,33 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/Triple.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/VersionTuple.h" +#include "llvm/TargetParser/Triple.h" namespace clang { namespace driver { +/// ABI version of device library. +struct DeviceLibABIVersion { + unsigned ABIVersion = 0; + DeviceLibABIVersion(unsigned V) : ABIVersion(V) {} + static DeviceLibABIVersion fromCodeObjectVersion(unsigned CodeObjectVersion) { + if (CodeObjectVersion < 4) + CodeObjectVersion = 4; + return DeviceLibABIVersion(CodeObjectVersion * 100); + } + /// Whether ABI version bc file is requested. + /// ABIVersion is code object version multiplied by 100. Code object v4 + /// and below works with ROCm 5.0 and below which does not have + /// abi_version_*.bc. Code object v5 requires abi_version_500.bc. + bool requiresLibrary() { return ABIVersion >= 500; } + std::string toString() { + assert(ABIVersion % 100 == 0 && "Not supported"); + return Twine(ABIVersion / 100).str(); + } +}; + /// A class to find a viable ROCM installation /// TODO: Generalize to handle libclc. class RocmInstallationDetector { @@ -57,6 +77,9 @@ private: const Driver &D; bool HasHIPRuntime = false; bool HasDeviceLibrary = false; + bool HasHIPStdParLibrary = false; + bool HasRocThrustLibrary = false; + bool HasRocPrimLibrary = false; // Default version if not detected or specified. const unsigned DefaultVersionMajor = 3; @@ -76,6 +99,13 @@ private: std::vector<std::string> RocmDeviceLibPathArg; // HIP runtime path specified by --hip-path. StringRef HIPPathArg; + // HIP Standard Parallel Algorithm acceleration library specified by + // --hipstdpar-path + StringRef HIPStdParPathArg; + // rocThrust algorithm library specified by --hipstdpar-thrust-path + StringRef HIPRocThrustPathArg; + // rocPrim algorithm library specified by --hipstdpar-prim-path + StringRef HIPRocPrimPathArg; // HIP version specified by --hip-version. StringRef HIPVersionArg; // Wheter -nogpulib is specified. @@ -87,6 +117,7 @@ private: SmallString<0> LibPath; SmallString<0> LibDevicePath; SmallString<0> IncludePath; + SmallString<0> SharePath; llvm::StringMap<std::string> LibDeviceMap; // Libraries that are always linked. @@ -107,6 +138,10 @@ private: ConditionalLibrary DenormalsAreZero; ConditionalLibrary CorrectlyRoundedSqrt; + // Maps ABI version to library path. The version number is in the format of + // three digits as used in the ABI version library name. + std::map<unsigned, std::string> ABIVersionMap; + // Cache ROCm installation search paths. SmallVector<Candidate, 4> ROCmSearchDirs; bool PrintROCmSearchDirs; @@ -142,7 +177,12 @@ public: getCommonBitcodeLibs(const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile, bool Wave64, bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, - bool FastRelaxedMath, bool CorrectSqrt) const; + bool FastRelaxedMath, bool CorrectSqrt, + DeviceLibABIVersion ABIVer, bool isOpenMP) const; + /// Check file paths of default bitcode libraries common to AMDGPU based + /// toolchains. \returns false if there are invalid or missing files. + bool checkCommonBitcodeLibs(StringRef GPUArch, StringRef LibDeviceFile, + DeviceLibABIVersion ABIVer) const; /// Check whether we detected a valid HIP runtime. bool hasHIPRuntime() const { return HasHIPRuntime; } @@ -150,6 +190,9 @@ public: /// Check whether we detected a valid ROCm device library. bool hasDeviceLibrary() const { return HasDeviceLibrary; } + /// Check whether we detected a valid HIP STDPAR Acceleration library. + bool hasHIPStdParLibrary() const { return HasHIPStdParLibrary; } + /// Print information about the detected ROCm installation. void print(raw_ostream &OS) const; @@ -214,9 +257,19 @@ public: return CorrectlyRoundedSqrt.get(Enabled); } + StringRef getABIVersionPath(DeviceLibABIVersion ABIVer) const { + auto Loc = ABIVersionMap.find(ABIVer.ABIVersion); + if (Loc == ABIVersionMap.end()) + return StringRef(); + return Loc->second; + } + /// Get libdevice file for given architecture - std::string getLibDeviceFile(StringRef Gpu) const { - return LibDeviceMap.lookup(Gpu); + StringRef getLibDeviceFile(StringRef Gpu) const { + auto Loc = LibDeviceMap.find(Gpu); + if (Loc == LibDeviceMap.end()) + return ""; + return Loc->second; } void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, @@ -226,7 +279,7 @@ public: void detectHIPRuntime(); /// Get the values for --rocm-device-lib-path arguments - std::vector<std::string> getRocmDeviceLibPathArg() const { + ArrayRef<std::string> getRocmDeviceLibPathArg() const { return RocmDeviceLibPathArg; } @@ -236,7 +289,7 @@ public: /// Get the value for --hip-version argument StringRef getHIPVersionArg() const { return HIPVersionArg; } - std::string getHIPVersion() const { return DetectedVersion; } + StringRef getHIPVersion() const { return DetectedVersion; } }; } // end namespace driver diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.cpp new file mode 100644 index 000000000000..27de69550853 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.cpp @@ -0,0 +1,93 @@ +//===--- SPIRV.cpp - SPIR-V Tool 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 "SPIRV.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/InputInfo.h" +#include "clang/Driver/Options.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace llvm::opt; + +void SPIRV::constructTranslateCommand(Compilation &C, const Tool &T, + const JobAction &JA, + const InputInfo &Output, + const InputInfo &Input, + const llvm::opt::ArgStringList &Args) { + llvm::opt::ArgStringList CmdArgs(Args); + CmdArgs.push_back(Input.getFilename()); + + if (Input.getType() == types::TY_PP_Asm) + CmdArgs.push_back("-to-binary"); + if (Output.getType() == types::TY_PP_Asm) + CmdArgs.push_back("--spirv-tools-dis"); + + CmdArgs.append({"-o", Output.getFilename()}); + + const char *Exec = + C.getArgs().MakeArgString(T.getToolChain().GetProgramPath("llvm-spirv")); + C.addCommand(std::make_unique<Command>(JA, T, ResponseFileSupport::None(), + Exec, CmdArgs, Input, Output)); +} + +void SPIRV::Translator::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + if (Inputs.size() != 1) + llvm_unreachable("Invalid number of input files."); + constructTranslateCommand(C, *this, JA, Output, Inputs[0], {}); +} + +clang::driver::Tool *SPIRVToolChain::getTranslator() const { + if (!Translator) + Translator = std::make_unique<SPIRV::Translator>(*this); + return Translator.get(); +} + +clang::driver::Tool *SPIRVToolChain::SelectTool(const JobAction &JA) const { + Action::ActionClass AC = JA.getKind(); + return SPIRVToolChain::getTool(AC); +} + +clang::driver::Tool *SPIRVToolChain::getTool(Action::ActionClass AC) const { + switch (AC) { + default: + break; + case Action::BackendJobClass: + case Action::AssembleJobClass: + return SPIRVToolChain::getTranslator(); + } + return ToolChain::getTool(AC); +} +clang::driver::Tool *SPIRVToolChain::buildLinker() const { + return new tools::SPIRV::Linker(*this); +} + +void SPIRV::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const ToolChain &ToolChain = getToolChain(); + std::string Linker = ToolChain.GetProgramPath(getShortName()); + ArgStringList CmdArgs; + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Args.MakeArgString(Linker), CmdArgs, + Inputs, Output)); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h new file mode 100644 index 000000000000..d4247ee0557f --- /dev/null +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/SPIRV.h @@ -0,0 +1,89 @@ +//===--- SPIRV.h - SPIR-V Tool 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_SPIRV_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SPIRV_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace SPIRV { + +void constructTranslateCommand(Compilation &C, const Tool &T, + const JobAction &JA, const InputInfo &Output, + const InputInfo &Input, + const llvm::opt::ArgStringList &Args); + +class LLVM_LIBRARY_VISIBILITY Translator : public Tool { +public: + Translator(const ToolChain &TC) + : Tool("SPIR-V::Translator", "llvm-spirv", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool hasIntegratedAssembler() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("SPIRV::Linker", "spirv-link", 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; +}; + +} // namespace SPIRV +} // namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY SPIRVToolChain final : public ToolChain { + mutable std::unique_ptr<Tool> Translator; + +public: + SPIRVToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : ToolChain(D, Triple, Args) {} + + bool useIntegratedAs() const override { return true; } + + 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; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } + bool isPICDefaultForced() const override { return false; } + bool SupportsProfiling() const override { return false; } + + clang::driver::Tool *SelectTool(const JobAction &JA) const override; + +protected: + clang::driver::Tool *getTool(Action::ActionClass AC) const override; + Tool *buildLinker() const override; + +private: + clang::driver::Tool *getTranslator() const; +}; + +} // namespace toolchains +} // namespace driver +} // namespace clang +#endif diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp index 4d1af094f481..200ac46aa534 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.cpp @@ -8,12 +8,16 @@ #include "Solaris.h" #include "CommonArgs.h" +#include "Gnu.h" #include "clang/Basic/LangStandard.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -29,20 +33,50 @@ void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; + // Just call the Gnu version, which enforces gas on Solaris. + gnutools::Assembler::ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput); +} - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); +bool solaris::isLinkerGnuLd(const ToolChain &TC, const ArgList &Args) { + // Only used if targetting Solaris. + const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ); + StringRef UseLinker = A ? A->getValue() : CLANG_DEFAULT_LINKER; + return UseLinker == "bfd" || UseLinker == "gld"; +} - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); +static bool getPIE(const ArgList &Args, const ToolChain &TC) { + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_r)) + return false; - for (const auto &II : Inputs) - CmdArgs.push_back(II.getFilename()); + return Args.hasFlag(options::OPT_pie, options::OPT_no_pie, + TC.isPIEDefault(Args)); +} - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), - Exec, CmdArgs, Inputs, Output)); +// FIXME: Need to handle CLANG_DEFAULT_LINKER here? +std::string solaris::Linker::getLinkerPath(const ArgList &Args) const { + const ToolChain &ToolChain = getToolChain(); + if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { + StringRef UseLinker = A->getValue(); + if (!UseLinker.empty()) { + if (llvm::sys::path::is_absolute(UseLinker) && + llvm::sys::fs::can_execute(UseLinker)) + return std::string(UseLinker); + + // Accept 'bfd' and 'gld' as aliases for the GNU linker. + if (UseLinker == "bfd" || UseLinker == "gld") + // FIXME: Could also use /usr/bin/gld here. + return "/usr/gnu/bin/ld"; + + // Accept 'ld' as alias for the default linker + if (UseLinker != "ld") + ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name) + << A->getAsString(Args); + } + } + + // getDefaultLinker() always returns an absolute path. + return ToolChain.getDefaultLinker(); } void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -50,24 +84,38 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const auto &ToolChain = static_cast<const Solaris &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool IsPIE = getPIE(Args, ToolChain); + const bool LinkerIsGnuLd = isLinkerGnuLd(ToolChain, Args); ArgStringList CmdArgs; - // Demangle C++ names in errors - CmdArgs.push_back("-C"); + // Demangle C++ names in errors. GNU ld already defaults to --demangle. + if (!LinkerIsGnuLd) + CmdArgs.push_back("-C"); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared, + options::OPT_r)) { CmdArgs.push_back("-e"); CmdArgs.push_back("_start"); } + if (IsPIE) { + if (LinkerIsGnuLd) { + CmdArgs.push_back("-pie"); + } else { + CmdArgs.push_back("-z"); + CmdArgs.push_back("type=pie"); + } + } + if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); CmdArgs.push_back("-dn"); } else { - CmdArgs.push_back("-Bdynamic"); - if (Args.hasArg(options::OPT_shared)) { + if (!Args.hasArg(options::OPT_r) && Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-shared"); - } // libpthread has been folded into libc since Solaris 10, no need to do // anything for pthreads. Claim argument to avoid warning. @@ -75,19 +123,50 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_pthreads); } + if (LinkerIsGnuLd) { + // Set the correct linker emulation for 32- and 64-bit Solaris. + switch (Arch) { + case llvm::Triple::x86: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf_i386_sol2"); + break; + case llvm::Triple::x86_64: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf_x86_64_sol2"); + break; + case llvm::Triple::sparc: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf32_sparc_sol2"); + break; + case llvm::Triple::sparcv9: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf64_sparc_sol2"); + break; + default: + break; + } + + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + CmdArgs.push_back("--eh-frame-hdr"); + } else { + // -rdynamic is a no-op with Solaris ld. Claim argument to avoid warning. + Args.ClaimAllArgs(options::OPT_rdynamic); + } + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi); bool HaveAnsi = false; @@ -102,29 +181,54 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409. if (HaveAnsi || (LangStd && !LangStd->isGNUMode())) values_X = "values-Xc.o"; - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(values_X))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(values_X))); const char *values_xpg = "values-xpg6.o"; // Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409. if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99()) values_xpg = "values-xpg4.o"; - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath(values_xpg))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(values_xpg))); + + const char *crtbegin = nullptr; + if (Args.hasArg(options::OPT_shared) || IsPIE) + crtbegin = "crtbeginS.o"; + else + crtbegin = "crtbegin.o"; + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + // Add crtfastmath.o if available and fast math is enabled. + ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs); } - getToolChain().AddFilePathLibArgs(Args, CmdArgs); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + Args.addAllArgs(CmdArgs, + {options::OPT_L, options::OPT_T_Group, options::OPT_r}); - Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_e, options::OPT_r}); + bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { + // Use the static OpenMP runtime with -static-openmp + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && + !Args.hasArg(options::OPT_static); + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (getToolChain().ShouldLinkCXXStdlib(Args)) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (D.CCCIsCXX()) { + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below. + if (D.IsFlangMode()) { + addFortranRuntimeLibraryPath(getToolChain(), Args, CmdArgs); + addFortranRuntimeLibs(getToolChain(), Args, CmdArgs); + CmdArgs.push_back("-lm"); + } if (Args.hasArg(options::OPT_fstack_protector) || Args.hasArg(options::OPT_fstack_protector_strong) || Args.hasArg(options::OPT_fstack_protector_all)) { @@ -132,25 +236,57 @@ 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 (Arch == llvm::Triple::sparc) { + addAsNeededOption(ToolChain, Args, CmdArgs, true); + CmdArgs.push_back("-latomic"); + addAsNeededOption(ToolChain, Args, CmdArgs, false); + } + addAsNeededOption(ToolChain, Args, CmdArgs, true); CmdArgs.push_back("-lgcc_s"); + addAsNeededOption(ToolChain, Args, CmdArgs, false); CmdArgs.push_back("-lc"); if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("-lm"); } - if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); + const SanitizerArgs &SA = ToolChain.getSanitizerArgs(Args); + if (NeedsSanitizerDeps) { + linkSanitizerRuntimeDeps(ToolChain, Args, CmdArgs); + + // Work around Solaris/amd64 ld bug when calling __tls_get_addr directly. + // However, ld -z relax=transtls is available since Solaris 11.2, but not + // in Illumos. + if (Arch == llvm::Triple::x86_64 && + (SA.needsAsanRt() || SA.needsStatsRt() || + (SA.needsUbsanRt() && !SA.requiresMinimalRuntime())) && + !LinkerIsGnuLd) { + CmdArgs.push_back("-z"); + CmdArgs.push_back("relax=transtls"); + } + } + // Avoid AsanInitInternal cycle, Issue #64126. + if (ToolChain.getTriple().isX86() && SA.needsSharedRt() && + SA.needsAsanRt()) { + CmdArgs.push_back("-z"); + CmdArgs.push_back("now"); + } } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + const char *crtend = nullptr; + if (Args.hasArg(options::OPT_shared) || IsPIE) + crtend = "crtendS.o"; + else + crtend = "crtend.o"; + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - getToolChain().addProfileRTLibs(Args, CmdArgs); + ToolChain.addProfileRTLibs(Args, CmdArgs); - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + const char *Exec = Args.MakeArgString(getLinkerPath(Args)); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, Inputs, Output)); } @@ -159,13 +295,12 @@ static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) { switch (Triple.getArch()) { case llvm::Triple::x86: case llvm::Triple::sparc: + default: break; case llvm::Triple::x86_64: return "/amd64"; case llvm::Triple::sparcv9: return "/sparcv9"; - default: - llvm_unreachable("Unsupported architecture"); } return ""; } @@ -192,7 +327,7 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, // If we are currently running Clang inside of the requested system root, // add its parent library path to those searched. - if (StringRef(D.Dir).startswith(D.SysRoot)) + if (StringRef(D.Dir).starts_with(D.SysRoot)) addPathIfExists(D, D.Dir + "/../lib", Paths); addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths); @@ -200,7 +335,6 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, SanitizerMask Solaris::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; - const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; SanitizerMask Res = ToolChain::getSupportedSanitizers(); // FIXME: Omit X86_64 until 64-bit support is figured out. if (IsX86) { @@ -208,12 +342,17 @@ SanitizerMask Solaris::getSupportedSanitizers() const { Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; } - if (IsX86 || IsX86_64) - Res |= SanitizerKind::Function; Res |= SanitizerKind::Vptr; return Res; } +const char *Solaris::getDefaultLinker() const { + // FIXME: Only handle Solaris ld and GNU ld here. + return llvm::StringSwitch<const char *>(CLANG_DEFAULT_LINKER) + .Cases("bfd", "gld", "/usr/gnu/bin/ld") + .Default("/usr/bin/ld"); +} + Tool *Solaris::buildAssembler() const { return new tools::solaris::Assembler(*this); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h index fbac92c2c0f3..9ec83b773da4 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Solaris.h @@ -17,12 +17,11 @@ namespace clang { namespace driver { namespace tools { -/// solaris -- Directly call Solaris assembler and linker +/// Directly call Solaris assembler and linker namespace solaris { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public gnutools::Assembler { public: - Assembler(const ToolChain &TC) - : Tool("solaris::Assembler", "assembler", TC) {} + Assembler(const ToolChain &TC) : gnutools::Assembler(TC) {} bool hasIntegratedCPP() const override { return false; } @@ -32,12 +31,15 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +bool isLinkerGnuLd(const ToolChain &TC, const llvm::opt::ArgList &Args); + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("solaris::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } + std::string getLinkerPath(const llvm::opt::ArgList &Args) const; void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -63,12 +65,8 @@ public: llvm::opt::ArgStringList &CC1Args) const override; SanitizerMask getSupportedSanitizers() const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } - const char *getDefaultLinker() const override { - // clang currently uses Solaris ld-only options. - return "/usr/bin/ld"; - } + const char *getDefaultLinker() const override; protected: Tool *buildAssembler() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/TCE.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/TCE.cpp index 33a81c54bd42..5f4051d31168 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/TCE.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/TCE.cpp @@ -34,7 +34,9 @@ bool TCEToolChain::IsMathErrnoDefault() const { return true; } bool TCEToolChain::isPICDefault() const { return false; } -bool TCEToolChain::isPIEDefault() const { return false; } +bool TCEToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool TCEToolChain::isPICDefaultForced() const { return false; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/TCE.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/TCE.h index 72933dae965e..31a64cfe878a 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/TCE.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/TCE.h @@ -27,7 +27,7 @@ public: bool IsMathErrnoDefault() const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; }; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp index e28f340f9aad..39529e0b6b35 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp @@ -28,18 +28,32 @@ VEToolChain::VEToolChain(const Driver &D, const llvm::Triple &Triple, getProgramPaths().push_back("/opt/nec/ve/bin"); // ProgramPaths are found via 'PATH' environment variable. - // default file paths are: - // ${RESOURCEDIR}/lib/linux/ve (== getArchSpecificLibPath) - // /lib/../lib64 - // /usr/lib/../lib64 - // ${BINPATH}/../lib - // /lib - // /usr/lib - // - // These are OK for host, but no go for VE. So, defines them all - // from scratch here. + // Default library paths are following: + // ${RESOURCEDIR}/lib/ve-unknown-linux-gnu, + // These are OK. + + // Default file paths are following: + // ${RESOURCEDIR}/lib/ve-unknown-linux-gnu, (== getArchSpecificLibPaths) + // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPaths) + // /lib/../lib64, + // /usr/lib/../lib64, + // ${BINPATH}/../lib, + // /lib, + // /usr/lib, + // These are OK for host, but no go for VE. + + // Define file paths from scratch here. getFilePaths().clear(); - getFilePaths().push_back(getArchSpecificLibPath()); + + // Add library directories: + // ${BINPATH}/../lib/ve-unknown-linux-gnu, (== getStdlibPath) + // ${RESOURCEDIR}/lib/ve-unknown-linux-gnu, (== getArchSpecificLibPaths) + // ${RESOURCEDIR}/lib/linux/ve, (== getArchSpecificLibPaths) + // ${SYSROOT}/opt/nec/ve/lib, + if (std::optional<std::string> Path = getStdlibPath()) + getFilePaths().push_back(std::move(*Path)); + for (const auto &Path : getArchSpecificLibPaths()) + getFilePaths().push_back(Path); getFilePaths().push_back(computeSysRoot() + "/opt/nec/ve/lib"); } @@ -53,7 +67,9 @@ Tool *VEToolChain::buildLinker() const { bool VEToolChain::isPICDefault() const { return false; } -bool VEToolChain::isPIEDefault() const { return false; } +bool VEToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool VEToolChain::isPICDefaultForced() const { return false; } @@ -113,9 +129,10 @@ void VEToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArrayRef<StringRef> DirVec(Dirs); addSystemIncludes(DriverArgs, CC1Args, DirVec); } else { - SmallString<128> P(getDriver().ResourceDir); - llvm::sys::path::append(P, "include/c++/v1"); - addSystemInclude(DriverArgs, CC1Args, P); + // Add following paths for multiple target installation. + // ${INSTALLDIR}/include/ve-unknown-linux-gnu/c++/v1, + // ${INSTALLDIR}/include/c++/v1, + addLibCxxIncludePaths(DriverArgs, CC1Args); } } @@ -126,7 +143,15 @@ void VEToolChain::AddCXXStdlibLibArgs(const ArgList &Args, tools::addArchSpecificRPath(*this, Args, CmdArgs); + // Add paths for libc++.so and other shared libraries. + if (std::optional<std::string> Path = getStdlibPath()) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back(Args.MakeArgString(*Path)); + } + CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); // libc++ requires -lpthread under glibc environment diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h index b330331ca84e..8b9ccaa7fada 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.h @@ -26,9 +26,8 @@ protected: Tool *buildLinker() const override; public: - bool IsIntegratedAssemblerDefault() const override { return true; } bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; bool SupportsProfiling() const override; bool hasBlocksRuntime() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp index 19f3571e6b38..0b16b660364f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -8,15 +8,17 @@ #include "WebAssembly.h" #include "CommonArgs.h" +#include "Gnu.h" #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Option/ArgList.h" +#include "llvm/Support/VirtualFileSystem.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -42,8 +44,15 @@ std::string wasm::Linker::getLinkerPath(const ArgList &Args) const { llvm::sys::fs::can_execute(UseLinker)) return std::string(UseLinker); - // Accept 'lld', and 'ld' as aliases for the default linker - if (UseLinker != "lld" && UseLinker != "ld") + // Interpret 'lld' as explicitly requesting `wasm-ld`, so look for that + // linker. Note that for `wasm32-wasip2` this overrides the default linker + // of `wasm-component-ld`. + if (UseLinker == "lld") { + return ToolChain.GetProgramPath("wasm-ld"); + } + + // Allow 'ld' as an alias for the default linker + if (UseLinker != "ld") ToolChain.getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args); } @@ -63,7 +72,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, ArgStringList CmdArgs; CmdArgs.push_back("-m"); - if (getToolChain().getTriple().isArch64Bit()) + if (ToolChain.getTriple().isArch64Bit()) CmdArgs.push_back("wasm64"); else CmdArgs.push_back("wasm32"); @@ -71,34 +80,56 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("--strip-all"); - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); + // On `wasip2` the default linker is `wasm-component-ld` which wraps the + // execution of `wasm-ld`. Find `wasm-ld` and pass it as an argument of where + // to find it to avoid it needing to hunt and rediscover or search `PATH` for + // where it is. + if (llvm::sys::path::stem(Linker).ends_with_insensitive( + "wasm-component-ld")) { + CmdArgs.push_back("--wasm-ld-path"); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetProgramPath("wasm-ld"))); + } + + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); - const char *Crt1 = "crt1.o"; - const char *Entry = NULL; + bool IsCommand = true; + const char *Crt1; + const char *Entry = nullptr; - // If crt1-command.o exists, it supports new-style commands, so use it. - // Otherwise, use the old crt1.o. This is a temporary transition measure. - // Once WASI libc no longer needs to support LLVM versions which lack - // support for new-style command, it can make crt1.o the same as - // crt1-command.o. And once LLVM no longer needs to support WASI libc - // versions before that, it can switch to using crt1-command.o. - if (ToolChain.GetFilePath("crt1-command.o") != "crt1-command.o") - Crt1 = "crt1-command.o"; + // When -shared is specified, use the reactor exec model unless + // specified otherwise. + if (Args.hasArg(options::OPT_shared)) + IsCommand = false; if (const Arg *A = Args.getLastArg(options::OPT_mexec_model_EQ)) { StringRef CM = A->getValue(); if (CM == "command") { - // Use default values. + IsCommand = true; } else if (CM == "reactor") { - Crt1 = "crt1-reactor.o"; - Entry = "_initialize"; + IsCommand = false; } else { ToolChain.getDriver().Diag(diag::err_drv_invalid_argument_to_option) << CM << A->getOption().getName(); } } + + if (IsCommand) { + // If crt1-command.o exists, it supports new-style commands, so use it. + // Otherwise, use the old crt1.o. This is a temporary transition measure. + // Once WASI libc no longer needs to support LLVM versions which lack + // support for new-style command, it can make crt1.o the same as + // crt1-command.o. And once LLVM no longer needs to support WASI libc + // versions before that, it can switch to using crt1-command.o. + Crt1 = "crt1.o"; + if (ToolChain.GetFilePath("crt1-command.o") != "crt1-command.o") + Crt1 = "crt1-command.o"; + } else { + Crt1 = "crt1-reactor.o"; + Entry = "_initialize"; + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(Crt1))); if (Entry) { @@ -106,6 +137,9 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Entry)); } + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back(Args.MakeArgString("-shared")); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -124,14 +158,25 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); + // When optimizing, if wasm-opt is available, run it. + std::string WasmOptPath; + if (Args.getLastArg(options::OPT_O_Group)) { + WasmOptPath = ToolChain.GetProgramPath("wasm-opt"); + if (WasmOptPath == "wasm-opt") { + WasmOptPath = {}; + } + } + + if (!WasmOptPath.empty()) { + CmdArgs.push_back("--keep-section=target_features"); + } + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), Linker, CmdArgs, Inputs, Output)); - // When optimizing, if wasm-opt is available, run it. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - auto WasmOptPath = getToolChain().GetProgramPath("wasm-opt"); - if (WasmOptPath != "wasm-opt") { + if (!WasmOptPath.empty()) { StringRef OOpt = "s"; if (A->getOption().matches(options::OPT_O4) || A->getOption().matches(options::OPT_Ofast)) @@ -143,13 +188,13 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (OOpt != "0") { const char *WasmOpt = Args.MakeArgString(WasmOptPath); - ArgStringList CmdArgs; - CmdArgs.push_back(Output.getFilename()); - CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); + ArgStringList OptArgs; + OptArgs.push_back(Output.getFilename()); + OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); + OptArgs.push_back("-o"); + OptArgs.push_back(Output.getFilename()); C.addCommand(std::make_unique<Command>( - JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, CmdArgs, + JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs, Inputs, Output)); } } @@ -193,6 +238,12 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, } } +const char *WebAssembly::getDefaultLinker() const { + if (getOS() == "wasip2") + return "wasm-component-ld"; + return "wasm-ld"; +} + bool WebAssembly::IsMathErrnoDefault() const { return false; } bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; } @@ -201,12 +252,12 @@ bool WebAssembly::UseObjCMixedDispatch() const { return true; } bool WebAssembly::isPICDefault() const { return false; } -bool WebAssembly::isPIEDefault() const { return false; } +bool WebAssembly::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool WebAssembly::isPICDefaultForced() const { return false; } -bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; } - bool WebAssembly::hasBlocksRuntime() const { return false; } // TODO: Support profiling. @@ -293,21 +344,24 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, // '-fwasm-exceptions' implies exception-handling feature CC1Args.push_back("-target-feature"); CC1Args.push_back("+exception-handling"); + // Backend needs -wasm-enable-eh to enable Wasm EH + CC1Args.push_back("-mllvm"); + CC1Args.push_back("-wasm-enable-eh"); } for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { StringRef Opt = A->getValue(0); - if (Opt.startswith("-emscripten-cxx-exceptions-allowed")) { + if (Opt.starts_with("-emscripten-cxx-exceptions-allowed")) { // '-mllvm -emscripten-cxx-exceptions-allowed' should be used with // '-mllvm -enable-emscripten-cxx-exceptions' - bool EmExceptionArgExists = false; + bool EmEHArgExists = false; for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions") { - EmExceptionArgExists = true; + EmEHArgExists = true; break; } } - if (!EmExceptionArgExists) + if (!EmEHArgExists) getDriver().Diag(diag::err_drv_argument_only_allowed_with) << "-mllvm -emscripten-cxx-exceptions-allowed" << "-mllvm -enable-emscripten-cxx-exceptions"; @@ -323,6 +377,38 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, ":noinline")); } } + + if (Opt.starts_with("-wasm-enable-sjlj")) { + // '-mllvm -wasm-enable-sjlj' is not compatible with + // '-mno-exception-handling' + if (DriverArgs.hasFlag(options::OPT_mno_exception_handing, + options::OPT_mexception_handing, false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-mllvm -wasm-enable-sjlj" + << "-mno-exception-handling"; + // '-mllvm -wasm-enable-sjlj' is not compatible with + // '-mllvm -enable-emscripten-cxx-exceptions' + // because we don't allow Emscripten EH + Wasm SjLj + for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { + if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions") + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-mllvm -wasm-enable-sjlj" + << "-mllvm -enable-emscripten-cxx-exceptions"; + } + // '-mllvm -wasm-enable-sjlj' is not compatible with + // '-mllvm -enable-emscripten-sjlj' + for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { + if (StringRef(A->getValue(0)) == "-enable-emscripten-sjlj") + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-mllvm -wasm-enable-sjlj" + << "-mllvm -enable-emscripten-sjlj"; + } + // '-mllvm -wasm-enable-sjlj' implies exception-handling feature + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+exception-handling"); + // Backend needs '-exception-model=wasm' to use Wasm EH instructions + CC1Args.push_back("-exception-model=wasm"); + } } } @@ -334,7 +420,11 @@ ToolChain::CXXStdlibType WebAssembly::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); - if (Value != "libc++") + if (Value == "libc++") + return ToolChain::CST_Libcxx; + else if (Value == "libstdc++") + return ToolChain::CST_Libstdcxx; + else getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } @@ -380,17 +470,18 @@ void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && - !DriverArgs.hasArg(options::OPT_nostdincxx)) { - if (getTriple().getOS() != llvm::Triple::UnknownOS) { - const std::string MultiarchTriple = - getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/" + MultiarchTriple + - "/c++/v1"); - } - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/c++/v1"); + + if (DriverArgs.hasArg(options::OPT_nostdlibinc, options::OPT_nostdinc, + options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addLibCxxIncludePaths(DriverArgs, CC1Args); + break; + case ToolChain::CST_Libstdcxx: + addLibStdCXXIncludePaths(DriverArgs, CC1Args); + break; } } @@ -400,10 +491,13 @@ void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: - llvm_unreachable("invalid stdlib name"); + CmdArgs.push_back("-lstdc++"); + break; } } @@ -412,9 +506,86 @@ SanitizerMask WebAssembly::getSupportedSanitizers() const { if (getTriple().isOSEmscripten()) { Res |= SanitizerKind::Vptr | SanitizerKind::Leak | SanitizerKind::Address; } + // -fsanitize=function places two words before the function label, which are + // -unsupported. + Res &= ~SanitizerKind::Function; return Res; } Tool *WebAssembly::buildLinker() const { return new tools::wasm::Linker(*this); } + +void WebAssembly::addLibCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + std::string LibPath = SysRoot + "/include"; + const std::string MultiarchTriple = + getMultiarchTriple(D, getTriple(), SysRoot); + bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS); + + std::string Version = detectLibcxxVersion(LibPath); + if (Version.empty()) + return; + + // First add the per-target include path if the OS is known. + if (IsKnownOs) { + std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/" + Version; + addSystemInclude(DriverArgs, CC1Args, TargetDir); + } + + // Second add the generic one. + addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version); +} + +void WebAssembly::addLibStdCXXIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // We cannot use GCCInstallationDetector here as the sysroot usually does + // not contain a full GCC installation. + // Instead, we search the given sysroot for /usr/include/xx, similar + // to how we do it for libc++. + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + std::string LibPath = SysRoot + "/include"; + const std::string MultiarchTriple = + getMultiarchTriple(D, getTriple(), SysRoot); + bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS); + + // This is similar to detectLibcxxVersion() + std::string Version; + { + std::error_code EC; + Generic_GCC::GCCVersion MaxVersion = + Generic_GCC::GCCVersion::Parse("0.0.0"); + SmallString<128> Path(LibPath); + llvm::sys::path::append(Path, "c++"); + for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(Path, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + if (VersionText[0] != 'v') { + auto Version = Generic_GCC::GCCVersion::Parse(VersionText); + if (Version > MaxVersion) + MaxVersion = Version; + } + } + if (MaxVersion.Major > 0) + Version = MaxVersion.Text; + } + + if (Version.empty()) + return; + + // First add the per-target include path if the OS is known. + if (IsKnownOs) { + std::string TargetDir = LibPath + "/c++/" + Version + "/" + MultiarchTriple; + addSystemInclude(DriverArgs, CC1Args, TargetDir); + } + + // Second add the generic one. + addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version); + // Third the backward one. + addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version + "/backward"); +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h index 8a3f82d9efdf..76e0ca39bd74 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.h @@ -18,7 +18,7 @@ namespace driver { namespace tools { namespace wasm { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: explicit Linker(const ToolChain &TC) : Tool("wasm::Linker", "linker", TC) {} bool isLinkJob() const override { return true; } @@ -45,12 +45,12 @@ private: bool IsObjCNonFragileABIDefault() const override; bool UseObjCMixedDispatch() const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; - bool IsIntegratedAssemblerDefault() const override; bool hasBlocksRuntime() const override; bool SupportsProfiling() const override; bool HasNativeLLVMSupport() const override; + unsigned GetDefaultDwarfVersion() const override { return 4; } void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, @@ -67,13 +67,22 @@ private: llvm::opt::ArgStringList &CmdArgs) const override; SanitizerMask getSupportedSanitizers() const override; - const char *getDefaultLinker() const override { return "wasm-ld"; } + const char *getDefaultLinker() const override; + + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } Tool *buildLinker() const override; std::string getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, StringRef SysRoot) const override; + + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + void addLibStdCXXIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; }; } // end namespace toolchains diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp index 5f94f83d3691..c95ebabdd30c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.cpp @@ -63,11 +63,10 @@ void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { ArgStringList CmdArgs; + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); } if (Args.hasArg(options::OPT_v)) @@ -102,7 +101,9 @@ Tool *XCoreToolChain::buildLinker() const { bool XCoreToolChain::isPICDefault() const { return false; } -bool XCoreToolChain::isPIEDefault() const { return false; } +bool XCoreToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool XCoreToolChain::isPICDefaultForced() const { return false; } @@ -128,6 +129,10 @@ void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { CC1Args.push_back("-nostdsysteminc"); + // Set `-fno-use-cxa-atexit` to default. + if (!DriverArgs.hasFlag(options::OPT_fuse_cxa_atexit, + options::OPT_fno_use_cxa_atexit, false)) + CC1Args.push_back("-fno-use-cxa-atexit"); } void XCoreToolChain::AddClangCXXStdlibIncludeArgs( diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h index 41dce08454c0..95359a6e2542 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/XCore.h @@ -20,7 +20,7 @@ namespace XCore { // For XCore, we do not need to instantiate tools for PreProcess, PreCompile and // Compile. // We simply use "clang -cc1" for those actions. -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { public: Assembler(const ToolChain &TC) : Tool("XCore::Assembler", "XCore-as", TC) {} @@ -31,7 +31,7 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { public: Linker(const ToolChain &TC) : Tool("XCore::Linker", "XCore-ld", TC) {} @@ -57,8 +57,9 @@ protected: Tool *buildLinker() const override; public: + bool IsIntegratedAssemblerDefault() const override { return false; } bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; bool SupportsProfiling() const override; bool hasBlocksRuntime() const override; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp index f921227076a5..96dbf602e7c1 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp @@ -11,11 +11,17 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/WithColor.h" +using namespace clang; using namespace clang::driver; +using namespace clang::driver::tools; using namespace clang::driver::toolchains; +using namespace llvm; using namespace llvm::opt; -using namespace clang; +using namespace llvm::sys; ZOS::ZOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args) {} @@ -31,3 +37,303 @@ void ZOS::addClangTargetOptions(const ArgList &DriverArgs, options::OPT_fno_aligned_allocation)) CC1Args.push_back("-faligned-alloc-unavailable"); } + +void zos::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + // Specify assembler output file. + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + // Specify assembler input file. + // The system assembler on z/OS takes exactly one input file. The driver is + // expected to invoke as(1) separately for each assembler source input file. + if (Inputs.size() != 1) + llvm_unreachable("Invalid number of input files."); + const InputInfo &II = Inputs[0]; + assert((II.isFilename() || II.isNothing()) && "Invalid input."); + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); +} + +static std::string getLEHLQ(const ArgList &Args) { + if (Args.hasArg(options::OPT_mzos_hlq_le_EQ)) { + Arg *LEHLQArg = Args.getLastArg(options::OPT_mzos_hlq_le_EQ); + StringRef HLQ = LEHLQArg->getValue(); + if (!HLQ.empty()) + return HLQ.str(); + } + return "CEE"; +} + +static std::string getClangHLQ(const ArgList &Args) { + if (Args.hasArg(options::OPT_mzos_hlq_clang_EQ)) { + Arg *ClangHLQArg = Args.getLastArg(options::OPT_mzos_hlq_clang_EQ); + StringRef HLQ = ClangHLQArg->getValue(); + if (!HLQ.empty()) + return HLQ.str(); + } + return getLEHLQ(Args); +} + +static std::string getCSSHLQ(const ArgList &Args) { + if (Args.hasArg(options::OPT_mzos_hlq_csslib_EQ)) { + Arg *CsslibHLQArg = Args.getLastArg(options::OPT_mzos_hlq_csslib_EQ); + StringRef HLQ = CsslibHLQArg->getValue(); + if (!HLQ.empty()) + return HLQ.str(); + } + return "SYS1"; +} + +void zos::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + const char *LinkingOutput) const { + const ZOS &ToolChain = static_cast<const ZOS &>(getToolChain()); + ArgStringList CmdArgs; + + const bool IsSharedLib = + Args.hasFlag(options::OPT_shared, options::OPT_static, false); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + SmallString<128> LinkerOptions; + LinkerOptions = "AMODE="; + LinkerOptions += "64"; + LinkerOptions += ",LIST"; + LinkerOptions += ",DYNAM=DLL"; + LinkerOptions += ",MSGLEVEL=4"; + LinkerOptions += ",CASE=MIXED"; + LinkerOptions += ",REUS=RENT"; + + CmdArgs.push_back("-b"); + CmdArgs.push_back(Args.MakeArgString(LinkerOptions)); + + if (!IsSharedLib) { + CmdArgs.push_back("-e"); + CmdArgs.push_back("CELQSTRT"); + + CmdArgs.push_back("-O"); + CmdArgs.push_back("CELQSTRT"); + + CmdArgs.push_back("-u"); + CmdArgs.push_back("CELQMAIN"); + } + + // Generate side file if -shared option is present. + if (IsSharedLib) { + StringRef OutputName = Output.getFilename(); + // Strip away the last file suffix in presence from output name and add + // a new .x suffix. + size_t Suffix = OutputName.find_last_of('.'); + const char *SideDeckName = + Args.MakeArgString(OutputName.substr(0, Suffix) + ".x"); + CmdArgs.push_back("-x"); + CmdArgs.push_back(SideDeckName); + } else { + // We need to direct side file to /dev/null to suppress linker warning when + // the object file contains exported symbols, and -shared or + // -Wl,-x<sidedeck>.x is not specified. + CmdArgs.push_back("-x"); + CmdArgs.push_back("/dev/null"); + } + + // Add archive library search paths. + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); + + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + // Specify linker input file(s) + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + // z/OS tool chain depends on LE data sets and the CSSLIB data set. + // These data sets can have different high level qualifiers (HLQs) + // as each installation can define them differently. + + std::string LEHLQ = getLEHLQ(Args); + std::string CsslibHLQ = getCSSHLQ(Args); + + StringRef ld_env_var = StringRef(getenv("_LD_SYSLIB")).trim(); + if (ld_env_var.empty()) { + CmdArgs.push_back("-S"); + CmdArgs.push_back(Args.MakeArgString("//'" + LEHLQ + ".SCEEBND2'")); + CmdArgs.push_back("-S"); + CmdArgs.push_back(Args.MakeArgString("//'" + CsslibHLQ + ".CSSLIB'")); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + ld_env_var = StringRef(getenv("_LD_SIDE_DECKS")).trim(); + if (ld_env_var.empty()) { + CmdArgs.push_back( + Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS001)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS003)'")); + } else { + SmallVector<StringRef> ld_side_deck; + ld_env_var.split(ld_side_deck, ":"); + for (StringRef ld_loc : ld_side_deck) { + CmdArgs.push_back((ld_loc.str()).c_str()); + } + } + } + // Link libc++ library + if (ToolChain.ShouldLinkCXXStdlib(Args)) { + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + } + + // Specify compiler-rt library path for linker + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); +} + +ToolChain::RuntimeLibType ZOS::GetDefaultRuntimeLibType() const { + return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType ZOS::GetDefaultCXXStdlibType() const { + return ToolChain::CST_Libcxx; +} + +void ZOS::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libstdcxx: + llvm::report_fatal_error("linking libstdc++ is unimplemented on z/OS"); + break; + case ToolChain::CST_Libcxx: { + std::string ClangHLQ = getClangHLQ(Args); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXE)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXS)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXP)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXA)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQXLA)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQUNW)'")); + } break; + } +} + +auto ZOS::buildAssembler() const -> Tool * { return new zos::Assembler(*this); } + +auto ZOS::buildLinker() const -> Tool * { return new zos::Linker(*this); } + +void ZOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + const Driver &D = getDriver(); + + // resolve ResourceDir + std::string ResourceDir(D.ResourceDir); + + // zos_wrappers must take highest precedence + + // - <clang>/lib/clang/<ver>/include/zos_wrappers + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(ResourceDir); + path::append(P, "include", "zos_wrappers"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + + // - <clang>/lib/clang/<ver>/include + SmallString<128> P2(ResourceDir); + path::append(P2, "include"); + addSystemInclude(DriverArgs, CC1Args, P2.str()); + } + + // - /usr/include + if (Arg *SysIncludeArg = + DriverArgs.getLastArg(options::OPT_mzos_sys_include_EQ)) { + StringRef SysInclude = SysIncludeArg->getValue(); + + // fall back to the default include path + if (!SysInclude.empty()) { + + // -mzos-sys-include opton can have colon separated + // list of paths, so we need to parse the value. + StringRef PathLE(SysInclude); + size_t Colon = PathLE.find(':'); + if (Colon == StringRef::npos) { + addSystemInclude(DriverArgs, CC1Args, PathLE.str()); + return; + } + + while (Colon != StringRef::npos) { + SmallString<128> P = PathLE.substr(0, Colon); + addSystemInclude(DriverArgs, CC1Args, P.str()); + PathLE = PathLE.substr(Colon + 1); + Colon = PathLE.find(':'); + } + if (PathLE.size()) + addSystemInclude(DriverArgs, CC1Args, PathLE.str()); + + return; + } + } + + addSystemInclude(DriverArgs, CC1Args, "/usr/include"); +} + +void ZOS::TryAddIncludeFromPath(llvm::SmallString<128> Path, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + if (!getVFS().exists(Path)) { + if (DriverArgs.hasArg(options::OPT_v)) + WithColor::warning(errs(), "Clang") + << "ignoring nonexistent directory \"" << Path << "\"\n"; + if (!DriverArgs.hasArg(options::OPT__HASH_HASH_HASH)) + return; + } + addSystemInclude(DriverArgs, CC1Args, Path); +} + +void ZOS::AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdincxx) || + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + // <install>/bin/../include/c++/v1 + llvm::SmallString<128> InstallBin = + llvm::StringRef(getDriver().getInstalledDir()); + llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1"); + TryAddIncludeFromPath(InstallBin, DriverArgs, CC1Args); + break; + } + case ToolChain::CST_Libstdcxx: + llvm::report_fatal_error( + "picking up libstdc++ headers is unimplemented on z/OS"); + break; + } +} diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h index cace85d6da77..45204ba0a543 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/ZOS.h @@ -14,6 +14,39 @@ namespace clang { namespace driver { +namespace tools { + +/// Directly call system default assembler and linker. +namespace zos { + +class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("zos::Assembler", "assembler", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("zos::Linker", "linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace zos +} // end namespace tools + namespace toolchains { class LLVM_LIBRARY_VISIBILITY ZOS : public ToolChain { @@ -23,14 +56,39 @@ public: ~ZOS() override; bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return false; } - bool IsIntegratedAssemblerDefault() const override { return true; } + void TryAddIncludeFromPath(llvm::SmallString<128> Path, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + unsigned GetDefaultDwarfVersion() const override { return 4; } + CXXStdlibType GetDefaultCXXStdlibType() const override; + + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override; void addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const override; + + const char *getDefaultLinker() const override { return "/bin/ld"; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; }; } // end namespace toolchains |