xref: /freebsd/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp (revision dc318a4ffabcbfa23bb56a33403aad36e6de30af)
1 //===--- AMDGPU.cpp - AMDGPU ToolChain Implementations ----------*- 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 #include "AMDGPU.h"
10 #include "CommonArgs.h"
11 #include "InputInfo.h"
12 #include "clang/Driver/Compilation.h"
13 #include "clang/Driver/DriverDiagnostic.h"
14 #include "llvm/Option/ArgList.h"
15 #include "llvm/Support/Path.h"
16 #include "llvm/Support/VirtualFileSystem.h"
17 
18 using namespace clang::driver;
19 using namespace clang::driver::tools;
20 using namespace clang::driver::toolchains;
21 using namespace clang;
22 using namespace llvm::opt;
23 
24 void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
25   assert(!Path.empty());
26 
27   const StringRef Suffix(".bc");
28   const StringRef Suffix2(".amdgcn.bc");
29 
30   std::error_code EC;
31   for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Path, EC), LE;
32        !EC && LI != LE; LI = LI.increment(EC)) {
33     StringRef FilePath = LI->path();
34     StringRef FileName = llvm::sys::path::filename(FilePath);
35     if (!FileName.endswith(Suffix))
36       continue;
37 
38     StringRef BaseName;
39     if (FileName.endswith(Suffix2))
40       BaseName = FileName.drop_back(Suffix2.size());
41     else if (FileName.endswith(Suffix))
42       BaseName = FileName.drop_back(Suffix.size());
43 
44     if (BaseName == "ocml") {
45       OCML = FilePath;
46     } else if (BaseName == "ockl") {
47       OCKL = FilePath;
48     } else if (BaseName == "opencl") {
49       OpenCL = FilePath;
50     } else if (BaseName == "hip") {
51       HIP = FilePath;
52     } else if (BaseName == "oclc_finite_only_off") {
53       FiniteOnly.Off = FilePath;
54     } else if (BaseName == "oclc_finite_only_on") {
55       FiniteOnly.On = FilePath;
56     } else if (BaseName == "oclc_daz_opt_on") {
57       DenormalsAreZero.On = FilePath;
58     } else if (BaseName == "oclc_daz_opt_off") {
59       DenormalsAreZero.Off = FilePath;
60     } else if (BaseName == "oclc_correctly_rounded_sqrt_on") {
61       CorrectlyRoundedSqrt.On = FilePath;
62     } else if (BaseName == "oclc_correctly_rounded_sqrt_off") {
63       CorrectlyRoundedSqrt.Off = FilePath;
64     } else if (BaseName == "oclc_unsafe_math_on") {
65       UnsafeMath.On = FilePath;
66     } else if (BaseName == "oclc_unsafe_math_off") {
67       UnsafeMath.Off = FilePath;
68     } else if (BaseName == "oclc_wavefrontsize64_on") {
69       WavefrontSize64.On = FilePath;
70     } else if (BaseName == "oclc_wavefrontsize64_off") {
71       WavefrontSize64.Off = FilePath;
72     } else {
73       // Process all bitcode filenames that look like
74       // ocl_isa_version_XXX.amdgcn.bc
75       const StringRef DeviceLibPrefix = "oclc_isa_version_";
76       if (!BaseName.startswith(DeviceLibPrefix))
77         continue;
78 
79       StringRef IsaVersionNumber =
80         BaseName.drop_front(DeviceLibPrefix.size());
81 
82       llvm::Twine GfxName = Twine("gfx") + IsaVersionNumber;
83       SmallString<8> Tmp;
84       LibDeviceMap.insert(
85         std::make_pair(GfxName.toStringRef(Tmp), FilePath.str()));
86     }
87   }
88 }
89 
90 void RocmInstallationDetector::ParseHIPVersionFile(llvm::StringRef V) {
91   SmallVector<StringRef, 4> VersionParts;
92   V.split(VersionParts, '\n');
93   unsigned Major;
94   unsigned Minor;
95   for (auto Part : VersionParts) {
96     auto Splits = Part.split('=');
97     if (Splits.first == "HIP_VERSION_MAJOR")
98       Splits.second.getAsInteger(0, Major);
99     else if (Splits.first == "HIP_VERSION_MINOR")
100       Splits.second.getAsInteger(0, Minor);
101     else if (Splits.first == "HIP_VERSION_PATCH")
102       VersionPatch = Splits.second.str();
103   }
104   VersionMajorMinor = llvm::VersionTuple(Major, Minor);
105   DetectedVersion =
106       (Twine(Major) + "." + Twine(Minor) + "." + VersionPatch).str();
107 }
108 
109 // For candidate specified by --rocm-path we do not do strict check.
110 SmallVector<RocmInstallationDetector::Candidate, 4>
111 RocmInstallationDetector::getInstallationPathCandidates() {
112   SmallVector<Candidate, 4> Candidates;
113   if (!RocmPathArg.empty()) {
114     Candidates.emplace_back(RocmPathArg.str());
115     return Candidates;
116   }
117 
118   // Try to find relative to the compiler binary.
119   const char *InstallDir = D.getInstalledDir();
120 
121   // Check both a normal Unix prefix position of the clang binary, as well as
122   // the Windows-esque layout the ROCm packages use with the host architecture
123   // subdirectory of bin.
124 
125   // Strip off directory (usually bin)
126   StringRef ParentDir = llvm::sys::path::parent_path(InstallDir);
127   StringRef ParentName = llvm::sys::path::filename(ParentDir);
128 
129   // Some builds use bin/{host arch}, so go up again.
130   if (ParentName == "bin") {
131     ParentDir = llvm::sys::path::parent_path(ParentDir);
132     ParentName = llvm::sys::path::filename(ParentDir);
133   }
134 
135   // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin
136   if (ParentName == "llvm")
137     ParentDir = llvm::sys::path::parent_path(ParentDir);
138 
139   Candidates.emplace_back(ParentDir.str(), /*StrictChecking=*/true);
140 
141   // Device library may be installed in clang resource directory.
142   Candidates.emplace_back(D.ResourceDir, /*StrictChecking=*/true);
143 
144   Candidates.emplace_back(D.SysRoot + "/opt/rocm", /*StrictChecking=*/true);
145   return Candidates;
146 }
147 
148 RocmInstallationDetector::RocmInstallationDetector(
149     const Driver &D, const llvm::Triple &HostTriple,
150     const llvm::opt::ArgList &Args, bool DetectHIPRuntime, bool DetectDeviceLib)
151     : D(D) {
152   RocmPathArg = Args.getLastArgValue(clang::driver::options::OPT_rocm_path_EQ);
153   RocmDeviceLibPathArg =
154       Args.getAllArgValues(clang::driver::options::OPT_rocm_device_lib_path_EQ);
155   if (auto *A = Args.getLastArg(clang::driver::options::OPT_hip_version_EQ)) {
156     HIPVersionArg = A->getValue();
157     unsigned Major = 0;
158     unsigned Minor = 0;
159     SmallVector<StringRef, 3> Parts;
160     HIPVersionArg.split(Parts, '.');
161     if (Parts.size())
162       Parts[0].getAsInteger(0, Major);
163     if (Parts.size() > 1)
164       Parts[1].getAsInteger(0, Minor);
165     if (Parts.size() > 2)
166       VersionPatch = Parts[2].str();
167     if (VersionPatch.empty())
168       VersionPatch = "0";
169     if (Major == 0 || Minor == 0)
170       D.Diag(diag::err_drv_invalid_value)
171           << A->getAsString(Args) << HIPVersionArg;
172 
173     VersionMajorMinor = llvm::VersionTuple(Major, Minor);
174     DetectedVersion =
175         (Twine(Major) + "." + Twine(Minor) + "." + VersionPatch).str();
176   } else {
177     VersionPatch = DefaultVersionPatch;
178     VersionMajorMinor =
179         llvm::VersionTuple(DefaultVersionMajor, DefaultVersionMinor);
180     DetectedVersion = (Twine(DefaultVersionMajor) + "." +
181                        Twine(DefaultVersionMinor) + "." + VersionPatch)
182                           .str();
183   }
184 
185   if (DetectHIPRuntime)
186     detectHIPRuntime();
187   if (DetectDeviceLib)
188     detectDeviceLibrary();
189 }
190 
191 void RocmInstallationDetector::detectDeviceLibrary() {
192   assert(LibDevicePath.empty());
193 
194   if (!RocmDeviceLibPathArg.empty())
195     LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1];
196   else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH"))
197     LibDevicePath = LibPathEnv;
198 
199   auto &FS = D.getVFS();
200   if (!LibDevicePath.empty()) {
201     // Maintain compatability with HIP flag/envvar pointing directly at the
202     // bitcode library directory. This points directly at the library path instead
203     // of the rocm root installation.
204     if (!FS.exists(LibDevicePath))
205       return;
206 
207     scanLibDevicePath(LibDevicePath);
208     HasDeviceLibrary = allGenericLibsValid() && !LibDeviceMap.empty();
209     return;
210   }
211 
212   // The install path situation in old versions of ROCm is a real mess, and
213   // use a different install layout. Multiple copies of the device libraries
214   // exist for each frontend project, and differ depending on which build
215   // system produced the packages. Standalone OpenCL builds also have a
216   // different directory structure from the ROCm OpenCL package.
217   auto Candidates = getInstallationPathCandidates();
218   for (const auto &Candidate : Candidates) {
219     auto CandidatePath = Candidate.Path;
220 
221     // Check device library exists at the given path.
222     auto CheckDeviceLib = [&](StringRef Path) {
223       bool CheckLibDevice = (!NoBuiltinLibs || Candidate.StrictChecking);
224       if (CheckLibDevice && !FS.exists(Path))
225         return false;
226 
227       scanLibDevicePath(Path);
228 
229       if (!NoBuiltinLibs) {
230         // Check that the required non-target libraries are all available.
231         if (!allGenericLibsValid())
232           return false;
233 
234         // Check that we have found at least one libdevice that we can link in
235         // if -nobuiltinlib hasn't been specified.
236         if (LibDeviceMap.empty())
237           return false;
238       }
239       return true;
240     };
241 
242     // The possible structures are:
243     // - ${ROCM_ROOT}/amdgcn/bitcode/*
244     // - ${ROCM_ROOT}/lib/*
245     // - ${ROCM_ROOT}/lib/bitcode/*
246     // so try to detect these layouts.
247     static llvm::SmallVector<const char *, 2> SubDirsList[] = {
248         {"amdgcn", "bitcode"},
249         {"lib"},
250         {"lib", "bitcode"},
251     };
252 
253     // Make a path by appending sub-directories to InstallPath.
254     auto MakePath = [&](const llvm::ArrayRef<const char *> &SubDirs) {
255       auto Path = CandidatePath;
256       for (auto SubDir : SubDirs)
257         llvm::sys::path::append(Path, SubDir);
258       return Path;
259     };
260 
261     for (auto SubDirs : SubDirsList) {
262       LibDevicePath = MakePath(SubDirs);
263       HasDeviceLibrary = CheckDeviceLib(LibDevicePath);
264       if (HasDeviceLibrary)
265         return;
266     }
267   }
268 }
269 
270 void RocmInstallationDetector::detectHIPRuntime() {
271   auto Candidates = getInstallationPathCandidates();
272   auto &FS = D.getVFS();
273 
274   for (const auto &Candidate : Candidates) {
275     InstallPath = Candidate.Path;
276     if (InstallPath.empty() || !FS.exists(InstallPath))
277       continue;
278 
279     BinPath = InstallPath;
280     llvm::sys::path::append(BinPath, "bin");
281     IncludePath = InstallPath;
282     llvm::sys::path::append(IncludePath, "include");
283     LibPath = InstallPath;
284     llvm::sys::path::append(LibPath, "lib");
285 
286     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
287         FS.getBufferForFile(BinPath + "/.hipVersion");
288     if (!VersionFile && Candidate.StrictChecking)
289       continue;
290 
291     if (HIPVersionArg.empty() && VersionFile)
292       ParseHIPVersionFile((*VersionFile)->getBuffer());
293 
294     HasHIPRuntime = true;
295     return;
296   }
297   HasHIPRuntime = false;
298 }
299 
300 void RocmInstallationDetector::print(raw_ostream &OS) const {
301   if (hasHIPRuntime())
302     OS << "Found HIP installation: " << InstallPath << ", version "
303        << DetectedVersion << '\n';
304 }
305 
306 void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs,
307                                                  ArgStringList &CC1Args) const {
308   bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5);
309 
310   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
311     // HIP header includes standard library wrapper headers under clang
312     // cuda_wrappers directory. Since these wrapper headers include_next
313     // standard C++ headers, whereas libc++ headers include_next other clang
314     // headers. The include paths have to follow this order:
315     // - wrapper include path
316     // - standard C++ include path
317     // - other clang include path
318     // Since standard C++ and other clang include paths are added in other
319     // places after this function, here we only need to make sure wrapper
320     // include path is added.
321     //
322     // ROCm 3.5 does not fully support the wrapper headers. Therefore it needs
323     // a workaround.
324     SmallString<128> P(D.ResourceDir);
325     if (UsesRuntimeWrapper)
326       llvm::sys::path::append(P, "include", "cuda_wrappers");
327     CC1Args.push_back("-internal-isystem");
328     CC1Args.push_back(DriverArgs.MakeArgString(P));
329   }
330 
331   if (DriverArgs.hasArg(options::OPT_nogpuinc))
332     return;
333 
334   if (!hasHIPRuntime()) {
335     D.Diag(diag::err_drv_no_hip_runtime);
336     return;
337   }
338 
339   CC1Args.push_back("-internal-isystem");
340   CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath()));
341   if (UsesRuntimeWrapper)
342     CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"});
343 }
344 
345 void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
346                                   const InputInfo &Output,
347                                   const InputInfoList &Inputs,
348                                   const ArgList &Args,
349                                   const char *LinkingOutput) const {
350 
351   std::string Linker = getToolChain().GetProgramPath(getShortName());
352   ArgStringList CmdArgs;
353   addLinkerCompressDebugSectionsOption(getToolChain(), Args, CmdArgs);
354   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
355   CmdArgs.push_back("-shared");
356   CmdArgs.push_back("-o");
357   CmdArgs.push_back(Output.getFilename());
358   C.addCommand(
359       std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(),
360                                 Args.MakeArgString(Linker), CmdArgs, Inputs));
361 }
362 
363 void amdgpu::getAMDGPUTargetFeatures(const Driver &D,
364                                      const llvm::opt::ArgList &Args,
365                                      std::vector<StringRef> &Features) {
366   if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi))
367     D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args);
368 
369   if (Args.getLastArg(options::OPT_mwavefrontsize64)) {
370     Features.push_back("-wavefrontsize16");
371     Features.push_back("-wavefrontsize32");
372     Features.push_back("+wavefrontsize64");
373   }
374   if (Args.getLastArg(options::OPT_mno_wavefrontsize64)) {
375     Features.push_back("-wavefrontsize16");
376     Features.push_back("+wavefrontsize32");
377     Features.push_back("-wavefrontsize64");
378   }
379 
380   handleTargetFeaturesGroup(
381     Args, Features, options::OPT_m_amdgpu_Features_Group);
382 }
383 
384 /// AMDGPU Toolchain
385 AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
386                                  const ArgList &Args)
387     : Generic_ELF(D, Triple, Args),
388       OptionsDefault({{options::OPT_O, "3"},
389                       {options::OPT_cl_std_EQ, "CL1.2"}}) {}
390 
391 Tool *AMDGPUToolChain::buildLinker() const {
392   return new tools::amdgpu::Linker(*this);
393 }
394 
395 DerivedArgList *
396 AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
397                                Action::OffloadKind DeviceOffloadKind) const {
398 
399   DerivedArgList *DAL =
400       Generic_ELF::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
401 
402   // Do nothing if not OpenCL (-x cl)
403   if (!Args.getLastArgValue(options::OPT_x).equals("cl"))
404     return DAL;
405 
406   if (!DAL)
407     DAL = new DerivedArgList(Args.getBaseArgs());
408   for (auto *A : Args)
409     DAL->append(A);
410 
411   const OptTable &Opts = getDriver().getOpts();
412 
413   // Phase 1 (.cl -> .bc)
414   if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) {
415     DAL->AddFlagArg(nullptr, Opts.getOption(getTriple().isArch64Bit()
416                                                 ? options::OPT_m64
417                                                 : options::OPT_m32));
418 
419     // Have to check OPT_O4, OPT_O0 & OPT_Ofast separately
420     // as they defined that way in Options.td
421     if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4,
422                      options::OPT_Ofast))
423       DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O),
424                         getOptionDefault(options::OPT_O));
425   }
426 
427   return DAL;
428 }
429 
430 bool AMDGPUToolChain::getDefaultDenormsAreZeroForTarget(
431     llvm::AMDGPU::GPUKind Kind) {
432 
433   // Assume nothing without a specific target.
434   if (Kind == llvm::AMDGPU::GK_NONE)
435     return false;
436 
437   const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind);
438 
439   // Default to enabling f32 denormals by default on subtargets where fma is
440   // fast with denormals
441   const bool BothDenormAndFMAFast =
442       (ArchAttr & llvm::AMDGPU::FEATURE_FAST_FMA_F32) &&
443       (ArchAttr & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32);
444   return !BothDenormAndFMAFast;
445 }
446 
447 llvm::DenormalMode AMDGPUToolChain::getDefaultDenormalModeForType(
448     const llvm::opt::ArgList &DriverArgs, const JobAction &JA,
449     const llvm::fltSemantics *FPType) const {
450   // Denormals should always be enabled for f16 and f64.
451   if (!FPType || FPType != &llvm::APFloat::IEEEsingle())
452     return llvm::DenormalMode::getIEEE();
453 
454   if (JA.getOffloadingDeviceKind() == Action::OFK_HIP ||
455       JA.getOffloadingDeviceKind() == Action::OFK_Cuda) {
456     auto Kind = llvm::AMDGPU::parseArchAMDGCN(JA.getOffloadingArch());
457     if (FPType && FPType == &llvm::APFloat::IEEEsingle() &&
458         DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero,
459                            options::OPT_fno_cuda_flush_denormals_to_zero,
460                            getDefaultDenormsAreZeroForTarget(Kind)))
461       return llvm::DenormalMode::getPreserveSign();
462 
463     return llvm::DenormalMode::getIEEE();
464   }
465 
466   const StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ);
467   auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);
468 
469   // TODO: There are way too many flags that change this. Do we need to check
470   // them all?
471   bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) ||
472              getDefaultDenormsAreZeroForTarget(Kind);
473 
474   // Outputs are flushed to zero (FTZ), preserving sign. Denormal inputs are
475   // also implicit treated as zero (DAZ).
476   return DAZ ? llvm::DenormalMode::getPreserveSign() :
477                llvm::DenormalMode::getIEEE();
478 }
479 
480 bool AMDGPUToolChain::isWave64(const llvm::opt::ArgList &DriverArgs,
481                                llvm::AMDGPU::GPUKind Kind) {
482   const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind);
483   static bool HasWave32 = (ArchAttr & llvm::AMDGPU::FEATURE_WAVE32);
484 
485   return !HasWave32 || DriverArgs.hasFlag(
486     options::OPT_mwavefrontsize64, options::OPT_mno_wavefrontsize64, false);
487 }
488 
489 
490 /// ROCM Toolchain
491 ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple,
492                              const ArgList &Args)
493     : AMDGPUToolChain(D, Triple, Args) {
494   RocmInstallation.detectDeviceLibrary();
495 }
496 
497 void AMDGPUToolChain::addClangTargetOptions(
498     const llvm::opt::ArgList &DriverArgs,
499     llvm::opt::ArgStringList &CC1Args,
500     Action::OffloadKind DeviceOffloadingKind) const {
501   // Default to "hidden" visibility, as object level linking will not be
502   // supported for the foreseeable future.
503   if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
504                          options::OPT_fvisibility_ms_compat)) {
505     CC1Args.push_back("-fvisibility");
506     CC1Args.push_back("hidden");
507     CC1Args.push_back("-fapply-global-visibility-to-externs");
508   }
509 }
510 
511 void ROCMToolChain::addClangTargetOptions(
512     const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
513     Action::OffloadKind DeviceOffloadingKind) const {
514   AMDGPUToolChain::addClangTargetOptions(DriverArgs, CC1Args,
515                                          DeviceOffloadingKind);
516 
517   // For the OpenCL case where there is no offload target, accept -nostdlib to
518   // disable bitcode linking.
519   if (DeviceOffloadingKind == Action::OFK_None &&
520       DriverArgs.hasArg(options::OPT_nostdlib))
521     return;
522 
523   if (DriverArgs.hasArg(options::OPT_nogpulib))
524     return;
525 
526   if (!RocmInstallation.hasDeviceLibrary()) {
527     getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
528     return;
529   }
530 
531   // Get the device name and canonicalize it
532   const StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ);
533   auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);
534   const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind);
535   std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
536   if (LibDeviceFile.empty()) {
537     getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch;
538     return;
539   }
540 
541   bool Wave64 = isWave64(DriverArgs, Kind);
542 
543   // TODO: There are way too many flags that change this. Do we need to check
544   // them all?
545   bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) ||
546              getDefaultDenormsAreZeroForTarget(Kind);
547   bool FiniteOnly = DriverArgs.hasArg(options::OPT_cl_finite_math_only);
548 
549   bool UnsafeMathOpt =
550       DriverArgs.hasArg(options::OPT_cl_unsafe_math_optimizations);
551   bool FastRelaxedMath = DriverArgs.hasArg(options::OPT_cl_fast_relaxed_math);
552   bool CorrectSqrt =
553       DriverArgs.hasArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt);
554 
555   // Add the OpenCL specific bitcode library.
556   CC1Args.push_back("-mlink-builtin-bitcode");
557   CC1Args.push_back(DriverArgs.MakeArgString(RocmInstallation.getOpenCLPath()));
558 
559   // Add the generic set of libraries.
560   RocmInstallation.addCommonBitcodeLibCC1Args(
561       DriverArgs, CC1Args, LibDeviceFile, Wave64, DAZ, FiniteOnly,
562       UnsafeMathOpt, FastRelaxedMath, CorrectSqrt);
563 }
564 
565 void RocmInstallationDetector::addCommonBitcodeLibCC1Args(
566     const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
567     StringRef LibDeviceFile, bool Wave64, bool DAZ, bool FiniteOnly,
568     bool UnsafeMathOpt, bool FastRelaxedMath, bool CorrectSqrt) const {
569   static const char LinkBitcodeFlag[] = "-mlink-builtin-bitcode";
570 
571   CC1Args.push_back(LinkBitcodeFlag);
572   CC1Args.push_back(DriverArgs.MakeArgString(getOCMLPath()));
573 
574   CC1Args.push_back(LinkBitcodeFlag);
575   CC1Args.push_back(DriverArgs.MakeArgString(getOCKLPath()));
576 
577   CC1Args.push_back(LinkBitcodeFlag);
578   CC1Args.push_back(DriverArgs.MakeArgString(getDenormalsAreZeroPath(DAZ)));
579 
580   CC1Args.push_back(LinkBitcodeFlag);
581   CC1Args.push_back(DriverArgs.MakeArgString(
582       getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath)));
583 
584   CC1Args.push_back(LinkBitcodeFlag);
585   CC1Args.push_back(DriverArgs.MakeArgString(
586       getFiniteOnlyPath(FiniteOnly || FastRelaxedMath)));
587 
588   CC1Args.push_back(LinkBitcodeFlag);
589   CC1Args.push_back(
590       DriverArgs.MakeArgString(getCorrectlyRoundedSqrtPath(CorrectSqrt)));
591 
592   CC1Args.push_back(LinkBitcodeFlag);
593   CC1Args.push_back(DriverArgs.MakeArgString(getWavefrontSize64Path(Wave64)));
594 
595   CC1Args.push_back(LinkBitcodeFlag);
596   CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile));
597 }
598