[llvm] [OFFLOAD] Add plugin with support for Intel oneAPI Level Zero (PR #158900)
Alexey Sachkov via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 16 06:23:39 PDT 2025
================
@@ -0,0 +1,625 @@
+//===--- Level Zero Target RTL Implementation -----------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Level Zero Program abstraction
+//
+//===----------------------------------------------------------------------===//
+
+#include <fstream>
+#ifdef _WIN32
+#include <fcntl.h>
+#include <io.h>
+#else
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif // !_WIN32
+
+#include "L0Plugin.h"
+#include "L0Program.h"
+
+namespace llvm::omp::target::plugin {
+
+Error L0GlobalHandlerTy::getGlobalMetadataFromDevice(GenericDeviceTy &Device,
+ DeviceImageTy &Image,
+ GlobalTy &DeviceGlobal) {
+ const char *GlobalName = DeviceGlobal.getName().data();
+
+ L0DeviceTy &l0Device = static_cast<L0DeviceTy &>(Device);
+ const L0ProgramTy *Program =
+ l0Device.getProgramFromImage(Image.getTgtImage());
+ void *Addr = Program->getOffloadVarDeviceAddr(GlobalName);
+
+ // Save the pointer to the symbol allowing nullptr.
+ DeviceGlobal.setPtr(Addr);
+
+ if (Addr == nullptr)
+ return Plugin::error(ErrorCode::UNKNOWN, "Failed to load global '%s'",
+ GlobalName);
+
+ return Plugin::success();
+}
+
+inline L0DeviceTy &L0ProgramTy::getL0Device() const {
+ return L0DeviceTy::makeL0Device(getDevice());
+}
+
+L0ProgramTy::~L0ProgramTy() {
+ for (auto *Kernel : Kernels) {
+ // We need explicit destructor and deallocate calls to release the kernels
+ // created by `GenericDeviceTy::constructKernel()`.
+ Kernel->~L0KernelTy();
+ getL0Device().getPlugin().free(Kernel);
+ }
+ for (auto Module : Modules) {
+ CALL_ZE_RET_VOID(zeModuleDestroy, Module);
+ }
+}
+
+void L0ProgramTy::setLibModule() {
+#if _WIN32
+ return;
+#else
+ const auto *Image = getTgtImage();
+ const size_t NumEntries =
+ static_cast<size_t>(Image->EntriesEnd - Image->EntriesBegin);
+ for (size_t I = 0; I < NumEntries; I++) {
+ const auto &Entry = Image->EntriesBegin[I];
+ // Image contains a kernel, so it is not compiled as a library module
+ if (Entry.SymbolName && Entry.Size == 0)
+ return;
+ }
+ // Check if the image belongs to a dynamic library
+ Dl_info DLI{nullptr};
+ if (dladdr(Image->ImageStart, &DLI) && DLI.dli_fname) {
+ std::vector<uint8_t> FileBin;
+ auto Size = readFile(DLI.dli_fname, FileBin);
+ if (Size) {
+ auto MB = MemoryBuffer::getMemBuffer(
+ StringRef(reinterpret_cast<const char *>(FileBin.data()), Size),
+ /*BufferName=*/"", /*RequiresNullTerminator=*/false);
+ auto ELF = ELFObjectFileBase::createELFObjectFile(MB->getMemBufferRef());
+ if (ELF) {
+ if (auto *Obj = dyn_cast<ELF64LEObjectFile>((*ELF).get())) {
+ const auto Header = Obj->getELFFile().getHeader();
+ if (Header.e_type == ELF::ET_DYN) {
+ DP("Processing current image as library\n");
+ IsLibModule = true;
+ }
+ }
+ }
+ }
+ }
+#endif // _WIN32
+}
+
+int32_t L0ProgramTy::addModule(size_t Size, const uint8_t *Image,
+ const std::string &CommonBuildOptions,
+ ze_module_format_t Format) {
+ const ze_module_constants_t SpecConstants =
+ LevelZeroPluginTy::getOptions().CommonSpecConstants.getModuleConstants();
+ auto &l0Device = getL0Device();
+ std::string BuildOptions(CommonBuildOptions);
+
+ // Add required flag to enable dynamic linking.
+ if (IsLibModule)
+ BuildOptions += " -library-compilation ";
+
+ ze_module_desc_t ModuleDesc{};
+ ModuleDesc.stype = ZE_STRUCTURE_TYPE_MODULE_DESC;
+ ModuleDesc.pNext = nullptr;
+ ModuleDesc.format = Format;
+ ze_module_handle_t Module = nullptr;
+ ze_module_build_log_handle_t BuildLog = nullptr;
+ ze_result_t RC;
+
+ // Build a single module from a single image
+ ModuleDesc.inputSize = Size;
+ ModuleDesc.pInputModule = Image;
+ ModuleDesc.pBuildFlags = BuildOptions.c_str();
+ ModuleDesc.pConstants = &SpecConstants;
+ CALL_ZE_RC(RC, zeModuleCreate, l0Device.getZeContext(),
+ l0Device.getZeDevice(), &ModuleDesc, &Module, &BuildLog);
+
+ const bool BuildFailed = (RC != ZE_RESULT_SUCCESS);
+
+ if (BuildFailed) {
+ if (IsLibModule)
+ return OFFLOAD_SUCCESS;
+ return OFFLOAD_FAIL;
+ } else {
----------------
AlexeySachkov wrote:
[Don't use `else` after `return`](https://llvm.org/docs/CodingStandards.html#don-t-use-else-after-a-return).
The fact that we return `OFFLOAD_SUCCESS` under `BuildFailed&& IsLibModule` condition looks weird. I think that a comment could be added here as to why it is done this way
https://github.com/llvm/llvm-project/pull/158900
More information about the llvm-commits
mailing list