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