Path: blob/main/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPSPV.cpp
35268 views
//===--- HIPSPV.cpp - HIPSPV ToolChain Implementation -----------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "HIPSPV.h"9#include "CommonArgs.h"10#include "HIPUtility.h"11#include "clang/Driver/Compilation.h"12#include "clang/Driver/Driver.h"13#include "clang/Driver/DriverDiagnostic.h"14#include "clang/Driver/InputInfo.h"15#include "clang/Driver/Options.h"16#include "llvm/Support/FileSystem.h"17#include "llvm/Support/Path.h"1819using namespace clang::driver;20using namespace clang::driver::toolchains;21using namespace clang::driver::tools;22using namespace clang;23using namespace llvm::opt;2425// Convenience function for creating temporary file for both modes of26// isSaveTempsEnabled().27static const char *getTempFile(Compilation &C, StringRef Prefix,28StringRef Extension) {29if (C.getDriver().isSaveTempsEnabled()) {30return C.getArgs().MakeArgString(Prefix + "." + Extension);31}32auto TmpFile = C.getDriver().GetTemporaryPath(Prefix, Extension);33return C.addTempFile(C.getArgs().MakeArgString(TmpFile));34}3536// Locates HIP pass plugin.37static std::string findPassPlugin(const Driver &D,38const llvm::opt::ArgList &Args) {39StringRef Path = Args.getLastArgValue(options::OPT_hipspv_pass_plugin_EQ);40if (!Path.empty()) {41if (llvm::sys::fs::exists(Path))42return Path.str();43D.Diag(diag::err_drv_no_such_file) << Path;44}4546StringRef hipPath = Args.getLastArgValue(options::OPT_hip_path_EQ);47if (!hipPath.empty()) {48SmallString<128> PluginPath(hipPath);49llvm::sys::path::append(PluginPath, "lib", "libLLVMHipSpvPasses.so");50if (llvm::sys::fs::exists(PluginPath))51return PluginPath.str().str();52PluginPath.assign(hipPath);53llvm::sys::path::append(PluginPath, "lib", "llvm",54"libLLVMHipSpvPasses.so");55if (llvm::sys::fs::exists(PluginPath))56return PluginPath.str().str();57}5859return std::string();60}6162void HIPSPV::Linker::constructLinkAndEmitSpirvCommand(63Compilation &C, const JobAction &JA, const InputInfoList &Inputs,64const InputInfo &Output, const llvm::opt::ArgList &Args) const {6566assert(!Inputs.empty() && "Must have at least one input.");67std::string Name = std::string(llvm::sys::path::stem(Output.getFilename()));68const char *TempFile = getTempFile(C, Name + "-link", "bc");6970// Link LLVM bitcode.71ArgStringList LinkArgs{};72for (auto Input : Inputs)73LinkArgs.push_back(Input.getFilename());74LinkArgs.append({"-o", TempFile});75const char *LlvmLink =76Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));77C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),78LlvmLink, LinkArgs, Inputs, Output));7980// Post-link HIP lowering.8182// Run LLVM IR passes to lower/expand/emulate HIP code that does not translate83// to SPIR-V (E.g. dynamic shared memory).84auto PassPluginPath = findPassPlugin(C.getDriver(), Args);85if (!PassPluginPath.empty()) {86const char *PassPathCStr = C.getArgs().MakeArgString(PassPluginPath);87const char *OptOutput = getTempFile(C, Name + "-lower", "bc");88ArgStringList OptArgs{TempFile, "-load-pass-plugin",89PassPathCStr, "-passes=hip-post-link-passes",90"-o", OptOutput};91const char *Opt = Args.MakeArgString(getToolChain().GetProgramPath("opt"));92C.addCommand(std::make_unique<Command>(93JA, *this, ResponseFileSupport::None(), Opt, OptArgs, Inputs, Output));94TempFile = OptOutput;95}9697// Emit SPIR-V binary.9899llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.1",100"--spirv-ext=+all"};101InputInfo TrInput = InputInfo(types::TY_LLVM_BC, TempFile, "");102SPIRV::constructTranslateCommand(C, *this, JA, Output, TrInput, TrArgs);103}104105void HIPSPV::Linker::ConstructJob(Compilation &C, const JobAction &JA,106const InputInfo &Output,107const InputInfoList &Inputs,108const ArgList &Args,109const char *LinkingOutput) const {110if (Inputs.size() > 0 && Inputs[0].getType() == types::TY_Image &&111JA.getType() == types::TY_Object)112return HIP::constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs,113Args, JA, *this);114115if (JA.getType() == types::TY_HIP_FATBIN)116return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs,117Args, *this);118119constructLinkAndEmitSpirvCommand(C, JA, Inputs, Output, Args);120}121122HIPSPVToolChain::HIPSPVToolChain(const Driver &D, const llvm::Triple &Triple,123const ToolChain &HostTC, const ArgList &Args)124: ToolChain(D, Triple, Args), HostTC(HostTC) {125// Lookup binaries into the driver directory, this is used to126// discover the clang-offload-bundler executable.127getProgramPaths().push_back(getDriver().Dir);128}129130void HIPSPVToolChain::addClangTargetOptions(131const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,132Action::OffloadKind DeviceOffloadingKind) const {133HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);134135assert(DeviceOffloadingKind == Action::OFK_HIP &&136"Only HIP offloading kinds are supported for GPUs.");137138CC1Args.append(139{"-fcuda-is-device", "-fcuda-allow-variadic-functions",140// A crude workaround for llvm-spirv which does not handle the141// autovectorized code well (vector reductions, non-i{8,16,32,64} types).142// TODO: Allow autovectorization when SPIR-V backend arrives.143"-mllvm", "-vectorize-loops=false", "-mllvm", "-vectorize-slp=false"});144145// Default to "hidden" visibility, as object level linking will not be146// supported for the foreseeable future.147if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,148options::OPT_fvisibility_ms_compat))149CC1Args.append(150{"-fvisibility=hidden", "-fapply-global-visibility-to-externs"});151152llvm::for_each(getDeviceLibs(DriverArgs),153[&](const BitCodeLibraryInfo &BCFile) {154CC1Args.append({"-mlink-builtin-bitcode",155DriverArgs.MakeArgString(BCFile.Path)});156});157}158159Tool *HIPSPVToolChain::buildLinker() const {160assert(getTriple().getArch() == llvm::Triple::spirv64);161return new tools::HIPSPV::Linker(*this);162}163164void HIPSPVToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {165HostTC.addClangWarningOptions(CC1Args);166}167168ToolChain::CXXStdlibType169HIPSPVToolChain::GetCXXStdlibType(const ArgList &Args) const {170return HostTC.GetCXXStdlibType(Args);171}172173void HIPSPVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,174ArgStringList &CC1Args) const {175HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);176}177178void HIPSPVToolChain::AddClangCXXStdlibIncludeArgs(179const ArgList &Args, ArgStringList &CC1Args) const {180HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);181}182183void HIPSPVToolChain::AddIAMCUIncludeArgs(const ArgList &Args,184ArgStringList &CC1Args) const {185HostTC.AddIAMCUIncludeArgs(Args, CC1Args);186}187188void HIPSPVToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,189ArgStringList &CC1Args) const {190if (DriverArgs.hasArg(options::OPT_nogpuinc))191return;192193StringRef hipPath = DriverArgs.getLastArgValue(options::OPT_hip_path_EQ);194if (hipPath.empty()) {195getDriver().Diag(diag::err_drv_hipspv_no_hip_path);196return;197}198SmallString<128> P(hipPath);199llvm::sys::path::append(P, "include");200CC1Args.append({"-isystem", DriverArgs.MakeArgString(P)});201}202203llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>204HIPSPVToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {205llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> BCLibs;206if (DriverArgs.hasArg(options::OPT_nogpulib))207return {};208209ArgStringList LibraryPaths;210// Find device libraries in --hip-device-lib-path and HIP_DEVICE_LIB_PATH.211auto HipDeviceLibPathArgs = DriverArgs.getAllArgValues(212// --hip-device-lib-path is alias to this option.213clang::driver::options::OPT_rocm_device_lib_path_EQ);214for (auto Path : HipDeviceLibPathArgs)215LibraryPaths.push_back(DriverArgs.MakeArgString(Path));216217StringRef HipPath = DriverArgs.getLastArgValue(options::OPT_hip_path_EQ);218if (!HipPath.empty()) {219SmallString<128> Path(HipPath);220llvm::sys::path::append(Path, "lib", "hip-device-lib");221LibraryPaths.push_back(DriverArgs.MakeArgString(Path));222}223224addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH");225226// Maintain compatability with --hip-device-lib.227auto BCLibArgs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ);228if (!BCLibArgs.empty()) {229llvm::for_each(BCLibArgs, [&](StringRef BCName) {230StringRef FullName;231for (std::string LibraryPath : LibraryPaths) {232SmallString<128> Path(LibraryPath);233llvm::sys::path::append(Path, BCName);234FullName = Path;235if (llvm::sys::fs::exists(FullName)) {236BCLibs.emplace_back(FullName.str());237return;238}239}240getDriver().Diag(diag::err_drv_no_such_file) << BCName;241});242} else {243// Search device library named as 'hipspv-<triple>.bc'.244auto TT = getTriple().normalize();245std::string BCName = "hipspv-" + TT + ".bc";246for (auto *LibPath : LibraryPaths) {247SmallString<128> Path(LibPath);248llvm::sys::path::append(Path, BCName);249if (llvm::sys::fs::exists(Path)) {250BCLibs.emplace_back(Path.str().str());251return BCLibs;252}253}254getDriver().Diag(diag::err_drv_no_hipspv_device_lib)255<< 1 << ("'" + TT + "' target");256return {};257}258259return BCLibs;260}261262SanitizerMask HIPSPVToolChain::getSupportedSanitizers() const {263// The HIPSPVToolChain only supports sanitizers in the sense that it allows264// sanitizer arguments on the command line if they are supported by the host265// toolchain. The HIPSPVToolChain will actually ignore any command line266// arguments for any of these "supported" sanitizers. That means that no267// sanitization of device code is actually supported at this time.268//269// This behavior is necessary because the host and device toolchains270// invocations often share the command line, so the device toolchain must271// tolerate flags meant only for the host toolchain.272return HostTC.getSupportedSanitizers();273}274275VersionTuple HIPSPVToolChain::computeMSVCVersion(const Driver *D,276const ArgList &Args) const {277return HostTC.computeMSVCVersion(D, Args);278}279280void HIPSPVToolChain::adjustDebugInfoKind(281llvm::codegenoptions::DebugInfoKind &DebugInfoKind,282const llvm::opt::ArgList &Args) const {283// Debug info generation is disabled for SPIRV-LLVM-Translator284// which currently aborts on the presence of DW_OP_LLVM_convert.285// TODO: Enable debug info when the SPIR-V backend arrives.286DebugInfoKind = llvm::codegenoptions::NoDebugInfo;287}288289290