using namespace clang;
using namespace llvm::opt;
+void RocmInstallationDetector::scanLibDevicePath() {
+ assert(!LibDevicePath.empty());
+
+ const StringRef Suffix(".bc");
+
+ std::error_code EC;
+ for (llvm::sys::fs::directory_iterator LI(LibDevicePath, 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 = 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()));
+ }
+ }
+}
+
RocmInstallationDetector::RocmInstallationDetector(
const Driver &D, const llvm::Triple &HostTriple,
const llvm::opt::ArgList &Args)
bool NoBuiltinLibs = Args.hasArg(options::OPT_nogpulib);
+ 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")) {
+ LibDevicePath = LibPathEnv;
+ }
+
+ 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 (!D.getVFS().exists(LibDevicePath))
+ return;
+
+ scanLibDevicePath();
+ IsValid = allGenericLibsValid() && !LibDeviceMap.empty();
+ return;
+ }
+
for (const auto &Candidate : Candidates) {
InstallPath = Candidate.Path;
if (InstallPath.empty() || !D.getVFS().exists(InstallPath))
if (CheckLibDevice && !FS.exists(LibDevicePath))
continue;
- const StringRef Suffix(".bc");
-
- std::error_code EC;
- for (llvm::sys::fs::directory_iterator LI(LibDevicePath, 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 = 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()));
- }
- }
+ scanLibDevicePath();
if (!NoBuiltinLibs) {
// Check that the required non-target libraries are all available.
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)
return;
}
- const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind);
- static bool HasWave32 = (ArchAttr & llvm::AMDGPU::FEATURE_WAVE32);
-
- bool Wave64 = !HasWave32 || DriverArgs.hasFlag(
- options::OPT_mwavefrontsize64, options::OPT_mno_wavefrontsize64, false);
+ bool Wave64 = isWave64(DriverArgs, Kind);
// TODO: There are way too many flags that change this. Do we need to check
// them all?
// CheckRocmVersionSupportsArch.
mutable llvm::SmallSet<CudaArch, 4> ArchsWithBadVersion;
+ void scanLibDevicePath();
+
public:
RocmInstallationDetector(const Driver &D, const llvm::Triple &HostTriple,
const llvm::opt::ArgList &Args);
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);
};
class LLVM_LIBRARY_VISIBILITY ROCMToolChain : public AMDGPUToolChain {
-private:
+protected:
RocmInstallationDetector RocmInstallation;
public:
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));
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.isValid()) {
+ getDriver().Diag(diag::err_drv_no_rocm_installation);
+ 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) << 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";
-
- bool FTZDAZ = DriverArgs.hasFlag(
- options::OPT_fcuda_flush_denormals_to_zero,
- options::OPT_fno_cuda_flush_denormals_to_zero,
- getDefaultDenormsAreZeroForTarget(Kind));
-
- std::string FlushDenormalControlBC = FTZDAZ ?
- "oclc_daz_opt_on.amdgcn.bc" :
- "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,
- std::string(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 *
// Test subtarget with flushing on by default.
// RUN: %clang -### -target x86_64-linux-gnu \
-// RUN: --cuda-gpu-arch=gfx803 \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --cuda-gpu-arch=gfx803 \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// Test subtarget with flushing off by ddefault.
// RUN: %clang -### -target x86_64-linux-gnu \
-// RUN: --cuda-gpu-arch=gfx900 \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --cuda-gpu-arch=gfx900 \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx900 \
// RUN: -fcuda-flush-denormals-to-zero \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx803 \
// RUN: -fno-cuda-flush-denormals-to-zero \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx900 \
// RUN: -fno-cuda-flush-denormals-to-zero \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx803 \
// RUN: -fcuda-flush-denormals-to-zero \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx803 \
// RUN: -fcuda-flush-denormals-to-zero -fno-cuda-flush-denormals-to-zero \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx900 \
// RUN: -fcuda-flush-denormals-to-zero -fno-cuda-flush-denormals-to-zero \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,NOFLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx900 \
// RUN: -fno-cuda-flush-denormals-to-zero -fcuda-flush-denormals-to-zero \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx803 \
// RUN: -fno-cuda-flush-denormals-to-zero -fcuda-flush-denormals-to-zero \
-// RUN: --hip-device-lib-path=%S/Inputs/hip_dev_lib \
+// RUN: --rocm-path=%S/Inputs/rocm-device-libs \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
-// Test environment variable HIP_DEVICE_LIB_PATH
+// Test --hip-device-lib-path flag
+// RUN: %clang -### -target x86_64-linux-gnu \
+// RUN: --cuda-gpu-arch=gfx803 \
+// RUN: --hip-device-lib-path=%S/Inputs/rocm-device-libs/amdgcn/bitcode \
+// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
+// RUN: 2>&1 | FileCheck %s --check-prefixes=COM,FLUSHD
-// RUN: env HIP_DEVICE_LIB_PATH=%S/Inputs/hip_dev_lib \
+
+// Test environment variable HIP_DEVICE_LIB_PATH
+// RUN: env HIP_DEVICE_LIB_PATH=%S/Inputs/rocm-device-libs/amdgcn/bitcode \
// RUN: %clang -### -target x86_64-linux-gnu \
// RUN: --cuda-gpu-arch=gfx900 \
// RUN: %S/Inputs/hip_multiple_inputs/b.hip \
// RUN: 2>&1 | FileCheck %s --check-prefixes=COM
// COM: {{"[^"]*clang[^"]*"}}
-// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}hip.amdgcn.bc"
-// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}ocml.amdgcn.bc"
-// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}ockl.amdgcn.bc"
-// FLUSHD-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_daz_opt_on.amdgcn.bc"
-// NOFLUSHD-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_daz_opt_off.amdgcn.bc"
+// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}hip.bc"
+// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}ocml.bc"
+// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}ockl.bc"
+
+// FLUSHD-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_daz_opt_on.bc"
+// NOFLUSHD-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_daz_opt_off.bc"
+
+// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_unsafe_math_off.bc"
+// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_finite_only_off.bc"
+// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_correctly_rounded_sqrt_on.bc"
+// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_wavefrontsize64_on.bc"
+// COM-SAME: "-mlink-builtin-bitcode" "{{.*}}oclc_isa_version_{{[0-9]+}}.bc"
+// Test --hip-device-lib-path format
+// RUN: %clang -### -target amdgcn-amd-amdhsa \
+// RUN: -x cl -mcpu=gfx900 \
+// RUN: --hip-device-lib-path=%S/Inputs/rocm-device-libs/amdgcn/bitcode \
+// RUN: %S/opencl.cl \
+// RUN: 2>&1 | FileCheck -dump-input-on-failure --check-prefixes=COMMON,COMMON-DEFAULT,GFX900-DEFAULT,GFX900,WAVE64 %s
+
+// Test environment variable HIP_DEVICE_LIB_PATH
+// RUN: env HIP_DEVICE_LIB_PATH=%S/Inputs/rocm-device-libs/amdgcn/bitcode %clang -### -target amdgcn-amd-amdhsa \
+// RUN: -x cl -mcpu=gfx900 \
+// RUN: %S/opencl.cl \
+// RUN: 2>&1 | FileCheck -dump-input-on-failure --check-prefixes=COMMON,COMMON-DEFAULT,GFX900-DEFAULT,GFX900,WAVE64 %s
+
+
+
// COMMON: "-triple" "amdgcn-amd-amdhsa"
// COMMON-SAME: "-mlink-builtin-bitcode" "{{.*}}/amdgcn/bitcode/opencl.bc"
// COMMON-SAME: "-mlink-builtin-bitcode" "{{.*}}/amdgcn/bitcode/ocml.bc"