xref: /freebsd/contrib/llvm-project/clang/lib/Driver/ToolChains/AMDGPU.cpp (revision 6132212808e8dccedc9e5d85fea4390c2f38059a)
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   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
354   CmdArgs.push_back("-shared");
355   CmdArgs.push_back("-o");
356   CmdArgs.push_back(Output.getFilename());
357   C.addCommand(
358       std::make_unique<Command>(JA, *this, ResponseFileSupport::AtFileCurCP(),
359                                 Args.MakeArgString(Linker), CmdArgs, Inputs));
360 }
361 
362 void amdgpu::getAMDGPUTargetFeatures(const Driver &D,
363                                      const llvm::opt::ArgList &Args,
364                                      std::vector<StringRef> &Features) {
365   if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi))
366     D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args);
367 
368   if (Args.getLastArg(options::OPT_mwavefrontsize64)) {
369     Features.push_back("-wavefrontsize16");
370     Features.push_back("-wavefrontsize32");
371     Features.push_back("+wavefrontsize64");
372   }
373   if (Args.getLastArg(options::OPT_mno_wavefrontsize64)) {
374     Features.push_back("-wavefrontsize16");
375     Features.push_back("+wavefrontsize32");
376     Features.push_back("-wavefrontsize64");
377   }
378 
379   handleTargetFeaturesGroup(
380     Args, Features, options::OPT_m_amdgpu_Features_Group);
381 }
382 
383 /// AMDGPU Toolchain
384 AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
385                                  const ArgList &Args)
386     : Generic_ELF(D, Triple, Args),
387       OptionsDefault({{options::OPT_O, "3"},
388                       {options::OPT_cl_std_EQ, "CL1.2"}}) {}
389 
390 Tool *AMDGPUToolChain::buildLinker() const {
391   return new tools::amdgpu::Linker(*this);
392 }
393 
394 DerivedArgList *
395 AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
396                                Action::OffloadKind DeviceOffloadKind) const {
397 
398   DerivedArgList *DAL =
399       Generic_ELF::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
400 
401   // Do nothing if not OpenCL (-x cl)
402   if (!Args.getLastArgValue(options::OPT_x).equals("cl"))
403     return DAL;
404 
405   if (!DAL)
406     DAL = new DerivedArgList(Args.getBaseArgs());
407   for (auto *A : Args)
408     DAL->append(A);
409 
410   const OptTable &Opts = getDriver().getOpts();
411 
412   // Phase 1 (.cl -> .bc)
413   if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) {
414     DAL->AddFlagArg(nullptr, Opts.getOption(getTriple().isArch64Bit()
415                                                 ? options::OPT_m64
416                                                 : options::OPT_m32));
417 
418     // Have to check OPT_O4, OPT_O0 & OPT_Ofast separately
419     // as they defined that way in Options.td
420     if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4,
421                      options::OPT_Ofast))
422       DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O),
423                         getOptionDefault(options::OPT_O));
424   }
425 
426   return DAL;
427 }
428 
429 bool AMDGPUToolChain::getDefaultDenormsAreZeroForTarget(
430     llvm::AMDGPU::GPUKind Kind) {
431 
432   // Assume nothing without a specific target.
433   if (Kind == llvm::AMDGPU::GK_NONE)
434     return false;
435 
436   const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind);
437 
438   // Default to enabling f32 denormals by default on subtargets where fma is
439   // fast with denormals
440   const bool BothDenormAndFMAFast =
441       (ArchAttr & llvm::AMDGPU::FEATURE_FAST_FMA_F32) &&
442       (ArchAttr & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32);
443   return !BothDenormAndFMAFast;
444 }
445 
446 llvm::DenormalMode AMDGPUToolChain::getDefaultDenormalModeForType(
447     const llvm::opt::ArgList &DriverArgs, const JobAction &JA,
448     const llvm::fltSemantics *FPType) const {
449   // Denormals should always be enabled for f16 and f64.
450   if (!FPType || FPType != &llvm::APFloat::IEEEsingle())
451     return llvm::DenormalMode::getIEEE();
452 
453   if (JA.getOffloadingDeviceKind() == Action::OFK_HIP ||
454       JA.getOffloadingDeviceKind() == Action::OFK_Cuda) {
455     auto Kind = llvm::AMDGPU::parseArchAMDGCN(JA.getOffloadingArch());
456     if (FPType && FPType == &llvm::APFloat::IEEEsingle() &&
457         DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero,
458                            options::OPT_fno_cuda_flush_denormals_to_zero,
459                            getDefaultDenormsAreZeroForTarget(Kind)))
460       return llvm::DenormalMode::getPreserveSign();
461 
462     return llvm::DenormalMode::getIEEE();
463   }
464 
465   const StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ);
466   auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);
467 
468   // TODO: There are way too many flags that change this. Do we need to check
469   // them all?
470   bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) ||
471              getDefaultDenormsAreZeroForTarget(Kind);
472 
473   // Outputs are flushed to zero (FTZ), preserving sign. Denormal inputs are
474   // also implicit treated as zero (DAZ).
475   return DAZ ? llvm::DenormalMode::getPreserveSign() :
476                llvm::DenormalMode::getIEEE();
477 }
478 
479 bool AMDGPUToolChain::isWave64(const llvm::opt::ArgList &DriverArgs,
480                                llvm::AMDGPU::GPUKind Kind) {
481   const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind);
482   static bool HasWave32 = (ArchAttr & llvm::AMDGPU::FEATURE_WAVE32);
483 
484   return !HasWave32 || DriverArgs.hasFlag(
485     options::OPT_mwavefrontsize64, options::OPT_mno_wavefrontsize64, false);
486 }
487 
488 
489 /// ROCM Toolchain
490 ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple,
491                              const ArgList &Args)
492     : AMDGPUToolChain(D, Triple, Args) {
493   RocmInstallation.detectDeviceLibrary();
494 }
495 
496 void AMDGPUToolChain::addClangTargetOptions(
497     const llvm::opt::ArgList &DriverArgs,
498     llvm::opt::ArgStringList &CC1Args,
499     Action::OffloadKind DeviceOffloadingKind) const {
500   // Default to "hidden" visibility, as object level linking will not be
501   // supported for the foreseeable future.
502   if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
503                          options::OPT_fvisibility_ms_compat)) {
504     CC1Args.push_back("-fvisibility");
505     CC1Args.push_back("hidden");
506     CC1Args.push_back("-fapply-global-visibility-to-externs");
507   }
508 }
509 
510 void ROCMToolChain::addClangTargetOptions(
511     const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
512     Action::OffloadKind DeviceOffloadingKind) const {
513   AMDGPUToolChain::addClangTargetOptions(DriverArgs, CC1Args,
514                                          DeviceOffloadingKind);
515 
516   // For the OpenCL case where there is no offload target, accept -nostdlib to
517   // disable bitcode linking.
518   if (DeviceOffloadingKind == Action::OFK_None &&
519       DriverArgs.hasArg(options::OPT_nostdlib))
520     return;
521 
522   if (DriverArgs.hasArg(options::OPT_nogpulib))
523     return;
524 
525   if (!RocmInstallation.hasDeviceLibrary()) {
526     getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
527     return;
528   }
529 
530   // Get the device name and canonicalize it
531   const StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ);
532   auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);
533   const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind);
534   std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
535   if (LibDeviceFile.empty()) {
536     getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch;
537     return;
538   }
539 
540   bool Wave64 = isWave64(DriverArgs, Kind);
541 
542   // TODO: There are way too many flags that change this. Do we need to check
543   // them all?
544   bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) ||
545              getDefaultDenormsAreZeroForTarget(Kind);
546   bool FiniteOnly = DriverArgs.hasArg(options::OPT_cl_finite_math_only);
547 
548   bool UnsafeMathOpt =
549       DriverArgs.hasArg(options::OPT_cl_unsafe_math_optimizations);
550   bool FastRelaxedMath = DriverArgs.hasArg(options::OPT_cl_fast_relaxed_math);
551   bool CorrectSqrt =
552       DriverArgs.hasArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt);
553 
554   // Add the OpenCL specific bitcode library.
555   CC1Args.push_back("-mlink-builtin-bitcode");
556   CC1Args.push_back(DriverArgs.MakeArgString(RocmInstallation.getOpenCLPath()));
557 
558   // Add the generic set of libraries.
559   RocmInstallation.addCommonBitcodeLibCC1Args(
560       DriverArgs, CC1Args, LibDeviceFile, Wave64, DAZ, FiniteOnly,
561       UnsafeMathOpt, FastRelaxedMath, CorrectSqrt);
562 }
563 
564 void RocmInstallationDetector::addCommonBitcodeLibCC1Args(
565     const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
566     StringRef LibDeviceFile, bool Wave64, bool DAZ, bool FiniteOnly,
567     bool UnsafeMathOpt, bool FastRelaxedMath, bool CorrectSqrt) const {
568   static const char LinkBitcodeFlag[] = "-mlink-builtin-bitcode";
569 
570   CC1Args.push_back(LinkBitcodeFlag);
571   CC1Args.push_back(DriverArgs.MakeArgString(getOCMLPath()));
572 
573   CC1Args.push_back(LinkBitcodeFlag);
574   CC1Args.push_back(DriverArgs.MakeArgString(getOCKLPath()));
575 
576   CC1Args.push_back(LinkBitcodeFlag);
577   CC1Args.push_back(DriverArgs.MakeArgString(getDenormalsAreZeroPath(DAZ)));
578 
579   CC1Args.push_back(LinkBitcodeFlag);
580   CC1Args.push_back(DriverArgs.MakeArgString(
581       getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath)));
582 
583   CC1Args.push_back(LinkBitcodeFlag);
584   CC1Args.push_back(DriverArgs.MakeArgString(
585       getFiniteOnlyPath(FiniteOnly || FastRelaxedMath)));
586 
587   CC1Args.push_back(LinkBitcodeFlag);
588   CC1Args.push_back(
589       DriverArgs.MakeArgString(getCorrectlyRoundedSqrtPath(CorrectSqrt)));
590 
591   CC1Args.push_back(LinkBitcodeFlag);
592   CC1Args.push_back(DriverArgs.MakeArgString(getWavefrontSize64Path(Wave64)));
593 
594   CC1Args.push_back(LinkBitcodeFlag);
595   CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile));
596 }
597