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;
 
 
   86    llvm::Triple Triple(C.getDriver().getTargetTriple());
 
   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))));
 
  344  const Driver &D = 
C.getDriver();
 
  345  std::string Name = std::string(llvm::sys::path::stem(Output.
getFilename()));
 
  350  const char *ObjinFile;
 
  351  const char *BundleFile;
 
  353    ObjinFile = 
C.getArgs().MakeArgString(Name + 
".mcin");
 
  354    BundleFile = 
C.getArgs().MakeArgString(Name + 
".hipfb");
 
  357    ObjinFile = 
C.addTempFile(
C.getArgs().MakeArgString(TmpNameMcin));
 
  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()),
 
  479                             StringRef Extension) {
 
  480  if (
C.getDriver().isSaveTempsEnabled()) {
 
  481    return C.getArgs().MakeArgString(Prefix + 
"." + Extension);
 
  483  auto TmpFile = 
C.getDriver().GetTemporaryPath(Prefix, Extension);
 
  484  return C.addTempFile(
C.getArgs().MakeArgString(TmpFile));
 
 
static std::string normalizeForBundler(const llvm::Triple &T, bool HasTargetID)
 
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
 
const char * getClangProgramPath() const
Get the path to the main clang executable.
 
DiagnosticBuilder Diag(unsigned DiagID) const
 
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
 
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.