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 
22 namespace clang {
23 namespace driver {
24 
25 /// ABI version of device library.
26 struct DeviceLibABIVersion {
27   unsigned ABIVersion = 0;
DeviceLibABIVersionDeviceLibABIVersion28   DeviceLibABIVersion(unsigned V) : ABIVersion(V) {}
fromCodeObjectVersionDeviceLibABIVersion29   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.
requiresLibraryDeviceLibABIVersion38   bool requiresLibrary() { return ABIVersion >= 500; }
toStringDeviceLibABIVersion39   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.
47 class RocmInstallationDetector {
48 private:
49   struct ConditionalLibrary {
50     SmallString<0> On;
51     SmallString<0> Off;
52 
isValidConditionalLibrary53     bool isValid() const { return !On.empty() && !Off.empty(); }
54 
getConditionalLibrary55     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 
isSPACKCandidate70     bool isSPACK() const { return !SPACKReleaseStr.empty(); }
71     Candidate(std::string Path, bool StrictChecking = false,
72               StringRef SPACKReleaseStr = {})
PathCandidate73         : 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 
allGenericLibsValid()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 
168 public:
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.
hasHIPRuntime()188   bool hasHIPRuntime() const { return HasHIPRuntime; }
189 
190   /// Check whether we detected a valid ROCm device library.
hasDeviceLibrary()191   bool hasDeviceLibrary() const { return HasDeviceLibrary; }
192 
193   /// Check whether we detected a valid HIP STDPAR Acceleration library.
hasHIPStdParLibrary()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.
getInstallPath()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.
getIncludePath()209   StringRef getIncludePath() const { return IncludePath; }
210 
211   /// Get the detected Rocm library path.
getLibPath()212   StringRef getLibPath() const { return LibPath; }
213 
214   /// Get the detected Rocm device library path.
getLibDevicePath()215   StringRef getLibDevicePath() const { return LibDevicePath; }
216 
getOCMLPath()217   StringRef getOCMLPath() const {
218     assert(!OCML.empty());
219     return OCML;
220   }
221 
getOCKLPath()222   StringRef getOCKLPath() const {
223     assert(!OCKL.empty());
224     return OCKL;
225   }
226 
getOpenCLPath()227   StringRef getOpenCLPath() const {
228     assert(!OpenCL.empty());
229     return OpenCL;
230   }
231 
getHIPPath()232   StringRef getHIPPath() const {
233     assert(!HIP.empty());
234     return HIP;
235   }
236 
237   /// Returns empty string of Asan runtime library is not available.
getAsanRTLPath()238   StringRef getAsanRTLPath() const { return AsanRTL; }
239 
getWavefrontSize64Path(bool Enabled)240   StringRef getWavefrontSize64Path(bool Enabled) const {
241     return WavefrontSize64.get(Enabled);
242   }
243 
getFiniteOnlyPath(bool Enabled)244   StringRef getFiniteOnlyPath(bool Enabled) const {
245     return FiniteOnly.get(Enabled);
246   }
247 
getUnsafeMathPath(bool Enabled)248   StringRef getUnsafeMathPath(bool Enabled) const {
249     return UnsafeMath.get(Enabled);
250   }
251 
getDenormalsAreZeroPath(bool Enabled)252   StringRef getDenormalsAreZeroPath(bool Enabled) const {
253     return DenormalsAreZero.get(Enabled);
254   }
255 
getCorrectlyRoundedSqrtPath(bool Enabled)256   StringRef getCorrectlyRoundedSqrtPath(bool Enabled) const {
257     return CorrectlyRoundedSqrt.get(Enabled);
258   }
259 
getABIVersionPath(DeviceLibABIVersion ABIVer)260   StringRef getABIVersionPath(DeviceLibABIVersion ABIVer) const {
261     auto Loc = ABIVersionMap.find(ABIVer.ABIVersion);
262     if (Loc == ABIVersionMap.end())
263       return StringRef();
264     return Loc->second;
265   }
266 
267   /// Get libdevice file for given architecture
getLibDeviceFile(StringRef Gpu)268   StringRef getLibDeviceFile(StringRef Gpu) const {
269     auto Loc = LibDeviceMap.find(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
getRocmDeviceLibPathArg()282   ArrayRef<std::string> getRocmDeviceLibPathArg() const {
283     return RocmDeviceLibPathArg;
284   }
285 
286   /// Get the value for --rocm-path argument
getRocmPathArg()287   StringRef getRocmPathArg() const { return RocmPathArg; }
288 
289   /// Get the value for --hip-version argument
getHIPVersionArg()290   StringRef getHIPVersionArg() const { return HIPVersionArg; }
291 
getHIPVersion()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