diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -53,7 +53,8 @@ ToolChains/Fuchsia.cpp ToolChains/Gnu.cpp ToolChains/Haiku.cpp - ToolChains/HIP.cpp + ToolChains/HIPUtility.cpp + ToolChains/HIPAMD.cpp ToolChains/Hexagon.cpp ToolChains/Hurd.cpp ToolChains/Linux.cpp diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -23,7 +23,7 @@ #include "ToolChains/FreeBSD.h" #include "ToolChains/Fuchsia.h" #include "ToolChains/Gnu.h" -#include "ToolChains/HIP.h" +#include "ToolChains/HIPAMD.h" #include "ToolChains/Haiku.h" #include "ToolChains/Hexagon.h" #include "ToolChains/Hurd.h" @@ -701,7 +701,7 @@ // because the device toolchain we create depends on both. auto &HIPTC = ToolChains[HIPTriple.str() + "/" + HostTriple.str()]; if (!HIPTC) { - HIPTC = std::make_unique( + HIPTC = std::make_unique( *this, HIPTriple, *HostTC, C.getInputArgs()); } C.addOffloadDeviceToolChain(HIPTC.get(), OFK); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7861,7 +7861,7 @@ Triples += '-'; Triples += CurTC->getTriple().normalize(); if ((CurKind == Action::OFK_HIP || CurKind == Action::OFK_Cuda) && - CurDep->getOffloadingArch()) { + !StringRef(CurDep->getOffloadingArch()).empty()) { Triples += '-'; Triples += CurDep->getOffloadingArch(); } diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -15,7 +15,7 @@ #include "Arch/SystemZ.h" #include "Arch/VE.h" #include "Arch/X86.h" -#include "HIP.h" +#include "HIPAMD.h" #include "Hexagon.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/LangOptions.h" diff --git a/clang/lib/Driver/ToolChains/HIP.h b/clang/lib/Driver/ToolChains/HIPAMD.h rename from clang/lib/Driver/ToolChains/HIP.h rename to clang/lib/Driver/ToolChains/HIPAMD.h --- a/clang/lib/Driver/ToolChains/HIP.h +++ b/clang/lib/Driver/ToolChains/HIPAMD.h @@ -1,4 +1,4 @@ -//===--- HIP.h - HIP ToolChain Implementations ------------------*- C++ -*-===// +//===--- HIPAMD.h - HIP ToolChain Implementations ---------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPAMD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPAMD_H -#include "clang/Driver/ToolChain.h" -#include "clang/Driver/Tool.h" #include "AMDGPU.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" namespace clang { namespace driver { @@ -19,11 +19,6 @@ namespace tools { namespace AMDGCN { - // Construct command for creating HIP fatbin. - void constructHIPFatbinCommand(Compilation &C, const JobAction &JA, - StringRef OutputFileName, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, const Tool& T); - // Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with // device library, then compiles it to ISA in a shared object. class LLVM_LIBRARY_VISIBILITY Linker : public Tool { @@ -38,17 +33,9 @@ const char *LinkingOutput) const override; private: - void constructLldCommand(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const InputInfo &Output, const llvm::opt::ArgList &Args) const; - - // Construct command for creating Object from HIP fatbin. - void constructGenerateObjFileFromHIPFatBinary(Compilation &C, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - const JobAction &JA) const; }; } // end namespace AMDGCN @@ -56,10 +43,10 @@ namespace toolchains { -class LLVM_LIBRARY_VISIBILITY HIPToolChain final : public ROCMToolChain { +class LLVM_LIBRARY_VISIBILITY HIPAMDToolChain final : public ROCMToolChain { public: - HIPToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const llvm::opt::ArgList &Args); + HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const llvm::opt::ArgList &Args); const llvm::Triple *getAuxTriple() const override { return &HostTC.getTriple(); @@ -68,9 +55,10 @@ llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void @@ -105,4 +93,4 @@ } // end namespace driver } // end namespace clang -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPAMD_H diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIPAMD.cpp rename from clang/lib/Driver/ToolChains/HIP.cpp rename to clang/lib/Driver/ToolChains/HIPAMD.cpp --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIPAMD.cpp @@ -1,4 +1,4 @@ -//===--- HIP.cpp - HIP Tool and ToolChain Implementations -------*- C++ -*-===// +//===--- HIPAMD.cpp - HIP Tool and ToolChain Implementations ----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,9 +6,10 @@ // //===----------------------------------------------------------------------===// -#include "HIP.h" +#include "HIPAMD.h" #include "AMDGPU.h" #include "CommonArgs.h" +#include "HIPUtility.h" #include "clang/Basic/Cuda.h" #include "clang/Basic/TargetID.h" #include "clang/Driver/Compilation.h" @@ -76,9 +77,9 @@ } void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const InputInfo &Output, - const llvm::opt::ArgList &Args) const { + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args) const { // Construct lld command. // The output from ld.lld is an HSA code object file. ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", "-shared", @@ -129,151 +130,28 @@ Lld, LldArgs, Inputs, Output)); } -// Construct a clang-offload-bundler command to bundle code objects for -// different GPU's into a HIP fat binary. -void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, - StringRef OutputFileName, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, const Tool& T) { - // Construct clang-offload-bundler command to bundle object files for - // for different GPU archs. - ArgStringList BundlerArgs; - BundlerArgs.push_back(Args.MakeArgString("-type=o")); - BundlerArgs.push_back( - Args.MakeArgString("-bundle-align=" + Twine(HIPCodeObjectAlign))); - - // ToDo: Remove the dummy host binary entry which is required by - // clang-offload-bundler. - std::string BundlerTargetArg = "-targets=host-x86_64-unknown-linux"; - std::string BundlerInputArg = "-inputs=" NULL_FILE; - - // For code object version 2 and 3, the offload kind in bundle ID is 'hip' - // for backward compatibility. For code object version 4 and greater, the - // offload kind in bundle ID is 'hipv4'. - std::string OffloadKind = "hip"; - if (getAMDGPUCodeObjectVersion(C.getDriver(), Args) >= 4) - OffloadKind = OffloadKind + "v4"; - for (const auto &II : Inputs) { - const auto* A = II.getAction(); - BundlerTargetArg = BundlerTargetArg + "," + OffloadKind + - "-amdgcn-amd-amdhsa--" + - StringRef(A->getOffloadingArch()).str(); - BundlerInputArg = BundlerInputArg + "," + II.getFilename(); - } - BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg)); - BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg)); - - std::string Output = std::string(OutputFileName); - auto BundlerOutputArg = - Args.MakeArgString(std::string("-outputs=").append(Output)); - BundlerArgs.push_back(BundlerOutputArg); - - const char *Bundler = Args.MakeArgString( - T.getToolChain().GetProgramPath("clang-offload-bundler")); - C.addCommand(std::make_unique( - JA, T, ResponseFileSupport::None(), Bundler, BundlerArgs, Inputs, - InputInfo(&JA, Args.MakeArgString(Output)))); -} - -/// Add Generated HIP Object File which has device images embedded into the -/// host to the argument list for linking. Using MC directives, embed the -/// device code and also define symbols required by the code generation so that -/// the image can be retrieved at runtime. -void AMDGCN::Linker::constructGenerateObjFileFromHIPFatBinary( - Compilation &C, const InputInfo &Output, - const InputInfoList &Inputs, const ArgList &Args, - const JobAction &JA) const { - const ToolChain &TC = getToolChain(); - std::string Name = std::string(llvm::sys::path::stem(Output.getFilename())); - - // Create Temp Object File Generator, - // Offload Bundled file and Bundled Object file. - // Keep them if save-temps is enabled. - const char *McinFile; - const char *BundleFile; - if (C.getDriver().isSaveTempsEnabled()) { - McinFile = C.getArgs().MakeArgString(Name + ".mcin"); - BundleFile = C.getArgs().MakeArgString(Name + ".hipfb"); - } else { - auto TmpNameMcin = C.getDriver().GetTemporaryPath(Name, "mcin"); - McinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin)); - auto TmpNameFb = C.getDriver().GetTemporaryPath(Name, "hipfb"); - BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameFb)); - } - constructHIPFatbinCommand(C, JA, BundleFile, Inputs, Args, *this); - - // Create a buffer to write the contents of the temp obj generator. - std::string ObjBuffer; - llvm::raw_string_ostream ObjStream(ObjBuffer); - - auto HostTriple = - C.getSingleOffloadToolChain()->getTriple(); - - // Add MC directives to embed target binaries. We ensure that each - // section and image is 16-byte aligned. This is not mandatory, but - // increases the likelihood of data to be aligned with a cache block - // in several main host machines. - ObjStream << "# HIP Object Generator\n"; - ObjStream << "# *** Automatically generated by Clang ***\n"; - if (HostTriple.isWindowsMSVCEnvironment()) { - ObjStream << " .section .hip_fatbin, \"dw\"\n"; - } else { - ObjStream << " .protected __hip_fatbin\n"; - ObjStream << " .type __hip_fatbin,@object\n"; - ObjStream << " .section .hip_fatbin,\"a\",@progbits\n"; - } - ObjStream << " .globl __hip_fatbin\n"; - ObjStream << " .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign)) - << "\n"; - ObjStream << "__hip_fatbin:\n"; - ObjStream << " .incbin "; - llvm::sys::printArg(ObjStream, BundleFile, /*Quote=*/true); - ObjStream << "\n"; - ObjStream.flush(); - - // Dump the contents of the temp object file gen if the user requested that. - // We support this option to enable testing of behavior with -###. - if (C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script)) - llvm::errs() << ObjBuffer; - - // Open script file and write the contents. - std::error_code EC; - llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None); - - if (EC) { - C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); - return; - } - - Objf << ObjBuffer; - - ArgStringList McArgs{"-triple", Args.MakeArgString(HostTriple.normalize()), - "-o", Output.getFilename(), - McinFile, "--filetype=obj"}; - const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc")); - C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), - Mc, McArgs, Inputs, Output)); -} - // For amdgcn the inputs of the linker job are device bitcode and output is // object file. It calls llvm-link, opt, llc, then lld steps. void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { if (Inputs.size() > 0 && Inputs[0].getType() == types::TY_Image && JA.getType() == types::TY_Object) - return constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, Args, JA); + return HIP::constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, + Args, JA, *this); if (JA.getType() == types::TY_HIP_FATBIN) - return constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, Args, *this); + return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, + Args, *this); return constructLldCommand(C, JA, Inputs, Output, Args); } -HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const ArgList &Args) +HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple, + const ToolChain &HostTC, const ArgList &Args) : ROCMToolChain(D, Triple, Args), HostTC(HostTC) { // Lookup binaries into the driver directory, this is used to // discover the clang-offload-bundler executable. @@ -288,9 +166,8 @@ } } -void HIPToolChain::addClangTargetOptions( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, +void HIPAMDToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const { HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); @@ -333,9 +210,9 @@ } llvm::opt::DerivedArgList * -HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, - StringRef BoundArch, - Action::OffloadKind DeviceOffloadKind) const { +HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { DerivedArgList *DAL = HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); if (!DAL) @@ -358,44 +235,44 @@ return DAL; } -Tool *HIPToolChain::buildLinker() const { +Tool *HIPAMDToolChain::buildLinker() const { assert(getTriple().getArch() == llvm::Triple::amdgcn); return new tools::AMDGCN::Linker(*this); } -void HIPToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { +void HIPAMDToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { HostTC.addClangWarningOptions(CC1Args); } ToolChain::CXXStdlibType -HIPToolChain::GetCXXStdlibType(const ArgList &Args) const { +HIPAMDToolChain::GetCXXStdlibType(const ArgList &Args) const { return HostTC.GetCXXStdlibType(Args); } -void HIPToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +void HIPAMDToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); } -void HIPToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, - ArgStringList &CC1Args) const { +void HIPAMDToolChain::AddClangCXXStdlibIncludeArgs( + const ArgList &Args, ArgStringList &CC1Args) const { HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); } -void HIPToolChain::AddIAMCUIncludeArgs(const ArgList &Args, - ArgStringList &CC1Args) const { +void HIPAMDToolChain::AddIAMCUIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { HostTC.AddIAMCUIncludeArgs(Args, CC1Args); } -void HIPToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { +void HIPAMDToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); } -SanitizerMask HIPToolChain::getSupportedSanitizers() const { - // The HIPToolChain only supports sanitizers in the sense that it allows +SanitizerMask HIPAMDToolChain::getSupportedSanitizers() const { + // The HIPAMDToolChain only supports sanitizers in the sense that it allows // sanitizer arguments on the command line if they are supported by the host - // toolchain. The HIPToolChain will actually ignore any command line + // toolchain. The HIPAMDToolChain will actually ignore any command line // arguments for any of these "supported" sanitizers. That means that no // sanitization of device code is actually supported at this time. // @@ -405,13 +282,13 @@ return HostTC.getSupportedSanitizers(); } -VersionTuple HIPToolChain::computeMSVCVersion(const Driver *D, - const ArgList &Args) const { +VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D, + const ArgList &Args) const { return HostTC.computeMSVCVersion(D, Args); } llvm::SmallVector -HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { +HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { llvm::SmallVector BCLibs; if (DriverArgs.hasArg(options::OPT_nogpulib)) return {}; @@ -485,7 +362,8 @@ return BCLibs; } -void HIPToolChain::checkTargetID(const llvm::opt::ArgList &DriverArgs) const { +void HIPAMDToolChain::checkTargetID( + const llvm::opt::ArgList &DriverArgs) const { auto PTID = getParsedTargetID(DriverArgs); if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) { getDriver().Diag(clang::diag::err_drv_bad_target_id) diff --git a/clang/lib/Driver/ToolChains/HIPUtility.h b/clang/lib/Driver/ToolChains/HIPUtility.h new file mode 100644 --- /dev/null +++ b/clang/lib/Driver/ToolChains/HIPUtility.h @@ -0,0 +1,35 @@ +//===--- HIPUtility.h - Common HIP Tool Chain Utilities ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPUTILITY_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPUTILITY_H + +#include "clang/Driver/Tool.h" + +namespace clang { +namespace driver { +namespace tools { +namespace HIP { + +// Construct command for creating HIP fatbin. +void constructHIPFatbinCommand(Compilation &C, const JobAction &JA, + StringRef OutputFileName, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, const Tool &T); + +// Construct command for creating Object from HIP fatbin. +void constructGenerateObjFileFromHIPFatBinary( + Compilation &C, const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, const JobAction &JA, const Tool &T); + +} // namespace HIP +} // namespace tools +} // namespace driver +} // namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIPUTILITY_H diff --git a/clang/lib/Driver/ToolChains/HIPUtility.cpp b/clang/lib/Driver/ToolChains/HIPUtility.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Driver/ToolChains/HIPUtility.cpp @@ -0,0 +1,166 @@ +//===--- HIPUtility.cpp - Common HIP Tool Chain Utilities -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "HIPUtility.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace llvm::opt; + +#if defined(_WIN32) || defined(_WIN64) +#define NULL_FILE "nul" +#else +#define NULL_FILE "/dev/null" +#endif + +namespace { +const unsigned HIPCodeObjectAlign = 4096; +} // namespace + +// Constructs a triple string for clang offload bundler. +static std::string normalizeForBundler(const llvm::Triple &T, + bool HasTargetID) { + return HasTargetID ? (T.getArchName() + "-" + T.getVendorName() + "-" + + T.getOSName() + "-" + T.getEnvironmentName()) + .str() + : T.normalize(); +} + +// Construct a clang-offload-bundler command to bundle code objects for +// different devices into a HIP fat binary. +void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA, + StringRef OutputFileName, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + const Tool &T) { + // Construct clang-offload-bundler command to bundle object files for + // for different GPU archs. + ArgStringList BundlerArgs; + BundlerArgs.push_back(Args.MakeArgString("-type=o")); + BundlerArgs.push_back( + Args.MakeArgString("-bundle-align=" + Twine(HIPCodeObjectAlign))); + + // ToDo: Remove the dummy host binary entry which is required by + // clang-offload-bundler. + std::string BundlerTargetArg = "-targets=host-x86_64-unknown-linux"; + std::string BundlerInputArg = "-inputs=" NULL_FILE; + + // AMDGCN: + // For code object version 2 and 3, the offload kind in bundle ID is 'hip' + // for backward compatibility. For code object version 4 and greater, the + // offload kind in bundle ID is 'hipv4'. + std::string OffloadKind = "hip"; + auto &TT = T.getToolChain().getTriple(); + if (TT.isAMDGCN() && getAMDGPUCodeObjectVersion(C.getDriver(), Args) >= 4) + OffloadKind = OffloadKind + "v4"; + for (const auto &II : Inputs) { + const auto *A = II.getAction(); + auto ArchStr = StringRef(A->getOffloadingArch()); + BundlerTargetArg += + "," + OffloadKind + "-" + normalizeForBundler(TT, !ArchStr.empty()); + if (!ArchStr.empty()) + BundlerTargetArg += "-" + ArchStr.str(); + BundlerInputArg = BundlerInputArg + "," + II.getFilename(); + } + BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg)); + BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg)); + + std::string Output = std::string(OutputFileName); + auto *BundlerOutputArg = + Args.MakeArgString(std::string("-outputs=").append(Output)); + BundlerArgs.push_back(BundlerOutputArg); + + const char *Bundler = Args.MakeArgString( + T.getToolChain().GetProgramPath("clang-offload-bundler")); + C.addCommand(std::make_unique( + JA, T, ResponseFileSupport::None(), Bundler, BundlerArgs, Inputs, + InputInfo(&JA, Args.MakeArgString(Output)))); +} + +/// Add Generated HIP Object File which has device images embedded into the +/// host to the argument list for linking. Using MC directives, embed the +/// device code and also define symbols required by the code generation so that +/// the image can be retrieved at runtime. +void HIP::constructGenerateObjFileFromHIPFatBinary( + Compilation &C, const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, const JobAction &JA, const Tool &T) { + const ToolChain &TC = T.getToolChain(); + std::string Name = std::string(llvm::sys::path::stem(Output.getFilename())); + + // Create Temp Object File Generator, + // Offload Bundled file and Bundled Object file. + // Keep them if save-temps is enabled. + const char *McinFile; + const char *BundleFile; + if (C.getDriver().isSaveTempsEnabled()) { + McinFile = C.getArgs().MakeArgString(Name + ".mcin"); + BundleFile = C.getArgs().MakeArgString(Name + ".hipfb"); + } else { + auto TmpNameMcin = C.getDriver().GetTemporaryPath(Name, "mcin"); + McinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin)); + auto TmpNameFb = C.getDriver().GetTemporaryPath(Name, "hipfb"); + BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameFb)); + } + HIP::constructHIPFatbinCommand(C, JA, BundleFile, Inputs, Args, T); + + // Create a buffer to write the contents of the temp obj generator. + std::string ObjBuffer; + llvm::raw_string_ostream ObjStream(ObjBuffer); + + auto HostTriple = + C.getSingleOffloadToolChain()->getTriple(); + + // Add MC directives to embed target binaries. We ensure that each + // section and image is 16-byte aligned. This is not mandatory, but + // increases the likelihood of data to be aligned with a cache block + // in several main host machines. + ObjStream << "# HIP Object Generator\n"; + ObjStream << "# *** Automatically generated by Clang ***\n"; + if (HostTriple.isWindowsMSVCEnvironment()) { + ObjStream << " .section .hip_fatbin, \"dw\"\n"; + } else { + ObjStream << " .protected __hip_fatbin\n"; + ObjStream << " .type __hip_fatbin,@object\n"; + ObjStream << " .section .hip_fatbin,\"a\",@progbits\n"; + } + ObjStream << " .globl __hip_fatbin\n"; + ObjStream << " .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign)) + << "\n"; + ObjStream << "__hip_fatbin:\n"; + ObjStream << " .incbin "; + llvm::sys::printArg(ObjStream, BundleFile, /*Quote=*/true); + ObjStream << "\n"; + ObjStream.flush(); + + // Dump the contents of the temp object file gen if the user requested that. + // We support this option to enable testing of behavior with -###. + if (C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script)) + llvm::errs() << ObjBuffer; + + // Open script file and write the contents. + std::error_code EC; + llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None); + + if (EC) { + C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return; + } + + Objf << ObjBuffer; + + ArgStringList McArgs{"-triple", Args.MakeArgString(HostTriple.normalize()), + "-o", Output.getFilename(), + McinFile, "--filetype=obj"}; + const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc")); + C.addCommand(std::make_unique(JA, T, ResponseFileSupport::None(), Mc, + McArgs, Inputs, Output)); +}