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 llvm::Triple
T(OrigT);
50 if (HasTargetID &&
T.isAMDGCN()) {
51 return (
"amdgcn-" +
T.getVendorName() +
"-" +
T.getOSName() +
"-" +
52 T.getEnvironmentName())
56 return HasTargetID ? (
T.getArchName() +
"-" +
T.getVendorName() +
"-" +
57 T.getOSName() +
"-" +
T.getEnvironmentName())
59 :
T.normalize(llvm::Triple::CanonicalForm::FOUR_IDENT);
67 const llvm::opt::ArgList &Args_)
69 DiagID(C.getDriver().getDiags().getCustomDiagID(
71 "Error collecting HIP undefined fatbin symbols: %0")),
72 Quiet(C.getArgs().hasArg(
options::OPT__HASH_HASH_HASH)),
73 Verbose(C.getArgs().hasArg(
options::OPT_v)) {
77 for (
const auto &Name : FatBinSymbols)
78 llvm::errs() <<
"Found undefined HIP fatbin symbol: " << Name <<
"\n";
79 for (
const auto &Name : GPUBinHandleSymbols)
80 llvm::errs() <<
"Found undefined HIP gpubin handle symbol: " << Name
90 return GPUBinHandleSymbols;
98 llvm::Triple Triple(C.getDriver().getTargetTriple());
99 bool IsMSVC = Triple.isWindowsMSVCEnvironment();
100 llvm::StringRef Ext = IsMSVC ?
".lib" :
".a";
102 for (
const auto *Arg : Args.filtered(options::OPT_l)) {
103 llvm::StringRef
Value = Arg->getValue();
104 if (
Value.starts_with(
":"))
105 ExactLibNames.push_back(
Value.drop_front());
107 LibNames.push_back(
Value);
109 for (
const auto *Arg : Args.filtered(options::OPT_L)) {
110 auto Path = Arg->getValue();
111 LibPaths.push_back(Path);
113 llvm::errs() <<
"HIP fatbin symbol search uses library path: " << Path
117 auto ProcessLib = [&](llvm::StringRef LibName,
bool IsExact) {
119 IsExact ? Twine(LibName).str()
120 : IsMSVC ? (Twine(LibName) + Ext).str()
121 : (Twine(
"lib") + LibName + Ext).str());
124 for (
const auto Path : LibPaths) {
126 llvm::sys::path::append(FullPath, FullLibName);
128 if (llvm::sys::fs::exists(FullPath)) {
130 llvm::errs() <<
"HIP fatbin symbol search found library: "
132 auto BufferOrErr = llvm::MemoryBuffer::getFile(FullPath);
134 errorHandler(llvm::errorCodeToError(BufferOrErr.getError()));
137 processInput(BufferOrErr.get()->getMemBufferRef());
142 if (!
Found && Verbose)
143 llvm::errs() <<
"HIP fatbin symbol search could not find library: "
144 << FullLibName <<
"\n";
147 for (
const auto LibName : ExactLibNames)
148 ProcessLib(LibName,
true);
150 for (
const auto LibName : LibNames)
151 ProcessLib(LibName,
false);
156 const llvm::opt::ArgList &Args;
160 std::set<std::string> FatBinSymbols;
161 std::set<std::string> GPUBinHandleSymbols;
162 std::set<std::string, std::less<>> DefinedFatBinSymbols;
163 std::set<std::string, std::less<>> DefinedGPUBinHandleSymbols;
164 const std::string FatBinPrefix =
"__hip_fatbin";
165 const std::string GPUBinHandlePrefix =
"__hip_gpubin_handle";
167 void populateSymbols() {
168 std::deque<const Action *> WorkList;
169 std::set<const Action *> Visited;
171 for (
const auto &
Action :
C.getActions())
172 WorkList.push_back(
Action);
174 while (!WorkList.empty()) {
175 const Action *CurrentAction = WorkList.front();
176 WorkList.pop_front();
178 if (!CurrentAction || !Visited.insert(CurrentAction).second)
181 if (
const auto *IA = dyn_cast<InputAction>(CurrentAction)) {
182 std::string ID = IA->getId().str();
184 ID = llvm::utohexstr(llvm::MD5Hash(ID),
true);
185 FatBinSymbols.insert((FatBinPrefix + Twine(
'_') + ID).str());
186 GPUBinHandleSymbols.insert(
187 (GPUBinHandlePrefix + Twine(
'_') + ID).str());
190 if (IA->getInputArg().getNumValues() == 0)
192 const char *Filename = IA->getInputArg().getValue();
195 auto BufferOrErr = llvm::MemoryBuffer::getFile(Filename);
202 processInput(BufferOrErr.get()->getMemBufferRef());
204 llvm::append_range(WorkList, CurrentAction->
getInputs());
208 void processInput(
const llvm::MemoryBufferRef &Buffer) {
210 auto ObjFileOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
212 processSymbols(**ObjFileOrErr);
217 llvm::consumeError(ObjFileOrErr.takeError());
218 auto ArchiveOrErr = llvm::object::Archive::create(Buffer);
220 llvm::Error Err = llvm::Error::success();
221 llvm::object::Archive &Archive = *ArchiveOrErr.get();
222 for (
auto &Child : Archive.children(Err)) {
223 auto ChildBufOrErr = Child.getMemoryBufferRef();
225 processInput(*ChildBufOrErr);
227 errorHandler(ChildBufOrErr.takeError());
231 errorHandler(std::move(Err));
236 llvm::consumeError(ArchiveOrErr.takeError());
239 void processSymbols(
const llvm::object::ObjectFile &Obj) {
240 for (
const auto &Symbol : Obj.symbols()) {
241 auto FlagOrErr = Symbol.getFlags();
243 errorHandler(FlagOrErr.takeError());
247 auto NameOrErr = Symbol.getName();
249 errorHandler(NameOrErr.takeError());
252 llvm::StringRef Name = *NameOrErr;
255 FlagOrErr.get() & llvm::object::SymbolRef::SF_Undefined;
256 bool isHidden = FlagOrErr.get() & llvm::object::SymbolRef::SF_Hidden;
257 bool isFatBinSymbol = Name.starts_with(FatBinPrefix);
258 bool isGPUBinHandleSymbol = Name.starts_with(GPUBinHandlePrefix);
262 if (isFatBinSymbol &&
263 DefinedFatBinSymbols.find(Name) == DefinedFatBinSymbols.end())
264 FatBinSymbols.insert(Name.str());
265 else if (isGPUBinHandleSymbol &&
266 DefinedGPUBinHandleSymbols.find(Name) ==
267 DefinedGPUBinHandleSymbols.end())
268 GPUBinHandleSymbols.insert(Name.str());
277 if (isFatBinSymbol) {
278 DefinedFatBinSymbols.insert(Name.str());
279 FatBinSymbols.erase(Name.str());
280 }
else if (isGPUBinHandleSymbol) {
281 DefinedGPUBinHandleSymbols.insert(Name.str());
282 GPUBinHandleSymbols.erase(Name.str());
287 void errorHandler(llvm::Error Err) {
290 C.getDriver().Diag(DiagID) << llvm::toString(std::move(Err));
297 llvm::StringRef OutputFileName,
299 const llvm::opt::ArgList &Args,
303 ArgStringList BundlerArgs;
304 BundlerArgs.push_back(Args.MakeArgString(
"-type=o"));
305 BundlerArgs.push_back(
306 Args.MakeArgString(
"-bundle-align=" + Twine(HIPCodeObjectAlign)));
310 std::string BundlerTargetArg =
"-targets=host-x86_64-unknown-linux-gnu";
315 std::string OffloadKind =
"hip";
316 if (
T.getToolChain().getTriple().isAMDGCN() &&
318 OffloadKind = OffloadKind +
"v4";
319 for (
const auto &II : Inputs) {
320 const auto *A = II.getAction();
321 const llvm::Triple &InputTriple = A->getOffloadingToolChain()->getTriple();
324 BundlerTargetArg +=
',' + OffloadKind +
'-';
326 BundlerTargetArg +=
"spirv64-amd-amdhsa-";
330 BundlerTargetArg +=
'-' + BA.
ArchName.str();
332 BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg));
335 std::string BundlerInputArg =
"-input=" NULL_FILE;
336 BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
337 for (
const auto &II : Inputs) {
338 BundlerInputArg = std::string(
"-input=") + II.getFilename();
339 BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
342 std::string Output = std::string(OutputFileName);
343 auto *BundlerOutputArg =
344 Args.MakeArgString(std::string(
"-output=").append(Output));
345 BundlerArgs.push_back(BundlerOutputArg);
349 const char *Bundler = Args.MakeArgString(
350 T.getToolChain().GetProgramPath(
"clang-offload-bundler"));
351 C.addCommand(std::make_unique<Command>(
353 InputInfo(&JA, Args.MakeArgString(Output))));
363 const Driver &D =
C.getDriver();
364 std::string Name = std::string(llvm::sys::path::stem(Output.
getFilename()));
369 const char *ObjinFile;
370 const char *BundleFile;
372 ObjinFile =
C.getArgs().MakeArgString(Name +
".mcin");
373 BundleFile =
C.getArgs().MakeArgString(Name +
".hipfb");
376 ObjinFile =
C.addTempFile(
C.getArgs().MakeArgString(TmpNameMcin));
378 BundleFile =
C.addTempFile(
C.getArgs().MakeArgString(TmpNameFb));
383 std::string ObjBuffer;
384 llvm::raw_string_ostream ObjStream(ObjBuffer);
391 std::string PrimaryHipFatbinSymbol;
392 std::string PrimaryGpuBinHandleSymbol;
393 bool FoundPrimaryHipFatbinSymbol =
false;
394 bool FoundPrimaryGpuBinHandleSymbol =
false;
396 std::vector<std::string> AliasHipFatbinSymbols;
397 std::vector<std::string> AliasGpuBinHandleSymbols;
401 for (
const auto &Symbol : Symbols.getFatBinSymbols()) {
402 if (!FoundPrimaryHipFatbinSymbol) {
403 PrimaryHipFatbinSymbol = Symbol;
404 FoundPrimaryHipFatbinSymbol =
true;
406 AliasHipFatbinSymbols.push_back(Symbol);
409 for (
const auto &Symbol : Symbols.getGPUBinHandleSymbols()) {
410 if (!FoundPrimaryGpuBinHandleSymbol) {
411 PrimaryGpuBinHandleSymbol = Symbol;
412 FoundPrimaryGpuBinHandleSymbol =
true;
414 AliasGpuBinHandleSymbols.push_back(Symbol);
421 ObjStream <<
"# HIP Object Generator\n";
422 ObjStream <<
"# *** Automatically generated by Clang ***\n";
423 if (FoundPrimaryGpuBinHandleSymbol) {
425 if (HostTriple.isWindowsMSVCEnvironment()) {
426 ObjStream <<
" .section .hip_gpubin_handle,\"dw\"\n";
427 }
else if (HostTriple.isMacOSX()) {
428 ObjStream <<
" .section __HIP,__gpubin_handle\n";
430 ObjStream <<
" .protected " << PrimaryGpuBinHandleSymbol <<
"\n";
431 ObjStream <<
" .type " << PrimaryGpuBinHandleSymbol <<
",@object\n";
432 ObjStream <<
" .section .hip_gpubin_handle,\"aw\"\n";
434 ObjStream <<
" .globl " << PrimaryGpuBinHandleSymbol <<
"\n";
435 ObjStream <<
" .p2align 3\n";
436 ObjStream << PrimaryGpuBinHandleSymbol <<
":\n";
437 ObjStream <<
" .zero 8\n";
440 for (
const auto &AliasSymbol : AliasGpuBinHandleSymbols) {
441 ObjStream <<
" .globl " << AliasSymbol <<
"\n";
442 ObjStream <<
" .set " << AliasSymbol <<
"," << PrimaryGpuBinHandleSymbol
446 if (FoundPrimaryHipFatbinSymbol) {
448 if (HostTriple.isWindowsMSVCEnvironment()) {
449 ObjStream <<
" .section .hip_fatbin,\"dw\"\n";
450 }
else if (HostTriple.isMacOSX()) {
452 ObjStream <<
" .section __HIP,__hip_fatbin\n";
454 ObjStream <<
" .protected " << PrimaryHipFatbinSymbol <<
"\n";
455 ObjStream <<
" .type " << PrimaryHipFatbinSymbol <<
",@object\n";
456 ObjStream <<
" .section .hip_fatbin,\"a\",@progbits\n";
458 ObjStream <<
" .globl " << PrimaryHipFatbinSymbol <<
"\n";
459 ObjStream <<
" .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign))
462 for (
const auto &AliasSymbol : AliasHipFatbinSymbols) {
463 ObjStream <<
" .globl " << AliasSymbol <<
"\n";
464 ObjStream <<
" .set " << AliasSymbol <<
"," << PrimaryHipFatbinSymbol
467 ObjStream << PrimaryHipFatbinSymbol <<
":\n";
468 ObjStream <<
" .incbin ";
469 llvm::sys::printArg(ObjStream, BundleFile,
true);
472 if (HostTriple.isOSLinux() && HostTriple.isOSBinFormatELF())
473 ObjStream <<
" .section .note.GNU-stack, \"\", @progbits\n";
477 if (
C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script))
478 llvm::errs() << ObjBuffer;
482 llvm::raw_fd_ostream Objf(ObjinFile, EC, llvm::sys::fs::OF_None);
485 D.
Diag(clang::diag::err_unable_to_make_temp) << EC.message();
491 ArgStringList ClangArgs{
"-target", Args.MakeArgStringRef(HostTriple.str()),
503 StringRef Extension) {
504 if (
C.getDriver().isSaveTempsEnabled()) {
505 return C.getArgs().MakeArgString(Prefix +
"." + Extension);
507 auto TmpFile =
C.getDriver().GetTemporaryPath(Prefix, Extension);
508 return C.addTempFile(
C.getArgs().MakeArgString(TmpFile));
static LLVM_ATTRIBUTE_USED bool isHidden(const CheckerRegistryData &Registry, StringRef CheckerName)
static std::string normalizeForBundler(const llvm::Triple &OrigT, StringRef BoundArch)
static StringRef getTriple(const Command &Job)
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.
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
bool isSaveTempsEnabled() const
const char * getPrependArg() const
DiagnosticBuilder Diag(unsigned DiagID) const
const char * getDriverProgramPath() const
Get the path to the main driver executable.
std::string GetTemporaryPath(StringRef Prefix, StringRef Suffix) const
GetTemporaryPath - Return the pathname of a temporary file to use as part of compilation; the file wi...
SmallVector< InputInfo, 4 > InputInfoList
Top level wrappers for InstallAPI frontend operations.
const FunctionProtoType * T
Represents a bound architecture for offload / multiple architecture compilation.
static constexpr ResponseFileSupport None()
Returns a ResponseFileSupport indicating that response files are not supported.