diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -56,12 +56,12 @@ "cannot find libdevice for %0. Provide path to different CUDA installation " "via --cuda-path, or pass -nocudalib to build without linking with libdevice.">; -def err_drv_no_rocm_installation : Error< - "cannot find ROCm installation. Provide its path via --rocm-path, or pass " - "-nogpulib and -nogpuinc to build without ROCm device library and HIP includes.">; def err_drv_no_rocm_device_lib : Error< - "cannot find device library for %0. Provide path to different ROCm installation " - "via --rocm-path, or pass -nogpulib to build without linking default libraries.">; + "cannot find ROCm device library%select{| for %1}0. Provide its path via --rocm-path or " + "--rocm-device-lib-path, or pass -nogpulib to build without ROCm device library.">; +def err_drv_no_hip_runtime : Error< + "cannot find HIP runtime. Provide its path via --rocm-path, or pass " + "-nogpuinc to build without HIP runtime.">; def err_drv_cuda_version_unsupported : Error< "GPU arch %0 is supported by CUDA versions between %1 and %2 (inclusive), " diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -637,15 +637,19 @@ "Use 32-bit pointers for accessing const/local/shared address spaces">; def rocm_path_EQ : Joined<["--"], "rocm-path=">, Group, HelpText<"ROCm installation path, used for finding and automatically linking required bitcode libraries.">; -def hip_device_lib_path_EQ : Joined<["--"], "hip-device-lib-path=">, Group, - HelpText<"HIP device library path. Alternative to rocm-path.">; +def rocm_device_lib_path_EQ : Joined<["--"], "rocm-device-lib-path=">, Group, + HelpText<"ROCm device library path. Alternative to rocm-path.">; +def : Joined<["--"], "hip-device-lib-path=">, Alias; def hip_device_lib_EQ : Joined<["--"], "hip-device-lib=">, Group, HelpText<"HIP device library">; +def hip_version_EQ : Joined<["--"], "hip-version=">, + HelpText<"HIP version in the format of major.minor.patch">; def fhip_dump_offload_linker_script : Flag<["-"], "fhip-dump-offload-linker-script">, Group, Flags<[NoArgumentUnused, HelpHidden]>; defm hip_new_launch_api : OptInFFlag<"hip-new-launch-api", - "Use new kernel launching API for HIP">; -defm gpu_allow_device_init : OptInFFlag<"gpu-allow-device-init", "Allow device side init function in HIP">; + "Use", "Don't use", " new kernel launching API for HIP">; +defm gpu_allow_device_init : OptInFFlag<"gpu-allow-device-init", + "Allow", "Don't allow", " device side init function in HIP">; def gpu_max_threads_per_block_EQ : Joined<["--"], "gpu-max-threads-per-block=">, Flags<[CC1Option]>, HelpText<"Default max threads per block for kernel launch bounds for HIP">; diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -242,7 +242,7 @@ EmittedKernels.push_back({CGF.CurFn, CGF.CurFuncDecl}); if (CudaFeatureEnabled(CGM.getTarget().getSDKVersion(), CudaFeature::CUDA_USES_NEW_LAUNCH) || - CGF.getLangOpts().HIPUseNewLaunchAPI) + (CGF.getLangOpts().HIP && CGF.getLangOpts().HIPUseNewLaunchAPI)) emitDeviceStubBodyNew(CGF, Args); else emitDeviceStubBodyLegacy(CGF, Args); diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -21,16 +21,14 @@ using namespace clang; using namespace llvm::opt; -void RocmInstallationDetector::scanLibDevicePath() { - assert(!LibDevicePath.empty()); +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(LibDevicePath, EC), - LE; + 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); @@ -89,60 +87,114 @@ } } -RocmInstallationDetector::RocmInstallationDetector( - const Driver &D, const llvm::Triple &HostTriple, - const llvm::opt::ArgList &Args) - : D(D) { - struct Candidate { - std::string Path; - bool StrictChecking; - - Candidate(std::string Path, bool StrictChecking = false) - : Path(Path), StrictChecking(StrictChecking) {} - }; +void RocmInstallationDetector::ParseHIPVersionFile(llvm::StringRef V) { + SmallVector 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::getInstallationPathCandidates() { SmallVector Candidates; + if (!RocmPathArg.empty()) { + Candidates.emplace_back(RocmPathArg.str()); + return Candidates; + } - if (Args.hasArg(clang::driver::options::OPT_rocm_path_EQ)) { - Candidates.emplace_back( - Args.getLastArgValue(clang::driver::options::OPT_rocm_path_EQ).str()); - } else { - // Try to find relative to the compiler binary. - const char *InstallDir = D.getInstalledDir(); + // 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. + // 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); + // 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 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); + } - if (ParentName == "llvm") { - // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin - Candidates.emplace_back(llvm::sys::path::parent_path(ParentDir).str(), - /*StrictChecking=*/true); - } + // 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; +} - Candidates.emplace_back(D.SysRoot + "/opt/rocm"); +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 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(); } - bool NoBuiltinLibs = Args.hasArg(options::OPT_nogpulib); + if (DetectHIPRuntime) + detectHIPRuntime(); + if (DetectDeviceLib) + detectDeviceLibrary(); +} +void RocmInstallationDetector::detectDeviceLibrary() { assert(LibDevicePath.empty()); - if (Args.hasArg(clang::driver::options::OPT_hip_device_lib_path_EQ)) { - LibDevicePath - = Args.getLastArgValue(clang::driver::options::OPT_hip_device_lib_path_EQ); - } else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH")) { + 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()) { @@ -152,61 +204,109 @@ if (!FS.exists(LibDevicePath)) return; - scanLibDevicePath(); - IsValid = allGenericLibsValid() && !LibDeviceMap.empty(); + 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 SubDirsList[] = { + {"amdgcn", "bitcode"}, + {"lib"}, + {"lib", "bitcode"}, + }; + + // Make a path by appending sub-directories to InstallPath. + auto MakePath = [&](const llvm::ArrayRef &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; - // 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. - // - // The desired structure is (${ROCM_ROOT} or - // ${OPENCL_ROOT})/amdgcn/bitcode/*, so try to detect this layout. - - // BinPath = InstallPath + "/bin"; - llvm::sys::path::append(IncludePath, InstallPath, "include"); - llvm::sys::path::append(LibDevicePath, InstallPath, "amdgcn", "bitcode"); + BinPath = InstallPath; + llvm::sys::path::append(BinPath, "bin"); + IncludePath = InstallPath; + llvm::sys::path::append(IncludePath, "include"); + LibPath = InstallPath; + llvm::sys::path::append(LibPath, "lib"); - // We don't need the include path for OpenCL, since clang already ships with - // the default header. - - bool CheckLibDevice = (!NoBuiltinLibs || Candidate.StrictChecking); - if (CheckLibDevice && !FS.exists(LibDevicePath)) + llvm::ErrorOr> VersionFile = + FS.getBufferForFile(BinPath + "/.hipVersion"); + if (!VersionFile && Candidate.StrictChecking) continue; - scanLibDevicePath(); - - if (!NoBuiltinLibs) { - // Check that the required non-target libraries are all available. - if (!allGenericLibsValid()) - continue; + if (HIPVersionArg.empty() && VersionFile) + ParseHIPVersionFile((*VersionFile)->getBuffer()); - // Check that we have found at least one libdevice that we can link in if - // -nobuiltinlib hasn't been specified. - if (LibDeviceMap.empty()) - continue; - } - - IsValid = true; - break; + HasHIPRuntime = true; + return; } + HasHIPRuntime = false; } void RocmInstallationDetector::print(raw_ostream &OS) const { - if (isValid()) - OS << "Found ROCm installation: " << InstallPath << '\n'; + 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 @@ -218,9 +318,12 @@ // 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); - llvm::sys::path::append(P, "include"); - llvm::sys::path::append(P, "cuda_wrappers"); + if (UsesRuntimeWrapper) + llvm::sys::path::append(P, "include", "cuda_wrappers"); CC1Args.push_back("-internal-isystem"); CC1Args.push_back(DriverArgs.MakeArgString(P)); } @@ -228,15 +331,15 @@ if (DriverArgs.hasArg(options::OPT_nogpuinc)) return; - if (!isValid()) { - D.Diag(diag::err_drv_no_rocm_installation); + if (!hasHIPRuntime()) { + D.Diag(diag::err_drv_no_hip_runtime); return; } CC1Args.push_back("-internal-isystem"); CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); - CC1Args.push_back("-include"); - CC1Args.push_back("__clang_hip_runtime_wrapper.h"); + if (UsesRuntimeWrapper) + CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"}); } void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -386,8 +489,9 @@ /// ROCM Toolchain ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : AMDGPUToolChain(D, Triple, Args), - RocmInstallation(D, Triple, Args) { } + : AMDGPUToolChain(D, Triple, Args), + RocmInstallation(D, Triple, Args, /*DetectHIPRuntime=*/false, + /*DetectDeviceLib=*/true) {} void AMDGPUToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, @@ -418,8 +522,8 @@ if (DriverArgs.hasArg(options::OPT_nogpulib)) return; - if (!RocmInstallation.isValid()) { - getDriver().Diag(diag::err_drv_no_rocm_installation); + if (!RocmInstallation.hasDeviceLibrary()) { + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; return; } @@ -429,7 +533,7 @@ 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) << GpuArch; + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch; return; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3953,7 +3953,8 @@ } } - 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(); @@ -4868,10 +4869,10 @@ 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); @@ -4990,6 +4991,11 @@ 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: @@ -5398,8 +5404,8 @@ // 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)) { diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2658,6 +2658,7 @@ // 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 { diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -224,6 +224,7 @@ // Lookup binaries into the driver directory, this is used to // discover the clang-offload-bundler executable. getProgramPaths().push_back(getDriver().Dir); + RocmInstallation.detectHIPRuntime(); } void HIPToolChain::addClangTargetOptions( @@ -279,8 +280,7 @@ 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, "", "HIP_DEVICE_LIB_PATH"); @@ -291,14 +291,14 @@ for (auto Lib : BCLibs) addBCLib(getDriver(), DriverArgs, CC1Args, LibraryPaths, Lib); } else { - if (!RocmInstallation.isValid()) { - getDriver().Diag(diag::err_drv_no_rocm_installation); + if (!RocmInstallation.hasDeviceLibrary()) { + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0; return; } std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); if (LibDeviceFile.empty()) { - getDriver().Diag(diag::err_drv_no_rocm_device_lib) << GpuArch; + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch; return; } diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -807,6 +807,7 @@ void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { CudaInstallation.print(OS); + RocmInstallation.print(OS); } // Windows SDKs and VC Toolchains group their contents into subdirectories based diff --git a/clang/lib/Driver/ToolChains/ROCm.h b/clang/lib/Driver/ToolChains/ROCm.h --- a/clang/lib/Driver/ToolChains/ROCm.h +++ b/clang/lib/Driver/ToolChains/ROCm.h @@ -18,6 +18,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Triple.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/VersionTuple.h" namespace clang { namespace driver { @@ -38,11 +39,43 @@ } }; + // 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 IsValid = false; - // RocmVersion Version = RocmVersion::UNKNOWN; + 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 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> BinPath; SmallString<0> LibPath; SmallString<0> LibDevicePath; SmallString<0> IncludePath; @@ -74,11 +107,15 @@ // CheckRocmVersionSupportsArch. mutable llvm::SmallSet ArchsWithBadVersion; - void scanLibDevicePath(); + void scanLibDevicePath(llvm::StringRef Path); + void ParseHIPVersionFile(llvm::StringRef V); + SmallVector getInstallationPathCandidates(); public: RocmInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, - const llvm::opt::ArgList &Args); + 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, @@ -93,8 +130,12 @@ /// most one error per Arch. void CheckRocmVersionSupportsArch(CudaArch Arch) const; - /// Check whether we detected a valid Rocm install. - bool isValid() const { return IsValid; } + /// 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; @@ -163,6 +204,22 @@ 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 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 diff --git a/clang/test/Driver/Inputs/rocm/bin/.hipVersion b/clang/test/Driver/Inputs/rocm/bin/.hipVersion new file mode 100644 --- /dev/null +++ b/clang/test/Driver/Inputs/rocm/bin/.hipVersion @@ -0,0 +1,4 @@ +# Auto-generated by cmake +HIP_VERSION_MAJOR=3 +HIP_VERSION_MINOR=6 +HIP_VERSION_PATCH=20214-a2917cd diff --git a/clang/test/Driver/hip-include-path.hip b/clang/test/Driver/hip-include-path.hip --- a/clang/test/Driver/hip-include-path.hip +++ b/clang/test/Driver/hip-include-path.hip @@ -37,3 +37,15 @@ // skip check of standard C++ include path // CLANG-SAME: "-internal-isystem" "{{.*}}clang/{{.*}}/include" // NOCLANG-NOT: "{{.*}}clang/{{.*}}/include" + +// RUN: %clang -c -### -target x86_64-unknown-linux-gnu --cuda-gpu-arch=gfx900 \ +// RUN: -std=c++11 --rocm-path=%S/Inputs/rocm -nogpulib %s 2>&1 \ +// RUN: --hip-version=3.5 | FileCheck -check-prefixes=ROCM35 %s + +// ROCM35-LABEL: "{{[^"]*}}clang{{[^"]*}}" "-cc1" +// ROCM35-NOT: "{{.*}}clang/{{.*}}/include/cuda_wrappers" +// ROCM35-SAME: "-internal-isystem" "{{[^"]*}}clang/{{[^"]*}}" +// ROCM35-SAME: "-internal-isystem" "{{[^"]*}}Inputs/rocm/include" +// ROCM35-NOT: "-include" "__clang_hip_runtime_wrapper.h" +// skip check of standard C++ include path +// ROCM35-SAME: "-internal-isystem" "{{[^"]*}}clang/{{[^"]*}}/include" diff --git a/clang/test/Driver/hip-launch-api.hip b/clang/test/Driver/hip-launch-api.hip new file mode 100644 --- /dev/null +++ b/clang/test/Driver/hip-launch-api.hip @@ -0,0 +1,17 @@ +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// By default FE assumes -fhip-new-launch-api. + +// RUN: %clang -### -target x86_64-unknown-linux-gnu -offload-arch=gfx906 %s \ +// RUN: 2>&1 | FileCheck -check-prefixes=NEW %s +// NEW: "-fhip-new-launch-api" + +// RUN: %clang -### -target x86_64-unknown-linux-gnu -offload-arch=gfx906 %s \ +// RUN: -fhip-new-launch-api 2>&1 | FileCheck -check-prefixes=NEW %s +// NEW: "-fhip-new-launch-api" + +// RUN: %clang -### -target x86_64-unknown-linux-gnu -offload-arch=gfx906 %s \ +// RUN: -fno-hip-new-launch-api 2>&1 | FileCheck -check-prefixes=OLD %s +// OLD-NOT: "-fhip-new-launch-api" diff --git a/clang/test/Driver/hip-std.hip b/clang/test/Driver/hip-std.hip new file mode 100644 --- /dev/null +++ b/clang/test/Driver/hip-std.hip @@ -0,0 +1,23 @@ +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// RUN: %clang -### -target x86_64-unknown-linux-gnu -offload-arch=gfx906 %s \ +// RUN: 2>&1 | FileCheck -check-prefixes=DEFAULT %s +// DEFAULT: "{{.*}}clang{{.*}}" "-cc1"{{.*}}"-fcuda-is-device"{{.*}}"-std=c++11" +// DEFAULT: "{{.*}}clang{{.*}}" "-cc1"{{.*}}"-std=c++11" + +// RUN: %clang -### -target x86_64-unknown-linux-gnu -offload-arch=gfx906 %s \ +// RUN: -std=c++17 %s 2>&1 | FileCheck -check-prefixes=SPECIFIED %s +// SPECIFIED: "{{.*}}clang{{.*}}" "-cc1"{{.*}}"-fcuda-is-device"{{.*}}"-std=c++17" +// SPECIFIED: "{{.*}}clang{{.*}}" "-cc1"{{.*}}"-std=c++17" + +// RUN: %clang -### -target x86_64-pc-windows-msvc -offload-arch=gfx906 %s \ +// RUN: 2>&1 | FileCheck -check-prefixes=MSVC-DEF %s +// MSVC-DEF: "{{.*}}clang{{.*}}" "-cc1"{{.*}}"-fcuda-is-device"{{.*}}"-std=c++14" +// MSVC-DEF: "{{.*}}clang{{.*}}" "-cc1"{{.*}}"-std=c++14" + +// RUN: %clang -### -target x86_64-pc-windows-msvc -offload-arch=gfx906 %s \ +// RUN: -std=c++17 %s 2>&1 | FileCheck -check-prefixes=MSVC-SPEC %s +// MSVC-SPEC: "{{.*}}clang{{.*}}" "-cc1"{{.*}}"-fcuda-is-device"{{.*}}"-std=c++17" +// MSVC-SPEC: "{{.*}}clang{{.*}}" "-cc1"{{.*}}"-std=c++17" diff --git a/clang/test/Driver/hip-version.hip b/clang/test/Driver/hip-version.hip new file mode 100644 --- /dev/null +++ b/clang/test/Driver/hip-version.hip @@ -0,0 +1,30 @@ +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// RUN: %clang -v --rocm-path=%S/Inputs/rocm 2>&1 \ +// RUN: | FileCheck -check-prefixes=FOUND %s + +// FOUND: Found HIP installation: {{.*Inputs.*rocm}}, version 3.6.20214-a2917cd + +// When --rocm-path is set and .hipVersion is not found, use default version + +// RUN: %clang -v --rocm-path=%S 2>&1 \ +// RUN: | FileCheck -check-prefixes=DEFAULT %s + +// DEFAULT: Found HIP installation: {{.*Driver}}, version 3.5. + +// RUN: %clang -v --rocm-path=%S --hip-version=3.7.0 2>&1 \ +// RUN: | FileCheck -check-prefixes=SPECIFIED %s + +// SPECIFIED: Found HIP installation: {{.*Driver}}, version 3.7.0 + +// RUN: %clang -v --rocm-path=%S --hip-version=3.7 2>&1 \ +// RUN: | FileCheck -check-prefixes=SPECIFIED2 %s + +// SPECIFIED2: Found HIP installation: {{.*Driver}}, version 3.7.0 + +// RUN: not %clang -v --rocm-path=%S --hip-version=x.y 2>&1 \ +// RUN: | FileCheck -check-prefixes=INVALID %s + +// INVALID: error: invalid value 'x.y' in '--hip-version=x.y' diff --git a/clang/test/Driver/rocm-detect.hip b/clang/test/Driver/rocm-detect.hip --- a/clang/test/Driver/rocm-detect.hip +++ b/clang/test/Driver/rocm-detect.hip @@ -22,6 +22,6 @@ // RUN: | FileCheck -check-prefixes=COMMON,GFX902,NODEFAULTLIBS %s -// GFX902-DEFAULTLIBS: error: cannot find device library for gfx902. Provide path to different ROCm installation via --rocm-path, or pass -nogpulib to build without linking default libraries. +// GFX902-DEFAULTLIBS: error: cannot find ROCm device library for gfx902. Provide its path via --rocm-path or --rocm-device-lib-path, or pass -nogpulib to build without ROCm device library // NODEFAULTLIBS-NOT: error: cannot find diff --git a/clang/test/Driver/rocm-detect.cl b/clang/test/Driver/rocm-detect.cl --- a/clang/test/Driver/rocm-detect.cl +++ b/clang/test/Driver/rocm-detect.cl @@ -16,6 +16,6 @@ // RUN: | FileCheck -check-prefixes=COMMON,GFX902,NODEFAULTLIBS %s -// GFX902-DEFAULTLIBS: error: cannot find device library for gfx902. Provide path to different ROCm installation via --rocm-path, or pass -nogpulib to build without linking default libraries. +// GFX902-DEFAULTLIBS: error: cannot find ROCm device library for gfx902. Provide its path via --rocm-path or --rocm-device-lib-path, or pass -nogpulib to build without ROCm device library // NODEFAULTLIBS-NOT: error: cannot find diff --git a/clang/test/Driver/rocm-not-found.cl b/clang/test/Driver/rocm-not-found.cl --- a/clang/test/Driver/rocm-not-found.cl +++ b/clang/test/Driver/rocm-not-found.cl @@ -5,7 +5,7 @@ // RUN: %clang -### --sysroot=%s/no-rocm-there -target amdgcn--amdhsa %s 2>&1 | FileCheck %s --check-prefix ERR // RUN: %clang -### --rocm-path=%s/no-rocm-there -target amdgcn--amdhsa %s 2>&1 | FileCheck %s --check-prefix ERR -// ERR: cannot find ROCm installation. Provide its path via --rocm-path, or pass -nogpulib and -nogpuinc to build without ROCm device library and HIP includes. +// ERR: cannot find ROCm device library. Provide its path via --rocm-path or --rocm-device-lib-path, or pass -nogpulib to build without ROCm device library // Accept nogpulib or nostdlib for OpenCL. // RUN: %clang -### -nogpulib --rocm-path=%s/no-rocm-there %s 2>&1 | FileCheck %s --check-prefix OK