[HIP] Fix rocm detection

Do not detect device library by default in rocm detector.
Only detect device library in Rocm and HIP toolchain.

Separate detection of HIP runtime and Rocm device library.

Detect rocm path by version file in host toolchains.

Also added detecting rocm version and printing rocm
installation path and version with -v.

Fixed include path and device library detection for
ROCm 3.5.

Added --hip-version option. Renamed --hip-device-lib-path
to --rocm-device-lib-path.

Fixed default value for -fhip-new-launch-api.

Added default -std option for HIP.

Differential Revision: https://reviews.llvm.org/D82930
This commit is contained in:
Yaxun (Sam) Liu 2020-07-01 00:00:04 -04:00
parent e628092524
commit 849d4405f5
17 changed files with 385 additions and 126 deletions

View File

@ -56,12 +56,12 @@ def err_drv_no_cuda_libdevice : Error<
"cannot find libdevice for %0. Provide path to different CUDA installation " "cannot find libdevice for %0. Provide path to different CUDA installation "
"via --cuda-path, or pass -nocudalib to build without linking with libdevice.">; "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< def err_drv_no_rocm_device_lib : Error<
"cannot find device library for %0. Provide path to different ROCm installation " "cannot find ROCm device library%select{| for %1}0. Provide its path via --rocm-path or "
"via --rocm-path, or pass -nogpulib to build without linking default libraries.">; "--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< def err_drv_cuda_version_unsupported : Error<
"GPU arch %0 is supported by CUDA versions between %1 and %2 (inclusive), " "GPU arch %0 is supported by CUDA versions between %1 and %2 (inclusive), "

View File

@ -637,15 +637,19 @@ defm cuda_short_ptr : OptInFFlag<"cuda-short-ptr",
"Use 32-bit pointers for accessing const/local/shared address spaces">; "Use 32-bit pointers for accessing const/local/shared address spaces">;
def rocm_path_EQ : Joined<["--"], "rocm-path=">, Group<i_Group>, def rocm_path_EQ : Joined<["--"], "rocm-path=">, Group<i_Group>,
HelpText<"ROCm installation path, used for finding and automatically linking required bitcode libraries.">; 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<Link_Group>, def rocm_device_lib_path_EQ : Joined<["--"], "rocm-device-lib-path=">, Group<Link_Group>,
HelpText<"HIP device library path. Alternative to rocm-path.">; HelpText<"ROCm device library path. Alternative to rocm-path.">;
def : Joined<["--"], "hip-device-lib-path=">, Alias<rocm_device_lib_path_EQ>;
def hip_device_lib_EQ : Joined<["--"], "hip-device-lib=">, Group<Link_Group>, def hip_device_lib_EQ : Joined<["--"], "hip-device-lib=">, Group<Link_Group>,
HelpText<"HIP device library">; 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">, def fhip_dump_offload_linker_script : Flag<["-"], "fhip-dump-offload-linker-script">,
Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>; Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>;
defm hip_new_launch_api : OptInFFlag<"hip-new-launch-api", defm hip_new_launch_api : OptInFFlag<"hip-new-launch-api",
"Use new kernel launching API for HIP">; "Use", "Don't use", " new kernel launching API for HIP">;
defm gpu_allow_device_init : OptInFFlag<"gpu-allow-device-init", "Allow device side init function in 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=">, def gpu_max_threads_per_block_EQ : Joined<["--"], "gpu-max-threads-per-block=">,
Flags<[CC1Option]>, Flags<[CC1Option]>,
HelpText<"Default max threads per block for kernel launch bounds for HIP">; HelpText<"Default max threads per block for kernel launch bounds for HIP">;

View File

