15 #include "llvm/Option/ArgList.h" 16 #include "llvm/Support/Path.h" 17 #include "llvm/Support/VirtualFileSystem.h" 22 using namespace clang;
25 void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
26 assert(!Path.empty());
28 const StringRef Suffix(
".bc");
29 const StringRef Suffix2(
".amdgcn.bc");
32 for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Path, EC),
LE;
33 !EC && LI !=
LE; LI = LI.increment(EC)) {
34 StringRef FilePath = LI->path();
35 StringRef FileName = llvm::sys::path::filename(FilePath);
36 if (!FileName.endswith(Suffix))
40 if (FileName.endswith(Suffix2))
41 BaseName = FileName.drop_back(Suffix2.size());
42 else if (FileName.endswith(Suffix))
43 BaseName = FileName.drop_back(Suffix.size());
45 if (BaseName ==
"ocml") {
47 }
else if (BaseName ==
"ockl") {
49 }
else if (BaseName ==
"opencl") {
51 }
else if (BaseName ==
"hip") {
53 }
else if (BaseName ==
"oclc_finite_only_off") {
54 FiniteOnly.Off = FilePath;
55 }
else if (BaseName ==
"oclc_finite_only_on") {
56 FiniteOnly.On = FilePath;
57 }
else if (BaseName ==
"oclc_daz_opt_on") {
58 DenormalsAreZero.On = FilePath;
59 }
else if (BaseName ==
"oclc_daz_opt_off") {
60 DenormalsAreZero.Off = FilePath;
61 }
else if (BaseName ==
"oclc_correctly_rounded_sqrt_on") {
62 CorrectlyRoundedSqrt.On = FilePath;
63 }
else if (BaseName ==
"oclc_correctly_rounded_sqrt_off") {
64 CorrectlyRoundedSqrt.Off = FilePath;
65 }
else if (BaseName ==
"oclc_unsafe_math_on") {
66 UnsafeMath.On = FilePath;
67 }
else if (BaseName ==
"oclc_unsafe_math_off") {
68 UnsafeMath.Off = FilePath;
69 }
else if (BaseName ==
"oclc_wavefrontsize64_on") {
70 WavefrontSize64.On = FilePath;
71 }
else if (BaseName ==
"oclc_wavefrontsize64_off") {
72 WavefrontSize64.Off = FilePath;
76 const StringRef DeviceLibPrefix =
"oclc_isa_version_";
77 if (!BaseName.startswith(DeviceLibPrefix))
80 StringRef IsaVersionNumber =
81 BaseName.drop_front(DeviceLibPrefix.size());
83 llvm::Twine GfxName = Twine(
"gfx") + IsaVersionNumber;
86 std::make_pair(GfxName.toStringRef(Tmp), FilePath.str()));
93 bool RocmInstallationDetector::parseHIPVersionFile(llvm::StringRef
V) {
95 V.split(VersionParts,
'\n');
98 for (
auto Part : VersionParts) {
99 auto Splits = Part.rtrim().split(
'=');
100 if (Splits.first ==
"HIP_VERSION_MAJOR") {
101 if (Splits.second.getAsInteger(0, Major))
103 }
else if (Splits.first ==
"HIP_VERSION_MINOR") {
104 if (Splits.second.getAsInteger(0, Minor))
106 }
else if (Splits.first ==
"HIP_VERSION_PATCH")
107 VersionPatch = Splits.second.str();
109 if (Major == ~0
U || Minor == ~0
U)
111 VersionMajorMinor = llvm::VersionTuple(Major, Minor);
113 (Twine(Major) +
"." + Twine(Minor) +
"." + VersionPatch).str();
119 RocmInstallationDetector::getInstallationPathCandidates() {
121 if (!RocmPathArg.empty()) {
122 Candidates.emplace_back(RocmPathArg.str());
127 const char *InstallDir = D.getInstalledDir();
134 StringRef ParentDir = llvm::sys::path::parent_path(InstallDir);
135 StringRef ParentName = llvm::sys::path::filename(ParentDir);
138 if (ParentName ==
"bin") {
139 ParentDir = llvm::sys::path::parent_path(ParentDir);
140 ParentName = llvm::sys::path::filename(ParentDir);
144 if (ParentName ==
"llvm")
145 ParentDir = llvm::sys::path::parent_path(ParentDir);
147 Candidates.emplace_back(ParentDir.str(),
true);
150 Candidates.emplace_back(D.ResourceDir,
true);
152 Candidates.emplace_back(D.SysRoot +
"/opt/rocm",
true);
157 const Driver &D,
const llvm::Triple &HostTriple,
158 const llvm::opt::ArgList &Args,
bool DetectHIPRuntime,
bool DetectDeviceLib)
160 RocmPathArg = Args.getLastArgValue(clang::driver::options::OPT_rocm_path_EQ);
161 RocmDeviceLibPathArg =
162 Args.getAllArgValues(clang::driver::options::OPT_rocm_device_lib_path_EQ);
163 if (
auto *A = Args.getLastArg(clang::driver::options::OPT_hip_version_EQ)) {
164 HIPVersionArg = A->getValue();
168 HIPVersionArg.split(Parts,
'.');
170 Parts[0].getAsInteger(0, Major);
171 if (Parts.size() > 1)
172 Parts[1].getAsInteger(0, Minor);
173 if (Parts.size() > 2)
174 VersionPatch = Parts[2].str();
175 if (VersionPatch.empty())
177 if (Major == 0 || Minor == 0)
178 D.
Diag(diag::err_drv_invalid_value)
179 << A->getAsString(Args) << HIPVersionArg;
181 VersionMajorMinor = llvm::VersionTuple(Major, Minor);
183 (Twine(Major) +
"." + Twine(Minor) +
"." + VersionPatch).str();
185 VersionPatch = DefaultVersionPatch;
187 llvm::VersionTuple(DefaultVersionMajor, DefaultVersionMinor);
188 DetectedVersion = (Twine(DefaultVersionMajor) +
"." +
189 Twine(DefaultVersionMinor) +
"." + VersionPatch)
193 if (DetectHIPRuntime)
200 assert(LibDevicePath.empty());
202 if (!RocmDeviceLibPathArg.empty())
203 LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1];
204 else if (
const char *LibPathEnv = ::getenv(
"HIP_DEVICE_LIB_PATH"))
205 LibDevicePath = LibPathEnv;
208 if (!LibDevicePath.empty()) {
212 if (!FS.exists(LibDevicePath))
215 scanLibDevicePath(LibDevicePath);
216 HasDeviceLibrary = allGenericLibsValid() && !LibDeviceMap.empty();
225 auto Candidates = getInstallationPathCandidates();
226 for (
const auto &Candidate : Candidates) {
227 auto CandidatePath = Candidate.Path;
230 auto CheckDeviceLib = [&](StringRef Path) {
231 bool CheckLibDevice = (!NoBuiltinLibs || Candidate.StrictChecking);
232 if (CheckLibDevice && !FS.exists(Path))
235 scanLibDevicePath(Path);
237 if (!NoBuiltinLibs) {
239 if (!allGenericLibsValid())
244 if (LibDeviceMap.empty())
255 static constexpr std::array<const char *, 2> SubDirsList[] = {
256 {
"amdgcn",
"bitcode"},
263 auto Path = CandidatePath;
264 for (
auto SubDir : SubDirs)
265 llvm::sys::path::append(Path, SubDir);
269 for (
auto SubDirs : SubDirsList) {
270 LibDevicePath = MakePath(SubDirs);
271 HasDeviceLibrary = CheckDeviceLib(LibDevicePath);
272 if (HasDeviceLibrary)
279 auto Candidates = getInstallationPathCandidates();
282 for (
const auto &Candidate : Candidates) {
283 InstallPath = Candidate.Path;
284 if (InstallPath.empty() || !FS.exists(InstallPath))
287 BinPath = InstallPath;
288 llvm::sys::path::append(BinPath,
"bin");
289 IncludePath = InstallPath;
290 llvm::sys::path::append(IncludePath,
"include");
291 LibPath = InstallPath;
292 llvm::sys::path::append(LibPath,
"lib");
294 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
295 FS.getBufferForFile(BinPath +
"/.hipVersion");
296 if (!VersionFile && Candidate.StrictChecking)
299 if (HIPVersionArg.empty() && VersionFile)
300 if (parseHIPVersionFile((*VersionFile)->getBuffer()))
303 HasHIPRuntime =
true;
306 HasHIPRuntime =
false;
311 OS <<
"Found HIP installation: " << InstallPath <<
", version " 312 << DetectedVersion <<
'\n';
316 ArgStringList &CC1Args)
const {
317 bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5);
319 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
334 if (UsesRuntimeWrapper)
335 llvm::sys::path::append(
P,
"include",
"cuda_wrappers");
336 CC1Args.push_back(
"-internal-isystem");
337 CC1Args.push_back(DriverArgs.MakeArgString(
P));
340 if (DriverArgs.hasArg(options::OPT_nogpuinc))
344 D.
Diag(diag::err_drv_no_hip_runtime);
348 CC1Args.push_back(
"-internal-isystem");
350 if (UsesRuntimeWrapper)
351 CC1Args.append({
"-include",
"__clang_hip_runtime_wrapper.h"});
358 const char *LinkingOutput)
const {
360 std::string
Linker = getToolChain().GetProgramPath(getShortName());
361 ArgStringList CmdArgs;
364 CmdArgs.push_back(
"-shared");
365 CmdArgs.push_back(
"-o");
367 C.addCommand(std::make_unique<Command>(
369 CmdArgs, Inputs, Output));
373 const llvm::Triple &Triple,
374 const llvm::opt::ArgList &Args,
375 std::vector<StringRef> &Features) {
378 StringRef TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ);
379 if (!TargetID.empty()) {
380 llvm::StringMap<bool> FeatureMap;
381 auto OptionalGpuArch =
parseTargetID(Triple, TargetID, &FeatureMap);
382 if (OptionalGpuArch) {
383 StringRef GpuArch = OptionalGpuArch.getValue();
389 auto Pos = FeatureMap.find(Feature);
390 if (Pos == FeatureMap.end())
392 Features.push_back(Args.MakeArgStringRef(
393 (Twine(Pos->second ?
"+" :
"-") + Feature).str()));
398 if (Args.hasFlag(options::OPT_mwavefrontsize64,
399 options::OPT_mno_wavefrontsize64,
false))
400 Features.push_back(
"+wavefrontsize64");
403 Args, Features, options::OPT_m_amdgpu_Features_Group);
407 AMDGPUToolChain::AMDGPUToolChain(
const Driver &D,
const llvm::Triple &Triple,
411 {{options::OPT_O,
"3"}, {options::OPT_cl_std_EQ,
"CL1.2"}}) {
427 DerivedArgList *DAL =
433 DAL =
new DerivedArgList(Args.getBaseArgs());
435 for (Arg *A : Args) {
442 if (!Args.getLastArgValue(options::OPT_x).equals(
"cl"))
446 if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) {
447 DAL->AddFlagArg(
nullptr, Opts.getOption(
getTriple().isArch64Bit()
449 : options::OPT_m32));
453 if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4,
455 DAL->AddJoinedArg(
nullptr, Opts.getOption(options::OPT_O),
463 llvm::AMDGPU::GPUKind
Kind) {
466 if (
Kind == llvm::AMDGPU::GK_NONE)
469 const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(
Kind);
473 const bool BothDenormAndFMAFast =
474 (ArchAttr & llvm::AMDGPU::FEATURE_FAST_FMA_F32) &&
475 (ArchAttr & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32);
476 return !BothDenormAndFMAFast;
480 const llvm::opt::ArgList &DriverArgs,
const JobAction &JA,
481 const llvm::fltSemantics *FPType)
const {
483 if (!FPType || FPType != &llvm::APFloat::IEEEsingle())
484 return llvm::DenormalMode::getIEEE();
489 auto Kind = llvm::AMDGPU::parseArchAMDGCN(Arch);
490 if (FPType && FPType == &llvm::APFloat::IEEEsingle() &&
491 DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero,
492 options::OPT_fno_cuda_flush_denormals_to_zero,
494 return llvm::DenormalMode::getPreserveSign();
496 return llvm::DenormalMode::getIEEE();
499 const StringRef GpuArch =
getGPUArch(DriverArgs);
500 auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);
504 bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) ||
509 return DAZ ? llvm::DenormalMode::getPreserveSign() :
510 llvm::DenormalMode::getIEEE();
514 llvm::AMDGPU::GPUKind
Kind) {
515 const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(
Kind);
516 bool HasWave32 = (ArchAttr & llvm::AMDGPU::FEATURE_WAVE32);
518 return !HasWave32 || DriverArgs.hasFlag(
519 options::OPT_mwavefrontsize64, options::OPT_mno_wavefrontsize64,
false);
531 const llvm::opt::ArgList &DriverArgs,
532 llvm::opt::ArgStringList &CC1Args,
536 if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
537 options::OPT_fvisibility_ms_compat)) {
538 CC1Args.push_back(
"-fvisibility");
539 CC1Args.push_back(
"hidden");
540 CC1Args.push_back(
"-fapply-global-visibility-to-externs");
547 getTriple(), DriverArgs.getLastArgValue(options::OPT_mcpu_EQ));
551 const llvm::opt::ArgList &DriverArgs)
const {
552 StringRef TargetID = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ);
553 if (TargetID.empty())
556 llvm::StringMap<bool> FeatureMap;
558 if (!OptionalGpuArch) {
559 getDriver().
Diag(clang::diag::err_drv_bad_target_id) << TargetID;
564 const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
567 DeviceOffloadingKind);
572 DriverArgs.hasArg(options::OPT_nostdlib))
575 if (DriverArgs.hasArg(options::OPT_nogpulib))
584 const StringRef GpuArch =
getGPUArch(DriverArgs);
585 auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);
586 const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(
Kind);
588 if (LibDeviceFile.empty()) {
589 getDriver().
Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch;
597 bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) ||
599 bool FiniteOnly = DriverArgs.hasArg(options::OPT_cl_finite_math_only);
602 DriverArgs.hasArg(options::OPT_cl_unsafe_math_optimizations);
603 bool FastRelaxedMath = DriverArgs.hasArg(options::OPT_cl_fast_relaxed_math);
605 DriverArgs.hasArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt);
608 CC1Args.push_back(
"-mlink-builtin-bitcode");
613 DriverArgs, CC1Args, LibDeviceFile, Wave64, DAZ, FiniteOnly,
614 UnsafeMathOpt, FastRelaxedMath, CorrectSqrt);
618 const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
619 StringRef LibDeviceFile,
bool Wave64,
bool DAZ,
bool FiniteOnly,
620 bool UnsafeMathOpt,
bool FastRelaxedMath,
bool CorrectSqrt)
const {
621 static const char LinkBitcodeFlag[] =
"-mlink-builtin-bitcode";
623 CC1Args.push_back(LinkBitcodeFlag);
624 CC1Args.push_back(DriverArgs.MakeArgString(getOCMLPath()));
626 CC1Args.push_back(LinkBitcodeFlag);
627 CC1Args.push_back(DriverArgs.MakeArgString(getOCKLPath()));
629 CC1Args.push_back(LinkBitcodeFlag);
630 CC1Args.push_back(DriverArgs.MakeArgString(getDenormalsAreZeroPath(DAZ)));
632 CC1Args.push_back(LinkBitcodeFlag);
633 CC1Args.push_back(DriverArgs.MakeArgString(
634 getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath)));
636 CC1Args.push_back(LinkBitcodeFlag);
637 CC1Args.push_back(DriverArgs.MakeArgString(
638 getFiniteOnlyPath(FiniteOnly || FastRelaxedMath)));
640 CC1Args.push_back(LinkBitcodeFlag);
642 DriverArgs.MakeArgString(getCorrectlyRoundedSqrtPath(CorrectSqrt)));
644 CC1Args.push_back(LinkBitcodeFlag);
645 CC1Args.push_back(DriverArgs.MakeArgString(getWavefrontSize64Path(Wave64)));
647 CC1Args.push_back(LinkBitcodeFlag);
648 CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile));
652 Option O = A->getOption();
653 if (O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie))
DiagnosticBuilder Diag(unsigned DiagID) const
llvm::StringRef getProcessorFromTargetID(const llvm::Triple &T, llvm::StringRef OffloadArch)
Get processor name from target ID.
bool hasHIPRuntime() const
Check whether we detected a valid HIP runtime.
void print(raw_ostream &OS) const
Print information about the detected ROCm installation.
OffloadKind getOffloadingDeviceKind() const
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
const llvm::SmallVector< llvm::StringRef, 4 > getAllPossibleTargetIDFeatures(const llvm::Triple &T, llvm::StringRef Processor)
Get all feature strings that can be used in target ID for Processor.
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const
llvm::vfs::FileSystem & getVFS() const
void detectDeviceLibrary()
bool hasDeviceLibrary() const
Check whether we detected a valid ROCm device library.
StringRef getIncludePath() const
Get the detected path to Rocm's bin directory.
RocmInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, const llvm::opt::ArgList &Args, bool DetectHIPRuntime=true, bool DetectDeviceLib=false)
std::string getLibDeviceFile(StringRef Gpu) const
Get libdevice file for given architecture.
Dataflow Directional Tag Classes.
llvm::Optional< llvm::StringRef > parseTargetID(const llvm::Triple &T, llvm::StringRef OffloadArch, llvm::StringMap< bool > *FeatureMap)
Parse a target ID to get processor and feature map.
Compilation - A set of tasks to perform for a single driver invocation.
static constexpr ResponseFileSupport AtFileCurCP()
bool LE(InterpState &S, CodePtr OpPC)
StringRef getOpenCLPath() const
const llvm::opt::OptTable & getOpts() const
const char * getOffloadingArch() const
void addCommonBitcodeLibCC1Args(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, StringRef LibDeviceFile, bool Wave64, bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, bool FastRelaxedMath, bool CorrectSqrt) const
Add arguments needed to link default bitcode libraries.
std::string ResourceDir
The path to the compiler resource directory.