| 1 | //===--- ROCm.h - ROCm installation detector --------------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ROCM_H |
| 10 | #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ROCM_H |
| 11 | |
| 12 | #include "clang/Basic/Cuda.h" |
| 13 | #include "clang/Basic/LLVM.h" |
| 14 | #include "clang/Driver/Driver.h" |
| 15 | #include "clang/Driver/Options.h" |
| 16 | #include "clang/Driver/SanitizerArgs.h" |
| 17 | #include "llvm/ADT/SmallString.h" |
| 18 | #include "llvm/ADT/StringMap.h" |
| 19 | #include "llvm/Option/ArgList.h" |
| 20 | #include "llvm/Support/VersionTuple.h" |
| 21 | #include "llvm/TargetParser/Triple.h" |
| 22 | |
| 23 | namespace clang { |
| 24 | namespace driver { |
| 25 | |
| 26 | /// ABI version of device library. |
| 27 | struct DeviceLibABIVersion { |
| 28 | unsigned ABIVersion = 0; |
| 29 | DeviceLibABIVersion(unsigned V) : ABIVersion(V) {} |
| 30 | static DeviceLibABIVersion fromCodeObjectVersion(unsigned CodeObjectVersion) { |
| 31 | if (CodeObjectVersion < 4) |
| 32 | CodeObjectVersion = 4; |
| 33 | return DeviceLibABIVersion(CodeObjectVersion * 100); |
| 34 | } |
| 35 | /// Whether ABI version bc file is requested. |
| 36 | /// ABIVersion is code object version multiplied by 100. Code object v4 |
| 37 | /// and below works with ROCm 5.0 and below which does not have |
| 38 | /// abi_version_*.bc. Code object v5 requires abi_version_500.bc. |
| 39 | bool requiresLibrary() { return ABIVersion >= 500; } |
| 40 | std::string toString() { return Twine(getAsCodeObjectVersion()).str(); } |
| 41 | |
| 42 | unsigned getAsCodeObjectVersion() const { |
| 43 | assert(ABIVersion % 100 == 0 && "Not supported" ); |
| 44 | return ABIVersion / 100; |
| 45 | } |
| 46 | }; |
| 47 | |
| 48 | /// A class to find a viable ROCM installation |
| 49 | /// TODO: Generalize to handle libclc. |
| 50 | class RocmInstallationDetector { |
| 51 | private: |
| 52 | struct ConditionalLibrary { |
| 53 | SmallString<0> On; |
| 54 | SmallString<0> Off; |
| 55 | |
| 56 | bool isValid() const { return !On.empty() && !Off.empty(); } |
| 57 | |
| 58 | StringRef get(bool Enabled) const { |
| 59 | assert(isValid()); |
| 60 | return Enabled ? On : Off; |
| 61 | } |
| 62 | }; |
| 63 | |
| 64 | // Installation path candidate. |
| 65 | struct Candidate { |
| 66 | llvm::SmallString<0> Path; |
| 67 | bool StrictChecking; |
| 68 | // Release string for ROCm packages built with SPACK if not empty. The |
| 69 | // installation directories of ROCm packages built with SPACK follow the |
| 70 | // convention <package_name>-<rocm_release_string>-<hash>. |
| 71 | std::string SPACKReleaseStr; |
| 72 | |
| 73 | bool isSPACK() const { return !SPACKReleaseStr.empty(); } |
| 74 | Candidate(std::string Path, bool StrictChecking = false, |
| 75 | StringRef SPACKReleaseStr = {}) |
| 76 | : Path(Path), StrictChecking(StrictChecking), |
| 77 | SPACKReleaseStr(SPACKReleaseStr.str()) {} |
| 78 | }; |
| 79 | |
| 80 | const Driver &D; |
| 81 | bool HasHIPRuntime = false; |
| 82 | bool HasDeviceLibrary = false; |
| 83 | bool HasHIPStdParLibrary = false; |
| 84 | bool HasRocThrustLibrary = false; |
| 85 | bool HasRocPrimLibrary = false; |
| 86 | |
| 87 | // Default version if not detected or specified. |
| 88 | const unsigned DefaultVersionMajor = 3; |
| 89 | const unsigned DefaultVersionMinor = 5; |
| 90 | const char *DefaultVersionPatch = "0" ; |
| 91 | |
| 92 | // The version string in Major.Minor.Patch format. |
| 93 | std::string DetectedVersion; |
| 94 | // Version containing major and minor. |
| 95 | llvm::VersionTuple VersionMajorMinor; |
| 96 | // Version containing patch. |
| 97 | std::string VersionPatch; |
| 98 | |
| 99 | // ROCm path specified by --rocm-path. |
| 100 | StringRef RocmPathArg; |
| 101 | // ROCm device library paths specified by --rocm-device-lib-path. |
| 102 | std::vector<std::string> RocmDeviceLibPathArg; |
| 103 | // HIP runtime path specified by --hip-path. |
| 104 | StringRef HIPPathArg; |
| 105 | // HIP Standard Parallel Algorithm acceleration library specified by |
| 106 | // --hipstdpar-path |
| 107 | StringRef HIPStdParPathArg; |
| 108 | // rocThrust algorithm library specified by --hipstdpar-thrust-path |
| 109 | StringRef HIPRocThrustPathArg; |
| 110 | // rocPrim algorithm library specified by --hipstdpar-prim-path |
| 111 | StringRef HIPRocPrimPathArg; |
| 112 | // HIP version specified by --hip-version. |
| 113 | StringRef HIPVersionArg; |
| 114 | // Wheter -nogpulib is specified. |
| 115 | bool NoBuiltinLibs = false; |
| 116 | |
| 117 | // Paths |
| 118 | SmallString<0> InstallPath; |
| 119 | SmallString<0> BinPath; |
| 120 | SmallString<0> LibPath; |
| 121 | SmallString<0> LibDevicePath; |
| 122 | SmallString<0> IncludePath; |
| 123 | SmallString<0> SharePath; |
| 124 | llvm::StringMap<std::string> LibDeviceMap; |
| 125 | |
| 126 | // Libraries that are always linked. |
| 127 | SmallString<0> OCML; |
| 128 | SmallString<0> OCKL; |
| 129 | |
| 130 | // Libraries that are always linked depending on the language |
| 131 | SmallString<0> OpenCL; |
| 132 | |
| 133 | // Asan runtime library |
| 134 | SmallString<0> AsanRTL; |
| 135 | |
| 136 | // Libraries swapped based on compile flags. |
| 137 | ConditionalLibrary WavefrontSize64; |
| 138 | ConditionalLibrary FiniteOnly; |
| 139 | ConditionalLibrary UnsafeMath; |
| 140 | ConditionalLibrary DenormalsAreZero; |
| 141 | ConditionalLibrary CorrectlyRoundedSqrt; |
| 142 | |
| 143 | // Maps ABI version to library path. The version number is in the format of |
| 144 | // three digits as used in the ABI version library name. |
| 145 | std::map<unsigned, std::string> ABIVersionMap; |
| 146 | |
| 147 | // Cache ROCm installation search paths. |
| 148 | SmallVector<Candidate, 4> ROCmSearchDirs; |
| 149 | bool PrintROCmSearchDirs; |
| 150 | bool Verbose; |
| 151 | |
| 152 | bool allGenericLibsValid() const { |
| 153 | return !OCML.empty() && !OCKL.empty() && !OpenCL.empty() && |
| 154 | WavefrontSize64.isValid() && FiniteOnly.isValid() && |
| 155 | UnsafeMath.isValid() && DenormalsAreZero.isValid() && |
| 156 | CorrectlyRoundedSqrt.isValid(); |
| 157 | } |
| 158 | |
| 159 | void scanLibDevicePath(llvm::StringRef Path); |
| 160 | bool parseHIPVersionFile(llvm::StringRef V); |
| 161 | const SmallVectorImpl<Candidate> &getInstallationPathCandidates(); |
| 162 | |
| 163 | /// Find the path to a SPACK package under the ROCm candidate installation |
| 164 | /// directory if the candidate is a SPACK ROCm candidate. \returns empty |
| 165 | /// string if the candidate is not SPACK ROCm candidate or the requested |
| 166 | /// package is not found. |
| 167 | llvm::SmallString<0> findSPACKPackage(const Candidate &Cand, |
| 168 | StringRef PackageName); |
| 169 | |
| 170 | public: |
| 171 | RocmInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, |
| 172 | const llvm::opt::ArgList &Args, |
| 173 | bool DetectHIPRuntime = true, |
| 174 | bool DetectDeviceLib = false); |
| 175 | |
| 176 | /// Get file paths of default bitcode libraries common to AMDGPU based |
| 177 | /// toolchains. |
| 178 | llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> getCommonBitcodeLibs( |
| 179 | const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile, |
| 180 | bool Wave64, bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, |
| 181 | bool FastRelaxedMath, bool CorrectSqrt, DeviceLibABIVersion ABIVer, |
| 182 | bool GPUSan, bool isOpenMP) const; |
| 183 | /// Check file paths of default bitcode libraries common to AMDGPU based |
| 184 | /// toolchains. \returns false if there are invalid or missing files. |
| 185 | bool checkCommonBitcodeLibs(StringRef GPUArch, StringRef LibDeviceFile, |
| 186 | DeviceLibABIVersion ABIVer) const; |
| 187 | |
| 188 | /// Check whether we detected a valid HIP runtime. |
| 189 | bool hasHIPRuntime() const { return HasHIPRuntime; } |
| 190 | |
| 191 | /// Check whether we detected a valid ROCm device library. |
| 192 | bool hasDeviceLibrary() const { return HasDeviceLibrary; } |
| 193 | |
| 194 | /// Check whether we detected a valid HIP STDPAR Acceleration library. |
| 195 | bool hasHIPStdParLibrary() const { return HasHIPStdParLibrary; } |
| 196 | |
| 197 | /// Print information about the detected ROCm installation. |
| 198 | void print(raw_ostream &OS) const; |
| 199 | |
| 200 | /// Get the detected Rocm install's version. |
| 201 | // RocmVersion version() const { return Version; } |
| 202 | |
| 203 | /// Get the detected Rocm installation path. |
| 204 | StringRef getInstallPath() const { return InstallPath; } |
| 205 | |
| 206 | /// Get the detected path to Rocm's bin directory. |
| 207 | // StringRef getBinPath() const { return BinPath; } |
| 208 | |
| 209 | /// Get the detected Rocm Include path. |
| 210 | StringRef getIncludePath() const { return IncludePath; } |
| 211 | |
| 212 | /// Get the detected Rocm library path. |
| 213 | StringRef getLibPath() const { return LibPath; } |
| 214 | |
| 215 | /// Get the detected Rocm device library path. |
| 216 | StringRef getLibDevicePath() const { return LibDevicePath; } |
| 217 | |
| 218 | StringRef getOCMLPath() const { |
| 219 | assert(!OCML.empty()); |
| 220 | return OCML; |
| 221 | } |
| 222 | |
| 223 | StringRef getOCKLPath() const { |
| 224 | assert(!OCKL.empty()); |
| 225 | return OCKL; |
| 226 | } |
| 227 | |
| 228 | StringRef getOpenCLPath() const { |
| 229 | assert(!OpenCL.empty()); |
| 230 | return OpenCL; |
| 231 | } |
| 232 | |
| 233 | /// Returns empty string of Asan runtime library is not available. |
| 234 | StringRef getAsanRTLPath() const { return AsanRTL; } |
| 235 | |
| 236 | StringRef getWavefrontSize64Path(bool Enabled) const { |
| 237 | return WavefrontSize64.get(Enabled); |
| 238 | } |
| 239 | |
| 240 | StringRef getFiniteOnlyPath(bool Enabled) const { |
| 241 | return FiniteOnly.get(Enabled); |
| 242 | } |
| 243 | |
| 244 | StringRef getUnsafeMathPath(bool Enabled) const { |
| 245 | return UnsafeMath.get(Enabled); |
| 246 | } |
| 247 | |
| 248 | StringRef getDenormalsAreZeroPath(bool Enabled) const { |
| 249 | return DenormalsAreZero.get(Enabled); |
| 250 | } |
| 251 | |
| 252 | StringRef getCorrectlyRoundedSqrtPath(bool Enabled) const { |
| 253 | return CorrectlyRoundedSqrt.get(Enabled); |
| 254 | } |
| 255 | |
| 256 | StringRef getABIVersionPath(DeviceLibABIVersion ABIVer) const { |
| 257 | auto Loc = ABIVersionMap.find(x: ABIVer.ABIVersion); |
| 258 | if (Loc == ABIVersionMap.end()) |
| 259 | return StringRef(); |
| 260 | return Loc->second; |
| 261 | } |
| 262 | |
| 263 | /// Get libdevice file for given architecture |
| 264 | StringRef getLibDeviceFile(StringRef Gpu) const { |
| 265 | auto Loc = LibDeviceMap.find(Key: Gpu); |
| 266 | if (Loc == LibDeviceMap.end()) |
| 267 | return "" ; |
| 268 | return Loc->second; |
| 269 | } |
| 270 | |
| 271 | void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, |
| 272 | llvm::opt::ArgStringList &CC1Args) const; |
| 273 | |
| 274 | void detectDeviceLibrary(); |
| 275 | void detectHIPRuntime(); |
| 276 | |
| 277 | /// Get the values for --rocm-device-lib-path arguments |
| 278 | ArrayRef<std::string> getRocmDeviceLibPathArg() const { |
| 279 | return RocmDeviceLibPathArg; |
| 280 | } |
| 281 | |
| 282 | /// Get the value for --rocm-path argument |
| 283 | StringRef getRocmPathArg() const { return RocmPathArg; } |
| 284 | |
| 285 | /// Get the value for --hip-version argument |
| 286 | StringRef getHIPVersionArg() const { return HIPVersionArg; } |
| 287 | |
| 288 | StringRef getHIPVersion() const { return DetectedVersion; } |
| 289 | }; |
| 290 | |
| 291 | } // end namespace driver |
| 292 | } // end namespace clang |
| 293 | |
| 294 | #endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ROCM_H |
| 295 | |