@ -242,7 +242,7 @@ void CGNVCUDARuntime::emitDeviceStub(CodeGenFunction &CGF,
EmittedKernels.push_back({CGF.CurFn, CGF.CurFuncDecl}); EmittedKernels.push_back({CGF.CurFn, CGF.CurFuncDecl});
if (CudaFeatureEnabled(CGM.getTarget().getSDKVersion(), if (CudaFeatureEnabled(CGM.getTarget().getSDKVersion(),
CudaFeature::CUDA_USES_NEW_LAUNCH) || CudaFeature::CUDA_USES_NEW_LAUNCH) ||
CGF.getLangOpts().HIPUseNewLaunchAPI) (CGF.getLangOpts().HIP && CGF.getLangOpts().HIPUseNewLaunchAPI))
emitDeviceStubBodyNew(CGF, Args); emitDeviceStubBodyNew(CGF, Args);
else else
emitDeviceStubBodyLegacy(CGF, Args); emitDeviceStubBodyLegacy(CGF, Args);

View File

@ -21,16 +21,14 @@ using namespace clang::driver::toolchains;
using namespace clang; using namespace clang;
using namespace llvm::opt; using namespace llvm::opt;
void RocmInstallationDetector::scanLibDevicePath() { void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
assert(!LibDevicePath.empty()); assert(!Path.empty());
const StringRef Suffix(".bc"); const StringRef Suffix(".bc");
const StringRef Suffix2(".amdgcn.bc"); const StringRef Suffix2(".amdgcn.bc");
std::error_code EC; std::error_code EC;
for (llvm::vfs::directory_iterator for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Path, EC), LE;
LI = D.getVFS().dir_begin(LibDevicePath, EC),
LE;
!EC && LI != LE; LI = LI.increment(EC)) { !EC && LI != LE; LI = LI.increment(EC)) {
StringRef FilePath = LI->path(); StringRef FilePath = LI->path();
StringRef FileName = llvm::sys::path::filename(FilePath); StringRef FileName = llvm::sys::path::filename(FilePath);
@ -89,60 +87,114 @@ void RocmInstallationDetector::scanLibDevicePath() {
} }
} }
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( RocmInstallationDetector::RocmInstallationDetector(
const Driver &D, const llvm::Triple &HostTriple, const Driver &D, const llvm::Triple &HostTriple,
const llvm::opt::ArgList &Args) const llvm::opt::ArgList &Args, bool DetectHIPRuntime, bool DetectDeviceLib)
: D(D) { : D(D) {
struct Candidate { RocmPathArg = Args.getLastArgValue(clang::driver::options::OPT_rocm_path_EQ);
std::string Path; RocmDeviceLibPathArg =
bool StrictChecking; 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;
Candidate(std::string Path, bool StrictChecking = false) VersionMajorMinor = llvm::VersionTuple(Major, Minor);
: Path(Path), StrictChecking(StrictChecking) {} DetectedVersion =
}; (Twine(Major) + "." + Twine(Minor) + "." + VersionPatch).str();
SmallVector<Candidate, 4> 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 { } else {
// Try to find relative to the compiler binary. VersionPatch = DefaultVersionPatch;
const char *InstallDir = D.getInstalledDir(); VersionMajorMinor =
llvm::VersionTuple(DefaultVersionMajor, DefaultVersionMinor);
// Check both a normal Unix prefix position of the clang binary, as well as DetectedVersion = (Twine(DefaultVersionMajor) + "." +
// the Windows-esque layout the ROCm packages use with the host architecture Twine(DefaultVersionMinor) + "." + VersionPatch)
// subdirectory of bin. .str();
// 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);
}
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);
}
Candidates.emplace_back(D.SysRoot + "/opt/rocm");
} }
bool NoBuiltinLibs = Args.hasArg(options::OPT_nogpulib); if (DetectHIPRuntime)
detectHIPRuntime();
if (DetectDeviceLib)
detectDeviceLibrary();
}
void RocmInstallationDetector::detectDeviceLibrary() {
assert(LibDevicePath.empty()); assert(LibDevicePath.empty());
if (Args.hasArg(clang::driver::options::OPT_hip_device_lib_path_EQ)) { if (!RocmDeviceLibPathArg.empty())
LibDevicePath LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1];
= Args.getLastArgValue(clang::driver::options::OPT_hip_device_lib_path_EQ); else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH"))
} else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH")) {
LibDevicePath = LibPathEnv; LibDevicePath = LibPathEnv;
}
auto &FS = D.getVFS(); auto &FS = D.getVFS();
if (!LibDevicePath.empty()) { if (!LibDevicePath.empty()) {
@ -152,61 +204,109 @@ RocmInstallationDetector::RocmInstallationDetector(
if (!FS.exists(LibDevicePath)) if (!FS.exists(LibDevicePath))
return; return;
scanLibDevicePath(); scanLibDevicePath(LibDevicePath);
IsValid = allGenericLibsValid() && !LibDeviceMap.empty(); HasDeviceLibrary = allGenericLibsValid() && !LibDeviceMap.empty();
return; 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) { for (const auto &Candidate : Candidates) {
InstallPath = Candidate.Path; InstallPath = Candidate.Path;
if (InstallPath.empty() || !FS.exists(InstallPath)) if (InstallPath.empty() || !FS.exists(InstallPath))
continue; continue;
// The install path situation in old versions of ROCm is a real mess, and BinPath = InstallPath;
// use a different install layout. Multiple copies of the device libraries llvm::sys::path::append(BinPath, "bin");
// exist for each frontend project, and differ depending on which build IncludePath = InstallPath;
// system produced the packages. Standalone OpenCL builds also have a llvm::sys::path::append(IncludePath, "include");
// different directory structure from the ROCm OpenCL package. LibPath = InstallPath;
// llvm::sys::path::append(LibPath, "lib");
// The desired structure is (${ROCM_ROOT} or
// ${OPENCL_ROOT})/amdgcn/bitcode/*, so try to detect this layout.
// BinPath = InstallPath + "/bin"; llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
llvm::sys::path::append(IncludePath, InstallPath, "include"); FS.getBufferForFile(BinPath + "/.hipVersion");
llvm::sys::path::append(LibDevicePath, InstallPath, "amdgcn", "bitcode"); if (!VersionFile && Candidate.StrictChecking)
// 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))
continue; continue;
scanLibDevicePath(); if (HIPVersionArg.empty() && VersionFile)
ParseHIPVersionFile((*VersionFile)->getBuffer());
if (!NoBuiltinLibs) { HasHIPRuntime = true;
// Check that the required non-target libraries are all available. return;
if (!allGenericLibsValid())
continue;
// 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 = false;
} }
void RocmInstallationDetector::print(raw_ostream &OS) const { void RocmInstallationDetector::print(raw_ostream &OS) const {
if (isValid()) if (hasHIPRuntime())
OS << "Found ROCm installation: " << InstallPath << '\n'; OS << "Found HIP installation: " << InstallPath << ", version "
<< DetectedVersion << '\n';
} }
void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const { ArgStringList &CC1Args) const {
bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5);
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
// HIP header includes standard library wrapper headers under clang // HIP header includes standard library wrapper headers under clang
// cuda_wrappers directory. Since these wrapper headers include_next // cuda_wrappers directory. Since these wrapper headers include_next
@ -218,9 +318,12 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs,
// Since standard C++ and other clang include paths are added in other // Since standard C++ and other clang include paths are added in other
// places after this function, here we only need to make sure wrapper // places after this function, here we only need to make sure wrapper
// include path is added. // include path is added.
//
// ROCm 3.5 does not fully support the wrapper headers. Therefore it needs
// a workaround.
SmallString<128> P(D.ResourceDir); SmallString<128> P(D.ResourceDir);
llvm::sys::path::append(P, "include"); if (UsesRuntimeWrapper)
llvm::sys::path::append(P, "cuda_wrappers"); llvm::sys::path::append(P, "include", "cuda_wrappers");
CC1Args.push_back("-internal-isystem"); CC1Args.push_back("-internal-isystem");
CC1Args.push_back(DriverArgs.MakeArgString(P)); CC1Args.push_back(DriverArgs.MakeArgString(P));
} }
@ -228,15 +331,15 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs,
if (DriverArgs.hasArg(options::OPT_nogpuinc)) if (DriverArgs.hasArg(options::OPT_nogpuinc))
return; return;
if (!isValid()) { if (!hasHIPRuntime()) {
D.Diag(diag::err_drv_no_rocm_installation); D.Diag(diag::err_drv_no_hip_runtime);
return; return;
} }
CC1Args.push_back("-internal-isystem"); CC1Args.push_back("-internal-isystem");
CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath()));
CC1Args.push_back("-include"); if (UsesRuntimeWrapper)
CC1Args.push_back("__clang_hip_runtime_wrapper.h"); CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"});
} }
void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@ -386,8 +489,9 @@ bool AMDGPUToolChain::isWave64(const llvm::opt::ArgList &DriverArgs,
/// ROCM Toolchain /// ROCM Toolchain
ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple, ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args) const ArgList &Args)
: AMDGPUToolChain(D, Triple, Args), : AMDGPUToolChain(D, Triple, Args),
RocmInstallation(D, Triple, Args) { } RocmInstallation(D, Triple, Args, /*DetectHIPRuntime=*/false,
/*DetectDeviceLib=*/true) {}
void AMDGPUToolChain::addClangTargetOptions( void AMDGPUToolChain::addClangTargetOptions(
const llvm::opt::ArgList &DriverArgs, const llvm::opt::ArgList &DriverArgs,
@ -418,8 +522,8 @@ void ROCMToolChain::addClangTargetOptions(
if (DriverArgs.hasArg(options::OPT_nogpulib)) if (DriverArgs.hasArg(options::OPT_nogpulib))
return; return;
if (!RocmInstallation.isValid()) { if (!RocmInstallation.hasDeviceLibrary()) {
getDriver().Diag(diag::err_drv_no_rocm_installation); getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
return; return;
} }
@ -429,7 +533,7 @@ void ROCMToolChain::addClangTargetOptions(
const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind);
std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
if (LibDeviceFile.empty()) { 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; return;
} }

View File

@ -3953,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 IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment();
bool IsIAMCU = RawTriple.isOSIAMCU(); bool IsIAMCU = RawTriple.isOSIAMCU();
@ -4868,10 +4869,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_finstrument_functions_after_inlining, options::OPT_finstrument_functions_after_inlining,
options::OPT_finstrument_function_entry_bare); options::OPT_finstrument_function_entry_bare);
// NVPTX doesn't support PGO or coverage. There's no runtime support for // NVPTX/AMDGCN doesn't support PGO or coverage. There's no runtime support
// sampling, overhead of call arc collection is way too high and there's no // for sampling, overhead of call arc collection is way too high and there's
// way to collect the output. // no way to collect the output.
if (!Triple.isNVPTX()) if (!Triple.isNVPTX() && !Triple.isAMDGCN())
addPGOAndCoverageFlags(TC, C, D, Output, Args, CmdArgs); addPGOAndCoverageFlags(TC, C, D, Output, Args, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ); Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ);
@ -4990,6 +4991,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs, Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs,
options::OPT_fno_trigraphs); 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: // GCC's behavior for -Wwrite-strings is a bit strange:
@ -5398,8 +5404,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Forward -cl options to -cc1 // Forward -cl options to -cc1
RenderOpenCLOptions(Args, CmdArgs); RenderOpenCLOptions(Args, CmdArgs);
if (Args.hasFlag(options::OPT_fhip_new_launch_api, if (IsHIP && Args.hasFlag(options::OPT_fhip_new_launch_api,
options::OPT_fno_hip_new_launch_api, false)) options::OPT_fno_hip_new_launch_api, true))
CmdArgs.push_back("-fhip-new-launch-api"); CmdArgs.push_back("-fhip-new-launch-api");
if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) { if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {

View File

@ -2658,6 +2658,7 @@ void Generic_GCC::printVerboseInfo(raw_ostream &OS) const {
// Print the information about how we detected the GCC installation. // Print the information about how we detected the GCC installation.
GCCInstallation.print(OS); GCCInstallation.print(OS);
CudaInstallation.print(OS); CudaInstallation.print(OS);
RocmInstallation.print(OS);
} }
bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const { bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const {

View File

@ -224,6 +224,7 @@ HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple,
// Lookup binaries into the driver directory, this is used to // Lookup binaries into the driver directory, this is used to
// discover the clang-offload-bundler executable. // discover the clang-offload-bundler executable.
getProgramPaths().push_back(getDriver().Dir); getProgramPaths().push_back(getDriver().Dir);
RocmInstallation.detectHIPRuntime();
} }
void HIPToolChain::addClangTargetOptions( void HIPToolChain::addClangTargetOptions(
@ -279,8 +280,7 @@ void HIPToolChain::addClangTargetOptions(
ArgStringList LibraryPaths; ArgStringList LibraryPaths;
// Find in --hip-device-lib-path and HIP_LIBRARY_PATH. // Find in --hip-device-lib-path and HIP_LIBRARY_PATH.
for (auto Path : for (auto Path : RocmInstallation.getRocmDeviceLibPathArg())
DriverArgs.getAllArgValues(options::OPT_hip_device_lib_path_EQ))
LibraryPaths.push_back(DriverArgs.MakeArgString(Path)); LibraryPaths.push_back(DriverArgs.MakeArgString(Path));
addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH"); addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH");
@ -291,14 +291,14 @@ void HIPToolChain::addClangTargetOptions(
for (auto Lib : BCLibs) for (auto Lib : BCLibs)
addBCLib(getDriver(), DriverArgs, CC1Args, LibraryPaths, Lib); addBCLib(getDriver(), DriverArgs, CC1Args, LibraryPaths, Lib);
} else { } else {
if (!RocmInstallation.isValid()) { if (!RocmInstallation.hasDeviceLibrary()) {
getDriver().Diag(diag::err_drv_no_rocm_installation); getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
return; return;
} }
std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
if (LibDeviceFile.empty()) { 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; return;
} }

View File

@ -807,6 +807,7 @@ void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
CudaInstallation.print(OS); CudaInstallation.print(OS);
RocmInstallation.print(OS);
} }
// Windows SDKs and VC Toolchains group their contents into subdirectories based // Windows SDKs and VC Toolchains group their contents into subdirectories based

View File

@ -18,6 +18,7 @@
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Triple.h" #include "llvm/ADT/Triple.h"
#include "llvm/Option/ArgList.h" #include "llvm/Option/ArgList.h"
#include "llvm/Support/VersionTuple.h"
namespace clang { namespace clang {
namespace driver { namespace driver {
@ -38,11 +39,43 @@ private:
} }
}; };
// 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; const Driver &D;
bool IsValid = false; bool HasHIPRuntime = false;
// RocmVersion Version = RocmVersion::UNKNOWN; 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> InstallPath;
// SmallString<0> BinPath; SmallString<0> BinPath;
SmallString<0> LibPath; SmallString<0> LibPath;
SmallString<0> LibDevicePath; SmallString<0> LibDevicePath;
SmallString<0> IncludePath; SmallString<0> IncludePath;
@ -74,11 +107,15 @@ private:
// CheckRocmVersionSupportsArch. // CheckRocmVersionSupportsArch.
mutable llvm::SmallSet<CudaArch, 4> ArchsWithBadVersion; mutable llvm::SmallSet<CudaArch, 4> ArchsWithBadVersion;
void scanLibDevicePath(); void scanLibDevicePath(llvm::StringRef Path);
void ParseHIPVersionFile(llvm::StringRef V);
SmallVector<Candidate, 4> getInstallationPathCandidates();
public: public:
RocmInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, 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. /// Add arguments needed to link default bitcode libraries.
void addCommonBitcodeLibCC1Args(const llvm::opt::ArgList &DriverArgs, void addCommonBitcodeLibCC1Args(const llvm::opt::ArgList &DriverArgs,
@ -93,8 +130,12 @@ public:
/// most one error per Arch. /// most one error per Arch.
void CheckRocmVersionSupportsArch(CudaArch Arch) const; void CheckRocmVersionSupportsArch(CudaArch Arch) const;
/// Check whether we detected a valid Rocm install. /// Check whether we detected a valid HIP runtime.
bool isValid() const { return IsValid; } 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. /// Print information about the detected ROCm installation.
void print(raw_ostream &OS) const; void print(raw_ostream &OS) const;
@ -163,6 +204,22 @@ public:
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const; 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 driver

View File

@ -0,0 +1,4 @@
# Auto-generated by cmake
HIP_VERSION_MAJOR=3
HIP_VERSION_MINOR=6
HIP_VERSION_PATCH=20214-a2917cd

View File

@ -37,3 +37,15 @@
// skip check of standard C++ include path // skip check of standard C++ include path
// CLANG-SAME: "-internal-isystem" "{{.*}}clang/{{.*}}/include" // CLANG-SAME: "-internal-isystem" "{{.*}}clang/{{.*}}/include"
// NOCLANG-NOT: "{{.*}}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"

View File

@ -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"

View File

@ -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"

View File

@ -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'

View File

@ -16,6 +16,6 @@
// RUN: | FileCheck -check-prefixes=COMMON,GFX902,NODEFAULTLIBS %s // 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 // NODEFAULTLIBS-NOT: error: cannot find

View File

@ -22,6 +22,6 @@
// RUN: | FileCheck -check-prefixes=COMMON,GFX902,NODEFAULTLIBS %s // 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 // NODEFAULTLIBS-NOT: error: cannot find

View File

@ -5,7 +5,7 @@
// RUN: %clang -### --sysroot=%s/no-rocm-there -target amdgcn--amdhsa %s 2>&1 | FileCheck %s --check-prefix ERR // 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 // 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. // Accept nogpulib or nostdlib for OpenCL.
// RUN: %clang -### -nogpulib --rocm-path=%s/no-rocm-there %s 2>&1 | FileCheck %s --check-prefix OK // RUN: %clang -### -nogpulib --rocm-path=%s/no-rocm-there %s 2>&1 | FileCheck %s --check-prefix OK