Reapplication of #137828 and #169638 Move building the .mod files from openmp/flang to openmp/flang-rt using a shared mechanism. Motivations to do so are: 1. Most modules are target-dependent and need to be re-compiled for each target separately, which is something the LLVM_ENABLE_RUNTIMES system already does. Prime example is `iso_c_binding.mod` which encodes the target's ABI. Constants such as `c_long_double` also have different values). Most other modules have `#ifdef`-enclosed code as well. For instance this caused offload targets nvptx64-nvidia-cuda/amdgpu-amd-amdhsa to use the modules files compiled for the host which may contrain uses of the types REAL(10) or REAL(16) not available for nvptx/amdgpu. 2. CMake has support for Fortran that we should use. Among other things, it automatically determines module dependencies so there is no need to hardcode them in the CMakeLists.txt. Currently the dependencies between builtin modules and `omp_lib.mod` seem to be incorrect: https://github.com/llvm/llvm-project/pull/174474#issuecomment-3880189581 3. It allows using Fortran itself to implement Flang-RT. Currently, only `iso_fortran_env_impl.f90` emits object files that are needed by Fortran applications (#89403). The workaround of #95388 could be reverted (PR #169525). If using Flang for cross-compilation or target-offloading, flang-rt must now be compiled for each target not only for the library, but also to get the target-specific module files. For instance in a bootstrapping runtime build, this can be done by adding: `-DLLVM_RUNTIME_TARGETS=default;nvptx64-nvidia-cuda;amdgpu-amd-amdhsa`. Some new dependencies come into play: * openmp depends on flang-rt for building `lib_omp.mod` and `lib_omp_kinds.mod`. Currently, if flang-rt is not found then the modules are not built. * check-flang depends on flang-rt: If not found, the majority of tests are disabled. If not building in a bootstrpping build, the location of the module files can be pointed to using `-DFLANG_INTRINSIC_MODULES_DIR=<path>`, e.g. in a flang-standalone build. Alternatively, the test needing any of the intrinsic modules could be marked with `REQUIRES: flangrt-modules`. * check-flang depends on openmp: Not a change; tests requiring `lib_omp.mod` and `lib_omp_kinds.mod` those are already marked with `openmp_runtime`. As intrinsic are now specific to the target, their location is moved from `include/flang` to `<resource-dir>/finclude/flang/<triple>`. The mechnism to compute the location have been moved from flang-rt (previously used to compute the location of `libflang_rt.*.a`) to common locations in `cmake/GetToolchainDirs.cmake` and `runtimes/CMakeLists.txt` so they can be used by both, openmp and flang-rt. Potentially the mechnism could also be shared by other libraries such as compiler-rt. `finclude` was chosen because `gfortran` uses it as well and avoids misuse such as `#include <flang/iso_c_binding.mod>`. The search location is now determined by `ToolChain` in the driver, instead of by the frontend. Another subdirectory `flang` avoids accidental inclusion of gfortran-modules which due to compression would result in user-unfriendly errors. Now the driver adds `-fintrinsic-module-path` for that location to the frontend call (Just like gfortran does). Since the driver determines the location, tests invoking `flang -fc1` and `bbc` must also be passed the location by llvm-lit. This works like llvm-lit does for finding the include dirs for Clang using `-print-file-name=...`.
458 lines
18 KiB
C++
458 lines
18 KiB
C++
//===--- HIPAMD.cpp - HIP Tool and ToolChain Implementations ----*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "HIPAMD.h"
|
|
#include "AMDGPU.h"
|
|
#include "HIPUtility.h"
|
|
#include "SPIRV.h"
|
|
#include "clang/Basic/Cuda.h"
|
|
#include "clang/Driver/CommonArgs.h"
|
|
#include "clang/Driver/Compilation.h"
|
|
#include "clang/Driver/Driver.h"
|
|
#include "clang/Driver/InputInfo.h"
|
|
#include "clang/Driver/SanitizerArgs.h"
|
|
#include "clang/Options/Options.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/TargetParser/TargetParser.h"
|
|
|
|
using namespace clang::driver;
|
|
using namespace clang::driver::toolchains;
|
|
using namespace clang::driver::tools;
|
|
using namespace clang;
|
|
using namespace llvm::opt;
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
#define NULL_FILE "nul"
|
|
#else
|
|
#define NULL_FILE "/dev/null"
|
|
#endif
|
|
|
|
void AMDGCN::Linker::constructLLVMLinkCommand(
|
|
Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
|
|
const InputInfo &Output, const llvm::opt::ArgList &Args) const {
|
|
|
|
ArgStringList LinkerInputs;
|
|
|
|
for (auto Input : Inputs)
|
|
if (Input.isFilename())
|
|
LinkerInputs.push_back(Input.getFilename());
|
|
|
|
// Look for archive of bundled bitcode in arguments, and add temporary files
|
|
// for the extracted archive of bitcode to inputs.
|
|
auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ);
|
|
AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LinkerInputs, "amdgcn",
|
|
TargetID, /*IsBitCodeSDL=*/true);
|
|
tools::constructLLVMLinkCommand(C, *this, JA, Inputs, LinkerInputs, Output,
|
|
Args);
|
|
}
|
|
|
|
void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
|
|
const InputInfoList &Inputs,
|
|
const InputInfo &Output,
|
|
const llvm::opt::ArgList &Args) const {
|
|
// Construct lld command.
|
|
// The output from ld.lld is an HSA code object file.
|
|
ArgStringList LldArgs{"-flavor",
|
|
"gnu",
|
|
"-m",
|
|
"elf64_amdgpu",
|
|
"--no-undefined",
|
|
"-shared",
|
|
"-plugin-opt=-amdgpu-internalize-symbols"};
|
|
if (Args.hasArg(options::OPT_hipstdpar))
|
|
LldArgs.push_back("-plugin-opt=-amdgpu-enable-hipstdpar");
|
|
|
|
auto &TC = getToolChain();
|
|
auto &D = TC.getDriver();
|
|
bool IsThinLTO = D.getOffloadLTOMode() == LTOK_Thin;
|
|
addLTOOptions(TC, Args, LldArgs, Output, Inputs, IsThinLTO);
|
|
|
|
// Extract all the -m options
|
|
std::vector<llvm::StringRef> Features;
|
|
amdgpu::getAMDGPUTargetFeatures(D, TC.getTriple(), Args, Features);
|
|
|
|
// Add features to mattr such as cumode
|
|
std::string MAttrString = "-plugin-opt=-mattr=";
|
|
for (auto OneFeature : unifyTargetFeatures(Features)) {
|
|
MAttrString.append(Args.MakeArgStringRef(OneFeature));
|
|
if (OneFeature != Features.back())
|
|
MAttrString.append(",");
|
|
}
|
|
if (!Features.empty())
|
|
LldArgs.push_back(Args.MakeArgString(MAttrString));
|
|
|
|
// ToDo: Remove this option after AMDGPU backend supports ISA-level linking.
|
|
// Since AMDGPU backend currently does not support ISA-level linking, all
|
|
// called functions need to be imported.
|
|
if (IsThinLTO) {
|
|
LldArgs.push_back("-plugin-opt=-force-import-all");
|
|
LldArgs.push_back("-plugin-opt=-avail-extern-to-local");
|
|
LldArgs.push_back("-plugin-opt=-avail-extern-gv-in-addrspace-to-local=3");
|
|
}
|
|
|
|
for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
|
|
LldArgs.push_back(
|
|
Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0)));
|
|
}
|
|
|
|
if (C.getDriver().isSaveTempsEnabled())
|
|
LldArgs.push_back("-save-temps");
|
|
|
|
addLinkerCompressDebugSectionsOption(TC, Args, LldArgs);
|
|
|
|
// Given that host and device linking happen in separate processes, the device
|
|
// linker doesn't always have the visibility as to which device symbols are
|
|
// needed by a program, especially for the device symbol dependencies that are
|
|
// introduced through the host symbol resolution.
|
|
// For example: host_A() (A.obj) --> host_B(B.obj) --> device_kernel_B()
|
|
// (B.obj) In this case, the device linker doesn't know that A.obj actually
|
|
// depends on the kernel functions in B.obj. When linking to static device
|
|
// library, the device linker may drop some of the device global symbols if
|
|
// they aren't referenced. As a workaround, we are adding to the
|
|
// --whole-archive flag such that all global symbols would be linked in.
|
|
LldArgs.push_back("--whole-archive");
|
|
|
|
for (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) {
|
|
StringRef ArgVal = Arg->getValue(1);
|
|
auto SplitArg = ArgVal.split("-mllvm=");
|
|
if (!SplitArg.second.empty()) {
|
|
LldArgs.push_back(
|
|
Args.MakeArgString(Twine("-plugin-opt=") + SplitArg.second));
|
|
} else {
|
|
LldArgs.push_back(Args.MakeArgStringRef(ArgVal));
|
|
}
|
|
Arg->claim();
|
|
}
|
|
|
|
LldArgs.append({"-o", Output.getFilename()});
|
|
for (auto Input : Inputs)
|
|
LldArgs.push_back(Input.getFilename());
|
|
|
|
// Look for archive of bundled bitcode in arguments, and add temporary files
|
|
// for the extracted archive of bitcode to inputs.
|
|
auto TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ);
|
|
AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LldArgs, "amdgcn",
|
|
TargetID, /*IsBitCodeSDL=*/true);
|
|
|
|
LldArgs.push_back("--no-whole-archive");
|
|
|
|
const char *Lld = Args.MakeArgStringRef(getToolChain().GetProgramPath("lld"));
|
|
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
|
|
Lld, LldArgs, Inputs, Output));
|
|
}
|
|
|
|
// For SPIR-V the inputs for the job are device AMDGCN SPIR-V flavoured bitcode
|
|
// and the output is either a compiled SPIR-V binary or bitcode (-emit-llvm). It
|
|
// calls llvm-link and then the llvm-spirv translator or the SPIR-V BE.
|
|
// TODO: consider if we want to run any targeted optimisations over IR here,
|
|
// over generic SPIR-V.
|
|
void AMDGCN::Linker::constructLinkAndEmitSpirvCommand(
|
|
Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
|
|
const InputInfo &Output, const llvm::opt::ArgList &Args) const {
|
|
assert(!Inputs.empty() && "Must have at least one input.");
|
|
|
|
std::string LinkedBCFilePrefix(
|
|
Twine(llvm::sys::path::stem(Output.getFilename()), "-linked").str());
|
|
const char *LinkedBCFilePath = HIP::getTempFile(C, LinkedBCFilePrefix, "bc");
|
|
InputInfo LinkedBCFile(&JA, LinkedBCFilePath, Output.getBaseInput());
|
|
|
|
bool UseSPIRVBackend =
|
|
Args.hasFlag(options::OPT_use_spirv_backend,
|
|
options::OPT_no_use_spirv_backend, /*Default=*/false);
|
|
|
|
constructLLVMLinkCommand(C, JA, Inputs, LinkedBCFile, Args);
|
|
|
|
if (UseSPIRVBackend) {
|
|
// This code handles the case in the new driver when --offload-device-only
|
|
// is unset and clang-linker-wrapper forwards the bitcode that must be
|
|
// compiled to SPIR-V.
|
|
|
|
llvm::opt::ArgStringList CmdArgs;
|
|
|
|
CmdArgs.append({"-cc1", "-triple=spirv64-amd-amdhsa", "-emit-obj",
|
|
"-disable-llvm-optzns", LinkedBCFile.getFilename(), "-o",
|
|
Output.getFilename()});
|
|
|
|
const Driver &Driver = getToolChain().getDriver();
|
|
const char *Exec = Driver.getClangProgramPath();
|
|
C.addCommand(std::make_unique<Command>(
|
|
JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, LinkedBCFile,
|
|
Output, Driver.getPrependArg()));
|
|
} else {
|
|
// Emit SPIR-V binary using the translator
|
|
llvm::opt::ArgStringList TrArgs{
|
|
"--spirv-max-version=1.6",
|
|
"--spirv-ext=+all",
|
|
"--spirv-allow-unknown-intrinsics",
|
|
"--spirv-lower-const-expr",
|
|
"--spirv-preserve-auxdata",
|
|
"--spirv-debug-info-version=nonsemantic-shader-200"};
|
|
SPIRV::constructTranslateCommand(C, *this, JA, Output, LinkedBCFile,
|
|
TrArgs);
|
|
}
|
|
}
|
|
|
|
// For amdgcn the inputs of the linker job are device bitcode and output is
|
|
// either an object file or bitcode (-emit-llvm). It calls llvm-link, opt,
|
|
// llc, then lld steps.
|
|
void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
|
const InputInfo &Output,
|
|
const InputInfoList &Inputs,
|
|
const ArgList &Args,
|
|
const char *LinkingOutput) const {
|
|
if (!Inputs.empty() && Inputs[0].getType() == types::TY_Image &&
|
|
JA.getType() == types::TY_Object)
|
|
return HIP::constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs,
|
|
Args, JA, *this);
|
|
|
|
if (JA.getType() == types::TY_HIP_FATBIN)
|
|
return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs,
|
|
Args, *this);
|
|
|
|
if (JA.getType() == types::TY_LLVM_BC)
|
|
return constructLLVMLinkCommand(C, JA, Inputs, Output, Args);
|
|
|
|
if (getToolChain().getEffectiveTriple().isSPIRV())
|
|
return constructLinkAndEmitSpirvCommand(C, JA, Inputs, Output, Args);
|
|
|
|
return constructLldCommand(C, JA, Inputs, Output, Args);
|
|
}
|
|
|
|
HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple,
|
|
const ToolChain &HostTC, const ArgList &Args)
|
|
: ROCMToolChain(D, Triple, Args), HostTC(HostTC) {
|
|
// Lookup binaries into the driver directory, this is used to
|
|
// discover the clang-offload-bundler executable.
|
|
getProgramPaths().push_back(getDriver().Dir);
|
|
}
|
|
|
|
void HIPAMDToolChain::addClangTargetOptions(
|
|
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
|
|
Action::OffloadKind DeviceOffloadingKind) const {
|
|
HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
|
|
|
|
assert(DeviceOffloadingKind == Action::OFK_HIP &&
|
|
"Only HIP offloading kinds are supported for GPUs.");
|
|
|
|
CC1Args.append({"-fcuda-is-device", "-fno-threadsafe-statics"});
|
|
|
|
if (!DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
|
|
false)) {
|
|
CC1Args.append({"-mllvm", "-amdgpu-internalize-symbols"});
|
|
if (DriverArgs.hasArgNoClaim(options::OPT_hipstdpar))
|
|
CC1Args.append({"-mllvm", "-amdgpu-enable-hipstdpar"});
|
|
}
|
|
|
|
StringRef MaxThreadsPerBlock =
|
|
DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ);
|
|
if (!MaxThreadsPerBlock.empty()) {
|
|
CC1Args.push_back(DriverArgs.MakeArgString(
|
|
Twine("--gpu-max-threads-per-block=") + MaxThreadsPerBlock));
|
|
}
|
|
|
|
// Default to "hidden" visibility, as object level linking will not be
|
|
// supported for the foreseeable future.
|
|
// TODO: remove the SPIR-V bypass once it can encode (hidden) visibility.
|
|
if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
|
|
options::OPT_fvisibility_ms_compat) &&
|
|
!getEffectiveTriple().isSPIRV() && !getDriver().IsFlangMode()) {
|
|
CC1Args.append({"-fvisibility=hidden"});
|
|
CC1Args.push_back("-fapply-global-visibility-to-externs");
|
|
}
|
|
|
|
if (getEffectiveTriple().isSPIRV()) {
|
|
// For SPIR-V we embed the command-line into the generated binary, in order
|
|
// to retrieve it at JIT time and be able to do target specific compilation
|
|
// with options that match the user-supplied ones.
|
|
if (!DriverArgs.hasArg(options::OPT_fembed_bitcode_marker))
|
|
CC1Args.push_back("-fembed-bitcode=marker");
|
|
// For SPIR-V we want to retain the pristine output of Clang CodeGen, since
|
|
// optimizations might lose structure / information that is necessary for
|
|
// generating optimal concrete AMDGPU code. We duplicate this because the
|
|
// HIP TC doesn't invoke the base AMDGPU TC addClangTargetOptions.
|
|
if (!DriverArgs.hasArg(options::OPT_disable_llvm_passes))
|
|
CC1Args.push_back("-disable-llvm-passes");
|
|
return; // No DeviceLibs for SPIR-V.
|
|
}
|
|
|
|
for (auto BCFile : getDeviceLibs(DriverArgs, DeviceOffloadingKind)) {
|
|
CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode"
|
|
: "-mlink-bitcode-file");
|
|
CC1Args.push_back(DriverArgs.MakeArgStringRef(BCFile.Path));
|
|
}
|
|
}
|
|
|
|
llvm::opt::DerivedArgList *
|
|
HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
|
|
StringRef BoundArch,
|
|
Action::OffloadKind DeviceOffloadKind) const {
|
|
DerivedArgList *DAL =
|
|
HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
|
|
if (!DAL)
|
|
DAL = new DerivedArgList(Args.getBaseArgs());
|
|
|
|
const OptTable &Opts = getDriver().getOpts();
|
|
|
|
for (Arg *A : Args) {
|
|
// Sanitizer coverage is currently not supported for AMDGPU.
|
|
if (A->getOption().matches(options::OPT_fsan_cov_Group)) {
|
|
diagnoseUnsupportedOption(A, *DAL, Args);
|
|
continue;
|
|
}
|
|
|
|
if (A->getOption().matches(options::OPT_fsanitize_EQ) &&
|
|
!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
|
|
true))
|
|
continue;
|
|
|
|
DAL->append(A);
|
|
}
|
|
|
|
if (!BoundArch.empty()) {
|
|
DAL->eraseArg(options::OPT_mcpu_EQ);
|
|
DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), BoundArch);
|
|
checkTargetID(*DAL);
|
|
}
|
|
|
|
if (!Args.hasArg(options::OPT_flto_partitions_EQ))
|
|
DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_flto_partitions_EQ),
|
|
"8");
|
|
|
|
return DAL;
|
|
}
|
|
|
|
Tool *HIPAMDToolChain::buildLinker() const {
|
|
assert(getTriple().isAMDGCN() ||
|
|
getTriple().getArch() == llvm::Triple::spirv64);
|
|
return new tools::AMDGCN::Linker(*this);
|
|
}
|
|
|
|
void HIPAMDToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
|
|
AMDGPUToolChain::addClangWarningOptions(CC1Args);
|
|
HostTC.addClangWarningOptions(CC1Args);
|
|
}
|
|
|
|
ToolChain::CXXStdlibType
|
|
HIPAMDToolChain::GetCXXStdlibType(const ArgList &Args) const {
|
|
return HostTC.GetCXXStdlibType(Args);
|
|
}
|
|
|
|
void HIPAMDToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
|
ArgStringList &CC1Args) const {
|
|
HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
|
|
}
|
|
|
|
void HIPAMDToolChain::AddClangCXXStdlibIncludeArgs(
|
|
const ArgList &Args, ArgStringList &CC1Args) const {
|
|
HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
|
|
}
|
|
|
|
void HIPAMDToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
|
|
ArgStringList &CC1Args) const {
|
|
HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
|
|
}
|
|
|
|
void HIPAMDToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
|
|
ArgStringList &CC1Args) const {
|
|
RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
|
|
}
|
|
|
|
VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D,
|
|
const ArgList &Args) const {
|
|
return HostTC.computeMSVCVersion(D, Args);
|
|
}
|
|
|
|
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
|
|
HIPAMDToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs,
|
|
Action::OffloadKind DeviceOffloadingKind) const {
|
|
llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs;
|
|
const llvm::Triple &TT = getEffectiveTriple();
|
|
|
|
if (!DriverArgs.hasFlag(options::OPT_offloadlib, options::OPT_no_offloadlib,
|
|
true) ||
|
|
TT.getEnvironment() == llvm::Triple::LLVM)
|
|
return {};
|
|
|
|
AMDGPUToolChain::ParsedTargetIDType TargetID = getParsedTargetID(DriverArgs);
|
|
if (!TargetID.OptionalTargetID || TargetID.OptionalTargetID == "amdgcnspirv")
|
|
return {};
|
|
|
|
ArgStringList LibraryPaths;
|
|
|
|
// Find in --hip-device-lib-path and HIP_LIBRARY_PATH.
|
|
for (StringRef Path : RocmInstallation->getRocmDeviceLibPathArg())
|
|
LibraryPaths.push_back(DriverArgs.MakeArgStringRef(Path));
|
|
|
|
addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH");
|
|
|
|
// Maintain compatability with --hip-device-lib.
|
|
auto BCLibArgs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ);
|
|
if (!BCLibArgs.empty()) {
|
|
for (StringRef BCName : BCLibArgs) {
|
|
StringRef FullName;
|
|
bool Found = false;
|
|
for (StringRef LibraryPath : LibraryPaths) {
|
|
SmallString<128> Path(LibraryPath);
|
|
llvm::sys::path::append(Path, BCName);
|
|
FullName = Path;
|
|
if (llvm::sys::fs::exists(FullName)) {
|
|
BCLibs.emplace_back(FullName);
|
|
Found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!Found)
|
|
getDriver().Diag(diag::err_drv_no_such_file) << BCName;
|
|
}
|
|
} else {
|
|
if (!RocmInstallation->hasDeviceLibrary()) {
|
|
getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
|
|
return {};
|
|
}
|
|
|
|
// Add common device libraries like ocml etc.
|
|
for (auto N : getCommonDeviceLibNames(
|
|
DriverArgs, *TargetID.OptionalTargetID, *TargetID.OptionalGPUArch,
|
|
DeviceOffloadingKind))
|
|
BCLibs.emplace_back(N);
|
|
|
|
// Add instrument lib.
|
|
auto InstLib =
|
|
DriverArgs.getLastArgValue(options::OPT_gpu_instrument_lib_EQ);
|
|
if (InstLib.empty())
|
|
return BCLibs;
|
|
if (llvm::sys::fs::exists(InstLib))
|
|
BCLibs.emplace_back(InstLib);
|
|
else
|
|
getDriver().Diag(diag::err_drv_no_such_file) << InstLib;
|
|
}
|
|
|
|
return BCLibs;
|
|
}
|
|
|
|
void HIPAMDToolChain::checkTargetID(
|
|
const llvm::opt::ArgList &DriverArgs) const {
|
|
auto PTID = getParsedTargetID(DriverArgs);
|
|
if (PTID.OptionalTargetID && !PTID.OptionalGPUArch &&
|
|
PTID.OptionalTargetID != "amdgcnspirv")
|
|
getDriver().Diag(clang::diag::err_drv_bad_target_id)
|
|
<< *PTID.OptionalTargetID;
|
|
}
|
|
|
|
SPIRVAMDToolChain::SPIRVAMDToolChain(const Driver &D,
|
|
const llvm::Triple &Triple,
|
|
const ArgList &Args)
|
|
: ROCMToolChain(D, Triple, Args) {
|
|
getProgramPaths().push_back(getDriver().Dir);
|
|
}
|
|
|
|
Tool *SPIRVAMDToolChain::buildLinker() const {
|
|
assert(getTriple().getArch() == llvm::Triple::spirv64);
|
|
return new tools::AMDGCN::Linker(*this);
|
|
}
|