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