14#include "llvm/ADT/StringExtras.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/Object/Archive.h"
17#include "llvm/Object/ObjectFile.h"
18#include "llvm/Support/MD5.h"
19#include "llvm/Support/MemoryBuffer.h"
20#include "llvm/Support/Path.h"
21#include "llvm/Support/raw_ostream.h"
22#include "llvm/TargetParser/Triple.h"
32#if defined(_WIN32) || defined(_WIN64)
33#define NULL_FILE "nul"
35#define NULL_FILE "/dev/null"
39const unsigned HIPCodeObjectAlign = 4096;
45 return HasTargetID ? (
T.getArchName() +
"-" +
T.getVendorName() +
"-" +
46 T.getOSName() +
"-" +
T.getEnvironmentName())
56 : C(C), DiagID(C.getDriver().getDiags().getCustomDiagID(
58 "Error collecting HIP undefined fatbin symbols: %0")),
59 Quiet(C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)),
60 Verbose(C.getArgs().hasArg(options::OPT_v)) {
63 for (
auto Name : FatBinSymbols)
64 llvm::errs() <<
"Found undefined HIP fatbin symbol: " << Name <<
"\n";
65 for (
auto Name : GPUBinHandleSymbols)
66 llvm::errs() <<
"Found undefined HIP gpubin handle symbol: " << Name
76 return GPUBinHandleSymbols;
84 std::set<std::string> FatBinSymbols;
85 std::set<std::string> GPUBinHandleSymbols;
86 std::set<std::string> DefinedFatBinSymbols;
87 std::set<std::string> DefinedGPUBinHandleSymbols;
88 const std::string FatBinPrefix =
"__hip_fatbin";
89 const std::string GPUBinHandlePrefix =
"__hip_gpubin_handle";
91 void populateSymbols() {
92 std::deque<const Action *> WorkList;
93 std::set<const Action *>
Visited;
95 for (
const auto &
Action : C.getActions())
96 WorkList.push_back(
Action);
98 while (!WorkList.empty()) {
99 const Action *CurrentAction = WorkList.front();
100 WorkList.pop_front();
102 if (!CurrentAction || !
Visited.insert(CurrentAction).second)
105 if (
const auto *IA = dyn_cast<InputAction>(CurrentAction)) {
106 std::string ID = IA->getId().str();
108 ID = llvm::utohexstr(llvm::MD5Hash(ID),
true);
109 FatBinSymbols.insert(Twine(FatBinPrefix +
"_" + ID).str());
110 GPUBinHandleSymbols.insert(
111 Twine(GPUBinHandlePrefix +
"_" + ID).str());
114 if (IA->getInputArg().getNumValues() == 0)
116 const char *
Filename = IA->getInputArg().getValue();
119 auto BufferOrErr = llvm::MemoryBuffer::getFile(
Filename);
126 processInput(BufferOrErr.get()->getMemBufferRef());
128 WorkList.insert(WorkList.end(), CurrentAction->
getInputs().begin(),
133 void processInput(
const llvm::MemoryBufferRef &Buffer) {
135 auto ObjFileOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
137 processSymbols(**ObjFileOrErr);
142 llvm::consumeError(ObjFileOrErr.takeError());
143 auto ArchiveOrErr = llvm::object::Archive::create(Buffer);
145 llvm::Error Err = llvm::Error::success();
146 llvm::object::Archive &Archive = *ArchiveOrErr.get();
147 for (
auto &Child : Archive.children(Err)) {
148 auto ChildBufOrErr = Child.getMemoryBufferRef();
150 processInput(*ChildBufOrErr);
152 errorHandler(ChildBufOrErr.takeError());
156 errorHandler(std::move(Err));
161 llvm::consumeError(ArchiveOrErr.takeError());
164 void processSymbols(
const llvm::object::ObjectFile &Obj) {
165 for (
const auto &Symbol : Obj.symbols()) {
166 auto FlagOrErr = Symbol.getFlags();
168 errorHandler(FlagOrErr.takeError());
172 auto NameOrErr = Symbol.getName();
174 errorHandler(NameOrErr.takeError());
177 llvm::StringRef Name = *NameOrErr;
180 FlagOrErr.get() & llvm::object::SymbolRef::SF_Undefined;
181 bool isFatBinSymbol = Name.starts_with(FatBinPrefix);
182 bool isGPUBinHandleSymbol = Name.starts_with(GPUBinHandlePrefix);
186 if (isFatBinSymbol) {
187 DefinedFatBinSymbols.insert(Name.str());
188 FatBinSymbols.erase(Name.str());
189 }
else if (isGPUBinHandleSymbol) {
190 DefinedGPUBinHandleSymbols.insert(Name.str());
191 GPUBinHandleSymbols.erase(Name.str());
197 if (isFatBinSymbol &&
198 DefinedFatBinSymbols.find(Name.str()) == DefinedFatBinSymbols.end())
199 FatBinSymbols.insert(Name.str());
200 else if (isGPUBinHandleSymbol &&
201 DefinedGPUBinHandleSymbols.find(Name.str()) ==
202 DefinedGPUBinHandleSymbols.end())
203 GPUBinHandleSymbols.insert(Name.str());
207 void errorHandler(llvm::Error Err) {
210 C.getDriver().Diag(DiagID) << llvm::toString(std::move(Err));
217 llvm::StringRef OutputFileName,
219 const llvm::opt::ArgList &Args,
223 ArgStringList BundlerArgs;
224 BundlerArgs.push_back(Args.MakeArgString(
"-type=o"));
225 BundlerArgs.push_back(
226 Args.MakeArgString(
"-bundle-align=" + Twine(HIPCodeObjectAlign)));
230 std::string BundlerTargetArg =
"-targets=host-x86_64-unknown-linux";
235 std::string OffloadKind =
"hip";
236 auto &TT =
T.getToolChain().getTriple();
238 OffloadKind = OffloadKind +
"v4";
239 for (
const auto &II : Inputs) {
240 const auto *A = II.getAction();
241 auto ArchStr = llvm::StringRef(A->getOffloadingArch());
244 if (!ArchStr.empty())
245 BundlerTargetArg +=
"-" + ArchStr.str();
247 BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg));
250 std::string BundlerInputArg =
"-input=" NULL_FILE;
251 BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
252 for (
const auto &II : Inputs) {
253 BundlerInputArg = std::string(
"-input=") + II.getFilename();
254 BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
257 std::string Output = std::string(OutputFileName);
258 auto *BundlerOutputArg =
259 Args.MakeArgString(std::string(
"-output=").append(Output));
260 BundlerArgs.push_back(BundlerOutputArg);
264 const char *Bundler = Args.MakeArgString(
265 T.getToolChain().GetProgramPath(
"clang-offload-bundler"));
266 C.addCommand(std::make_unique<Command>(
268 InputInfo(&JA, Args.MakeArgString(Output))));
279 std::string Name = std::string(llvm::sys::path::stem(Output.
getFilename()));
284 const char *McinFile;
285 const char *BundleFile;
286 if (
C.getDriver().isSaveTempsEnabled()) {
287 McinFile =
C.getArgs().MakeArgString(Name +
".mcin");
288 BundleFile =
C.getArgs().MakeArgString(Name +
".hipfb");
290 auto TmpNameMcin =
C.getDriver().GetTemporaryPath(Name,
"mcin");
291 McinFile =
C.addTempFile(
C.getArgs().MakeArgString(TmpNameMcin));
292 auto TmpNameFb =
C.getDriver().GetTemporaryPath(Name,
"hipfb");
293 BundleFile =
C.addTempFile(
C.getArgs().MakeArgString(TmpNameFb));
298 std::string ObjBuffer;
299 llvm::raw_string_ostream ObjStream(ObjBuffer);
306 std::string PrimaryHipFatbinSymbol;
307 std::string PrimaryGpuBinHandleSymbol;
308 bool FoundPrimaryHipFatbinSymbol =
false;
309 bool FoundPrimaryGpuBinHandleSymbol =
false;
311 std::vector<std::string> AliasHipFatbinSymbols;
312 std::vector<std::string> AliasGpuBinHandleSymbols;
316 for (
const auto &Symbol : Symbols.getFatBinSymbols()) {
317 if (!FoundPrimaryHipFatbinSymbol) {
318 PrimaryHipFatbinSymbol = Symbol;
319 FoundPrimaryHipFatbinSymbol =
true;
321 AliasHipFatbinSymbols.push_back(Symbol);
324 for (
const auto &Symbol : Symbols.getGPUBinHandleSymbols()) {
325 if (!FoundPrimaryGpuBinHandleSymbol) {
326 PrimaryGpuBinHandleSymbol = Symbol;
327 FoundPrimaryGpuBinHandleSymbol =
true;
329 AliasGpuBinHandleSymbols.push_back(Symbol);
336 ObjStream <<
"# HIP Object Generator\n";
337 ObjStream <<
"# *** Automatically generated by Clang ***\n";
338 if (FoundPrimaryGpuBinHandleSymbol) {
340 if (HostTriple.isWindowsMSVCEnvironment())
341 ObjStream <<
" .section .hip_gpubin_handle,\"dw\"\n";
343 ObjStream <<
" .protected " << PrimaryGpuBinHandleSymbol <<
"\n";
344 ObjStream <<
" .type " << PrimaryGpuBinHandleSymbol <<
",@object\n";
345 ObjStream <<
" .section .hip_gpubin_handle,\"aw\"\n";
347 ObjStream <<
" .globl " << PrimaryGpuBinHandleSymbol <<
"\n";
348 ObjStream <<
" .p2align 3\n";
349 ObjStream << PrimaryGpuBinHandleSymbol <<
":\n";
350 ObjStream <<
" .zero 8\n";
353 for (
const auto &AliasSymbol : AliasGpuBinHandleSymbols) {
354 ObjStream <<
" .globl " << AliasSymbol <<
"\n";
355 ObjStream <<
" .set " << AliasSymbol <<
"," << PrimaryGpuBinHandleSymbol
359 if (FoundPrimaryHipFatbinSymbol) {
361 if (HostTriple.isWindowsMSVCEnvironment())
362 ObjStream <<
" .section .hip_fatbin,\"dw\"\n";
364 ObjStream <<
" .protected " << PrimaryHipFatbinSymbol <<
"\n";
365 ObjStream <<
" .type " << PrimaryHipFatbinSymbol <<
",@object\n";
366 ObjStream <<
" .section .hip_fatbin,\"a\",@progbits\n";
368 ObjStream <<
" .globl " << PrimaryHipFatbinSymbol <<
"\n";
369 ObjStream <<
" .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign))
372 for (
const auto &AliasSymbol : AliasHipFatbinSymbols) {
373 ObjStream <<
" .globl " << AliasSymbol <<
"\n";
374 ObjStream <<
" .set " << AliasSymbol <<
"," << PrimaryHipFatbinSymbol
377 ObjStream << PrimaryHipFatbinSymbol <<
":\n";
378 ObjStream <<
" .incbin ";
379 llvm::sys::printArg(ObjStream, BundleFile,
true);
382 if (HostTriple.isOSLinux() && HostTriple.isOSBinFormatELF())
383 ObjStream <<
" .section .note.GNU-stack, \"\", @progbits\n";
388 if (
C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script))
389 llvm::errs() << ObjBuffer;
393 llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None);
396 C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
402 ArgStringList McArgs{
"-triple", Args.MakeArgString(HostTriple.normalize()),
404 McinFile,
"--filetype=obj"};
405 const char *Mc = Args.MakeArgString(TC.
GetProgramPath(
"llvm-mc"));
407 McArgs, Inputs, Output));
static std::string normalizeForBundler(const llvm::Triple &T, bool HasTargetID)
llvm::DenseSet< const void * > Visited
HIPUndefinedFatBinSymbols(const Compilation &C)
const std::set< std::string > & getGPUBinHandleSymbols() const
const std::set< std::string > & getFatBinSymbols() const
Concrete class used by the front-end to report problems and issues.
Action - Represent an abstract compilation step to perform.
Compilation - A set of tasks to perform for a single driver invocation.
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
static constexpr ResponseFileSupport None()
Returns a ResponseFileSupport indicating that response files are not supported.