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/Option/ArgList.h"
19#include "llvm/Support/VersionTuple.h"
20#include "llvm/TargetParser/Triple.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 bool HasHIPStdParLibrary = false;
81 bool HasRocThrustLibrary = false;
82 bool HasRocPrimLibrary = false;
83
84 // Default version if not detected or specified.
85 const unsigned DefaultVersionMajor = 3;
86 const unsigned DefaultVersionMinor = 5;
87 const char *DefaultVersionPatch = "0";
88
89 // The version string in Major.Minor.Patch format.
90 std::string DetectedVersion;
91 // Version containing major and minor.
92 llvm::VersionTuple VersionMajorMinor;
93 // Version containing patch.
94 std::string VersionPatch;
95
96 // ROCm path specified by --rocm-path.
97 StringRef RocmPathArg;
98 // ROCm device library paths specified by --rocm-device-lib-path.
99 std::vector<std::string> RocmDeviceLibPathArg;
100 // HIP runtime path specified by --hip-path.
101 StringRef HIPPathArg;
102 // HIP Standard Parallel Algorithm acceleration library specified by
103 // --hipstdpar-path
104 StringRef HIPStdParPathArg;
105 // rocThrust algorithm library specified by --hipstdpar-thrust-path
106 StringRef HIPRocThrustPathArg;
107 // rocPrim algorithm library specified by --hipstdpar-prim-path
108 StringRef HIPRocPrimPathArg;
109 // HIP version specified by --hip-version.
110 StringRef HIPVersionArg;
111 // Wheter -nogpulib is specified.
112 bool NoBuiltinLibs = false;
113
114 // Paths
115 SmallString<0> InstallPath;
116 SmallString<0> BinPath;
117 SmallString<0> LibPath;
118 SmallString<0> LibDevicePath;
119 SmallString<0> IncludePath;
120 SmallString<0> SharePath;
121 llvm::StringMap<std::string> LibDeviceMap;
122
123 // Libraries that are always linked.
124 SmallString<0> OCML;
125 SmallString<0> OCKL;
126
127 // Libraries that are always linked depending on the language
128 SmallString<0> OpenCL;
129 SmallString<0> HIP;
130
131 // Asan runtime library
132 SmallString<0> AsanRTL;
133
134 // Libraries swapped based on compile flags.
135 ConditionalLibrary WavefrontSize64;
136 ConditionalLibrary FiniteOnly;
137 ConditionalLibrary UnsafeMath;
138 ConditionalLibrary DenormalsAreZero;
139 ConditionalLibrary CorrectlyRoundedSqrt;
140
141 // Maps ABI version to library path. The version number is in the format of
142 // three digits as used in the ABI version library name.
143 std::map<unsigned, std::string> ABIVersionMap;
144
145 // Cache ROCm installation search paths.
146 SmallVector<Candidate, 4> ROCmSearchDirs;
147 bool PrintROCmSearchDirs;
148 bool Verbose;
149
150 bool allGenericLibsValid() const {
151 return !OCML.empty() && !OCKL.empty() && !OpenCL.empty() && !HIP.empty() &&
152 WavefrontSize64.isValid() && FiniteOnly.isValid() &&
153 UnsafeMath.isValid() && DenormalsAreZero.isValid() &&
154 CorrectlyRoundedSqrt.isValid();
155 }
156
157 void scanLibDevicePath(llvm::StringRef Path);
158 bool parseHIPVersionFile(llvm::StringRef V);
159 const SmallVectorImpl<Candidate> &getInstallationPathCandidates();
160
161 /// Find the path to a SPACK package under the ROCm candidate installation
162 /// directory if the candidate is a SPACK ROCm candidate. \returns empty
163 /// string if the candidate is not SPACK ROCm candidate or the requested
164 /// package is not found.
165 llvm::SmallString<0> findSPACKPackage(const Candidate &Cand,
166 StringRef PackageName);
167
168public:
169 RocmInstallationDetector(const Driver &D, const llvm::Triple &HostTriple,
170 const llvm::opt::ArgList &Args,
171 bool DetectHIPRuntime = true,
172 bool DetectDeviceLib = false);
173
174 /// Get file paths of default bitcode libraries common to AMDGPU based
175 /// toolchains.
176 llvm::SmallVector<std::string, 12>
177 getCommonBitcodeLibs(const llvm::opt::ArgList &DriverArgs,
178 StringRef LibDeviceFile, bool Wave64, bool DAZ,
179 bool FiniteOnly, bool UnsafeMathOpt,
180 bool FastRelaxedMath, bool CorrectSqrt,
181 DeviceLibABIVersion ABIVer, bool isOpenMP) const;
182 /// Check file paths of default bitcode libraries common to AMDGPU based
183 /// toolchains. \returns false if there are invalid or missing files.
184 bool checkCommonBitcodeLibs(StringRef GPUArch, StringRef LibDeviceFile,
185 DeviceLibABIVersion ABIVer) const;
186
187 /// Check whether we detected a valid HIP runtime.
188 bool hasHIPRuntime() const { return HasHIPRuntime; }
189
190 /// Check whether we detected a valid ROCm device library.
191 bool hasDeviceLibrary() const { return HasDeviceLibrary; }
192
193 /// Check whether we detected a valid HIP STDPAR Acceleration library.
194 bool hasHIPStdParLibrary() const { return HasHIPStdParLibrary; }
195
196 /// Print information about the detected ROCm installation.
197 void print(raw_ostream &OS) const;
198
199 /// Get the detected Rocm install's version.
200 // RocmVersion version() const { return Version; }
201
202 /// Get the detected Rocm installation path.
203 StringRef getInstallPath() const { return InstallPath; }
204
205 /// Get the detected path to Rocm's bin directory.
206 // StringRef getBinPath() const { return BinPath; }
207
208 /// Get the detected Rocm Include path.
209 StringRef getIncludePath() const { return IncludePath; }
210
211 /// Get the detected Rocm library path.
212 StringRef getLibPath() const { return LibPath; }
213
214 /// Get the detected Rocm device library path.
215 StringRef getLibDevicePath() const { return LibDevicePath; }
216
217 StringRef getOCMLPath() const {
218 assert(!OCML.empty());
219 return OCML;
220 }
221
222 StringRef getOCKLPath() const {
223 assert(!OCKL.empty());
224 return OCKL;
225 }
226
227 StringRef getOpenCLPath() const {
228 assert(!OpenCL.empty());
229 return OpenCL;
230 }
231
232 StringRef getHIPPath() const {
233 assert(!HIP.empty());
234 return HIP;
235 }
236
237 /// Returns empty string of Asan runtime library is not available.
238 StringRef getAsanRTLPath() const { return AsanRTL; }
239
240 StringRef getWavefrontSize64Path(bool Enabled) const {
241 return WavefrontSize64.get(Enabled);
242 }
243
244 StringRef getFiniteOnlyPath(bool Enabled) const {
245 return FiniteOnly.get(Enabled);
246 }
247
248 StringRef getUnsafeMathPath(bool Enabled) const {
249 return UnsafeMath.get(Enabled);
250 }
251
252 StringRef getDenormalsAreZeroPath(bool Enabled) const {
253 return DenormalsAreZero.get(Enabled);
254 }
255
256 StringRef getCorrectlyRoundedSqrtPath(bool Enabled) const {
257 return CorrectlyRoundedSqrt.get(Enabled);
258 }
259
260 StringRef getABIVersionPath(DeviceLibABIVersion ABIVer) const {
261 auto Loc = ABIVersionMap.find(x: ABIVer.ABIVersion);
262 if (Loc == ABIVersionMap.end())
263 return StringRef();
264 return Loc->second;
265 }
266
267 /// Get libdevice file for given architecture
268 StringRef getLibDeviceFile(StringRef Gpu) const {
269 auto Loc = LibDeviceMap.find(Key: Gpu);
270 if (Loc == LibDeviceMap.end())
271 return "";
272 return Loc->second;
273 }
274
275 void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
276 llvm::opt::ArgStringList &CC1Args) const;
277
278 void detectDeviceLibrary();
279 void detectHIPRuntime();
280
281 /// Get the values for --rocm-device-lib-path arguments
282 ArrayRef<std::string> getRocmDeviceLibPathArg() const {
283 return RocmDeviceLibPathArg;
284 }
285
286 /// Get the value for --rocm-path argument
287 StringRef getRocmPathArg() const { return RocmPathArg; }
288
289 /// Get the value for --hip-version argument
290 StringRef getHIPVersionArg() const { return HIPVersionArg; }
291
292 StringRef getHIPVersion() const { return DetectedVersion; }
293};
294
295} // end namespace driver
296} // end namespace clang
297
298#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ROCM_H
299