================
@@ -6,24 +6,209 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements offloading to CUDA devices.
+// This file implements offloading to HIP and CUDA devices.
//
//===----------------------------------------------------------------------===//
#include "DeviceOffload.h"
+#include "IncrementalAction.h"
#include "clang/Basic/TargetOptions.h"
-#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/CodeGen/BackendUtil.h"
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Driver/OffloadBundler.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
#include "clang/Interpreter/PartialTranslationUnit.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/TargetParser/AMDGPUTargetParser.h"
+#include "llvm/TargetParser/Host.h"
namespace clang {
+static llvm::Expected<llvm::TargetMachine *>
+getOrCreateTargetMachine(std::unique_ptr<llvm::TargetMachine> &Cache,
+ llvm::Module &M, llvm::StringRef CPU) {
+ if (!Cache) {
+ std::string Error;
+ const llvm::Target *Target =
+ llvm::TargetRegistry::lookupTarget(M.getTargetTriple(), Error);
+ if (!Target)
+ return llvm::make_error<llvm::StringError>(std::move(Error),
+ std::error_code());
+ llvm::TargetOptions TO = llvm::TargetOptions();
+ Cache.reset(Target->createTargetMachine(M.getTargetTriple(), CPU, "", TO,
+ llvm::Reloc::Model::PIC_));
+ }
+ M.setDataLayout(Cache->createDataLayout());
+ return Cache.get();
+}
+
+IncrementalHIPDeviceParser::IncrementalHIPDeviceParser(
+ CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
+ IncrementalAction *DeviceAct,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS,
+ llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
+ : IncrementalParser(DeviceInstance, DeviceAct, Err, PTUs),
+ DeviceCI(DeviceInstance), VFS(FS),
+ CodeGenOpts(HostInstance.getCodeGenOpts()),
+ TargetOpts(DeviceInstance.getTargetOpts()) {
+ if (Err)
+ return;
+ StringRef Arch = TargetOpts.CPU;
+ if (!Arch.starts_with("gfx")) {
+ Err = llvm::joinErrors(std::move(Err), llvm::make_error<llvm::StringError>(
+ "Invalid HIP architecture",
+
llvm::inconvertibleErrorCode()));
+ return;
+ }
+}
+
+llvm::Expected<TranslationUnitDecl *>
+IncrementalHIPDeviceParser::Parse(llvm::StringRef Input) {
+ if (FrontendAction *WrappedAct = Act->getWrapped())
+ if (WrappedAct->hasIRSupport())
+ static_cast<CodeGenAction *>(WrappedAct)->reloadLinkModules(DeviceCI);
+
+ return IncrementalParser::Parse(Input);
+}
+
+llvm::Expected<llvm::StringRef> IncrementalHIPDeviceParser::GenerateHSACO() {
+ auto &PTU = PTUs.back();
+
+ CodeGenOptions CodeGenOptsForObj = DeviceCI.getCodeGenOpts();
+ CodeGenOptsForObj.DisableLLVMPasses = true;
+
+ llvm::SmallVector<char, 0> Object;
+ auto ObjOS = std::make_unique<llvm::raw_svector_ostream>(Object);
+ clang::emitBackendOutput(
+ DeviceCI, CodeGenOptsForObj, DeviceCI.getTarget().getDataLayoutString(),
+ PTU.TheModule.get(), Backend_EmitObj, DeviceCI.getVirtualFileSystemPtr(),
+ std::move(ObjOS));
+
+ std::string Exe = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
+ llvm::StringRef ExeDir = llvm::sys::path::parent_path(Exe);
+ llvm::ErrorOr<std::string> LLDPath =
+ llvm::sys::findProgramByName("ld.lld", {ExeDir});
+ if (!LLDPath)
+ LLDPath = llvm::sys::findProgramByName("ld.lld");
+ if (!LLDPath)
+ return llvm::make_error<llvm::StringError>(
+ "Could not find ld.lld next to the executable or on PATH.",
+ llvm::inconvertibleErrorCode());
+
+ int ObjFD = -1;
+ llvm::SmallString<128> ObjFile;
+ if (llvm::sys::fs::createTemporaryFile("kernel", "o", ObjFD, ObjFile))
+ return llvm::make_error<llvm::StringError>(
+ "Failed to create a temporary object file.",
+ llvm::inconvertibleErrorCode());
+ llvm::FileRemover ObjRemover(ObjFile);
+ {
+ llvm::raw_fd_ostream OS(ObjFD, /*shouldClose=*/true);
+ OS << llvm::StringRef(Object.data(), Object.size());
+ }
+
+ llvm::SmallString<128> HsacoFile;
+ if (llvm::sys::fs::createTemporaryFile("kernel", "hsaco", HsacoFile))
+ return llvm::make_error<llvm::StringError>(
+ "Failed to create a temporary code object file.",
+ llvm::inconvertibleErrorCode());
+ llvm::FileRemover HsacoRemover(HsacoFile);
+
+ llvm::StringRef Args[] = {"ld.lld", "-shared", "--no-undefined",
+ ObjFile, "-o", HsacoFile};
+ if (llvm::sys::ExecuteAndWait(*LLDPath, Args) != 0)
+ return llvm::make_error<llvm::StringError>("ld.lld invocation failed.",
+ llvm::inconvertibleErrorCode());
+
+ auto HsacoBuf = llvm::MemoryBuffer::getFile(HsacoFile, /*IsText=*/false);
+ if (!HsacoBuf)
+ return llvm::make_error<llvm::StringError>(
+ "Failed to read the code object.", llvm::inconvertibleErrorCode());
+
+ llvm::StringRef Buffer = (*HsacoBuf)->getBuffer();
+ HSACOContent.assign(Buffer.begin(), Buffer.end());
+ return llvm::StringRef(HSACOContent.data(), HSACOContent.size());
+}
+
+llvm::Error IncrementalHIPDeviceParser::GenerateOffloadBundle() {
+ static constexpr unsigned CodeObjectAlign = 4096;
+
+ const PartialTranslationUnit &PTU = PTUs.back();
+
+ llvm::SmallString<128> HostFile;
+ if (llvm::sys::fs::createTemporaryFile("hip-host", "", HostFile))
+ return llvm::make_error<llvm::StringError>(
+ "Failed to create a temporary host bundle input.",
+ llvm::inconvertibleErrorCode());
+ llvm::FileRemover HostRemover(HostFile);
+
+ llvm::SmallString<128> DeviceFile;
+ int DeviceFD = -1;
+ if (llvm::sys::fs::createTemporaryFile("hip-device", "hsaco", DeviceFD,
+ DeviceFile))
+ return llvm::make_error<llvm::StringError>(
+ "Failed to create a temporary code object file.",
+ llvm::inconvertibleErrorCode());
+ llvm::FileRemover DeviceRemover(DeviceFile);
+ {
+ llvm::raw_fd_ostream OS(DeviceFD, /*shouldClose=*/true);
+ OS << llvm::StringRef(HSACOContent.data(), HSACOContent.size());
+ }
+
+ llvm::SmallString<128> BundleFile;
+ if (llvm::sys::fs::createTemporaryFile("hip-bundle", "hipfb", BundleFile))
+ return llvm::make_error<llvm::StringError>(
+ "Failed to create a temporary offload bundle file.",
+ llvm::inconvertibleErrorCode());
+ llvm::FileRemover BundleRemover(BundleFile);
+
+ std::string TargetID = llvm::AMDGPU::TargetID::createFromSubtargetFeatures(
+ DeviceCI.getTarget().getTriple(), TargetOpts.CPU,
+ llvm::join(TargetOpts.Features, ","))
+ .getCanonicalTargetIDString();
+
+ std::string HostTriple = "host-" + llvm::sys::getProcessTriple() + "-";
+ std::string DeviceTriple =
+ "hip-" + PTU.TheModule->getTargetTriple().str() + "--" + TargetID;
----------------
AdityaSinha149 wrote:
i have created a new PR #225049 which moves the `normalizeForBundler ` function
from `HIPUtility.cpp` to `OffloadBundler` so that it would be accessible in
`DeviceOffload.cpp`. Please review that and after merging it, I will update
this code to use that function.
https://github.com/llvm/llvm-project/pull/218337
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits