clang  15.0.0git
HIPSPV.cpp
Go to the documentation of this file.
1 //===--- HIPSPV.cpp - HIPSPV ToolChain Implementation -----------*- 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 "HIPSPV.h"
10 #include "CommonArgs.h"
11 #include "HIPUtility.h"
13 #include "clang/Driver/Driver.h"
15 #include "clang/Driver/InputInfo.h"
16 #include "clang/Driver/Options.h"
17 #include "llvm/Support/FileSystem.h"
18 #include "llvm/Support/Path.h"
19 
20 using namespace clang::driver;
21 using namespace clang::driver::toolchains;
22 using namespace clang::driver::tools;
23 using namespace clang;
24 using namespace llvm::opt;
25 
26 // Convenience function for creating temporary file for both modes of
27 // isSaveTempsEnabled().
28 static const char *getTempFile(Compilation &C, StringRef Prefix,
29  StringRef Extension) {
30  if (C.getDriver().isSaveTempsEnabled()) {
31  return C.getArgs().MakeArgString(Prefix + "." + Extension);
32  }
33  auto TmpFile = C.getDriver().GetTemporaryPath(Prefix, Extension);
34  return C.addTempFile(C.getArgs().MakeArgString(TmpFile));
35 }
36 
37 // Locates HIP pass plugin.
39  const llvm::opt::ArgList &Args) {
40  StringRef Path = Args.getLastArgValue(options::OPT_hipspv_pass_plugin_EQ);
41  if (!Path.empty()) {
42  if (llvm::sys::fs::exists(Path))
43  return Path.str();
44  D.Diag(diag::err_drv_no_such_file) << Path;
45  }
46 
47  StringRef hipPath = Args.getLastArgValue(options::OPT_hip_path_EQ);
48  if (!hipPath.empty()) {
49  SmallString<128> PluginPath(hipPath);
50  llvm::sys::path::append(PluginPath, "lib", "libLLVMHipSpvPasses.so");
51  if (llvm::sys::fs::exists(PluginPath))
52  return PluginPath.str().str();
53  PluginPath.assign(hipPath);
54  llvm::sys::path::append(PluginPath, "lib", "llvm",
55  "libLLVMHipSpvPasses.so");
56  if (llvm::sys::fs::exists(PluginPath))
57  return PluginPath.str().str();
58  }
59 
60  return std::string();
61 }
62 
63 void HIPSPV::Linker::constructLinkAndEmitSpirvCommand(
64  Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
65  const InputInfo &Output, const llvm::opt::ArgList &Args) const {
66 
67  assert(!Inputs.empty() && "Must have at least one input.");
68  std::string Name = std::string(llvm::sys::path::stem(Output.getFilename()));
69  const char *TempFile = getTempFile(C, Name + "-link", "bc");
70 
71  // Link LLVM bitcode.
72  ArgStringList LinkArgs{};
73  for (auto Input : Inputs)
74  LinkArgs.push_back(Input.getFilename());
75  LinkArgs.append({"-o", TempFile});
76  const char *LlvmLink =
77  Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));
78  C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
79  LlvmLink, LinkArgs, Inputs, Output));
80 
81  // Post-link HIP lowering.
82 
83  // Run LLVM IR passes to lower/expand/emulate HIP code that does not translate
84  // to SPIR-V (E.g. dynamic shared memory).
85  auto PassPluginPath = findPassPlugin(C.getDriver(), Args);
86  if (!PassPluginPath.empty()) {
87  const char *PassPathCStr = C.getArgs().MakeArgString(PassPluginPath);
88  const char *OptOutput = getTempFile(C, Name + "-lower", "bc");
89  ArgStringList OptArgs{TempFile, "-load-pass-plugin",
90  PassPathCStr, "-passes=hip-post-link-passes",
91  "-o", OptOutput};
92  const char *Opt = Args.MakeArgString(getToolChain().GetProgramPath("opt"));
93  C.addCommand(std::make_unique<Command>(
94  JA, *this, ResponseFileSupport::None(), Opt, OptArgs, Inputs, Output));
95  TempFile = OptOutput;
96  }
97 
98  // Emit SPIR-V binary.
99 
100  llvm::opt::ArgStringList TrArgs{"--spirv-max-version=1.1",
101  "--spirv-ext=+all"};
102  InputInfo TrInput = InputInfo(types::TY_LLVM_BC, TempFile, "");
103  SPIRV::constructTranslateCommand(C, *this, JA, Output, TrInput, TrArgs);
104 }
105 
106 void HIPSPV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
107  const InputInfo &Output,
108  const InputInfoList &Inputs,
109  const ArgList &Args,
110  const char *LinkingOutput) const {
111  if (Inputs.size() > 0 && Inputs[0].getType() == types::TY_Image &&
112  JA.getType() == types::TY_Object)
113  return HIP::constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs,
114  Args, JA, *this);
115 
116  if (JA.getType() == types::TY_HIP_FATBIN)
117  return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs,
118  Args, *this);
119 
120  constructLinkAndEmitSpirvCommand(C, JA, Inputs, Output, Args);
121 }
122 
123 HIPSPVToolChain::HIPSPVToolChain(const Driver &D, const llvm::Triple &Triple,
124  const ToolChain &HostTC, const ArgList &Args)
125  : ToolChain(D, Triple, Args), HostTC(HostTC) {
126  // Lookup binaries into the driver directory, this is used to
127  // discover the clang-offload-bundler executable.
128  getProgramPaths().push_back(getDriver().Dir);
129 }
130 
132  const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
133  Action::OffloadKind DeviceOffloadingKind) const {
134  HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
135 
136  assert(DeviceOffloadingKind == Action::OFK_HIP &&
137  "Only HIP offloading kinds are supported for GPUs.");
138 
139  CC1Args.append(
140  {"-fcuda-is-device", "-fcuda-allow-variadic-functions",
141  // A crude workaround for llvm-spirv which does not handle the
142  // autovectorized code well (vector reductions, non-i{8,16,32,64} types).
143  // TODO: Allow autovectorization when SPIR-V backend arrives.
144  "-mllvm", "-vectorize-loops=false", "-mllvm", "-vectorize-slp=false"});
145 
146  if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
147  options::OPT_fno_cuda_approx_transcendentals, false))
148  CC1Args.push_back("-fcuda-approx-transcendentals");
149 
150  // Default to "hidden" visibility, as object level linking will not be
151  // supported for the foreseeable future.
152  if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
153  options::OPT_fvisibility_ms_compat))
154  CC1Args.append(
155  {"-fvisibility", "hidden", "-fapply-global-visibility-to-externs"});
156 
157  llvm::for_each(getHIPDeviceLibs(DriverArgs),
158  [&](const BitCodeLibraryInfo &BCFile) {
159  CC1Args.append({"-mlink-builtin-bitcode",
160  DriverArgs.MakeArgString(BCFile.Path)});
161  });
162 }
163 
165  assert(getTriple().getArch() == llvm::Triple::spirv64);
166  return new tools::HIPSPV::Linker(*this);
167 }
168 
169 void HIPSPVToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
171 }
172 
174 HIPSPVToolChain::GetCXXStdlibType(const ArgList &Args) const {
175  return HostTC.GetCXXStdlibType(Args);
176 }
177 
178 void HIPSPVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
179  ArgStringList &CC1Args) const {
180  HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
181 }
182 
184  const ArgList &Args, ArgStringList &CC1Args) const {
185  HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
186 }
187 
188 void HIPSPVToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
189  ArgStringList &CC1Args) const {
190  HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
191 }
192 
193 void HIPSPVToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
194  ArgStringList &CC1Args) const {
195  if (DriverArgs.hasArg(options::OPT_nogpuinc))
196  return;
197 
198  StringRef hipPath = DriverArgs.getLastArgValue(options::OPT_hip_path_EQ);
199  if (hipPath.empty()) {
200  getDriver().Diag(diag::err_drv_hipspv_no_hip_path) << 1 << "'-nogpuinc'";
201  return;
202  }
203  SmallString<128> P(hipPath);
204  llvm::sys::path::append(P, "include");
205  CC1Args.append({"-isystem", DriverArgs.MakeArgString(P)});
206 }
207 
209 HIPSPVToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
211  if (DriverArgs.hasArg(options::OPT_nogpulib))
212  return {};
213 
214  ArgStringList LibraryPaths;
215  // Find device libraries in --hip-device-lib-path and HIP_DEVICE_LIB_PATH.
216  auto HipDeviceLibPathArgs = DriverArgs.getAllArgValues(
217  // --hip-device-lib-path is alias to this option.
218  clang::driver::options::OPT_rocm_device_lib_path_EQ);
219  for (auto Path : HipDeviceLibPathArgs)
220  LibraryPaths.push_back(DriverArgs.MakeArgString(Path));
221 
222  StringRef HipPath = DriverArgs.getLastArgValue(options::OPT_hip_path_EQ);
223  if (!HipPath.empty()) {
224  SmallString<128> Path(HipPath);
225  llvm::sys::path::append(Path, "lib", "hip-device-lib");
226  LibraryPaths.push_back(DriverArgs.MakeArgString(Path));
227  }
228 
229  addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH");
230 
231  // Maintain compatability with --hip-device-lib.
232  auto BCLibArgs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ);
233  if (!BCLibArgs.empty()) {
234  llvm::for_each(BCLibArgs, [&](StringRef BCName) {
235  StringRef FullName;
236  for (std::string LibraryPath : LibraryPaths) {
237  SmallString<128> Path(LibraryPath);
238  llvm::sys::path::append(Path, BCName);
239  FullName = Path;
240  if (llvm::sys::fs::exists(FullName)) {
241  BCLibs.emplace_back(FullName.str());
242  return;
243  }
244  }
245  getDriver().Diag(diag::err_drv_no_such_file) << BCName;
246  });
247  } else {
248  // Search device library named as 'hipspv-<triple>.bc'.
249  auto TT = getTriple().normalize();
250  std::string BCName = "hipspv-" + TT + ".bc";
251  for (auto *LibPath : LibraryPaths) {
252  SmallString<128> Path(LibPath);
253  llvm::sys::path::append(Path, BCName);
254  if (llvm::sys::fs::exists(Path)) {
255  BCLibs.emplace_back(Path.str().str());
256  return BCLibs;
257  }
258  }
259  getDriver().Diag(diag::err_drv_no_hipspv_device_lib)
260  << 1 << ("'" + TT + "' target");
261  return {};
262  }
263 
264  return BCLibs;
265 }
266 
268  // The HIPSPVToolChain only supports sanitizers in the sense that it allows
269  // sanitizer arguments on the command line if they are supported by the host
270  // toolchain. The HIPSPVToolChain will actually ignore any command line
271  // arguments for any of these "supported" sanitizers. That means that no
272  // sanitization of device code is actually supported at this time.
273  //
274  // This behavior is necessary because the host and device toolchains
275  // invocations often share the command line, so the device toolchain must
276  // tolerate flags meant only for the host toolchain.
278 }
279 
281  const ArgList &Args) const {
282  return HostTC.computeMSVCVersion(D, Args);
283 }
284 
287  const llvm::opt::ArgList &Args) const {
288  // Debug info generation is disabled for SPIRV-LLVM-Translator
289  // which currently aborts on the presence of DW_OP_LLVM_convert.
290  // TODO: Enable debug info when the SPIR-V backend arrives.
292 }
clang::driver::toolchains::HIPSPVToolChain::getHIPDeviceLibs
llvm::SmallVector< BitCodeLibraryInfo, 12 > getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override
Get paths of HIP device libraries.
Definition: HIPSPV.cpp:209
clang::driver::toolchains
Definition: AIX.h:55
clang::driver::toolchains::HIPSPVToolChain::AddHIPIncludeArgs
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
Add arguments to use system-specific HIP includes.
Definition: HIPSPV.cpp:193
clang::driver::tools::HIP::constructHIPFatbinCommand
void constructHIPFatbinCommand(Compilation &C, const JobAction &JA, StringRef OutputFileName, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const Tool &T)
clang::driver::ToolChain::getProgramPaths
path_list & getProgramPaths()
Definition: ToolChain.h:266
Driver.h
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::driver::ToolChain::computeMSVCVersion
virtual VersionTuple computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const
On Windows, returns the MSVC compatibility version.
Definition: ToolChain.cpp:1084
llvm::SmallVector
Definition: LLVM.h:38
clang::driver::ToolChain::AddClangCXXStdlibIncludeArgs
virtual void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const
AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set the include paths to use for...
Definition: ToolChain.cpp:940
clang::driver::tools
Definition: AIX.h:17
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:55
clang::driver::ToolChain::getDriver
const Driver & getDriver() const
Definition: ToolChain.h:225
clang::driver::Action::OFK_HIP
@ OFK_HIP
Definition: Action.h:97
clang::codegenoptions::NoDebugInfo
@ NoDebugInfo
Don't generate debug info.
Definition: DebugInfoOptions.h:22
clang::driver::ToolChain::BitCodeLibraryInfo
Definition: ToolChain.h:116
clang::driver::ToolChain::addClangWarningOptions
virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const
Add warning options that need to be passed to cc1 for this target.
Definition: ToolChain.cpp:780
clang::driver::InputInfo
InputInfo - Wrapper for information about an input source.
Definition: InputInfo.h:22
clang::driver::tools::SPIRV::constructTranslateCommand
void constructTranslateCommand(Compilation &C, const Tool &T, const JobAction &JA, const InputInfo &Output, const InputInfo &Input, const llvm::opt::ArgStringList &Args)
Definition: SPIRV.cpp:20
InputInfo.h
clang::driver::toolchains::HIPSPVToolChain::AddIAMCUIncludeArgs
void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
Add arguments to use MCU GCC toolchain includes.
Definition: HIPSPV.cpp:188
HIPSPV.h
clang::driver::Driver::Diag
DiagnosticBuilder Diag(unsigned DiagID) const
Definition: Driver.h:132
clang::driver::Tool
Tool - Information on a specific compilation tool.
Definition: Tool.h:32
Options.h
clang::driver::Action::getType
types::ID getType() const
Definition: Action.h:149
clang::driver::tools::HIP::constructGenerateObjFileFromHIPFatBinary
void constructGenerateObjFileFromHIPFatBinary(Compilation &C, const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &Args, const JobAction &JA, const Tool &T)
llvm::opt
Definition: DiagnosticOptions.h:19
DriverDiagnostic.h
clang::driver::ToolChain::AddClangSystemIncludeArgs
virtual void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const
Add the clang cc1 arguments for system include paths.
Definition: ToolChain.cpp:771
clang::driver::toolchains::HIPSPVToolChain::AddClangCXXStdlibIncludeArgs
void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args) const override
AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set the include paths to use for...
Definition: HIPSPV.cpp:183
clang::driver::ToolChain::CXXStdlibType
CXXStdlibType
Definition: ToolChain.h:95
clang::driver::toolchains::HIPSPVToolChain::AddClangSystemIncludeArgs
void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
Add the clang cc1 arguments for system include paths.
Definition: HIPSPV.cpp:178
llvm::SmallString< 128 >
clang::driver::ToolChain::getTriple
const llvm::Triple & getTriple() const
Definition: ToolChain.h:227
findPassPlugin
static std::string findPassPlugin(const Driver &D, const llvm::opt::ArgList &Args)
Definition: HIPSPV.cpp:38
clang::driver::ToolChain::getArch
llvm::Triple::ArchType getArch() const
Definition: ToolChain.h:241
clang::driver::toolchains::HIPSPVToolChain::adjustDebugInfoKind
void adjustDebugInfoKind(codegenoptions::DebugInfoKind &DebugInfoKind, const llvm::opt::ArgList &Args) const override
Adjust debug information kind considering all passed options.
Definition: HIPSPV.cpp:285
clang::driver::toolchains::HIPSPVToolChain::buildLinker
Tool * buildLinker() const override
Definition: HIPSPV.cpp:164
P
StringRef P
Definition: ASTMatchersInternal.cpp:563
clang::driver::ToolChain::BitCodeLibraryInfo::Path
std::string Path
Definition: ToolChain.h:117
clang::driver::ToolChain::getSupportedSanitizers
virtual SanitizerMask getSupportedSanitizers() const
Return sanitizers which are available in this toolchain.
Definition: ToolChain.cpp:1031
Compilation.h
clang::driver::tools::HIPSPV::Linker
Definition: HIPSPV.h:23
clang::driver::ToolChain
ToolChain - Access to tools for a single platform.
Definition: ToolChain.h:91
clang::driver::toolchains::HIPSPVToolChain::getSupportedSanitizers
SanitizerMask getSupportedSanitizers() const override
Return sanitizers which are available in this toolchain.
Definition: HIPSPV.cpp:267
clang::driver::toolchains::HIPSPVToolChain::HostTC
const ToolChain & HostTC
Definition: HIPSPV.h:93
clang::driver::toolchains::HIPSPVToolChain::GetCXXStdlibType
CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override
Definition: HIPSPV.cpp:174
clang::driver::toolchains::HIPSPVToolChain::addClangTargetOptions
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override
Add options that need to be passed to cc1 for this target.
Definition: HIPSPV.cpp:131
clang::driver::Compilation
Compilation - A set of tasks to perform for a single driver invocation.
Definition: Compilation.h:45
clang::driver::ToolChain::GetCXXStdlibType
virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const
Definition: ToolChain.cpp:852
clang::driver::ToolChain::AddIAMCUIncludeArgs
virtual void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const
Add arguments to use MCU GCC toolchain includes.
Definition: ToolChain.cpp:1067
clang::driver::InputInfo::getFilename
const char * getFilename() const
Definition: InputInfo.h:83
CommonArgs.h
clang
Definition: CalledOnceCheck.h:17
clang::driver::Driver
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:71
HIPUtility.h
clang::codegenoptions::DebugInfoKind
DebugInfoKind
Definition: DebugInfoOptions.h:20
clang::driver::tools::addDirectoryList
void addDirectoryList(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const char *ArgName, const char *EnvVar)
EnvVar is split by system delimiter for environment variables.
getTempFile
static const char * getTempFile(Compilation &C, StringRef Prefix, StringRef Extension)
Definition: HIPSPV.cpp:28
clang::driver::toolchains::HIPSPVToolChain::computeMSVCVersion
VersionTuple computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override
On Windows, returns the MSVC compatibility version.
Definition: HIPSPV.cpp:280
clang::driver::ToolChain::addClangTargetOptions
virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const
Add options that need to be passed to cc1 for this target.
Definition: ToolChain.cpp:776
clang::driver::Action::OffloadKind
OffloadKind
Definition: Action.h:88
clang::driver
Definition: Action.h:31
clang::driver::ResponseFileSupport::None
static constexpr ResponseFileSupport None()
Returns a ResponseFileSupport indicating that response files are not supported.
Definition: Job.h:78
clang::driver::toolchains::HIPSPVToolChain::addClangWarningOptions
void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override
Add warning options that need to be passed to cc1 for this target.
Definition: HIPSPV.cpp:169
clang::driver::JobAction
Definition: Action.h:395
clang::SanitizerMask
Definition: Sanitizers.h:30
clang::driver::toolchains::HIPSPVToolChain::HIPSPVToolChain
HIPSPVToolChain(const Driver &D, const llvm::Triple &Triple, const ToolChain &HostTC, const llvm::opt::ArgList &Args)
Definition: HIPSPV.cpp:123