diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /clang/lib/Driver/ToolChains | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'clang/lib/Driver/ToolChains')
77 files changed, 3466 insertions, 1758 deletions
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 6fbff61f7656..ac5544eedb00 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -13,12 +13,15 @@ #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" using AIX = clang::driver::toolchains::AIX; using namespace clang::driver; using namespace clang::driver::tools; +using namespace clang::driver::toolchains; using namespace llvm::opt; +using namespace llvm::sys; void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, @@ -73,7 +76,8 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -81,6 +85,7 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const AIX &ToolChain = static_cast<const AIX &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; const bool IsArch32Bit = ToolChain.getTriple().isArch32Bit(); @@ -129,6 +134,12 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename()))); } + // Collect all static constructor and destructor functions in CXX mode. This + // has to come before AddLinkerInputs as the implied option needs to precede + // any other '-bcdtors' settings or '-bnocdtors' that '-Wl' might forward. + if (D.CCCIsCXX()) + CmdArgs.push_back("-bcdtors:all:0:s"); + // Specify linker input file(s). AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); @@ -145,7 +156,8 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } /// AIX - AIX tool chain which can call as(1) and ld(1) directly. @@ -154,6 +166,43 @@ AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); } +// Returns the effective header sysroot path to use. +// This comes from either -isysroot or --sysroot. +llvm::StringRef +AIX::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const { + if (DriverArgs.hasArg(options::OPT_isysroot)) + return DriverArgs.getLastArgValue(options::OPT_isysroot); + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + return "/"; +} + +void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + // Return if -nostdinc is specified as a driver option. + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); + const Driver &D = getDriver(); + + // Add the Clang builtin headers (<resource>/include). + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + path::append(P, "/include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + } + + // Return if -nostdlibinc is specified as a driver option. + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Add <sysroot>/usr/include. + SmallString<128> UP(Sysroot); + path::append(UP, "/usr/include"); + addSystemInclude(DriverArgs, CC1Args, UP.str()); +} + auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); } auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); } diff --git a/clang/lib/Driver/ToolChains/AIX.h b/clang/lib/Driver/ToolChains/AIX.h index 69b948bc0ea8..942bb3cceb8a 100644 --- a/clang/lib/Driver/ToolChains/AIX.h +++ b/clang/lib/Driver/ToolChains/AIX.h @@ -63,9 +63,16 @@ public: bool isPIEDefault() const override { return false; } bool isPICDefaultForced() const override { return true; } + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + +private: + llvm::StringRef GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index 71a2c68b4197..bc6d1fcd4a00 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -12,6 +12,8 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -19,6 +21,327 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; +void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) { + assert(!Path.empty()); + + const StringRef Suffix(".bc"); + const StringRef Suffix2(".amdgcn.bc"); + + std::error_code EC; + for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Path, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef FilePath = LI->path(); + StringRef FileName = llvm::sys::path::filename(FilePath); + if (!FileName.endswith(Suffix)) + continue; + + StringRef BaseName; + if (FileName.endswith(Suffix2)) + BaseName = FileName.drop_back(Suffix2.size()); + else if (FileName.endswith(Suffix)) + BaseName = FileName.drop_back(Suffix.size()); + + if (BaseName == "ocml") { + OCML = FilePath; + } else if (BaseName == "ockl") { + OCKL = FilePath; + } else if (BaseName == "opencl") { + OpenCL = FilePath; + } else if (BaseName == "hip") { + HIP = FilePath; + } else if (BaseName == "oclc_finite_only_off") { + FiniteOnly.Off = FilePath; + } else if (BaseName == "oclc_finite_only_on") { + FiniteOnly.On = FilePath; + } else if (BaseName == "oclc_daz_opt_on") { + DenormalsAreZero.On = FilePath; + } else if (BaseName == "oclc_daz_opt_off") { + DenormalsAreZero.Off = FilePath; + } else if (BaseName == "oclc_correctly_rounded_sqrt_on") { + CorrectlyRoundedSqrt.On = FilePath; + } else if (BaseName == "oclc_correctly_rounded_sqrt_off") { + CorrectlyRoundedSqrt.Off = FilePath; + } else if (BaseName == "oclc_unsafe_math_on") { + UnsafeMath.On = FilePath; + } else if (BaseName == "oclc_unsafe_math_off") { + UnsafeMath.Off = FilePath; + } else if (BaseName == "oclc_wavefrontsize64_on") { + WavefrontSize64.On = FilePath; + } else if (BaseName == "oclc_wavefrontsize64_off") { + WavefrontSize64.Off = FilePath; + } else { + // Process all bitcode filenames that look like + // ocl_isa_version_XXX.amdgcn.bc + const StringRef DeviceLibPrefix = "oclc_isa_version_"; + if (!BaseName.startswith(DeviceLibPrefix)) + continue; + + StringRef IsaVersionNumber = + BaseName.drop_front(DeviceLibPrefix.size()); + + llvm::Twine GfxName = Twine("gfx") + IsaVersionNumber; + SmallString<8> Tmp; + LibDeviceMap.insert( + std::make_pair(GfxName.toStringRef(Tmp), FilePath.str())); + } + } +} + +void RocmInstallationDetector::ParseHIPVersionFile(llvm::StringRef V) { + SmallVector<StringRef, 4> VersionParts; + V.split(VersionParts, '\n'); + unsigned Major; + unsigned Minor; + for (auto Part : VersionParts) { + auto Splits = Part.split('='); + if (Splits.first == "HIP_VERSION_MAJOR") + Splits.second.getAsInteger(0, Major); + else if (Splits.first == "HIP_VERSION_MINOR") + Splits.second.getAsInteger(0, Minor); + else if (Splits.first == "HIP_VERSION_PATCH") + VersionPatch = Splits.second.str(); + } + VersionMajorMinor = llvm::VersionTuple(Major, Minor); + DetectedVersion = + (Twine(Major) + "." + Twine(Minor) + "." + VersionPatch).str(); +} + +// For candidate specified by --rocm-path we do not do strict check. +SmallVector<RocmInstallationDetector::Candidate, 4> +RocmInstallationDetector::getInstallationPathCandidates() { + SmallVector<Candidate, 4> Candidates; + if (!RocmPathArg.empty()) { + Candidates.emplace_back(RocmPathArg.str()); + return Candidates; + } + + // Try to find relative to the compiler binary. + const char *InstallDir = D.getInstalledDir(); + + // Check both a normal Unix prefix position of the clang binary, as well as + // the Windows-esque layout the ROCm packages use with the host architecture + // subdirectory of bin. + + // Strip off directory (usually bin) + StringRef ParentDir = llvm::sys::path::parent_path(InstallDir); + StringRef ParentName = llvm::sys::path::filename(ParentDir); + + // Some builds use bin/{host arch}, so go up again. + if (ParentName == "bin") { + ParentDir = llvm::sys::path::parent_path(ParentDir); + ParentName = llvm::sys::path::filename(ParentDir); + } + + // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin + if (ParentName == "llvm") + ParentDir = llvm::sys::path::parent_path(ParentDir); + + Candidates.emplace_back(ParentDir.str(), /*StrictChecking=*/true); + + // Device library may be installed in clang resource directory. + Candidates.emplace_back(D.ResourceDir, /*StrictChecking=*/true); + + Candidates.emplace_back(D.SysRoot + "/opt/rocm", /*StrictChecking=*/true); + return Candidates; +} + +RocmInstallationDetector::RocmInstallationDetector( + const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args, bool DetectHIPRuntime, bool DetectDeviceLib) + : D(D) { + RocmPathArg = Args.getLastArgValue(clang::driver::options::OPT_rocm_path_EQ); + RocmDeviceLibPathArg = + Args.getAllArgValues(clang::driver::options::OPT_rocm_device_lib_path_EQ); + if (auto *A = Args.getLastArg(clang::driver::options::OPT_hip_version_EQ)) { + HIPVersionArg = A->getValue(); + unsigned Major = 0; + unsigned Minor = 0; + SmallVector<StringRef, 3> Parts; + HIPVersionArg.split(Parts, '.'); + if (Parts.size()) + Parts[0].getAsInteger(0, Major); + if (Parts.size() > 1) + Parts[1].getAsInteger(0, Minor); + if (Parts.size() > 2) + VersionPatch = Parts[2].str(); + if (VersionPatch.empty()) + VersionPatch = "0"; + if (Major == 0 || Minor == 0) + D.Diag(diag::err_drv_invalid_value) + << A->getAsString(Args) << HIPVersionArg; + + VersionMajorMinor = llvm::VersionTuple(Major, Minor); + DetectedVersion = + (Twine(Major) + "." + Twine(Minor) + "." + VersionPatch).str(); + } else { + VersionPatch = DefaultVersionPatch; + VersionMajorMinor = + llvm::VersionTuple(DefaultVersionMajor, DefaultVersionMinor); + DetectedVersion = (Twine(DefaultVersionMajor) + "." + + Twine(DefaultVersionMinor) + "." + VersionPatch) + .str(); + } + + if (DetectHIPRuntime) + detectHIPRuntime(); + if (DetectDeviceLib) + detectDeviceLibrary(); +} + +void RocmInstallationDetector::detectDeviceLibrary() { + assert(LibDevicePath.empty()); + + if (!RocmDeviceLibPathArg.empty()) + LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1]; + else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH")) + LibDevicePath = LibPathEnv; + + auto &FS = D.getVFS(); + if (!LibDevicePath.empty()) { + // Maintain compatability with HIP flag/envvar pointing directly at the + // bitcode library directory. This points directly at the library path instead + // of the rocm root installation. + if (!FS.exists(LibDevicePath)) + return; + + scanLibDevicePath(LibDevicePath); + HasDeviceLibrary = allGenericLibsValid() && !LibDeviceMap.empty(); + return; + } + + // The install path situation in old versions of ROCm is a real mess, and + // use a different install layout. Multiple copies of the device libraries + // exist for each frontend project, and differ depending on which build + // system produced the packages. Standalone OpenCL builds also have a + // different directory structure from the ROCm OpenCL package. + auto Candidates = getInstallationPathCandidates(); + for (const auto &Candidate : Candidates) { + auto CandidatePath = Candidate.Path; + + // Check device library exists at the given path. + auto CheckDeviceLib = [&](StringRef Path) { + bool CheckLibDevice = (!NoBuiltinLibs || Candidate.StrictChecking); + if (CheckLibDevice && !FS.exists(Path)) + return false; + + scanLibDevicePath(Path); + + if (!NoBuiltinLibs) { + // Check that the required non-target libraries are all available. + if (!allGenericLibsValid()) + return false; + + // Check that we have found at least one libdevice that we can link in + // if -nobuiltinlib hasn't been specified. + if (LibDeviceMap.empty()) + return false; + } + return true; + }; + + // The possible structures are: + // - ${ROCM_ROOT}/amdgcn/bitcode/* + // - ${ROCM_ROOT}/lib/* + // - ${ROCM_ROOT}/lib/bitcode/* + // so try to detect these layouts. + static llvm::SmallVector<const char *, 2> SubDirsList[] = { + {"amdgcn", "bitcode"}, + {"lib"}, + {"lib", "bitcode"}, + }; + + // Make a path by appending sub-directories to InstallPath. + auto MakePath = [&](const llvm::ArrayRef<const char *> &SubDirs) { + auto Path = CandidatePath; + for (auto SubDir : SubDirs) + llvm::sys::path::append(Path, SubDir); + return Path; + }; + + for (auto SubDirs : SubDirsList) { + LibDevicePath = MakePath(SubDirs); + HasDeviceLibrary = CheckDeviceLib(LibDevicePath); + if (HasDeviceLibrary) + return; + } + } +} + +void RocmInstallationDetector::detectHIPRuntime() { + auto Candidates = getInstallationPathCandidates(); + auto &FS = D.getVFS(); + + for (const auto &Candidate : Candidates) { + InstallPath = Candidate.Path; + if (InstallPath.empty() || !FS.exists(InstallPath)) + continue; + + BinPath = InstallPath; + llvm::sys::path::append(BinPath, "bin"); + IncludePath = InstallPath; + llvm::sys::path::append(IncludePath, "include"); + LibPath = InstallPath; + llvm::sys::path::append(LibPath, "lib"); + + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = + FS.getBufferForFile(BinPath + "/.hipVersion"); + if (!VersionFile && Candidate.StrictChecking) + continue; + + if (HIPVersionArg.empty() && VersionFile) + ParseHIPVersionFile((*VersionFile)->getBuffer()); + + HasHIPRuntime = true; + return; + } + HasHIPRuntime = false; +} + +void RocmInstallationDetector::print(raw_ostream &OS) const { + if (hasHIPRuntime()) + OS << "Found HIP installation: " << InstallPath << ", version " + << DetectedVersion << '\n'; +} + +void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5); + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + // HIP header includes standard library wrapper headers under clang + // cuda_wrappers directory. Since these wrapper headers include_next + // standard C++ headers, whereas libc++ headers include_next other clang + // headers. The include paths have to follow this order: + // - wrapper include path + // - standard C++ include path + // - other clang include path + // Since standard C++ and other clang include paths are added in other + // places after this function, here we only need to make sure wrapper + // include path is added. + // + // ROCm 3.5 does not fully support the wrapper headers. Therefore it needs + // a workaround. + SmallString<128> P(D.ResourceDir); + if (UsesRuntimeWrapper) + llvm::sys::path::append(P, "include", "cuda_wrappers"); + CC1Args.push_back("-internal-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(P)); + } + + if (DriverArgs.hasArg(options::OPT_nogpuinc)) + return; + + if (!hasHIPRuntime()) { + D.Diag(diag::err_drv_no_hip_runtime); + return; + } + + CC1Args.push_back("-internal-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); + if (UsesRuntimeWrapper) + CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"}); +} + void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -31,8 +354,9 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-shared"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), - CmdArgs, Inputs)); + C.addCommand( + std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(Linker), CmdArgs, Inputs)); } void amdgpu::getAMDGPUTargetFeatures(const Driver &D, @@ -102,6 +426,73 @@ AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, return DAL; } +bool AMDGPUToolChain::getDefaultDenormsAreZeroForTarget( + llvm::AMDGPU::GPUKind Kind) { + + // Assume nothing without a specific target. + if (Kind == llvm::AMDGPU::GK_NONE) + return false; + + const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind); + + // Default to enabling f32 denormals by default on subtargets where fma is + // fast with denormals + const bool BothDenormAndFMAFast = + (ArchAttr & llvm::AMDGPU::FEATURE_FAST_FMA_F32) && + (ArchAttr & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32); + return !BothDenormAndFMAFast; +} + +llvm::DenormalMode AMDGPUToolChain::getDefaultDenormalModeForType( + const llvm::opt::ArgList &DriverArgs, const JobAction &JA, + const llvm::fltSemantics *FPType) const { + // Denormals should always be enabled for f16 and f64. + if (!FPType || FPType != &llvm::APFloat::IEEEsingle()) + return llvm::DenormalMode::getIEEE(); + + if (JA.getOffloadingDeviceKind() == Action::OFK_HIP || + JA.getOffloadingDeviceKind() == Action::OFK_Cuda) { + auto Kind = llvm::AMDGPU::parseArchAMDGCN(JA.getOffloadingArch()); + if (FPType && FPType == &llvm::APFloat::IEEEsingle() && + DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, + options::OPT_fno_cuda_flush_denormals_to_zero, + getDefaultDenormsAreZeroForTarget(Kind))) + return llvm::DenormalMode::getPreserveSign(); + + return llvm::DenormalMode::getIEEE(); + } + + const StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ); + auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); + + // TODO: There are way too many flags that change this. Do we need to check + // them all? + bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) || + getDefaultDenormsAreZeroForTarget(Kind); + + // Outputs are flushed to zero (FTZ), preserving sign. Denormal inputs are + // also implicit treated as zero (DAZ). + return DAZ ? llvm::DenormalMode::getPreserveSign() : + llvm::DenormalMode::getIEEE(); +} + +bool AMDGPUToolChain::isWave64(const llvm::opt::ArgList &DriverArgs, + llvm::AMDGPU::GPUKind Kind) { + const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind); + static bool HasWave32 = (ArchAttr & llvm::AMDGPU::FEATURE_WAVE32); + + return !HasWave32 || DriverArgs.hasFlag( + options::OPT_mwavefrontsize64, options::OPT_mno_wavefrontsize64, false); +} + + +/// ROCM Toolchain +ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : AMDGPUToolChain(D, Triple, Args) { + RocmInstallation.detectDeviceLibrary(); +} + void AMDGPUToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, @@ -115,3 +506,91 @@ void AMDGPUToolChain::addClangTargetOptions( CC1Args.push_back("-fapply-global-visibility-to-externs"); } } + +void ROCMToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + AMDGPUToolChain::addClangTargetOptions(DriverArgs, CC1Args, + DeviceOffloadingKind); + + // For the OpenCL case where there is no offload target, accept -nostdlib to + // disable bitcode linking. + if (DeviceOffloadingKind == Action::OFK_None && + DriverArgs.hasArg(options::OPT_nostdlib)) + return; + + if (DriverArgs.hasArg(options::OPT_nogpulib)) + return; + + if (!RocmInstallation.hasDeviceLibrary()) { + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; + return; + } + + // Get the device name and canonicalize it + const StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ); + 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; + } + + bool Wave64 = isWave64(DriverArgs, Kind); + + // TODO: There are way too many flags that change this. Do we need to check + // them all? + bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) || + getDefaultDenormsAreZeroForTarget(Kind); + bool FiniteOnly = DriverArgs.hasArg(options::OPT_cl_finite_math_only); + + bool UnsafeMathOpt = + DriverArgs.hasArg(options::OPT_cl_unsafe_math_optimizations); + bool FastRelaxedMath = DriverArgs.hasArg(options::OPT_cl_fast_relaxed_math); + bool CorrectSqrt = + DriverArgs.hasArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt); + + // Add the OpenCL specific bitcode library. + CC1Args.push_back("-mlink-builtin-bitcode"); + CC1Args.push_back(DriverArgs.MakeArgString(RocmInstallation.getOpenCLPath())); + + // Add the generic set of libraries. + RocmInstallation.addCommonBitcodeLibCC1Args( + DriverArgs, CC1Args, LibDeviceFile, Wave64, DAZ, FiniteOnly, + UnsafeMathOpt, FastRelaxedMath, CorrectSqrt); +} + +void RocmInstallationDetector::addCommonBitcodeLibCC1Args( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + StringRef LibDeviceFile, bool Wave64, bool DAZ, bool FiniteOnly, + bool UnsafeMathOpt, bool FastRelaxedMath, bool CorrectSqrt) const { + static const char LinkBitcodeFlag[] = "-mlink-builtin-bitcode"; + + CC1Args.push_back(LinkBitcodeFlag); + CC1Args.push_back(DriverArgs.MakeArgString(getOCMLPath())); + + CC1Args.push_back(LinkBitcodeFlag); + CC1Args.push_back(DriverArgs.MakeArgString(getOCKLPath())); + + CC1Args.push_back(LinkBitcodeFlag); + CC1Args.push_back(DriverArgs.MakeArgString(getDenormalsAreZeroPath(DAZ))); + + CC1Args.push_back(LinkBitcodeFlag); + CC1Args.push_back(DriverArgs.MakeArgString( + getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath))); + + CC1Args.push_back(LinkBitcodeFlag); + CC1Args.push_back(DriverArgs.MakeArgString( + getFiniteOnlyPath(FiniteOnly || FastRelaxedMath))); + + CC1Args.push_back(LinkBitcodeFlag); + CC1Args.push_back( + DriverArgs.MakeArgString(getCorrectlyRoundedSqrtPath(CorrectSqrt))); + + CC1Args.push_back(LinkBitcodeFlag); + CC1Args.push_back(DriverArgs.MakeArgString(getWavefrontSize64Path(Wave64))); + + CC1Args.push_back(LinkBitcodeFlag); + CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); +} diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h index f4c78bea5cc9..5d44faf28b05 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/clang/lib/Driver/ToolChains/AMDGPU.h @@ -10,19 +10,24 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H #include "Gnu.h" +#include "ROCm.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/TargetParser.h" + #include <map> namespace clang { namespace driver { + namespace tools { namespace amdgpu { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "ld.lld", TC) {} + Linker(const ToolChain &TC) : Tool("amdgpu::Linker", "ld.lld", TC) {} bool isLinkJob() const override { return true; } bool hasIntegratedCPP() const override { return false; } void ConstructJob(Compilation &C, const JobAction &JA, @@ -40,11 +45,9 @@ void getAMDGPUTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, namespace toolchains { class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF { - -private: +protected: const std::map<options::ID, const StringRef> OptionsDefault; -protected: Tool *buildLinker() const override; const StringRef getOptionDefault(options::ID OptID) const { auto opt = OptionsDefault.find(OptID); @@ -66,6 +69,34 @@ public: void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + + /// Return whether denormals should be flushed, and treated as 0 by default + /// for the subtarget. + static bool getDefaultDenormsAreZeroForTarget(llvm::AMDGPU::GPUKind GPUKind); + + llvm::DenormalMode getDefaultDenormalModeForType( + const llvm::opt::ArgList &DriverArgs, const JobAction &JA, + const llvm::fltSemantics *FPType = nullptr) const override; + + static bool isWave64(const llvm::opt::ArgList &DriverArgs, + llvm::AMDGPU::GPUKind Kind); + /// Needed for using lto. + bool HasNativeLLVMSupport() const override { + return true; + } + + /// Needed for translating LTO options. + const char *getDefaultLinker() const override { return "ld.lld"; } +}; + +class LLVM_LIBRARY_VISIBILITY ROCMToolChain : public AMDGPUToolChain { +public: + ROCMToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index e8a3a7b38c31..092bade53c63 100644 --- a/clang/lib/Driver/ToolChains/AVR.cpp +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -74,13 +74,11 @@ AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, // No avr-libc found and so no runtime linked. D.Diag(diag::warn_drv_avr_libc_not_found); } else { // We have enough information to link stdlibs - std::string GCCRoot = GCCInstallation.getInstallPath(); + std::string GCCRoot = std::string(GCCInstallation.getInstallPath()); std::string LibcRoot = AVRLibcRoot.getValue(); getFilePaths().push_back(LibcRoot + std::string("/lib/") + std::string(*FamilyName)); - getFilePaths().push_back(LibcRoot + std::string("/lib/") + - std::string(*FamilyName)); getFilePaths().push_back(GCCRoot + std::string("/") + std::string(*FamilyName)); @@ -144,8 +142,9 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName)); } - C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), - CmdArgs, Inputs)); + C.addCommand( + std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(Linker), CmdArgs, Inputs)); } llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const { diff --git a/clang/lib/Driver/ToolChains/AVR.h b/clang/lib/Driver/ToolChains/AVR.h index d244fc4f90e9..a3198b249580 100644 --- a/clang/lib/Driver/ToolChains/AVR.h +++ b/clang/lib/Driver/ToolChains/AVR.h @@ -40,10 +40,10 @@ private: namespace tools { namespace AVR { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: Linker(const llvm::Triple &Triple, const ToolChain &TC, bool LinkStdlib) - : GnuTool("AVR::Linker", "avr-ld", TC), Triple(Triple), + : Tool("AVR::Linker", "avr-ld", TC), Triple(Triple), LinkStdlib(LinkStdlib) {} bool hasIntegratedCPP() const override { return false; } diff --git a/clang/lib/Driver/ToolChains/Ananas.cpp b/clang/lib/Driver/ToolChains/Ananas.cpp index 2f11c9739a0e..a4141a57accc 100644 --- a/clang/lib/Driver/ToolChains/Ananas.cpp +++ b/clang/lib/Driver/ToolChains/Ananas.cpp @@ -39,7 +39,8 @@ void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -103,7 +104,7 @@ void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); - AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); } @@ -123,7 +124,8 @@ void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } // Ananas - Ananas tool chain which can call as(1) and ld(1) directly. diff --git a/clang/lib/Driver/ToolChains/Ananas.h b/clang/lib/Driver/ToolChains/Ananas.h index 5e45b47fc108..72ad3edcf056 100644 --- a/clang/lib/Driver/ToolChains/Ananas.h +++ b/clang/lib/Driver/ToolChains/Ananas.h @@ -19,10 +19,9 @@ namespace tools { /// ananas -- Directly call GNU Binutils assembler and linker namespace ananas { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: - Assembler(const ToolChain &TC) - : GnuTool("ananas::Assembler", "assembler", TC) {} + Assembler(const ToolChain &TC) : Tool("ananas::Assembler", "assembler", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -32,9 +31,9 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("ananas::Linker", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("ananas::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 9c27504dccf5..487c50dfc466 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -39,7 +39,7 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, // Handle CPU name is 'native'. if (CPU == "native") - return llvm::sys::getHostCPUName(); + return std::string(llvm::sys::getHostCPUName()); else if (CPU.size()) return CPU; @@ -54,7 +54,8 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, // Decode AArch64 features from string like +[no]featureA+[no]featureB+... static bool DecodeAArch64Features(const Driver &D, StringRef text, - std::vector<StringRef> &Features) { + std::vector<StringRef> &Features, + llvm::AArch64::ArchKind ArchKind) { SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); @@ -66,6 +67,11 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text, D.Diag(clang::diag::err_drv_no_neon_modifier); else return false; + + // +sve implies +f32mm if the base architecture is v8.6A + // it isn't the case in general that sve implies both f64mm and f32mm + if ((ArchKind == llvm::AArch64::ArchKind::ARMV8_6A) && Feature == "sve") + Features.push_back("+f32mm"); } return true; } @@ -76,6 +82,7 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, std::vector<StringRef> &Features) { std::pair<StringRef, StringRef> Split = Mcpu.split("+"); CPU = Split.first; + llvm::AArch64::ArchKind ArchKind = llvm::AArch64::ArchKind::ARMV8A; if (CPU == "native") CPU = llvm::sys::getHostCPUName(); @@ -83,7 +90,7 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, if (CPU == "generic") { Features.push_back("+neon"); } else { - llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseCPUArch(CPU); + ArchKind = llvm::AArch64::parseCPUArch(CPU); if (!llvm::AArch64::getArchFeatures(ArchKind, Features)) return false; @@ -92,10 +99,11 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, return false; } - if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)) - return false; + if (Split.second.size() && + !DecodeAArch64Features(D, Split.second, Features, ArchKind)) + return false; - return true; + return true; } static bool @@ -108,7 +116,8 @@ 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() && !DecodeAArch64Features(D, Split.second, Features))) + (Split.second.size() && + !DecodeAArch64Features(D, Split.second, Features, ArchKind))) return false; return true; @@ -139,8 +148,9 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, // Handle CPU name is 'native'. if (MtuneLowerCase == "native") - MtuneLowerCase = llvm::sys::getHostCPUName(); - if (MtuneLowerCase == "cyclone" || MtuneLowerCase.find("apple") == 0) { + MtuneLowerCase = std::string(llvm::sys::getHostCPUName()); + if (MtuneLowerCase == "cyclone" || + StringRef(MtuneLowerCase).startswith("apple")) { Features.push_back("+zcm"); Features.push_back("+zcz"); } @@ -208,6 +218,39 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args); } + // Enable/disable straight line speculation hardening. + if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) { + StringRef Scope = A->getValue(); + bool EnableRetBr = false; + bool EnableBlr = false; + if (Scope != "none" && Scope != "all") { + SmallVector<StringRef, 4> Opts; + Scope.split(Opts, ","); + for (auto Opt : Opts) { + Opt = Opt.trim(); + if (Opt == "retbr") { + EnableRetBr = true; + continue; + } + if (Opt == "blr") { + EnableBlr = true; + continue; + } + D.Diag(diag::err_invalid_sls_hardening) + << Scope << A->getAsString(Args); + break; + } + } else if (Scope == "all") { + EnableRetBr = true; + EnableBlr = true; + } + + if (EnableRetBr) + Features.push_back("+harden-sls-retbr"); + if (EnableBlr) + Features.push_back("+harden-sls-blr"); + } + // En/disable crc if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { if (A->getOption().matches(options::OPT_mcrc)) @@ -322,6 +365,10 @@ 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"}); + if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) if (A->getOption().matches(options::OPT_mno_unaligned_access)) @@ -399,6 +446,9 @@ fp16_fml_fallthrough: if (Args.hasArg(options::OPT_ffixed_x28)) Features.push_back("+reserve-x28"); + if (Args.hasArg(options::OPT_ffixed_x30)) + Features.push_back("+reserve-x30"); + if (Args.hasArg(options::OPT_fcall_saved_x8)) Features.push_back("+call-saved-x8"); diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index a1923e731489..afe896b4a65b 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -57,7 +57,7 @@ void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, static void getARMHWDivFeatures(const Driver &D, const Arg *A, const ArgList &Args, StringRef HWDiv, std::vector<StringRef> &Features) { - unsigned HWDivID = llvm::ARM::parseHWDiv(HWDiv); + uint64_t HWDivID = llvm::ARM::parseHWDiv(HWDiv); if (!llvm::ARM::getHWDivFeatures(HWDivID, Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -91,7 +91,7 @@ static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, CPU = CPU.split("+").first; if (CPU != "generic") { llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); - unsigned Extension = llvm::ARM::getDefaultExtensions(CPU, ArchKind); + uint64_t Extension = llvm::ARM::getDefaultExtensions(CPU, ArchKind); llvm::ARM::getExtensionFeatures(Extension, Features); } } @@ -137,9 +137,8 @@ bool arm::useAAPCSForMachO(const llvm::Triple &T) { } // Select mode for reading thread pointer (-mtp=soft/cp15). -arm::ReadTPMode arm::getReadTPMode(const ToolChain &TC, const ArgList &Args) { +arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { - const Driver &D = TC.getDriver(); arm::ReadTPMode ThreadPointer = llvm::StringSwitch<arm::ReadTPMode>(A->getValue()) .Case("cp15", ReadTPMode::Cp15) @@ -156,11 +155,14 @@ arm::ReadTPMode arm::getReadTPMode(const ToolChain &TC, const ArgList &Args) { return ReadTPMode::Soft; } +arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { + return arm::getARMFloatABI(TC.getDriver(), TC.getEffectiveTriple(), Args); +} + // Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. -arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { - const Driver &D = TC.getDriver(); - const llvm::Triple &Triple = TC.getEffectiveTriple(); +arm::FloatABI arm::getARMFloatABI(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) { auto SubArch = getARMSubArchVersionNumber(Triple); arm::FloatABI ABI = FloatABI::Invalid; if (Arg *A = @@ -276,18 +278,20 @@ arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { return ABI; } -void arm::getARMTargetFeatures(const ToolChain &TC, - const llvm::Triple &Triple, - const ArgList &Args, - ArgStringList &CmdArgs, - std::vector<StringRef> &Features, - bool ForAS) { - const Driver &D = TC.getDriver(); +static bool hasIntegerMVE(const std::vector<StringRef> &F) { + auto MVE = llvm::find(llvm::reverse(F), "+mve"); + auto NoMVE = llvm::find(llvm::reverse(F), "-mve"); + return MVE != F.rend() && + (NoMVE == F.rend() || std::distance(MVE, NoMVE) > 0); +} +void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, ArgStringList &CmdArgs, + std::vector<StringRef> &Features, bool ForAS) { bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); - arm::FloatABI ABI = arm::getARMFloatABI(TC, Args); - arm::ReadTPMode ThreadPointer = arm::getReadTPMode(TC, Args); + arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args); + arm::ReadTPMode ThreadPointer = arm::getReadTPMode(D, Args); const Arg *WaCPU = nullptr, *WaFPU = nullptr; const Arg *WaHDiv = nullptr, *WaArch = nullptr; @@ -459,18 +463,13 @@ fp16_fml_fallthrough: // Disable all features relating to hardware FP, not already disabled by the // above call. - Features.insert(Features.end(), {"-neon", "-crypto", "-dotprod", "-fp16fml", - "-mve", "-mve.fp", "-fpregs"}); + Features.insert(Features.end(), + {"-dotprod", "-fp16fml", "-mve", "-mve.fp", "-fpregs"}); } else if (FPUID == llvm::ARM::FK_NONE) { // -mfpu=none is *very* similar to -mfloat-abi=soft, only that it should not // disable MVE-I. - Features.insert(Features.end(), - {"-neon", "-crypto", "-dotprod", "-fp16fml", "-mve.fp"}); - // Even though we remove MVE-FP, we still need to check if it was originally - // present among the requested extensions, because it implies MVE-I, which - // should not be disabled by -mfpu-none. - if (!llvm::is_contained(Features, "+mve") && - !llvm::is_contained(Features, "+mve.fp")) + Features.insert(Features.end(), {"-dotprod", "-fp16fml", "-mve.fp"}); + if (!hasIntegerMVE(Features)) Features.emplace_back("-fpregs"); } @@ -612,14 +611,14 @@ fp16_fml_fallthrough: const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { std::string MArch; if (!Arch.empty()) - MArch = Arch; + MArch = std::string(Arch); else - MArch = Triple.getArchName(); + MArch = std::string(Triple.getArchName()); MArch = StringRef(MArch).split("+").first.lower(); // Handle -march=native. if (MArch == "native") { - std::string CPU = llvm::sys::getHostCPUName(); + std::string CPU = std::string(llvm::sys::getHostCPUName()); if (CPU != "generic") { // Translate the native cpu into the architecture suffix for that CPU. StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); @@ -657,12 +656,12 @@ std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, std::string MCPU = StringRef(CPU).split("+").first.lower(); // Handle -mcpu=native. if (MCPU == "native") - return llvm::sys::getHostCPUName(); + return std::string(llvm::sys::getHostCPUName()); else return MCPU; } - return getARMCPUForMArch(Arch, Triple); + return std::string(getARMCPUForMArch(Arch, Triple)); } /// getLLVMArchSuffixForARM - Get the LLVM ArchKind value to use for a diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.h b/clang/lib/Driver/ToolChains/Arch/ARM.h index 5640f8371262..0ba1a59852aa 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -48,13 +48,15 @@ enum class FloatABI { }; FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args); -ReadTPMode getReadTPMode(const ToolChain &TC, const llvm::opt::ArgList &Args); +FloatABI getARMFloatABI(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); +ReadTPMode getReadTPMode(const Driver &D, const llvm::opt::ArgList &Args); bool useAAPCSForMachO(const llvm::Triple &T); void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args, llvm::StringRef &Arch, llvm::StringRef &CPU, bool FromAs = false); -void getARMTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, +void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, std::vector<llvm::StringRef> &Features, bool ForAS); diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/clang/lib/Driver/ToolChains/Arch/PPC.cpp index f1baadaebf41..144e276a6bd8 100644 --- a/clang/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -26,7 +26,7 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { StringRef CPUName = A->getValue(); if (CPUName == "native") { - std::string CPU = llvm::sys::getHostCPUName(); + std::string CPU = std::string(llvm::sys::getHostCPUName()); if (!CPU.empty() && CPU != "generic") return CPU; else @@ -70,6 +70,7 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { .Case("power7", "pwr7") .Case("power8", "pwr8") .Case("power9", "pwr9") + .Case("power10", "pwr10") .Case("future", "future") .Case("pwr3", "pwr3") .Case("pwr4", "pwr4") @@ -80,6 +81,7 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { .Case("pwr7", "pwr7") .Case("pwr8", "pwr8") .Case("pwr9", "pwr9") + .Case("pwr10", "pwr10") .Case("powerpc", "ppc") .Case("powerpc64", "ppc64") .Case("powerpc64le", "ppc64le") @@ -91,14 +93,16 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { const char *ppc::getPPCAsmModeForCPU(StringRef Name) { return llvm::StringSwitch<const char *>(Name) - .Case("pwr7", "-mpower7") - .Case("power7", "-mpower7") - .Case("pwr8", "-mpower8") - .Case("power8", "-mpower8") - .Case("ppc64le", "-mpower8") - .Case("pwr9", "-mpower9") - .Case("power9", "-mpower9") - .Default("-many"); + .Case("pwr7", "-mpower7") + .Case("power7", "-mpower7") + .Case("pwr8", "-mpower8") + .Case("power8", "-mpower8") + .Case("ppc64le", "-mpower8") + .Case("pwr9", "-mpower9") + .Case("power9", "-mpower9") + .Case("pwr10", "-mpower10") + .Case("power10", "-mpower10") + .Default("-many"); } void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 8c343b8693f3..80d12e5aa8da 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -22,6 +22,14 @@ 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"; @@ -29,6 +37,8 @@ static StringRef getExtensionTypeDesc(StringRef Ext) { 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(); } @@ -39,10 +49,29 @@ static StringRef getExtensionType(StringRef Ext) { 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 == "zbb" || Ext == "zbc" || Ext == "zbe" || + Ext == "zbf" || Ext == "zbm" || Ext == "zbp" || Ext == "zbr" || + Ext == "zbs" || Ext == "zbt" || Ext == "zbproposedc") + return RISCVExtensionVersion{"0", "92"}; + if (Ext == "v") + return RISCVExtensionVersion{"0", "8"}; + 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; } @@ -52,17 +81,15 @@ static bool isSupportedExtension(StringRef Ext) { // 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, StringRef MArch, - StringRef Ext, StringRef In, +static bool getExtensionVersion(const Driver &D, const ArgList &Args, + StringRef MArch, StringRef Ext, StringRef In, std::string &Major, std::string &Minor) { - Major = In.take_while(isDigit); + Major = std::string(In.take_while(isDigit)); In = In.substr(Major.size()); - if (Major.empty()) - return true; - if (In.consume_front("p")) { - Minor = 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()) { @@ -74,7 +101,53 @@ static bool getExtensionVersion(const Driver &D, StringRef MArch, } } - // TODO: Handle extensions with version number. + // 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; @@ -89,7 +162,7 @@ static bool getExtensionVersion(const Driver &D, StringRef MArch, // Parse the ISA string containing non-standard user-level // extensions, standard supervisor-level extensions and // non-standard supervisor-level extensions. -// These extensions start with 'x', 's', 'sx' prefixes, follow a +// 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. @@ -105,7 +178,7 @@ static void getExtensionFeatures(const Driver &D, SmallVector<StringRef, 8> Split; Exts.split(Split, StringRef("_")); - SmallVector<StringRef, 3> Prefix{"x", "s", "sx"}; + SmallVector<StringRef, 4> Prefix{"z", "x", "s", "sx"}; auto I = Prefix.begin(); auto E = Prefix.end(); @@ -119,8 +192,10 @@ static void getExtensionFeatures(const Driver &D, } StringRef Type = getExtensionType(Ext); - StringRef Name(Ext.substr(Type.size())); 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) @@ -133,7 +208,7 @@ static void getExtensionFeatures(const Driver &D, ++I; if (I == E) { - std::string Error = Desc; + 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; @@ -143,35 +218,30 @@ static void getExtensionFeatures(const Driver &D, // The order is OK, do not advance I to the next prefix // to allow repeated extension type, e.g.: rv32ixabc_xdef. - if (Name.empty()) { - std::string Error = Desc; + 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 << Ext; + << MArch << Error << Type; return; } std::string Major, Minor; - auto Pos = Name.find_if(isDigit); - if (Pos != StringRef::npos) { - auto Next = Name.substr(Pos); - Name = Name.substr(0, Pos); - if (!getExtensionVersion(D, MArch, Ext, Next, Major, Minor)) - return; - } + if (!getExtensionVersion(D, Args, MArch, Name, Vers, Major, Minor)) + return; // Check if duplicated extension. - if (llvm::is_contained(AllExts, Ext)) { + if (llvm::is_contained(AllExts, Name)) { std::string Error = "duplicated "; Error += Desc; D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; + << 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(Ext); + AllExts.push_back(Name); } // Set target features. @@ -186,7 +256,10 @@ static void getExtensionFeatures(const Driver &D, << MArch << Error << Ext; return; } - Features.push_back(Args.MakeArgString("+" + Ext)); + if (isExperimentalExtension(Ext)) + Features.push_back(Args.MakeArgString("+experimental-" + Ext)); + else + Features.push_back(Args.MakeArgString("+" + Ext)); } } @@ -251,28 +324,35 @@ static bool getArchFeatures(const Driver &D, StringRef MArch, // Skip rvxxx StringRef Exts = MArch.substr(5); - // Remove non-standard extensions and supervisor-level extensions. - // They have 'x', 's', 'sx' prefixes. Parse them at the end. - // Find the very first occurrence of 's' or 'x'. + // 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("sx"); + size_t Pos = Exts.find_first_of("zsx"); if (Pos != StringRef::npos) { OtherExts = Exts.substr(Pos); Exts = Exts.substr(0, Pos); } std::string Major, Minor; - if (!getExtensionVersion(D, MArch, std::string(1, Baseline), Exts, 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 - // and consume the underscore '_' that might follow. auto StdExtsItr = StdExts.begin(); auto StdExtsEnd = StdExts.end(); - for (auto I = Exts.begin(), E = Exts.end(); I != E; ++I) { + for (auto I = Exts.begin(), E = Exts.end(); I != E; ) { char c = *I; // Check ISA extensions are specified in the canonical order. @@ -295,18 +375,15 @@ static bool getArchFeatures(const Driver &D, StringRef MArch, // Move to next char to prevent repeated letter. ++StdExtsItr; - if (std::next(I) != E) { - // Skip c. - std::string Next = std::string(std::next(I), E); - std::string Major, Minor; - if (!getExtensionVersion(D, MArch, std::string(1, c), Next, Major, Minor)) - return false; - - // TODO: Use version number when setting target features - // and consume the underscore '_' that might follow. - } + 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". @@ -331,7 +408,22 @@ static bool getArchFeatures(const Driver &D, StringRef MArch, case 'c': Features.push_back("+c"); break; + case 'b': + Features.push_back("+experimental-b"); + break; + case 'v': + Features.push_back("+experimental-v"); + 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. @@ -433,12 +525,11 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, Features.push_back("-relax"); // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is - // specified... - if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) { - // ... but we don't support -msave-restore, so issue a warning. - D.Diag(diag::warn_drv_clang_unsupported) - << Args.getLastArg(options::OPT_msave_restore)->getAsString(Args); - } + // specified. + if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) + Features.push_back("+save-restore"); + else + Features.push_back("-save-restore"); // Now add any that the user explicitly requested on the command line, // which may override the defaults. diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp index 2b77d59fdc66..f81bf68172de 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "SystemZ.h" +#include "clang/Config/config.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Host.h" @@ -16,24 +18,40 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +systemz::FloatABI systemz::getSystemZFloatABI(const Driver &D, + const ArgList &Args) { + // Hard float is the default. + systemz::FloatABI ABI = systemz::FloatABI::Hard; + if (Args.hasArg(options::OPT_mfloat_abi_EQ)) + D.Diag(diag::err_drv_unsupported_opt) + << Args.getLastArg(options::OPT_mfloat_abi_EQ)->getAsString(Args); + + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_msoft_float, + options::OPT_mhard_float)) + if (A->getOption().matches(clang::driver::options::OPT_msoft_float)) + ABI = systemz::FloatABI::Soft; + + return ABI; +} + std::string systemz::getSystemZTargetCPU(const ArgList &Args) { if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { llvm::StringRef CPUName = A->getValue(); if (CPUName == "native") { - std::string CPU = llvm::sys::getHostCPUName(); + std::string CPU = std::string(llvm::sys::getHostCPUName()); if (!CPU.empty() && CPU != "generic") return CPU; else return ""; } - return CPUName; + return std::string(CPUName); } - return "z10"; + return CLANG_SYSTEMZ_DEFAULT_ARCH; } -void systemz::getSystemZTargetFeatures(const ArgList &Args, +void systemz::getSystemZTargetFeatures(const Driver &D, const ArgList &Args, std::vector<llvm::StringRef> &Features) { // -m(no-)htm overrides use of the transactional-execution facility. if (Arg *A = Args.getLastArg(options::OPT_mhtm, options::OPT_mno_htm)) { @@ -49,4 +67,8 @@ void systemz::getSystemZTargetFeatures(const ArgList &Args, else Features.push_back("-vector"); } + + systemz::FloatABI FloatABI = systemz::getSystemZFloatABI(D, Args); + if (FloatABI == systemz::FloatABI::Soft) + Features.push_back("+soft-float"); } diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.h b/clang/lib/Driver/ToolChains/Arch/SystemZ.h index 77dcbc47be5c..1e42b68a8f3c 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.h +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H +#include "clang/Driver/Driver.h" #include "llvm/ADT/StringRef.h" #include "llvm/Option/Option.h" #include <string> @@ -19,9 +20,16 @@ namespace driver { namespace tools { namespace systemz { +enum class FloatABI { + Soft, + Hard, +}; + +FloatABI getSystemZFloatABI(const Driver &D, const llvm::opt::ArgList &Args); + std::string getSystemZTargetCPU(const llvm::opt::ArgList &Args); -void getSystemZTargetFeatures(const llvm::opt::ArgList &Args, +void getSystemZTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, std::vector<llvm::StringRef> &Features); } // end namespace systemz diff --git a/clang/lib/Driver/ToolChains/Arch/VE.cpp b/clang/lib/Driver/ToolChains/Arch/VE.cpp new file mode 100644 index 000000000000..fa10e4810f1c --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/VE.cpp @@ -0,0 +1,26 @@ +//===--- VE.cpp - Tools 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 "VE.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +const char *ve::getVEAsmModeForCPU(StringRef Name, const llvm::Triple &Triple) { + return ""; +} + +void ve::getVETargetFeatures(const Driver &D, const ArgList &Args, + std::vector<StringRef> &Features) {} diff --git a/clang/lib/Driver/ToolChains/Arch/VE.h b/clang/lib/Driver/ToolChains/Arch/VE.h new file mode 100644 index 000000000000..713e3e7d042f --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/VE.h @@ -0,0 +1,33 @@ +//===--- VE.h - VE-specific Tool Helpers ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_VE_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_VE_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace ve { + +void getVETargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features); +const char *getVEAsmModeForCPU(llvm::StringRef Name, + const llvm::Triple &Triple); + +} // end namespace ve +} // namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_VE_H diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index d1e0c8253b79..2cc44c09917f 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -31,7 +31,7 @@ const char *x86::getX86TargetCPU(const ArgList &Args, // // FIXME: We should also incorporate the detected target features for use // with -native. - std::string CPU = llvm::sys::getHostCPUName(); + std::string CPU = std::string(llvm::sys::getHostCPUName()); if (!CPU.empty() && CPU != "generic") return Args.MakeArgString(CPU); } @@ -94,6 +94,7 @@ const char *x86::getX86TargetCPU(const ArgList &Args, switch (Triple.getOS()) { case llvm::Triple::FreeBSD: + return "i686"; case llvm::Triple::NetBSD: case llvm::Triple::OpenBSD: return "i486"; @@ -146,6 +147,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, // flags). This is a bit hacky but keeps existing usages working. We should // consider deprecating this and instead warn if the user requests external // retpoline thunks and *doesn't* request some form of retpolines. + auto SpectreOpt = clang::driver::options::ID::OPT_INVALID; if (Args.hasArgNoClaim(options::OPT_mretpoline, options::OPT_mno_retpoline, options::OPT_mspeculative_load_hardening, options::OPT_mno_speculative_load_hardening)) { @@ -153,12 +155,14 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, false)) { Features.push_back("+retpoline-indirect-calls"); Features.push_back("+retpoline-indirect-branches"); + SpectreOpt = options::OPT_mretpoline; } else if (Args.hasFlag(options::OPT_mspeculative_load_hardening, options::OPT_mno_speculative_load_hardening, false)) { // On x86, speculative load hardening relies on at least using retpolines // for indirect calls. Features.push_back("+retpoline-indirect-calls"); + SpectreOpt = options::OPT_mspeculative_load_hardening; } } else if (Args.hasFlag(options::OPT_mretpoline_external_thunk, options::OPT_mno_retpoline_external_thunk, false)) { @@ -166,6 +170,44 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, // eventually switch to an error here. Features.push_back("+retpoline-indirect-calls"); Features.push_back("+retpoline-indirect-branches"); + SpectreOpt = options::OPT_mretpoline_external_thunk; + } + + auto LVIOpt = clang::driver::options::ID::OPT_INVALID; + if (Args.hasFlag(options::OPT_mlvi_hardening, options::OPT_mno_lvi_hardening, + false)) { + Features.push_back("+lvi-load-hardening"); + Features.push_back("+lvi-cfi"); // load hardening implies CFI protection + LVIOpt = options::OPT_mlvi_hardening; + } else if (Args.hasFlag(options::OPT_mlvi_cfi, options::OPT_mno_lvi_cfi, + false)) { + Features.push_back("+lvi-cfi"); + LVIOpt = options::OPT_mlvi_cfi; + } + + if (Args.hasFlag(options::OPT_m_seses, options::OPT_mno_seses, false)) { + if (LVIOpt == options::OPT_mlvi_hardening) + D.Diag(diag::err_drv_argument_not_allowed_with) + << D.getOpts().getOptionName(options::OPT_mlvi_hardening) + << D.getOpts().getOptionName(options::OPT_m_seses); + + if (SpectreOpt != clang::driver::options::ID::OPT_INVALID) + D.Diag(diag::err_drv_argument_not_allowed_with) + << D.getOpts().getOptionName(SpectreOpt) + << D.getOpts().getOptionName(options::OPT_m_seses); + + Features.push_back("+seses"); + if (!Args.hasArg(options::OPT_mno_lvi_cfi)) { + Features.push_back("+lvi-cfi"); + LVIOpt = options::OPT_mlvi_cfi; + } + } + + if (SpectreOpt != clang::driver::options::ID::OPT_INVALID && + LVIOpt != clang::driver::options::ID::OPT_INVALID) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << D.getOpts().getOptionName(SpectreOpt) + << D.getOpts().getOptionName(LVIOpt); } // Now add any that the user explicitly requested on the command line, diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp index dff0e04183ef..97cfa7d0e156 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -67,7 +67,7 @@ Tool *BareMetal::buildLinker() const { std::string BareMetal::getRuntimesDir() const { SmallString<128> Dir(getDriver().ResourceDir); llvm::sys::path::append(Dir, "lib", "baremetal"); - return Dir.str(); + return std::string(Dir.str()); } void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -157,7 +157,7 @@ void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, void BareMetal::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back(Args.MakeArgString("-lclang_rt.builtins-" + - getTriple().getArchName() + ".a")); + getTriple().getArchName())); } void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -191,7 +191,7 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>(JA, *this, - Args.MakeArgString(TC.GetLinkerPath()), - CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Args.MakeArgString(TC.GetLinkerPath()), + CmdArgs, Inputs)); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 9b3055413e9e..9d6333bb5f1d 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Clang.h" +#include "AMDGPU.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" #include "Arch/Mips.h" @@ -14,12 +15,12 @@ #include "Arch/RISCV.h" #include "Arch/Sparc.h" #include "Arch/SystemZ.h" +#include "Arch/VE.h" #include "Arch/X86.h" -#include "AMDGPU.h" #include "CommonArgs.h" #include "Hexagon.h" -#include "MSP430.h" #include "InputInfo.h" +#include "MSP430.h" #include "PS4CPU.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/CodeGenOptions.h" @@ -35,6 +36,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -307,10 +309,9 @@ static void getWebAssemblyTargetFeatures(const ArgList &Args, handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); } -static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, +static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, - bool ForAS) { - const Driver &D = TC.getDriver(); + bool ForAS, bool IsAux = false) { std::vector<StringRef> Features; switch (Triple.getArch()) { default: @@ -326,7 +327,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS); + arm::getARMTargetFeatures(D, Triple, Args, CmdArgs, Features, ForAS); break; case llvm::Triple::ppc: @@ -339,7 +340,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, riscv::getRISCVTargetFeatures(D, Triple, Args, Features); break; case llvm::Triple::systemz: - systemz::getSystemZTargetFeatures(Args, Features); + systemz::getSystemZTargetFeatures(D, Args, Features); break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: @@ -368,27 +369,14 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, break; case llvm::Triple::msp430: msp430::getMSP430TargetFeatures(D, Args, Features); + break; + case llvm::Triple::ve: + ve::getVETargetFeatures(D, Args, Features); } - // Find the last of each feature. - llvm::StringMap<unsigned> LastOpt; - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - StringRef Name = Features[I]; - assert(Name[0] == '-' || Name[0] == '+'); - LastOpt[Name.drop_front(1)] = I; - } - - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - // If this feature was overridden, ignore it. - StringRef Name = Features[I]; - llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1)); - assert(LastI != LastOpt.end()); - unsigned Last = LastI->second; - if (Last != I) - continue; - - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back(Name.data()); + for (auto Feature : unifyTargetFeatures(Features)) { + CmdArgs.push_back(IsAux ? "-aux-target-feature" : "-target-feature"); + CmdArgs.push_back(Feature.data()); } } @@ -464,6 +452,11 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, } } + // OPT_fignore_exceptions means exception could still be thrown, + // but no clean up or catch would happen in current module. + // So we do not set EH to false. + Args.AddLastArg(CmdArgs, options::OPT_fignore_exceptions); + if (EH) CmdArgs.push_back("-fexceptions"); } @@ -505,7 +498,7 @@ static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) { return codegenoptions::DebugLineTablesOnly; if (A.getOption().matches(options::OPT_gline_directives_only)) return codegenoptions::DebugDirectivesOnly; - return codegenoptions::LimitedDebugInfo; + return codegenoptions::DebugInfoConstructor; } static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { @@ -522,7 +515,7 @@ static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { static bool useFramePointerForTargetByDefault(const ArgList &Args, const llvm::Triple &Triple) { - if (Args.hasArg(options::OPT_pg)) + if (Args.hasArg(options::OPT_pg) && !Args.hasArg(options::OPT_mfentry)) return true; switch (Triple.getArch()) { @@ -553,6 +546,13 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, Triple.isOSHurd()) { switch (Triple.getArch()) { // Don't use a frame pointer on linux if optimizing for certain targets. + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + if (Triple.isAndroid()) + return true; + LLVM_FALLTHROUGH; case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::mips: @@ -721,38 +721,6 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input, } } -static void appendUserToPath(SmallVectorImpl<char> &Result) { -#ifdef LLVM_ON_UNIX - const char *Username = getenv("LOGNAME"); -#else - const char *Username = getenv("USERNAME"); -#endif - if (Username) { - // Validate that LoginName can be used in a path, and get its length. - size_t Len = 0; - for (const char *P = Username; *P; ++P, ++Len) { - if (!clang::isAlphanumeric(*P) && *P != '_') { - Username = nullptr; - break; - } - } - - if (Username && Len > 0) { - Result.append(Username, Username + Len); - return; - } - } - -// Fallback to user id. -#ifdef LLVM_ON_UNIX - std::string UID = llvm::utostr(getuid()); -#else - // FIXME: Windows seems to have an 'SID' that might work. - std::string UID = "9999"; -#endif - Result.append(UID.begin(), UID.end()); -} - static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, const Driver &D, const InputInfo &Output, const ArgList &Args, @@ -808,8 +776,8 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, CmdArgs.push_back("-fprofile-instrument=clang"); if (TC.getTriple().isWindowsMSVCEnvironment()) { // Add dependent lib for clang_rt.profile - CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + - TC.getCompilerRT(Args, "profile"))); + CmdArgs.push_back(Args.MakeArgString( + "--dependent-lib=" + TC.getCompilerRTBasename(Args, "profile"))); } } @@ -826,8 +794,9 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, } if (PGOGenArg) { if (TC.getTriple().isWindowsMSVCEnvironment()) { - CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + - TC.getCompilerRT(Args, "profile"))); + // Add dependent lib for clang_rt.profile + CmdArgs.push_back(Args.MakeArgString( + "--dependent-lib=" + TC.getCompilerRTBasename(Args, "profile"))); } if (PGOGenArg->getOption().matches( PGOGenerateArg ? options::OPT_fprofile_generate_EQ @@ -856,11 +825,10 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, } } - bool EmitCovNotes = Args.hasArg(options::OPT_ftest_coverage) || + bool EmitCovNotes = Args.hasFlag(options::OPT_ftest_coverage, + options::OPT_fno_test_coverage, false) || Args.hasArg(options::OPT_coverage); - bool EmitCovData = Args.hasFlag(options::OPT_fprofile_arcs, - options::OPT_fno_profile_arcs, false) || - Args.hasArg(options::OPT_coverage); + bool EmitCovData = TC.needsGCovInstrumentation(Args); if (EmitCovNotes) CmdArgs.push_back("-femit-coverage-notes"); if (EmitCovData) @@ -1190,12 +1158,14 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_MP); Args.AddLastArg(CmdArgs, options::OPT_MV); - // Add offload include arguments specific for CUDA. This must happen before - // we -I or -include anything else, because we must pick up the CUDA headers - // from the particular CUDA installation, rather than from e.g. - // /usr/local/include. + // Add offload include arguments specific for CUDA/HIP. This must happen + // before we -I or -include anything else, because we must pick up the + // CUDA/HIP headers from the particular CUDA/ROCm installation, rather than + // from e.g. /usr/local/include. if (JA.isOffloading(Action::OFK_Cuda)) getToolChain().AddCudaIncludeArgs(Args, CmdArgs); + if (JA.isOffloading(Action::OFK_HIP)) + getToolChain().AddHIPIncludeArgs(Args, CmdArgs); // If we are offloading to a target via OpenMP we need to include the // openmp_wrappers folder which contains alternative system headers. @@ -1212,7 +1182,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, } CmdArgs.push_back("-include"); - CmdArgs.push_back("__clang_openmp_math_declares.h"); + CmdArgs.push_back("__clang_openmp_device_functions.h"); } // Add -i* options, and automatically translate to @@ -1227,6 +1197,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, if (YcArg && JA.getKind() >= Action::PrecompileJobClass && JA.getKind() <= Action::AssembleJobClass) { CmdArgs.push_back(Args.MakeArgString("-building-pch-with-obj")); + CmdArgs.push_back(Args.MakeArgString("-fpch-instantiate-templates")); } if (YcArg || YuArg) { StringRef ThroughHeader = YcArg ? YcArg->getValue() : YuArg->getValue(); @@ -1404,20 +1375,6 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { } } -static bool isNoCommonDefault(const llvm::Triple &Triple) { - switch (Triple.getArch()) { - default: - if (Triple.isOSFuchsia()) - return true; - return false; - - case llvm::Triple::xcore: - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - return true; - } -} - static bool hasMultipleInvocations(const llvm::Triple &Triple, const ArgList &Args) { // Supported only on Darwin where we invoke the compiler multiple times @@ -1594,7 +1551,7 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, const ToolChain &TC = getToolChain(); // Add the target features - getTargetFeatures(TC, EffectiveTriple, Args, CmdArgs, false); + getTargetFeatures(TC.getDriver(), EffectiveTriple, Args, CmdArgs, false); // Add target specific flags. switch (TC.getArch()) { @@ -1662,6 +1619,10 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, case llvm::Triple::wasm64: AddWebAssemblyTargetArgs(Args, CmdArgs); break; + + case llvm::Triple::ve: + AddVETargetArgs(Args, CmdArgs); + break; } } @@ -1970,6 +1931,36 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, } } +static void SetRISCVSmallDataLimit(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + const Driver &D = TC.getDriver(); + const llvm::Triple &Triple = TC.getTriple(); + // Default small data limitation is eight. + const char *SmallDataLimit = "8"; + // Get small data limitation. + if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, + options::OPT_fPIC)) { + // Not support linker relaxation for PIC. + SmallDataLimit = "0"; + if (Args.hasArg(options::OPT_G)) { + D.Diag(diag::warn_drv_unsupported_sdata); + } + } else if (Args.getLastArgValue(options::OPT_mcmodel_EQ) + .equals_lower("large") && + (Triple.getArch() == llvm::Triple::riscv64)) { + // Not support linker relaxation for RV64 with large code model. + SmallDataLimit = "0"; + if (Args.hasArg(options::OPT_G)) { + D.Diag(diag::warn_drv_unsupported_sdata); + } + } else if (Arg *A = Args.getLastArg(options::OPT_G)) { + SmallDataLimit = A->getValue(); + } + // Forward the -msmall-data-limit= option. + CmdArgs.push_back("-msmall-data-limit"); + CmdArgs.push_back(SmallDataLimit); +} + void Clang::AddRISCVTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const llvm::Triple &Triple = getToolChain().getTriple(); @@ -1977,6 +1968,8 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args, CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName.data()); + + SetRISCVSmallDataLimit(getToolChain(), Args, CmdArgs); } void Clang::AddSparcTargetArgs(const ArgList &Args, @@ -2003,70 +1996,30 @@ void Clang::AddSystemZTargetArgs(const ArgList &Args, options::OPT_mno_backchain, false); bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack, options::OPT_mno_packed_stack, false); - if (HasBackchain && HasPackedStack) { + systemz::FloatABI FloatABI = + systemz::getSystemZFloatABI(getToolChain().getDriver(), Args); + bool HasSoftFloat = (FloatABI == systemz::FloatABI::Soft); + if (HasBackchain && HasPackedStack && !HasSoftFloat) { const Driver &D = getToolChain().getDriver(); D.Diag(diag::err_drv_unsupported_opt) - << Args.getLastArg(options::OPT_mpacked_stack)->getAsString(Args) + - " " + Args.getLastArg(options::OPT_mbackchain)->getAsString(Args); + << "-mpacked-stack -mbackchain -mhard-float"; } if (HasBackchain) CmdArgs.push_back("-mbackchain"); if (HasPackedStack) CmdArgs.push_back("-mpacked-stack"); -} - -static void addX86AlignBranchArgs(const Driver &D, const ArgList &Args, - ArgStringList &CmdArgs) { - if (Args.hasArg(options::OPT_mbranches_within_32B_boundaries)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-x86-branches-within-32B-boundaries"); - } - if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_boundary_EQ)) { - StringRef Value = A->getValue(); - unsigned Boundary; - if (Value.getAsInteger(10, Boundary) || Boundary < 16 || - !llvm::isPowerOf2_64(Boundary)) { - D.Diag(diag::err_drv_invalid_argument_to_option) - << Value << A->getOption().getName(); - } else { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back( - Args.MakeArgString("-x86-align-branch-boundary=" + Twine(Boundary))); - } - } - if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_EQ)) { - std::string AlignBranch; - for (StringRef T : A->getValues()) { - if (T != "fused" && T != "jcc" && T != "jmp" && T != "call" && - T != "ret" && T != "indirect") - D.Diag(diag::err_drv_invalid_malign_branch_EQ) - << T << "fused, jcc, jmp, call, ret, indirect"; - if (!AlignBranch.empty()) - AlignBranch += '+'; - AlignBranch += T; - } - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-x86-align-branch=" + AlignBranch)); - } - if (const Arg *A = - Args.getLastArg(options::OPT_malign_branch_prefix_size_EQ)) { - StringRef Value = A->getValue(); - unsigned PrefixSize; - if (Value.getAsInteger(10, PrefixSize) || PrefixSize > 5) { - D.Diag(diag::err_drv_invalid_argument_to_option) - << Value << A->getOption().getName(); - } else { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-x86-align-branch-prefix-size=" + - Twine(PrefixSize))); - } + if (HasSoftFloat) { + // Floating point operations and argument passing are soft. + CmdArgs.push_back("-msoft-float"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); } } void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); - addX86AlignBranchArgs(D, Args, CmdArgs); + addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/false); if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || Args.hasArg(options::OPT_mkernel) || @@ -2167,6 +2120,12 @@ void Clang::AddWebAssemblyTargetArgs(const ArgList &Args, } } +void Clang::AddVETargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + // Floating point operations and argument passing are hard. + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("hard"); +} + void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, StringRef Target, const InputInfo &Output, const InputInfo &Input, const ArgList &Args) const { @@ -2421,7 +2380,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, CmdArgs.push_back(Value.data()); } else { RenderDebugEnablingArgs(Args, CmdArgs, - codegenoptions::LimitedDebugInfo, + codegenoptions::DebugInfoConstructor, DwarfVersion, llvm::DebuggerKind::Default); } } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || @@ -2480,7 +2439,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, bool OFastEnabled, const ArgList &Args, - ArgStringList &CmdArgs) { + ArgStringList &CmdArgs, + const JobAction &JA) { // Handle various floating point optimization flags, mapping them to the // appropriate LLVM code generation flags. This is complicated by several // "umbrella" flags, so we do this by stepping through the flags incrementally @@ -2502,10 +2462,17 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, StringRef FPModel = ""; // -ffp-exception-behavior options: strict, maytrap, ignore StringRef FPExceptionBehavior = ""; - StringRef DenormalFPMath = ""; + const llvm::DenormalMode DefaultDenormalFPMath = + TC.getDefaultDenormalModeForType(Args, JA); + const llvm::DenormalMode DefaultDenormalFP32Math = + TC.getDefaultDenormalModeForType(Args, JA, &llvm::APFloat::IEEEsingle()); + + llvm::DenormalMode DenormalFPMath = DefaultDenormalFPMath; + llvm::DenormalMode DenormalFP32Math = DefaultDenormalFP32Math; StringRef FPContract = ""; 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()); @@ -2527,8 +2494,13 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ReciprocalMath = false; SignedZeros = true; // -fno_fast_math restores default denormal and fpcontract handling - DenormalFPMath = ""; FPContract = ""; + DenormalFPMath = llvm::DenormalMode::getIEEE(); + + // FIXME: The target may have picked a non-IEEE default mode here based on + // -cl-denorms-are-zero. Should the target consider -fp-model interaction? + DenormalFP32Math = llvm::DenormalMode::getIEEE(); + StringRef Val = A->getValue(); if (OFastEnabled && !Val.equals("fast")) { // Only -ffp-model=fast is compatible with OFast, ignore. @@ -2562,6 +2534,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, optID = options::OPT_frounding_math; FPExceptionBehavior = "strict"; FPModel = Val; + FPContract = "off"; TrappingMath = true; } else D.Diag(diag::err_drv_unsupported_option_argument) @@ -2621,7 +2594,19 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, break; case options::OPT_fdenormal_fp_math_EQ: - DenormalFPMath = A->getValue(); + DenormalFPMath = llvm::parseDenormalFPAttribute(A->getValue()); + if (!DenormalFPMath.isValid()) { + D.Diag(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + } + break; + + case options::OPT_fdenormal_fp_math_f32_EQ: + DenormalFP32Math = llvm::parseDenormalFPAttribute(A->getValue()); + if (!DenormalFP32Math.isValid()) { + D.Diag(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + } break; // Validate and pass through -ffp-contract option. @@ -2690,8 +2675,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, SignedZeros = true; TrappingMath = true; FPExceptionBehavior = "strict"; - // -fno_unsafe_math_optimizations restores default denormal handling - DenormalFPMath = ""; + + // The target may have opted to flush by default, so force IEEE. + DenormalFPMath = llvm::DenormalMode::getIEEE(); + DenormalFP32Math = llvm::DenormalMode::getIEEE(); break; case options::OPT_Ofast: @@ -2724,7 +2711,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, TrappingMath = false; RoundingFPMath = false; // -fno_fast_math restores default denormal and fpcontract handling - DenormalFPMath = ""; + DenormalFPMath = DefaultDenormalFPMath; + DenormalFP32Math = llvm::DenormalMode::getIEEE(); FPContract = ""; break; } @@ -2734,7 +2722,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (HonorINFs && HonorNaNs && !AssociativeMath && !ReciprocalMath && SignedZeros && TrappingMath && RoundingFPMath && - DenormalFPMath.empty() && FPContract.empty()) + (FPContract.equals("off") || FPContract.empty()) && + DenormalFPMath == llvm::DenormalMode::getIEEE() && + DenormalFP32Math == llvm::DenormalMode::getIEEE()) // OK: Current Arg doesn't conflict with -ffp-model=strict ; else { @@ -2780,9 +2770,21 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, } else if (TrappingMathPresent) CmdArgs.push_back("-fno-trapping-math"); - if (!DenormalFPMath.empty()) - CmdArgs.push_back( - Args.MakeArgString("-fdenormal-fp-math=" + DenormalFPMath)); + // The default is IEEE. + if (DenormalFPMath != llvm::DenormalMode::getIEEE()) { + llvm::SmallString<64> DenormFlag; + llvm::raw_svector_ostream ArgStr(DenormFlag); + ArgStr << "-fdenormal-fp-math=" << DenormalFPMath; + CmdArgs.push_back(Args.MakeArgString(ArgStr.str())); + } + + // Add f32 specific denormal mode flag if it's different. + if (DenormalFP32Math != DenormalFPMath) { + llvm::SmallString<64> DenormFlag; + llvm::raw_svector_ostream ArgStr(DenormFlag); + ArgStr << "-fdenormal-fp-math-f32=" << DenormalFP32Math; + CmdArgs.push_back(Args.MakeArgString(ArgStr.str())); + } if (!FPContract.empty()) CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); @@ -2957,6 +2959,22 @@ static void RenderSSPOptions(const ToolChain &TC, const ArgList &Args, } } +static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple(); + + if (!EffectiveTriple.isOSLinux()) + return; + + if (!EffectiveTriple.isX86() && !EffectiveTriple.isSystemZ() && + !EffectiveTriple.isPPC64()) + return; + + if (Args.hasFlag(options::OPT_fstack_clash_protection, + options::OPT_fnostack_clash_protection, false)) + CmdArgs.push_back("-fstack-clash-protection"); +} + static void RenderTrivialAutoVarInitOptions(const Driver &D, const ToolChain &TC, const ArgList &Args, @@ -2999,9 +3017,26 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D, CmdArgs.push_back( Args.MakeArgString("-ftrivial-auto-var-init=" + TrivialAutoVarInit)); } + + if (Arg *A = + Args.getLastArg(options::OPT_ftrivial_auto_var_init_stop_after)) { + if (!Args.hasArg(options::OPT_ftrivial_auto_var_init) || + StringRef( + Args.getLastArg(options::OPT_ftrivial_auto_var_init)->getValue()) == + "uninitialized") + D.Diag(diag::err_drv_trivial_auto_var_init_stop_after_missing_dependency); + A->claim(); + StringRef Val = A->getValue(); + if (std::stoi(Val.str()) <= 0) + D.Diag(diag::err_drv_trivial_auto_var_init_stop_after_invalid_value); + CmdArgs.push_back( + Args.MakeArgString("-ftrivial-auto-var-init-stop-after=" + Val)); + } } static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) { + // cl-denorms-are-zero is not forwarded. It is translated into a generic flag + // for denormal flushing handling based on the target. const unsigned ForwardedArguments[] = { options::OPT_cl_opt_disable, options::OPT_cl_strict_aliasing, @@ -3012,7 +3047,6 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) { options::OPT_cl_fast_relaxed_math, options::OPT_cl_mad_enable, options::OPT_cl_no_signed_zeros, - options::OPT_cl_denorms_are_zero, options::OPT_cl_fp32_correctly_rounded_divide_sqrt, options::OPT_cl_uniform_work_group_size }; @@ -3136,11 +3170,13 @@ static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, CmdArgs.push_back("-fno-math-builtin"); } -void Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) { - llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Result); - llvm::sys::path::append(Result, "org.llvm.clang."); - appendUserToPath(Result); - llvm::sys::path::append(Result, "ModuleCache"); +bool Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) { + if (llvm::sys::path::cache_directory(Result)) { + llvm::sys::path::append(Result, "clang"); + llvm::sys::path::append(Result, "ModuleCache"); + return true; + } + return false; } static void RenderModulesOptions(Compilation &C, const Driver &D, @@ -3197,6 +3233,7 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) Path = A->getValue(); + bool HasPath = true; if (C.isForDiagnostics()) { // When generating crash reports, we want to emit the modules along with // the reproduction sources, so we ignore any provided module path. @@ -3205,12 +3242,16 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, llvm::sys::path::append(Path, "modules"); } else if (Path.empty()) { // No module path was provided: use the default. - Driver::getDefaultModuleCachePath(Path); + HasPath = Driver::getDefaultModuleCachePath(Path); } - const char Arg[] = "-fmodules-cache-path="; - Path.insert(Path.begin(), Arg, Arg + strlen(Arg)); - CmdArgs.push_back(Args.MakeArgString(Path)); + // `HasPath` will only be false if getDefaultModuleCachePath() fails. + // That being said, that failure is unlikely and not caching is harmless. + if (HasPath) { + const char Arg[] = "-fmodules-cache-path="; + Path.insert(Path.begin(), Arg, Arg + strlen(Arg)); + CmdArgs.push_back(Args.MakeArgString(Path)); + } } if (HaveModules) { @@ -3469,9 +3510,9 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, CmdArgs.push_back("-fno-diagnostics-fixit-info"); // Enable -fdiagnostics-show-option by default. - if (Args.hasFlag(options::OPT_fdiagnostics_show_option, - options::OPT_fno_diagnostics_show_option)) - CmdArgs.push_back("-fdiagnostics-show-option"); + if (!Args.hasFlag(options::OPT_fdiagnostics_show_option, + options::OPT_fno_diagnostics_show_option, true)) + CmdArgs.push_back("-fno-diagnostics-show-option"); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { @@ -3574,8 +3615,7 @@ static DwarfFissionKind getDebugFissionKind(const Driver &D, static void RenderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, const ArgList &Args, - bool EmitCodeView, bool IsWindowsMSVC, - ArgStringList &CmdArgs, + bool EmitCodeView, ArgStringList &CmdArgs, codegenoptions::DebugInfoKind &DebugInfoKind, DwarfFissionKind &DwarfFission) { if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, @@ -3613,7 +3653,7 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, if (const Arg *A = Args.getLastArg(options::OPT_g_Group, options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ)) { - DebugInfoKind = codegenoptions::LimitedDebugInfo; + DebugInfoKind = codegenoptions::DebugInfoConstructor; // If the last option explicitly specified a debug-info level, use it. if (checkDebugInfoOption(A, Args, D, TC) && @@ -3708,10 +3748,9 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, // not to include any column info. if (const Arg *A = Args.getLastArg(options::OPT_gcolumn_info)) (void)checkDebugInfoOption(A, Args, D, TC); - if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, - /*Default=*/!EmitCodeView && - DebuggerTuning != llvm::DebuggerKind::SCE)) - CmdArgs.push_back("-dwarf-column-info"); + if (!Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, + !EmitCodeView && DebuggerTuning != llvm::DebuggerKind::SCE)) + CmdArgs.push_back("-gno-column-info"); // FIXME: Move backend command line options to the module. // If -gline-tables-only or -gline-directives-only is the last option it wins. @@ -3719,7 +3758,7 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, if (checkDebugInfoOption(A, Args, D, TC)) { if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && DebugInfoKind != codegenoptions::DebugDirectivesOnly) { - DebugInfoKind = codegenoptions::LimitedDebugInfo; + DebugInfoKind = codegenoptions::DebugInfoConstructor; CmdArgs.push_back("-dwarf-ext-refs"); CmdArgs.push_back("-fmodule-format=obj"); } @@ -3739,7 +3778,9 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, TC.GetDefaultStandaloneDebug()); if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug)) (void)checkDebugInfoOption(A, Args, D, TC); - if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug) + if ((DebugInfoKind == codegenoptions::LimitedDebugInfo || + DebugInfoKind == codegenoptions::DebugInfoConstructor) && + NeedFullDebug) DebugInfoKind = codegenoptions::FullDebugInfo; if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source, @@ -3912,7 +3953,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } - const llvm::Triple *AuxTriple = IsCuda ? TC.getAuxTriple() : nullptr; + const llvm::Triple *AuxTriple = + (IsCuda || IsHIP) ? TC.getAuxTriple() : nullptr; bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment(); bool IsIAMCU = RawTriple.isOSIAMCU(); @@ -3977,6 +4019,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); } + if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) { + CmdArgs.push_back("-fsycl"); + CmdArgs.push_back("-fsycl-is-device"); + + if (Arg *A = Args.getLastArg(options::OPT_sycl_std_EQ)) { + A->render(Args, CmdArgs); + } else { + // Ensure the default version in SYCL mode is 1.2.1 (aka 2017) + CmdArgs.push_back("-sycl-std=2017"); + } + } + if (IsOpenMPDevice) { // We have to pass the triple of the host if compiling for an OpenMP device. std::string NormalizedTriple = @@ -3990,9 +4044,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb)) { unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; - unsigned Version; - Triple.getArchName().substr(Offset).getAsInteger(10, Version); - if (Version < 7) + unsigned Version = 0; + bool Failure = + Triple.getArchName().substr(Offset).consumeInteger(10, Version); + if (Failure || Version < 7) D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() << TripleStr; } @@ -4083,7 +4138,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef ArgStr = Args.hasArg(options::OPT_interface_stub_version_EQ) ? Args.getLastArgValue(options::OPT_interface_stub_version_EQ) - : "experimental-ifs-v1"; + : "experimental-ifs-v2"; CmdArgs.push_back("-emit-interface-stubs"); CmdArgs.push_back( Args.MakeArgString(Twine("-interface-stub-version=") + ArgStr.str())); @@ -4153,8 +4208,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_function_sections, options::OPT_fdata_sections, options::OPT_fno_data_sections, + options::OPT_fbasic_block_sections_EQ, + options::OPT_funique_internal_linkage_names, + options::OPT_fno_unique_internal_linkage_names, options::OPT_funique_section_names, options::OPT_fno_unique_section_names, + options::OPT_funique_basic_block_section_names, + options::OPT_fno_unique_basic_block_section_names, options::OPT_mrestrict_it, options::OPT_mno_restrict_it, options::OPT_mstackrealign, @@ -4195,7 +4255,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mdisable-tail-calls"); RenderFloatingPointOptions(TC, D, isOptimizationLevelFast(Args), Args, - CmdArgs); + CmdArgs, JA); // Render ABI arguments switch (TC.getArch()) { @@ -4240,8 +4300,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, II.getInputArg().renderAsInput(Args, CmdArgs); } - C.addCommand(std::make_unique<Command>(JA, *this, D.getClangProgramPath(), - CmdArgs, Inputs)); + C.addCommand( + std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileUTF8(), + D.getClangProgramPath(), CmdArgs, Inputs)); return; } @@ -4266,8 +4327,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Discard value names in assert builds unless otherwise specified. if (Args.hasFlag(options::OPT_fdiscard_value_names, - options::OPT_fno_discard_value_names, !IsAssertBuild)) + 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()); + }))) { + D.Diag(diag::warn_ignoring_fdiscard_for_bitcode); + } CmdArgs.push_back("-discard-value-names"); + } // Set the main file name, so that debug info works even with // -save-temps. @@ -4321,14 +4390,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, bool IsPIE; std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(TC, Args); - const char *RMName = RelocationModelName(RelocationModel); + bool IsROPI = RelocationModel == llvm::Reloc::ROPI || + RelocationModel == llvm::Reloc::ROPI_RWPI; + bool IsRWPI = RelocationModel == llvm::Reloc::RWPI || + RelocationModel == llvm::Reloc::ROPI_RWPI; - if ((RelocationModel == llvm::Reloc::ROPI || - RelocationModel == llvm::Reloc::ROPI_RWPI) && - types::isCXX(Input.getType()) && + if (Args.hasArg(options::OPT_mcmse) && + !Args.hasArg(options::OPT_fallow_unsupported)) { + if (IsROPI) + D.Diag(diag::err_cmse_pi_are_incompatible) << IsROPI; + if (IsRWPI) + D.Diag(diag::err_cmse_pi_are_incompatible) << !IsRWPI; + } + + if (IsROPI && types::isCXX(Input.getType()) && !Args.hasArg(options::OPT_fallow_unsupported)) D.Diag(diag::err_drv_ropi_incompatible_with_cxx); + const char *RMName = RelocationModelName(RelocationModel); if (RMName) { CmdArgs.push_back("-mrelocation-model"); CmdArgs.push_back(RMName); @@ -4352,15 +4431,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } - CmdArgs.push_back("-mthread-model"); - if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) { - if (!TC.isThreadModelSupported(A->getValue())) - D.Diag(diag::err_drv_invalid_thread_model_for_target) - << A->getValue() << A->getAsString(Args); - CmdArgs.push_back(A->getValue()); + // The default is -fno-semantic-interposition. We render it just because we + // require explicit -fno-semantic-interposition to infer dso_local. + if (Arg *A = Args.getLastArg(options::OPT_fsemantic_interposition, + options::OPT_fno_semantic_interposition)) + if (RelocationModel != llvm::Reloc::Static && !IsPIE) + A->render(Args, CmdArgs); + + { + std::string Model; + if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) { + if (!TC.isThreadModelSupported(A->getValue())) + D.Diag(diag::err_drv_invalid_thread_model_for_target) + << A->getValue() << A->getAsString(Args); + Model = A->getValue(); + } else + Model = TC.getThreadModel(); + if (Model != "posix") { + CmdArgs.push_back("-mthread-model"); + CmdArgs.push_back(Args.MakeArgString(Model)); + } } - else - CmdArgs.push_back(Args.MakeArgString(TC.getThreadModel())); Args.AddLastArg(CmdArgs, options::OPT_fveclib); @@ -4413,6 +4504,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Arg *A = Args.getLastArg(options::OPT_maix_struct_return, + options::OPT_msvr4_struct_return)) { + if (TC.getArch() != llvm::Triple::ppc) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << RawTriple.str(); + } else if (A->getOption().matches(options::OPT_maix_struct_return)) { + CmdArgs.push_back("-maix-struct-return"); + } else { + assert(A->getOption().matches(options::OPT_msvr4_struct_return)); + CmdArgs.push_back("-msvr4-struct-return"); + } + } + if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return, options::OPT_freg_struct_return)) { if (TC.getArch() != llvm::Triple::x86) { @@ -4429,6 +4533,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) CmdArgs.push_back("-fdefault-calling-conv=stdcall"); + if (Args.hasArg(options::OPT_fenable_matrix)) { + // enable-matrix is needed by both the LangOpts and by LLVM. + CmdArgs.push_back("-fenable-matrix"); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-matrix"); + } + CodeGenOptions::FramePointerKind FPKeepKind = getFramePointerKind(Args, RawTriple); const char *FPKeepKindStr = nullptr; @@ -4447,8 +4558,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(FPKeepKindStr); if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, - options::OPT_fno_zero_initialized_in_bss)) - CmdArgs.push_back("-mno-zero-initialized-in-bss"); + options::OPT_fno_zero_initialized_in_bss, true)) + CmdArgs.push_back("-fno-zero-initialized-in-bss"); bool OFastEnabled = isOptimizationLevelFast(Args); // If -Ofast is the optimization level, then -fstrict-aliasing should be @@ -4495,7 +4606,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fsplit_stack)) CmdArgs.push_back("-split-stacks"); - RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs); + RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs, JA); + + if (Arg *A = Args.getLastArg(options::OPT_mdouble_EQ)) { + if (TC.getArch() == llvm::Triple::avr) + A->render(Args, CmdArgs); + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) { if (TC.getTriple().isX86()) @@ -4511,9 +4630,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Decide whether to use verbose asm. Verbose assembly is the default on // toolchains which have the integrated assembler on by default. bool IsIntegratedAssemblerDefault = TC.IsIntegratedAssemblerDefault(); - if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, - IsIntegratedAssemblerDefault)) - CmdArgs.push_back("-masm-verbose"); + if (!Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, + IsIntegratedAssemblerDefault)) + CmdArgs.push_back("-fno-verbose-asm"); if (!TC.useIntegratedAs()) CmdArgs.push_back("-no-integrated-as"); @@ -4529,8 +4648,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Enable -mconstructor-aliases except on darwin, where we have to work around // a linker bug (see <rdar://problem/7651567>), and CUDA device code, where - // aliases aren't supported. - if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX()) + // aliases aren't supported. Similarly, aliases aren't yet supported for AIX. + if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX() && !RawTriple.isOSAIX()) CmdArgs.push_back("-mconstructor-aliases"); // Darwin's kernel doesn't support guard variables; just die if we @@ -4539,7 +4658,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fforbid-guard-variables"); if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields, - false)) { + Triple.isWindowsGNUEnvironment())) { CmdArgs.push_back("-mms-bitfields"); } @@ -4575,14 +4694,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, AsynchronousUnwindTables)) CmdArgs.push_back("-munwind-tables"); + // Prepare `-aux-target-cpu` and `-aux-target-feature` unless + // `--gpu-use-aux-triple-only` is specified. + if (!Args.getLastArg(options::OPT_gpu_use_aux_triple_only) && + ((IsCuda && JA.isDeviceOffloading(Action::OFK_Cuda)) || + (IsHIP && JA.isDeviceOffloading(Action::OFK_HIP)))) { + const ArgList &HostArgs = + C.getArgsForToolChain(nullptr, StringRef(), Action::OFK_None); + std::string HostCPU = + getCPUName(HostArgs, *TC.getAuxTriple(), /*FromAs*/ false); + if (!HostCPU.empty()) { + CmdArgs.push_back("-aux-target-cpu"); + CmdArgs.push_back(Args.MakeArgString(HostCPU)); + } + getTargetFeatures(D, *TC.getAuxTriple(), HostArgs, CmdArgs, + /*ForAS*/ false, /*IsAux*/ true); + } + TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind()); // FIXME: Handle -mtune=. (void)Args.hasArg(options::OPT_mtune_EQ); if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { - CmdArgs.push_back("-mcode-model"); - CmdArgs.push_back(A->getValue()); + StringRef CM = A->getValue(); + if (CM == "small" || CM == "kernel" || CM == "medium" || CM == "large" || + CM == "tiny") + A->render(Args, CmdArgs); + else + D.Diag(diag::err_drv_invalid_argument_to_option) + << CM << A->getOption().getName(); } if (Arg *A = Args.getLastArg(options::OPT_mtls_size_EQ)) { @@ -4617,8 +4758,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); DwarfFissionKind DwarfFission; - RenderDebugOptions(TC, D, RawTriple, Args, EmitCodeView, IsWindowsMSVC, - CmdArgs, DebugInfoKind, DwarfFission); + RenderDebugOptions(TC, D, RawTriple, Args, EmitCodeView, CmdArgs, + DebugInfoKind, DwarfFission); // Add the split debug info name to the command lines here so we // can propagate it to the backend. @@ -4664,11 +4805,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddAllArgs(CmdArgs, options::OPT_v); - Args.AddLastArg(CmdArgs, options::OPT_H); + + if (Args.getLastArg(options::OPT_H)) { + CmdArgs.push_back("-H"); + CmdArgs.push_back("-sys-header-deps"); + } + if (D.CCPrintHeaders && !D.CCGenDiagnostics) { CmdArgs.push_back("-header-include-file"); CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename : "-"); + CmdArgs.push_back("-sys-header-deps"); } Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); @@ -4679,6 +4826,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, : "-"); } + // Give the gen diagnostics more chances to succeed, by avoiding intentional + // crashes. + if (D.CCGenDiagnostics) + CmdArgs.push_back("-disable-pragma-debug-crash"); + bool UseSeparateSections = isUseSeparateSections(Triple); if (Args.hasFlag(options::OPT_ffunction_sections, @@ -4686,6 +4838,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-ffunction-sections"); } + if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_sections_EQ)) { + StringRef Val = A->getValue(); + if (Val != "all" && Val != "labels" && Val != "none" && + !(Val.startswith("list=") && llvm::sys::fs::exists(Val.substr(5)))) + D.Diag(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + else + A->render(Args, CmdArgs); + } + if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, UseSeparateSections)) { CmdArgs.push_back("-fdata-sections"); @@ -4695,14 +4857,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_unique_section_names, true)) CmdArgs.push_back("-fno-unique-section-names"); + if (Args.hasFlag(options::OPT_funique_internal_linkage_names, + options::OPT_fno_unique_internal_linkage_names, false)) + CmdArgs.push_back("-funique-internal-linkage-names"); + + if (Args.hasFlag(options::OPT_funique_basic_block_section_names, + options::OPT_fno_unique_basic_block_section_names, false)) + CmdArgs.push_back("-funique-basic-block-section-names"); + Args.AddLastArg(CmdArgs, options::OPT_finstrument_functions, options::OPT_finstrument_functions_after_inlining, options::OPT_finstrument_function_entry_bare); - // NVPTX doesn't support PGO or coverage. There's no runtime support for - // sampling, overhead of call arc collection is way too high and there's no - // way to collect the output. - if (!Triple.isNVPTX()) + // NVPTX/AMDGCN doesn't support PGO or coverage. There's no runtime support + // 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); Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ); @@ -4821,6 +4991,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs, options::OPT_fno_trigraphs); + + // HIP headers has minimum C++ standard requirements. Therefore set the + // default language standard. + if (IsHIP) + CmdArgs.push_back(IsWindowsMSVC ? "-std=c++14" : "-std=c++11"); } // GCC's behavior for -Wwrite-strings is a bit strange: @@ -4964,15 +5139,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Pass -fmessage-length=. - CmdArgs.push_back("-fmessage-length"); + unsigned MessageLength = 0; if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { - CmdArgs.push_back(A->getValue()); + StringRef V(A->getValue()); + if (V.getAsInteger(0, MessageLength)) + D.Diag(diag::err_drv_invalid_argument_to_option) + << V << A->getOption().getName(); } else { // If -fmessage-length=N was not specified, determine whether this is a // terminal and, if so, implicitly define -fmessage-length appropriately. - unsigned N = llvm::sys::Process::StandardErrColumns(); - CmdArgs.push_back(Args.MakeArgString(Twine(N))); + MessageLength = llvm::sys::Process::StandardErrColumns(); } + if (MessageLength != 0) + CmdArgs.push_back( + Args.MakeArgString("-fmessage-length=" + Twine(MessageLength))); // -fvisibility= and -fvisibility-ms-compat are of a piece. if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ, @@ -5001,7 +5181,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); Args.AddLastArg(CmdArgs, options::OPT_femulated_tls, options::OPT_fno_emulated_tls); - Args.AddLastArg(CmdArgs, options::OPT_fkeep_static_consts); // AltiVec-like language extensions aren't relevant for assembling. if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) @@ -5047,6 +5226,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_openmp_cuda_mode, /*Default=*/false)) CmdArgs.push_back("-fopenmp-cuda-mode"); + // When in OpenMP offloading mode with NVPTX target, forward + // cuda-parallel-target-regions flag + if (Args.hasFlag(options::OPT_fopenmp_cuda_parallel_target_regions, + options::OPT_fno_openmp_cuda_parallel_target_regions, + /*Default=*/true)) + CmdArgs.push_back("-fopenmp-cuda-parallel-target-regions"); + // When in OpenMP offloading mode with NVPTX target, check if full runtime // is required. if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime, @@ -5077,20 +5263,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) { StringRef S0 = A->getValue(), S = S0; - unsigned Size, Start = 0; + unsigned Size, Offset = 0; if (!Triple.isAArch64() && Triple.getArch() != llvm::Triple::x86 && Triple.getArch() != llvm::Triple::x86_64) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; else if (S.consumeInteger(10, Size) || (!S.empty() && (!S.consume_front(",") || - S.consumeInteger(10, Start) || !S.empty()))) + S.consumeInteger(10, Offset) || !S.empty()))) D.Diag(diag::err_drv_invalid_argument_to_option) << S0 << A->getOption().getName(); - else if (Start) + else if (Size < Offset) D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument); - else + else { CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size))); + CmdArgs.push_back(Args.MakeArgString( + "-fpatchable-function-entry-offset=" + Twine(Offset))); + } } if (TC.SupportsProfiling()) { @@ -5164,11 +5353,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_pthread); - if (Args.hasFlag(options::OPT_mspeculative_load_hardening, options::OPT_mno_speculative_load_hardening, - false)) + if (Args.hasFlag(options::OPT_mspeculative_load_hardening, + options::OPT_mno_speculative_load_hardening, false)) CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening")); RenderSSPOptions(TC, Args, CmdArgs, KernelOrKext); + RenderSCPOptions(TC, Args, CmdArgs); RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs); // Translate -mstackrealign @@ -5214,8 +5404,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward -cl options to -cc1 RenderOpenCLOptions(Args, CmdArgs); - if (Args.hasFlag(options::OPT_fhip_new_launch_api, - options::OPT_fno_hip_new_launch_api, false)) + if (IsHIP && Args.hasFlag(options::OPT_fhip_new_launch_api, + options::OPT_fno_hip_new_launch_api, true)) CmdArgs.push_back("-fhip-new-launch-api"); if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) { @@ -5299,7 +5489,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fuse-cxa-atexit is default. if (!Args.hasFlag( options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, - !RawTriple.isOSWindows() && + !RawTriple.isOSAIX() && !RawTriple.isOSWindows() && TC.getArch() != llvm::Triple::xcore && ((RawTriple.getVendor() != llvm::Triple::MipsTechnologies) || RawTriple.hasEnvironment())) || @@ -5311,16 +5501,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RawTriple.isOSDarwin() && !KernelOrKext)) CmdArgs.push_back("-fregister-global-dtors-with-atexit"); - // -fms-extensions=0 is default. - if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, - IsWindowsMSVC)) - CmdArgs.push_back("-fms-extensions"); - // -fno-use-line-directives is default. if (Args.hasFlag(options::OPT_fuse_line_directives, options::OPT_fno_use_line_directives, false)) CmdArgs.push_back("-fuse-line-directives"); + // -fms-extensions=0 is default. + if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, + IsWindowsMSVC)) + CmdArgs.push_back("-fms-extensions"); + // -fms-compatibility=0 is default. bool IsMSVCCompat = Args.hasFlag( options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility, @@ -5434,11 +5624,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fpch_validate_input_files_content, options::OPT_fno_pch_validate_input_files_content, false)) CmdArgs.push_back("-fvalidate-ast-input-files-content"); + if (Args.hasFlag(options::OPT_fpch_instantiate_templates, + options::OPT_fno_pch_instantiate_templates, false)) + CmdArgs.push_back("-fpch-instantiate-templates"); Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager, options::OPT_fno_experimental_new_pass_manager); - ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); + ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, Inputs, CmdArgs, rewriteKind); RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None, Input, CmdArgs); @@ -5558,11 +5751,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_Qy, options::OPT_Qn, true)) CmdArgs.push_back("-Qn"); - // -fcommon is the default unless compiling kernel code or the target says so - bool NoCommonDefault = KernelOrKext || isNoCommonDefault(RawTriple); - if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, - !NoCommonDefault)) - CmdArgs.push_back("-fno-common"); + // -fno-common is the default, set -fcommon only when that flag is set. + if (Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, false)) + CmdArgs.push_back("-fcommon"); // -fsigned-bitfields is default, and clang doesn't yet support // -funsigned-bitfields. @@ -5680,6 +5871,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_dM); Args.AddLastArg(CmdArgs, options::OPT_dD); + Args.AddLastArg(CmdArgs, options::OPT_fmax_tokens_EQ); + // Handle serialized diagnostics. if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) { CmdArgs.push_back("-serialize-diagnostic-file"); @@ -5749,7 +5942,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of // pristine IR generated by the frontend. Ideally, a new compile action should // be added so both IR can be captured. - if (C.getDriver().isSaveTempsEnabled() && + if ((C.getDriver().isSaveTempsEnabled() || + JA.isHostOffloading(Action::OFK_OpenMP)) && !(C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO()) && isa<CompileJobAction>(JA)) CmdArgs.push_back("-disable-llvm-passes"); @@ -5779,7 +5973,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Arg->render(Args, OriginalArgs); SmallString<256> Flags; - Flags += Exec; + EscapeSpacesAndBackslashes(Exec, Flags); for (const char *OriginalArg : OriginalArgs) { SmallString<128> EscapedArg; EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); @@ -5891,10 +6085,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (SplitLTOUnit) CmdArgs.push_back("-fsplit-lto-unit"); - if (Arg *A = Args.getLastArg(options::OPT_fexperimental_isel, - options::OPT_fno_experimental_isel)) { + if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel, + options::OPT_fno_global_isel)) { CmdArgs.push_back("-mllvm"); - if (A->getOption().matches(options::OPT_fexperimental_isel)) { + if (A->getOption().matches(options::OPT_fglobal_isel)) { CmdArgs.push_back("-global-isel=1"); // GISel is on by default on AArch64 -O0, so don't bother adding @@ -5913,9 +6107,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-global-isel-abort=2"); if (!IsArchSupported) - D.Diag(diag::warn_drv_experimental_isel_incomplete) << Triple.getArchName(); + D.Diag(diag::warn_drv_global_isel_incomplete) << Triple.getArchName(); else - D.Diag(diag::warn_drv_experimental_isel_incomplete_opt); + D.Diag(diag::warn_drv_global_isel_incomplete_opt); } } else { CmdArgs.push_back("-global-isel=0"); @@ -5939,6 +6133,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fforce-enable-int128"); } + if (Args.hasFlag(options::OPT_fkeep_static_consts, + options::OPT_fno_keep_static_consts, false)) + CmdArgs.push_back("-fkeep-static-consts"); + if (Args.hasFlag(options::OPT_fcomplete_member_pointers, options::OPT_fno_complete_member_pointers, false)) CmdArgs.push_back("-fcomplete-member-pointers"); @@ -5950,11 +6148,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_moutline, options::OPT_mno_outline)) { if (A->getOption().matches(options::OPT_moutline)) { - // We only support -moutline in AArch64 right now. If we're not compiling - // for AArch64, emit a warning and ignore the flag. Otherwise, add the - // proper mllvm flags. - if (Triple.getArch() != llvm::Triple::aarch64 && - Triple.getArch() != llvm::Triple::aarch64_32) { + // We only support -moutline in AArch64 and ARM targets right now. If + // we're not compiling for these, emit a warning and ignore the flag. + // Otherwise, add the proper mllvm flags. + if (!(Triple.isARM() || Triple.isThumb() || + Triple.getArch() == llvm::Triple::aarch64 || + Triple.getArch() == llvm::Triple::aarch64_32)) { D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName(); } else { CmdArgs.push_back("-mllvm"); @@ -6026,30 +6225,33 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, auto CLCommand = getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput); C.addCommand(std::make_unique<FallbackCommand>( - JA, *this, Exec, CmdArgs, Inputs, std::move(CLCommand))); + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, + std::move(CLCommand))); } else if (Args.hasArg(options::OPT__SLASH_fallback) && isa<PrecompileJobAction>(JA)) { // In /fallback builds, run the main compilation even if the pch generation // fails, so that the main compilation's fallback to cl.exe runs. - C.addCommand(std::make_unique<ForceSuccessCommand>(JA, *this, Exec, - CmdArgs, Inputs)); + C.addCommand(std::make_unique<ForceSuccessCommand>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); } else if (D.CC1Main && !D.CCGenDiagnostics) { // Invoke the CC1 directly in this process - C.addCommand( - std::make_unique<CC1Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<CC1Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); } else { - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); } // Make the compile command echo its inputs for /showFilenames. if (Output.getType() == types::TY_Object && Args.hasFlag(options::OPT__SLASH_showFilenames, options::OPT__SLASH_showFilenames_, false)) { - C.getJobs().getJobs().back()->setPrintInputFilenames(true); + C.getJobs().getJobs().back()->PrintInputFilenames = true; } if (Arg *A = Args.getLastArg(options::OPT_pg)) - if (FPKeepKind == CodeGenOptions::FramePointerKind::None) + if (FPKeepKind == CodeGenOptions::FramePointerKind::None && + !Args.hasArg(options::OPT_mfentry)) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" << A->getAsString(Args); @@ -6072,7 +6274,7 @@ Clang::Clang(const ToolChain &TC) // CAUTION! The first constructor argument ("clang") is not arbitrary, // as it is for other tools. Some operations on a Tool actually test // whether that tool is Clang based on the Tool's Name as a string. - : Tool("clang", "clang frontend", TC, RF_Full) {} + : Tool("clang", "clang frontend", TC) {} Clang::~Clang() {} @@ -6080,6 +6282,7 @@ Clang::~Clang() {} /// /// Returns true if the runtime is non-fragile. ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, + const InputInfoList &inputs, ArgStringList &cmdArgs, RewriteKind rewriteKind) const { // Look for the controlling runtime option. @@ -6203,8 +6406,11 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple()); } - cmdArgs.push_back( - args.MakeArgString("-fobjc-runtime=" + runtime.getAsString())); + if (llvm::any_of(inputs, [](const InputInfo &input) { + return types::isObjC(input.getType()); + })) + cmdArgs.push_back( + args.MakeArgString("-fobjc-runtime=" + runtime.getAsString())); return runtime; } @@ -6274,6 +6480,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, codegenoptions::DebugInfoKind *DebugInfoKind, bool *EmitCodeView) const { unsigned RTOptionID = options::OPT__SLASH_MT; + bool isNVPTX = getToolChain().getTriple().isNVPTX(); if (Args.hasArg(options::OPT__SLASH_LDd)) // The /LDd option implies /MTd. The dependent lib part can be overridden, @@ -6326,7 +6533,13 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("--dependent-lib=oldnames"); } - Args.AddLastArg(CmdArgs, options::OPT_show_includes); + if (Arg *ShowIncludes = + Args.getLastArg(options::OPT__SLASH_showIncludes, + options::OPT__SLASH_showIncludes_user)) { + CmdArgs.push_back("--show-includes"); + if (ShowIncludes->getOption().matches(options::OPT__SLASH_showIncludes)) + CmdArgs.push_back("-sys-header-deps"); + } // This controls whether or not we emit RTTI data for polymorphic types. if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, @@ -6335,8 +6548,8 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, // This controls whether or not we emit stack-protector instrumentation. // In MSVC, Buffer Security Check (/GS) is on by default. - if (Args.hasFlag(options::OPT__SLASH_GS, options::OPT__SLASH_GS_, - /*Default=*/true)) { + if (!isNVPTX && Args.hasFlag(options::OPT__SLASH_GS, options::OPT__SLASH_GS_, + /*Default=*/true)) { CmdArgs.push_back("-stack-protector"); CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong))); } @@ -6347,7 +6560,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, options::OPT_gline_tables_only)) { *EmitCodeView = true; if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7)) - *DebugInfoKind = codegenoptions::LimitedDebugInfo; + *DebugInfoKind = codegenoptions::DebugInfoConstructor; else *DebugInfoKind = codegenoptions::DebugLineTablesOnly; } else { @@ -6356,7 +6569,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, const Driver &D = getToolChain().getDriver(); EHFlags EH = parseClangCLEHFlags(D, Args); - if (EH.Synch || EH.Asynch) { + if (!isNVPTX && (EH.Synch || EH.Asynch)) { if (types::isCXX(InputType)) CmdArgs.push_back("-fcxx-exceptions"); CmdArgs.push_back("-fexceptions"); @@ -6425,7 +6638,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, options::OPT__SLASH_Gregcall)) { unsigned DCCOptId = CCArg->getOption().getID(); const char *DCCFlag = nullptr; - bool ArchSupported = true; + bool ArchSupported = !isNVPTX; llvm::Triple::ArchType Arch = getToolChain().getArch(); switch (DCCOptId) { case options::OPT__SLASH_Gd: @@ -6531,7 +6744,8 @@ void ClangAs::AddMIPSTargetArgs(const ArgList &Args, void ClangAs::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - addX86AlignBranchArgs(getToolChain().getDriver(), Args, CmdArgs); + addX86AlignBranchArgs(getToolChain().getDriver(), Args, CmdArgs, + /*IsLTO=*/false); if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { StringRef Value = A->getValue(); @@ -6601,7 +6815,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, } // Add the target features - getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, true); + getTargetFeatures(D, Triple, Args, CmdArgs, true); // Ignore explicit -force_cpusubtype_ALL option. (void)Args.hasArg(options::OPT_force__cpusubtype__ALL); @@ -6643,7 +6857,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // the guard for source type, however there is a test which asserts // that some assembler invocation receives no -debug-info-kind, // and it's not clear whether that test is just overly restrictive. - DebugInfoKind = (WantDebug ? codegenoptions::LimitedDebugInfo + DebugInfoKind = (WantDebug ? codegenoptions::DebugInfoConstructor : codegenoptions::NoDebugInfo); // Add the -fdebug-compilation-dir flag if needed. addDebugCompDirArg(Args, CmdArgs, C.getDriver().getVFS()); @@ -6686,7 +6900,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, SmallString<256> Flags; const char *Exec = getToolChain().getDriver().getClangProgramPath(); - Flags += Exec; + EscapeSpacesAndBackslashes(Exec, Flags); for (const char *OriginalArg : OriginalArgs) { SmallString<128> EscapedArg; EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); @@ -6763,7 +6977,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Input.getFilename()); const char *Exec = getToolChain().getDriver().getClangProgramPath(); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); } // Begin OffloadBundler @@ -6847,7 +7062,7 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, // All the inputs are encoded as commands. C.addCommand(std::make_unique<Command>( - JA, *this, + JA, *this, ResponseFileSupport::None(), TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), CmdArgs, None)); } @@ -6913,7 +7128,7 @@ void OffloadBundler::ConstructJobMultipleOutputs( // All the inputs are encoded as commands. C.addCommand(std::make_unique<Command>( - JA, *this, + JA, *this, ResponseFileSupport::None(), TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), CmdArgs, None)); } @@ -6943,7 +7158,7 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA, } C.addCommand(std::make_unique<Command>( - JA, *this, + JA, *this, ResponseFileSupport::None(), Args.MakeArgString(getToolChain().GetProgramPath(getShortName())), CmdArgs, Inputs)); } diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index b345c02489d4..a607e3c27de9 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -73,10 +73,13 @@ private: llvm::opt::ArgStringList &CmdArgs) const; void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + void AddVETargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args, + const InputInfoList &inputs, llvm::opt::ArgStringList &cmdArgs, RewriteKind rewrite) const; @@ -118,7 +121,7 @@ public: class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { public: ClangAs(const ToolChain &TC) - : Tool("clang::as", "clang integrated assembler", TC, RF_Full) {} + : Tool("clang::as", "clang integrated assembler", TC) {} void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; void AddX86TargetArgs(const llvm::opt::ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/CloudABI.cpp b/clang/lib/Driver/ToolChains/CloudABI.cpp index cf1d0d551e57..8dcfd4951bbf 100644 --- a/clang/lib/Driver/ToolChains/CloudABI.cpp +++ b/clang/lib/Driver/ToolChains/CloudABI.cpp @@ -75,7 +75,7 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); - AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); } @@ -92,7 +92,8 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } // CloudABI - CloudABI tool chain which can call ld(1) directly. @@ -102,7 +103,7 @@ CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple, : Generic_ELF(D, Triple, Args) { SmallString<128> P(getDriver().Dir); llvm::sys::path::append(P, "..", getTriple().str(), "lib"); - getFilePaths().push_back(P.str()); + getFilePaths().push_back(std::string(P.str())); } void CloudABI::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, diff --git a/clang/lib/Driver/ToolChains/CloudABI.h b/clang/lib/Driver/ToolChains/CloudABI.h index cc381c2b1e1f..98bf23127706 100644 --- a/clang/lib/Driver/ToolChains/CloudABI.h +++ b/clang/lib/Driver/ToolChains/CloudABI.h @@ -19,9 +19,9 @@ namespace tools { /// cloudabi -- Directly call GNU Binutils linker namespace cloudabi { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("cloudabi::Linker", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("cloudabi::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 37ec73468570..1cac5a0822a4 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -12,6 +12,7 @@ #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/SystemZ.h" +#include "Arch/VE.h" #include "Arch/X86.h" #include "HIP.h" #include "Hexagon.h" @@ -50,6 +51,7 @@ #include "llvm/Support/Program.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/YAMLParser.h" @@ -82,6 +84,31 @@ void tools::handleTargetFeaturesGroup(const ArgList &Args, } } +std::vector<StringRef> +tools::unifyTargetFeatures(const std::vector<StringRef> &Features) { + std::vector<StringRef> UnifiedFeatures; + // Find the last of each feature. + llvm::StringMap<unsigned> LastOpt; + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + StringRef Name = Features[I]; + assert(Name[0] == '-' || Name[0] == '+'); + LastOpt[Name.drop_front(1)] = I; + } + + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + // If this feature was overridden, ignore it. + StringRef Name = Features[I]; + llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1)); + assert(LastI != LastOpt.end()); + unsigned Last = LastI->second; + if (Last != I) + continue; + + UnifiedFeatures.push_back(Name); + } + return UnifiedFeatures; +} + void tools::addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs, const char *ArgName, const char *EnvVar) { const char *DirList = ::getenv(EnvVar); @@ -91,7 +118,7 @@ void tools::addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs, return; // Nothing to do. StringRef Name(ArgName); - if (Name.equals("-I") || Name.equals("-L")) + if (Name.equals("-I") || Name.equals("-L") || Name.empty()) CombinedArg = true; StringRef Dirs(DirList); @@ -151,14 +178,12 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); for (const auto &II : Inputs) { - // If the current tool chain refers to an OpenMP or HIP offloading host, we - // should ignore inputs that refer to OpenMP or HIP offloading devices - + // If the current tool chain refers to an OpenMP offloading host, we + // should ignore inputs that refer to OpenMP offloading devices - // they will be embedded according to a proper linker script. if (auto *IA = II.getAction()) if ((JA.isHostOffloading(Action::OFK_OpenMP) && - IA->isDeviceOffloading(Action::OFK_OpenMP)) || - (JA.isHostOffloading(Action::OFK_HIP) && - IA->isDeviceOffloading(Action::OFK_HIP))) + IA->isDeviceOffloading(Action::OFK_OpenMP))) continue; if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) @@ -278,7 +303,7 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, T, CPUName, ABIName); - return CPUName; + return std::string(CPUName); } case llvm::Triple::nvptx: @@ -293,15 +318,19 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, std::string TargetCPUName = ppc::getPPCTargetCPU(Args); // LLVM may default to generating code for the native CPU, // but, like gcc, we default to a more generic option for - // each architecture. (except on Darwin) - if (TargetCPUName.empty() && !T.isOSDarwin()) { - if (T.getArch() == llvm::Triple::ppc64) - TargetCPUName = "ppc64"; - else if (T.getArch() == llvm::Triple::ppc64le) - TargetCPUName = "ppc64le"; - else - TargetCPUName = "ppc"; - } + // each architecture. (except on AIX) + if (!TargetCPUName.empty()) + return TargetCPUName; + + if (T.isOSAIX()) + TargetCPUName = "pwr4"; + else if (T.getArch() == llvm::Triple::ppc64le) + TargetCPUName = "ppc64le"; + else if (T.getArch() == llvm::Triple::ppc64) + TargetCPUName = "ppc64"; + else + TargetCPUName = "ppc"; + return TargetCPUName; } @@ -334,18 +363,18 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, case llvm::Triple::wasm32: case llvm::Triple::wasm64: - return getWebAssemblyTargetCPU(Args); + return std::string(getWebAssemblyTargetCPU(Args)); } } -unsigned tools::getLTOParallelism(const ArgList &Args, const Driver &D) { - unsigned Parallelism = 0; +llvm::StringRef tools::getLTOParallelism(const ArgList &Args, const Driver &D) { Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ); - if (LtoJobsArg && - StringRef(LtoJobsArg->getValue()).getAsInteger(10, Parallelism)) - D.Diag(diag::err_drv_invalid_int_value) << LtoJobsArg->getAsString(Args) - << LtoJobsArg->getValue(); - return Parallelism; + if (!LtoJobsArg) + return {}; + if (!llvm::get_threadpool_strategy(LtoJobsArg->getValue())) + D.Diag(diag::err_drv_invalid_int_value) + << LtoJobsArg->getAsString(Args) << LtoJobsArg->getValue(); + return LtoJobsArg->getValue(); } // CloudABI uses -ffunction-sections and -fdata-sections by default. @@ -353,28 +382,32 @@ bool tools::isUseSeparateSections(const llvm::Triple &Triple) { return Triple.getOS() == llvm::Triple::CloudABI; } -void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, +void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO) { - // Tell the linker to load the plugin. This has to come before AddLinkerInputs - // as gold requires -plugin to come before any -plugin-opt that -Wl might - // forward. - CmdArgs.push_back("-plugin"); + const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath()); + const Driver &D = ToolChain.getDriver(); + if (llvm::sys::path::filename(Linker) != "ld.lld" && + llvm::sys::path::stem(Linker) != "ld.lld") { + // Tell the linker to load the plugin. This has to come before + // AddLinkerInputs as gold requires -plugin to come before any -plugin-opt + // that -Wl might forward. + CmdArgs.push_back("-plugin"); #if defined(_WIN32) - const char *Suffix = ".dll"; + const char *Suffix = ".dll"; #elif defined(__APPLE__) - const char *Suffix = ".dylib"; + const char *Suffix = ".dylib"; #else - const char *Suffix = ".so"; + const char *Suffix = ".so"; #endif - SmallString<1024> Plugin; - llvm::sys::path::native(Twine(ToolChain.getDriver().Dir) + - "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + - Suffix, - Plugin); - CmdArgs.push_back(Args.MakeArgString(Plugin)); + SmallString<1024> Plugin; + llvm::sys::path::native( + Twine(D.Dir) + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + Suffix, + Plugin); + CmdArgs.push_back(Args.MakeArgString(Plugin)); + } // Try to pass driver level flags relevant to LTO code generation down to // the plugin. @@ -385,13 +418,19 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + // The optimization level matches + // CompilerInvocation.cpp:getOptimizationLevel(). StringRef OOpt; if (A->getOption().matches(options::OPT_O4) || A->getOption().matches(options::OPT_Ofast)) OOpt = "3"; - else if (A->getOption().matches(options::OPT_O)) + else if (A->getOption().matches(options::OPT_O)) { OOpt = A->getValue(); - else if (A->getOption().matches(options::OPT_O0)) + if (OOpt == "g") + OOpt = "1"; + else if (OOpt == "s" || OOpt == "z") + OOpt = "2"; + } else if (A->getOption().matches(options::OPT_O0)) OOpt = "0"; if (!OOpt.empty()) CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt)); @@ -406,7 +445,8 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, if (IsThinLTO) CmdArgs.push_back("-plugin-opt=thinlto"); - if (unsigned Parallelism = getLTOParallelism(Args, ToolChain.getDriver())) + StringRef Parallelism = getLTOParallelism(Args, D); + if (!Parallelism.empty()) CmdArgs.push_back( Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism))); @@ -437,7 +477,7 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, if (Arg *A = getLastProfileSampleUseArg(Args)) { StringRef FName = A->getValue(); if (!llvm::sys::fs::exists(FName)) - ToolChain.getDriver().Diag(diag::err_drv_no_such_file) << FName; + D.Diag(diag::err_drv_no_such_file) << FName; else CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); @@ -480,17 +520,21 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, } // Setup statistics file output. - SmallString<128> StatsFile = - getStatsFileName(Args, Output, Input, ToolChain.getDriver()); + SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); if (!StatsFile.empty()) CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile)); + + addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true); } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { + // Enable -frtlib-add-rpath by default for the case of VE. + const bool IsVE = TC.getTriple().isVE(); + bool DefaultValue = IsVE; if (!Args.hasFlag(options::OPT_frtlib_add_rpath, - options::OPT_fno_rtlib_add_rpath, false)) + options::OPT_fno_rtlib_add_rpath, DefaultValue)) return; std::string CandidateRPath = TC.getArchSpecificLibPath(); @@ -583,6 +627,11 @@ static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { + // Fuchsia never needs these. Any sanitizer runtimes with system + // dependencies use the `.deplibs` feature instead. + if (TC.getTriple().isOSFuchsia()) + return; + // Force linking against the system libraries sanitizers depends on // (see PR15823 why this is necessary). CmdArgs.push_back("--no-as-needed"); @@ -642,17 +691,21 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("stats_client"); // Collect static runtimes. - if (Args.hasArg(options::OPT_shared) || SanArgs.needsSharedRt()) { - // Don't link static runtimes into DSOs or if -shared-libasan. + if (Args.hasArg(options::OPT_shared)) { + // Don't link static runtimes into DSOs. return; } - if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { + + // Each static runtime that has a DSO counterpart above is excluded below, + // but runtimes that exist only as static are not affected by needsSharedRt. + + if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { StaticRuntimes.push_back("asan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("asan_cxx"); } - if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) { StaticRuntimes.push_back("hwasan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("hwasan_cxx"); @@ -671,7 +724,7 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("tsan_cxx"); } - if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { if (SanArgs.requiresMinimalRuntime()) { StaticRuntimes.push_back("ubsan_minimal"); } else { @@ -684,18 +737,20 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, NonWholeStaticRuntimes.push_back("safestack"); RequiredSymbols.push_back("__safestack_init"); } - if (SanArgs.needsCfiRt() && SanArgs.linkRuntimes()) - StaticRuntimes.push_back("cfi"); - if (SanArgs.needsCfiDiagRt() && SanArgs.linkRuntimes()) { - StaticRuntimes.push_back("cfi_diag"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("ubsan_standalone_cxx"); + if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes())) { + if (SanArgs.needsCfiRt() && SanArgs.linkRuntimes()) + StaticRuntimes.push_back("cfi"); + if (SanArgs.needsCfiDiagRt() && SanArgs.linkRuntimes()) { + StaticRuntimes.push_back("cfi_diag"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("ubsan_standalone_cxx"); + } } if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) { NonWholeStaticRuntimes.push_back("stats"); RequiredSymbols.push_back("__sanitizer_stats_register"); } - if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) { + if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) { if (SanArgs.requiresMinimalRuntime()) { StaticRuntimes.push_back("scudo_minimal"); if (SanArgs.linkCXXRuntimes()) @@ -751,7 +806,7 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("--export-dynamic"); if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) - CmdArgs.push_back("-export-dynamic-symbol=__cfi_check"); + CmdArgs.push_back("--export-dynamic-symbol=__cfi_check"); return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty(); } @@ -834,10 +889,12 @@ void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename()); // First extract the dwo sections. - C.addCommand(std::make_unique<Command>(JA, T, Exec, ExtractArgs, II)); + C.addCommand(std::make_unique<Command>( + JA, T, ResponseFileSupport::AtFileCurCP(), Exec, ExtractArgs, II)); // Then remove them from the original .o file. - C.addCommand(std::make_unique<Command>(JA, T, Exec, StripArgs, II)); + C.addCommand(std::make_unique<Command>( + JA, T, ResponseFileSupport::AtFileCurCP(), Exec, StripArgs, II)); } // Claim options we don't want to warn if they are unused. We do this for @@ -1211,7 +1268,14 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, case ToolChain::UNW_CompilerRT: if (LGT == LibGccType::StaticLibGcc) CmdArgs.push_back("-l:libunwind.a"); - else + else if (TC.getTriple().isOSCygMing()) { + if (LGT == LibGccType::SharedLibGcc) + CmdArgs.push_back("-l:libunwind.dll.a"); + else + // Let the linker choose between libunwind.dll.a and libunwind.a + // depending on what's available, and depending on the -static flag + CmdArgs.push_back("-lunwind"); + } else CmdArgs.push_back("-l:libunwind.so"); break; } @@ -1263,114 +1327,6 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, } } -/// Add HIP linker script arguments at the end of the argument list so that -/// the fat binary is built by embedding the device images into the host. The -/// linker script also defines a symbol required by the code generation so that -/// the image can be retrieved at runtime. This should be used only in tool -/// chains that support linker scripts. -void tools::AddHIPLinkerScript(const ToolChain &TC, Compilation &C, - const InputInfo &Output, - const InputInfoList &Inputs, const ArgList &Args, - ArgStringList &CmdArgs, const JobAction &JA, - const Tool &T) { - - // If this is not a HIP host toolchain, we don't need to do anything. - if (!JA.isHostOffloading(Action::OFK_HIP)) - return; - - InputInfoList DeviceInputs; - for (const auto &II : Inputs) { - const Action *A = II.getAction(); - // Is this a device linking action? - if (A && isa<LinkJobAction>(A) && A->isDeviceOffloading(Action::OFK_HIP)) { - DeviceInputs.push_back(II); - } - } - - if (DeviceInputs.empty()) - return; - - // Create temporary linker script. Keep it if save-temps is enabled. - const char *LKS; - std::string Name = llvm::sys::path::filename(Output.getFilename()); - if (C.getDriver().isSaveTempsEnabled()) { - LKS = C.getArgs().MakeArgString(Name + ".lk"); - } else { - auto TmpName = C.getDriver().GetTemporaryPath(Name, "lk"); - LKS = C.addTempFile(C.getArgs().MakeArgString(TmpName)); - } - - // Add linker script option to the command. - CmdArgs.push_back("-T"); - CmdArgs.push_back(LKS); - - // Create a buffer to write the contents of the linker script. - std::string LksBuffer; - llvm::raw_string_ostream LksStream(LksBuffer); - - // Get the HIP offload tool chain. - auto *HIPTC = static_cast<const toolchains::CudaToolChain *>( - C.getSingleOffloadToolChain<Action::OFK_HIP>()); - assert(HIPTC->getTriple().getArch() == llvm::Triple::amdgcn && - "Wrong platform"); - (void)HIPTC; - - const char *BundleFile; - if (C.getDriver().isSaveTempsEnabled()) { - BundleFile = C.getArgs().MakeArgString(Name + ".hipfb"); - } else { - auto TmpName = C.getDriver().GetTemporaryPath(Name, "hipfb"); - BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpName)); - } - AMDGCN::constructHIPFatbinCommand(C, JA, BundleFile, DeviceInputs, Args, T); - - // Add commands to embed target binaries. We ensure that each section and - // image is 16-byte aligned. This is not mandatory, but increases the - // likelihood of data to be aligned with a cache block in several main host - // machines. - LksStream << "/*\n"; - LksStream << " HIP Offload Linker Script\n"; - LksStream << " *** Automatically generated by Clang ***\n"; - LksStream << "*/\n"; - LksStream << "TARGET(binary)\n"; - LksStream << "INPUT(" << BundleFile << ")\n"; - LksStream << "SECTIONS\n"; - LksStream << "{\n"; - LksStream << " .hip_fatbin :\n"; - LksStream << " ALIGN(0x10)\n"; - LksStream << " {\n"; - LksStream << " PROVIDE_HIDDEN(__hip_fatbin = .);\n"; - LksStream << " " << BundleFile << "\n"; - LksStream << " }\n"; - LksStream << " /DISCARD/ :\n"; - LksStream << " {\n"; - LksStream << " * ( __CLANG_OFFLOAD_BUNDLE__* )\n"; - LksStream << " }\n"; - LksStream << "}\n"; - LksStream << "INSERT BEFORE .data\n"; - LksStream.flush(); - - // Dump the contents of the linker script if the user requested that. We - // support this option to enable testing of behavior with -###. - if (C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script)) - llvm::errs() << LksBuffer; - - // If this is a dry run, do not create the linker script file. - if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) - return; - - // Open script file and write the contents. - std::error_code EC; - llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::OF_None); - - if (EC) { - C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); - return; - } - - Lksf << LksBuffer; -} - SmallString<128> tools::getStatsFileName(const llvm::opt::ArgList &Args, const InputInfo &Output, const InputInfo &Input, @@ -1399,3 +1355,53 @@ void tools::addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags) { Flags.push_back(std::string(Enabled ? "+" : "-") + Flag); } + +void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs, bool IsLTO) { + auto addArg = [&, IsLTO](const Twine &Arg) { + if (IsLTO) { + CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg)); + } else { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString(Arg)); + } + }; + + if (Args.hasArg(options::OPT_mbranches_within_32B_boundaries)) { + addArg(Twine("-x86-branches-within-32B-boundaries")); + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_boundary_EQ)) { + StringRef Value = A->getValue(); + unsigned Boundary; + if (Value.getAsInteger(10, Boundary) || Boundary < 16 || + !llvm::isPowerOf2_64(Boundary)) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + } else { + addArg("-x86-align-branch-boundary=" + Twine(Boundary)); + } + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_EQ)) { + std::string AlignBranch; + for (StringRef T : A->getValues()) { + if (T != "fused" && T != "jcc" && T != "jmp" && T != "call" && + T != "ret" && T != "indirect") + D.Diag(diag::err_drv_invalid_malign_branch_EQ) + << T << "fused, jcc, jmp, call, ret, indirect"; + if (!AlignBranch.empty()) + AlignBranch += '+'; + AlignBranch += T; + } + addArg("-x86-align-branch=" + Twine(AlignBranch)); + } + if (const Arg *A = Args.getLastArg(options::OPT_mpad_max_prefix_size_EQ)) { + StringRef Value = A->getValue(); + unsigned PrefixSize; + if (Value.getAsInteger(10, PrefixSize)) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + } else { + addArg("-x86-pad-max-prefix-size=" + Twine(PrefixSize)); + } + } +} diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index 84b9d2cf59b4..29dedec9b09c 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -45,12 +45,6 @@ void AddRunTimeLibs(const ToolChain &TC, const Driver &D, llvm::opt::ArgStringList &CmdArgs, const llvm::opt::ArgList &Args); -void AddHIPLinkerScript(const ToolChain &TC, Compilation &C, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, const JobAction &JA, - const Tool &T); - const char *SplitDebugName(const llvm::opt::ArgList &Args, const InputInfo &Input, const InputInfo &Output); @@ -58,7 +52,7 @@ void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, const JobAction &JA, const llvm::opt::ArgList &Args, const InputInfo &Output, const char *OutFile); -void AddGoldPlugin(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, +void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO); @@ -88,12 +82,18 @@ llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args); bool isObjCAutoRefCount(const llvm::opt::ArgList &Args); -unsigned getLTOParallelism(const llvm::opt::ArgList &Args, const Driver &D); +llvm::StringRef getLTOParallelism(const llvm::opt::ArgList &Args, + const Driver &D); bool areOptimizationsEnabled(const llvm::opt::ArgList &Args); bool isUseSeparateSections(const llvm::Triple &Triple); +/// \p EnvVar is split by system delimiter for environment variables. +/// If \p ArgName is "-I", "-L", or an empty string, each entry from \p EnvVar +/// is prefixed by \p ArgName then added to \p Args. Otherwise, for each +/// entry of \p EnvVar, \p ArgName is added to \p Args first, then the entry +/// itself is added. void addDirectoryList(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const char *ArgName, const char *EnvVar); @@ -106,10 +106,20 @@ void AddTargetFeature(const llvm::opt::ArgList &Args, std::string getCPUName(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. +/// +/// Note: Since \p Features may contain default values before calling +/// this function, or may be appended with entries to override arguments, +/// entries in \p Features are not unique. void handleTargetFeaturesGroup(const llvm::opt::ArgList &Args, std::vector<StringRef> &Features, llvm::opt::OptSpecifier Group); +/// If there are multiple +xxx or -xxx features, keep the last one. +std::vector<StringRef> +unifyTargetFeatures(const std::vector<StringRef> &Features); + /// Handles the -save-stats option and returns the filename to save statistics /// to. SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args, @@ -121,6 +131,8 @@ SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args, void addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags); +void addX86AlignBranchArgs(const Driver &D, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, bool IsLTO); } // end namespace tools } // end namespace driver } // end namespace clang diff --git a/clang/lib/Driver/ToolChains/CrossWindows.cpp b/clang/lib/Driver/ToolChains/CrossWindows.cpp index dbf6114eb2ec..127a8a5f24cc 100644 --- a/clang/lib/Driver/ToolChains/CrossWindows.cpp +++ b/clang/lib/Driver/ToolChains/CrossWindows.cpp @@ -57,7 +57,8 @@ void tools::CrossWindows::Assembler::ConstructJob( const std::string Assembler = TC.GetProgramPath("as"); Exec = Args.MakeArgString(Assembler); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } void tools::CrossWindows::Linker::ConstructJob( @@ -202,7 +203,8 @@ void tools::CrossWindows::Linker::ConstructJob( Exec = Args.MakeArgString(TC.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); } CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, diff --git a/clang/lib/Driver/ToolChains/CrossWindows.h b/clang/lib/Driver/ToolChains/CrossWindows.h index 7267a35d48b9..df9a7f71bf9f 100644 --- a/clang/lib/Driver/ToolChains/CrossWindows.h +++ b/clang/lib/Driver/ToolChains/CrossWindows.h @@ -33,8 +33,7 @@ public: class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) - : Tool("CrossWindows::Linker", "ld", TC, RF_Full) {} + Linker(const ToolChain &TC) : Tool("CrossWindows::Linker", "ld", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 02871d2ce411..110a0bca9bc1 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -18,9 +18,11 @@ #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" +#include "llvm/Support/TargetParser.h" #include "llvm/Support/VirtualFileSystem.h" #include <system_error> @@ -32,37 +34,33 @@ using namespace llvm::opt; // 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". -static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { +void CudaInstallationDetector::ParseCudaVersionFile(llvm::StringRef V) { + Version = CudaVersion::UNKNOWN; if (!V.startswith("CUDA Version ")) - return CudaVersion::UNKNOWN; + return; V = V.substr(strlen("CUDA Version ")); - int Major = -1, Minor = -1; - auto First = V.split('.'); - auto Second = First.second.split('.'); - if (First.first.getAsInteger(10, Major) || - Second.first.getAsInteger(10, Minor)) - return CudaVersion::UNKNOWN; - - if (Major == 7 && Minor == 0) { - // This doesn't appear to ever happen -- version.txt doesn't exist in the - // CUDA 7 installs I've seen. But no harm in checking. - return CudaVersion::CUDA_70; + SmallVector<StringRef,4> VersionParts; + V.split(VersionParts, '.'); + if (VersionParts.size() < 2) + return; + DetectedVersion = join_items(".", VersionParts[0], VersionParts[1]); + Version = CudaStringToVersion(DetectedVersion); + if (Version != CudaVersion::UNKNOWN) { + // TODO(tra): remove the warning once we have all features of 10.2 and 11.0 + // implemented. + DetectedVersionIsNotSupported = Version > CudaVersion::LATEST_SUPPORTED; + return; } - if (Major == 7 && Minor == 5) - return CudaVersion::CUDA_75; - if (Major == 8 && Minor == 0) - return CudaVersion::CUDA_80; - if (Major == 9 && Minor == 0) - return CudaVersion::CUDA_90; - if (Major == 9 && Minor == 1) - return CudaVersion::CUDA_91; - if (Major == 9 && Minor == 2) - return CudaVersion::CUDA_92; - if (Major == 10 && Minor == 0) - return CudaVersion::CUDA_100; - if (Major == 10 && Minor == 1) - return CudaVersion::CUDA_101; - return CudaVersion::UNKNOWN; + + Version = CudaVersion::LATEST_SUPPORTED; + DetectedVersionIsNotSupported = true; +} + +void CudaInstallationDetector::WarnIfUnsupportedVersion() { + if (DetectedVersionIsNotSupported) + D.Diag(diag::warn_drv_unknown_cuda_version) + << DetectedVersion + << CudaVersionToString(CudaVersion::LATEST_SUPPORTED); } CudaInstallationDetector::CudaInstallationDetector( @@ -80,6 +78,7 @@ CudaInstallationDetector::CudaInstallationDetector( // In decreasing order so we prefer newer versions to older versions. std::initializer_list<const char *> Versions = {"8.0", "7.5", "7.0"}; + auto &FS = D.getVFS(); if (Args.hasArg(clang::driver::options::OPT_cuda_path_EQ)) { Candidates.emplace_back( @@ -106,8 +105,9 @@ CudaInstallationDetector::CudaInstallationDetector( StringRef ptxasDir = llvm::sys::path::parent_path(ptxasAbsolutePath); if (llvm::sys::path::filename(ptxasDir) == "bin") - Candidates.emplace_back(llvm::sys::path::parent_path(ptxasDir), - /*StrictChecking=*/true); + Candidates.emplace_back( + std::string(llvm::sys::path::parent_path(ptxasDir)), + /*StrictChecking=*/true); } } @@ -115,7 +115,7 @@ CudaInstallationDetector::CudaInstallationDetector( for (const char *Ver : Versions) Candidates.emplace_back(D.SysRoot + "/usr/local/cuda-" + Ver); - Distro Dist(D.getVFS(), llvm::Triple(llvm::sys::getProcessTriple())); + Distro Dist(FS, llvm::Triple(llvm::sys::getProcessTriple())); if (Dist.IsDebian() || Dist.IsUbuntu()) // Special case for Debian to have nvidia-cuda-toolkit work // out of the box. More info on http://bugs.debian.org/882505 @@ -126,14 +126,13 @@ CudaInstallationDetector::CudaInstallationDetector( for (const auto &Candidate : Candidates) { InstallPath = Candidate.Path; - if (InstallPath.empty() || !D.getVFS().exists(InstallPath)) + if (InstallPath.empty() || !FS.exists(InstallPath)) continue; BinPath = InstallPath + "/bin"; IncludePath = InstallPath + "/include"; LibDevicePath = InstallPath + "/nvvm/libdevice"; - auto &FS = D.getVFS(); if (!(FS.exists(IncludePath) && FS.exists(BinPath))) continue; bool CheckLibDevice = (!NoCudaLib || Candidate.StrictChecking); @@ -160,25 +159,26 @@ CudaInstallationDetector::CudaInstallationDetector( // version.txt isn't present. Version = CudaVersion::CUDA_70; } else { - Version = ParseCudaVersionFile((*VersionFile)->getBuffer()); + ParseCudaVersionFile((*VersionFile)->getBuffer()); } if (Version >= CudaVersion::CUDA_90) { // CUDA-9+ uses single libdevice file for all GPU variants. std::string FilePath = LibDevicePath + "/libdevice.10.bc"; if (FS.exists(FilePath)) { - for (const char *GpuArchName : - {"sm_30", "sm_32", "sm_35", "sm_37", "sm_50", "sm_52", "sm_53", - "sm_60", "sm_61", "sm_62", "sm_70", "sm_72", "sm_75"}) { - const CudaArch GpuArch = StringToCudaArch(GpuArchName); - if (Version >= MinVersionForCudaArch(GpuArch) && - Version <= MaxVersionForCudaArch(GpuArch)) - LibDeviceMap[GpuArchName] = FilePath; + for (int Arch = (int)CudaArch::SM_30, E = (int)CudaArch::LAST; Arch < E; + ++Arch) { + CudaArch GpuArch = static_cast<CudaArch>(Arch); + if (!IsNVIDIAGpuArch(GpuArch)) + continue; + std::string GpuArchName(CudaArchToString(GpuArch)); + LibDeviceMap[GpuArchName] = FilePath; } } } else { std::error_code EC; - for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE; + for (llvm::vfs::directory_iterator LI = FS.dir_begin(LibDevicePath, EC), + LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef FilePath = LI->path(); StringRef FileName = llvm::sys::path::filename(FilePath); @@ -194,27 +194,27 @@ CudaInstallationDetector::CudaInstallationDetector( // capability. NVCC's choice of the libdevice library version is // rather peculiar and depends on the CUDA version. if (GpuArch == "compute_20") { - LibDeviceMap["sm_20"] = FilePath; - LibDeviceMap["sm_21"] = FilePath; - LibDeviceMap["sm_32"] = FilePath; + LibDeviceMap["sm_20"] = std::string(FilePath); + LibDeviceMap["sm_21"] = std::string(FilePath); + LibDeviceMap["sm_32"] = std::string(FilePath); } else if (GpuArch == "compute_30") { - LibDeviceMap["sm_30"] = FilePath; + LibDeviceMap["sm_30"] = std::string(FilePath); if (Version < CudaVersion::CUDA_80) { - LibDeviceMap["sm_50"] = FilePath; - LibDeviceMap["sm_52"] = FilePath; - LibDeviceMap["sm_53"] = FilePath; + LibDeviceMap["sm_50"] = std::string(FilePath); + LibDeviceMap["sm_52"] = std::string(FilePath); + LibDeviceMap["sm_53"] = std::string(FilePath); } - LibDeviceMap["sm_60"] = FilePath; - LibDeviceMap["sm_61"] = FilePath; - LibDeviceMap["sm_62"] = FilePath; + LibDeviceMap["sm_60"] = std::string(FilePath); + LibDeviceMap["sm_61"] = std::string(FilePath); + LibDeviceMap["sm_62"] = std::string(FilePath); } else if (GpuArch == "compute_35") { - LibDeviceMap["sm_35"] = FilePath; - LibDeviceMap["sm_37"] = FilePath; + LibDeviceMap["sm_35"] = std::string(FilePath); + LibDeviceMap["sm_37"] = std::string(FilePath); } else if (GpuArch == "compute_50") { if (Version >= CudaVersion::CUDA_80) { - LibDeviceMap["sm_50"] = FilePath; - LibDeviceMap["sm_52"] = FilePath; - LibDeviceMap["sm_53"] = FilePath; + LibDeviceMap["sm_50"] = std::string(FilePath); + LibDeviceMap["sm_52"] = std::string(FilePath); + LibDeviceMap["sm_53"] = std::string(FilePath); } } } @@ -242,7 +242,7 @@ void CudaInstallationDetector::AddCudaIncludeArgs( CC1Args.push_back(DriverArgs.MakeArgString(P)); } - if (DriverArgs.hasArg(options::OPT_nocudainc)) + if (DriverArgs.hasArg(options::OPT_nogpuinc)) return; if (!isValid()) { @@ -423,7 +423,11 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, Exec = A->getValue(); else Exec = Args.MakeArgString(TC.GetProgramPath("ptxas")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, + ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8, + "--options-file"}, + Exec, CmdArgs, Inputs)); } static bool shouldIncludePTX(const ArgList &Args, const char *gpu_arch) { @@ -477,10 +481,9 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, continue; // We need to pass an Arch of the form "sm_XX" for cubin files and // "compute_XX" for ptx. - const char *Arch = - (II.getType() == types::TY_PP_Asm) - ? CudaVirtualArchToString(VirtualArchForCudaArch(gpu_arch)) - : gpu_arch_str; + const char *Arch = (II.getType() == types::TY_PP_Asm) + ? CudaArchToVirtualArchString(gpu_arch) + : gpu_arch_str; CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") + Arch + ",file=" + II.getFilename())); } @@ -489,7 +492,11 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(A)); const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, + ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8, + "--options-file"}, + Exec, CmdArgs, Inputs)); } void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, @@ -566,7 +573,11 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("nvlink")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, + ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8, + "--options-file"}, + Exec, CmdArgs, Inputs)); } /// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary, @@ -578,8 +589,10 @@ CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, const Action::OffloadKind OK) : ToolChain(D, Triple, Args), HostTC(HostTC), CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) { - if (CudaInstallation.isValid()) - getProgramPaths().push_back(CudaInstallation.getBinPath()); + if (CudaInstallation.isValid()) { + CudaInstallation.WarnIfUnsupportedVersion(); + getProgramPaths().push_back(std::string(CudaInstallation.getBinPath())); + } // Lookup binaries into the driver directory, this is used to // discover the clang-offload-bundler executable. getProgramPaths().push_back(getDriver().Dir); @@ -596,7 +609,7 @@ std::string CudaToolChain::getInputFilename(const InputInfo &Input) const { // these particular file names. SmallString<256> Filename(ToolChain::getInputFilename(Input)); llvm::sys::path::replace_extension(Filename, "cubin"); - return Filename.str(); + return std::string(Filename.str()); } void CudaToolChain::addClangTargetOptions( @@ -614,10 +627,6 @@ void CudaToolChain::addClangTargetOptions( if (DeviceOffloadingKind == Action::OFK_Cuda) { CC1Args.push_back("-fcuda-is-device"); - if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, - options::OPT_fno_cuda_flush_denormals_to_zero, false)) - CC1Args.push_back("-fcuda-flush-denormals-to-zero"); - if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, options::OPT_fno_cuda_approx_transcendentals, false)) CC1Args.push_back("-fcuda-approx-transcendentals"); @@ -648,24 +657,30 @@ void CudaToolChain::addClangTargetOptions( // by new PTX version, so we need to raise PTX level to enable them in NVPTX // back-end. const char *PtxFeature = nullptr; - switch(CudaInstallation.version()) { - case CudaVersion::CUDA_101: - PtxFeature = "+ptx64"; - break; - case CudaVersion::CUDA_100: - PtxFeature = "+ptx63"; - break; - case CudaVersion::CUDA_92: - PtxFeature = "+ptx61"; - break; - case CudaVersion::CUDA_91: - PtxFeature = "+ptx61"; - break; - case CudaVersion::CUDA_90: - PtxFeature = "+ptx60"; - break; - default: - PtxFeature = "+ptx42"; + switch (CudaInstallation.version()) { + case CudaVersion::CUDA_110: + PtxFeature = "+ptx70"; + break; + case CudaVersion::CUDA_102: + PtxFeature = "+ptx65"; + break; + case CudaVersion::CUDA_101: + PtxFeature = "+ptx64"; + break; + case CudaVersion::CUDA_100: + PtxFeature = "+ptx63"; + break; + case CudaVersion::CUDA_92: + PtxFeature = "+ptx61"; + break; + case CudaVersion::CUDA_91: + PtxFeature = "+ptx61"; + break; + case CudaVersion::CUDA_90: + PtxFeature = "+ptx60"; + break; + default: + PtxFeature = "+ptx42"; } CC1Args.append({"-target-feature", PtxFeature}); if (DriverArgs.hasFlag(options::OPT_fcuda_short_ptr, @@ -718,6 +733,21 @@ void CudaToolChain::addClangTargetOptions( } } +llvm::DenormalMode CudaToolChain::getDefaultDenormalModeForType( + const llvm::opt::ArgList &DriverArgs, const JobAction &JA, + const llvm::fltSemantics *FPType) const { + if (JA.getOffloadingDeviceKind() == Action::OFK_Cuda) { + if (FPType && FPType == &llvm::APFloat::IEEEsingle() && + DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, + options::OPT_fno_cuda_flush_denormals_to_zero, + false)) + return llvm::DenormalMode::getPreserveSign(); + } + + assert(JA.getOffloadingDeviceKind() != Action::OFK_Host); + return llvm::DenormalMode::getIEEE(); +} + bool CudaToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const { const Option &O = A->getOption(); return (O.matches(options::OPT_gN_Group) && @@ -748,7 +778,7 @@ void CudaToolChain::adjustDebugInfoKind( void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { // Check our CUDA version if we're going to include the CUDA headers. - if (!DriverArgs.hasArg(options::OPT_nocudainc) && + if (!DriverArgs.hasArg(options::OPT_nogpuinc) && !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) { StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ); assert(!Arch.empty() && "Must have an explicit GPU arch."); @@ -793,36 +823,6 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, } for (Arg *A : Args) { - if (A->getOption().matches(options::OPT_Xarch__)) { - // Skip this argument unless the architecture matches BoundArch - if (BoundArch.empty() || A->getValue(0) != BoundArch) - continue; - - unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); - unsigned Prev = Index; - std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); - - // If the argument parsing failed or more than one argument was - // consumed, the -Xarch_ argument's parameter tried to consume - // extra arguments. Emit an error and ignore. - // - // We also want to disallow any options which would alter the - // driver behavior; that isn't going to work in our model. We - // use isDriverOption() as an approximation, although things - // like -O4 are going to slip through. - if (!XarchArg || Index > Prev + 1) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) - << A->getAsString(Args); - continue; - } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) - << A->getAsString(Args); - continue; - } - XarchArg->setBaseArg(A); - A = XarchArg.release(); - DAL->AddSynthesizedArg(A); - } DAL->append(A); } diff --git a/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h index 4ee8b6f1fea9..873eb7338a30 100644 --- a/clang/lib/Driver/ToolChains/Cuda.h +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -30,6 +30,8 @@ private: const Driver &D; bool IsValid = false; CudaVersion Version = CudaVersion::UNKNOWN; + std::string DetectedVersion; + bool DetectedVersionIsNotSupported = false; std::string InstallPath; std::string BinPath; std::string LibPath; @@ -75,6 +77,10 @@ public: std::string getLibDeviceFile(StringRef Gpu) const { return LibDeviceMap.lookup(Gpu); } + void WarnIfUnsupportedVersion(); + +private: + void ParseCudaVersionFile(llvm::StringRef V); }; namespace tools { @@ -83,9 +89,7 @@ namespace NVPTX { // Run ptxas, the NVPTX assembler. class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: - Assembler(const ToolChain &TC) - : Tool("NVPTX::Assembler", "ptxas", TC, RF_Full, llvm::sys::WEM_UTF8, - "--options-file") {} + Assembler(const ToolChain &TC) : Tool("NVPTX::Assembler", "ptxas", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -99,9 +103,7 @@ class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { // assembly into a single output file. class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) - : Tool("NVPTX::Linker", "fatbinary", TC, RF_Full, llvm::sys::WEM_UTF8, - "--options-file") {} + Linker(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -114,8 +116,7 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool { public: OpenMPLinker(const ToolChain &TC) - : Tool("NVPTX::OpenMPLinker", "nvlink", TC, RF_Full, llvm::sys::WEM_UTF8, - "--options-file") {} + : Tool("NVPTX::OpenMPLinker", "nvlink", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -149,6 +150,10 @@ public: llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + llvm::DenormalMode getDefaultDenormalModeForType( + const llvm::opt::ArgList &DriverArgs, const JobAction &JA, + const llvm::fltSemantics *FPType = nullptr) const override; + // Never try to use the integrated assembler with CUDA; always fork out to // ptxas. bool useIntegratedAs() const override { return false; } diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 344a14fe1ea7..7b879f8cb652 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" #include <cstdlib> // ::getenv @@ -147,7 +148,8 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, // asm_final spec is empty. const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } void darwin::MachOTool::anchor() {} @@ -201,16 +203,11 @@ static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) { void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs, - const InputInfoList &Inputs) const { + const InputInfoList &Inputs, + unsigned Version[5]) const { const Driver &D = getToolChain().getDriver(); const toolchains::MachO &MachOTC = getMachOToolChain(); - unsigned Version[5] = {0, 0, 0, 0, 0}; - if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { - if (!Driver::GetReleaseVersion(A->getValue(), Version)) - D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args); - } - // Newer linkers support -demangle. Pass it if supported and not disabled by // the user. if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) @@ -335,7 +332,7 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_init); // Add the deployment target. - if (!Version[0] || Version[0] >= 520) + if (Version[0] >= 520) MachOTC.addPlatformVersionArgs(Args, CmdArgs); else MachOTC.addMinVersionArgs(Args, CmdArgs); @@ -429,6 +426,75 @@ static bool isObjCRuntimeLinked(const ArgList &Args) { return Args.hasArg(options::OPT_fobjc_link_runtime); } +static bool checkRemarksOptions(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + // When enabling remarks, we need to error if: + // * The remark file is specified but we're targeting multiple architectures, + // which means more than one remark file is being generated. + bool hasMultipleInvocations = + Args.getAllArgValues(options::OPT_arch).size() > 1; + bool hasExplicitOutputFile = + Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (hasMultipleInvocations && hasExplicitOutputFile) { + D.Diag(diag::err_drv_invalid_output_with_multiple_archs) + << "-foptimization-record-file"; + return false; + } + return true; +} + +static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple, + const InputInfo &Output, const JobAction &JA) { + StringRef Format = "yaml"; + if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) + Format = A->getValue(); + + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-output"); + CmdArgs.push_back("-mllvm"); + + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + CmdArgs.push_back(A->getValue()); + } else { + assert(Output.isFilename() && "Unexpected ld output."); + SmallString<128> F; + F = Output.getFilename(); + F += ".opt."; + F += Format; + + CmdArgs.push_back(Args.MakeArgString(F)); + } + + if (const Arg *A = + Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { + CmdArgs.push_back("-mllvm"); + std::string Passes = + std::string("-lto-pass-remarks-filter=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Passes)); + } + + if (!Format.empty()) { + CmdArgs.push_back("-mllvm"); + Twine FormatArg = Twine("-lto-pass-remarks-format=") + Format; + CmdArgs.push_back(Args.MakeArgString(FormatArg)); + } + + if (getLastProfileUseArg(Args)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-with-hotness"); + + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { + CmdArgs.push_back("-mllvm"); + std::string Opt = + std::string("-lto-pass-remarks-hotness-threshold=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } + } +} + void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -455,63 +521,26 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("touch")); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, None)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, None)); return; } + unsigned Version[5] = {0, 0, 0, 0, 0}; + if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { + if (!Driver::GetReleaseVersion(A->getValue(), Version)) + getToolChain().getDriver().Diag(diag::err_drv_invalid_version_number) + << A->getAsString(Args); + } + // I'm not sure why this particular decomposition exists in gcc, but // we follow suite for ease of comparison. - AddLinkArgs(C, Args, CmdArgs, Inputs); + AddLinkArgs(C, Args, CmdArgs, Inputs, Version); - // For LTO, pass the name of the optimization record file and other - // opt-remarks flags. - if (Args.hasFlag(options::OPT_fsave_optimization_record, - options::OPT_fsave_optimization_record_EQ, - options::OPT_fno_save_optimization_record, false)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-lto-pass-remarks-output"); - CmdArgs.push_back("-mllvm"); - - SmallString<128> F; - F = Output.getFilename(); - F += ".opt."; - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) - F += A->getValue(); - else - F += "yaml"; - - CmdArgs.push_back(Args.MakeArgString(F)); - - if (getLastProfileUseArg(Args)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-lto-pass-remarks-with-hotness"); - - if (const Arg *A = - Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { - CmdArgs.push_back("-mllvm"); - std::string Opt = - std::string("-lto-pass-remarks-hotness-threshold=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Opt)); - } - } - - if (const Arg *A = - Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { - CmdArgs.push_back("-mllvm"); - std::string Passes = - std::string("-lto-pass-remarks-filter=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Passes)); - } - - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) { - CmdArgs.push_back("-mllvm"); - std::string Format = - std::string("-lto-pass-remarks-format=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Format)); - } - } + if (willEmitRemarks(Args) && + checkRemarksOptions(getToolChain().getDriver(), Args, + getToolChain().getTriple())) + renderRemarksOptions(Args, CmdArgs, getToolChain().getTriple(), Output, JA); // Propagate the -moutline flag to the linker in LTO. if (Arg *A = @@ -605,10 +634,12 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, getMachOToolChain().addProfileRTLibs(Args, CmdArgs); - if (unsigned Parallelism = - getLTOParallelism(Args, getToolChain().getDriver())) { + StringRef Parallelism = getLTOParallelism(Args, getToolChain().getDriver()); + if (!Parallelism.empty()) { CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-threads=" + Twine(Parallelism))); + unsigned NumThreads = + llvm::get_threadpool_strategy(Parallelism)->compute_thread_count(); + CmdArgs.push_back(Args.MakeArgString("-threads=" + Twine(NumThreads))); } if (getToolChain().ShouldLinkCXXStdlib(Args)) @@ -655,9 +686,16 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } + ResponseFileSupport ResponseSupport = ResponseFileSupport::AtFileUTF8(); + if (Version[0] < 607) { + // For older versions of the linker, use the legacy filelist method instead. + ResponseSupport = {ResponseFileSupport::RF_FileList, llvm::sys::WEM_UTF8, + "-filelist"}; + } + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - std::unique_ptr<Command> Cmd = - std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs); + std::unique_ptr<Command> Cmd = std::make_unique<Command>( + JA, *this, ResponseSupport, Exec, CmdArgs, Inputs); Cmd->setInputFileList(std::move(InputFileList)); C.addCommand(std::move(Cmd)); } @@ -681,7 +719,8 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, @@ -701,7 +740,8 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dsymutil")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, @@ -724,7 +764,8 @@ void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) @@ -738,7 +779,7 @@ MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) /// Darwin - Darwin tool chain for i386 and x86_64. Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : MachO(D, Triple, Args), TargetInitialized(false), - CudaInstallation(D, Triple, Args) {} + CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) {} types::ID MachO::LookupTypeForExtension(StringRef Ext) const { types::ID Ty = ToolChain::LookupTypeForExtension(Ext); @@ -790,6 +831,11 @@ void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs, CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } +void Darwin::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); +} + // This is just a MachO name translation routine and there's no // way to join this into ARMTargetParser without breaking all // other assumptions. Maybe MachO should consider standardising @@ -913,6 +959,10 @@ DarwinClang::DarwinClang(const Driver &D, const llvm::Triple &Triple, : Darwin(D, Triple, Args) {} void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const { + // Always error about undefined 'TARGET_OS_*' macros. + CC1Args.push_back("-Wundef-prefix=TARGET_OS_"); + CC1Args.push_back("-Werror=undef-prefix"); + // For modern targets, promote certain warnings to errors. if (isTargetWatchOSBased() || getTriple().isArch64Bit()) { // Always enable -Wdeprecated-objc-isa-usage and promote it @@ -944,6 +994,8 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, // Avoid linking compatibility stubs on i386 mac. if (isTargetMacOS() && getArch() == llvm::Triple::x86) return; + if (isTargetAppleSiliconMac()) + return; ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true); @@ -1068,8 +1120,8 @@ StringRef Darwin::getPlatformFamily() const { StringRef Darwin::getSDKName(StringRef isysroot) { // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk - auto BeginSDK = llvm::sys::path::begin(isysroot); - auto EndSDK = llvm::sys::path::end(isysroot); + auto BeginSDK = llvm::sys::path::rbegin(isysroot); + auto EndSDK = llvm::sys::path::rend(isysroot); for (auto IT = BeginSDK; IT != EndSDK; ++IT) { StringRef SDK = *IT; if (SDK.endswith(".sdk")) @@ -1131,7 +1183,8 @@ static void addSectalignToPage(const ArgList &Args, ArgStringList &CmdArgs, void Darwin::addProfileRTLibs(const ArgList &Args, ArgStringList &CmdArgs) const { - if (!needsProfileRT(Args)) return; + if (!needsProfileRT(Args) && !needsGCovInstrumentation(Args)) + return; AddLinkRuntimeLib(Args, CmdArgs, "profile", RuntimeLinkOptions(RLO_AlwaysLink | RLO_FirstLink)); @@ -1146,6 +1199,7 @@ void Darwin::addProfileRTLibs(const ArgList &Args, addExportedSymbol(CmdArgs, "___gcov_flush"); addExportedSymbol(CmdArgs, "_flush_fn_list"); addExportedSymbol(CmdArgs, "_writeout_fn_list"); + addExportedSymbol(CmdArgs, "_reset_fn_list"); } else { addExportedSymbol(CmdArgs, "___llvm_profile_filename"); addExportedSymbol(CmdArgs, "___llvm_profile_raw_version"); @@ -1270,17 +1324,17 @@ static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) { unsigned Major, Minor, Micro; llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); if (!SystemTriple.isMacOSX()) - return MacOSSDKVersion; + return std::string(MacOSSDKVersion); SystemTriple.getMacOSXVersion(Major, Minor, Micro); VersionTuple SystemVersion(Major, Minor, Micro); bool HadExtra; if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro, HadExtra)) - return MacOSSDKVersion; + return std::string(MacOSSDKVersion); VersionTuple SDKVersion(Major, Minor, Micro); if (SDKVersion > SystemVersion) return SystemVersion.getAsString(); - return MacOSSDKVersion; + return std::string(MacOSSDKVersion); } namespace { @@ -1320,7 +1374,7 @@ struct DarwinPlatform { void setOSVersion(StringRef S) { assert(Kind == TargetArg && "Unexpected kind!"); - OSVersion = S; + OSVersion = std::string(S); } bool hasOSVersion() const { return HasOSVersion; } @@ -1577,7 +1631,7 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args, size_t StartVer = SDK.find_first_of("0123456789"); size_t EndVer = SDK.find_last_of("0123456789"); if (StartVer != StringRef::npos && EndVer > StartVer) - Version = SDK.slice(StartVer, EndVer + 1); + Version = std::string(SDK.slice(StartVer, EndVer + 1)); } if (Version.empty()) return None; @@ -1643,8 +1697,16 @@ inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS; StringRef MachOArchName = Toolchain.getMachOArchName(Args); - if (MachOArchName == "armv7" || MachOArchName == "armv7s" || - MachOArchName == "arm64") + if (MachOArchName == "arm64") { +#if __arm64__ + // A clang running on an Apple Silicon mac defaults + // to building for mac when building for arm64 rather than + // defaulting to iOS. + OSTy = llvm::Triple::MacOSX; +#else + OSTy = llvm::Triple::IOS; +#endif + } else if (MachOArchName == "armv7" || MachOArchName == "armv7s") OSTy = llvm::Triple::IOS; else if (MachOArchName == "armv7k" || MachOArchName == "arm64_32") OSTy = llvm::Triple::WatchOS; @@ -1793,7 +1855,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (Platform == MacOS) { if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, Micro, HadExtra) || - HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) + HadExtra || Major < 10 || Major >= 100 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) << OSTarget->getAsString(Args, Opts); } else if (Platform == IPhoneOS) { @@ -1870,7 +1932,10 @@ void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs bool NoStdInc = DriverArgs.hasArg(options::OPT_nostdinc); bool NoStdlibInc = DriverArgs.hasArg(options::OPT_nostdlibinc); - bool NoBuiltinInc = DriverArgs.hasArg(options::OPT_nobuiltininc); + bool NoBuiltinInc = DriverArgs.hasFlag( + options::OPT_nobuiltininc, options::OPT_ibuiltininc, /*Default=*/false); + bool ForceBuiltinInc = DriverArgs.hasFlag( + options::OPT_ibuiltininc, options::OPT_nobuiltininc, /*Default=*/false); // Add <sysroot>/usr/local/include if (!NoStdInc && !NoStdlibInc) { @@ -1880,7 +1945,7 @@ void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs } // Add the Clang builtin headers (<resource>/include) - if (!NoStdInc && !NoBuiltinInc) { + if (!(NoStdInc && !ForceBuiltinInc) && !NoBuiltinInc) { SmallString<128> P(D.ResourceDir); llvm::sys::path::append(P, "include"); addSystemInclude(DriverArgs, CC1Args, P); @@ -1896,7 +1961,7 @@ void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs CIncludeDirs.split(dirs, ":"); for (llvm::StringRef dir : dirs) { llvm::StringRef Prefix = - llvm::sys::path::is_absolute(dir) ? llvm::StringRef(Sysroot) : ""; + llvm::sys::path::is_absolute(dir) ? "" : llvm::StringRef(Sysroot); addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); } } else { @@ -2129,32 +2194,7 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, continue; Arg *OriginalArg = A; - unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); - unsigned Prev = Index; - std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); - - // If the argument parsing failed or more than one argument was - // consumed, the -Xarch_ argument's parameter tried to consume - // extra arguments. Emit an error and ignore. - // - // We also want to disallow any options which would alter the - // driver behavior; that isn't going to work in our model. We - // use isDriverOption() as an approximation, although things - // like -O4 are going to slip through. - if (!XarchArg || Index > Prev + 1) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) - << A->getAsString(Args); - continue; - } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) - << A->getAsString(Args); - continue; - } - - XarchArg->setBaseArg(A); - - A = XarchArg.release(); - DAL->AddSynthesizedArg(A); + TranslateXarchArgs(Args, A, DAL); // Linker input arguments require custom handling. The problem is that we // have already constructed the phase actions, so we can not treat them as @@ -2369,6 +2409,10 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, OS << "-target-sdk-version=" << SDKInfo->getVersion(); CC1Args.push_back(DriverArgs.MakeArgString(OS.str())); } + + // Enable compatibility mode for NSItemProviderCompletionHandler in + // Foundation/NSItemProvider.h. + CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking"); } DerivedArgList * @@ -2511,6 +2555,9 @@ void Darwin::addMinVersionArgs(const ArgList &Args, CmdArgs.push_back("-macosx_version_min"); } + VersionTuple MinTgtVers = getEffectiveTriple().getMinimumSupportedOSVersion(); + if (!MinTgtVers.empty() && MinTgtVers > TargetVersion) + TargetVersion = MinTgtVers; CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); } @@ -2543,6 +2590,9 @@ void Darwin::addPlatformVersionArgs(const llvm::opt::ArgList &Args, PlatformName += "-simulator"; CmdArgs.push_back(Args.MakeArgString(PlatformName)); VersionTuple TargetVersion = getTargetVersion().withoutBuild(); + VersionTuple MinTgtVers = getEffectiveTriple().getMinimumSupportedOSVersion(); + if (!MinTgtVers.empty() && MinTgtVers > TargetVersion) + TargetVersion = MinTgtVers; CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); if (SDKInfo) { VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild(); @@ -2553,98 +2603,102 @@ void Darwin::addPlatformVersionArgs(const llvm::opt::ArgList &Args, } } -void Darwin::addStartObjectFileArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Derived from startfile spec. - if (Args.hasArg(options::OPT_dynamiclib)) { - // Derived from darwin_dylib1 spec. - if (isTargetWatchOSBased()) { - ; // watchOS does not need dylib1.o. - } else if (isTargetIOSSimulator()) { - ; // iOS simulator does not need dylib1.o. - } else if (isTargetIPhoneOS()) { - if (isIPhoneOSVersionLT(3, 1)) - CmdArgs.push_back("-ldylib1.o"); +// Add additional link args for the -dynamiclib option. +static void addDynamicLibLinkArgs(const Darwin &D, const ArgList &Args, + ArgStringList &CmdArgs) { + // Derived from darwin_dylib1 spec. + if (D.isTargetIPhoneOS()) { + if (D.isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-ldylib1.o"); + return; + } + + if (!D.isTargetMacOS()) + return; + if (D.isMacosxVersionLT(10, 5)) + CmdArgs.push_back("-ldylib1.o"); + else if (D.isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-ldylib1.10.5.o"); +} + +// Add additional link args for the -bundle option. +static void addBundleLinkArgs(const Darwin &D, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_static)) + return; + // Derived from darwin_bundle1 spec. + if ((D.isTargetIPhoneOS() && D.isIPhoneOSVersionLT(3, 1)) || + (D.isTargetMacOS() && D.isMacosxVersionLT(10, 6))) + CmdArgs.push_back("-lbundle1.o"); +} + +// Add additional link args for the -pg option. +static void addPgProfilingLinkArgs(const Darwin &D, const ArgList &Args, + ArgStringList &CmdArgs) { + if (D.isTargetMacOS() && D.isMacosxVersionLT(10, 9)) { + if (Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_object) || + Args.hasArg(options::OPT_preload)) { + CmdArgs.push_back("-lgcrt0.o"); } else { - if (isMacosxVersionLT(10, 5)) - CmdArgs.push_back("-ldylib1.o"); - else if (isMacosxVersionLT(10, 6)) - CmdArgs.push_back("-ldylib1.10.5.o"); + CmdArgs.push_back("-lgcrt1.o"); + + // darwin_crt2 spec is empty. } + // By default on OS X 10.8 and later, we don't link with a crt1.o + // file and the linker knows to use _main as the entry point. But, + // when compiling with -pg, we need to link with the gcrt1.o file, + // so pass the -no_new_main option to tell the linker to use the + // "start" symbol as the entry point. + if (!D.isMacosxVersionLT(10, 8)) + CmdArgs.push_back("-no_new_main"); } else { - if (Args.hasArg(options::OPT_bundle)) { - if (!Args.hasArg(options::OPT_static)) { - // Derived from darwin_bundle1 spec. - if (isTargetWatchOSBased()) { - ; // watchOS does not need bundle1.o. - } else if (isTargetIOSSimulator()) { - ; // iOS simulator does not need bundle1.o. - } else if (isTargetIPhoneOS()) { - if (isIPhoneOSVersionLT(3, 1)) - CmdArgs.push_back("-lbundle1.o"); - } else { - if (isMacosxVersionLT(10, 6)) - CmdArgs.push_back("-lbundle1.o"); - } - } - } else { - if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) { - if (isTargetMacOS() && isMacosxVersionLT(10, 9)) { - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_object) || - Args.hasArg(options::OPT_preload)) { - CmdArgs.push_back("-lgcrt0.o"); - } else { - CmdArgs.push_back("-lgcrt1.o"); - - // darwin_crt2 spec is empty. - } - // By default on OS X 10.8 and later, we don't link with a crt1.o - // file and the linker knows to use _main as the entry point. But, - // when compiling with -pg, we need to link with the gcrt1.o file, - // so pass the -no_new_main option to tell the linker to use the - // "start" symbol as the entry point. - if (isTargetMacOS() && !isMacosxVersionLT(10, 8)) - CmdArgs.push_back("-no_new_main"); - } else { - getDriver().Diag(diag::err_drv_clang_unsupported_opt_pg_darwin) - << isTargetMacOS(); - } - } else { - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_object) || - Args.hasArg(options::OPT_preload)) { - CmdArgs.push_back("-lcrt0.o"); - } else { - // Derived from darwin_crt1 spec. - if (isTargetWatchOSBased()) { - ; // watchOS does not need crt1.o. - } else if (isTargetIOSSimulator()) { - ; // iOS simulator does not need crt1.o. - } else if (isTargetIPhoneOS()) { - if (getArch() == llvm::Triple::aarch64) - ; // iOS does not need any crt1 files for arm64 - else if (isIPhoneOSVersionLT(3, 1)) - CmdArgs.push_back("-lcrt1.o"); - else if (isIPhoneOSVersionLT(6, 0)) - CmdArgs.push_back("-lcrt1.3.1.o"); - } else { - if (isMacosxVersionLT(10, 5)) - CmdArgs.push_back("-lcrt1.o"); - else if (isMacosxVersionLT(10, 6)) - CmdArgs.push_back("-lcrt1.10.5.o"); - else if (isMacosxVersionLT(10, 8)) - CmdArgs.push_back("-lcrt1.10.6.o"); - - // darwin_crt2 spec is empty. - } - } - } - } + D.getDriver().Diag(diag::err_drv_clang_unsupported_opt_pg_darwin) + << D.isTargetMacOS(); } +} + +static void addDefaultCRTLinkArgs(const Darwin &D, const ArgList &Args, + ArgStringList &CmdArgs) { + // Derived from darwin_crt1 spec. + if (D.isTargetIPhoneOS()) { + if (D.getArch() == llvm::Triple::aarch64) + ; // iOS does not need any crt1 files for arm64 + else if (D.isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-lcrt1.o"); + else if (D.isIPhoneOSVersionLT(6, 0)) + CmdArgs.push_back("-lcrt1.3.1.o"); + return; + } + + if (!D.isTargetMacOS()) + return; + if (D.isMacosxVersionLT(10, 5)) + CmdArgs.push_back("-lcrt1.o"); + else if (D.isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-lcrt1.10.5.o"); + else if (D.isMacosxVersionLT(10, 8)) + CmdArgs.push_back("-lcrt1.10.6.o"); + // darwin_crt2 spec is empty. +} + +void Darwin::addStartObjectFileArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Derived from startfile spec. + if (Args.hasArg(options::OPT_dynamiclib)) + addDynamicLibLinkArgs(*this, Args, CmdArgs); + else if (Args.hasArg(options::OPT_bundle)) + addBundleLinkArgs(*this, Args, CmdArgs); + else if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) + addPgProfilingLinkArgs(*this, Args, CmdArgs); + else if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_object) || + Args.hasArg(options::OPT_preload)) + CmdArgs.push_back("-lcrt0.o"); + else + addDefaultCRTLinkArgs(*this, Args, CmdArgs); - if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) && - !isTargetWatchOS() && isMacosxVersionLT(10, 5)) { + if (isTargetMacOS() && Args.hasArg(options::OPT_shared_libgcc) && + isMacosxVersionLT(10, 5)) { const char *Str = Args.MakeArgString(GetFilePath("crt3.o")); CmdArgs.push_back(Str); } @@ -2667,6 +2721,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const { Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; Res |= SanitizerKind::Function; + Res |= SanitizerKind::ObjCCast; // Prior to 10.9, macOS shipped a version of the C++ standard library without // C++11 support. The same is true of iOS prior to version 5. These OS'es are @@ -2687,4 +2742,5 @@ SanitizerMask Darwin::getSupportedSanitizers() const { void Darwin::printVerboseInfo(raw_ostream &OS) const { CudaInstallation.print(OS); + RocmInstallation.print(OS); } diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h index 1b193a4c4eb9..64c252efea7d 100644 --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H #include "Cuda.h" +#include "ROCm.h" #include "clang/Driver/DarwinSDKInfo.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" @@ -40,13 +41,8 @@ protected: } public: - MachOTool( - const char *Name, const char *ShortName, const ToolChain &TC, - ResponseFileSupport ResponseSupport = RF_None, - llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8, - const char *ResponseFlag = "@") - : Tool(Name, ShortName, TC, ResponseSupport, ResponseEncoding, - ResponseFlag) {} + MachOTool(const char *Name, const char *ShortName, const ToolChain &TC) + : Tool(Name, ShortName, TC) {} }; class LLVM_LIBRARY_VISIBILITY Assembler : public MachOTool { @@ -66,12 +62,10 @@ class LLVM_LIBRARY_VISIBILITY Linker : public MachOTool { bool NeedsTempPath(const InputInfoList &Inputs) const; void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - const InputInfoList &Inputs) const; + const InputInfoList &Inputs, unsigned Version[5]) const; public: - Linker(const ToolChain &TC) - : MachOTool("darwin::Linker", "linker", TC, RF_FileList, - llvm::sys::WEM_UTF8, "-filelist") {} + Linker(const ToolChain &TC) : MachOTool("darwin::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } @@ -300,6 +294,7 @@ public: mutable Optional<DarwinSDKInfo> SDKInfo; CudaInstallationDetector CudaInstallation; + RocmInstallationDetector RocmInstallation; private: void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; @@ -357,6 +352,7 @@ protected: const_cast<Darwin *>(this)->setTripleEnvironment(llvm::Triple::Simulator); } +public: bool isTargetIPhoneOS() const { assert(TargetInitialized && "Target not initialized!"); return (TargetPlatform == IPhoneOS || TargetPlatform == TvOS) && @@ -409,6 +405,17 @@ protected: return TargetPlatform == MacOS; } + bool isTargetMacOSBased() const { + assert(TargetInitialized && "Target not initialized!"); + // FIXME (Alex L): Add remaining MacCatalyst suppport. + return TargetPlatform == MacOS; + } + + bool isTargetAppleSiliconMac() const { + assert(TargetInitialized && "Target not initialized!"); + return isTargetMacOSBased() && getArch() == llvm::Triple::aarch64; + } + bool isTargetInitialized() const { return TargetInitialized; } VersionTuple getTargetVersion() const { @@ -422,11 +429,20 @@ protected: return TargetVersion < VersionTuple(V0, V1, V2); } + /// Returns true if the minimum supported macOS version for the slice that's + /// being built is less than the specified version. If there's no minimum + /// supported macOS version, the deployment target version is compared to the + /// specifed version instead. bool isMacosxVersionLT(unsigned V0, unsigned V1 = 0, unsigned V2 = 0) const { - assert(isTargetMacOS() && "Unexpected call for non OS X target!"); - return TargetVersion < VersionTuple(V0, V1, V2); + assert(isTargetMacOS() && getTriple().isMacOSX() && + "Unexpected call for non OS X target!"); + VersionTuple MinVers = getTriple().getMinimumSupportedOSVersion(); + return (!MinVers.empty() && MinVers > TargetVersion + ? MinVers + : TargetVersion) < VersionTuple(V0, V1, V2); } +protected: /// Return true if c++17 aligned allocation/deallocation functions are not /// implemented in the c++ standard library of the deployment target we are /// targeting. @@ -461,6 +477,8 @@ public: void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; bool UseObjCMixedDispatch() const override { // This is only used with the non-fragile ABI and non-legacy dispatch. diff --git a/clang/lib/Driver/ToolChains/DragonFly.cpp b/clang/lib/Driver/ToolChains/DragonFly.cpp index 424331fbc6fe..88dd0c899d8a 100644 --- a/clang/lib/Driver/ToolChains/DragonFly.cpp +++ b/clang/lib/Driver/ToolChains/DragonFly.cpp @@ -45,7 +45,8 @@ void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -169,7 +170,8 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. diff --git a/clang/lib/Driver/ToolChains/DragonFly.h b/clang/lib/Driver/ToolChains/DragonFly.h index 7e76904f1055..3ed5acefaefb 100644 --- a/clang/lib/Driver/ToolChains/DragonFly.h +++ b/clang/lib/Driver/ToolChains/DragonFly.h @@ -18,10 +18,10 @@ namespace driver { namespace tools { /// dragonfly -- Directly call GNU Binutils assembler and linker namespace dragonfly { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: Assembler(const ToolChain &TC) - : GnuTool("dragonfly::Assembler", "assembler", TC) {} + : Tool("dragonfly::Assembler", "assembler", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -31,9 +31,9 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("dragonfly::Linker", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("dragonfly::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 9b9eb81fa111..80f6db7ea642 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -70,10 +70,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, const auto& D = C.getDriver(); const char* Exec = Args.MakeArgString(D.GetProgramPath("flang", TC)); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); } -Flang::Flang(const ToolChain &TC) - : Tool("flang", "flang frontend", TC, RF_Full) {} +Flang::Flang(const ToolChain &TC) : Tool("flang", "flang frontend", TC) {} Flang::~Flang() {} diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index c5c6f530f48c..909ac5e99212 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -99,7 +99,8 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::sparcel: case llvm::Triple::sparcv9: { std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + CmdArgs.push_back( + sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; } @@ -127,7 +128,8 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -275,7 +277,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); - AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); } @@ -357,7 +359,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. @@ -388,6 +391,12 @@ unsigned FreeBSD::GetDefaultDwarfVersion() const { return 4; } +void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/v1"); +} + void FreeBSD::addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { @@ -416,6 +425,11 @@ void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs, CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } +void FreeBSD::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); +} + Tool *FreeBSD::buildAssembler() const { return new tools::freebsd::Assembler(*this); } diff --git a/clang/lib/Driver/ToolChains/FreeBSD.h b/clang/lib/Driver/ToolChains/FreeBSD.h index 84bdbfd9a312..abc0876cef26 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.h +++ b/clang/lib/Driver/ToolChains/FreeBSD.h @@ -19,10 +19,10 @@ namespace tools { /// freebsd -- Directly call GNU Binutils assembler and linker namespace freebsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: Assembler(const ToolChain &TC) - : GnuTool("freebsd::Assembler", "assembler", TC) {} + : Tool("freebsd::Assembler", "assembler", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -32,9 +32,9 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("freebsd::Linker", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("freebsd::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } @@ -59,16 +59,20 @@ public: bool IsObjCNonFragileABIDefault() const override { return true; } CXXStdlibType GetDefaultCXXStdlibType() const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; - llvm::ExceptionHandling GetExceptionModel( - const llvm::opt::ArgList &Args) const override; + llvm::ExceptionHandling + GetExceptionModel(const llvm::opt::ArgList &Args) const override; bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp index 808d0408d0d4..94e025e3055a 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -15,6 +15,7 @@ #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/VirtualFileSystem.h" @@ -47,6 +48,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_w); CmdArgs.push_back("-z"); + CmdArgs.push_back("max-page-size=4096"); + + CmdArgs.push_back("-z"); CmdArgs.push_back("now"); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); @@ -56,6 +60,7 @@ 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("--pack-dyn-relocs=relr"); } if (!D.SysRoot.empty()) @@ -111,7 +116,7 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); - AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); } @@ -159,7 +164,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lc"); } - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } /// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. @@ -174,7 +180,7 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, if (!D.SysRoot.empty()) { SmallString<128> P(D.SysRoot); llvm::sys::path::append(P, "lib"); - getFilePaths().push_back(P.str()); + getFilePaths().push_back(std::string(P.str())); } auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> { @@ -183,7 +189,7 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, if (auto CXXStdlibPath = getCXXStdlibPath()) { SmallString<128> P(*CXXStdlibPath); llvm::sys::path::append(P, M.gccSuffix()); - FP.push_back(P.str()); + FP.push_back(std::string(P.str())); } } return FP; @@ -289,7 +295,7 @@ void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, CIncludeDirs.split(dirs, ":"); for (StringRef dir : dirs) { StringRef Prefix = - llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot); addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); } return; @@ -340,6 +346,7 @@ SanitizerMask Fuchsia::getSupportedSanitizers() const { Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::Leak; Res |= SanitizerKind::SafeStack; Res |= SanitizerKind::Scudo; return Res; @@ -360,3 +367,13 @@ 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 fee0e018f3ce..3159a54bda06 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.h +++ b/clang/lib/Driver/ToolChains/Fuchsia.h @@ -69,6 +69,9 @@ 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 da197e476621..c8a7fce07ef1 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -35,8 +35,7 @@ using namespace clang; using namespace llvm::opt; using tools::addMultilibFlag; - -void tools::GnuTool::anchor() {} +using tools::addPathIfExists; static bool forwardToGCC(const Option &O) { // Don't forward inputs from the original command line. They are added from @@ -189,7 +188,8 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, GCCName = "gcc"; const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void tools::gcc::Preprocessor::RenderExtraToolArgs( @@ -304,12 +304,14 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { if (T.getEnvironment() == llvm::Triple::GNUX32) return "elf32_x86_64"; return "elf_x86_64"; + case llvm::Triple::ve: + return "elf64ve"; default: return nullptr; } } -static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) { +static bool getPIE(const ArgList &Args, const ToolChain &TC) { if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_r) || Args.hasArg(options::OPT_static_pie)) return false; @@ -317,17 +319,16 @@ static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) { Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, options::OPT_nopie); if (!A) - return ToolChain.isPIEDefault(); + return TC.isPIEDefault(); return A->getOption().matches(options::OPT_pie); } -static bool getStaticPIE(const ArgList &Args, - const toolchains::Linux &ToolChain) { +static bool getStaticPIE(const ArgList &Args, const ToolChain &TC) { bool HasStaticPIE = Args.hasArg(options::OPT_static_pie); // -no-pie is an alias for -nopie. So, handling -nopie takes care of // -no-pie as well. if (HasStaticPIE && Args.hasArg(options::OPT_nopie)) { - const Driver &D = ToolChain.getDriver(); + const Driver &D = TC.getDriver(); const llvm::opt::OptTable &Opts = D.getOpts(); const char *StaticPIEName = Opts.getOptionName(options::OPT_static_pie); const char *NoPIEName = Opts.getOptionName(options::OPT_nopie); @@ -341,13 +342,55 @@ static bool getStatic(const ArgList &Args) { !Args.hasArg(options::OPT_static_pie); } +void tools::gnutools::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); + + // GNU ar tool command "ar <options> <output_file> <input_files>". + ArgStringList CmdArgs; + // Create and insert file members with a deterministic index. + CmdArgs.push_back("rcsD"); + CmdArgs.push_back(Output.getFilename()); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + // Delete old output archive file if it already exists before generating a new + // archive file. + 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::AtFileCurCP(), Exec, CmdArgs, Inputs)); +} + void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::Linux &ToolChain = - static_cast<const toolchains::Linux &>(getToolChain()); + // FIXME: The Linker class constructor takes a ToolChain and not a + // Generic_ELF, so the static_cast might return a reference to a invalid + // instance (see PR45061). Ideally, the Linker constructor needs to take a + // Generic_ELF instead. + const toolchains::Generic_ELF &ToolChain = + static_cast<const toolchains::Generic_ELF &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); @@ -355,6 +398,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool isAndroid = ToolChain.getTriple().isAndroid(); const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); + const bool IsVE = ToolChain.getTriple().isVE(); const bool IsPIE = getPIE(Args, ToolChain); const bool IsStaticPIE = getStaticPIE(Args, ToolChain); const bool IsStatic = getStatic(Args); @@ -418,8 +462,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (isAndroid) CmdArgs.push_back("--warn-shared-textrel"); - for (const auto &Opt : ToolChain.ExtraOpts) - CmdArgs.push_back(Opt.c_str()); + ToolChain.addExtraOpts(CmdArgs); CmdArgs.push_back("--eh-frame-hdr"); @@ -446,10 +489,9 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-export-dynamic"); if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE) { - const std::string Loader = - D.DyldPrefix + ToolChain.getDynamicLinker(Args); CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back(Args.MakeArgString(Loader)); + CmdArgs.push_back(Args.MakeArgString(Twine(D.DyldPrefix) + + ToolChain.getDynamicLinker(Args))); } } @@ -475,6 +517,11 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); } + if (IsVE) { + CmdArgs.push_back("-z"); + CmdArgs.push_back("max-page-size=0x4000000"); + } + if (IsIAMCU) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); else if (HasCRTBeginEndFiles) { @@ -502,7 +549,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } // Add crtfastmath.o if available and fast math is enabled. - ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs); + ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs); } Args.AddAllArgs(CmdArgs, options::OPT_L); @@ -512,7 +559,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); - AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); } @@ -623,12 +670,11 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - // Add HIP offloading linker script args if required. - AddHIPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA, - *this); + Args.AddAllArgs(CmdArgs, options::OPT_T); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void tools::gnutools::Assembler::ConstructJob(Compilation &C, @@ -646,6 +692,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; + const char *DefaultAssembler = "as"; std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(getToolChain(), Args); @@ -866,6 +913,8 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); break; } + case llvm::Triple::ve: + DefaultAssembler = "nas"; } for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, @@ -890,8 +939,10 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath(DefaultAssembler)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); // Handle the debug info splitting at object creation time if we're // creating an object. @@ -1527,7 +1578,7 @@ static void findRISCVBareMetalMultilibs(const Driver &D, }; // currently only support the set of multilibs like riscv-gnu-toolchain does. // TODO: support MULTILIB_REUSE - SmallVector<RiscvMultilib, 8> RISCVMultilibSet = { + constexpr RiscvMultilib RISCVMultilibSet[] = { {"rv32i", "ilp32"}, {"rv32im", "ilp32"}, {"rv32iac", "ilp32"}, {"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"}, {"rv64imafdc", "lp64d"}}; @@ -1767,7 +1818,7 @@ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { StringRef MinorStr = Second.first; if (Second.second.empty()) { if (size_t EndNumber = MinorStr.find_first_not_of("0123456789")) { - GoodVersion.PatchSuffix = MinorStr.substr(EndNumber); + GoodVersion.PatchSuffix = std::string(MinorStr.substr(EndNumber)); MinorStr = MinorStr.slice(0, EndNumber); } } @@ -1793,7 +1844,7 @@ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || GoodVersion.Patch < 0) return BadVersion; - GoodVersion.PatchSuffix = PatchText.substr(EndNumber); + GoodVersion.PatchSuffix = std::string(PatchText.substr(EndNumber)); } } @@ -1848,7 +1899,7 @@ void Generic_GCC::GCCInstallationDetector::init( if (GCCToolchainDir.back() == '/') GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the / - Prefixes.push_back(GCCToolchainDir); + Prefixes.push_back(std::string(GCCToolchainDir)); } else { // If we have a SysRoot, try that first. if (!D.SysRoot.empty()) { @@ -1975,6 +2026,7 @@ 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. + Prefixes.push_back("/opt/rh/devtoolset-9/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-8/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-7/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); @@ -2090,6 +2142,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu", "riscv64-linux-gnu", "riscv64-unknown-elf", + "riscv64-redhat-linux", "riscv64-suse-linux"}; static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; @@ -2460,7 +2513,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( StringRef VersionText = llvm::sys::path::filename(LI->path()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(LI->path()).second) + if (!CandidateGCCInstallPaths.insert(std::string(LI->path())).second) continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; @@ -2572,7 +2625,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), GCCInstallation(D), - CudaInstallation(D, Triple, Args) { + CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -2605,6 +2658,7 @@ void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { // Print the information about how we detected the GCC installation. GCCInstallation.print(OS); CudaInstallation.print(OS); + RocmInstallation.print(OS); } bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const { @@ -2666,6 +2720,140 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { } } +static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, + const Multilib &Multilib, + StringRef InstallPath, + ToolChain::path_list &Paths) { + if (const auto &PathsCallback = Multilibs.filePathsCallback()) + for (const auto &Path : PathsCallback(Multilib)) + addPathIfExists(D, InstallPath + Path, Paths); +} + +void Generic_GCC::PushPPaths(ToolChain::path_list &PPaths) { + // Cross-compiling binutils and GCC installations (vanilla and openSUSE at + // least) put various tools in a triple-prefixed directory off of the parent + // of the GCC installation. We use the GCC triple here to ensure that we end + // up with tools that support the same amount of cross compiling as the + // detected GCC installation. For example, if we find a GCC installation + // targeting x86_64, but it is a bi-arch GCC installation, it can also be + // used to target i386. + if (GCCInstallation.isValid()) { + PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple().str() + "/bin") + .str()); + } +} + +void Generic_GCC::AddMultilibPaths(const Driver &D, + const std::string &SysRoot, + const std::string &OSLibDir, + const std::string &MultiarchTriple, + path_list &Paths) { + // Add the multilib suffixed paths where they are available. + if (GCCInstallation.isValid()) { + const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); + const std::string &LibPath = + std::string(GCCInstallation.getParentLibPath()); + + // Add toolchain / multilib specific file paths. + addMultilibsFilePaths(D, Multilibs, SelectedMultilib, + GCCInstallation.getInstallPath(), Paths); + + // Sourcery CodeBench MIPS toolchain holds some libraries under + // a biarch-like suffix of the GCC installation. + addPathIfExists( + D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(), + Paths); + + // GCC cross compiling toolchains will install target libraries which ship + // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as + // any part of the GCC installation in + // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat + // debatable, but is the reality today. We need to search this tree even + // when we have a sysroot somewhere else. It is the responsibility of + // whomever is doing the cross build targeting a sysroot using a GCC + // installation that is *not* within the system root to ensure two things: + // + // 1) Any DSOs that are linked in from this tree or from the install path + // above must be present on the system root and found via an + // appropriate rpath. + // 2) There must not be libraries installed into + // <prefix>/<triple>/<libdir> unless they should be preferred over + // those within the system root. + // + // Note that this matches the GCC behavior. See the below comment for where + // Clang diverges from GCC's behavior. + addPathIfExists(D, + LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + + SelectedMultilib.osSuffix(), + Paths); + + // If the GCC installation we found is inside of the sysroot, we want to + // prefer libraries installed in the parent prefix of the GCC installation. + // It is important to *not* use these paths when the GCC installation is + // outside of the system root as that can pick up unintended libraries. + // This usually happens when there is an external cross compiler on the + // host system, and a more minimal sysroot available that is the target of + // the cross. Note that GCC does include some of these directories in some + // configurations but this seems somewhere between questionable and simply + // a bug. + if (StringRef(LibPath).startswith(SysRoot)) { + addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); + addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); + } + } +} + +void Generic_GCC::AddMultiarchPaths(const Driver &D, + const std::string &SysRoot, + const std::string &OSLibDir, + path_list &Paths) { + // Try walking via the GCC triple path in case of biarch or multiarch GCC + // installations with strange symlinks. + if (GCCInstallation.isValid()) { + addPathIfExists(D, + SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + + "/../../" + OSLibDir, + Paths); + + // Add the 'other' biarch variant path + Multilib BiarchSibling; + if (GCCInstallation.getBiarchSibling(BiarchSibling)) { + addPathIfExists( + D, GCCInstallation.getInstallPath() + BiarchSibling.gccSuffix(), + Paths); + } + + // See comments above on the multilib variant for details of why this is + // included even from outside the sysroot. + const std::string &LibPath = + std::string(GCCInstallation.getParentLibPath()); + const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + addPathIfExists( + D, LibPath + "/../" + GCCTriple.str() + "/lib" + Multilib.osSuffix(), + Paths); + + // See comments above on the multilib variant for details of why this is + // only included from within the sysroot. + if (StringRef(LibPath).startswith(SysRoot)) + addPathIfExists(D, LibPath, Paths); + } +} + +void Generic_GCC::AddMultilibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + // Add include directories specific to the selected multilib set and multilib. + if (GCCInstallation.isValid()) { + const auto &Callback = Multilibs.includeDirsCallback(); + if (Callback) { + for (const auto &Path : Callback(GCCInstallation.getMultilib())) + addExternCSystemIncludeIfExists( + DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); + } + } +} + void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdlibinc) || @@ -2696,7 +2884,7 @@ static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { if (Version > MaxVersion) { MaxVersion = Version; - MaxVersionString = VersionText; + MaxVersionString = std::string(VersionText); } } } @@ -2706,7 +2894,6 @@ static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, void Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - const std::string& SysRoot = getDriver().SysRoot; auto AddIncludePath = [&](std::string Path) { std::string IncludePath = DetectLibcxxIncludePath(getVFS(), Path); if (IncludePath.empty() || !getVFS().exists(IncludePath)) @@ -2722,6 +2909,7 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, // If this is a development, non-installed, clang, libcxx will // not be found at ../include/c++ but it likely to be found at // one of the following two locations: + std::string SysRoot = computeSysRoot(); if (AddIncludePath(SysRoot + "/usr/local/include/c++")) return; if (AddIncludePath(SysRoot + "/usr/include/c++")) diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 083f74c05477..52690ab4b83c 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H #include "Cuda.h" +#include "ROCm.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" #include <set> @@ -35,23 +36,26 @@ bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, namespace tools { -/// Base class for all GNU tools that provide the same behavior when -/// it comes to response files support -class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool { - virtual void anchor(); - +/// Directly call GNU Binutils' assembler and linker. +namespace gnutools { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: - GnuTool(const char *Name, const char *ShortName, const ToolChain &TC) - : Tool(Name, ShortName, TC, RF_Full, llvm::sys::WEM_CurrentCodePage) {} + Assembler(const ToolChain &TC) : Tool("GNU::Assembler", "assembler", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; }; -/// Directly call GNU Binutils' assembler and linker. -namespace gnutools { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Assembler(const ToolChain &TC) : GnuTool("GNU::Assembler", "assembler", TC) {} + Linker(const ToolChain &TC) : Tool("GNU::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -59,9 +63,10 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY StaticLibTool : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("GNU::Linker", "linker", TC) {} + StaticLibTool(const ToolChain &TC) + : Tool("GNU::StaticLibTool", "static-lib-linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } @@ -75,10 +80,10 @@ public: /// gcc - Generic GCC tool implementations. namespace gcc { -class LLVM_LIBRARY_VISIBILITY Common : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Common : public Tool { public: Common(const char *Name, const char *ShortName, const ToolChain &TC) - : GnuTool(Name, ShortName, TC) {} + : Tool(Name, ShortName, TC) {} // A gcc tool has an "integrated" assembler that it will call to produce an // object. Let it use that assembler so that we don't have to deal with @@ -278,6 +283,7 @@ public: protected: GCCInstallationDetector GCCInstallation; CudaInstallationDetector CudaInstallation; + RocmInstallationDetector RocmInstallation; public: Generic_GCC(const Driver &D, const llvm::Triple &Triple, @@ -314,6 +320,16 @@ protected: /// Check whether the target triple's architecture is 32-bits. bool isTarget32Bit() const { return getTriple().isArch32Bit(); } + void PushPPaths(ToolChain::path_list &PPaths); + void AddMultilibPaths(const Driver &D, const std::string &SysRoot, + const std::string &OSLibDir, + const std::string &MultiarchTriple, + path_list &Paths); + void AddMultiarchPaths(const Driver &D, const std::string &SysRoot, + const std::string &OSLibDir, path_list &Paths); + void AddMultilibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + // FIXME: This should be final, but the CrossWindows toolchain does weird // things that can't be easily generalized. void AddClangCXXStdlibIncludeArgs( @@ -356,6 +372,12 @@ public: void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + + virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const { + return {}; + } + + virtual void addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {} }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index f89e648948ab..7d17f809690e 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "HIP.h" +#include "AMDGPU.h" #include "CommonArgs.h" #include "InputInfo.h" #include "clang/Basic/Cuda.h" @@ -16,6 +17,7 @@ #include "clang/Driver/Options.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TargetParser.h" using namespace clang::driver; using namespace clang::driver::toolchains; @@ -47,159 +49,51 @@ static void addBCLib(const Driver &D, const ArgList &Args, } D.Diag(diag::err_drv_no_such_file) << BCName; } - -static const char *getOutputFileName(Compilation &C, StringRef Base, - const char *Postfix, - const char *Extension) { - const char *OutputFileName; - if (C.getDriver().isSaveTempsEnabled()) { - OutputFileName = - C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension); - } else { - std::string TmpName = - C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension); - OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName)); - } - return OutputFileName; -} - -static void addOptLevelArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - bool IsLlc = false) { - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - StringRef OOpt = "3"; - if (A->getOption().matches(options::OPT_O4) || - A->getOption().matches(options::OPT_Ofast)) - OOpt = "3"; - else if (A->getOption().matches(options::OPT_O0)) - OOpt = "0"; - else if (A->getOption().matches(options::OPT_O)) { - // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3 - // so we map -Os/-Oz to -O2. - // Only clang supports -Og, and maps it to -O1. - // We map anything else to -O2. - OOpt = llvm::StringSwitch<const char *>(A->getValue()) - .Case("1", "1") - .Case("2", "2") - .Case("3", "3") - .Case("s", IsLlc ? "2" : "s") - .Case("z", IsLlc ? "2" : "z") - .Case("g", "1") - .Default("2"); - } - CmdArgs.push_back(Args.MakeArgString("-O" + OOpt)); - } -} } // namespace -const char *AMDGCN::Linker::constructLLVMLinkCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const ArgList &Args, StringRef SubArchName, - StringRef OutputFilePrefix) const { - ArgStringList CmdArgs; - // Add the input bc's created by compile step. - for (const auto &II : Inputs) - CmdArgs.push_back(II.getFilename()); - - // Add an intermediate output file. - CmdArgs.push_back("-o"); - auto OutputFileName = getOutputFileName(C, OutputFilePrefix, "-linked", "bc"); - CmdArgs.push_back(OutputFileName); - SmallString<128> ExecPath(C.getDriver().Dir); - llvm::sys::path::append(ExecPath, "llvm-link"); - const char *Exec = Args.MakeArgString(ExecPath); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); - return OutputFileName; -} - -const char *AMDGCN::Linker::constructOptCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix, const char *InputFileName) const { - // Construct opt command. - ArgStringList OptArgs; - // The input to opt is the output from llvm-link. - OptArgs.push_back(InputFileName); - // Pass optimization arg to opt. - addOptLevelArgs(Args, OptArgs); - OptArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); - OptArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); - - for (const Arg *A : Args.filtered(options::OPT_mllvm)) { - OptArgs.push_back(A->getValue(0)); - } - - OptArgs.push_back("-o"); - auto OutputFileName = - getOutputFileName(C, OutputFilePrefix, "-optimized", "bc"); - OptArgs.push_back(OutputFileName); - SmallString<128> OptPath(C.getDriver().Dir); - llvm::sys::path::append(OptPath, "opt"); - const char *OptExec = Args.MakeArgString(OptPath); - C.addCommand(std::make_unique<Command>(JA, *this, OptExec, OptArgs, Inputs)); - return OutputFileName; -} +void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args) const { + // Construct lld command. + // The output from ld.lld is an HSA code object file. + ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", "-shared", + "-plugin-opt=-amdgpu-internalize-symbols"}; -const char *AMDGCN::Linker::constructLlcCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix, const char *InputFileName, - bool OutputIsAsm) const { - // Construct llc command. - ArgStringList LlcArgs; - // The input to llc is the output from opt. - LlcArgs.push_back(InputFileName); - // Pass optimization arg to llc. - addOptLevelArgs(Args, LlcArgs, /*IsLlc=*/true); - LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); - LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); - LlcArgs.push_back( - Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj"))); + auto &TC = getToolChain(); + auto &D = TC.getDriver(); + assert(!Inputs.empty() && "Must have at least one input."); + addLTOOptions(TC, Args, LldArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); // Extract all the -m options std::vector<llvm::StringRef> Features; - handleTargetFeaturesGroup( - Args, Features, options::OPT_m_amdgpu_Features_Group); + amdgpu::getAMDGPUTargetFeatures(D, Args, Features); - // Add features to mattr such as xnack - std::string MAttrString = "-mattr="; - for(auto OneFeature : Features) { + // Add features to mattr such as cumode + std::string MAttrString = "-plugin-opt=-mattr="; + for (auto OneFeature : unifyTargetFeatures(Features)) { MAttrString.append(Args.MakeArgString(OneFeature)); if (OneFeature != Features.back()) MAttrString.append(","); } - if(!Features.empty()) - LlcArgs.push_back(Args.MakeArgString(MAttrString)); + if (!Features.empty()) + LldArgs.push_back(Args.MakeArgString(MAttrString)); for (const Arg *A : Args.filtered(options::OPT_mllvm)) { - LlcArgs.push_back(A->getValue(0)); + LldArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0))); } - // Add output filename - LlcArgs.push_back("-o"); - auto LlcOutputFile = - getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o"); - LlcArgs.push_back(LlcOutputFile); - SmallString<128> LlcPath(C.getDriver().Dir); - llvm::sys::path::append(LlcPath, "llc"); - const char *Llc = Args.MakeArgString(LlcPath); - C.addCommand(std::make_unique<Command>(JA, *this, Llc, LlcArgs, Inputs)); - return LlcOutputFile; -} - -void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const InputInfo &Output, - const llvm::opt::ArgList &Args, - const char *InputFileName) const { - // Construct lld command. - // The output from ld.lld is an HSA code object file. - ArgStringList LldArgs{ - "-flavor", "gnu", "-shared", "-o", Output.getFilename(), InputFileName}; - SmallString<128> LldPath(C.getDriver().Dir); - llvm::sys::path::append(LldPath, "lld"); - const char *Lld = Args.MakeArgString(LldPath); - C.addCommand(std::make_unique<Command>(JA, *this, Lld, LldArgs, Inputs)); + if (C.getDriver().isSaveTempsEnabled()) + LldArgs.push_back("-save-temps"); + + LldArgs.append({"-o", Output.getFilename()}); + for (auto Input : Inputs) + LldArgs.push_back(Input.getFilename()); + const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Lld, LldArgs, Inputs)); } // Construct a clang-offload-bundler command to bundle code objects for @@ -226,14 +120,84 @@ void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg)); BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg)); - auto BundlerOutputArg = - Args.MakeArgString(std::string("-outputs=").append(OutputFileName)); + auto BundlerOutputArg = Args.MakeArgString( + std::string("-outputs=").append(std::string(OutputFileName))); BundlerArgs.push_back(BundlerOutputArg); - SmallString<128> BundlerPath(C.getDriver().Dir); - llvm::sys::path::append(BundlerPath, "clang-offload-bundler"); - const char *Bundler = Args.MakeArgString(BundlerPath); - C.addCommand(std::make_unique<Command>(JA, T, Bundler, BundlerArgs, Inputs)); + const char *Bundler = Args.MakeArgString( + T.getToolChain().GetProgramPath("clang-offload-bundler")); + C.addCommand(std::make_unique<Command>(JA, T, ResponseFileSupport::None(), + Bundler, BundlerArgs, Inputs)); +} + +/// Add Generated HIP Object File which has device images embedded into the +/// host to the argument list for linking. Using MC directives, embed the +/// device code and also define symbols required by the code generation so that +/// the image can be retrieved at runtime. +void AMDGCN::Linker::constructGenerateObjFileFromHIPFatBinary( + Compilation &C, const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + const JobAction &JA) const { + const ToolChain &TC = getToolChain(); + std::string Name = + std::string(llvm::sys::path::stem(Output.getFilename())); + + // Create Temp Object File Generator, + // Offload Bundled file and Bundled Object file. + // Keep them if save-temps is enabled. + const char *McinFile; + const char *BundleFile; + if (C.getDriver().isSaveTempsEnabled()) { + McinFile = C.getArgs().MakeArgString(Name + ".mcin"); + BundleFile = C.getArgs().MakeArgString(Name + ".hipfb"); + } else { + auto TmpNameMcin = C.getDriver().GetTemporaryPath(Name, "mcin"); + McinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin)); + auto TmpNameFb = C.getDriver().GetTemporaryPath(Name, "hipfb"); + BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameFb)); + } + constructHIPFatbinCommand(C, JA, BundleFile, Inputs, Args, *this); + + // Create a buffer to write the contents of the temp obj generator. + std::string ObjBuffer; + llvm::raw_string_ostream ObjStream(ObjBuffer); + + // Add MC directives to embed target binaries. We ensure that each + // section and image is 16-byte aligned. This is not mandatory, but + // increases the likelihood of data to be aligned with a cache block + // in several main host machines. + ObjStream << "# HIP Object Generator\n"; + ObjStream << "# *** Automatically generated by Clang ***\n"; + ObjStream << " .type __hip_fatbin,@object\n"; + ObjStream << " .section .hip_fatbin,\"aMS\",@progbits,1\n"; + ObjStream << " .data\n"; + ObjStream << " .globl __hip_fatbin\n"; + ObjStream << " .p2align 3\n"; + ObjStream << "__hip_fatbin:\n"; + ObjStream << " .incbin \"" << BundleFile << "\"\n"; + ObjStream.flush(); + + // Dump the contents of the temp object file gen if the user requested that. + // We support this option to enable testing of behavior with -###. + if (C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script)) + llvm::errs() << ObjBuffer; + + // Open script file and write the contents. + std::error_code EC; + llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None); + + if (EC) { + C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return; + } + + Objf << ObjBuffer; + + ArgStringList McArgs{"-o", Output.getFilename(), + McinFile, "--filetype=obj"}; + const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc")); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Mc, McArgs, Inputs)); } // For amdgcn the inputs of the linker job are device bitcode and output is @@ -243,37 +207,20 @@ void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + if (Inputs.size() > 0 && + Inputs[0].getType() == types::TY_Image && + JA.getType() == types::TY_Object) + return constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, Args, JA); if (JA.getType() == types::TY_HIP_FATBIN) return constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, Args, *this); - assert(getToolChain().getTriple().getArch() == llvm::Triple::amdgcn && - "Unsupported target"); - - std::string SubArchName = JA.getOffloadingArch(); - assert(StringRef(SubArchName).startswith("gfx") && "Unsupported sub arch"); - - // Prefix for temporary file name. - std::string Prefix = llvm::sys::path::stem(Inputs[0].getFilename()).str(); - if (!C.getDriver().isSaveTempsEnabled()) - Prefix += "-" + SubArchName; - - // Each command outputs different files. - const char *LLVMLinkCommand = - constructLLVMLinkCommand(C, JA, Inputs, Args, SubArchName, Prefix); - const char *OptCommand = constructOptCommand(C, JA, Inputs, Args, SubArchName, - Prefix, LLVMLinkCommand); - if (C.getDriver().isSaveTempsEnabled()) - constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, OptCommand, - /*OutputIsAsm=*/true); - const char *LlcCommand = - constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, OptCommand); - constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand); + return constructLldCommand(C, JA, Inputs, Output, Args); } HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple, const ToolChain &HostTC, const ArgList &Args) - : ToolChain(D, Triple, Args), HostTC(HostTC) { + : ROCMToolChain(D, Triple, Args), HostTC(HostTC) { // Lookup binaries into the driver directory, this is used to // discover the clang-offload-bundler executable. getProgramPaths().push_back(getDriver().Dir); @@ -285,20 +232,16 @@ void HIPToolChain::addClangTargetOptions( Action::OffloadKind DeviceOffloadingKind) const { HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); - StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ); assert(!GpuArch.empty() && "Must have an explicit GPU arch."); (void) GpuArch; assert(DeviceOffloadingKind == Action::OFK_HIP && "Only HIP offloading kinds are supported for GPUs."); + auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); + const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); - CC1Args.push_back("-target-cpu"); - CC1Args.push_back(DriverArgs.MakeArgStringRef(GpuArch)); CC1Args.push_back("-fcuda-is-device"); - if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, - options::OPT_fno_cuda_flush_denormals_to_zero, false)) - CC1Args.push_back("-fcuda-flush-denormals-to-zero"); - if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, options::OPT_fno_cuda_approx_transcendentals, false)) CC1Args.push_back("-fcuda-approx-transcendentals"); @@ -306,6 +249,8 @@ void HIPToolChain::addClangTargetOptions( if (DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) CC1Args.push_back("-fgpu-rdc"); + else + CC1Args.append({"-mllvm", "-amdgpu-internalize-symbols"}); StringRef MaxThreadsPerBlock = DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ); @@ -334,46 +279,50 @@ void HIPToolChain::addClangTargetOptions( ArgStringList LibraryPaths; // Find in --hip-device-lib-path and HIP_LIBRARY_PATH. - for (auto Path : - DriverArgs.getAllArgValues(options::OPT_hip_device_lib_path_EQ)) + for (auto Path : RocmInstallation.getRocmDeviceLibPathArg()) LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); - addDirectoryList(DriverArgs, LibraryPaths, "-L", "HIP_DEVICE_LIB_PATH"); + addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH"); - llvm::SmallVector<std::string, 10> BCLibs; + // Maintain compatability with --hip-device-lib. + auto BCLibs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ); + if (!BCLibs.empty()) { + for (auto Lib : BCLibs) + addBCLib(getDriver(), DriverArgs, CC1Args, LibraryPaths, Lib); + } else { + if (!RocmInstallation.hasDeviceLibrary()) { + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; + return; + } - // Add bitcode library in --hip-device-lib. - for (auto Lib : DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ)) { - BCLibs.push_back(DriverArgs.MakeArgString(Lib)); - } + 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. - if (BCLibs.empty()) { - // Get the bc lib file name for ISA version. For example, - // gfx803 => oclc_isa_version_803.amdgcn.bc. - std::string GFXVersion = GpuArch.drop_front(3).str(); - std::string ISAVerBC = "oclc_isa_version_" + GFXVersion + ".amdgcn.bc"; - - llvm::StringRef FlushDenormalControlBC; - if (DriverArgs.hasArg(options::OPT_fcuda_flush_denormals_to_zero)) - FlushDenormalControlBC = "oclc_daz_opt_on.amdgcn.bc"; - else - FlushDenormalControlBC = "oclc_daz_opt_off.amdgcn.bc"; - - llvm::StringRef WaveFrontSizeBC; - if (stoi(GFXVersion) < 1000) - WaveFrontSizeBC = "oclc_wavefrontsize64_on.amdgcn.bc"; - else - WaveFrontSizeBC = "oclc_wavefrontsize64_off.amdgcn.bc"; - - BCLibs.append({"hip.amdgcn.bc", "ocml.amdgcn.bc", "ockl.amdgcn.bc", - "oclc_finite_only_off.amdgcn.bc", FlushDenormalControlBC, - "oclc_correctly_rounded_sqrt_on.amdgcn.bc", - "oclc_unsafe_math_off.amdgcn.bc", ISAVerBC, - WaveFrontSizeBC}); + // 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_fcuda_flush_denormals_to_zero, + options::OPT_fno_cuda_flush_denormals_to_zero, + getDefaultDenormsAreZeroForTarget(Kind)); + // TODO: Check standard C++ flags? + bool FiniteOnly = false; + bool UnsafeMathOpt = false; + bool FastRelaxedMath = false; + bool CorrectSqrt = true; + bool Wave64 = isWave64(DriverArgs, Kind); + + // Add the HIP specific bitcode library. + CC1Args.push_back("-mlink-builtin-bitcode"); + CC1Args.push_back(DriverArgs.MakeArgString(RocmInstallation.getHIPPath())); + + // Add the generic set of libraries. + RocmInstallation.addCommonBitcodeLibCC1Args( + DriverArgs, CC1Args, LibDeviceFile, Wave64, DAZ, FiniteOnly, + UnsafeMathOpt, FastRelaxedMath, CorrectSqrt); } - for (auto Lib : BCLibs) - addBCLib(getDriver(), DriverArgs, CC1Args, LibraryPaths, Lib); } llvm::opt::DerivedArgList * @@ -388,42 +337,12 @@ HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, const OptTable &Opts = getDriver().getOpts(); for (Arg *A : Args) { - if (A->getOption().matches(options::OPT_Xarch__)) { - // Skip this argument unless the architecture matches BoundArch. - if (BoundArch.empty() || A->getValue(0) != BoundArch) - continue; - - unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); - unsigned Prev = Index; - std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); - - // If the argument parsing failed or more than one argument was - // consumed, the -Xarch_ argument's parameter tried to consume - // extra arguments. Emit an error and ignore. - // - // We also want to disallow any options which would alter the - // driver behavior; that isn't going to work in our model. We - // use isDriverOption() as an approximation, although things - // like -O4 are going to slip through. - if (!XarchArg || Index > Prev + 1) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) - << A->getAsString(Args); - continue; - } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) - << A->getAsString(Args); - continue; - } - XarchArg->setBaseArg(A); - A = XarchArg.release(); - DAL->AddSynthesizedArg(A); - } DAL->append(A); } if (!BoundArch.empty()) { - DAL->eraseArg(options::OPT_march_EQ); - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); + DAL->eraseArg(options::OPT_mcpu_EQ); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), BoundArch); } return DAL; @@ -458,6 +377,11 @@ void HIPToolChain::AddIAMCUIncludeArgs(const ArgList &Args, HostTC.AddIAMCUIncludeArgs(Args, CC1Args); } +void HIPToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); +} + SanitizerMask HIPToolChain::getSupportedSanitizers() const { // The HIPToolChain only supports sanitizers in the sense that it allows // sanitizer arguments on the command line if they are supported by the host diff --git a/clang/lib/Driver/ToolChains/HIP.h b/clang/lib/Driver/ToolChains/HIP.h index c4f944e458bf..5e2be7138579 100644 --- a/clang/lib/Driver/ToolChains/HIP.h +++ b/clang/lib/Driver/ToolChains/HIP.h @@ -11,6 +11,7 @@ #include "clang/Driver/ToolChain.h" #include "clang/Driver/Tool.h" +#include "AMDGPU.h" namespace clang { namespace driver { @@ -37,34 +38,17 @@ public: const char *LinkingOutput) const override; 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; - - /// \return opt output file name. - const char *constructOptCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix, - const char *InputFileName) const; - - /// \return llc output file name. - const char *constructLlcCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix, - const char *InputFileName, - bool OutputIsAsm = false) const; void constructLldCommand(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const InputInfo &Output, - const llvm::opt::ArgList &Args, - const char *InputFileName) const; + const llvm::opt::ArgList &Args) const; + + // Construct command for creating Object from HIP fatbin. + void constructGenerateObjFileFromHIPFatBinary(Compilation &C, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + const JobAction &JA) const; }; } // end namespace AMDGCN @@ -72,7 +56,7 @@ private: namespace toolchains { -class LLVM_LIBRARY_VISIBILITY HIPToolChain : public ToolChain { +class LLVM_LIBRARY_VISIBILITY HIPToolChain final : public ROCMToolChain { public: HIPToolChain(const Driver &D, const llvm::Triple &Triple, const ToolChain &HostTC, const llvm::opt::ArgList &Args); @@ -106,6 +90,8 @@ public: llvm::opt::ArgStringList &CC1Args) const override; void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; SanitizerMask getSupportedSanitizers() const override; diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index e4d9ea8a70f9..775f6e1094fa 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -31,7 +31,6 @@ static StringRef getDefaultHvxLength(StringRef Cpu) { .Case("v60", "64b") .Case("v62", "64b") .Case("v65", "64b") - .Case("v66", "128b") .Default("128b"); } @@ -48,13 +47,12 @@ static void handleHVXWarnings(const Driver &D, const ArgList &Args) { // Handle hvx target features explicitly. static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, std::vector<StringRef> &Features, - bool &HasHVX) { + StringRef Cpu, bool &HasHVX) { // Handle HVX warnings. handleHVXWarnings(D, Args); // Add the +hvx* features based on commandline flags. StringRef HVXFeature, HVXLength; - StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args)); // Handle -mhvx, -mhvx=, -mno-hvx. if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx, @@ -108,7 +106,15 @@ void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args, Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls"); bool HasHVX = false; - handleHVXTargetFeatures(D, Args, Features, HasHVX); + StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args)); + // 't' in Cpu denotes tiny-core micro-architecture. For now, the co-processors + // have no dependency on micro-architecture. + const bool TinyCore = Cpu.contains('t'); + + if (TinyCore) + Cpu = Cpu.take_front(Cpu.size() - 1); + + handleHVXTargetFeatures(D, Args, Features, Cpu, HasHVX); if (HexagonToolChain::isAutoHVXEnabled(Args) && !HasHVX) D.Diag(diag::warn_drv_vectorize_needs_hvx); @@ -183,7 +189,8 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, } auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName)); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA, @@ -258,18 +265,43 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, UseG0 = G.getValue() == 0; } - //---------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------- CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); + if (HTC.getTriple().isMusl()) { + if (!Args.hasArg(options::OPT_shared, options::OPT_static)) + CmdArgs.push_back("-dynamic-linker=/lib/ld-musl-hexagon.so.1"); + + if (!Args.hasArg(options::OPT_shared, options::OPT_nostartfiles, + options::OPT_nostdlib)) + CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crt1.o")); + else if (Args.hasArg(options::OPT_shared) && + !Args.hasArg(options::OPT_nostartfiles, options::OPT_nostdlib)) + CmdArgs.push_back(Args.MakeArgString(D.SysRoot + "/usr/lib/crti.o")); + + CmdArgs.push_back( + Args.MakeArgString(StringRef("-L") + D.SysRoot + "/usr/lib")); + Args.AddAllArgs(CmdArgs, + {options::OPT_T_Group, options::OPT_e, options::OPT_s, + options::OPT_t, options::OPT_u_Group}); + AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + CmdArgs.push_back("-lclang_rt.builtins-hexagon"); + CmdArgs.push_back("-lc"); + } + if (D.CCCIsCXX()) { + if (HTC.ShouldLinkCXXStdlib(Args)) + HTC.AddCXXStdlibLibArgs(Args, CmdArgs); + } + return; + } + //---------------------------------------------------------------------------- // moslib //---------------------------------------------------------------------------- std::vector<std::string> OsLibs; bool HasStandalone = false; - for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) { A->claim(); OsLibs.emplace_back(A->getValue()); @@ -375,7 +407,8 @@ void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA, LinkingOutput); const char *Exec = Args.MakeArgString(HTC.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } // Hexagon tools end. @@ -481,6 +514,22 @@ HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, HexagonToolChain::~HexagonToolChain() {} +void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CXXStdlibType Type = GetCXXStdlibType(Args); + switch (Type) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); + break; + + case ToolChain::CST_Libstdcxx: + CmdArgs.push_back("-lstdc++"); + break; + } +} + Tool *HexagonToolChain::buildAssembler() const { return new tools::hexagon::Assembler(*this); } @@ -517,6 +566,14 @@ unsigned HexagonToolChain::getOptimizationLevel( void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { + + bool UseInitArrayDefault = getTriple().isMusl(); + + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, + UseInitArrayDefault)) + CC1Args.push_back("-fno-use-init-array"); + if (DriverArgs.hasArg(options::OPT_ffixed_r19)) { CC1Args.push_back("-target-feature"); CC1Args.push_back("+reserved-r19"); @@ -534,12 +591,37 @@ void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; const Driver &D = getDriver(); + if (!D.SysRoot.empty()) { + SmallString<128> P(D.SysRoot); + if (getTriple().isMusl()) + llvm::sys::path::append(P, "usr/include"); + else + llvm::sys::path::append(P, "include"); + addExternCSystemInclude(DriverArgs, CC1Args, P.str()); + return; + } + std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), D.PrefixDirs); addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); } - +void HexagonToolChain::addLibCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + if (!D.SysRoot.empty() && getTriple().isMusl()) + addLibStdCXXIncludePaths(D.SysRoot + "/usr/include/c++/v1", "", "", "", "", + "", DriverArgs, CC1Args); + else if (getTriple().isMusl()) + addLibStdCXXIncludePaths("/usr/include/c++/v1", "", "", "", "", "", + DriverArgs, CC1Args); + else { + std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); + addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++/v1", "", "", "", + "", DriverArgs, CC1Args); + } +} void HexagonToolChain::addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { @@ -552,14 +634,22 @@ void HexagonToolChain::addLibStdCxxIncludePaths( ToolChain::CXXStdlibType HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const { Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); - if (!A) - return ToolChain::CST_Libstdcxx; - + if (!A) { + if (getTriple().isMusl()) + return ToolChain::CST_Libcxx; + else + return ToolChain::CST_Libstdcxx; + } StringRef Value = A->getValue(); - if (Value != "libstdc++") + if (Value != "libstdc++" && Value != "libc++") getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); - return ToolChain::CST_Libstdcxx; + if (Value == "libstdc++") + return ToolChain::CST_Libstdcxx; + else if (Value == "libc++") + return ToolChain::CST_Libcxx; + else + return ToolChain::CST_Libstdcxx; } bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) { diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h index d7b4a13d3a4f..c32cb7f09591 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.h +++ b/clang/lib/Driver/ToolChains/Hexagon.h @@ -20,10 +20,10 @@ namespace hexagon { // For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile // and Compile. // We simply use "clang -cc1" for those actions. -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: Assembler(const ToolChain &TC) - : GnuTool("hexagon::Assembler", "hexagon-as", TC) {} + : Tool("hexagon::Assembler", "hexagon-as", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -35,9 +35,9 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("hexagon::Linker", "hexagon-ld", TC) {} + Linker(const ToolChain &TC) : Tool("hexagon::Linker", "hexagon-ld", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } @@ -81,10 +81,18 @@ public: const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - const char *getDefaultLinker() const override { return "hexagon-link"; } + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + const char *getDefaultLinker() const override { + return getTriple().isMusl() ? "ld.lld" : "hexagon-link"; + } CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } bool IsIntegratedAssemblerDefault() const override { return true; diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp index 72166ca9f359..a700d7b9064c 100644 --- a/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/clang/lib/Driver/ToolChains/Hurd.cpp @@ -61,21 +61,35 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { return Triple.isArch32Bit() ? "lib" : "lib64"; } -Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) +Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { + GCCInstallation.init(Triple, Args); + Multilibs = GCCInstallation.getMultilibs(); + SelectedMultilib = GCCInstallation.getMultilib(); std::string SysRoot = computeSysRoot(); + ToolChain::path_list &PPaths = getProgramPaths(); + + Generic_GCC::PushPPaths(PPaths); + + // The selection of paths to try here is designed to match the patterns which + // the GCC driver itself uses, as this is part of the GCC-compatible driver. + // This was determined by running GCC in a fake filesystem, creating all + // possible permutations of these directories, and seeing which ones it added + // to the link paths. path_list &Paths = getFilePaths(); - const std::string OSLibDir = getOSLibDir(Triple, Args); + const std::string OSLibDir = std::string(getOSLibDir(Triple, Args)); const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); #ifdef ENABLE_LINKER_BUILD_ID ExtraOpts.push_back("--build-id"); #endif - // If we are currently running Clang inside of the requested system root, add - // its parent library paths to those searched. + Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths); + + // Similar to the logic for GCC above, if we currently running Clang inside + // of the requested system root, add its parent library paths to + // those searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) { @@ -89,8 +103,11 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); - // If we are currently running Clang inside of the requested system root, add - // its parent library path to those searched. + Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths); + + // Similar to the logic for GCC above, if we are currently running Clang + // inside of the requested system root, add its parent library path to those + // searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) @@ -108,13 +125,6 @@ Tool *Hurd::buildAssembler() const { return new tools::gnutools::Assembler(*this); } -std::string Hurd::computeSysRoot() const { - if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot; - - return std::string(); -} - std::string Hurd::getDynamicLinker(const ArgList &Args) const { if (getArch() == llvm::Triple::x86) return "/lib/ld.so"; @@ -149,7 +159,7 @@ void Hurd::AddClangSystemIncludeArgs(const ArgList &DriverArgs, CIncludeDirs.split(Dirs, ":"); for (StringRef Dir : Dirs) { StringRef Prefix = - llvm::sys::path::is_absolute(Dir) ? StringRef(SysRoot) : ""; + llvm::sys::path::is_absolute(Dir) ? "" : StringRef(SysRoot); addExternCSystemInclude(DriverArgs, CC1Args, Prefix + Dir); } return; @@ -157,6 +167,9 @@ void Hurd::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Lacking those, try to detect the correct set of system includes for the // target triple. + + AddMultilibIncludeArgs(DriverArgs, CC1Args); + if (getTriple().getArch() == llvm::Triple::x86) { std::string Path = SysRoot + "/usr/include/i386-gnu"; if (D.getVFS().exists(Path)) @@ -170,3 +183,8 @@ void Hurd::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } + +void Hurd::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { + for (const auto &Opt : ExtraOpts) + CmdArgs.push_back(Opt.c_str()); +} diff --git a/clang/lib/Driver/ToolChains/Hurd.h b/clang/lib/Driver/ToolChains/Hurd.h index 86c6c3f734dd..0612a55280a8 100644 --- a/clang/lib/Driver/ToolChains/Hurd.h +++ b/clang/lib/Driver/ToolChains/Hurd.h @@ -27,9 +27,9 @@ public: AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - virtual std::string computeSysRoot() const; + std::string getDynamicLinker(const llvm::opt::ArgList &Args) const override; - virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const; + void addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const override; std::vector<std::string> ExtraOpts; diff --git a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp index 8f947e79bd1f..f7c11421e809 100644 --- a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp +++ b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp @@ -54,8 +54,9 @@ void Merger::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(InputFilename.c_str())); } - C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Merger), - CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Args.MakeArgString(Merger), CmdArgs, + Inputs)); } } // namespace ifstool } // namespace tools diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index bff1ab1009be..180350476c38 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -208,15 +208,6 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { return Triple.isArch32Bit() ? "lib" : "lib64"; } -static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, - const Multilib &Multilib, - StringRef InstallPath, - ToolChain::path_list &Paths) { - if (const auto &PathsCallback = Multilibs.filePathsCallback()) - for (const auto &Path : PathsCallback(Multilib)) - addPathIfExists(D, InstallPath + Path, Paths); -} - Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); @@ -224,21 +215,9 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) SelectedMultilib = GCCInstallation.getMultilib(); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); - - // Cross-compiling binutils and GCC installations (vanilla and openSUSE at - // least) put various tools in a triple-prefixed directory off of the parent - // of the GCC installation. We use the GCC triple here to ensure that we end - // up with tools that support the same amount of cross compiling as the - // detected GCC installation. For example, if we find a GCC installation - // targeting x86_64, but it is a bi-arch GCC installation, it can also be - // used to target i386. - // FIXME: This seems unlikely to be Linux-specific. ToolChain::path_list &PPaths = getProgramPaths(); - if (GCCInstallation.isValid()) { - PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + - GCCInstallation.getTriple().str() + "/bin") - .str()); - } + + Generic_GCC::PushPPaths(PPaths); Distro Distro(D.getVFS(), Triple); @@ -253,10 +232,9 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("relro"); } - // The lld default page size is too large for Aarch64, which produces much - // larger .so files and images for arm64 device targets. Use 4KB page size - // for Android arm64 targets instead. - if (Triple.isAArch64() && Triple.isAndroid()) { + // Android ARM/AArch64 use max-page-size=4096 to reduce VMA usage. Note, lld + // from 11 onwards default max-page-size to 65536 for both ARM and AArch64. + if ((Triple.isARM() || Triple.isAArch64()) && Triple.isAndroid()) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("max-page-size=4096"); } @@ -314,60 +292,10 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // to the link paths. path_list &Paths = getFilePaths(); - const std::string OSLibDir = getOSLibDir(Triple, Args); + const std::string OSLibDir = std::string(getOSLibDir(Triple, Args)); const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); - // Add the multilib suffixed paths where they are available. - if (GCCInstallation.isValid()) { - const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); - const std::string &LibPath = GCCInstallation.getParentLibPath(); - - // Add toolchain / multilib specific file paths. - addMultilibsFilePaths(D, Multilibs, SelectedMultilib, - GCCInstallation.getInstallPath(), Paths); - - // Sourcery CodeBench MIPS toolchain holds some libraries under - // a biarch-like suffix of the GCC installation. - addPathIfExists( - D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(), - Paths); - - // GCC cross compiling toolchains will install target libraries which ship - // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as - // any part of the GCC installation in - // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat - // debatable, but is the reality today. We need to search this tree even - // when we have a sysroot somewhere else. It is the responsibility of - // whomever is doing the cross build targeting a sysroot using a GCC - // installation that is *not* within the system root to ensure two things: - // - // 1) Any DSOs that are linked in from this tree or from the install path - // above must be present on the system root and found via an - // appropriate rpath. - // 2) There must not be libraries installed into - // <prefix>/<triple>/<libdir> unless they should be preferred over - // those within the system root. - // - // Note that this matches the GCC behavior. See the below comment for where - // Clang diverges from GCC's behavior. - addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + - OSLibDir + SelectedMultilib.osSuffix(), - Paths); - - // If the GCC installation we found is inside of the sysroot, we want to - // prefer libraries installed in the parent prefix of the GCC installation. - // It is important to *not* use these paths when the GCC installation is - // outside of the system root as that can pick up unintended libraries. - // This usually happens when there is an external cross compiler on the - // host system, and a more minimal sysroot available that is the target of - // the cross. Note that GCC does include some of these directories in some - // configurations but this seems somewhere between questionable and simply - // a bug. - if (StringRef(LibPath).startswith(SysRoot)) { - addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); - addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); - } - } + Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths); // Similar to the logic for GCC above, if we currently running Clang inside // of the requested system root, add its parent library paths to @@ -411,36 +339,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) addPathIfExists(D, SysRoot + "/usr/" + OSLibDir + "/" + ABIName, Paths); } - // Try walking via the GCC triple path in case of biarch or multiarch GCC - // installations with strange symlinks. - if (GCCInstallation.isValid()) { - addPathIfExists(D, - SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + - "/../../" + OSLibDir, - Paths); - - // Add the 'other' biarch variant path - Multilib BiarchSibling; - if (GCCInstallation.getBiarchSibling(BiarchSibling)) { - addPathIfExists(D, GCCInstallation.getInstallPath() + - BiarchSibling.gccSuffix(), - Paths); - } - - // See comments above on the multilib variant for details of why this is - // included even from outside the sysroot. - const std::string &LibPath = GCCInstallation.getParentLibPath(); - const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + - Multilib.osSuffix(), - Paths); - - // See comments above on the multilib variant for details of why this is - // only included from within the sysroot. - if (StringRef(LibPath).startswith(SysRoot)) - addPathIfExists(D, LibPath, Paths); - } + Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths); // Similar to the logic for GCC above, if we are currently running Clang // inside of the requested system root, add its parent library path to those @@ -464,6 +363,10 @@ bool Linux::HasNativeLLVMSupport() const { return true; } Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); } +Tool *Linux::buildStaticLibTool() const { + return new tools::gnutools::StaticLibTool(*this); +} + Tool *Linux::buildAssembler() const { return new tools::gnutools::Assembler(*this); } @@ -638,6 +541,8 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { Loader = X32 ? "ld-linux-x32.so.2" : "ld-linux-x86-64.so.2"; break; } + case llvm::Triple::ve: + return "/opt/nec/ve/lib/ld-linux-ve.so.1"; } if (Distro == Distro::Exherbo && @@ -674,7 +579,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, CIncludeDirs.split(dirs, ":"); for (StringRef dir : dirs) { StringRef Prefix = - llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : ""; + llvm::sys::path::is_absolute(dir) ? "" : StringRef(SysRoot); addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); } return; @@ -683,15 +588,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Lacking those, try to detect the correct set of system includes for the // target triple. - // Add include directories specific to the selected multilib set and multilib. - if (GCCInstallation.isValid()) { - const auto &Callback = Multilibs.includeDirsCallback(); - if (Callback) { - for (const auto &Path : Callback(GCCInstallation.getMultilib())) - addExternCSystemIncludeIfExists( - DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); - } - } + AddMultilibIncludeArgs(DriverArgs, CC1Args); // Implement generic Debian multiarch support. const StringRef X86_64MultiarchIncludeDirs[] = { @@ -906,6 +803,11 @@ void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } +void Linux::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); +} + void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (GCCInstallation.isValid()) { @@ -944,6 +846,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { getTriple().getArch() == llvm::Triple::thumb || getTriple().getArch() == llvm::Triple::armeb || getTriple().getArch() == llvm::Triple::thumbeb; + const bool IsSystemZ = getTriple().getArch() == llvm::Triple::systemz; SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; @@ -956,7 +859,8 @@ SanitizerMask Linux::getSupportedSanitizers() const { Res |= SanitizerKind::SafeStack; if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::DataFlow; - if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64) + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 || + IsSystemZ) Res |= SanitizerKind::Leak; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) Res |= SanitizerKind::Thread; @@ -976,13 +880,34 @@ SanitizerMask Linux::getSupportedSanitizers() const { void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { - if (!needsProfileRT(Args)) return; - - // Add linker option -u__llvm_runtime_variable to cause runtime + // Add linker option -u__llvm_profile_runtime to cause runtime // initialization module to be linked in. - if ((!Args.hasArg(options::OPT_coverage)) && - (!Args.hasArg(options::OPT_ftest_coverage))) + if (needsProfileRT(Args)) CmdArgs.push_back(Args.MakeArgString( Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); ToolChain::addProfileRTLibs(Args, CmdArgs); } + +llvm::DenormalMode +Linux::getDefaultDenormalModeForType(const llvm::opt::ArgList &DriverArgs, + const JobAction &JA, + const llvm::fltSemantics *FPType) const { + switch (getTriple().getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: { + std::string Unused; + // DAZ and FTZ are turned on in crtfastmath.o + if (!DriverArgs.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && + isFastMathRuntimeAvailable(DriverArgs, Unused)) + return llvm::DenormalMode::getPreserveSign(); + return llvm::DenormalMode::getIEEE(); + } + default: + return llvm::DenormalMode::getIEEE(); + } +} + +void Linux::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { + for (const auto &Opt : ExtraOpts) + CmdArgs.push_back(Opt.c_str()); +} diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index f5518eac218a..6b16b0e64990 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -31,6 +31,8 @@ public: llvm::opt::ArgStringList &CC1Args) const override; void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetDefaultCXXStdlibType() const override; @@ -40,15 +42,22 @@ public: SanitizerMask getSupportedSanitizers() const override; void addProfileRTLibs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - virtual std::string computeSysRoot() const; + std::string computeSysRoot() const override; - virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const; + std::string getDynamicLinker(const llvm::opt::ArgList &Args) const override; + + void addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const override; std::vector<std::string> ExtraOpts; + llvm::DenormalMode getDefaultDenormalModeForType( + const llvm::opt::ArgList &DriverArgs, const JobAction &JA, + const llvm::fltSemantics *FPType = nullptr) const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + Tool *buildStaticLibTool() const override; std::string getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, diff --git a/clang/lib/Driver/ToolChains/MSP430.cpp b/clang/lib/Driver/ToolChains/MSP430.cpp index bc77f015915d..b0bc2e014b48 100644 --- a/clang/lib/Driver/ToolChains/MSP430.cpp +++ b/clang/lib/Driver/ToolChains/MSP430.cpp @@ -143,7 +143,7 @@ std::string MSP430ToolChain::computeSysRoot() const { else llvm::sys::path::append(Dir, getDriver().Dir, "..", getTriple().str()); - return Dir.str(); + return std::string(Dir.str()); } void MSP430ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -227,6 +227,7 @@ void msp430::Linker::ConstructJob(Compilation &C, const JobAction &JA, } CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), - CmdArgs, Inputs)); + C.addCommand( + std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(Linker), CmdArgs, Inputs)); } diff --git a/clang/lib/Driver/ToolChains/MSP430.h b/clang/lib/Driver/ToolChains/MSP430.h index b5308a8dd687..58fd158cd12f 100644 --- a/clang/lib/Driver/ToolChains/MSP430.h +++ b/clang/lib/Driver/ToolChains/MSP430.h @@ -44,7 +44,7 @@ protected: Tool *buildLinker() const override; private: - std::string computeSysRoot() const; + std::string computeSysRoot() const override; }; } // end namespace toolchains @@ -52,10 +52,9 @@ private: namespace tools { namespace msp430 { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) - : GnuTool("MSP430::Linker", "msp430-elf-ld", TC) {} + Linker(const ToolChain &TC) : Tool("MSP430::Linker", "msp430-elf-ld", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } void ConstructJob(Compilation &C, const JobAction &JA, diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 4e143f6a5d3f..6b3c00e2ab6d 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -128,13 +128,13 @@ static bool findVCToolChainViaEnvironment(std::string &Path, llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath); llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath); if (ParentFilename == "VC") { - Path = ParentPath; + Path = std::string(ParentPath); VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; return true; } if (ParentFilename == "x86ret" || ParentFilename == "x86chk" || ParentFilename == "amd64ret" || ParentFilename == "amd64chk") { - Path = ParentPath; + Path = std::string(ParentPath); VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal; return true; } @@ -163,7 +163,7 @@ static bool findVCToolChainViaEnvironment(std::string &Path, for (int i = 0; i < 3; ++i) ToolChainPath = llvm::sys::path::parent_path(ToolChainPath); - Path = ToolChainPath; + Path = std::string(ToolChainPath); VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; return true; } @@ -261,7 +261,7 @@ static bool findVCToolChainViaSetupConfig(std::string &Path, if (!llvm::sys::fs::is_directory(ToolchainPath)) return false; - Path = ToolchainPath.str(); + Path = std::string(ToolchainPath.str()); VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer; return true; #endif @@ -282,7 +282,7 @@ static bool findVCToolChainViaRegistry(std::string &Path, VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)"))); llvm::sys::path::append(VCPath, "VC"); - Path = VCPath.str(); + Path = std::string(VCPath.str()); VSLayout = MSVCToolChain::ToolsetLayout::OlderVS; return true; } @@ -300,7 +300,8 @@ static std::string FindVisualStudioExecutable(const ToolChain &TC, SmallString<128> FilePath(MSVC.getSubDirectoryPath( toolchains::MSVCToolChain::SubDirectoryType::Bin)); llvm::sys::path::append(FilePath, Exe); - return llvm::sys::fs::can_execute(FilePath) ? FilePath.str() : Exe; + return std::string(llvm::sys::fs::can_execute(FilePath) ? FilePath.str() + : Exe); } void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -349,6 +350,16 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); } + // Add the compiler-rt library directories to libpath if they exist to help + // the linker find the various sanitizer, builtin, and profiling runtimes. + for (const auto &LibPath : TC.getLibraryPaths()) { + if (TC.getVFS().exists(LibPath)) + CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); + } + auto CRTPath = TC.getCompilerRTPath(); + if (TC.getVFS().exists(CRTPath)) + CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath)); + if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L)) for (const auto &LibPath : Args.getAllArgValues(options::OPT_L)) CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); @@ -581,8 +592,9 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, linkPath = TC.GetProgramPath(Linker.str().c_str()); } - auto LinkCmd = std::make_unique<Command>( - JA, *this, Args.MakeArgString(linkPath), CmdArgs, Inputs); + auto LinkCmd = + std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileUTF16(), + Args.MakeArgString(linkPath), CmdArgs, Inputs); if (!Environment.empty()) LinkCmd->setEnvironment(Environment); C.addCommand(std::move(LinkCmd)); @@ -722,13 +734,15 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( CmdArgs.push_back(Fo); std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe"); - return std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), - CmdArgs, Inputs); + return std::make_unique<Command>(JA, *this, + ResponseFileSupport::AtFileUTF16(), + Args.MakeArgString(Exec), CmdArgs, Inputs); } MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { + : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), + RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -786,8 +800,14 @@ void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } +void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); +} + void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { CudaInstallation.print(OS); + RocmInstallation.print(OS); } // Windows SDKs and VC Toolchains group their contents into subdirectories based @@ -892,7 +912,7 @@ MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type, llvm::sys::path::append(Path, "lib", SubdirName); break; } - return Path.str(); + return std::string(Path.str()); } #ifdef _WIN32 @@ -1046,7 +1066,7 @@ static bool getWindows10SDKVersionFromPath(const std::string &SDKPath, if (!CandidateName.startswith("10.")) continue; if (CandidateName > SDKVersion) - SDKVersion = CandidateName; + SDKVersion = std::string(CandidateName); } return !SDKVersion.empty(); @@ -1129,7 +1149,7 @@ bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const { } } - path = libPath.str(); + path = std::string(libPath.str()); return true; } @@ -1168,7 +1188,7 @@ bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const { llvm::SmallString<128> LibPath(UniversalCRTSdkPath); llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName); - Path = LibPath.str(); + Path = std::string(LibPath.str()); return true; } @@ -1475,14 +1495,15 @@ static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL, return; } - std::string NewVal = Val; + std::string NewVal = std::string(Val); NewVal[Hash] = '='; DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal); } llvm::opt::DerivedArgList * MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, - StringRef BoundArch, Action::OffloadKind) const { + StringRef BoundArch, + Action::OffloadKind OFK) const { DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); const OptTable &Opts = getDriver().getOpts(); @@ -1521,7 +1542,8 @@ MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, } else if (A->getOption().matches(options::OPT_D)) { // Translate -Dfoo#bar into -Dfoo=bar. TranslateDArg(A, *DAL, Opts); - } else { + } else if (OFK != Action::OFK_HIP) { + // HIP Toolchain translates input args by itself. DAL->append(A); } } diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index 41a69a82fecf..dba99ed77246 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H +#include "AMDGPU.h" #include "Cuda.h" #include "clang/Basic/DebugInfoOptions.h" #include "clang/Driver/Compilation.h" @@ -23,9 +24,7 @@ namespace tools { namespace visualstudio { class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) - : Tool("visualstudio::Linker", "linker", TC, RF_Full, - llvm::sys::WEM_UTF16) {} + Linker(const ToolChain &TC) : Tool("visualstudio::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } @@ -39,8 +38,7 @@ public: class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { public: Compiler(const ToolChain &TC) - : Tool("visualstudio::Compiler", "compiler", TC, RF_Full, - llvm::sys::WEM_UTF16) {} + : Tool("visualstudio::Compiler", "compiler", TC) {} bool hasIntegratedAssembler() const override { return true; } bool hasIntegratedCPP() const override { return true; } @@ -125,6 +123,9 @@ public: void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + bool getWindowsSDKLibraryPath(std::string &path) const; /// Check if Universal CRT should be used if available bool getUniversalCRTLibraryPath(std::string &path) const; @@ -155,6 +156,7 @@ private: std::string VCToolChainPath; ToolsetLayout VSLayout = ToolsetLayout::OlderVS; CudaInstallationDetector CudaInstallation; + RocmInstallationDetector RocmInstallation; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 8f24384e688b..a1a1b413fb6c 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -18,6 +18,7 @@ #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" #include <system_error> using namespace clang::diag; @@ -49,7 +50,8 @@ void tools::MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); if (Args.hasArg(options::OPT_gsplit_dwarf)) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, @@ -198,6 +200,17 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); TC.AddFilePathLibArgs(Args, CmdArgs); + + // Add the compiler-rt library directories if they exist to help + // the linker find the various sanitizer, builtin, and profiling runtimes. + for (const auto &LibPath : TC.getLibraryPaths()) { + if (TC.getVFS().exists(LibPath)) + CmdArgs.push_back(Args.MakeArgString("-L" + LibPath)); + } + auto CRTPath = TC.getCompilerRTPath(); + if (TC.getVFS().exists(CRTPath)) + CmdArgs.push_back(Args.MakeArgString("-L" + CRTPath)); + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); // TODO: Add profile stuff here @@ -292,21 +305,25 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lkernel32"); } - if (Args.hasArg(options::OPT_static)) + if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("--end-group"); - else + } else { AddLibGCC(Args, CmdArgs); + if (!HasWindowsApp) + CmdArgs.push_back("-lkernel32"); + } } if (!Args.hasArg(options::OPT_nostartfiles)) { // Add crtfastmath.o if available and fast math is enabled. - TC.AddFastMathRuntimeIfAvailable(Args, CmdArgs); + TC.addFastMathRuntimeIfAvailable(Args, CmdArgs); CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); } } const char *Exec = Args.MakeArgString(TC.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); } // Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple. @@ -323,7 +340,7 @@ static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, continue; if (CandidateVersion <= Version) continue; - Ver = VersionText; + Ver = std::string(VersionText); GccLibDir = LI->path(); } return Ver.size(); @@ -335,7 +352,7 @@ void toolchains::MinGW::findGccLibDir() { Archs[0] += "-w64-mingw32"; Archs.emplace_back("mingw32"); if (Arch.empty()) - Arch = Archs[0].str(); + Arch = std::string(Archs[0].str()); // lib: Arch Linux, Ubuntu, Windows // lib64: openSUSE Linux for (StringRef CandidateLib : {"lib", "lib64"}) { @@ -343,7 +360,7 @@ void toolchains::MinGW::findGccLibDir() { llvm::SmallString<1024> LibDir(Base); llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch); if (findGccVersion(LibDir, GccLibDir, Ver)) { - Arch = CandidateArch; + Arch = std::string(CandidateArch); return; } } @@ -372,7 +389,7 @@ llvm::ErrorOr<std::string> toolchains::MinGW::findClangRelativeSysroot() { StringRef Sep = llvm::sys::path::get_separator(); for (StringRef CandidateSubdir : Subdirs) { if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) { - Arch = CandidateSubdir; + Arch = std::string(CandidateSubdir); return (ClangRoot + Sep + CandidateSubdir).str(); } } @@ -381,7 +398,8 @@ llvm::ErrorOr<std::string> toolchains::MinGW::findClangRelativeSysroot() { toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { + : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), + RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().SysRoot.size()) @@ -389,12 +407,13 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, // 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()) - Base = llvm::sys::path::parent_path(TargetSubdir.get()); + Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); else if (llvm::ErrorOr<std::string> GPPName = findGcc()) - Base = llvm::sys::path::parent_path( - llvm::sys::path::parent_path(GPPName.get())); + Base = std::string(llvm::sys::path::parent_path( + llvm::sys::path::parent_path(GPPName.get()))); else - Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); + Base = std::string( + llvm::sys::path::parent_path(getDriver().getInstalledDir())); Base += llvm::sys::path::get_separator(); findGccLibDir(); @@ -482,8 +501,14 @@ void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } +void toolchains::MinGW::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); +} + void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const { CudaInstallation.print(OS); + RocmInstallation.print(OS); } // Include directories for various hosts: diff --git a/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h index 6752a405be87..2f1559fcf34c 100644 --- a/clang/lib/Driver/ToolChains/MinGW.h +++ b/clang/lib/Driver/ToolChains/MinGW.h @@ -11,8 +11,10 @@ #include "Cuda.h" #include "Gnu.h" +#include "ROCm.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/Support/ErrorOr.h" namespace clang { namespace driver { @@ -34,8 +36,7 @@ public: class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) - : Tool("MinGW::Linker", "linker", TC, Tool::RF_Full) {} + Linker(const ToolChain &TC) : Tool("MinGW::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } @@ -81,6 +82,8 @@ public: void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; void printVerboseInfo(raw_ostream &OS) const override; @@ -91,6 +94,7 @@ protected: private: CudaInstallationDetector CudaInstallation; + RocmInstallationDetector RocmInstallation; std::string Base; std::string GccLibDir; diff --git a/clang/lib/Driver/ToolChains/Minix.cpp b/clang/lib/Driver/ToolChains/Minix.cpp index 6947049ea52e..d0314795620c 100644 --- a/clang/lib/Driver/ToolChains/Minix.cpp +++ b/clang/lib/Driver/ToolChains/Minix.cpp @@ -36,7 +36,8 @@ void tools::minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -88,7 +89,8 @@ void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } /// Minix - Minix tool chain which can call as(1) and ld(1) directly. diff --git a/clang/lib/Driver/ToolChains/Minix.h b/clang/lib/Driver/ToolChains/Minix.h index 1ed6acebab9c..af8d59c5085a 100644 --- a/clang/lib/Driver/ToolChains/Minix.h +++ b/clang/lib/Driver/ToolChains/Minix.h @@ -18,10 +18,9 @@ namespace driver { namespace tools { /// minix -- Directly call GNU Binutils assembler and linker namespace minix { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: - Assembler(const ToolChain &TC) - : GnuTool("minix::Assembler", "assembler", TC) {} + Assembler(const ToolChain &TC) : Tool("minix::Assembler", "assembler", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -31,9 +30,9 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("minix::Linker", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("minix::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } diff --git a/clang/lib/Driver/ToolChains/MipsLinux.cpp b/clang/lib/Driver/ToolChains/MipsLinux.cpp index cfda7f4bb4df..41b7b839f3b3 100644 --- a/clang/lib/Driver/ToolChains/MipsLinux.cpp +++ b/clang/lib/Driver/ToolChains/MipsLinux.cpp @@ -136,5 +136,5 @@ std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, } llvm::sys::path::append( Path, Twine("libclang_rt." + Component + "-" + "mips" + Suffix)); - return Path.str(); + return std::string(Path.str()); } diff --git a/clang/lib/Driver/ToolChains/Myriad.cpp b/clang/lib/Driver/ToolChains/Myriad.cpp index 2ce0f13ce3d1..84fe4748b6fa 100644 --- a/clang/lib/Driver/ToolChains/Myriad.cpp +++ b/clang/lib/Driver/ToolChains/Myriad.cpp @@ -77,8 +77,9 @@ void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, std::string Exec = Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); - C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), - CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Args.MakeArgString(Exec), CmdArgs, + Inputs)); } void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, @@ -112,8 +113,9 @@ void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, std::string Exec = Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); - C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), - CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Args.MakeArgString(Exec), CmdArgs, + Inputs)); } void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -198,8 +200,9 @@ void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, std::string Exec = Args.MakeArgString(TC.GetProgramPath("sparc-myriad-rtems-ld")); - C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), - CmdArgs, Inputs)); + C.addCommand( + std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(Exec), CmdArgs, Inputs)); } MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, diff --git a/clang/lib/Driver/ToolChains/Myriad.h b/clang/lib/Driver/ToolChains/Myriad.h index 9f5225fbc62c..cae574bdcfea 100644 --- a/clang/lib/Driver/ToolChains/Myriad.h +++ b/clang/lib/Driver/ToolChains/Myriad.h @@ -49,9 +49,9 @@ public: /// whereas the linker, which accepts code for a mixture of Sparc and SHAVE, /// is in the Myriad namespace. namespace Myriad { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("shave::Linker", "ld", TC) {} + Linker(const ToolChain &TC) : Tool("shave::Linker", "ld", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } void ConstructJob(Compilation &C, const JobAction &JA, diff --git a/clang/lib/Driver/ToolChains/NaCl.cpp b/clang/lib/Driver/ToolChains/NaCl.cpp index 97241c884027..15a773675299 100644 --- a/clang/lib/Driver/ToolChains/NaCl.cpp +++ b/clang/lib/Driver/ToolChains/NaCl.cpp @@ -193,7 +193,8 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } /// NaCl Toolchain diff --git a/clang/lib/Driver/ToolChains/NaCl.h b/clang/lib/Driver/ToolChains/NaCl.h index ab243f8087bb..5e5fdb583bb6 100644 --- a/clang/lib/Driver/ToolChains/NaCl.h +++ b/clang/lib/Driver/ToolChains/NaCl.h @@ -27,9 +27,9 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("NaCl::Linker", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("NaCl::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp index 0100a387d6c3..253ee6ce0f72 100644 --- a/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -103,7 +103,8 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as"))); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -337,7 +338,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } /// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. diff --git a/clang/lib/Driver/ToolChains/NetBSD.h b/clang/lib/Driver/ToolChains/NetBSD.h index 6d404263f625..8348554fd149 100644 --- a/clang/lib/Driver/ToolChains/NetBSD.h +++ b/clang/lib/Driver/ToolChains/NetBSD.h @@ -19,10 +19,9 @@ namespace tools { /// netbsd -- Directly call GNU Binutils assembler and linker namespace netbsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: - Assembler(const ToolChain &TC) - : GnuTool("netbsd::Assembler", "assembler", TC) {} + Assembler(const ToolChain &TC) : Tool("netbsd::Assembler", "assembler", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -32,9 +31,9 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("netbsd::Linker", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("netbsd::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp index 80343c0394cb..9c1a9c5f8228 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -89,7 +89,8 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -227,7 +228,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs)); } SanitizerMask OpenBSD::getSupportedSanitizers() const { diff --git a/clang/lib/Driver/ToolChains/OpenBSD.h b/clang/lib/Driver/ToolChains/OpenBSD.h index 9f1ee0f66402..897eee57ab68 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/clang/lib/Driver/ToolChains/OpenBSD.h @@ -19,10 +19,10 @@ namespace tools { /// openbsd -- Directly call GNU Binutils assembler and linker namespace openbsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { public: Assembler(const ToolChain &TC) - : GnuTool("openbsd::Assembler", "assembler", TC) {} + : Tool("openbsd::Assembler", "assembler", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -32,9 +32,9 @@ public: const char *LinkingOutput) const override; }; -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("openbsd::Linker", "linker", TC) {} + Linker(const ToolChain &TC) : Tool("openbsd::Linker", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index 4e8840296205..6dc81899cbaa 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -30,13 +30,17 @@ void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasFlag(options::OPT_fprofile_generate, - options::OPT_fno_profile_instr_generate, false) || + options::OPT_fno_profile_generate, false) || Args.hasFlag(options::OPT_fprofile_generate_EQ, - options::OPT_fno_profile_instr_generate, false) || + 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("--dependent-lib=libclang_rt.profile-x86_64.a"); @@ -62,7 +66,8 @@ void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); } static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { @@ -84,13 +89,13 @@ void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a"); } -static void ConstructPS4LinkJob(const Tool &T, Compilation &C, - const JobAction &JA, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) { +void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(T.getToolChain()); + static_cast<const toolchains::FreeBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; @@ -139,216 +144,16 @@ static void ConstructPS4LinkJob(const Tool &T, Compilation &C, CmdArgs.push_back("-lpthread"); } - const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); - - C.addCommand(std::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); -} - -static void ConstructGoldLinkJob(const Tool &T, Compilation &C, - const JobAction &JA, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) { - const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(T.getToolChain()); - const Driver &D = ToolChain.getDriver(); - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - if (Args.hasArg(options::OPT_pie)) - CmdArgs.push_back("-pie"); - - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-Bstatic"); - } else { - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-Bshareable"); - } else { - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back("/libexec/ld-elf.so.1"); - } - CmdArgs.push_back("--enable-new-dtags"); - } - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - AddPS4SanitizerArgs(ToolChain, CmdArgs); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - const char *crt1 = nullptr; - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - crt1 = "gcrt1.o"; - else if (Args.hasArg(options::OPT_pie)) - crt1 = "Scrt1.o"; - else - crt1 = "crt1.o"; - } - if (crt1) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - - const char *crtbegin = nullptr; - if (Args.hasArg(options::OPT_static)) - crtbegin = "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - crtbegin = "crtbeginS.o"; - else - crtbegin = "crtbegin.o"; - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_r); - - if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) - CmdArgs.push_back("--no-demangle"); - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - // For PS4, we always want to pass libm, libstdc++ and libkernel - // libraries for both C and C++ compilations. - CmdArgs.push_back("-lkernel"); - if (D.CCCIsCXX()) { - if (ToolChain.ShouldLinkCXXStdlib(Args)) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lm_p"); - else - CmdArgs.push_back("-lm"); - } - // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding - // the default system libraries. Just mimic this for now. - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lgcc_p"); - else - CmdArgs.push_back("-lcompiler_rt"); - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lstdc++"); - } else if (Args.hasArg(options::OPT_pg)) { - CmdArgs.push_back("-lgcc_eh_p"); - } else { - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lstdc++"); - CmdArgs.push_back("--no-as-needed"); - } - - if (Args.hasArg(options::OPT_pthread)) { - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lpthread_p"); - else - CmdArgs.push_back("-lpthread"); - } - - if (Args.hasArg(options::OPT_pg)) { - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("-lc"); - else { - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("--start-group"); - CmdArgs.push_back("-lc_p"); - CmdArgs.push_back("-lpthread_p"); - CmdArgs.push_back("--end-group"); - } else { - CmdArgs.push_back("-lc_p"); - } - } - CmdArgs.push_back("-lgcc_p"); - } else { - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("--start-group"); - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("--end-group"); - } else { - CmdArgs.push_back("-lc"); - } - CmdArgs.push_back("-lcompiler_rt"); - } - - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lstdc++"); - } else if (Args.hasArg(options::OPT_pg)) { - CmdArgs.push_back("-lgcc_eh_p"); - } else { - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lstdc++"); - CmdArgs.push_back("--no-as-needed"); - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); - else - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + if (Args.hasArg(options::OPT_fuse_ld_EQ)) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << "-fuse-ld" << getToolChain().getTriple().str(); } const char *Exec = -#ifdef _WIN32 - Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold")); -#else Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); -#endif - - C.addCommand(std::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); -} - -void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(getToolChain()); - const Driver &D = ToolChain.getDriver(); - bool PS4Linker; - StringRef LinkerOptName; - if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { - LinkerOptName = A->getValue(); - if (LinkerOptName != "ps4" && LinkerOptName != "gold") - D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName; - } - if (LinkerOptName == "gold") - PS4Linker = false; - else if (LinkerOptName == "ps4") - PS4Linker = true; - else - PS4Linker = !Args.hasArg(options::OPT_shared); - - if (PS4Linker) - ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); - else - ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); } toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, @@ -382,7 +187,7 @@ toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, if (!llvm::sys::fs::exists(PrefixDir)) getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; } else - PrefixDir = PS4SDKDir.str(); + PrefixDir = std::string(PS4SDKDir.str()); SmallString<512> PS4SDKIncludeDir(PrefixDir); llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); @@ -407,7 +212,7 @@ toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, << "PS4 system libraries" << PS4SDKLibDir; return; } - getFilePaths().push_back(PS4SDKLibDir.str()); + getFilePaths().push_back(std::string(PS4SDKLibDir.str())); } Tool *toolchains::PS4CPU::buildAssembler() const { @@ -430,3 +235,17 @@ SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { Res |= SanitizerKind::Vptr; return Res; } + +void toolchains::PS4CPU::addClangTargetOptions( + const ArgList &DriverArgs, + ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + // PS4 does not use init arrays. + if (DriverArgs.hasArg(options::OPT_fuse_init_array)) { + Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array); + getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target) + << A->getAsString(DriverArgs) << getTriple().str(); + } + + CC1Args.push_back("-fno-use-init-array"); +} diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h index 18852b2808cb..968be015d411 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/clang/lib/Driver/ToolChains/PS4CPU.h @@ -26,8 +26,7 @@ void addSanitizerArgs(const ToolChain &TC, llvm::opt::ArgStringList &CmdArgs); class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { public: - Assemble(const ToolChain &TC) - : Tool("PS4cpu::Assemble", "assembler", TC, RF_Full) {} + Assemble(const ToolChain &TC) : Tool("PS4cpu::Assemble", "assembler", TC) {} bool hasIntegratedCPP() const override { return false; } @@ -40,7 +39,7 @@ public: class LLVM_LIBRARY_VISIBILITY Link : public Tool { public: - Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC, RF_Full) {} + Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } @@ -88,6 +87,20 @@ public: // capable of unit splitting. bool canSplitThinLTOUnit() const override { return false; } + void addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const override; + + llvm::DenormalMode getDefaultDenormalModeForType( + const llvm::opt::ArgList &DriverArgs, const JobAction &JA, + const llvm::fltSemantics *FPType) const override { + // DAZ and FTZ are on by default. + return llvm::DenormalMode::getPreserveSign(); + } + + bool useRelaxRelocations() const override { return true; } + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index ddc329e3c722..cc912d94cb92 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -119,7 +119,7 @@ std::string RISCVToolChain::computeSysRoot() const { if (!llvm::sys::fs::exists(SysRootDir)) return std::string(); - return SysRootDir.str(); + return std::string(SysRootDir.str()); } void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -142,7 +142,7 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf32lriscv"); } - std::string Linker = getToolChain().GetProgramPath(getShortName()); + std::string Linker = getToolChain().GetLinkerPath(); bool WantCRTs = !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); @@ -191,7 +191,8 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), - CmdArgs, Inputs)); + C.addCommand( + std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(), + Args.MakeArgString(Linker), CmdArgs, Inputs)); } // RISCV tools end. diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.h b/clang/lib/Driver/ToolChains/RISCVToolchain.h index bb7f64849bcb..4734aee5f1ab 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.h +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -39,16 +39,16 @@ protected: Tool *buildLinker() const override; private: - std::string computeSysRoot() const; + std::string computeSysRoot() const override; }; } // end namespace toolchains namespace tools { namespace RISCV { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - Linker(const ToolChain &TC) : GnuTool("RISCV::Linker", "ld", TC) {} + Linker(const ToolChain &TC) : Tool("RISCV::Linker", "ld", TC) {} bool hasIntegratedCPP() const override { return false; } bool isLinkJob() const override { return true; } void ConstructJob(Compilation &C, const JobAction &JA, diff --git a/clang/lib/Driver/ToolChains/ROCm.h b/clang/lib/Driver/ToolChains/ROCm.h new file mode 100644 index 000000000000..962c72fedfe0 --- /dev/null +++ b/clang/lib/Driver/ToolChains/ROCm.h @@ -0,0 +1,228 @@ +//===--- ROCm.h - ROCm installation detector --------------------*- 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_ROCM_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ROCM_H + +#include "clang/Basic/Cuda.h" +#include "clang/Basic/LLVM.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/VersionTuple.h" + +namespace clang { +namespace driver { + +/// A class to find a viable ROCM installation +/// TODO: Generalize to handle libclc. +class RocmInstallationDetector { +private: + struct ConditionalLibrary { + SmallString<0> On; + SmallString<0> Off; + + bool isValid() const { return !On.empty() && !Off.empty(); } + + StringRef get(bool Enabled) const { + assert(isValid()); + return Enabled ? On : Off; + } + }; + + // Installation path candidate. + struct Candidate { + llvm::SmallString<0> Path; + bool StrictChecking; + + Candidate(std::string Path, bool StrictChecking = false) + : Path(Path), StrictChecking(StrictChecking) {} + }; + + const Driver &D; + bool HasHIPRuntime = false; + bool HasDeviceLibrary = false; + + // Default version if not detected or specified. + const unsigned DefaultVersionMajor = 3; + const unsigned DefaultVersionMinor = 5; + const char *DefaultVersionPatch = "0"; + + // The version string in Major.Minor.Patch format. + std::string DetectedVersion; + // Version containing major and minor. + llvm::VersionTuple VersionMajorMinor; + // Version containing patch. + std::string VersionPatch; + + // ROCm path specified by --rocm-path. + StringRef RocmPathArg; + // ROCm device library paths specified by --rocm-device-lib-path. + std::vector<std::string> RocmDeviceLibPathArg; + // HIP version specified by --hip-version. + StringRef HIPVersionArg; + // Wheter -nogpulib is specified. + bool NoBuiltinLibs = false; + + // Paths + SmallString<0> InstallPath; + SmallString<0> BinPath; + SmallString<0> LibPath; + SmallString<0> LibDevicePath; + SmallString<0> IncludePath; + llvm::StringMap<std::string> LibDeviceMap; + + // Libraries that are always linked. + SmallString<0> OCML; + SmallString<0> OCKL; + + // Libraries that are always linked depending on the language + SmallString<0> OpenCL; + SmallString<0> HIP; + + // Libraries swapped based on compile flags. + ConditionalLibrary WavefrontSize64; + ConditionalLibrary FiniteOnly; + ConditionalLibrary UnsafeMath; + ConditionalLibrary DenormalsAreZero; + ConditionalLibrary CorrectlyRoundedSqrt; + + bool allGenericLibsValid() const { + return !OCML.empty() && !OCKL.empty() && !OpenCL.empty() && !HIP.empty() && + WavefrontSize64.isValid() && FiniteOnly.isValid() && + UnsafeMath.isValid() && DenormalsAreZero.isValid() && + CorrectlyRoundedSqrt.isValid(); + } + + // GPU architectures for which we have raised an error in + // CheckRocmVersionSupportsArch. + mutable llvm::SmallSet<CudaArch, 4> ArchsWithBadVersion; + + void scanLibDevicePath(llvm::StringRef Path); + void ParseHIPVersionFile(llvm::StringRef V); + SmallVector<Candidate, 4> getInstallationPathCandidates(); + +public: + RocmInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args, + bool DetectHIPRuntime = true, + bool DetectDeviceLib = false); + + /// Add arguments needed to link default bitcode libraries. + void addCommonBitcodeLibCC1Args(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef LibDeviceFile, bool Wave64, + bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, + bool FastRelaxedMath, bool CorrectSqrt) const; + + /// Emit an error if Version does not support the given Arch. + /// + /// If either Version or Arch is unknown, does not emit an error. Emits at + /// most one error per Arch. + void CheckRocmVersionSupportsArch(CudaArch Arch) const; + + /// Check whether we detected a valid HIP runtime. + bool hasHIPRuntime() const { return HasHIPRuntime; } + + /// Check whether we detected a valid ROCm device library. + bool hasDeviceLibrary() const { return HasDeviceLibrary; } + + /// Print information about the detected ROCm installation. + void print(raw_ostream &OS) const; + + /// Get the detected Rocm install's version. + // RocmVersion version() const { return Version; } + + /// Get the detected Rocm installation path. + StringRef getInstallPath() const { return InstallPath; } + + /// Get the detected path to Rocm's bin directory. + // StringRef getBinPath() const { return BinPath; } + + /// Get the detected Rocm Include path. + StringRef getIncludePath() const { return IncludePath; } + + /// Get the detected Rocm library path. + StringRef getLibPath() const { return LibPath; } + + /// Get the detected Rocm device library path. + StringRef getLibDevicePath() const { return LibDevicePath; } + + StringRef getOCMLPath() const { + assert(!OCML.empty()); + return OCML; + } + + StringRef getOCKLPath() const { + assert(!OCKL.empty()); + return OCKL; + } + + StringRef getOpenCLPath() const { + assert(!OpenCL.empty()); + return OpenCL; + } + + StringRef getHIPPath() const { + assert(!HIP.empty()); + return HIP; + } + + StringRef getWavefrontSize64Path(bool Enabled) const { + return WavefrontSize64.get(Enabled); + } + + StringRef getFiniteOnlyPath(bool Enabled) const { + return FiniteOnly.get(Enabled); + } + + StringRef getUnsafeMathPath(bool Enabled) const { + return UnsafeMath.get(Enabled); + } + + StringRef getDenormalsAreZeroPath(bool Enabled) const { + return DenormalsAreZero.get(Enabled); + } + + StringRef getCorrectlyRoundedSqrtPath(bool Enabled) const { + return CorrectlyRoundedSqrt.get(Enabled); + } + + /// Get libdevice file for given architecture + std::string getLibDeviceFile(StringRef Gpu) const { + return LibDeviceMap.lookup(Gpu); + } + + void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + void detectDeviceLibrary(); + void detectHIPRuntime(); + + /// Get the values for --rocm-device-lib-path arguments + std::vector<std::string> getRocmDeviceLibPathArg() const { + return RocmDeviceLibPathArg; + } + + /// Get the value for --rocm-path argument + StringRef getRocmPathArg() const { return RocmPathArg; } + + /// Get the value for --hip-version argument + StringRef getHIPVersionArg() const { return HIPVersionArg; } + + std::string getHIPVersion() const { return DetectedVersion; } +}; + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ROCM_H diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index fc4e2cf151ef..b8fdc87478bc 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -41,7 +41,8 @@ void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -150,7 +151,8 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) { @@ -244,7 +246,7 @@ void Solaris::AddClangSystemIncludeArgs(const ArgList &DriverArgs, CIncludeDirs.split(dirs, ":"); for (StringRef dir : dirs) { StringRef Prefix = - llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot); addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); } return; diff --git a/clang/lib/Driver/ToolChains/VEToolchain.cpp b/clang/lib/Driver/ToolChains/VEToolchain.cpp new file mode 100644 index 000000000000..6ea405c0269c --- /dev/null +++ b/clang/lib/Driver/ToolChains/VEToolchain.cpp @@ -0,0 +1,119 @@ +//===--- VE.cpp - VE ToolChain Implementations ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "VEToolchain.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include <cstdlib> // ::getenv + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +/// VE tool chain +VEToolChain::VEToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Linux(D, Triple, Args) { + getProgramPaths().push_back("/opt/nec/ve/bin"); + // ProgramPaths are found via 'PATH' environment variable. + + // default file paths are: + // ${RESOURCEDIR}/lib/linux/ve (== getArchSpecificLibPath) + // /lib/../lib64 + // /usr/lib/../lib64 + // ${BINPATH}/../lib + // /lib + // /usr/lib + // + // These are OK for host, but no go for VE. So, defines them all + // from scratch here. + getFilePaths().clear(); + getFilePaths().push_back(getArchSpecificLibPath()); + getFilePaths().push_back(computeSysRoot() + "/opt/nec/ve/lib"); +} + +Tool *VEToolChain::buildAssembler() const { + return new tools::gnutools::Assembler(*this); +} + +Tool *VEToolChain::buildLinker() const { + return new tools::gnutools::Linker(*this); +} + +bool VEToolChain::isPICDefault() const { return false; } + +bool VEToolChain::isPIEDefault() const { return false; } + +bool VEToolChain::isPICDefaultForced() const { return false; } + +bool VEToolChain::SupportsProfiling() const { return false; } + +bool VEToolChain::hasBlocksRuntime() const { return false; } + +void VEToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (DriverArgs.hasArg(options::OPT_nobuiltininc) && + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(getDriver().ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { + if (const char *cl_include_dir = getenv("NCC_C_INCLUDE_PATH")) { + SmallVector<StringRef, 4> Dirs; + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; + StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); + ArrayRef<StringRef> DirVec(Dirs); + addSystemIncludes(DriverArgs, CC1Args, DirVec); + } else { + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/opt/nec/ve/include"); + } + } +} + +void VEToolChain::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args, + Action::OffloadKind) const { + CC1Args.push_back("-nostdsysteminc"); + bool UseInitArrayDefault = true; + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, UseInitArrayDefault)) + CC1Args.push_back("-fno-use-init-array"); +} + +void VEToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + // TODO upstream VE libc++ patches + llvm_unreachable("The VE target has no C++ stdlib for Clang yet"); +} + +void VEToolChain::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // TODO upstream VE libc++ patches + llvm_unreachable("The VE target has no C++ stdlib for Clang yet"); +} + +llvm::ExceptionHandling +VEToolChain::GetExceptionModel(const ArgList &Args) const { + // VE uses SjLj exceptions. + return llvm::ExceptionHandling::SjLj; +} diff --git a/clang/lib/Driver/ToolChains/VEToolchain.h b/clang/lib/Driver/ToolChains/VEToolchain.h new file mode 100644 index 000000000000..59069c0a7595 --- /dev/null +++ b/clang/lib/Driver/ToolChains/VEToolchain.h @@ -0,0 +1,66 @@ +//===--- VE.h - VE ToolChain Implementations --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_VE_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_VE_H + +#include "Linux.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY VEToolChain : public Linux { +public: + VEToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; + +public: + bool isPICDefault() const override; + bool isPIEDefault() const override; + bool isPICDefaultForced() const override; + bool SupportsProfiling() const override; + bool hasBlocksRuntime() const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + llvm::ExceptionHandling + GetExceptionModel(const llvm::opt::ArgList &Args) const override; + + CXXStdlibType + GetCXXStdlibType(const llvm::opt::ArgList &Args) const override { + return ToolChain::CST_Libcxx; + } + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + + const char *getDefaultLinker() const override { return "nld"; } +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_VE_H diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 907f86b8233c..10168736400f 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -40,7 +40,7 @@ std::string wasm::Linker::getLinkerPath(const ArgList &Args) const { if (!UseLinker.empty()) { if (llvm::sys::path::is_absolute(UseLinker) && llvm::sys::fs::can_execute(UseLinker)) - return UseLinker; + return std::string(UseLinker); // Accept 'lld', and 'ld' as aliases for the default linker if (UseLinker != "lld" && UseLinker != "ld") @@ -62,6 +62,12 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *Linker = Args.MakeArgString(getLinkerPath(Args)); ArgStringList CmdArgs; + CmdArgs.push_back("-m"); + if (getToolChain().getTriple().isArch64Bit()) + CmdArgs.push_back("wasm64"); + else + CmdArgs.push_back("wasm32"); + if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("--strip-all"); @@ -69,8 +75,26 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_u); ToolChain.AddFilePathLibArgs(Args, CmdArgs); + const char *Crt1 = "crt1.o"; + const char *Entry = NULL; + if (const Arg *A = Args.getLastArg(options::OPT_mexec_model_EQ)) { + StringRef CM = A->getValue(); + if (CM == "command") { + // Use default values. + } else if (CM == "reactor") { + Crt1 = "crt1-reactor.o"; + Entry = "_initialize"; + } else { + ToolChain.getDriver().Diag(diag::err_drv_invalid_argument_to_option) + << CM << A->getOption().getName(); + } + } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(Crt1))); + if (Entry) { + CmdArgs.push_back(Args.MakeArgString("--entry")); + CmdArgs.push_back(Args.MakeArgString(Entry)); + } AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); @@ -90,7 +114,8 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), Linker, CmdArgs, Inputs)); // When optimizing, if wasm-opt is available, run it. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { @@ -112,7 +137,9 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique<Command>(JA, *this, WasmOpt, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>( + JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, CmdArgs, + Inputs)); } } } @@ -283,7 +310,7 @@ void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, CIncludeDirs.split(dirs, ":"); for (StringRef dir : dirs) { StringRef Prefix = - llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot); addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); } return; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.h b/clang/lib/Driver/ToolChains/WebAssembly.h index 67d5fce84576..616bfb5d3d0c 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/clang/lib/Driver/ToolChains/WebAssembly.h @@ -18,10 +18,9 @@ namespace driver { namespace tools { namespace wasm { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { public: - explicit Linker(const ToolChain &TC) - : GnuTool("wasm::Linker", "linker", TC) {} + explicit Linker(const ToolChain &TC) : Tool("wasm::Linker", "linker", TC) {} bool isLinkJob() const override { return true; } bool hasIntegratedCPP() const override { return false; } std::string getLinkerPath(const llvm::opt::ArgList &Args) const; diff --git a/clang/lib/Driver/ToolChains/XCore.cpp b/clang/lib/Driver/ToolChains/XCore.cpp index ba3a6d44adda..5030c73c7d82 100644 --- a/clang/lib/Driver/ToolChains/XCore.cpp +++ b/clang/lib/Driver/ToolChains/XCore.cpp @@ -52,7 +52,8 @@ void tools::XCore::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -80,7 +81,8 @@ void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); - C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); } /// XCore tool chain |