aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Driver/ToolChains/AMDGPU.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Driver/ToolChains/AMDGPU.cpp')
-rw-r--r--clang/lib/Driver/ToolChains/AMDGPU.cpp383
1 files changed, 311 insertions, 72 deletions
diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index 0971a2da62a3..d63c5e12c4af 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -8,13 +8,20 @@
#include "AMDGPU.h"
#include "CommonArgs.h"
-#include "InputInfo.h"
#include "clang/Basic/TargetID.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/InputInfo.h"
+#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/LineIterator.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include <system_error>
+
+#define AMDGPU_ARCH_PROGRAM_NAME "amdgpu-arch"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -22,6 +29,48 @@ using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
+// Look for sub-directory starts with PackageName under ROCm candidate path.
+// If there is one and only one matching sub-directory found, append the
+// sub-directory to Path. If there is no matching sub-directory or there are
+// more than one matching sub-directories, diagnose them. Returns the full
+// path of the package if there is only one matching sub-directory, otherwise
+// returns an empty string.
+llvm::SmallString<0>
+RocmInstallationDetector::findSPACKPackage(const Candidate &Cand,
+ StringRef PackageName) {
+ if (!Cand.isSPACK())
+ return {};
+ std::error_code EC;
+ std::string Prefix = Twine(PackageName + "-" + Cand.SPACKReleaseStr).str();
+ llvm::SmallVector<llvm::SmallString<0>> SubDirs;
+ for (llvm::vfs::directory_iterator File = D.getVFS().dir_begin(Cand.Path, EC),
+ FileEnd;
+ File != FileEnd && !EC; File.increment(EC)) {
+ llvm::StringRef FileName = llvm::sys::path::filename(File->path());
+ if (FileName.startswith(Prefix)) {
+ SubDirs.push_back(FileName);
+ if (SubDirs.size() > 1)
+ break;
+ }
+ }
+ if (SubDirs.size() == 1) {
+ auto PackagePath = Cand.Path;
+ llvm::sys::path::append(PackagePath, SubDirs[0]);
+ return PackagePath;
+ }
+ if (SubDirs.size() == 0 && Verbose) {
+ llvm::errs() << "SPACK package " << Prefix << " not found at " << Cand.Path
+ << '\n';
+ return {};
+ }
+
+ if (SubDirs.size() > 1 && Verbose) {
+ llvm::errs() << "Cannot use SPACK package " << Prefix << " at " << Cand.Path
+ << " due to multiple installations for the same version\n";
+ }
+ return {};
+}
+
void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
assert(!Path.empty());
@@ -50,6 +99,8 @@ void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {
OpenCL = FilePath;
} else if (BaseName == "hip") {
HIP = FilePath;
+ } else if (BaseName == "asanrtl") {
+ AsanRTL = FilePath;
} else if (BaseName == "oclc_finite_only_off") {
FiniteOnly.Off = FilePath;
} else if (BaseName == "oclc_finite_only_on") {
@@ -114,13 +165,37 @@ bool RocmInstallationDetector::parseHIPVersionFile(llvm::StringRef V) {
return false;
}
-// For candidate specified by --rocm-path we do not do strict check.
-SmallVector<RocmInstallationDetector::Candidate, 4>
+/// \returns a list of candidate directories for ROCm installation, which is
+/// cached and populated only once.
+const SmallVectorImpl<RocmInstallationDetector::Candidate> &
RocmInstallationDetector::getInstallationPathCandidates() {
- SmallVector<Candidate, 4> Candidates;
+
+ // Return the cached candidate list if it has already been populated.
+ if (!ROCmSearchDirs.empty())
+ return ROCmSearchDirs;
+
+ auto DoPrintROCmSearchDirs = [&]() {
+ if (PrintROCmSearchDirs)
+ for (auto Cand : ROCmSearchDirs) {
+ llvm::errs() << "ROCm installation search path";
+ if (Cand.isSPACK())
+ llvm::errs() << " (Spack " << Cand.SPACKReleaseStr << ")";
+ llvm::errs() << ": " << Cand.Path << '\n';
+ }
+ };
+
+ // For candidate specified by --rocm-path we do not do strict check, i.e.,
+ // checking existence of HIP version file and device library files.
if (!RocmPathArg.empty()) {
- Candidates.emplace_back(RocmPathArg.str());
- return Candidates;
+ ROCmSearchDirs.emplace_back(RocmPathArg.str());
+ DoPrintROCmSearchDirs();
+ return ROCmSearchDirs;
+ } else if (const char *RocmPathEnv = ::getenv("ROCM_PATH")) {
+ if (!StringRef(RocmPathEnv).empty()) {
+ ROCmSearchDirs.emplace_back(RocmPathEnv);
+ DoPrintROCmSearchDirs();
+ return ROCmSearchDirs;
+ }
}
// Try to find relative to the compiler binary.
@@ -129,41 +204,120 @@ RocmInstallationDetector::getInstallationPathCandidates() {
// Check both a normal Unix prefix position of the clang binary, as well as
// the Windows-esque layout the ROCm packages use with the host architecture
// subdirectory of bin.
+ auto DeduceROCmPath = [](StringRef ClangPath) {
+ // Strip off directory (usually bin)
+ StringRef ParentDir = llvm::sys::path::parent_path(ClangPath);
+ StringRef ParentName = llvm::sys::path::filename(ParentDir);
+
+ // Some builds use bin/{host arch}, so go up again.
+ if (ParentName == "bin") {
+ ParentDir = llvm::sys::path::parent_path(ParentDir);
+ ParentName = llvm::sys::path::filename(ParentDir);
+ }
- // Strip off directory (usually bin)
- StringRef ParentDir = llvm::sys::path::parent_path(InstallDir);
- StringRef ParentName = llvm::sys::path::filename(ParentDir);
+ // Detect ROCm packages built with SPACK.
+ // clang is installed at
+ // <rocm_root>/llvm-amdgpu-<rocm_release_string>-<hash>/bin directory.
+ // We only consider the parent directory of llvm-amdgpu package as ROCm
+ // installation candidate for SPACK.
+ if (ParentName.startswith("llvm-amdgpu-")) {
+ auto SPACKPostfix =
+ ParentName.drop_front(strlen("llvm-amdgpu-")).split('-');
+ auto SPACKReleaseStr = SPACKPostfix.first;
+ if (!SPACKReleaseStr.empty()) {
+ ParentDir = llvm::sys::path::parent_path(ParentDir);
+ return Candidate(ParentDir.str(), /*StrictChecking=*/true,
+ SPACKReleaseStr);
+ }
+ }
- // Some builds use bin/{host arch}, so go up again.
- if (ParentName == "bin") {
- ParentDir = llvm::sys::path::parent_path(ParentDir);
- ParentName = llvm::sys::path::filename(ParentDir);
+ // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin
+ // Some versions of the aomp package install to /opt/rocm/aomp/bin
+ if (ParentName == "llvm" || ParentName.startswith("aomp"))
+ ParentDir = llvm::sys::path::parent_path(ParentDir);
+
+ return Candidate(ParentDir.str(), /*StrictChecking=*/true);
+ };
+
+ // Deduce ROCm path by the path used to invoke clang. Do not resolve symbolic
+ // link of clang itself.
+ ROCmSearchDirs.emplace_back(DeduceROCmPath(InstallDir));
+
+ // Deduce ROCm path by the real path of the invoked clang, resolving symbolic
+ // link of clang itself.
+ llvm::SmallString<256> RealClangPath;
+ llvm::sys::fs::real_path(D.getClangProgramPath(), RealClangPath);
+ auto ParentPath = llvm::sys::path::parent_path(RealClangPath);
+ if (ParentPath != InstallDir)
+ ROCmSearchDirs.emplace_back(DeduceROCmPath(ParentPath));
+
+ // Device library may be installed in clang or resource directory.
+ auto ClangRoot = llvm::sys::path::parent_path(InstallDir);
+ auto RealClangRoot = llvm::sys::path::parent_path(ParentPath);
+ ROCmSearchDirs.emplace_back(ClangRoot.str(), /*StrictChecking=*/true);
+ if (RealClangRoot != ClangRoot)
+ ROCmSearchDirs.emplace_back(RealClangRoot.str(), /*StrictChecking=*/true);
+ ROCmSearchDirs.emplace_back(D.ResourceDir,
+ /*StrictChecking=*/true);
+
+ ROCmSearchDirs.emplace_back(D.SysRoot + "/opt/rocm",
+ /*StrictChecking=*/true);
+
+ // Find the latest /opt/rocm-{release} directory.
+ std::error_code EC;
+ std::string LatestROCm;
+ llvm::VersionTuple LatestVer;
+ // Get ROCm version from ROCm directory name.
+ auto GetROCmVersion = [](StringRef DirName) {
+ llvm::VersionTuple V;
+ std::string VerStr = DirName.drop_front(strlen("rocm-")).str();
+ // The ROCm directory name follows the format of
+ // rocm-{major}.{minor}.{subMinor}[-{build}]
+ std::replace(VerStr.begin(), VerStr.end(), '-', '.');
+ V.tryParse(VerStr);
+ return V;
+ };
+ for (llvm::vfs::directory_iterator
+ File = D.getVFS().dir_begin(D.SysRoot + "/opt", EC),
+ FileEnd;
+ File != FileEnd && !EC; File.increment(EC)) {
+ llvm::StringRef FileName = llvm::sys::path::filename(File->path());
+ if (!FileName.startswith("rocm-"))
+ continue;
+ if (LatestROCm.empty()) {
+ LatestROCm = FileName.str();
+ LatestVer = GetROCmVersion(LatestROCm);
+ continue;
+ }
+ auto Ver = GetROCmVersion(FileName);
+ if (LatestVer < Ver) {
+ LatestROCm = FileName.str();
+ LatestVer = Ver;
+ }
}
+ if (!LatestROCm.empty())
+ ROCmSearchDirs.emplace_back(D.SysRoot + "/opt/" + LatestROCm,
+ /*StrictChecking=*/true);
- // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin
- if (ParentName == "llvm")
- ParentDir = llvm::sys::path::parent_path(ParentDir);
-
- Candidates.emplace_back(ParentDir.str(), /*StrictChecking=*/true);
-
- // Device library may be installed in clang resource directory.
- Candidates.emplace_back(D.ResourceDir, /*StrictChecking=*/true);
-
- Candidates.emplace_back(D.SysRoot + "/opt/rocm", /*StrictChecking=*/true);
- return Candidates;
+ DoPrintROCmSearchDirs();
+ return ROCmSearchDirs;
}
RocmInstallationDetector::RocmInstallationDetector(
const Driver &D, const llvm::Triple &HostTriple,
const llvm::opt::ArgList &Args, bool DetectHIPRuntime, bool DetectDeviceLib)
: D(D) {
+ Verbose = Args.hasArg(options::OPT_v);
RocmPathArg = Args.getLastArgValue(clang::driver::options::OPT_rocm_path_EQ);
+ PrintROCmSearchDirs =
+ Args.hasArg(clang::driver::options::OPT_print_rocm_search_dirs);
RocmDeviceLibPathArg =
Args.getAllArgValues(clang::driver::options::OPT_rocm_device_lib_path_EQ);
+ HIPPathArg = Args.getLastArgValue(clang::driver::options::OPT_hip_path_EQ);
if (auto *A = Args.getLastArg(clang::driver::options::OPT_hip_version_EQ)) {
HIPVersionArg = A->getValue();
- unsigned Major = 0;
- unsigned Minor = 0;
+ unsigned Major = ~0U;
+ unsigned Minor = ~0U;
SmallVector<StringRef, 3> Parts;
HIPVersionArg.split(Parts, '.');
if (Parts.size())
@@ -174,7 +328,9 @@ RocmInstallationDetector::RocmInstallationDetector(
VersionPatch = Parts[2].str();
if (VersionPatch.empty())
VersionPatch = "0";
- if (Major == 0 || Minor == 0)
+ if (Major != ~0U && Minor == ~0U)
+ Minor = 0;
+ if (Major == ~0U || Minor == ~0U)
D.Diag(diag::err_drv_invalid_value)
<< A->getAsString(Args) << HIPVersionArg;
@@ -222,8 +378,8 @@ void RocmInstallationDetector::detectDeviceLibrary() {
// exist for each frontend project, and differ depending on which build
// system produced the packages. Standalone OpenCL builds also have a
// different directory structure from the ROCm OpenCL package.
- auto Candidates = getInstallationPathCandidates();
- for (const auto &Candidate : Candidates) {
+ auto &ROCmDirs = getInstallationPathCandidates();
+ for (const auto &Candidate : ROCmDirs) {
auto CandidatePath = Candidate.Path;
// Check device library exists at the given path.
@@ -276,13 +432,21 @@ void RocmInstallationDetector::detectDeviceLibrary() {
}
void RocmInstallationDetector::detectHIPRuntime() {
- auto Candidates = getInstallationPathCandidates();
+ SmallVector<Candidate, 4> HIPSearchDirs;
+ if (!HIPPathArg.empty())
+ HIPSearchDirs.emplace_back(HIPPathArg.str(), /*StrictChecking=*/true);
+ else
+ HIPSearchDirs.append(getInstallationPathCandidates());
auto &FS = D.getVFS();
- for (const auto &Candidate : Candidates) {
+ for (const auto &Candidate : HIPSearchDirs) {
InstallPath = Candidate.Path;
if (InstallPath.empty() || !FS.exists(InstallPath))
continue;
+ // HIP runtime built by SPACK is installed to
+ // <rocm_root>/hip-<rocm_release_string>-<hash> directory.
+ auto SPACKPath = findSPACKPackage(Candidate, "hip");
+ InstallPath = SPACKPath.empty() ? InstallPath : SPACKPath;
BinPath = InstallPath;
llvm::sys::path::append(BinPath, "bin");
@@ -413,7 +577,7 @@ AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
// and errors for the last invalid code object version options.
// It is done here to avoid repeated warning or error messages for
// each tool invocation.
- (void)getOrCheckAMDGPUCodeObjectVersion(D, Args, /*Diagnose=*/true);
+ checkAMDGPUCodeObjectVersion(D, Args);
}
Tool *AMDGPUToolChain::buildLinker() const {
@@ -488,8 +652,8 @@ llvm::DenormalMode AMDGPUToolChain::getDefaultDenormalModeForType(
auto Arch = getProcessorFromTargetID(getTriple(), JA.getOffloadingArch());
auto Kind = llvm::AMDGPU::parseArchAMDGCN(Arch);
if (FPType && FPType == &llvm::APFloat::IEEEsingle() &&
- DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero,
- options::OPT_fno_cuda_flush_denormals_to_zero,
+ DriverArgs.hasFlag(options::OPT_fgpu_flush_denormals_to_zero,
+ options::OPT_fno_gpu_flush_denormals_to_zero,
getDefaultDenormsAreZeroForTarget(Kind)))
return llvm::DenormalMode::getPreserveSign();
@@ -547,17 +711,99 @@ AMDGPUToolChain::getGPUArch(const llvm::opt::ArgList &DriverArgs) const {
getTriple(), DriverArgs.getLastArgValue(options::OPT_mcpu_EQ));
}
-void AMDGPUToolChain::checkTargetID(
- const llvm::opt::ArgList &DriverArgs) const {
+AMDGPUToolChain::ParsedTargetIDType
+AMDGPUToolChain::getParsedTargetID(const llvm::opt::ArgList &DriverArgs) const {
StringRef TargetID = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ);
if (TargetID.empty())
- return;
+ return {None, None, None};
llvm::StringMap<bool> FeatureMap;
auto OptionalGpuArch = parseTargetID(getTriple(), TargetID, &FeatureMap);
- if (!OptionalGpuArch) {
- getDriver().Diag(clang::diag::err_drv_bad_target_id) << TargetID;
+ if (!OptionalGpuArch)
+ return {TargetID.str(), None, None};
+
+ return {TargetID.str(), OptionalGpuArch.getValue().str(), FeatureMap};
+}
+
+void AMDGPUToolChain::checkTargetID(
+ const llvm::opt::ArgList &DriverArgs) const {
+ auto PTID = getParsedTargetID(DriverArgs);
+ if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) {
+ getDriver().Diag(clang::diag::err_drv_bad_target_id)
+ << PTID.OptionalTargetID.getValue();
+ }
+}
+
+llvm::Error
+AMDGPUToolChain::detectSystemGPUs(const ArgList &Args,
+ SmallVector<std::string, 1> &GPUArchs) const {
+ std::string Program;
+ if (Arg *A = Args.getLastArg(options::OPT_amdgpu_arch_tool_EQ))
+ Program = A->getValue();
+ else
+ Program = GetProgramPath(AMDGPU_ARCH_PROGRAM_NAME);
+ llvm::SmallString<64> OutputFile;
+ llvm::sys::fs::createTemporaryFile("print-system-gpus", "" /* No Suffix */,
+ OutputFile);
+ llvm::FileRemover OutputRemover(OutputFile.c_str());
+ llvm::Optional<llvm::StringRef> Redirects[] = {
+ {""},
+ OutputFile.str(),
+ {""},
+ };
+
+ std::string ErrorMessage;
+ if (int Result = llvm::sys::ExecuteAndWait(
+ Program.c_str(), {}, {}, Redirects, /* SecondsToWait */ 0,
+ /*MemoryLimit*/ 0, &ErrorMessage)) {
+ if (Result > 0) {
+ ErrorMessage = "Exited with error code " + std::to_string(Result);
+ } else if (Result == -1) {
+ ErrorMessage = "Execute failed: " + ErrorMessage;
+ } else {
+ ErrorMessage = "Crashed: " + ErrorMessage;
+ }
+
+ return llvm::createStringError(std::error_code(),
+ Program + ": " + ErrorMessage);
+ }
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf =
+ llvm::MemoryBuffer::getFile(OutputFile.c_str());
+ if (!OutputBuf) {
+ return llvm::createStringError(OutputBuf.getError(),
+ "Failed to read stdout of " + Program +
+ ": " + OutputBuf.getError().message());
+ }
+
+ for (llvm::line_iterator LineIt(**OutputBuf); !LineIt.is_at_end(); ++LineIt) {
+ GPUArchs.push_back(LineIt->str());
}
+ return llvm::Error::success();
+}
+
+llvm::Error AMDGPUToolChain::getSystemGPUArch(const ArgList &Args,
+ std::string &GPUArch) const {
+ // detect the AMDGPU installed in system
+ SmallVector<std::string, 1> GPUArchs;
+ auto Err = detectSystemGPUs(Args, GPUArchs);
+ if (Err) {
+ return Err;
+ }
+ if (GPUArchs.empty()) {
+ return llvm::createStringError(std::error_code(),
+ "No AMD GPU detected in the system");
+ }
+ GPUArch = GPUArchs[0];
+ if (GPUArchs.size() > 1) {
+ bool AllSame = std::all_of(
+ GPUArchs.begin(), GPUArchs.end(),
+ [&](const StringRef &GPUArch) { return GPUArch == GPUArchs.front(); });
+ if (!AllSame)
+ return llvm::createStringError(
+ std::error_code(), "Multiple AMD GPUs found with different archs");
+ }
+ return llvm::Error::success();
}
void ROCMToolChain::addClangTargetOptions(
@@ -605,47 +851,40 @@ void ROCMToolChain::addClangTargetOptions(
DriverArgs.hasArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt);
// Add the OpenCL specific bitcode library.
- CC1Args.push_back("-mlink-builtin-bitcode");
- CC1Args.push_back(DriverArgs.MakeArgString(RocmInstallation.getOpenCLPath()));
+ llvm::SmallVector<std::string, 12> BCLibs;
+ BCLibs.push_back(RocmInstallation.getOpenCLPath().str());
// Add the generic set of libraries.
- RocmInstallation.addCommonBitcodeLibCC1Args(
- DriverArgs, CC1Args, LibDeviceFile, Wave64, DAZ, FiniteOnly,
- UnsafeMathOpt, FastRelaxedMath, CorrectSqrt);
+ BCLibs.append(RocmInstallation.getCommonBitcodeLibs(
+ DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt,
+ FastRelaxedMath, CorrectSqrt));
+
+ llvm::for_each(BCLibs, [&](StringRef BCFile) {
+ CC1Args.push_back("-mlink-builtin-bitcode");
+ CC1Args.push_back(DriverArgs.MakeArgString(BCFile));
+ });
}
-void RocmInstallationDetector::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 {
- static const char LinkBitcodeFlag[] = "-mlink-builtin-bitcode";
-
- CC1Args.push_back(LinkBitcodeFlag);
- CC1Args.push_back(DriverArgs.MakeArgString(getOCMLPath()));
-
- CC1Args.push_back(LinkBitcodeFlag);
- CC1Args.push_back(DriverArgs.MakeArgString(getOCKLPath()));
-
- CC1Args.push_back(LinkBitcodeFlag);
- CC1Args.push_back(DriverArgs.MakeArgString(getDenormalsAreZeroPath(DAZ)));
-
- CC1Args.push_back(LinkBitcodeFlag);
- CC1Args.push_back(DriverArgs.MakeArgString(
- getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath)));
+llvm::SmallVector<std::string, 12>
+RocmInstallationDetector::getCommonBitcodeLibs(
+ const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile, bool Wave64,
+ bool DAZ, bool FiniteOnly, bool UnsafeMathOpt, bool FastRelaxedMath,
+ bool CorrectSqrt) const {
- CC1Args.push_back(LinkBitcodeFlag);
- CC1Args.push_back(DriverArgs.MakeArgString(
- getFiniteOnlyPath(FiniteOnly || FastRelaxedMath)));
+ llvm::SmallVector<std::string, 12> BCLibs;
- CC1Args.push_back(LinkBitcodeFlag);
- CC1Args.push_back(
- DriverArgs.MakeArgString(getCorrectlyRoundedSqrtPath(CorrectSqrt)));
+ auto AddBCLib = [&](StringRef BCFile) { BCLibs.push_back(BCFile.str()); };
- CC1Args.push_back(LinkBitcodeFlag);
- CC1Args.push_back(DriverArgs.MakeArgString(getWavefrontSize64Path(Wave64)));
+ AddBCLib(getOCMLPath());
+ AddBCLib(getOCKLPath());
+ AddBCLib(getDenormalsAreZeroPath(DAZ));
+ AddBCLib(getUnsafeMathPath(UnsafeMathOpt || FastRelaxedMath));
+ AddBCLib(getFiniteOnlyPath(FiniteOnly || FastRelaxedMath));
+ AddBCLib(getCorrectlyRoundedSqrtPath(CorrectSqrt));
+ AddBCLib(getWavefrontSize64Path(Wave64));
+ AddBCLib(LibDeviceFile);
- CC1Args.push_back(LinkBitcodeFlag);
- CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile));
+ return BCLibs;
}
bool AMDGPUToolChain::shouldSkipArgument(const llvm::opt::Arg *A) const {