diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-11-19 20:06:13 +0000 |
commit | c0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch) | |
tree | f42add1021b9f2ac6a69ac7cf6c4499962739a45 /clang/lib/Driver/ToolChains | |
parent | 344a3780b2e33f6ca763666c380202b18aab72a3 (diff) | |
download | src-c0981da47d5696fe36474fcf86b4ce03ae3ff818.tar.gz src-c0981da47d5696fe36474fcf86b4ce03ae3ff818.zip |
Vendor import of llvm-project main llvmorg-14-init-10186-gff7f2cfa959b.vendor/llvm-project/llvmorg-14-init-10186-gff7f2cfa959b
Diffstat (limited to 'clang/lib/Driver/ToolChains')
64 files changed, 1932 insertions, 1122 deletions
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 3000b8416adf..e4bbf498b9cd 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -98,6 +98,26 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-bnoentry"); } + // Specify PGO linker option without LTO + if (!D.isUsingLTO() && + (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + 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"); + // Specify linker output file. assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { @@ -218,15 +238,44 @@ 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++"); 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."); diff --git a/clang/lib/Driver/ToolChains/AIX.h b/clang/lib/Driver/ToolChains/AIX.h index d1ec6d10fb3a..e7ec3a5ece4d 100644 --- a/clang/lib/Driver/ToolChains/AIX.h +++ b/clang/lib/Driver/ToolChains/AIX.h @@ -63,13 +63,19 @@ 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; } 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; diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index d63c5e12c4af..b5eaf1adca6b 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -754,7 +754,7 @@ AMDGPUToolChain::detectSystemGPUs(const ArgList &Args, std::string ErrorMessage; if (int Result = llvm::sys::ExecuteAndWait( - Program.c_str(), {}, {}, Redirects, /* SecondsToWait */ 0, + Program, {}, {}, Redirects, /* SecondsToWait */ 0, /*MemoryLimit*/ 0, &ErrorMessage)) { if (Result > 0) { ErrorMessage = "Exited with error code " + std::to_string(Result); @@ -796,9 +796,9 @@ llvm::Error AMDGPUToolChain::getSystemGPUArch(const ArgList &Args, } GPUArch = GPUArchs[0]; if (GPUArchs.size() > 1) { - bool AllSame = std::all_of( - GPUArchs.begin(), GPUArchs.end(), - [&](const StringRef &GPUArch) { return GPUArch == GPUArchs.front(); }); + bool AllSame = llvm::all_of(GPUArchs, [&](const StringRef &GPUArch) { + return GPUArch == GPUArchs.front(); + }); if (!AllSame) return llvm::createStringError( std::error_code(), "Multiple AMD GPUs found with different archs"); @@ -893,3 +893,38 @@ bool AMDGPUToolChain::shouldSkipArgument(const llvm::opt::Arg *A) const { return true; return false; } + +llvm::SmallVector<std::string, 12> +ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, + const std::string &GPUArch) 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; + return {}; + } + + // If --hip-device-lib is not set, add the default bitcode libraries. + // TODO: There are way too many flags that change this. Do we need to check + // them all? + bool DAZ = DriverArgs.hasFlag(options::OPT_fgpu_flush_denormals_to_zero, + options::OPT_fno_gpu_flush_denormals_to_zero, + getDefaultDenormsAreZeroForTarget(Kind)); + bool FiniteOnly = DriverArgs.hasFlag( + options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, false); + bool UnsafeMathOpt = + DriverArgs.hasFlag(options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, false); + bool FastRelaxedMath = DriverArgs.hasFlag(options::OPT_ffast_math, + 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); + bool Wave64 = isWave64(DriverArgs, Kind); + + return RocmInstallation.getCommonBitcodeLibs( + DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, + FastRelaxedMath, CorrectSqrt); +} diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h index 50ed3b3ded9a..156bfd1fbdb2 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/clang/lib/Driver/ToolChains/AMDGPU.h @@ -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,14 +60,16 @@ protected: public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - unsigned GetDefaultDwarfVersion() const override { return 4; } + unsigned GetDefaultDwarfVersion() const override { return 5; } bool IsIntegratedAssemblerDefault() const override { return true; } bool IsMathErrnoDefault() const override { return false; } bool useIntegratedAs() const override { return true; } bool 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; } @@ -136,6 +138,11 @@ public: addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + + // 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; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp index fe1d19c2dd67..863e2c597d53 100644 --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp @@ -9,12 +9,14 @@ #include "AMDGPUOpenMP.h" #include "AMDGPU.h" #include "CommonArgs.h" +#include "ToolChains/ROCm.h" #include "clang/Basic/DiagnosticDriver.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/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" @@ -84,14 +86,54 @@ static bool checkSystemForAMDGPU(const ArgList &Args, const AMDGPUToolChain &TC, } // namespace const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const ArgList &Args, StringRef SubArchName, - StringRef OutputFilePrefix) const { + 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) { + // This is not certain to work. The device libs added here, and passed to + // llvm-link, are missing attributes that they expect to be inserted when + // passed to mlink-builtin-bitcode. The amdgpu backend does not generate + // conservatively correct code when attributes are missing, so this may + // be the root cause of miscompilations. Passing via mlink-builtin-bitcode + // ultimately hits CodeGenModule::addDefaultFunctionDefinitionAttributes + // on each function, see D28538 for context. + // Potential workarounds: + // - unconditionally link all of the device libs to every translation + // unit in clang via mlink-builtin-bitcode + // - build a libm bitcode file as part of the DeviceRTL and explictly + // mlink-builtin-bitcode the rocm device libs components at build time + // - drop this llvm-link fork in favour or some calls into LLVM, chosen + // to do basically the same work as llvm-link but with that call first + // - write an opt pass that sets that on every function it sees and pipe + // the device-libs bitcode through that on the way to this llvm-link + SmallVector<std::string, 12> BCLibs = + AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str()); + llvm::for_each(BCLibs, [&](StringRef BCFile) { + CmdArgs.push_back(Args.MakeArgString(BCFile)); + }); + } + } + + AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn", + SubArchName, + /* bitcode SDL?*/ true, + /* PostClang Link? */ false); // Add an intermediate output file. CmdArgs.push_back("-o"); const char *OutputFileName = @@ -180,8 +222,8 @@ void AMDGCN::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, assert(Prefix.length() && "no linker inputs are files "); // Each command outputs different files. - const char *LLVMLinkCommand = - constructLLVMLinkCommand(C, JA, Inputs, Args, GPUArch, Prefix); + const char *LLVMLinkCommand = constructLLVMLinkCommand( + AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix); // Produce readable assembly if save-temps is enabled. if (C.getDriver().isSaveTempsEnabled()) @@ -226,7 +268,7 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions( std::string BitcodeSuffix; if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime, options::OPT_fno_openmp_target_new_runtime, false)) - BitcodeSuffix = "new-amdgcn-" + GPUArch; + BitcodeSuffix = "new-amdgpu-" + GPUArch; else BitcodeSuffix = "amdgcn-" + GPUArch; diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h index effca7e212cc..233256bf7378 100644 --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h @@ -16,6 +16,10 @@ namespace clang { namespace driver { +namespace toolchains { +class AMDGPUOpenMPToolChain; +} + namespace tools { namespace AMDGCN { @@ -35,11 +39,11 @@ public: private: /// \return llvm-link output file name. - const char *constructLLVMLinkCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix) const; + 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, diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index f147292038a8..a66cae8b4d6b 100644 --- a/clang/lib/Driver/ToolChains/AVR.cpp +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -28,9 +28,9 @@ using namespace llvm::opt; namespace { -const struct { +constexpr struct { StringRef Name; - std::string SubPath; + StringRef SubPath; StringRef Family; unsigned DataAddr; } MCUInfo[] = { @@ -298,6 +298,7 @@ llvm::Optional<unsigned> GetMCUSectionAddressData(StringRef MCUName) { } const StringRef PossibleAVRLibcLocations[] = { + "/avr", "/usr/avr", "/usr/lib/avr", }; @@ -314,7 +315,7 @@ AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, 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); + std::string CPU = getCPUName(D, Args, Triple); if (CPU.empty()) { // We cannot link any standard libraries without an MCU specified. @@ -370,6 +371,16 @@ void AVRToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 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"); +} + Tool *AVRToolChain::buildLinker() const { return new tools::AVR::Linker(getTriple(), *this, LinkStdlib); } @@ -378,8 +389,10 @@ void AVR::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(); + // Compute information about the target AVR. - std::string CPU = getCPUName(Args, getToolChain().getTriple()); + std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); llvm::Optional<StringRef> FamilyName = GetMCUFamilyName(CPU); llvm::Optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU); @@ -403,9 +416,7 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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; + D.Diag(diag::warn_drv_avr_linker_section_addresses_not_implemented) << CPU; } // If the family name is known, we can link with the device-specific libgcc. @@ -414,6 +425,8 @@ 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)); @@ -425,6 +438,8 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Add the link library specific to the MCU. CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU)); + CmdArgs.push_back("--end-group"); + // Specify the family name as the emulation mode to use. // This is almost always required because otherwise avr-ld // will assume 'avr2' and warn about the program being larger @@ -438,11 +453,21 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, } llvm::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; diff --git a/clang/lib/Driver/ToolChains/AVR.h b/clang/lib/Driver/ToolChains/AVR.h index f612aa691182..2d027957ed76 100644 --- a/clang/lib/Driver/ToolChains/AVR.h +++ b/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,6 +26,11 @@ 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; + protected: Tool *buildLinker() const override; diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index ed8c7e94b013..0b60d097b9ca 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -79,10 +79,32 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text, else 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 (Feature == "sve2") + Features.push_back("+sve"); + else if (Feature == "sve2-bitperm" || Feature == "sve2-sha3" || + Feature == "sve2-aes" || Feature == "sve2-sm4") { + Features.push_back("+sve"); + Features.push_back("+sve2"); + } else if (Feature == "nosve") { + Features.push_back("-sve2"); + Features.push_back("-sve2-bitperm"); + Features.push_back("-sve2-sha3"); + Features.push_back("-sve2-aes"); + Features.push_back("-sve2-sm4"); + } else if (Feature == "nosve2") { + Features.push_back("-sve2-bitperm"); + Features.push_back("-sve2-sha3"); + Features.push_back("-sve2-aes"); + Features.push_back("-sve2-sm4"); + } + + // +sve implies +f32mm if the base architecture is v8.6A, v8.7A, v9.1A or + // v9.2A. 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") + ArchKind == llvm::AArch64::ArchKind::ARMV8_7A || + ArchKind == llvm::AArch64::ArchKind::ARMV9_1A || + ArchKind == llvm::AArch64::ArchKind::ARMV9_2A) && + Feature == "sve") Features.push_back("+f32mm"); } return true; @@ -127,8 +149,20 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first); if (ArchKind == llvm::AArch64::ArchKind::INVALID || - !llvm::AArch64::getArchFeatures(ArchKind, Features) || - (Split.second.size() && + !llvm::AArch64::getArchFeatures(ArchKind, Features)) + return false; + + // Enable SVE2 by default on Armv9-A. + // It can still be disabled if +nosve2 is present. + // We must do this early so that DecodeAArch64Features has the correct state + if ((ArchKind == llvm::AArch64::ArchKind::ARMV9A || + ArchKind == llvm::AArch64::ArchKind::ARMV9_1A || + ArchKind == llvm::AArch64::ArchKind::ARMV9_2A)) { + Features.push_back("+sve"); + Features.push_back("+sve2"); + } + + if ((Split.second.size() && !DecodeAArch64Features(D, Split.second, Features, ArchKind))) return false; @@ -210,6 +244,9 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, else if (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple)) success = getAArch64ArchFeaturesFromMcpu( D, getAArch64TargetCPU(Args, Triple, A), Args, Features); + else + // Default to 'A' profile if the architecture is not specified. + success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Features); if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) success = @@ -345,7 +382,10 @@ fp16_fml_fallthrough: NoCrypto = true; } - if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd) { + if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd || + std::find(ItBegin, ItEnd, "+v9a") != ItEnd || + std::find(ItBegin, ItEnd, "+v9.1a") != ItEnd || + std::find(ItBegin, ItEnd, "+v9.2a") != ItEnd) { if (HasCrypto && !NoCrypto) { // Check if we have NOT disabled an algorithm with something like: // +crypto, -algorithm @@ -404,9 +444,11 @@ fp16_fml_fallthrough: } } - auto V8_6Pos = llvm::find(Features, "+v8.6a"); - if (V8_6Pos != std::end(Features)) - V8_6Pos = Features.insert(std::next(V8_6Pos), {"+i8mm", "+bf16"}); + const char *Archs[] = {"+v8.6a", "+v8.7a", "+v9.1a", "+v9.2a"}; + auto Pos = std::find_first_of(Features.begin(), Features.end(), + std::begin(Archs), std::end(Archs)); + if (Pos != std::end(Features)) + Pos = Features.insert(std::next(Pos), {"+i8mm", "+bf16"}); if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 4ab547fabe43..21c091e1a0ba 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -148,13 +148,21 @@ bool arm::useAAPCSForMachO(const llvm::Triple &T) { } // 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) { if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { arm::ReadTPMode ThreadPointer = llvm::StringSwitch<arm::ReadTPMode>(A->getValue()) .Case("cp15", ReadTPMode::Cp15) .Case("soft", ReadTPMode::Soft) .Default(ReadTPMode::Invalid); + if (ThreadPointer == ReadTPMode::Cp15 && + getARMSubArchVersionNumber(Triple) < 7 && + llvm::ARM::parseArch(Triple.getArchName()) != + llvm::ARM::ArchKind::ARMV6T2) { + D.Diag(diag::err_target_unsupported_tp_hard) << Triple.getArchName(); + return ReadTPMode::Invalid; + } if (ThreadPointer != ReadTPMode::Invalid) return ThreadPointer; if (StringRef(A->getValue()).empty()) @@ -314,6 +322,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: @@ -418,7 +430,7 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, 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); + arm::ReadTPMode ThreadPointer = arm::getReadTPMode(D, Args, Triple); llvm::Optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv, WaArch; @@ -701,6 +713,18 @@ fp16_fml_fallthrough: 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"); + } + // 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. @@ -763,7 +787,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 +796,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 @@ -845,7 +871,7 @@ fp16_fml_fallthrough: } -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); diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.h b/clang/lib/Driver/ToolChains/Arch/ARM.h index 8e7c10ecd5d6..b6fd68fbb9c6 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -24,7 +24,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); @@ -53,7 +53,8 @@ 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); +ReadTPMode getReadTPMode(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); void setArchNameInTriple(const Driver &D, const llvm::opt::ArgList &Args, types::ID InputType, llvm::Triple &Triple); diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/clang/lib/Driver/ToolChains/Arch/Mips.cpp index 5a509dbb2bd3..c374d745da38 100644 --- a/clang/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -441,7 +441,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 +450,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); } diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.h b/clang/lib/Driver/ToolChains/Arch/Mips.h index 074012f40fe5..f4c11a7e3188 100644 --- a/clang/lib/Driver/ToolChains/Arch/Mips.h +++ b/clang/lib/Driver/ToolChains/Arch/Mips.h @@ -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/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index ade93d6881a7..323f588c8269 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -7,462 +7,42 @@ //===----------------------------------------------------------------------===// #include "RISCV.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/Option/ArgList.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/raw_ostream.h" -#include "ToolChains/CommonArgs.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"); - - // 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); - } + 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(); + }); - 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; } - // 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); - + (*ISAInfo)->toFeatures( + Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); }); return true; } @@ -610,24 +190,30 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { // rv32* -> ilp32 // rv64g | rv64*d -> lp64d // 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 + auto ParseResult = llvm::RISCVISAInfo::parseArchString( + Arch, /* EnableExperimentalExtension */ true); + if (!ParseResult) { + // Ignore parsing error, just go 3rd step. + consumeError(ParseResult.takeError()); + } else { + auto &ISAInfo = *ParseResult; + bool HasD = ISAInfo->hasExtension("d"); + unsigned XLen = ISAInfo->getXLen(); + if (XLen == 32) { + bool HasE = ISAInfo->hasExtension("e"); + if (HasD) + return "ilp32d"; + if (HasE) + return "ilp32e"; 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 + } else if (XLen == 64) { + if (HasD) + return "lp64d"; return "lp64"; + } + llvm_unreachable("unhandled XLen"); } // 3. Choose a default based on the triple diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 12749c7ec871..bfa008f964e1 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -11,6 +11,8 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Host.h" @@ -20,7 +22,7 @@ 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(); @@ -37,29 +39,34 @@ std::string x86::getX86TargetCPU(const ArgList &Args, 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). diff --git a/clang/lib/Driver/ToolChains/Arch/X86.h b/clang/lib/Driver/ToolChains/Arch/X86.h index 14f0a26c8be4..36a2ab52899d 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.h +++ b/clang/lib/Driver/ToolChains/Arch/X86.h @@ -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/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp index ce73e39d1456..cd07692be358 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -125,6 +125,20 @@ static bool isARMBareMetal(const llvm::Triple &Triple) { return true; } +/// Is the triple aarch64-none-elf? +static bool isAArch64BareMetal(const llvm::Triple &Triple) { + if (Triple.getArch() != llvm::Triple::aarch64) + 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) @@ -151,7 +165,8 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, } bool BareMetal::handlesTarget(const llvm::Triple &Triple) { - return isARMBareMetal(Triple) || isRISCVBareMetal(Triple); + return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) || + isRISCVBareMetal(Triple); } Tool *BareMetal::buildLinker() const { diff --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h index d68c43c64c97..dc718e09ad43 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.h +++ b/clang/lib/Driver/ToolChains/BareMetal.h @@ -42,7 +42,9 @@ public: bool useIntegratedAs() const override { return true; } 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; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a4b53a640ab5..e5476e07a5cc 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -22,6 +22,7 @@ #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/LangOptions.h" @@ -612,7 +613,8 @@ getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { A && A->getOption().matches(options::OPT_fno_omit_frame_pointer); bool OmitLeafFP = Args.hasFlag(options::OPT_momit_leaf_frame_pointer, options::OPT_mno_omit_leaf_frame_pointer, - Triple.isAArch64() || Triple.isPS4CPU()); + Triple.isAArch64() || Triple.isPS4CPU() || + Triple.isVE()); if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { if (OmitLeafFP) @@ -643,7 +645,7 @@ static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgString 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 @@ -658,7 +660,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 @@ -673,7 +675,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 @@ -748,7 +750,7 @@ 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 ArgList &Args, SanitizerArgs &SanArgs, ArgStringList &CmdArgs) { auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate, @@ -795,11 +797,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(); @@ -927,7 +924,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, else if (Val != "single") D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; - } else if (TC.getSanitizerArgs().needsTsanRt()) { + } else if (SanArgs.needsTsanRt()) { CmdArgs.push_back("-fprofile-update=atomic"); } @@ -1256,7 +1253,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // If we are offloading to a target via OpenMP we need to include the // openmp_wrappers folder which contains alternative system headers. if (JA.isDeviceOffloading(Action::OFK_OpenMP) && - getToolChain().getTriple().isNVPTX()){ + (getToolChain().getTriple().isNVPTX() || + getToolChain().getTriple().isAMDGCN())) { if (!Args.hasArg(options::OPT_nobuiltininc)) { // Add openmp_wrappers/* to our system include path. This lets us wrap // standard library headers. @@ -1587,8 +1585,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,7 +1594,7 @@ 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(); } @@ -1607,7 +1605,7 @@ void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args, 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); @@ -1825,17 +1823,46 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, 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.endswith("+")) + 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; } AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { + StringRef Name = A->getValue(); + + std::string TuneCPU; + if (Name == "native") + TuneCPU = std::string(llvm::sys::getHostCPUName()); + else + TuneCPU = std::string(Name); + + if (!TuneCPU.empty()) { + CmdArgs.push_back("-tune-cpu"); + CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + } + } } void Clang::AddMIPSTargetArgs(const ArgList &Args, @@ -2173,6 +2200,7 @@ 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; @@ -2182,6 +2210,11 @@ void Clang::AddX86TargetArgs(const ArgList &Args, 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"); @@ -2411,7 +2444,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 : @@ -2617,6 +2650,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; @@ -2638,10 +2672,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, llvm::DenormalMode DenormalFPMath = DefaultDenormalFPMath; llvm::DenormalMode DenormalFP32Math = DefaultDenormalFP32Math; - StringRef FPContract = "on"; + // 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; + if (!JA.isDeviceOffloading(Action::OFK_Cuda) && + !JA.isOffloading(Action::OFK_HIP)) + FPContract = "on"; bool StrictFPModel = false; - if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); CmdArgs.push_back(A->getValue()); @@ -2685,12 +2723,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // 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); + << Args.MakeArgString("-ffp-model=" + FPModel) + << Args.MakeArgString("-ffp-model=" + Val); if (Val.equals("fast")) { optID = options::OPT_ffast_math; FPModel = Val; - FPContract = Val; + FPContract = "fast"; } else if (Val.equals("precise")) { optID = options::OPT_ffp_contract; FPModel = Val; @@ -2719,6 +2757,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; @@ -2780,11 +2820,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_ffp_contract: { StringRef Val = A->getValue(); if (PreciseFPModel) { - // When -ffp-model=precise is seen on the command line, - // the boolean PreciseFPModel is set to true which indicates - // "the current option is actually PreciseFPModel". The optID - // is changed to OPT_ffp_contract and FPContract is set to "on". - // the argument Val string is "precise": it shouldn't be checked. + // -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")) FPContract = Val; @@ -2877,12 +2915,17 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; - TrappingMath = false; - RoundingFPMath = false; // -fno_fast_math restores default denormal and fpcontract handling DenormalFPMath = DefaultDenormalFPMath; DenormalFP32Math = llvm::DenormalMode::getIEEE(); - FPContract = "on"; + if (!JA.isDeviceOffloading(Action::OFK_Cuda) && + !JA.isOffloading(Action::OFK_HIP)) + if (FPContract == "fast") { + FPContract = "on"; + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-contract=fast" + << "-ffp-contract=on"; + } break; } if (StrictFPModel) { @@ -2915,6 +2958,9 @@ 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"); @@ -3128,14 +3174,44 @@ 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::getARMSubArchVersionNumber(EffectiveTriple) < 7 && + llvm::ARM::parseArch(EffectiveTriple.getArchName()) != + llvm::ARM::ArchKind::ARMV6T2) { + 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-hard"); + } if (EffectiveTriple.isAArch64() && Value != "sysreg" && Value != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) << A->getOption().getName() << Value << "sysreg global"; @@ -3146,7 +3222,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; @@ -3154,6 +3231,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); } @@ -3179,7 +3262,7 @@ static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple(); - if (!EffectiveTriple.isOSLinux()) + if (!EffectiveTriple.isOSFreeBSD() && !EffectiveTriple.isOSLinux()) return; if (!EffectiveTriple.isX86() && !EffectiveTriple.isSystemZ() && @@ -3354,7 +3437,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); } } @@ -3554,11 +3637,11 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, 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()))); + 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)) { @@ -3873,12 +3956,6 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, 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); - if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, options::OPT_fno_debug_info_for_profiling, false) && checkDebugInfoOption( @@ -4132,6 +4209,29 @@ 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, + options::OPT_gsimple_template_names_EQ); + 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"); + } else if (Opt.matches(options::OPT_gsimple_template_names_EQ)) { + ForwardTemplateParams = true; + StringRef Value = SimpleTemplateNamesArg->getValue(); + if (Value == "simple") { + CmdArgs.push_back("-gsimple-template-names=simple"); + } else if (Value == "mangled") { + CmdArgs.push_back("-gsimple-template-names=mangled"); + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << Opt.getName() << SimpleTemplateNamesArg->getValue(); + } + } + } if (Args.hasFlag(options::OPT_fdebug_ranges_base_address, options::OPT_fno_debug_ranges_base_address, false)) { @@ -4178,7 +4278,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 @@ -4360,7 +4460,7 @@ 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. @@ -4478,28 +4578,18 @@ 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 { + // Only AMDGPU supports device-side LTO. + if (IsDeviceOffloadAction && !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 { + assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); + CmdArgs.push_back(Args.MakeArgString( + Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); + CmdArgs.push_back("-flto-unit"); } } } @@ -4537,7 +4627,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, @@ -4581,8 +4671,7 @@ 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. @@ -4599,7 +4688,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: @@ -4650,6 +4739,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; @@ -4665,10 +4755,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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"); @@ -4721,6 +4810,22 @@ 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)))); + } + llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; @@ -5062,9 +5167,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 <rdar://problem/7651567>), 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 @@ -5102,16 +5207,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. - 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"); + auto SanitizeArgs = TC.getSanitizerArgs(Args); + bool AsyncUnwindTables = Args.hasFlag( + options::OPT_fasynchronous_unwind_tables, + options::OPT_fno_asynchronous_unwind_tables, + (TC.IsUnwindTablesDefault(Args) || SanitizeArgs.needsUnwindTables()) && + !Freestanding); + bool UnwindTables = Args.hasFlag(options::OPT_funwind_tables, + options::OPT_fno_unwind_tables, false); + 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. @@ -5120,7 +5227,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)); @@ -5162,7 +5269,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // 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)); @@ -5346,7 +5453,7 @@ 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, D, Output, Args, SanitizeArgs, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ); @@ -5354,7 +5461,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (RawTriple.isPS4CPU() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { PS4cpu::addProfileRTArgs(TC, Args, CmdArgs); - PS4cpu::addSanitizerArgs(TC, CmdArgs); + PS4cpu::addSanitizerArgs(TC, Args, CmdArgs); } // Pass options for controlling the default header search paths. @@ -5416,7 +5523,26 @@ 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); + } + if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) CmdArgs.push_back("-pedantic"); Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); @@ -5433,6 +5559,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables, options::OPT_fno_experimental_relative_cxx_abi_vtables); + 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). // @@ -5693,7 +5822,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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); - + Args.AddLastArg(CmdArgs, options::OPT_fnew_infallible); Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); if (Args.hasFlag(options::OPT_fno_operator_names, @@ -5736,6 +5865,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, @@ -5751,12 +5883,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_openmp_cuda_mode, /*Default=*/false)) CmdArgs.push_back("-fopenmp-cuda-mode"); + // When in OpenMP offloading mode, enable or disable the new device + // runtime. + if (Args.hasFlag(options::OPT_fopenmp_target_new_runtime, + options::OPT_fno_openmp_target_new_runtime, + /*Default=*/false)) + CmdArgs.push_back("-fopenmp-target-new-runtime"); + + // When in OpenMP offloading mode, enable debugging on the device. + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); + if (Args.hasFlag(options::OPT_fopenmp_target_debug, + options::OPT_fno_openmp_target_debug, /*Default=*/false)) + CmdArgs.push_back("-fopenmp-target-debug"); + // When in OpenMP offloading mode with NVPTX target, check if full runtime // is required. if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime, options::OPT_fno_openmp_cuda_force_full_runtime, /*Default=*/false)) CmdArgs.push_back("-fopenmp-cuda-force-full-runtime"); + + // When in OpenMP offloading mode, forward assumptions information about + // thread and team counts in the device. + if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, + 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"); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -5771,10 +5927,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); + if (!Args.hasFlag(options::OPT_fopenmp_extensions, + options::OPT_fno_openmp_extensions, /*Default=*/true)) + CmdArgs.push_back("-fno-openmp-extensions"); } - const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); - Sanitize.addArgs(TC, Args, CmdArgs, InputType); + SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType); const XRayArgs &XRay = TC.getXRayArgs(); XRay.addArgs(TC, Args, CmdArgs, InputType); @@ -5891,6 +6049,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderSCPOptions(TC, Args, CmdArgs); RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs); + Args.AddLastArg(CmdArgs, options::OPT_fswift_async_fp_EQ); + // Translate -mstackrealign if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, false)) @@ -6175,7 +6335,8 @@ 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. @@ -6715,12 +6876,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } bool DefaultsSplitLTOUnit = - (WholeProgramVTables || Sanitize.needsLTO()) && + (WholeProgramVTables || SanitizeArgs.needsLTO()) && (LTOMode == LTOK_Full || TC.canSplitThinLTOUnit()); 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) @@ -6819,7 +6980,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-faddrsig"); if ((Triple.isOSBinFormatELF() || Triple.isOSBinFormatMachO()) && - (EH || UnwindTables || DebugInfoKind != codegenoptions::NoDebugInfo)) + (EH || AsyncUnwindTables || UnwindTables || + DebugInfoKind != codegenoptions::NoDebugInfo)) CmdArgs.push_back("-D__GCC_HAVE_DWARF2_CFI_ASM=1"); if (Arg *A = Args.getLastArg(options::OPT_fsymbol_partition_EQ)) { @@ -7431,7 +7593,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)); @@ -7667,18 +7829,30 @@ 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) && + CurDep->getOffloadingArch()) { + 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.startswith_insensitive("-march="); + if (Arch) { + GPUArchName = ArchStr.substr(7); + Triples += "-"; + break; + } + } + Triples += GPUArchName.str(); + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); @@ -7701,8 +7875,11 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, assert(CurTC == nullptr && "Expected one dependence!"); CurTC = TC; }); + UB += C.addTempFile( + C.getArgs().MakeArgString(CurTC->getInputFilename(Inputs[I]))); + } else { + UB += CurTC->getInputFilename(Inputs[I]); } - UB += CurTC->getInputFilename(Inputs[I]); } CmdArgs.push_back(TCArgs.MakeArgString(UB)); @@ -7746,19 +7923,30 @@ 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.startswith_insensitive("-march="); + if (Arch) { + GPUArchName = ArchStr.substr(7); + Triples += "-"; + break; + } + } + Triples += GPUArchName.str(); + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); diff --git a/clang/lib/Driver/ToolChains/CloudABI.cpp b/clang/lib/Driver/ToolChains/CloudABI.cpp index 9ee46ac857f0..501e3a382ec1 100644 --- a/clang/lib/Driver/ToolChains/CloudABI.cpp +++ b/clang/lib/Driver/ToolChains/CloudABI.cpp @@ -47,7 +47,7 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--no-dynamic-linker"); // Provide PIE linker flags in case PIE is default for the architecture. - if (ToolChain.isPIEDefault()) { + if (ToolChain.isPIEDefault(Args)) { CmdArgs.push_back("-pie"); CmdArgs.push_back("-zrelro"); } @@ -125,7 +125,7 @@ Tool *CloudABI::buildLinker() const { return new tools::cloudabi::Linker(*this); } -bool CloudABI::isPIEDefault() const { +bool CloudABI::isPIEDefault(const llvm::opt::ArgList &Args) const { // Only enable PIE on architectures that support PC-relative // addressing. PC-relative addressing is required, as the process // startup code must be able to relocate itself. diff --git a/clang/lib/Driver/ToolChains/CloudABI.h b/clang/lib/Driver/ToolChains/CloudABI.h index 98bf23127706..8856fe3dde6d 100644 --- a/clang/lib/Driver/ToolChains/CloudABI.h +++ b/clang/lib/Driver/ToolChains/CloudABI.h @@ -55,7 +55,7 @@ public: void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; SanitizerMask getDefaultSanitizers() const override; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 83cab3ac00cb..630baf9d6ae6 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -34,6 +34,7 @@ #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" @@ -266,6 +267,15 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, // Pass -z prefix for gcc linker compatibility. A.claim(); A.render(Args, CmdArgs); + } else if (A.getOption().matches(options::OPT_b)) { + const llvm::Triple &T = TC.getTriple(); + if (!T.isOSAIX()) { + TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << A.getSpelling() << T.str(); + } + // Pass -b prefix for AIX linker. + A.claim(); + A.render(Args, CmdArgs); } else { A.renderAsInput(Args, CmdArgs); } @@ -346,8 +356,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()) { @@ -403,14 +413,9 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, 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) + if (T.isOSAIX()) + TargetCPUName = "pwr7"; + else if (T.getArch() == llvm::Triple::ppc64le) TargetCPUName = "ppc64le"; else if (T.getArch() == llvm::Triple::ppc64) TargetCPUName = "ppc64"; @@ -438,7 +443,7 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &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" + @@ -506,7 +511,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, // 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)); @@ -616,11 +621,6 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back("-plugin-opt=new-pass-manager"); } - // 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"); - // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); if (!StatsFile.empty()) @@ -657,7 +657,7 @@ void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, std::string CandidateRPath = TC.getArchSpecificLibPath(); if (TC.getVFS().exists(CandidateRPath)) { CmdArgs.push_back("-rpath"); - CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str())); + CmdArgs.push_back(Args.MakeArgString(CandidateRPath)); } } @@ -775,7 +775,8 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, CmdArgs.push_back("-ldl"); // Required for backtrace on some OSes if (TC.getTriple().isOSFreeBSD() || - TC.getTriple().isOSNetBSD()) + TC.getTriple().isOSNetBSD() || + TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lexecinfo"); } @@ -786,7 +787,7 @@ 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()) { @@ -922,7 +923,7 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols); - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); // Inject libfuzzer dependencies. if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() && !Args.hasArg(options::OPT_shared)) { @@ -1115,7 +1116,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)) @@ -1587,6 +1588,292 @@ 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. +/// +bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + SmallVector<std::string, 8> LibraryPaths, std::string Lib, + StringRef Arch, StringRef Target, bool isBitCodeSDL, + bool postClangLink) { + 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)) { + if (postClangLink) + CC1Args.push_back("-mlink-builtin-bitcode"); + 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 (for amdgcn) or to the +/// clang-nvlink-wrapper (for nvptx) commands by the driver. +bool tools::GetSDLFromOffloadArchive( + Compilation &C, const Driver &D, const Tool &T, const JobAction &JA, + const InputInfoList &Inputs, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, SmallVector<std::string, 8> LibraryPaths, + StringRef Lib, StringRef Arch, StringRef Target, bool isBitCodeSDL, + bool postClangLink) { + + // We don't support bitcode archive bundles for nvptx + if (isBitCodeSDL && Arch.contains("nvptx")) + return false; + + bool FoundAOB = false; + SmallVector<std::string, 2> AOBFileNames; + std::string ArchiveOfBundles; + for (auto LPath : LibraryPaths) { + ArchiveOfBundles.clear(); + + AOBFileNames.push_back(Twine(LPath + "/libdevice/lib" + Lib + ".a").str()); + AOBFileNames.push_back(Twine(LPath + "/lib" + Lib + ".a").str()); + + for (auto AOB : AOBFileNames) { + if (llvm::sys::fs::exists(AOB)) { + ArchiveOfBundles = AOB; + FoundAOB = true; + break; + } + } + + if (!FoundAOB) + continue; + + StringRef Prefix = isBitCodeSDL ? "libbc-" : "lib"; + std::string OutputLib = D.GetTemporaryPath( + Twine(Prefix + Lib + "-" + Arch + "-" + Target).str(), "a"); + + C.addTempFile(C.getArgs().MakeArgString(OutputLib.c_str())); + + 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("-inputs=" + ArchiveOfBundles); + std::string OffloadArg("-targets=" + std::string(DeviceTriple)); + std::string OutputArg("-outputs=" + OutputLib); + + const char *UBProgram = DriverArgs.MakeArgString( + T.getToolChain().GetProgramPath("clang-offload-bundler")); + + ArgStringList UBArgs; + UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(TypeArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(InputArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(OutputArg.c_str())); + + // Add this flag to not exit from clang-offload-bundler if no compatible + // code object is found in heterogenous archive library. + std::string AdditionalArgs("-allow-missing-bundles"); + UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs.c_str())); + + C.addCommand(std::make_unique<Command>( + JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs, + InputInfo(&JA, C.getArgs().MakeArgString(OutputLib.c_str())))); + if (postClangLink) + CC1Args.push_back("-mlink-builtin-bitcode"); + + CC1Args.push_back(DriverArgs.MakeArgString(OutputLib)); + break; + } + + return FoundAOB; +} + +// Wrapper function used by driver for adding SDLs during link phase. +void tools::AddStaticDeviceLibsLinking(Compilation &C, const Tool &T, + const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink) { + AddStaticDeviceLibs(&C, &T, &JA, &Inputs, C.getDriver(), DriverArgs, CC1Args, + Arch, Target, isBitCodeSDL, postClangLink); +} + +// Wrapper function used for post clang linking of bitcode SDLS for nvptx by +// the CUDA toolchain. +void tools::AddStaticDeviceLibsPostLinking(const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink) { + AddStaticDeviceLibs(nullptr, nullptr, nullptr, nullptr, D, DriverArgs, + CC1Args, Arch, Target, isBitCodeSDL, postClangLink); +} + +// 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 NVPTX, the archive members +// contain cubin for Nvidia GPUs and are linked one time during the +// link phase by the CUDA SDK linker called nvlink. For AMDGPU, the +// process for machine code SDLs is still in development. But they +// will be linked by the LLVM tool lld. +// +// * 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, bool postClangLink) { + + SmallVector<std::string, 8> LibraryPaths; + // Add search directories from LIBRARY_PATH env variable + llvm::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, Twine("lib") + CLANG_LIBDIR_SUFFIX); + 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 (!HostOnlyArchives->contains(SDLName)) { + SDLNames.insert(SDLName); + } + } + + // The search stops as soon as an SDL file is found. The driver then provides + // the full filename of the SDL to the llvm-link or clang-nvlink-wrapper + // command. If no SDL is found after searching each LINKPATH with + // SEARCH-ORDER, it is possible that an archive file lib<libname>.a exists + // and may contain bundled object files. + for (auto SDLName : SDLNames) { + // This is the only call to SDLSearch + if (!SDLSearch(D, DriverArgs, CC1Args, LibraryPaths, SDLName, Arch, Target, + isBitCodeSDL, postClangLink)) { + GetSDLFromOffloadArchive(*C, D, *T, *JA, *Inputs, DriverArgs, CC1Args, + LibraryPaths, SDLName, Arch, Target, + isBitCodeSDL, postClangLink); + } + } +} + static llvm::opt::Arg * getAMDGPUCodeObjectArgument(const Driver &D, const llvm::opt::ArgList &Args) { // The last of -mcode-object-v3, -mno-code-object-v3 and @@ -1684,6 +1971,12 @@ 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, Twine("lib") + CLANG_LIBDIR_SUFFIX); + LibraryPaths.emplace_back(DefaultLibPath.c_str()); + // Add user defined library paths from LIBRARY_PATH. llvm::Optional<std::string> LibPath = llvm::sys::Process::GetEnv("LIBRARY_PATH"); @@ -1695,32 +1988,31 @@ 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 : options::OPT_libomptarget_nvptx_bc_path_EQ; StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgcn" : "nvptx"; + std::string LibOmpTargetName = "libomptarget-" + BitcodeSuffix.str() + ".bc"; + // 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); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index c94c15864661..00291a3681c8 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -49,6 +49,39 @@ 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, bool postClangLink); +void AddStaticDeviceLibsPostLinking(const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, + StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink); +void AddStaticDeviceLibs(Compilation *C, const Tool *T, const JobAction *JA, + const InputInfoList *Inputs, const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, StringRef Arch, + StringRef Target, bool isBitCodeSDL, + bool postClangLink); + +bool SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, + SmallVector<std::string, 8> LibraryPaths, std::string Lib, + StringRef Arch, StringRef Target, bool isBitCodeSDL, + bool postClangLink); + +bool GetSDLFromOffloadArchive(Compilation &C, const Driver &D, const Tool &T, + const JobAction &JA, const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + SmallVector<std::string, 8> LibraryPaths, + StringRef Lib, StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink); + const char *SplitDebugName(const JobAction &JA, const llvm::opt::ArgList &Args, const InputInfo &Input, const InputInfo &Output); @@ -107,8 +140,8 @@ 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); /// Iterate \p Args and convert -mxxx to +xxx and -mno-xxx to -xxx and /// append it to \p Features. diff --git a/clang/lib/Driver/ToolChains/CrossWindows.cpp b/clang/lib/Driver/ToolChains/CrossWindows.cpp index 07abf4f83f7d..2b043fbeecda 100644 --- a/clang/lib/Driver/ToolChains/CrossWindows.cpp +++ b/clang/lib/Driver/ToolChains/CrossWindows.cpp @@ -185,7 +185,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")); @@ -223,7 +223,7 @@ 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; } diff --git a/clang/lib/Driver/ToolChains/CrossWindows.h b/clang/lib/Driver/ToolChains/CrossWindows.h index ffe75332c2e8..bab690ea34d0 100644 --- a/clang/lib/Driver/ToolChains/CrossWindows.h +++ b/clang/lib/Driver/ToolChains/CrossWindows.h @@ -57,7 +57,7 @@ public: bool IsIntegratedAssemblerDefault() const override { return true; } bool IsUnwindTablesDefault(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/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 769eae14df51..5397c7a9a0e6 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -17,6 +17,7 @@ #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" @@ -34,25 +35,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,10 +59,18 @@ 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; + 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. auto StartsWithWords = @@ -100,21 +90,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( @@ -206,31 +202,17 @@ CudaInstallationDetector::CudaInstallationDetector( 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"; @@ -319,8 +301,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"); } @@ -632,8 +612,16 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(CubinF); } + AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "nvptx", GPUArch, + false, false); + + // Find nvlink and pass it as "--nvlink-path=" argument of + // clang-nvlink-wrapper. + CmdArgs.push_back(Args.MakeArgString( + Twine("--nvlink-path=" + getToolChain().GetProgramPath("nvlink")))); + const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("nvlink")); + Args.MakeArgString(getToolChain().GetProgramPath("clang-nvlink-wrapper")); C.addCommand(std::make_unique<Command>( JA, *this, ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8, @@ -686,7 +674,8 @@ 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"); + CC1Args.append( + {"-fcuda-is-device", "-mllvm", "-enable-memcpyopt-without-libcalls"}); if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, options::OPT_fno_cuda_approx_transcendentals, false)) @@ -720,6 +709,9 @@ void CudaToolChain::addClangTargetOptions( case CudaVersion::CUDA_##CUDA_VER: \ PtxFeature = "+ptx" #PTX_VER; \ break; + CASE_CUDA_VERSION(115, 75); + CASE_CUDA_VERSION(114, 74); + CASE_CUDA_VERSION(113, 73); CASE_CUDA_VERSION(112, 72); CASE_CUDA_VERSION(111, 71); CASE_CUDA_VERSION(110, 70); @@ -760,6 +752,8 @@ void CudaToolChain::addClangTargetOptions( addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, getTriple()); + AddStaticDeviceLibsPostLinking(getDriver(), DriverArgs, CC1Args, "nvptx", GpuArch, + /* bitcode SDL?*/ true, /* PostClang Link? */ true); } } @@ -831,17 +825,9 @@ 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; - } - } - if (!IsDuplicate) + for (Arg *A : Args) + if (!llvm::is_contained(*DAL, A)) DAL->append(A); - } StringRef Arch = DAL->getLastArgValue(options::OPT_march_EQ); if (Arch.empty()) @@ -884,6 +870,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/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h index 6ae4415a563a..a7e6e84f4902 100644 --- a/clang/lib/Driver/ToolChains/Cuda.h +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -30,8 +30,6 @@ 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; @@ -62,7 +60,10 @@ 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. @@ -156,7 +157,9 @@ public: 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 supportsDebugInfoOption(const llvm::opt::Arg *A) const override; diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 261f522f6c49..06d3edc70e45 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -34,7 +34,7 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; -static const VersionTuple minimumMacCatalystDeploymentTarget() { +static VersionTuple minimumMacCatalystDeploymentTarget() { return VersionTuple(13, 1); } @@ -94,6 +94,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 +114,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 +131,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 && @@ -729,6 +729,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, @@ -982,6 +1030,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); } @@ -1305,7 +1357,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, return; } - const SanitizerArgs &Sanitize = getSanitizerArgs(); + const SanitizerArgs &Sanitize = getSanitizerArgs(Args); if (Sanitize.needsAsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); if (Sanitize.needsLsanRt()) @@ -1379,6 +1431,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. @@ -1430,7 +1484,8 @@ struct DarwinPlatform { 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: @@ -1455,6 +1510,7 @@ struct DarwinPlatform { std::string getAsString(DerivedArgList &Args, const OptTable &Opts) { switch (Kind) { case TargetArg: + case MTargetOSArg: case OSVersionArg: case InferredFromSDK: case InferredFromArch: @@ -1466,40 +1522,54 @@ 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 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, None)) { NativeTargetVersion = *MacOSVersion; } } } - Result.Environment = DarwinEnvironmentKind::MacCatalyst; - Result.NativeTargetVersion = NativeTargetVersion; break; } default: break; } + } + + 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; + Result.setEnvironment(TT.getEnvironment(), + VersionTuple(Major, Minor, Micro), SDKInfo); + return Result; + } + static DarwinPlatform + createFromMTargetOS(llvm::Triple::OSType OS, VersionTuple OSVersion, + llvm::Triple::EnvironmentType Environment, Arg *A, + const 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, @@ -1750,7 +1820,12 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, << Triple.getOSName(); break; case llvm::Triple::IOS: - Triple.getiOSVersion(Major, Minor, Micro); + if (Triple.isMacCatalystEnvironment() && !Triple.getOSMajorVersion()) { + Major = 13; + Minor = 1; + Micro = 0; + } else + Triple.getiOSVersion(Major, Minor, Micro); break; case llvm::Triple::TvOS: Triple.getOSVersion(Major, Minor, Micro); @@ -1813,6 +1888,39 @@ Optional<DarwinPlatform> getDeploymentTargetFromTargetArg( Triple, OSVersion, Args.getLastArg(options::OPT_target), SDKInfo); } +/// Returns the deployment target that's specified using the -mtargetos option. +Optional<DarwinPlatform> +getDeploymentTargetFromMTargetOSArg(DerivedArgList &Args, + const Driver &TheDriver, + const Optional<DarwinSDKInfo> &SDKInfo) { + auto *A = Args.getLastArg(options::OPT_mtargetos_EQ); + if (!A) + return None; + 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: + break; + default: + TheDriver.Diag(diag::err_drv_invalid_os_in_arg) + << TT.getOSName() << A->getAsString(Args); + return None; + } + + unsigned Major, Minor, Micro; + TT.getOSVersion(Major, Minor, Micro); + if (!Major) { + TheDriver.Diag(diag::err_drv_invalid_version_number) + << A->getAsString(Args); + return None; + } + return DarwinPlatform::createFromMTargetOS(TT.getOS(), + VersionTuple(Major, Minor, Micro), + TT.getEnvironment(), A, SDKInfo); +} + Optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS, const ArgList &Args, const Driver &TheDriver) { @@ -1861,6 +1969,13 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { Optional<DarwinPlatform> OSTarget = getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver(), SDKInfo); if (OSTarget) { + // 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; + } Optional<DarwinPlatform> OSVersionArgTarget = getDeploymentTargetFromOSVersionArg(Args, getDriver()); if (OSVersionArgTarget) { @@ -1892,6 +2007,18 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } } } + } 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=. + 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()); @@ -2656,7 +2783,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 || diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h index 4de122c8d513..a307cd317ac3 100644 --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -78,6 +78,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 +139,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: @@ -239,7 +254,7 @@ public: } 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; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 1bfad6115d51..b82c5d7600df 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -37,8 +37,9 @@ void Flang::AddFortranDialectOptions(const ArgList &Args, 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}); } void Flang::AddOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index 5dcf74dabf4f..dc05f9893465 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -99,7 +99,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: { - 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); @@ -110,7 +110,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 { @@ -145,7 +145,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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" @@ -467,7 +467,9 @@ bool FreeBSD::HasNativeLLVMSupport() const { return true; } bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; } -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; diff --git a/clang/lib/Driver/ToolChains/FreeBSD.h b/clang/lib/Driver/ToolChains/FreeBSD.h index abc0876cef26..2a721c750a64 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.h +++ b/clang/lib/Driver/ToolChains/FreeBSD.h @@ -74,7 +74,7 @@ public: llvm::ExceptionHandling GetExceptionModel(const llvm::opt::ArgList &Args) const override; bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; unsigned GetDefaultDwarfVersion() const override; // Until dtrace (via CTF) and LLDB can deal with distributed debug info, diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp index fd9804a7f353..a7afec6963a1 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -60,6 +60,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"); } @@ -89,7 +91,7 @@ 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)) { std::string Dyld = D.DyldPrefix; @@ -247,17 +249,16 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, 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", + addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "fsanitize=address", + Flags); + addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), "fsanitize=hwaddress", Flags); addMultilibFlag( @@ -437,13 +438,3 @@ SanitizerMask Fuchsia::getDefaultSanitizers() const { } 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/clang/lib/Driver/ToolChains/Fuchsia.h b/clang/lib/Driver/ToolChains/Fuchsia.h index 07adf9b7101d..c0e69df22821 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.h +++ b/clang/lib/Driver/ToolChains/Fuchsia.h @@ -54,7 +54,9 @@ public: return true; } 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,9 +73,6 @@ 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 diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index da39f29e4619..7aeadd84dfee 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -312,7 +312,7 @@ static bool getPIE(const ArgList &Args, const ToolChain &TC) { Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, options::OPT_nopie); if (!A) - return TC.isPIEDefault(); + return TC.isPIEDefault(Args); return A->getOption().matches(options::OPT_pie); } @@ -429,11 +429,6 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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"); @@ -451,7 +446,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // 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); + std::string CPU = getCPUName(D, Args, Triple); if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") CmdArgs.push_back("--fix-cortex-a53-843419"); } @@ -473,17 +468,12 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, return; } - if (IsStatic) { - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || - Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb) - CmdArgs.push_back("-Bstatic"); - else - CmdArgs.push_back("-static"); - } else if (Args.hasArg(options::OPT_shared)) { + if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-shared"); - } - if (!IsStatic) { + if (IsStatic) { + CmdArgs.push_back("-static"); + } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); @@ -534,10 +524,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 @@ -712,10 +702,6 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, } } - if (getToolChain().isNoExecStackDefault()) { - CmdArgs.push_back("--noexecstack"); - } - switch (getToolChain().getArch()) { default: break; @@ -734,32 +720,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: @@ -775,7 +761,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, 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 +769,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); @@ -931,7 +917,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 { @@ -1086,7 +1072,8 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, .flag("-m32") .flag("-mabi=n32"); - Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32"); + Multilib M32 = + Multilib().gccSuffix("/32").flag("-m64").flag("+m32").flag("-mabi=n32"); DebianMipsMultilibs = MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); @@ -1473,7 +1460,7 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, 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", + addMultilibFlag(tools::mips::isNaN2008(D, Args, TargetTriple), "mnan=2008", Flags); addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); @@ -2052,7 +2039,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( // 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. + // Yet, still look for RHEL/CentOS devtoolsets and gcc-toolsets. + Prefixes.push_back("/opt/rh/gcc-toolset-10/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-10/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-9/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-8/root/usr"); @@ -2074,24 +2062,28 @@ 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"}; @@ -2105,31 +2097,28 @@ 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", "i686-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 +2129,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 +2169,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", @@ -2708,6 +2694,7 @@ bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const { case llvm::Triple::ppcle: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: + case llvm::Triple::x86: case llvm::Triple::x86_64: return true; default: @@ -2727,7 +2714,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(); diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 40fd756a5653..4eb7ab0215ab 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -298,7 +298,7 @@ public: bool IsUnwindTablesDefault(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/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index 59d58aadb687..07af1a0457c7 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -16,6 +16,7 @@ #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" @@ -37,6 +38,43 @@ namespace { const unsigned HIPCodeObjectAlign = 4096; } // namespace +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)) + 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::constructLldCommand(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const InputInfo &Output, @@ -86,12 +124,6 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, 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)); @@ -237,6 +269,14 @@ HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple, // 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. + 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 HIPToolChain::addClangTargetOptions( @@ -276,9 +316,10 @@ void HIPToolChain::addClangTargetOptions( 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::for_each(getHIPDeviceLibs(DriverArgs), [&](auto BCFile) { + CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" + : "-mlink-bitcode-file"); + CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path)); }); } @@ -294,7 +335,8 @@ HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, const OptTable &Opts = getDriver().getOpts(); for (Arg *A : Args) { - if (!shouldSkipArgument(A)) + if (!shouldSkipArgument(A) && + !shouldSkipSanitizeOption(*this, Args, BoundArch, A)) DAL->append(A); } @@ -359,9 +401,9 @@ VersionTuple HIPToolChain::computeMSVCVersion(const Driver *D, return HostTC.computeMSVCVersion(D, Args); } -llvm::SmallVector<std::string, 12> +llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { - llvm::SmallVector<std::string, 12> BCLibs; + llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs; if (DriverArgs.hasArg(options::OPT_nogpulib)) return {}; ArgStringList LibraryPaths; @@ -382,7 +424,7 @@ HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { llvm::sys::path::append(Path, BCName); FullName = Path; if (llvm::sys::fs::exists(FullName)) { - BCLibs.push_back(FullName.str()); + BCLibs.push_back(FullName); return; } } @@ -395,37 +437,11 @@ HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { } StringRef GpuArch = getGPUArch(DriverArgs); assert(!GpuArch.empty() && "Must have an explicit GPU arch."); - (void)GpuArch; - auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); - const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); - - std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); - if (LibDeviceFile.empty()) { - getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch; - return {}; - } // If --hip-device-lib is not set, add the default bitcode libraries. - // TODO: There are way too many flags that change this. Do we need to check - // them all? - bool DAZ = DriverArgs.hasFlag(options::OPT_fgpu_flush_denormals_to_zero, - options::OPT_fno_gpu_flush_denormals_to_zero, - getDefaultDenormsAreZeroForTarget(Kind)); - bool FiniteOnly = - DriverArgs.hasFlag(options::OPT_ffinite_math_only, - options::OPT_fno_finite_math_only, false); - bool UnsafeMathOpt = - DriverArgs.hasFlag(options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations, false); - bool FastRelaxedMath = DriverArgs.hasFlag( - options::OPT_ffast_math, 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); - bool Wave64 = isWave64(DriverArgs, Kind); - if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize, - options::OPT_fno_gpu_sanitize, false)) { + options::OPT_fno_gpu_sanitize) && + getSanitizerArgs(DriverArgs).needsAsanRt()) { auto AsanRTL = RocmInstallation.getAsanRTLPath(); if (AsanRTL.empty()) { unsigned DiagID = getDriver().getDiags().getCustomDiagID( @@ -436,16 +452,15 @@ HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { getDriver().Diag(DiagID); return {}; } else - BCLibs.push_back(AsanRTL.str()); + BCLibs.push_back({AsanRTL.str(), /*ShouldInternalize=*/false}); } // Add the HIP specific bitcode library. - BCLibs.push_back(RocmInstallation.getHIPPath().str()); + BCLibs.push_back(RocmInstallation.getHIPPath()); - // Add the generic set of libraries. - BCLibs.append(RocmInstallation.getCommonBitcodeLibs( - DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, - FastRelaxedMath, CorrectSqrt)); + // Add common device libraries like ocml etc. + for (auto N : getCommonDeviceLibNames(DriverArgs, GpuArch.str())) + BCLibs.push_back(StringRef(N)); // Add instrument lib. auto InstLib = @@ -453,7 +468,7 @@ HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { if (InstLib.empty()) return BCLibs; if (llvm::sys::fs::exists(InstLib)) - BCLibs.push_back(InstLib.str()); + BCLibs.push_back(InstLib); else getDriver().Diag(diag::err_drv_no_such_file) << InstLib; } @@ -466,22 +481,6 @@ void HIPToolChain::checkTargetID(const llvm::opt::ArgList &DriverArgs) const { 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(); - } } + return; } diff --git a/clang/lib/Driver/ToolChains/HIP.h b/clang/lib/Driver/ToolChains/HIP.h index 3cced0a320dc..60b3d69b3f52 100644 --- a/clang/lib/Driver/ToolChains/HIP.h +++ b/clang/lib/Driver/ToolChains/HIP.h @@ -83,7 +83,7 @@ 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> + llvm::SmallVector<BitCodeLibraryInfo, 12> getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; @@ -92,7 +92,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; diff --git a/clang/lib/Driver/ToolChains/Haiku.h b/clang/lib/Driver/ToolChains/Haiku.h index 2bc98322bebf..669379a21605 100644 --- a/clang/lib/Driver/ToolChains/Haiku.h +++ b/clang/lib/Driver/ToolChains/Haiku.h @@ -22,7 +22,7 @@ public: Haiku(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - bool isPIEDefault() const override { + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { return getTriple().getArch() == llvm::Triple::x86_64; } diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 828bfdbb05a3..18270818d158 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -146,6 +146,8 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, "-mcpu=hexagon" + toolchains::HexagonToolChain::GetTargetCPUVersion(Args))); + addSanitizerRuntimes(HTC, Args, CmdArgs); + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -223,6 +225,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, bool UseShared = IsShared && !IsStatic; StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); + bool NeedsSanitizerDeps = addSanitizerRuntimes(HTC, Args, CmdArgs); + //---------------------------------------------------------------------------- // Silence warnings for various options //---------------------------------------------------------------------------- @@ -288,6 +292,12 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (NeedsSanitizerDeps) { + linkSanitizerRuntimeDeps(HTC, CmdArgs); + + CmdArgs.push_back("-lunwind"); + } + CmdArgs.push_back("-lclang_rt.builtins-hexagon"); CmdArgs.push_back("-lc"); } @@ -450,6 +460,13 @@ Optional<unsigned> HexagonToolChain::getSmallDataThreshold( return None; } +std::string HexagonToolChain::getCompilerRTPath() const { + SmallString<128> Dir(getDriver().SysRoot); + llvm::sys::path::append(Dir, "usr", "lib"); + Dir += SelectedMultilib.gccSuffix(); + return std::string(Dir.str()); +} + void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, ToolChain::path_list &LibPaths) const { const Driver &D = getDriver(); @@ -470,7 +487,7 @@ 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); @@ -588,21 +605,43 @@ void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc) || - DriverArgs.hasArg(options::OPT_nostdlibinc)) + if (DriverArgs.hasArg(options::OPT_nostdinc)) return; + const bool IsELF = !getTriple().isMusl() && !getTriple().isOSLinux(); + const bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux(); + const Driver &D = getDriver(); - if (!D.SysRoot.empty()) { + SmallString<128> ResourceDirInclude(D.ResourceDir); + if (!IsELF) { + llvm::sys::path::append(ResourceDirInclude, "include"); + if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && + (!IsLinuxMusl || DriverArgs.hasArg(options::OPT_nostdlibinc))) + addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); + } + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + const bool HasSysRoot = !D.SysRoot.empty(); + if (HasSysRoot) { SmallString<128> P(D.SysRoot); - if (getTriple().isMusl()) + if (IsLinuxMusl) llvm::sys::path::append(P, "usr/include"); else llvm::sys::path::append(P, "include"); + addExternCSystemInclude(DriverArgs, CC1Args, P.str()); - return; + // LOCAL_INCLUDE_DIR + addSystemInclude(DriverArgs, CC1Args, P + "/usr/local/include"); + // TOOL_INCLUDE_DIR + AddMultilibIncludeArgs(DriverArgs, CC1Args); } + if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && IsLinuxMusl) + addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); + + if (HasSysRoot) + return; std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), D.PrefixDirs); addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); @@ -665,11 +704,11 @@ 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; diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h index c32cb7f09591..899630555352 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.h +++ b/clang/lib/Driver/ToolChains/Hexagon.h @@ -104,9 +104,11 @@ 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); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index c9360fc67165..0224383e63a1 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -206,8 +206,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 @@ -262,6 +261,13 @@ 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, SysRoot + "/libo32", Paths); + addPathIfExists(D, SysRoot + "/usr/libo32", Paths); + } Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths); addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); @@ -303,8 +309,13 @@ Linux::Linux(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).startswith(SysRoot)) { + // Even if OSLibDir != "lib", this is needed for Clang in the build + // directory (not installed) to find libc++. addPathIfExists(D, D.Dir + "/../lib", Paths); + if (OSLibDir != "lib") + addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); + } addPathIfExists(D, SysRoot + "/lib", Paths); addPathIfExists(D, SysRoot + "/usr/lib", Paths); @@ -449,7 +460,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); @@ -651,9 +662,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 getTriple().isAndroid() || getTriple().isMusl() || + getSanitizerArgs(Args).requiresPIE(); } bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const { @@ -669,10 +680,6 @@ bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const { return true; } -bool Linux::isNoExecStackDefault() const { - return getTriple().isAndroid(); -} - bool Linux::IsMathErrnoDefault() const { if (getTriple().isAndroid()) return false; @@ -694,6 +701,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { getTriple().getArch() == llvm::Triple::thumbeb; 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; @@ -707,7 +715,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::DataFlow; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 || - IsRISCV64 || IsSystemZ) + IsRISCV64 || IsSystemZ || IsHexagon) Res |= SanitizerKind::Leak; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ) Res |= SanitizerKind::Thread; @@ -716,7 +724,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { if (IsX86 || IsX86_64) Res |= SanitizerKind::Function; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || - IsPowerPC64) + IsPowerPC64 || IsHexagon) Res |= SanitizerKind::Scudo; if (IsX86_64 || IsAArch64) { Res |= SanitizerKind::HWAddress; diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index 169a37c44072..a5ec33bd44f1 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -43,8 +43,7 @@ public: 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, diff --git a/clang/lib/Driver/ToolChains/MSP430.h b/clang/lib/Driver/ToolChains/MSP430.h index 9d247ca3a896..2e838c027e0f 100644 --- a/clang/lib/Driver/ToolChains/MSP430.h +++ b/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 diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 0dc94a4c6c7d..792b0a51fea0 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -63,6 +63,61 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +// Windows SDKs and VC Toolchains group their contents into subdirectories based +// on the target architecture. This function converts an llvm::Triple::ArchType +// to the corresponding subdirectory name. +static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) { + using ArchType = llvm::Triple::ArchType; + switch (Arch) { + case ArchType::x86: + return "x86"; + case ArchType::x86_64: + return "x64"; + case ArchType::arm: + return "arm"; + case ArchType::aarch64: + return "arm64"; + default: + return ""; + } +} + +// Similar to the above function, but for Visual Studios before VS2017. +static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) { + using ArchType = llvm::Triple::ArchType; + switch (Arch) { + case ArchType::x86: + // x86 is default in legacy VC toolchains. + // e.g. x86 libs are directly in /lib as opposed to /lib/x86. + return ""; + case ArchType::x86_64: + return "amd64"; + case ArchType::arm: + return "arm"; + case ArchType::aarch64: + return "arm64"; + default: + return ""; + } +} + +// Similar to the above function, but for DevDiv internal builds. +static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) { + using ArchType = llvm::Triple::ArchType; + switch (Arch) { + case ArchType::x86: + return "i386"; + case ArchType::x86_64: + return "amd64"; + case ArchType::arm: + return "arm"; + case ArchType::aarch64: + return "arm64"; + default: + return ""; + } +} + static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) { auto Status = VFS.status(Path); if (!Status) @@ -396,6 +451,20 @@ 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", + llvmArchToLegacyVCArch(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)) { @@ -461,7 +530,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 +541,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)); @@ -726,15 +795,17 @@ bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const { } 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, @@ -752,61 +823,6 @@ void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { RocmInstallation.print(OS); } -// Windows SDKs and VC Toolchains group their contents into subdirectories based -// on the target architecture. This function converts an llvm::Triple::ArchType -// to the corresponding subdirectory name. -static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) { - using ArchType = llvm::Triple::ArchType; - switch (Arch) { - case ArchType::x86: - return "x86"; - case ArchType::x86_64: - return "x64"; - case ArchType::arm: - return "arm"; - case ArchType::aarch64: - return "arm64"; - default: - return ""; - } -} - -// Similar to the above function, but for Visual Studios before VS2017. -static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) { - using ArchType = llvm::Triple::ArchType; - switch (Arch) { - case ArchType::x86: - // x86 is default in legacy VC toolchains. - // e.g. x86 libs are directly in /lib as opposed to /lib/x86. - return ""; - case ArchType::x86_64: - return "amd64"; - case ArchType::arm: - return "arm"; - case ArchType::aarch64: - return "arm64"; - default: - return ""; - } -} - -// Similar to the above function, but for DevDiv internal builds. -static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) { - using ArchType = llvm::Triple::ArchType; - switch (Arch) { - case ArchType::x86: - return "i386"; - case ArchType::x86_64: - return "amd64"; - case ArchType::arm: - return "arm"; - case ArchType::aarch64: - return "arm64"; - default: - return ""; - } -} - // 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 @@ -1263,6 +1279,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; diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index 19d94c5c606e..8f033de09bf6 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -52,7 +52,7 @@ public: bool IsIntegratedAssemblerDefault() const override; bool IsUnwindTablesDefault(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 diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 20efbdc237a8..ecce2f062bd7 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -98,7 +98,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; @@ -136,10 +136,13 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, llvm_unreachable("Unsupported target architecture."); } - if (Args.hasArg(options::OPT_mwindows)) { + Arg *SubsysArg = + Args.getLastArg(options::OPT_mwindows, options::OPT_mconsole); + if (SubsysArg && SubsysArg->getOption().matches(options::OPT_mwindows)) { CmdArgs.push_back("--subsystem"); CmdArgs.push_back("windows"); - } else if (Args.hasArg(options::OPT_mconsole)) { + } else if (SubsysArg && + SubsysArg->getOption().matches(options::OPT_mconsole)) { CmdArgs.push_back("--subsystem"); CmdArgs.push_back("console"); } @@ -346,29 +349,29 @@ static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, } 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()); + llvm::SmallVector<llvm::SmallString<32>, 2> SubdirNames; + SubdirNames.emplace_back(getTriple().getArchName()); + SubdirNames[0] += "-w64-mingw32"; + SubdirNames.emplace_back("mingw32"); + if (SubdirName.empty()) + SubdirName = std::string(SubdirNames[0].str()); // 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); + llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot); if (findGccVersion(LibDir, GccLibDir, Ver)) { - Arch = std::string(CandidateArch); + SubdirName = std::string(CandidateSysroot); return; } } } } -llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() { +static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &T) { llvm::SmallVector<llvm::SmallString<32>, 2> Gccs; - Gccs.emplace_back(getTriple().getArchName()); + Gccs.emplace_back(T.getArchName()); Gccs[0] += "-w64-mingw32-gcc"; Gccs.emplace_back("mingw32-gcc"); // Please do not add "gcc" here @@ -378,17 +381,18 @@ 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() { +static llvm::ErrorOr<std::string> +findClangRelativeSysroot(const Driver &D, const llvm::Triple &T, + std::string &SubdirName) { llvm::SmallVector<llvm::SmallString<32>, 2> Subdirs; - Subdirs.emplace_back(getTriple().str()); - Subdirs.emplace_back(getTriple().getArchName()); + Subdirs.emplace_back(T.str()); + Subdirs.emplace_back(T.getArchName()); Subdirs[1] += "-w64-mingw32"; - StringRef ClangRoot = - llvm::sys::path::parent_path(getDriver().getInstalledDir()); + 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(); } } @@ -401,13 +405,16 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); + // The sequence for detecting a sysroot here should be kept in sync with + // the testTriple function below. 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(), getTriple(), SubdirName)) Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); - else if (llvm::ErrorOr<std::string> GPPName = findGcc()) + else if (llvm::ErrorOr<std::string> GPPName = findGcc(getTriple())) Base = std::string(llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get()))); else @@ -420,10 +427,10 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, // correct crtbegin.o ,cetend.o would be found. getFilePaths().push_back(GccLibDir); getFilePaths().push_back( - (Base + Arch + llvm::sys::path::get_separator() + "lib").str()); + (Base + SubdirName + llvm::sys::path::get_separator() + "lib").str()); getFilePaths().push_back(Base + "lib"); // openSUSE - getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib"); + getFilePaths().push_back(Base + SubdirName + "/sys-root/mingw/lib"); NativeLLVMSupport = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER) @@ -471,13 +478,17 @@ bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const { } 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::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool toolchains::MinGW::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::aarch64; } llvm::ExceptionHandling @@ -568,11 +579,12 @@ void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) { // openSUSE addSystemInclude(DriverArgs, CC1Args, - Base + Arch + "/sys-root/mingw/include"); + Base + SubdirName + "/sys-root/mingw/include"); } addSystemInclude(DriverArgs, CC1Args, - Base + Arch + llvm::sys::path::get_separator() + "include"); + Base + SubdirName + llvm::sys::path::get_separator() + + "include"); addSystemInclude(DriverArgs, CC1Args, Base + "include"); } @@ -585,19 +597,27 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( 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; 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); @@ -605,9 +625,61 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( for (auto &CppIncludeBase : CppIncludeBases) { addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); CppIncludeBase += Slash; - addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + SubdirName); 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; + if (llvm::ErrorOr<std::string> TargetSubdir = + findClangRelativeSysroot(D, Triple, SubdirName)) + return true; + if (llvm::ErrorOr<std::string> GPPName = findGcc(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/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h index 2f1559fcf34c..c3de19b97724 100644 --- a/clang/lib/Driver/ToolChains/MinGW.h +++ b/clang/lib/Driver/ToolChains/MinGW.h @@ -60,12 +60,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; 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; @@ -99,12 +102,10 @@ private: std::string Base; std::string GccLibDir; std::string Ver; - std::string Arch; + std::string SubdirName; 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(); bool NativeLLVMSupport; }; diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp index 1ce5a2a203c2..7571398b7cc6 100644 --- a/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -29,12 +29,17 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const toolchains::NetBSD &ToolChain = + static_cast<const toolchains::NetBSD &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); + claimNoWarnArgs(Args); ArgStringList CmdArgs; // 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,29 @@ 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: { 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 +106,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)); @@ -116,6 +120,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const toolchains::NetBSD &ToolChain = static_cast<const toolchains::NetBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); + ArgStringList CmdArgs; if (!D.SysRoot.empty()) @@ -150,7 +156,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 +174,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"); @@ -254,19 +260,18 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - 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); + Triple.getOSVersion(Major, Minor, Micro); bool useLibgcc = true; if (Major >= 7 || Major == 0) { switch (ToolChain.getArch()) { @@ -294,7 +299,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, // 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); + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) @@ -302,7 +307,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lm"); } if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, CmdArgs); if (NeedsXRayDeps) linkXRayRuntimeDeps(ToolChain, CmdArgs); if (Args.hasArg(options::OPT_pthread)) @@ -496,7 +501,7 @@ 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"); diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp index e162165b2561..96abac57764f 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/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" @@ -28,16 +29,30 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const toolchains::OpenBSD &ToolChain = + static_cast<const toolchains::OpenBSD &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); + claimNoWarnArgs(Args); ArgStringList CmdArgs; - switch (getToolChain().getArch()) { + 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: + case llvm::Triple::armeb: { + 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 +60,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 +70,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 +99,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)); @@ -94,7 +112,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { const toolchains::OpenBSD &ToolChain = static_cast<const toolchains::OpenBSD &>(getToolChain()); - const Driver &D = getToolChain().getDriver(); + const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -174,6 +192,11 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + // Use the static OpenMP runtime with -static-openmp + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && + !Args.hasArg(options::OPT_static); + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); @@ -221,6 +244,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); } + ToolChain.addProfileRTLibs(Args, CmdArgs); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), diff --git a/clang/lib/Driver/ToolChains/OpenBSD.h b/clang/lib/Driver/ToolChains/OpenBSD.h index 4932ed5c609c..95c10cc62316 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/clang/lib/Driver/ToolChains/OpenBSD.h @@ -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; diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index 383b0c50d410..5783a733983a 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -71,8 +71,9 @@ void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, Exec, CmdArgs, Inputs, Output)); } -static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); +static void AddPS4SanitizerArgs(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); if (SanArgs.needsUbsanRt()) { CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); } @@ -81,9 +82,9 @@ static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { } } -void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, +void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); if (SanArgs.needsUbsanRt()) CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a"); if (SanArgs.needsAsanRt()) @@ -127,7 +128,7 @@ void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, } if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - AddPS4SanitizerArgs(ToolChain, CmdArgs); + AddPS4SanitizerArgs(ToolChain, Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h index 5f5d0e57d4ea..82f9523f84fb 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/clang/lib/Driver/ToolChains/PS4CPU.h @@ -23,7 +23,8 @@ namespace PS4cpu { 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 { public: diff --git a/clang/lib/Driver/ToolChains/SPIRV.cpp b/clang/lib/Driver/ToolChains/SPIRV.cpp new file mode 100644 index 000000000000..16e72d3c733f --- /dev/null +++ b/clang/lib/Driver/ToolChains/SPIRV.cpp @@ -0,0 +1,49 @@ +//===--- 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::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-text"); + + 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], {}); +} diff --git a/clang/lib/Driver/ToolChains/SPIRV.h b/clang/lib/Driver/ToolChains/SPIRV.h new file mode 100644 index 000000000000..35d0446bd8b8 --- /dev/null +++ b/clang/lib/Driver/ToolChains/SPIRV.h @@ -0,0 +1,46 @@ +//===--- 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 addTranslatorArgs(const llvm::opt::ArgList &InArgs, + llvm::opt::ArgStringList &OutArgs); + +void constructTranslateCommand(Compilation &C, const Tool &T, + const JobAction &JA, const InputInfo &Output, + const InputInfo &Input, + 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; +}; + +} // namespace SPIRV +} // namespace tools +} // namespace driver +} // namespace clang +#endif diff --git a/clang/lib/Driver/ToolChains/TCE.cpp b/clang/lib/Driver/ToolChains/TCE.cpp index 33a81c54bd42..5f4051d31168 100644 --- a/clang/lib/Driver/ToolChains/TCE.cpp +++ b/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/clang/lib/Driver/ToolChains/TCE.h b/clang/lib/Driver/ToolChains/TCE.h index 72933dae965e..31a64cfe878a 100644 --- a/clang/lib/Driver/ToolChains/TCE.h +++ b/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/clang/lib/Driver/ToolChains/VEToolchain.cpp b/clang/lib/Driver/ToolChains/VEToolchain.cpp index e28f340f9aad..1fcc52684baa 100644 --- a/clang/lib/Driver/ToolChains/VEToolchain.cpp +++ b/clang/lib/Driver/ToolChains/VEToolchain.cpp @@ -53,7 +53,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; } diff --git a/clang/lib/Driver/ToolChains/VEToolchain.h b/clang/lib/Driver/ToolChains/VEToolchain.h index b330331ca84e..964b0d0dd8d4 100644 --- a/clang/lib/Driver/ToolChains/VEToolchain.h +++ b/clang/lib/Driver/ToolChains/VEToolchain.h @@ -28,7 +28,7 @@ protected: 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/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 19f3571e6b38..a7298a9a71bf 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -63,7 +63,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"); @@ -130,7 +130,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, // When optimizing, if wasm-opt is available, run it. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - auto WasmOptPath = getToolChain().GetProgramPath("wasm-opt"); + auto WasmOptPath = ToolChain.GetProgramPath("wasm-opt"); if (WasmOptPath != "wasm-opt") { StringRef OOpt = "s"; if (A->getOption().matches(options::OPT_O4) || @@ -201,7 +201,9 @@ 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; } @@ -293,6 +295,9 @@ 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)) { @@ -300,14 +305,14 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, if (Opt.startswith("-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 +328,38 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, ":noinline")); } } + + if (Opt.startswith("-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"); + } } } diff --git a/clang/lib/Driver/ToolChains/WebAssembly.h b/clang/lib/Driver/ToolChains/WebAssembly.h index 8a3f82d9efdf..c84e59675946 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/clang/lib/Driver/ToolChains/WebAssembly.h @@ -45,7 +45,7 @@ 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; diff --git a/clang/lib/Driver/ToolChains/XCore.cpp b/clang/lib/Driver/ToolChains/XCore.cpp index 5f94f83d3691..7e74f6374050 100644 --- a/clang/lib/Driver/ToolChains/XCore.cpp +++ b/clang/lib/Driver/ToolChains/XCore.cpp @@ -102,7 +102,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; } diff --git a/clang/lib/Driver/ToolChains/XCore.h b/clang/lib/Driver/ToolChains/XCore.h index 41dce08454c0..d9a05da3c678 100644 --- a/clang/lib/Driver/ToolChains/XCore.h +++ b/clang/lib/Driver/ToolChains/XCore.h @@ -58,7 +58,7 @@ protected: public: 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/clang/lib/Driver/ToolChains/ZOS.h b/clang/lib/Driver/ToolChains/ZOS.h index cace85d6da77..50bff0993561 100644 --- a/clang/lib/Driver/ToolChains/ZOS.h +++ b/clang/lib/Driver/ToolChains/ZOS.h @@ -23,7 +23,9 @@ 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; } |