clang 24.0.0git
HIPAMD.cpp
Go to the documentation of this file.
1//===--- HIPAMD.cpp - HIP Tool and ToolChain Implementations ----*- 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 "HIPAMD.h"
10#include "AMDGPU.h"
11#include "HIPUtility.h"
12#include "SPIRV.h"
13#include "clang/Basic/Cuda.h"
16#include "clang/Driver/Driver.h"
20#include "llvm/Support/FileSystem.h"
21#include "llvm/Support/Path.h"
22#include "llvm/TargetParser/TargetParser.h"
23
24using namespace clang::driver;
25using namespace clang::driver::toolchains;
26using namespace clang::driver::tools;
27using namespace clang;
28using namespace llvm::opt;
29
30#if defined(_WIN32) || defined(_WIN64)
31#define NULL_FILE "nul"
32#else
33#define NULL_FILE "/dev/null"
34#endif
35
36void AMDGCN::Linker::constructLLVMLinkCommand(
37 Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
38 const InputInfo &Output, const llvm::opt::ArgList &Args) const {
39
40 ArgStringList LinkerInputs;
41
42 for (auto Input : Inputs)
43 if (Input.isFilename())
44 LinkerInputs.push_back(Input.getFilename());
45
46 tools::constructLLVMLinkCommand(C, *this, JA, Inputs, LinkerInputs, Output,
47 Args);
48}
49
50void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
51 const InputInfoList &Inputs,
52 const InputInfo &Output,
53 const llvm::opt::ArgList &Args) const {
54 // Construct lld command.
55 // The output from ld.lld is an HSA code object file.
56 ArgStringList LldArgs{"-flavor",
57 "gnu",
58 "-m",
59 "elf64_amdgpu",
60 "--no-undefined",
61 "-shared",
62 "-plugin-opt=-amdgpu-internalize-symbols"};
63 if (Args.hasArg(options::OPT_hipstdpar))
64 LldArgs.push_back("-plugin-opt=-amdgpu-enable-hipstdpar");
65
66 auto &TC = getToolChain();
67 auto &D = TC.getDriver();
68 bool IsThinLTO = TC.getLTOMode(Args, Action::OFK_HIP) == LTOK_Thin;
69 addLTOOptions(TC, Args, LldArgs, Output, Inputs, IsThinLTO);
70
71 // Extract all the -m options
72 std::vector<llvm::StringRef> Features;
73 amdgpu::getAMDGPUTargetFeatures(D, TC.getEffectiveTriple(), Args, Features);
74
75 // Add features to mattr such as cumode
76 std::string MAttrString = "-plugin-opt=-mattr=";
77 for (auto OneFeature : unifyTargetFeatures(Features)) {
78 MAttrString.append(Args.MakeArgStringRef(OneFeature));
79 if (OneFeature != Features.back())
80 MAttrString.append(",");
81 }
82 if (!Features.empty())
83 LldArgs.push_back(Args.MakeArgString(MAttrString));
84
85 // ToDo: Remove this option after AMDGPU backend supports ISA-level linking.
86 // Since AMDGPU backend currently does not support ISA-level linking, all
87 // called functions need to be imported.
88 if (IsThinLTO) {
89 LldArgs.push_back("-plugin-opt=-force-import-all");
90 LldArgs.push_back("-plugin-opt=-avail-extern-to-local");
91 LldArgs.push_back("-plugin-opt=-avail-extern-gv-in-addrspace-to-local=3");
92 }
93
94 for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
95 LldArgs.push_back(
96 Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0)));
97 }
98
99 if (C.getDriver().isSaveTempsEnabled())
100 LldArgs.push_back("-save-temps");
101
102 addLinkerCompressDebugSectionsOption(TC, Args, LldArgs);
103
104 // Given that host and device linking happen in separate processes, the device
105 // linker doesn't always have the visibility as to which device symbols are
106 // needed by a program, especially for the device symbol dependencies that are
107 // introduced through the host symbol resolution.
108 // For example: host_A() (A.obj) --> host_B(B.obj) --> device_kernel_B()
109 // (B.obj) In this case, the device linker doesn't know that A.obj actually
110 // depends on the kernel functions in B.obj. When linking to static device
111 // library, the device linker may drop some of the device global symbols if
112 // they aren't referenced. As a workaround, we are adding to the
113 // --whole-archive flag such that all global symbols would be linked in.
114 LldArgs.push_back("--whole-archive");
115
116 for (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) {
117 StringRef ArgVal = Arg->getValue(1);
118 auto SplitArg = ArgVal.split("-mllvm=");
119 if (!SplitArg.second.empty()) {
120 LldArgs.push_back(
121 Args.MakeArgString(Twine("-plugin-opt=") + SplitArg.second));
122 } else {
123 LldArgs.push_back(Args.MakeArgStringRef(ArgVal));
124 }
125 Arg->claim();
126 }
127
128 LldArgs.append({"-o", Output.getFilename()});
129 for (auto Input : Inputs)
130 LldArgs.push_back(Input.getFilename());
131 TC.addProfileRTLibs(Args, LldArgs);
132
133 LldArgs.push_back("--no-whole-archive");
134
135 const char *Lld = Args.MakeArgStringRef(getToolChain().GetProgramPath("lld"));
136 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
137 Lld, LldArgs, Inputs, Output));
138}
139
140// For SPIR-V the inputs for the job are device AMDGCN SPIR-V flavoured bitcode
141// and the output is either a compiled SPIR-V binary or bitcode (-emit-llvm). It
142// calls llvm-link and then the llvm-spirv translator or the SPIR-V BE.
143// TODO: consider if we want to run any targeted optimisations over IR here,
144// over generic SPIR-V.
145void AMDGCN::Linker::constructLinkAndEmitSpirvCommand(
146 Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
147 const InputInfo &Output, const llvm::opt::ArgList &Args) const {
148 assert(!Inputs.empty() && "Must have at least one input.");
149
150 std::string LinkedBCFilePrefix(
151 Twine(llvm::sys::path::stem(Output.getFilename()), "-linked").str());
152 const char *LinkedBCFilePath = HIP::getTempFile(C, LinkedBCFilePrefix, "bc");
153 InputInfo LinkedBCFile(&JA, LinkedBCFilePath, Output.getBaseInput());
154
155 bool UseSPIRVBackend = Args.hasFlag(options::OPT_use_spirv_backend,
156 options::OPT_no_use_spirv_backend,
157 /*Default=*/true);
158
159 constructLLVMLinkCommand(C, JA, Inputs, LinkedBCFile, Args);
160
161 if (UseSPIRVBackend) {
162 // This code handles the case when --offload-device-only is unset and
163 // clang-linker-wrapper forwards the bitcode that must be compiled to
164 // SPIR-V.
165
166 llvm::opt::ArgStringList CmdArgs;
167
168 CmdArgs.append({"-cc1", "-triple=spirv64-amd-amdhsa", "-emit-obj",
169 "-disable-llvm-optzns", "-mllvm", "-spirv-preserve-auxdata",
170 LinkedBCFile.getFilename(), "-o", Output.getFilename()});
171
172 const Driver &Driver = getToolChain().getDriver();
173 const char *Exec = Driver.getDriverProgramPath();
174 C.addCommand(std::make_unique<Command>(
175 JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, LinkedBCFile,
176 Output, Driver.getPrependArg()));
177 } else {
178 // Emit SPIR-V binary using the translator
179 llvm::opt::ArgStringList TrArgs{
180 "--spirv-max-version=1.6",
181 "--spirv-ext=+all",
182 "--spirv-allow-unknown-intrinsics",
183 "--spirv-lower-const-expr",
184 "--spirv-preserve-auxdata",
185 "--spirv-debug-info-version=nonsemantic-shader-200"};
186 SPIRV::constructTranslateCommand(C, *this, JA, Output, LinkedBCFile,
187 TrArgs);
188 }
189}
190
191// For amdgcn the inputs of the linker job are device bitcode and output is
192// either an object file or bitcode (-emit-llvm). It calls llvm-link, opt,
193// llc, then lld steps.
195 const InputInfo &Output,
196 const InputInfoList &Inputs,
197 const ArgList &Args,
198 const char *LinkingOutput) const {
199 if (JA.getType() == types::TY_HIP_FATBIN)
200 return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs,
201 Args, *this);
202
203 if (JA.getType() == types::TY_LLVM_BC)
204 return constructLLVMLinkCommand(C, JA, Inputs, Output, Args);
205
206 if (getToolChain().getEffectiveTriple().isSPIRV())
207 return constructLinkAndEmitSpirvCommand(C, JA, Inputs, Output, Args);
208
209 return constructLldCommand(C, JA, Inputs, Output, Args);
210}
211
213 const llvm::Triple &Triple,
214 const llvm::opt::ArgList &Args)
215 : AMDGPUToolChain(D, Triple, Args) {}
216
218 return new tools::AMDGCN::Linker(*this);
219}
types::ID getType() const
Definition Action.h:153
Compilation - A set of tasks to perform for a single driver invocation.
Definition Compilation.h:46
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition Driver.h:93
InputInfo - Wrapper for information about an input source.
Definition InputInfo.h:22
const char * getBaseInput() const
Definition InputInfo.h:78
const char * getFilename() const
Definition InputInfo.h:83
Tool - Information on a specific compilation tool.
Definition Tool.h:32
const ToolChain & getToolChain() const
Definition Tool.h:52
AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, const ToolChain *HostTC=nullptr, Action::OffloadKind Kind=Action::OFK_None, bool ShouldLinkDeviceLibs=false)
AMDGPU Toolchain.
Definition AMDGPU.cpp:724
SPIRVAMDToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
Definition HIPAMD.cpp:212
void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override
ConstructJob - Construct jobs to perform the action JA, writing to Output and with Inputs,...
Definition HIPAMD.cpp:194
void constructHIPFatbinCommand(Compilation &C, const JobAction &JA, StringRef OutputFileName, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const Tool &T)
const char * getTempFile(Compilation &C, StringRef Prefix, StringRef Extension)
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
void getAMDGPUTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector< StringRef > &Features, bool ForAS=false)
Definition AMDGPU.cpp:690
SmallVector< StringRef > unifyTargetFeatures(ArrayRef< StringRef > Features)
If there are multiple +xxx or -xxx features, keep the last one.
void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, const InputInfoList &Inputs, bool IsThinLTO)
void addLinkerCompressDebugSectionsOption(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs)
void constructLLVMLinkCommand(Compilation &C, const Tool &T, const JobAction &JA, const InputInfoList &JobInputs, const llvm::opt::ArgStringList &LinkerInputs, const InputInfo &Output, const llvm::opt::ArgList &Args, const char *OutputFilename=nullptr)
SmallVector< InputInfo, 4 > InputInfoList
Definition Driver.h:49
Top level wrappers for InstallAPI frontend operations.
bool(*)(llvm::ArrayRef< const char * >, llvm::raw_ostream &, llvm::raw_ostream &, bool, bool) Driver
Definition Wasm.cpp:36
static constexpr ResponseFileSupport None()
Returns a ResponseFileSupport indicating that response files are not supported.
Definition Job.h:79