13#include "llvm/ADT/StringExtras.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Object/Archive.h"
16#include "llvm/Object/ObjectFile.h"
17#include "llvm/Support/MD5.h"
18#include "llvm/Support/MemoryBuffer.h"
19#include "llvm/Support/Path.h"
20#include "llvm/Support/raw_ostream.h"
21#include "llvm/TargetParser/Triple.h"
31#if defined(_WIN32) || defined(_WIN64)
32#define NULL_FILE "nul"
34#define NULL_FILE "/dev/null"
38const unsigned HIPCodeObjectAlign = 4096;
44 return HasTargetID ? (
T.getArchName() +
"-" +
T.getVendorName() +
"-" +
45 T.getOSName() +
"-" +
T.getEnvironmentName())
47 :
T.normalize(llvm::Triple::CanonicalForm::FOUR_IDENT);
55 const llvm::opt::ArgList &Args_)
57 DiagID(C.getDriver().getDiags().getCustomDiagID(
59 "Error collecting HIP undefined fatbin symbols: %0")),
60 Quiet(C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)),
61 Verbose(C.getArgs().hasArg(options::OPT_v)) {
65 for (
const auto &Name : FatBinSymbols)
66 llvm::errs() <<
"Found undefined HIP fatbin symbol: " << Name <<
"\n";
67 for (
const auto &Name : GPUBinHandleSymbols)
68 llvm::errs() <<
"Found undefined HIP gpubin handle symbol: " << Name
78 return GPUBinHandleSymbols;
87 bool IsMSVC = Triple.isWindowsMSVCEnvironment();
88 llvm::StringRef Ext = IsMSVC ?
".lib" :
".a";
90 for (
const auto *Arg : Args.filtered(options::OPT_l)) {
91 llvm::StringRef
Value = Arg->getValue();
92 if (
Value.starts_with(
":"))
93 ExactLibNames.push_back(
Value.drop_front());
95 LibNames.push_back(
Value);
97 for (
const auto *Arg : Args.filtered(options::OPT_L)) {
98 auto Path = Arg->getValue();
99 LibPaths.push_back(
Path);
101 llvm::errs() <<
"HIP fatbin symbol search uses library path: " <<
Path
105 auto ProcessLib = [&](llvm::StringRef LibName,
bool IsExact) {
107 IsExact ? Twine(LibName).str()
108 : IsMSVC ? (Twine(LibName) + Ext).str()
109 : (Twine(
"lib") + LibName + Ext).str());
112 for (
const auto Path : LibPaths) {
114 llvm::sys::path::append(FullPath, FullLibName);
116 if (llvm::sys::fs::exists(FullPath)) {
118 llvm::errs() <<
"HIP fatbin symbol search found library: "
120 auto BufferOrErr = llvm::MemoryBuffer::getFile(FullPath);
122 errorHandler(llvm::errorCodeToError(BufferOrErr.getError()));
125 processInput(BufferOrErr.get()->getMemBufferRef());
130 if (!
Found && Verbose)
131 llvm::errs() <<
"HIP fatbin symbol search could not find library: "
132 << FullLibName <<
"\n";
135 for (
const auto LibName : ExactLibNames)
136 ProcessLib(LibName,
true);
138 for (
const auto LibName : LibNames)
139 ProcessLib(LibName,
false);
144 const llvm::opt::ArgList &Args;
148 std::set<std::string> FatBinSymbols;
149 std::set<std::string> GPUBinHandleSymbols;
150 std::set<std::string, std::less<>> DefinedFatBinSymbols;
151 std::set<std::string, std::less<>> DefinedGPUBinHandleSymbols;
152 const std::string FatBinPrefix =
"__hip_fatbin";
153 const std::string GPUBinHandlePrefix =
"__hip_gpubin_handle";
155 void populateSymbols() {
156 std::deque<const Action *> WorkList;
157 std::set<const Action *>
Visited;
159 for (
const auto &
Action : C.getActions())
160 WorkList.push_back(
Action);
162 while (!WorkList.empty()) {
163 const Action *CurrentAction = WorkList.front();
164 WorkList.pop_front();
166 if (!CurrentAction || !
Visited.insert(CurrentAction).second)
169 if (
const auto *IA = dyn_cast<InputAction>(CurrentAction)) {
170 std::string ID = IA->getId().str();
172 ID = llvm::utohexstr(llvm::MD5Hash(ID),
true);
173 FatBinSymbols.insert((FatBinPrefix + Twine(
'_') + ID).str());
174 GPUBinHandleSymbols.insert(
175 (GPUBinHandlePrefix + Twine(
'_') + ID).str());
178 if (IA->getInputArg().getNumValues() == 0)
180 const char *
Filename = IA->getInputArg().getValue();
183 auto BufferOrErr = llvm::MemoryBuffer::getFile(
Filename);
190 processInput(BufferOrErr.get()->getMemBufferRef());
192 llvm::append_range(WorkList, CurrentAction->
getInputs());
196 void processInput(
const llvm::MemoryBufferRef &Buffer) {
198 auto ObjFileOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
200 processSymbols(**ObjFileOrErr);
205 llvm::consumeError(ObjFileOrErr.takeError());
206 auto ArchiveOrErr = llvm::object::Archive::create(Buffer);
208 llvm::Error Err = llvm::Error::success();
209 llvm::object::Archive &Archive = *ArchiveOrErr.get();
210 for (
auto &Child : Archive.children(Err)) {
211 auto ChildBufOrErr = Child.getMemoryBufferRef();
213 processInput(*ChildBufOrErr);
215 errorHandler(ChildBufOrErr.takeError());
219 errorHandler(std::move(Err));
224 llvm::consumeError(ArchiveOrErr.takeError());
227 void processSymbols(
const llvm::object::ObjectFile &Obj) {
228 for (
const auto &Symbol : Obj.symbols()) {
229 auto FlagOrErr = Symbol.getFlags();
231 errorHandler(FlagOrErr.takeError());
235 auto NameOrErr = Symbol.getName();
237 errorHandler(NameOrErr.takeError());
240 llvm::StringRef Name = *NameOrErr;
243 FlagOrErr.get() & llvm::object::SymbolRef::SF_Undefined;
244 bool isFatBinSymbol = Name.starts_with(FatBinPrefix);
245 bool isGPUBinHandleSymbol = Name.starts_with(GPUBinHandlePrefix);
249 if (isFatBinSymbol) {
250 DefinedFatBinSymbols.insert(Name.str());
251 FatBinSymbols.erase(Name.str());
252 }
else if (isGPUBinHandleSymbol) {
253 DefinedGPUBinHandleSymbols.insert(Name.str());
254 GPUBinHandleSymbols.erase(Name.str());
260 if (isFatBinSymbol &&
261 DefinedFatBinSymbols.find(Name) == DefinedFatBinSymbols.end())
262 FatBinSymbols.insert(Name.str());
263 else if (isGPUBinHandleSymbol && DefinedGPUBinHandleSymbols.find(Name) ==
264 DefinedGPUBinHandleSymbols.end())
265 GPUBinHandleSymbols.insert(Name.str());
269 void errorHandler(llvm::Error Err) {
272 C.getDriver().Diag(DiagID) << llvm::toString(std::move(Err));
279 llvm::StringRef OutputFileName,
281 const llvm::opt::ArgList &Args,
285 ArgStringList BundlerArgs;
286 BundlerArgs.push_back(Args.MakeArgString(
"-type=o"));
287 BundlerArgs.push_back(
288 Args.MakeArgString(
"-bundle-align=" + Twine(HIPCodeObjectAlign)));
292 std::string BundlerTargetArg =
"-targets=host-x86_64-unknown-linux-gnu";
297 std::string OffloadKind =
"hip";
298 auto &TT =
T.getToolChain().getTriple();
300 OffloadKind = OffloadKind +
"v4";
301 for (
const auto &II : Inputs) {
302 const auto *A = II.getAction();
303 auto ArchStr = llvm::StringRef(A->getOffloadingArch());
304 BundlerTargetArg +=
',' + OffloadKind +
'-';
305 if (ArchStr ==
"amdgcnspirv")
310 if (!ArchStr.empty())
311 BundlerTargetArg +=
'-' + ArchStr.str();
313 BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg));
316 std::string BundlerInputArg =
"-input=" NULL_FILE;
317 BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
318 for (
const auto &II : Inputs) {
319 BundlerInputArg = std::string(
"-input=") + II.getFilename();
320 BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
323 std::string Output = std::string(OutputFileName);
324 auto *BundlerOutputArg =
325 Args.MakeArgString(std::string(
"-output=").append(Output));
326 BundlerArgs.push_back(BundlerOutputArg);
330 const char *Bundler = Args.MakeArgString(
331 T.getToolChain().GetProgramPath(
"clang-offload-bundler"));
332 C.addCommand(std::make_unique<Command>(
334 InputInfo(&JA, Args.MakeArgString(Output))));
345 std::string Name = std::string(llvm::sys::path::stem(Output.
getFilename()));
350 const char *ObjinFile;
351 const char *BundleFile;
352 if (
D.isSaveTempsEnabled()) {
353 ObjinFile =
C.getArgs().MakeArgString(Name +
".mcin");
354 BundleFile =
C.getArgs().MakeArgString(Name +
".hipfb");
356 auto TmpNameMcin =
D.GetTemporaryPath(Name,
"mcin");
357 ObjinFile =
C.addTempFile(
C.getArgs().MakeArgString(TmpNameMcin));
358 auto TmpNameFb =
D.GetTemporaryPath(Name,
"hipfb");
359 BundleFile =
C.addTempFile(
C.getArgs().MakeArgString(TmpNameFb));
364 std::string ObjBuffer;
365 llvm::raw_string_ostream ObjStream(ObjBuffer);
372 std::string PrimaryHipFatbinSymbol;
373 std::string PrimaryGpuBinHandleSymbol;
374 bool FoundPrimaryHipFatbinSymbol =
false;
375 bool FoundPrimaryGpuBinHandleSymbol =
false;
377 std::vector<std::string> AliasHipFatbinSymbols;
378 std::vector<std::string> AliasGpuBinHandleSymbols;
382 for (
const auto &Symbol : Symbols.getFatBinSymbols()) {
383 if (!FoundPrimaryHipFatbinSymbol) {
384 PrimaryHipFatbinSymbol = Symbol;
385 FoundPrimaryHipFatbinSymbol =
true;
387 AliasHipFatbinSymbols.push_back(Symbol);
390 for (
const auto &Symbol : Symbols.getGPUBinHandleSymbols()) {
391 if (!FoundPrimaryGpuBinHandleSymbol) {
392 PrimaryGpuBinHandleSymbol = Symbol;
393 FoundPrimaryGpuBinHandleSymbol =
true;
395 AliasGpuBinHandleSymbols.push_back(Symbol);
402 ObjStream <<
"# HIP Object Generator\n";
403 ObjStream <<
"# *** Automatically generated by Clang ***\n";
404 if (FoundPrimaryGpuBinHandleSymbol) {
406 if (HostTriple.isWindowsMSVCEnvironment())
407 ObjStream <<
" .section .hip_gpubin_handle,\"dw\"\n";
409 ObjStream <<
" .protected " << PrimaryGpuBinHandleSymbol <<
"\n";
410 ObjStream <<
" .type " << PrimaryGpuBinHandleSymbol <<
",@object\n";
411 ObjStream <<
" .section .hip_gpubin_handle,\"aw\"\n";
413 ObjStream <<
" .globl " << PrimaryGpuBinHandleSymbol <<
"\n";
414 ObjStream <<
" .p2align 3\n";
415 ObjStream << PrimaryGpuBinHandleSymbol <<
":\n";
416 ObjStream <<
" .zero 8\n";
419 for (
const auto &AliasSymbol : AliasGpuBinHandleSymbols) {
420 ObjStream <<
" .globl " << AliasSymbol <<
"\n";
421 ObjStream <<
" .set " << AliasSymbol <<
"," << PrimaryGpuBinHandleSymbol
425 if (FoundPrimaryHipFatbinSymbol) {
427 if (HostTriple.isWindowsMSVCEnvironment())
428 ObjStream <<
" .section .hip_fatbin,\"dw\"\n";
430 ObjStream <<
" .protected " << PrimaryHipFatbinSymbol <<
"\n";
431 ObjStream <<
" .type " << PrimaryHipFatbinSymbol <<
",@object\n";
432 ObjStream <<
" .section .hip_fatbin,\"a\",@progbits\n";
434 ObjStream <<
" .globl " << PrimaryHipFatbinSymbol <<
"\n";
435 ObjStream <<
" .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign))
438 for (
const auto &AliasSymbol : AliasHipFatbinSymbols) {
439 ObjStream <<
" .globl " << AliasSymbol <<
"\n";
440 ObjStream <<
" .set " << AliasSymbol <<
"," << PrimaryHipFatbinSymbol
443 ObjStream << PrimaryHipFatbinSymbol <<
":\n";
444 ObjStream <<
" .incbin ";
445 llvm::sys::printArg(ObjStream, BundleFile,
true);
448 if (HostTriple.isOSLinux() && HostTriple.isOSBinFormatELF())
449 ObjStream <<
" .section .note.GNU-stack, \"\", @progbits\n";
453 if (
C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script))
454 llvm::errs() << ObjBuffer;
458 llvm::raw_fd_ostream Objf(ObjinFile, EC, llvm::sys::fs::OF_None);
461 D.Diag(clang::diag::err_unable_to_make_temp) << EC.message();
467 ArgStringList ClangArgs{
"-target", Args.MakeArgString(HostTriple.normalize()),
472 D.getClangProgramPath(), ClangArgs,
473 Inputs, Output,
D.getPrependArg()));
static std::string normalizeForBundler(const llvm::Triple &T, bool HasTargetID)
llvm::DenseSet< const void * > Visited
const std::set< std::string > & getGPUBinHandleSymbols() const
void processStaticLibraries()
HIPUndefinedFatBinSymbols(const Compilation &C, const llvm::opt::ArgList &Args_)
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.
const Driver & getDriver() const
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
std::string getTargetTriple() const
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.