[llvm] [Offload] Use new error code handling mechanism (PR #139275)

Ross Brunton via llvm-commits llvm-commits at lists.llvm.org
Fri May 9 07:52:14 PDT 2025


https://github.com/RossBrunton created https://github.com/llvm/llvm-project/pull/139275

[Offload] Use new error code handling mechanism

This removes the old ErrorCode-less error method and requires
every user to provide a concrete error code. All calls have been
updated.

Depends on https://github.com/llvm/llvm-project/pull/138258 ignore the first 4 commits of this MR.

>From 6ebda46f19a78166b2c4940982eba1fe3104ad29 Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Fri, 2 May 2025 12:50:45 +0100
Subject: [PATCH 1/5] [Offload] Add Error Codes to PluginInterface

A new ErrorCode enumeration is present in PluginInterface which can
be used when returning an llvm::Error from offload and PluginInterface
functions.

This enum must be kept up to sync with liboffload's ol_errc_t enum, so
both are automatically generated from liboffload's enum definition.

Some error codes have also been shuffled around to allow for future
work. Note that this patch only adds the machinery; actual error codes
will be added in a future patch.
---
 offload/liboffload/API/APIDefs.td             |  3 +-
 offload/liboffload/API/CMakeLists.txt         | 10 ++-
 offload/liboffload/API/Common.td              | 22 +++--
 offload/liboffload/CMakeLists.txt             |  2 +
 offload/liboffload/include/OffloadImpl.hpp    | 14 +++-
 .../liboffload/include/generated/OffloadAPI.h | 83 +++++++++----------
 .../include/generated/OffloadPrint.hpp        | 27 +++---
 .../common/include/OffloadErrcodes.inc        | 37 +++++++++
 .../common/include/PluginInterface.h          | 38 ++++++++-
 offload/tools/offload-tblgen/APIGen.cpp       |  3 +
 offload/tools/offload-tblgen/CMakeLists.txt   |  3 +-
 offload/tools/offload-tblgen/Generators.hpp   |  2 +
 .../{FuncsGen.cpp => MiscGen.cpp}             | 24 ++++++
 offload/tools/offload-tblgen/RecordTypes.hpp  |  7 ++
 .../tools/offload-tblgen/offload-tblgen.cpp   | 10 ++-
 15 files changed, 207 insertions(+), 78 deletions(-)
 create mode 100644 offload/plugins-nextgen/common/include/OffloadErrcodes.inc
 rename offload/tools/offload-tblgen/{FuncsGen.cpp => MiscGen.cpp} (75%)

diff --git a/offload/liboffload/API/APIDefs.td b/offload/liboffload/API/APIDefs.td
index 640932dcf8464..38508525f1d26 100644
--- a/offload/liboffload/API/APIDefs.td
+++ b/offload/liboffload/API/APIDefs.td
@@ -152,9 +152,10 @@ class Function : APIObject {
         AddHandleChecksToReturns<params, returns_with_def>.returns_out>.returns_out;
 }
 
-class Etor<string Name, string Desc> {
+class Etor<string Name, string Desc, int Value=-1> {
   string name = Name;
   string desc = Desc;
+  int value = Value;
   string tagged_type;
 }
 
diff --git a/offload/liboffload/API/CMakeLists.txt b/offload/liboffload/API/CMakeLists.txt
index 8fd6cb539374a..62b8803ca2a13 100644
--- a/offload/liboffload/API/CMakeLists.txt
+++ b/offload/liboffload/API/CMakeLists.txt
@@ -11,13 +11,17 @@ if (CLANG_FORMAT)
     tablegen(OFFLOAD OffloadFuncs.inc -gen-func-names)
     tablegen(OFFLOAD OffloadImplFuncDecls.inc -gen-impl-func-decls)
     tablegen(OFFLOAD OffloadPrint.hpp -gen-print-header)
+    tablegen(OFFLOAD OffloadErrcodes.inc -gen-errcodes)
 
-    set(OFFLOAD_GENERATED_FILES ${TABLEGEN_OUTPUT})
+    set(FILES_TO_COPY "OffloadAPI.h;OffloadEntryPoints.inc;OffloadFuncs.inc;OffloadImplFuncDecls.inc;OffloadPrint.hpp")
+    set(GEN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include/generated)
     add_public_tablegen_target(OffloadGenerate)
     add_custom_command(TARGET OffloadGenerate POST_BUILD COMMAND ${CLANG_FORMAT}
-        -i ${OFFLOAD_GENERATED_FILES})
+        -i ${TABLEGEN_OUTPUT})
     add_custom_command(TARGET OffloadGenerate POST_BUILD COMMAND ${CMAKE_COMMAND}
-        -E copy_if_different ${OFFLOAD_GENERATED_FILES} "${CMAKE_CURRENT_SOURCE_DIR}/../include/generated")
+        -E copy_if_different ${FILES_TO_COPY} ${GEN_DIR})
+    add_custom_command(TARGET OffloadGenerate POST_BUILD COMMAND ${CMAKE_COMMAND}
+        -E copy_if_different OffloadErrcodes.inc "${LIBOFFLOAD_ROOT}/../plugins-nextgen/common/include/OffloadErrcodes.inc")
 else()
     message(WARNING "clang-format was not found, so the OffloadGenerate target\
         will not be available. Offload will still build, but you will not be\
diff --git a/offload/liboffload/API/Common.td b/offload/liboffload/API/Common.td
index de7502b540618..12551d1eb5fd5 100644
--- a/offload/liboffload/API/Common.td
+++ b/offload/liboffload/API/Common.td
@@ -83,26 +83,30 @@ def : Typedef {
   let value = "void *";
 }
 
-def : Enum {
+def ErrorCode : Enum {
   let name = "ol_errc_t";
   let desc = "Defines Return/Error codes";
   let etors =[
-    Etor<"SUCCESS", "Success">,
-    Etor<"INVALID_VALUE", "Invalid Value">,
+    Etor<"SUCCESS", "Success", 0>,
+
+    // Universal errors
+    Etor<"INVALID_NULL_POINTER", "A pointer argument is null when it should not be">,
+    Etor<"INVALID_ARGUMENT", "An argument is invalid">,
+    Etor<"OUT_OF_RESOURCES", "Out of resources">,
+    Etor<"UNSUPPORTED", "generic error code for unsupported features and enums">,
+
+    // Liboffload specific errors
+    Etor<"INVALID_VALUE", "Invalid Value", 0x1000>,
     Etor<"INVALID_PLATFORM", "Invalid platform">,
     Etor<"INVALID_DEVICE", "Invalid device">,
     Etor<"INVALID_QUEUE", "Invalid queue">,
     Etor<"INVALID_EVENT", "Invalid event">,
     Etor<"INVALID_KERNEL_NAME", "Named kernel not found in the program binary">,
-    Etor<"OUT_OF_RESOURCES", "Out of resources">,
-    Etor<"UNSUPPORTED_FEATURE", "generic error code for unsupported features">,
-    Etor<"INVALID_ARGUMENT", "generic error code for invalid arguments">,
     Etor<"INVALID_NULL_HANDLE", "handle argument is not valid">,
-    Etor<"INVALID_NULL_POINTER", "pointer argument may not be nullptr">,
     Etor<"INVALID_SIZE", "invalid size or dimensions (e.g., must not be zero, or is out of bounds)">,
     Etor<"INVALID_ENUMERATION", "enumerator argument is not valid">,
-    Etor<"UNSUPPORTED_ENUMERATION", "enumerator argument is not supported by the device">,
-    Etor<"UNKNOWN", "Unknown or internal error">
+
+    Etor<"UNKNOWN", "Unknown or internal error", 0x10000>
   ];
 }
 
diff --git a/offload/liboffload/CMakeLists.txt b/offload/liboffload/CMakeLists.txt
index db12236ddfc7f..9927fa3c3400a 100644
--- a/offload/liboffload/CMakeLists.txt
+++ b/offload/liboffload/CMakeLists.txt
@@ -1,3 +1,5 @@
+set(LIBOFFLOAD_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
+
 add_subdirectory(API)
 
 add_llvm_library(
diff --git a/offload/liboffload/include/OffloadImpl.hpp b/offload/liboffload/include/OffloadImpl.hpp
index 48fdc2b884199..7d2c0c53fc85b 100644
--- a/offload/liboffload/include/OffloadImpl.hpp
+++ b/offload/liboffload/include/OffloadImpl.hpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 #pragma once
 
+#include "PluginInterface.h"
 #include <OffloadAPI.h>
 #include <iostream>
 #include <memory>
@@ -93,9 +94,7 @@ struct ol_impl_result_t {
     ol_errc_t ErrCode;
     llvm::StringRef Details;
     llvm::handleAllErrors(std::move(Error), [&](llvm::StringError &Err) {
-      // TODO: PluginInterface doesn't yet have a way to communicate offload
-      // error codes
-      ErrCode = OL_ERRC_UNKNOWN;
+      ErrCode = GetErrorCode(Err.convertToErrorCode());
       Details = errorStrs().insert(Err.getMessage()).first->getKeyData();
     });
 
@@ -105,5 +104,14 @@ struct ol_impl_result_t {
   operator ol_result_t() { return Result; }
 
 private:
+  static ol_errc_t GetErrorCode(std::error_code Code) {
+    if (Code.category() == llvm::omp::target::plugin::make_error_code(
+                               llvm::omp::target::plugin::ErrorCode::SUCCESS)
+                               .category()) {
+      return static_cast<ol_errc_t>(Code.value());
+    }
+    return OL_ERRC_UNKNOWN;
+  }
+
   ol_result_t Result;
 };
diff --git a/offload/liboffload/include/generated/OffloadAPI.h b/offload/liboffload/include/generated/OffloadAPI.h
index ace31c57cf2f8..13a840ce772fb 100644
--- a/offload/liboffload/include/generated/OffloadAPI.h
+++ b/offload/liboffload/include/generated/OffloadAPI.h
@@ -17,6 +17,45 @@
 extern "C" {
 #endif
 
+///////////////////////////////////////////////////////////////////////////////
+/// @brief Defines Return/Error codes
+typedef enum ol_errc_t {
+  /// Success
+  OL_ERRC_SUCCESS = 0,
+  /// A pointer argument is null when it should not be
+  OL_ERRC_INVALID_NULL_POINTER = 1,
+  /// An argument is invalid
+  OL_ERRC_INVALID_ARGUMENT = 2,
+  /// Out of resources
+  OL_ERRC_OUT_OF_RESOURCES = 3,
+  /// generic error code for unsupported features and enums
+  OL_ERRC_UNSUPPORTED = 4,
+  /// Invalid Value
+  OL_ERRC_INVALID_VALUE = 4096,
+  /// Invalid platform
+  OL_ERRC_INVALID_PLATFORM = 4097,
+  /// Invalid device
+  OL_ERRC_INVALID_DEVICE = 4098,
+  /// Invalid queue
+  OL_ERRC_INVALID_QUEUE = 4099,
+  /// Invalid event
+  OL_ERRC_INVALID_EVENT = 4100,
+  /// Named kernel not found in the program binary
+  OL_ERRC_INVALID_KERNEL_NAME = 4101,
+  /// handle argument is not valid
+  OL_ERRC_INVALID_NULL_HANDLE = 4102,
+  /// invalid size or dimensions (e.g., must not be zero, or is out of bounds)
+  OL_ERRC_INVALID_SIZE = 4103,
+  /// enumerator argument is not valid
+  OL_ERRC_INVALID_ENUMERATION = 4104,
+  /// Unknown or internal error
+  OL_ERRC_UNKNOWN = 65536,
+  /// @cond
+  OL_ERRC_FORCE_UINT32 = 0x7fffffff
+  /// @endcond
+
+} ol_errc_t;
+
 ///////////////////////////////////////////////////////////////////////////////
 #ifndef OL_VERSION_MAJOR
 /// @brief Major version of the Offload API
@@ -101,47 +140,6 @@ typedef struct ol_program_impl_t *ol_program_handle_t;
 /// @brief Handle of kernel object
 typedef void *ol_kernel_handle_t;
 
-///////////////////////////////////////////////////////////////////////////////
-/// @brief Defines Return/Error codes
-typedef enum ol_errc_t {
-  /// Success
-  OL_ERRC_SUCCESS = 0,
-  /// Invalid Value
-  OL_ERRC_INVALID_VALUE = 1,
-  /// Invalid platform
-  OL_ERRC_INVALID_PLATFORM = 2,
-  /// Invalid device
-  OL_ERRC_INVALID_DEVICE = 3,
-  /// Invalid queue
-  OL_ERRC_INVALID_QUEUE = 4,
-  /// Invalid event
-  OL_ERRC_INVALID_EVENT = 5,
-  /// Named kernel not found in the program binary
-  OL_ERRC_INVALID_KERNEL_NAME = 6,
-  /// Out of resources
-  OL_ERRC_OUT_OF_RESOURCES = 7,
-  /// generic error code for unsupported features
-  OL_ERRC_UNSUPPORTED_FEATURE = 8,
-  /// generic error code for invalid arguments
-  OL_ERRC_INVALID_ARGUMENT = 9,
-  /// handle argument is not valid
-  OL_ERRC_INVALID_NULL_HANDLE = 10,
-  /// pointer argument may not be nullptr
-  OL_ERRC_INVALID_NULL_POINTER = 11,
-  /// invalid size or dimensions (e.g., must not be zero, or is out of bounds)
-  OL_ERRC_INVALID_SIZE = 12,
-  /// enumerator argument is not valid
-  OL_ERRC_INVALID_ENUMERATION = 13,
-  /// enumerator argument is not supported by the device
-  OL_ERRC_UNSUPPORTED_ENUMERATION = 14,
-  /// Unknown or internal error
-  OL_ERRC_UNKNOWN = 15,
-  /// @cond
-  OL_ERRC_FORCE_UINT32 = 0x7fffffff
-  /// @endcond
-
-} ol_errc_t;
-
 ///////////////////////////////////////////////////////////////////////////////
 /// @brief Details of the error condition returned by an API call
 typedef struct ol_error_struct_t {
@@ -477,7 +475,8 @@ OL_APIEXPORT ol_result_t OL_APICALL olMemFree(
 /// @brief Enqueue a memcpy operation.
 ///
 /// @details
-///    - For host pointers, use the device returned by olGetHostDevice
+///    - For host pointers, use the host device belonging to the
+///    OL_PLATFORM_BACKEND_HOST platform.
 ///    - If a queue is specified, at least one device must be a non-host device
 ///    - If a queue is not specified, the memcpy happens synchronously
 ///
diff --git a/offload/liboffload/include/generated/OffloadPrint.hpp b/offload/liboffload/include/generated/OffloadPrint.hpp
index 7f5e33aea6f73..e99bb2db669fb 100644
--- a/offload/liboffload/include/generated/OffloadPrint.hpp
+++ b/offload/liboffload/include/generated/OffloadPrint.hpp
@@ -49,6 +49,18 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
   case OL_ERRC_SUCCESS:
     os << "OL_ERRC_SUCCESS";
     break;
+  case OL_ERRC_INVALID_NULL_POINTER:
+    os << "OL_ERRC_INVALID_NULL_POINTER";
+    break;
+  case OL_ERRC_INVALID_ARGUMENT:
+    os << "OL_ERRC_INVALID_ARGUMENT";
+    break;
+  case OL_ERRC_OUT_OF_RESOURCES:
+    os << "OL_ERRC_OUT_OF_RESOURCES";
+    break;
+  case OL_ERRC_UNSUPPORTED:
+    os << "OL_ERRC_UNSUPPORTED";
+    break;
   case OL_ERRC_INVALID_VALUE:
     os << "OL_ERRC_INVALID_VALUE";
     break;
@@ -67,30 +79,15 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
   case OL_ERRC_INVALID_KERNEL_NAME:
     os << "OL_ERRC_INVALID_KERNEL_NAME";
     break;
-  case OL_ERRC_OUT_OF_RESOURCES:
-    os << "OL_ERRC_OUT_OF_RESOURCES";
-    break;
-  case OL_ERRC_UNSUPPORTED_FEATURE:
-    os << "OL_ERRC_UNSUPPORTED_FEATURE";
-    break;
-  case OL_ERRC_INVALID_ARGUMENT:
-    os << "OL_ERRC_INVALID_ARGUMENT";
-    break;
   case OL_ERRC_INVALID_NULL_HANDLE:
     os << "OL_ERRC_INVALID_NULL_HANDLE";
     break;
-  case OL_ERRC_INVALID_NULL_POINTER:
-    os << "OL_ERRC_INVALID_NULL_POINTER";
-    break;
   case OL_ERRC_INVALID_SIZE:
     os << "OL_ERRC_INVALID_SIZE";
     break;
   case OL_ERRC_INVALID_ENUMERATION:
     os << "OL_ERRC_INVALID_ENUMERATION";
     break;
-  case OL_ERRC_UNSUPPORTED_ENUMERATION:
-    os << "OL_ERRC_UNSUPPORTED_ENUMERATION";
-    break;
   case OL_ERRC_UNKNOWN:
     os << "OL_ERRC_UNKNOWN";
     break;
diff --git a/offload/plugins-nextgen/common/include/OffloadErrcodes.inc b/offload/plugins-nextgen/common/include/OffloadErrcodes.inc
new file mode 100644
index 0000000000000..146a2cd0ce0bf
--- /dev/null
+++ b/offload/plugins-nextgen/common/include/OffloadErrcodes.inc
@@ -0,0 +1,37 @@
+//===- Auto-generated file, part of the LLVM/Offload project --------------===//
+//
+// 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 OFFLOAD_ERRC
+#error Please define the macro OFFLOAD_ERRCODE(Name, Desc, Value)
+#endif
+
+// Error codes are shared between PluginInterface and liboffload.
+// To add new error codes, add them to offload/liboffload/API/Common.td and run
+// the GenerateOffload target.
+
+OFFLOAD_ERRC(SUCCESS, "Success", 0)
+OFFLOAD_ERRC(INVALID_NULL_POINTER,
+             "A pointer argument is null when it should not be", 1)
+OFFLOAD_ERRC(INVALID_ARGUMENT, "An argument is invalid", 2)
+OFFLOAD_ERRC(OUT_OF_RESOURCES, "Out of resources", 3)
+OFFLOAD_ERRC(UNSUPPORTED,
+             "generic error code for unsupported features and enums", 4)
+OFFLOAD_ERRC(INVALID_VALUE, "Invalid Value", 4096)
+OFFLOAD_ERRC(INVALID_PLATFORM, "Invalid platform", 4097)
+OFFLOAD_ERRC(INVALID_DEVICE, "Invalid device", 4098)
+OFFLOAD_ERRC(INVALID_QUEUE, "Invalid queue", 4099)
+OFFLOAD_ERRC(INVALID_EVENT, "Invalid event", 4100)
+OFFLOAD_ERRC(INVALID_KERNEL_NAME,
+             "Named kernel not found in the program binary", 4101)
+OFFLOAD_ERRC(INVALID_NULL_HANDLE, "handle argument is not valid", 4102)
+OFFLOAD_ERRC(
+    INVALID_SIZE,
+    "invalid size or dimensions (e.g., must not be zero, or is out of bounds)",
+    4103)
+OFFLOAD_ERRC(INVALID_ENUMERATION, "enumerator argument is not valid", 4104)
+OFFLOAD_ERRC(UNKNOWN, "Unknown or internal error", 65536)
diff --git a/offload/plugins-nextgen/common/include/PluginInterface.h b/offload/plugins-nextgen/common/include/PluginInterface.h
index e54a8afdd3f4f..19fe26b10760b 100644
--- a/offload/plugins-nextgen/common/include/PluginInterface.h
+++ b/offload/plugins-nextgen/common/include/PluginInterface.h
@@ -58,6 +58,30 @@ struct GenericKernelTy;
 struct GenericDeviceTy;
 struct RecordReplayTy;
 
+enum class ErrorCode {
+#define OFFLOAD_ERRC(Name, _, Value) Name = Value,
+#include "OffloadErrcodes.inc"
+#undef OFFLOAD_ERRC
+};
+
+class OffloadErrorCategory : public std::error_category {
+  const char *name() const noexcept override { return "Offload Error"; }
+  std::string message(int ev) const override {
+    switch (static_cast<ErrorCode>(ev)) {
+#define OFFLOAD_ERRC(Name, Desc, Value)                                        \
+  case ErrorCode::Name:                                                        \
+    return #Desc;
+#include "OffloadErrcodes.inc"
+#undef OFFLOAD_ERRC
+    }
+  }
+};
+
+inline std::error_code make_error_code(ErrorCode EC) {
+  static OffloadErrorCategory Cat{};
+  return {static_cast<int>(EC), Cat};
+}
+
 /// Class that wraps the __tgt_async_info to simply its usage. In case the
 /// object is constructed without a valid __tgt_async_info, the object will use
 /// an internal one and will synchronize the current thread with the pending
@@ -1385,7 +1409,13 @@ static inline Error success() { return Error::success(); }
 /// Create a string error.
 template <typename... ArgsTy>
 static Error error(const char *ErrFmt, ArgsTy... Args) {
-  return createStringError(inconvertibleErrorCode(), ErrFmt, Args...);
+  return createStringError(ErrorCode::UNKNOWN, ErrFmt, Args...);
+}
+
+/// Create a string error.
+template <typename... ArgsTy>
+static Error error(ErrorCode Code, const char *ErrFmt, ArgsTy... Args) {
+  return createStringError(Code, ErrFmt, Args...);
 }
 
 /// Check the plugin-specific error code and return an error or success
@@ -1596,4 +1626,10 @@ template <typename ResourceRef> class GenericDeviceResourceManagerTy {
 } // namespace omp
 } // namespace llvm
 
+namespace std {
+template <>
+struct is_error_code_enum<llvm::omp::target::plugin::ErrorCode>
+    : std::true_type {};
+} // namespace std
+
 #endif // OPENMP_LIBOMPTARGET_PLUGINS_COMMON_PLUGININTERFACE_H
diff --git a/offload/tools/offload-tblgen/APIGen.cpp b/offload/tools/offload-tblgen/APIGen.cpp
index 800c9cadfe38b..14f8435c578d7 100644
--- a/offload/tools/offload-tblgen/APIGen.cpp
+++ b/offload/tools/offload-tblgen/APIGen.cpp
@@ -132,6 +132,9 @@ static void ProcessEnum(const EnumRec &Enum, raw_ostream &OS) {
 
   uint32_t EtorVal = 0;
   for (const auto &EnumVal : Enum.getValues()) {
+    if (auto NewVal = EnumVal.getEnumValue()) {
+      EtorVal = *NewVal;
+    }
     if (Enum.isTyped()) {
       OS << MakeComment(
           formatv("[{0}] {1}", EnumVal.getTaggedType(), EnumVal.getDesc())
diff --git a/offload/tools/offload-tblgen/CMakeLists.txt b/offload/tools/offload-tblgen/CMakeLists.txt
index e7e7c85490543..613b166d62b4d 100644
--- a/offload/tools/offload-tblgen/CMakeLists.txt
+++ b/offload/tools/offload-tblgen/CMakeLists.txt
@@ -13,7 +13,7 @@ add_tablegen(offload-tblgen OFFLOAD
   EXPORT OFFLOAD
   APIGen.cpp
   EntryPointGen.cpp
-  FuncsGen.cpp
+  MiscGen.cpp
   GenCommon.hpp
   Generators.hpp
   offload-tblgen.cpp
@@ -23,4 +23,3 @@ add_tablegen(offload-tblgen OFFLOAD
 
 set(OFFLOAD_TABLEGEN_EXE "${OFFLOAD_TABLEGEN_EXE}" CACHE INTERNAL "")
 set(OFFLOAD_TABLEGEN_TARGET "${OFFLOAD_TABLEGEN_TARGET}" CACHE INTERNAL "")
-
diff --git a/offload/tools/offload-tblgen/Generators.hpp b/offload/tools/offload-tblgen/Generators.hpp
index 8b6104c5cd9c6..f3474dfc52e86 100644
--- a/offload/tools/offload-tblgen/Generators.hpp
+++ b/offload/tools/offload-tblgen/Generators.hpp
@@ -21,3 +21,5 @@ void EmitOffloadPrintHeader(const llvm::RecordKeeper &Records,
                             llvm::raw_ostream &OS);
 void EmitOffloadExports(const llvm::RecordKeeper &Records,
                         llvm::raw_ostream &OS);
+void EmitOffloadErrcodes(const llvm::RecordKeeper &Records,
+                         llvm::raw_ostream &OS);
diff --git a/offload/tools/offload-tblgen/FuncsGen.cpp b/offload/tools/offload-tblgen/MiscGen.cpp
similarity index 75%
rename from offload/tools/offload-tblgen/FuncsGen.cpp
rename to offload/tools/offload-tblgen/MiscGen.cpp
index 3238652176198..e0e12ab3af714 100644
--- a/offload/tools/offload-tblgen/FuncsGen.cpp
+++ b/offload/tools/offload-tblgen/MiscGen.cpp
@@ -72,3 +72,27 @@ void EmitOffloadImplFuncDecls(const RecordKeeper &Records, raw_ostream &OS) {
     OS << ");\n\n";
   }
 }
+
+// Emit macro calls for each error enum
+void EmitOffloadErrcodes(const RecordKeeper &Records, raw_ostream &OS) {
+  OS << GenericHeader;
+  OS << R"(
+#ifndef OFFLOAD_ERRC
+#error Please define the macro OFFLOAD_ERRCODE(Name, Desc, Value)
+#endif
+
+// Error codes are shared between PluginInterface and liboffload.
+// To add new error codes, add them to offload/liboffload/API/Common.td and run the GenerateOffload target.
+
+)";
+
+  auto ErrorCodeEnum = EnumRec{Records.getDef("ErrorCode")};
+  uint32_t EtorVal = 0;
+  for (const auto &EnumVal : ErrorCodeEnum.getValues()) {
+    if (auto NewVal = EnumVal.getEnumValue()) {
+      EtorVal = *NewVal;
+    }
+    OS << formatv(TAB_1 "OFFLOAD_ERRC({0}, \"{1}\", {2})\n", EnumVal.getName(),
+                  EnumVal.getDesc(), EtorVal++);
+  }
+}
diff --git a/offload/tools/offload-tblgen/RecordTypes.hpp b/offload/tools/offload-tblgen/RecordTypes.hpp
index 686634ed778aa..5969ec311b28e 100644
--- a/offload/tools/offload-tblgen/RecordTypes.hpp
+++ b/offload/tools/offload-tblgen/RecordTypes.hpp
@@ -69,6 +69,13 @@ class EnumValueRec {
   StringRef getTaggedType() const {
     return rec->getValueAsString("tagged_type");
   }
+  std::optional<uint32_t> getEnumValue() const {
+    if (rec->getValueAsInt("value") == -1) {
+      return std::nullopt;
+    } else {
+      return rec->getValueAsInt("value");
+    }
+  }
 
 private:
   const Record *rec;
diff --git a/offload/tools/offload-tblgen/offload-tblgen.cpp b/offload/tools/offload-tblgen/offload-tblgen.cpp
index 1912abf5265c7..83a4af04b8b22 100644
--- a/offload/tools/offload-tblgen/offload-tblgen.cpp
+++ b/offload/tools/offload-tblgen/offload-tblgen.cpp
@@ -30,7 +30,8 @@ enum ActionType {
   GenImplFuncDecls,
   GenEntryPoints,
   GenPrintHeader,
-  GenExports
+  GenExports,
+  GenErrcodes,
 };
 
 namespace {
@@ -52,7 +53,9 @@ cl::opt<ActionType> Action(
         clEnumValN(GenPrintHeader, "gen-print-header",
                    "Generate Offload API print header"),
         clEnumValN(GenExports, "gen-exports",
-                   "Generate export file for the Offload library")));
+                   "Generate export file for the Offload library"),
+        clEnumValN(GenErrcodes, "gen-errcodes",
+                   "Generate Offload Error Code enum")));
 }
 
 static bool OffloadTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
@@ -81,6 +84,9 @@ static bool OffloadTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
   case GenExports:
     EmitOffloadExports(Records, OS);
     break;
+  case GenErrcodes:
+    EmitOffloadErrcodes(Records, OS);
+    break;
   }
 
   return false;

>From 5850cb9ec404f11499cbc7fa2cdf0c0fbdfb7057 Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Mon, 5 May 2025 11:18:49 +0100
Subject: [PATCH 2/5] [Offload] Don't partition error code enum into categories

---
 offload/liboffload/API/APIDefs.td             |  3 +-
 offload/liboffload/API/Common.td              | 17 +++++----
 .../liboffload/include/generated/OffloadAPI.h | 36 +++++++++----------
 .../include/generated/OffloadPrint.hpp        | 24 ++++++-------
 .../common/include/OffloadErrcodes.inc        | 30 ++++++++--------
 offload/tools/offload-tblgen/APIGen.cpp       |  3 --
 offload/tools/offload-tblgen/MiscGen.cpp      |  3 --
 offload/tools/offload-tblgen/RecordTypes.hpp  |  7 ----
 8 files changed, 54 insertions(+), 69 deletions(-)

diff --git a/offload/liboffload/API/APIDefs.td b/offload/liboffload/API/APIDefs.td
index 38508525f1d26..640932dcf8464 100644
--- a/offload/liboffload/API/APIDefs.td
+++ b/offload/liboffload/API/APIDefs.td
@@ -152,10 +152,9 @@ class Function : APIObject {
         AddHandleChecksToReturns<params, returns_with_def>.returns_out>.returns_out;
 }
 
-class Etor<string Name, string Desc, int Value=-1> {
+class Etor<string Name, string Desc> {
   string name = Name;
   string desc = Desc;
-  int value = Value;
   string tagged_type;
 }
 
diff --git a/offload/liboffload/API/Common.td b/offload/liboffload/API/Common.td
index 12551d1eb5fd5..d19c9c662faec 100644
--- a/offload/liboffload/API/Common.td
+++ b/offload/liboffload/API/Common.td
@@ -87,26 +87,25 @@ def ErrorCode : Enum {
   let name = "ol_errc_t";
   let desc = "Defines Return/Error codes";
   let etors =[
-    Etor<"SUCCESS", "Success", 0>,
+    Etor<"SUCCESS", "Success">,
 
     // Universal errors
+    Etor<"UNKNOWN", "Unknown or internal error">,
     Etor<"INVALID_NULL_POINTER", "A pointer argument is null when it should not be">,
     Etor<"INVALID_ARGUMENT", "An argument is invalid">,
     Etor<"OUT_OF_RESOURCES", "Out of resources">,
     Etor<"UNSUPPORTED", "generic error code for unsupported features and enums">,
+    Etor<"INVALID_SIZE", "invalid size or dimensions (e.g., must not be zero, or is out of bounds)">,
+    Etor<"INVALID_ENUMERATION", "enumerator argument is not valid">,
+    Etor<"INVALID_KERNEL_NAME", "Named kernel not found in the program binary">,
 
-    // Liboffload specific errors
-    Etor<"INVALID_VALUE", "Invalid Value", 0x1000>,
+    // Handle related errors - only makes sense for liboffload
+    Etor<"INVALID_VALUE", "Invalid Value">,
     Etor<"INVALID_PLATFORM", "Invalid platform">,
     Etor<"INVALID_DEVICE", "Invalid device">,
     Etor<"INVALID_QUEUE", "Invalid queue">,
     Etor<"INVALID_EVENT", "Invalid event">,
-    Etor<"INVALID_KERNEL_NAME", "Named kernel not found in the program binary">,
-    Etor<"INVALID_NULL_HANDLE", "handle argument is not valid">,
-    Etor<"INVALID_SIZE", "invalid size or dimensions (e.g., must not be zero, or is out of bounds)">,
-    Etor<"INVALID_ENUMERATION", "enumerator argument is not valid">,
-
-    Etor<"UNKNOWN", "Unknown or internal error", 0x10000>
+    Etor<"INVALID_NULL_HANDLE", "handle argument is not valid">
   ];
 }
 
diff --git a/offload/liboffload/include/generated/OffloadAPI.h b/offload/liboffload/include/generated/OffloadAPI.h
index 13a840ce772fb..66ea48c8ca14f 100644
--- a/offload/liboffload/include/generated/OffloadAPI.h
+++ b/offload/liboffload/include/generated/OffloadAPI.h
@@ -22,34 +22,34 @@ extern "C" {
 typedef enum ol_errc_t {
   /// Success
   OL_ERRC_SUCCESS = 0,
+  /// Unknown or internal error
+  OL_ERRC_UNKNOWN = 1,
   /// A pointer argument is null when it should not be
-  OL_ERRC_INVALID_NULL_POINTER = 1,
+  OL_ERRC_INVALID_NULL_POINTER = 2,
   /// An argument is invalid
-  OL_ERRC_INVALID_ARGUMENT = 2,
+  OL_ERRC_INVALID_ARGUMENT = 3,
   /// Out of resources
-  OL_ERRC_OUT_OF_RESOURCES = 3,
+  OL_ERRC_OUT_OF_RESOURCES = 4,
   /// generic error code for unsupported features and enums
-  OL_ERRC_UNSUPPORTED = 4,
+  OL_ERRC_UNSUPPORTED = 5,
+  /// invalid size or dimensions (e.g., must not be zero, or is out of bounds)
+  OL_ERRC_INVALID_SIZE = 6,
+  /// enumerator argument is not valid
+  OL_ERRC_INVALID_ENUMERATION = 7,
+  /// Named kernel not found in the program binary
+  OL_ERRC_INVALID_KERNEL_NAME = 8,
   /// Invalid Value
-  OL_ERRC_INVALID_VALUE = 4096,
+  OL_ERRC_INVALID_VALUE = 9,
   /// Invalid platform
-  OL_ERRC_INVALID_PLATFORM = 4097,
+  OL_ERRC_INVALID_PLATFORM = 10,
   /// Invalid device
-  OL_ERRC_INVALID_DEVICE = 4098,
+  OL_ERRC_INVALID_DEVICE = 11,
   /// Invalid queue
-  OL_ERRC_INVALID_QUEUE = 4099,
+  OL_ERRC_INVALID_QUEUE = 12,
   /// Invalid event
-  OL_ERRC_INVALID_EVENT = 4100,
-  /// Named kernel not found in the program binary
-  OL_ERRC_INVALID_KERNEL_NAME = 4101,
+  OL_ERRC_INVALID_EVENT = 13,
   /// handle argument is not valid
-  OL_ERRC_INVALID_NULL_HANDLE = 4102,
-  /// invalid size or dimensions (e.g., must not be zero, or is out of bounds)
-  OL_ERRC_INVALID_SIZE = 4103,
-  /// enumerator argument is not valid
-  OL_ERRC_INVALID_ENUMERATION = 4104,
-  /// Unknown or internal error
-  OL_ERRC_UNKNOWN = 65536,
+  OL_ERRC_INVALID_NULL_HANDLE = 14,
   /// @cond
   OL_ERRC_FORCE_UINT32 = 0x7fffffff
   /// @endcond
diff --git a/offload/liboffload/include/generated/OffloadPrint.hpp b/offload/liboffload/include/generated/OffloadPrint.hpp
index e99bb2db669fb..af5ca0a96b509 100644
--- a/offload/liboffload/include/generated/OffloadPrint.hpp
+++ b/offload/liboffload/include/generated/OffloadPrint.hpp
@@ -49,6 +49,9 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
   case OL_ERRC_SUCCESS:
     os << "OL_ERRC_SUCCESS";
     break;
+  case OL_ERRC_UNKNOWN:
+    os << "OL_ERRC_UNKNOWN";
+    break;
   case OL_ERRC_INVALID_NULL_POINTER:
     os << "OL_ERRC_INVALID_NULL_POINTER";
     break;
@@ -61,6 +64,15 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
   case OL_ERRC_UNSUPPORTED:
     os << "OL_ERRC_UNSUPPORTED";
     break;
+  case OL_ERRC_INVALID_SIZE:
+    os << "OL_ERRC_INVALID_SIZE";
+    break;
+  case OL_ERRC_INVALID_ENUMERATION:
+    os << "OL_ERRC_INVALID_ENUMERATION";
+    break;
+  case OL_ERRC_INVALID_KERNEL_NAME:
+    os << "OL_ERRC_INVALID_KERNEL_NAME";
+    break;
   case OL_ERRC_INVALID_VALUE:
     os << "OL_ERRC_INVALID_VALUE";
     break;
@@ -76,21 +88,9 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
   case OL_ERRC_INVALID_EVENT:
     os << "OL_ERRC_INVALID_EVENT";
     break;
-  case OL_ERRC_INVALID_KERNEL_NAME:
-    os << "OL_ERRC_INVALID_KERNEL_NAME";
-    break;
   case OL_ERRC_INVALID_NULL_HANDLE:
     os << "OL_ERRC_INVALID_NULL_HANDLE";
     break;
-  case OL_ERRC_INVALID_SIZE:
-    os << "OL_ERRC_INVALID_SIZE";
-    break;
-  case OL_ERRC_INVALID_ENUMERATION:
-    os << "OL_ERRC_INVALID_ENUMERATION";
-    break;
-  case OL_ERRC_UNKNOWN:
-    os << "OL_ERRC_UNKNOWN";
-    break;
   default:
     os << "unknown enumerator";
     break;
diff --git a/offload/plugins-nextgen/common/include/OffloadErrcodes.inc b/offload/plugins-nextgen/common/include/OffloadErrcodes.inc
index 146a2cd0ce0bf..217565647c4e1 100644
--- a/offload/plugins-nextgen/common/include/OffloadErrcodes.inc
+++ b/offload/plugins-nextgen/common/include/OffloadErrcodes.inc
@@ -15,23 +15,23 @@
 // the GenerateOffload target.
 
 OFFLOAD_ERRC(SUCCESS, "Success", 0)
+OFFLOAD_ERRC(UNKNOWN, "Unknown or internal error", 1)
 OFFLOAD_ERRC(INVALID_NULL_POINTER,
-             "A pointer argument is null when it should not be", 1)
-OFFLOAD_ERRC(INVALID_ARGUMENT, "An argument is invalid", 2)
-OFFLOAD_ERRC(OUT_OF_RESOURCES, "Out of resources", 3)
+             "A pointer argument is null when it should not be", 2)
+OFFLOAD_ERRC(INVALID_ARGUMENT, "An argument is invalid", 3)
+OFFLOAD_ERRC(OUT_OF_RESOURCES, "Out of resources", 4)
 OFFLOAD_ERRC(UNSUPPORTED,
-             "generic error code for unsupported features and enums", 4)
-OFFLOAD_ERRC(INVALID_VALUE, "Invalid Value", 4096)
-OFFLOAD_ERRC(INVALID_PLATFORM, "Invalid platform", 4097)
-OFFLOAD_ERRC(INVALID_DEVICE, "Invalid device", 4098)
-OFFLOAD_ERRC(INVALID_QUEUE, "Invalid queue", 4099)
-OFFLOAD_ERRC(INVALID_EVENT, "Invalid event", 4100)
-OFFLOAD_ERRC(INVALID_KERNEL_NAME,
-             "Named kernel not found in the program binary", 4101)
-OFFLOAD_ERRC(INVALID_NULL_HANDLE, "handle argument is not valid", 4102)
+             "generic error code for unsupported features and enums", 5)
 OFFLOAD_ERRC(
     INVALID_SIZE,
     "invalid size or dimensions (e.g., must not be zero, or is out of bounds)",
-    4103)
-OFFLOAD_ERRC(INVALID_ENUMERATION, "enumerator argument is not valid", 4104)
-OFFLOAD_ERRC(UNKNOWN, "Unknown or internal error", 65536)
+    6)
+OFFLOAD_ERRC(INVALID_ENUMERATION, "enumerator argument is not valid", 7)
+OFFLOAD_ERRC(INVALID_KERNEL_NAME,
+             "Named kernel not found in the program binary", 8)
+OFFLOAD_ERRC(INVALID_VALUE, "Invalid Value", 9)
+OFFLOAD_ERRC(INVALID_PLATFORM, "Invalid platform", 10)
+OFFLOAD_ERRC(INVALID_DEVICE, "Invalid device", 11)
+OFFLOAD_ERRC(INVALID_QUEUE, "Invalid queue", 12)
+OFFLOAD_ERRC(INVALID_EVENT, "Invalid event", 13)
+OFFLOAD_ERRC(INVALID_NULL_HANDLE, "handle argument is not valid", 14)
diff --git a/offload/tools/offload-tblgen/APIGen.cpp b/offload/tools/offload-tblgen/APIGen.cpp
index 14f8435c578d7..800c9cadfe38b 100644
--- a/offload/tools/offload-tblgen/APIGen.cpp
+++ b/offload/tools/offload-tblgen/APIGen.cpp
@@ -132,9 +132,6 @@ static void ProcessEnum(const EnumRec &Enum, raw_ostream &OS) {
 
   uint32_t EtorVal = 0;
   for (const auto &EnumVal : Enum.getValues()) {
-    if (auto NewVal = EnumVal.getEnumValue()) {
-      EtorVal = *NewVal;
-    }
     if (Enum.isTyped()) {
       OS << MakeComment(
           formatv("[{0}] {1}", EnumVal.getTaggedType(), EnumVal.getDesc())
diff --git a/offload/tools/offload-tblgen/MiscGen.cpp b/offload/tools/offload-tblgen/MiscGen.cpp
index e0e12ab3af714..b73d70d58c239 100644
--- a/offload/tools/offload-tblgen/MiscGen.cpp
+++ b/offload/tools/offload-tblgen/MiscGen.cpp
@@ -89,9 +89,6 @@ void EmitOffloadErrcodes(const RecordKeeper &Records, raw_ostream &OS) {
   auto ErrorCodeEnum = EnumRec{Records.getDef("ErrorCode")};
   uint32_t EtorVal = 0;
   for (const auto &EnumVal : ErrorCodeEnum.getValues()) {
-    if (auto NewVal = EnumVal.getEnumValue()) {
-      EtorVal = *NewVal;
-    }
     OS << formatv(TAB_1 "OFFLOAD_ERRC({0}, \"{1}\", {2})\n", EnumVal.getName(),
                   EnumVal.getDesc(), EtorVal++);
   }
diff --git a/offload/tools/offload-tblgen/RecordTypes.hpp b/offload/tools/offload-tblgen/RecordTypes.hpp
index 5969ec311b28e..686634ed778aa 100644
--- a/offload/tools/offload-tblgen/RecordTypes.hpp
+++ b/offload/tools/offload-tblgen/RecordTypes.hpp
@@ -69,13 +69,6 @@ class EnumValueRec {
   StringRef getTaggedType() const {
     return rec->getValueAsString("tagged_type");
   }
-  std::optional<uint32_t> getEnumValue() const {
-    if (rec->getValueAsInt("value") == -1) {
-      return std::nullopt;
-    } else {
-      return rec->getValueAsInt("value");
-    }
-  }
 
 private:
   const Record *rec;

>From e8e6651859415f054d1c00876f0b23caeccfb53c Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Wed, 7 May 2025 14:50:39 +0100
Subject: [PATCH 3/5] [Offload] Follow other LLVM error code handling

---
 offload/plugins-nextgen/common/CMakeLists.txt |  1 +
 .../common/include/OffloadError.h             | 76 +++++++++++++++++++
 .../common/include/PluginInterface.h          | 52 ++++---------
 .../common/src/OffloadError.cpp               | 40 ++++++++++
 4 files changed, 133 insertions(+), 36 deletions(-)
 create mode 100644 offload/plugins-nextgen/common/include/OffloadError.h
 create mode 100644 offload/plugins-nextgen/common/src/OffloadError.cpp

diff --git a/offload/plugins-nextgen/common/CMakeLists.txt b/offload/plugins-nextgen/common/CMakeLists.txt
index ffc431f68dbc5..2fcfaf8225a63 100644
--- a/offload/plugins-nextgen/common/CMakeLists.txt
+++ b/offload/plugins-nextgen/common/CMakeLists.txt
@@ -5,6 +5,7 @@ add_library(PluginCommon OBJECT
   src/GlobalHandler.cpp
   src/JIT.cpp
   src/RPC.cpp
+  src/OffloadError.cpp
   src/Utils/ELF.cpp
 )
 add_dependencies(PluginCommon intrinsics_gen)
diff --git a/offload/plugins-nextgen/common/include/OffloadError.h b/offload/plugins-nextgen/common/include/OffloadError.h
new file mode 100644
index 0000000000000..2b0f49cdf7262
--- /dev/null
+++ b/offload/plugins-nextgen/common/include/OffloadError.h
@@ -0,0 +1,76 @@
+//===- OffloadError.h - Definition of error class -------------------------===//
+//
+// 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 OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_OFFLOAD_ERROR_H
+#define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_OFFLOAD_ERROR_H
+
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace llvm {
+namespace omp {
+namespace target {
+namespace plugin {
+
+enum class ErrorCode {
+#define OFFLOAD_ERRC(Name, _, Value) Name = Value,
+#include "OffloadErrcodes.inc"
+#undef OFFLOAD_ERRC
+};
+
+class OffloadErrorCategory : public std::error_category {
+  const char *name() const noexcept override { return "Offload Error"; }
+  std::string message(int ev) const override {
+    switch (static_cast<ErrorCode>(ev)) {
+#define OFFLOAD_ERRC(Name, Desc, Value)                                        \
+  case ErrorCode::Name:                                                        \
+    return #Desc;
+#include "OffloadErrcodes.inc"
+#undef OFFLOAD_ERRC
+    }
+  }
+};
+} // namespace plugin
+} // namespace target
+} // namespace omp
+} // namespace llvm
+
+namespace std {
+template <>
+struct is_error_code_enum<llvm::omp::target::plugin::ErrorCode>
+    : std::true_type {};
+} // namespace std
+
+namespace llvm {
+namespace omp {
+namespace target {
+namespace plugin {
+
+const std::error_category &OffloadErrCategory();
+
+inline std::error_code make_error_code(ErrorCode E) {
+  return std::error_code(static_cast<int>(E), OffloadErrCategory());
+}
+
+/// Base class for errors originating in DIA SDK, e.g. COM calls
+class OffloadError : public ErrorInfo<OffloadError, StringError> {
+public:
+  using ErrorInfo<OffloadError, StringError>::ErrorInfo;
+
+  OffloadError(const Twine &S) : ErrorInfo(S, ErrorCode::UNKNOWN) {}
+
+  static char ID;
+};
+} // namespace plugin
+} // namespace target
+} // namespace omp
+} // namespace llvm
+
+#endif
diff --git a/offload/plugins-nextgen/common/include/PluginInterface.h b/offload/plugins-nextgen/common/include/PluginInterface.h
index 19fe26b10760b..899ae0f9be3f5 100644
--- a/offload/plugins-nextgen/common/include/PluginInterface.h
+++ b/offload/plugins-nextgen/common/include/PluginInterface.h
@@ -30,6 +30,7 @@
 #include "GlobalHandler.h"
 #include "JIT.h"
 #include "MemoryManager.h"
+#include "OffloadError.h"
 #include "RPC.h"
 #include "omptarget.h"
 
@@ -58,30 +59,6 @@ struct GenericKernelTy;
 struct GenericDeviceTy;
 struct RecordReplayTy;
 
-enum class ErrorCode {
-#define OFFLOAD_ERRC(Name, _, Value) Name = Value,
-#include "OffloadErrcodes.inc"
-#undef OFFLOAD_ERRC
-};
-
-class OffloadErrorCategory : public std::error_category {
-  const char *name() const noexcept override { return "Offload Error"; }
-  std::string message(int ev) const override {
-    switch (static_cast<ErrorCode>(ev)) {
-#define OFFLOAD_ERRC(Name, Desc, Value)                                        \
-  case ErrorCode::Name:                                                        \
-    return #Desc;
-#include "OffloadErrcodes.inc"
-#undef OFFLOAD_ERRC
-    }
-  }
-};
-
-inline std::error_code make_error_code(ErrorCode EC) {
-  static OffloadErrorCategory Cat{};
-  return {static_cast<int>(EC), Cat};
-}
-
 /// Class that wraps the __tgt_async_info to simply its usage. In case the
 /// object is constructed without a valid __tgt_async_info, the object will use
 /// an internal one and will synchronize the current thread with the pending
@@ -1406,16 +1383,25 @@ namespace Plugin {
 /// Plugin::check().
 static inline Error success() { return Error::success(); }
 
-/// Create a string error.
+/// Create an Offload error.
 template <typename... ArgsTy>
-static Error error(const char *ErrFmt, ArgsTy... Args) {
-  return createStringError(ErrorCode::UNKNOWN, ErrFmt, Args...);
+static Error error(ErrorCode Code, const char *ErrFmt, ArgsTy... Args) {
+  std::string Buffer;
+  raw_string_ostream(Buffer) << format(ErrFmt, Args...);
+  return make_error<OffloadError>(Code, Buffer);
 }
 
-/// Create a string error.
 template <typename... ArgsTy>
-static Error error(ErrorCode Code, const char *ErrFmt, ArgsTy... Args) {
-  return createStringError(Code, ErrFmt, Args...);
+static Error error(const char *ErrFmt, ArgsTy... Args) {
+  return error(ErrorCode::UNKNOWN, ErrFmt, Args...);
+}
+
+inline Error error(ErrorCode Code, const char *S) {
+  return make_error<OffloadError>(Code, S);
+}
+
+inline Error error(const char *S) {
+  return make_error<OffloadError>(ErrorCode::UNKNOWN, S);
 }
 
 /// Check the plugin-specific error code and return an error or success
@@ -1626,10 +1612,4 @@ template <typename ResourceRef> class GenericDeviceResourceManagerTy {
 } // namespace omp
 } // namespace llvm
 
-namespace std {
-template <>
-struct is_error_code_enum<llvm::omp::target::plugin::ErrorCode>
-    : std::true_type {};
-} // namespace std
-
 #endif // OPENMP_LIBOMPTARGET_PLUGINS_COMMON_PLUGININTERFACE_H
diff --git a/offload/plugins-nextgen/common/src/OffloadError.cpp b/offload/plugins-nextgen/common/src/OffloadError.cpp
new file mode 100644
index 0000000000000..51d35bdcb0289
--- /dev/null
+++ b/offload/plugins-nextgen/common/src/OffloadError.cpp
@@ -0,0 +1,40 @@
+//===- OffloadError.cpp - Error extensions for offload --------------------===//
+//
+// 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 "OffloadError.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+using namespace llvm::omp::target::plugin;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class OffloadErrorCategory : public std::error_category {
+public:
+  const char *name() const noexcept override { return "llvm.offload"; }
+  std::string message(int Condition) const override {
+    switch (static_cast<ErrorCode>(Condition)) {
+#define OFFLOAD_ERRC(Name, Desc, Value)                                        \
+  case ErrorCode::Name:                                                        \
+    return #Desc;
+#include "OffloadErrcodes.inc"
+#undef OFFLOAD_ERRC
+    }
+    llvm_unreachable("Unrecognized offload ErrorCode");
+  }
+};
+} // namespace
+
+const std::error_category &llvm::omp::target::plugin::OffloadErrCategory() {
+  static OffloadErrorCategory MSFCategory;
+  return MSFCategory;
+}
+
+char OffloadError::ID;

>From 06d962ad8a3c74f2f923a31ebb99e0b39cd475d5 Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Wed, 7 May 2025 16:18:49 +0100
Subject: [PATCH 4/5] [Offload] Respond to feedback and fix extra definition

---
 .../include => include/Shared}/OffloadErrcodes.inc |  0
 offload/liboffload/API/CMakeLists.txt              |  2 +-
 .../plugins-nextgen/common/include/OffloadError.h  | 14 +-------------
 .../plugins-nextgen/common/src/OffloadError.cpp    |  8 ++++----
 4 files changed, 6 insertions(+), 18 deletions(-)
 rename offload/{plugins-nextgen/common/include => include/Shared}/OffloadErrcodes.inc (100%)

diff --git a/offload/plugins-nextgen/common/include/OffloadErrcodes.inc b/offload/include/Shared/OffloadErrcodes.inc
similarity index 100%
rename from offload/plugins-nextgen/common/include/OffloadErrcodes.inc
rename to offload/include/Shared/OffloadErrcodes.inc
diff --git a/offload/liboffload/API/CMakeLists.txt b/offload/liboffload/API/CMakeLists.txt
index 62b8803ca2a13..5f8d1435d141f 100644
--- a/offload/liboffload/API/CMakeLists.txt
+++ b/offload/liboffload/API/CMakeLists.txt
@@ -21,7 +21,7 @@ if (CLANG_FORMAT)
     add_custom_command(TARGET OffloadGenerate POST_BUILD COMMAND ${CMAKE_COMMAND}
         -E copy_if_different ${FILES_TO_COPY} ${GEN_DIR})
     add_custom_command(TARGET OffloadGenerate POST_BUILD COMMAND ${CMAKE_COMMAND}
-        -E copy_if_different OffloadErrcodes.inc "${LIBOFFLOAD_ROOT}/../plugins-nextgen/common/include/OffloadErrcodes.inc")
+        -E copy_if_different OffloadErrcodes.inc "${LIBOMPTARGET_INCLUDE_DIR}/Shared/OffloadErrcodes.inc")
 else()
     message(WARNING "clang-format was not found, so the OffloadGenerate target\
         will not be available. Offload will still build, but you will not be\
diff --git a/offload/plugins-nextgen/common/include/OffloadError.h b/offload/plugins-nextgen/common/include/OffloadError.h
index 2b0f49cdf7262..04f5c31b4c9e1 100644
--- a/offload/plugins-nextgen/common/include/OffloadError.h
+++ b/offload/plugins-nextgen/common/include/OffloadError.h
@@ -21,22 +21,10 @@ namespace plugin {
 
 enum class ErrorCode {
 #define OFFLOAD_ERRC(Name, _, Value) Name = Value,
-#include "OffloadErrcodes.inc"
+#include "Shared/OffloadErrcodes.inc"
 #undef OFFLOAD_ERRC
 };
 
-class OffloadErrorCategory : public std::error_category {
-  const char *name() const noexcept override { return "Offload Error"; }
-  std::string message(int ev) const override {
-    switch (static_cast<ErrorCode>(ev)) {
-#define OFFLOAD_ERRC(Name, Desc, Value)                                        \
-  case ErrorCode::Name:                                                        \
-    return #Desc;
-#include "OffloadErrcodes.inc"
-#undef OFFLOAD_ERRC
-    }
-  }
-};
 } // namespace plugin
 } // namespace target
 } // namespace omp
diff --git a/offload/plugins-nextgen/common/src/OffloadError.cpp b/offload/plugins-nextgen/common/src/OffloadError.cpp
index 51d35bdcb0289..d0b05af791bc1 100644
--- a/offload/plugins-nextgen/common/src/OffloadError.cpp
+++ b/offload/plugins-nextgen/common/src/OffloadError.cpp
@@ -13,9 +13,9 @@ using namespace llvm;
 using namespace llvm::omp::target::plugin;
 
 namespace {
-// FIXME: This class is only here to support the transition to llvm::Error. It
-// will be removed once this transition is complete. Clients should prefer to
-// deal with the Error value directly, rather than converting to error_code.
+// OffloadError inherits from llvm::StringError which requires a
+// std::error_code. Once/if that requirement is removed, then this
+// std::error_code machinery can be removed.
 class OffloadErrorCategory : public std::error_category {
 public:
   const char *name() const noexcept override { return "llvm.offload"; }
@@ -24,7 +24,7 @@ class OffloadErrorCategory : public std::error_category {
 #define OFFLOAD_ERRC(Name, Desc, Value)                                        \
   case ErrorCode::Name:                                                        \
     return #Desc;
-#include "OffloadErrcodes.inc"
+#include "Shared/OffloadErrcodes.inc"
 #undef OFFLOAD_ERRC
     }
     llvm_unreachable("Unrecognized offload ErrorCode");

>From 14a92fef27fcda13a2dd4dff481a6f638b04176d Mon Sep 17 00:00:00 2001
From: Ross Brunton <ross at codeplay.com>
Date: Fri, 2 May 2025 12:45:47 +0100
Subject: [PATCH 5/5] [Offload] Use new error code handling mechanism

This removes the old ErrorCode-less error method and requires
every user to provide a concrete error code. All calls have been
updated.
---
 offload/include/Shared/OffloadErrcodes.inc    | 44 ++++++----
 offload/liboffload/API/Common.td              | 15 +++-
 .../liboffload/include/generated/OffloadAPI.h | 47 ++++++----
 .../include/generated/OffloadPrint.hpp        | 37 ++++++--
 offload/liboffload/src/OffloadImpl.cpp        |  2 +-
 .../plugins-nextgen/amdgpu/dynamic_hsa/hsa.h  |  1 +
 offload/plugins-nextgen/amdgpu/src/rtl.cpp    | 88 +++++++++++++------
 .../common/include/PluginInterface.h          |  9 --
 .../common/src/GlobalHandler.cpp              | 35 +++++---
 offload/plugins-nextgen/common/src/JIT.cpp    |  2 +-
 .../common/src/PluginInterface.cpp            | 66 +++++++++-----
 offload/plugins-nextgen/common/src/RPC.cpp    |  1 +
 offload/plugins-nextgen/cuda/src/rtl.cpp      | 70 ++++++++++-----
 offload/plugins-nextgen/host/src/rtl.cpp      | 36 +++++---
 .../OffloadAPI/kernel/olGetKernel.cpp         |  4 +-
 15 files changed, 307 insertions(+), 150 deletions(-)

diff --git a/offload/include/Shared/OffloadErrcodes.inc b/offload/include/Shared/OffloadErrcodes.inc
index 217565647c4e1..e0797e2bac194 100644
--- a/offload/include/Shared/OffloadErrcodes.inc
+++ b/offload/include/Shared/OffloadErrcodes.inc
@@ -16,22 +16,36 @@
 
 OFFLOAD_ERRC(SUCCESS, "Success", 0)
 OFFLOAD_ERRC(UNKNOWN, "Unknown or internal error", 1)
+OFFLOAD_ERRC(HOST_IO, "I/O error on host", 2)
+OFFLOAD_ERRC(INVALID_BINARY, "A provided binary image is malformed", 3)
 OFFLOAD_ERRC(INVALID_NULL_POINTER,
-             "A pointer argument is null when it should not be", 2)
-OFFLOAD_ERRC(INVALID_ARGUMENT, "An argument is invalid", 3)
-OFFLOAD_ERRC(OUT_OF_RESOURCES, "Out of resources", 4)
-OFFLOAD_ERRC(UNSUPPORTED,
-             "generic error code for unsupported features and enums", 5)
+             "A pointer argument is null when it should not be", 4)
+OFFLOAD_ERRC(INVALID_ARGUMENT, "An argument is invalid", 5)
+OFFLOAD_ERRC(NOT_FOUND, "Requested object was not found in the binary image", 6)
+OFFLOAD_ERRC(OUT_OF_RESOURCES, "Out of resources", 7)
 OFFLOAD_ERRC(
     INVALID_SIZE,
     "invalid size or dimensions (e.g., must not be zero, or is out of bounds)",
-    6)
-OFFLOAD_ERRC(INVALID_ENUMERATION, "enumerator argument is not valid", 7)
-OFFLOAD_ERRC(INVALID_KERNEL_NAME,
-             "Named kernel not found in the program binary", 8)
-OFFLOAD_ERRC(INVALID_VALUE, "Invalid Value", 9)
-OFFLOAD_ERRC(INVALID_PLATFORM, "Invalid platform", 10)
-OFFLOAD_ERRC(INVALID_DEVICE, "Invalid device", 11)
-OFFLOAD_ERRC(INVALID_QUEUE, "Invalid queue", 12)
-OFFLOAD_ERRC(INVALID_EVENT, "Invalid event", 13)
-OFFLOAD_ERRC(INVALID_NULL_HANDLE, "handle argument is not valid", 14)
+    8)
+OFFLOAD_ERRC(INVALID_ENUMERATION, "enumerator argument is not valid", 9)
+OFFLOAD_ERRC(HOST_TOOL_NOT_FOUND,
+             "A required binary (linker, etc.) was not found on the host", 10)
+OFFLOAD_ERRC(INVALID_VALUE, "Invalid Value", 11)
+OFFLOAD_ERRC(UNIMPLEMENTED,
+             "Generic error code for features currently unimplemented by the "
+             "device/backend",
+             12)
+OFFLOAD_ERRC(
+    UNSUPPORTED,
+    "Generic error code for features unsupported by the device/backend", 13)
+OFFLOAD_ERRC(ASSEMBLE_FAILURE,
+             "Assembler failure while processing binary image", 14)
+OFFLOAD_ERRC(LINK_FAILURE, "Linker failure while processing binary image", 15)
+OFFLOAD_ERRC(BACKEND_FAILURE,
+             "The plugin backend is in an invalid or unsupported state", 16)
+OFFLOAD_ERRC(INVALID_NULL_HANDLE,
+             "A handle argument is null when it should not be", 17)
+OFFLOAD_ERRC(INVALID_PLATFORM, "Invalid platform", 18)
+OFFLOAD_ERRC(INVALID_DEVICE, "Invalid device", 19)
+OFFLOAD_ERRC(INVALID_QUEUE, "Invalid queue", 20)
+OFFLOAD_ERRC(INVALID_EVENT, "Invalid event", 21)
diff --git a/offload/liboffload/API/Common.td b/offload/liboffload/API/Common.td
index d19c9c662faec..71079420a210f 100644
--- a/offload/liboffload/API/Common.td
+++ b/offload/liboffload/API/Common.td
@@ -91,21 +91,28 @@ def ErrorCode : Enum {
 
     // Universal errors
     Etor<"UNKNOWN", "Unknown or internal error">,
+    Etor<"HOST_IO", "I/O error on host">,
+    Etor<"INVALID_BINARY", "A provided binary image is malformed">,
     Etor<"INVALID_NULL_POINTER", "A pointer argument is null when it should not be">,
     Etor<"INVALID_ARGUMENT", "An argument is invalid">,
+    Etor<"NOT_FOUND", "Requested object was not found in the binary image">,
     Etor<"OUT_OF_RESOURCES", "Out of resources">,
-    Etor<"UNSUPPORTED", "generic error code for unsupported features and enums">,
     Etor<"INVALID_SIZE", "invalid size or dimensions (e.g., must not be zero, or is out of bounds)">,
     Etor<"INVALID_ENUMERATION", "enumerator argument is not valid">,
-    Etor<"INVALID_KERNEL_NAME", "Named kernel not found in the program binary">,
+    Etor<"HOST_TOOL_NOT_FOUND", "A required binary (linker, etc.) was not found on the host">,
+    Etor<"INVALID_VALUE", "Invalid Value">,
+    Etor<"UNIMPLEMENTED", "Generic error code for features currently unimplemented by the device/backend">,
+    Etor<"UNSUPPORTED", "Generic error code for features unsupported by the device/backend">,
+    Etor<"ASSEMBLE_FAILURE", "Assembler failure while processing binary image">,
+    Etor<"LINK_FAILURE", "Linker failure while processing binary image">,
+    Etor<"BACKEND_FAILURE", "The plugin backend is in an invalid or unsupported state">,
 
     // Handle related errors - only makes sense for liboffload
-    Etor<"INVALID_VALUE", "Invalid Value">,
+    Etor<"INVALID_NULL_HANDLE", "A handle argument is null when it should not be">,
     Etor<"INVALID_PLATFORM", "Invalid platform">,
     Etor<"INVALID_DEVICE", "Invalid device">,
     Etor<"INVALID_QUEUE", "Invalid queue">,
     Etor<"INVALID_EVENT", "Invalid event">,
-    Etor<"INVALID_NULL_HANDLE", "handle argument is not valid">
   ];
 }
 
diff --git a/offload/liboffload/include/generated/OffloadAPI.h b/offload/liboffload/include/generated/OffloadAPI.h
index 66ea48c8ca14f..d38ed06b91559 100644
--- a/offload/liboffload/include/generated/OffloadAPI.h
+++ b/offload/liboffload/include/generated/OffloadAPI.h
@@ -24,32 +24,47 @@ typedef enum ol_errc_t {
   OL_ERRC_SUCCESS = 0,
   /// Unknown or internal error
   OL_ERRC_UNKNOWN = 1,
+  /// I/O error on host
+  OL_ERRC_HOST_IO = 2,
+  /// A provided binary image is malformed
+  OL_ERRC_INVALID_BINARY = 3,
   /// A pointer argument is null when it should not be
-  OL_ERRC_INVALID_NULL_POINTER = 2,
+  OL_ERRC_INVALID_NULL_POINTER = 4,
   /// An argument is invalid
-  OL_ERRC_INVALID_ARGUMENT = 3,
+  OL_ERRC_INVALID_ARGUMENT = 5,
+  /// Requested object was not found in the binary image
+  OL_ERRC_NOT_FOUND = 6,
   /// Out of resources
-  OL_ERRC_OUT_OF_RESOURCES = 4,
-  /// generic error code for unsupported features and enums
-  OL_ERRC_UNSUPPORTED = 5,
+  OL_ERRC_OUT_OF_RESOURCES = 7,
   /// invalid size or dimensions (e.g., must not be zero, or is out of bounds)
-  OL_ERRC_INVALID_SIZE = 6,
+  OL_ERRC_INVALID_SIZE = 8,
   /// enumerator argument is not valid
-  OL_ERRC_INVALID_ENUMERATION = 7,
-  /// Named kernel not found in the program binary
-  OL_ERRC_INVALID_KERNEL_NAME = 8,
+  OL_ERRC_INVALID_ENUMERATION = 9,
+  /// A required binary (linker, etc.) was not found on the host
+  OL_ERRC_HOST_TOOL_NOT_FOUND = 10,
   /// Invalid Value
-  OL_ERRC_INVALID_VALUE = 9,
+  OL_ERRC_INVALID_VALUE = 11,
+  /// Generic error code for features currently unimplemented by the
+  /// device/backend
+  OL_ERRC_UNIMPLEMENTED = 12,
+  /// Generic error code for features unsupported by the device/backend
+  OL_ERRC_UNSUPPORTED = 13,
+  /// Assembler failure while processing binary image
+  OL_ERRC_ASSEMBLE_FAILURE = 14,
+  /// Linker failure while processing binary image
+  OL_ERRC_LINK_FAILURE = 15,
+  /// The plugin backend is in an invalid or unsupported state
+  OL_ERRC_BACKEND_FAILURE = 16,
+  /// A handle argument is null when it should not be
+  OL_ERRC_INVALID_NULL_HANDLE = 17,
   /// Invalid platform
-  OL_ERRC_INVALID_PLATFORM = 10,
+  OL_ERRC_INVALID_PLATFORM = 18,
   /// Invalid device
-  OL_ERRC_INVALID_DEVICE = 11,
+  OL_ERRC_INVALID_DEVICE = 19,
   /// Invalid queue
-  OL_ERRC_INVALID_QUEUE = 12,
+  OL_ERRC_INVALID_QUEUE = 20,
   /// Invalid event
-  OL_ERRC_INVALID_EVENT = 13,
-  /// handle argument is not valid
-  OL_ERRC_INVALID_NULL_HANDLE = 14,
+  OL_ERRC_INVALID_EVENT = 21,
   /// @cond
   OL_ERRC_FORCE_UINT32 = 0x7fffffff
   /// @endcond
diff --git a/offload/liboffload/include/generated/OffloadPrint.hpp b/offload/liboffload/include/generated/OffloadPrint.hpp
index af5ca0a96b509..9b916543eec0d 100644
--- a/offload/liboffload/include/generated/OffloadPrint.hpp
+++ b/offload/liboffload/include/generated/OffloadPrint.hpp
@@ -52,30 +52,54 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
   case OL_ERRC_UNKNOWN:
     os << "OL_ERRC_UNKNOWN";
     break;
+  case OL_ERRC_HOST_IO:
+    os << "OL_ERRC_HOST_IO";
+    break;
+  case OL_ERRC_INVALID_BINARY:
+    os << "OL_ERRC_INVALID_BINARY";
+    break;
   case OL_ERRC_INVALID_NULL_POINTER:
     os << "OL_ERRC_INVALID_NULL_POINTER";
     break;
   case OL_ERRC_INVALID_ARGUMENT:
     os << "OL_ERRC_INVALID_ARGUMENT";
     break;
+  case OL_ERRC_NOT_FOUND:
+    os << "OL_ERRC_NOT_FOUND";
+    break;
   case OL_ERRC_OUT_OF_RESOURCES:
     os << "OL_ERRC_OUT_OF_RESOURCES";
     break;
-  case OL_ERRC_UNSUPPORTED:
-    os << "OL_ERRC_UNSUPPORTED";
-    break;
   case OL_ERRC_INVALID_SIZE:
     os << "OL_ERRC_INVALID_SIZE";
     break;
   case OL_ERRC_INVALID_ENUMERATION:
     os << "OL_ERRC_INVALID_ENUMERATION";
     break;
-  case OL_ERRC_INVALID_KERNEL_NAME:
-    os << "OL_ERRC_INVALID_KERNEL_NAME";
+  case OL_ERRC_HOST_TOOL_NOT_FOUND:
+    os << "OL_ERRC_HOST_TOOL_NOT_FOUND";
     break;
   case OL_ERRC_INVALID_VALUE:
     os << "OL_ERRC_INVALID_VALUE";
     break;
+  case OL_ERRC_UNIMPLEMENTED:
+    os << "OL_ERRC_UNIMPLEMENTED";
+    break;
+  case OL_ERRC_UNSUPPORTED:
+    os << "OL_ERRC_UNSUPPORTED";
+    break;
+  case OL_ERRC_ASSEMBLE_FAILURE:
+    os << "OL_ERRC_ASSEMBLE_FAILURE";
+    break;
+  case OL_ERRC_LINK_FAILURE:
+    os << "OL_ERRC_LINK_FAILURE";
+    break;
+  case OL_ERRC_BACKEND_FAILURE:
+    os << "OL_ERRC_BACKEND_FAILURE";
+    break;
+  case OL_ERRC_INVALID_NULL_HANDLE:
+    os << "OL_ERRC_INVALID_NULL_HANDLE";
+    break;
   case OL_ERRC_INVALID_PLATFORM:
     os << "OL_ERRC_INVALID_PLATFORM";
     break;
@@ -88,9 +112,6 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
   case OL_ERRC_INVALID_EVENT:
     os << "OL_ERRC_INVALID_EVENT";
     break;
-  case OL_ERRC_INVALID_NULL_HANDLE:
-    os << "OL_ERRC_INVALID_NULL_HANDLE";
-    break;
   default:
     os << "unknown enumerator";
     break;
diff --git a/offload/liboffload/src/OffloadImpl.cpp b/offload/liboffload/src/OffloadImpl.cpp
index b50c7e0f87b7c..ea65282e3ba52 100644
--- a/offload/liboffload/src/OffloadImpl.cpp
+++ b/offload/liboffload/src/OffloadImpl.cpp
@@ -482,7 +482,7 @@ ol_impl_result_t olGetKernel_impl(ol_program_handle_t Program,
   auto &Device = Program->Image->getDevice();
   auto KernelImpl = Device.constructKernel(KernelName);
   if (!KernelImpl)
-    return OL_ERRC_INVALID_KERNEL_NAME;
+    return ol_impl_result_t::fromError(KernelImpl.takeError());
 
   auto Err = KernelImpl->init(Device, *Program->Image);
   if (Err)
diff --git a/offload/plugins-nextgen/amdgpu/dynamic_hsa/hsa.h b/offload/plugins-nextgen/amdgpu/dynamic_hsa/hsa.h
index 27e4541481301..61f680bab3a07 100644
--- a/offload/plugins-nextgen/amdgpu/dynamic_hsa/hsa.h
+++ b/offload/plugins-nextgen/amdgpu/dynamic_hsa/hsa.h
@@ -30,6 +30,7 @@ typedef enum {
   HSA_STATUS_INFO_BREAK = 0x1,
   HSA_STATUS_ERROR = 0x1000,
   HSA_STATUS_ERROR_INVALID_CODE_OBJECT = 0x1010,
+  HSA_STATUS_ERROR_INVALID_SYMBOL_NAME = 0x1013,
   HSA_STATUS_ERROR_NOT_INITIALIZED = 0x100B,
   HSA_STATUS_ERROR_EXCEPTION = 0x1016,
 } hsa_status_t;
diff --git a/offload/plugins-nextgen/amdgpu/src/rtl.cpp b/offload/plugins-nextgen/amdgpu/src/rtl.cpp
index ed575f2213f28..8cd1187e83eb1 100644
--- a/offload/plugins-nextgen/amdgpu/src/rtl.cpp
+++ b/offload/plugins-nextgen/amdgpu/src/rtl.cpp
@@ -167,7 +167,8 @@ Error asyncMemCopy(bool UseMultipleSdmaEngines, void *Dst, hsa_agent_t DstAgent,
 // This solution is probably not the best
 #if !(HSA_AMD_INTERFACE_VERSION_MAJOR >= 1 &&                                  \
       HSA_AMD_INTERFACE_VERSION_MINOR >= 2)
-  return Plugin::error("Async copy on selected SDMA requires ROCm 5.7");
+  return Plugin::error(ErrorCode::UNSUPPORTED,
+                       "Async copy on selected SDMA requires ROCm 5.7");
 #else
   static std::atomic<int> SdmaEngine{1};
 
@@ -237,7 +238,8 @@ struct AMDGPUResourceRef : public GenericDeviceResourceRef {
   /// reference must be to a valid resource before calling to this function.
   Error destroy(GenericDeviceTy &Device) override {
     if (!Resource)
-      return Plugin::error("Destroying an invalid resource");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Destroying an invalid resource");
 
     if (auto Err = Resource->deinit())
       return Err;
@@ -335,7 +337,8 @@ struct AMDGPUMemoryPoolTy {
       // The agent is not allowed to access the memory pool in any case. Do not
       // continue because otherwise it result in undefined behavior.
       if (Access == HSA_AMD_MEMORY_POOL_ACCESS_NEVER_ALLOWED)
-        return Plugin::error("An agent is not allowed to access a memory pool");
+        return Plugin::error(ErrorCode::INVALID_VALUE,
+                             "An agent is not allowed to access a memory pool");
     }
 #endif
 
@@ -416,7 +419,8 @@ struct AMDGPUMemoryManagerTy : public DeviceAllocatorTy {
 
     *PtrStorage = MemoryManager->allocate(Size, nullptr);
     if (*PtrStorage == nullptr)
-      return Plugin::error("Failure to allocate from AMDGPU memory manager");
+      return Plugin::error(ErrorCode::OUT_OF_RESOURCES,
+                           "Failure to allocate from AMDGPU memory manager");
 
     return Plugin::success();
   }
@@ -426,7 +430,8 @@ struct AMDGPUMemoryManagerTy : public DeviceAllocatorTy {
     assert(Ptr && "Invalid pointer");
 
     if (MemoryManager->free(Ptr))
-      return Plugin::error("Failure to deallocate from AMDGPU memory manager");
+      return Plugin::error(ErrorCode::UNKNOWN,
+                           "Failure to deallocate from AMDGPU memory manager");
 
     return Plugin::success();
   }
@@ -540,7 +545,8 @@ struct AMDGPUKernelTy : public GenericKernelTy {
 
     // Make sure it is a kernel symbol.
     if (SymbolType != HSA_SYMBOL_KIND_KERNEL)
-      return Plugin::error("Symbol %s is not a kernel function");
+      return Plugin::error(ErrorCode::INVALID_BINARY,
+                           "Symbol %s is not a kernel function");
 
     // TODO: Read the kernel descriptor for the max threads per block. May be
     // read from the image.
@@ -1115,7 +1121,8 @@ struct AMDGPUStreamTy {
   /// Use a barrier packet with two input signals.
   Error waitOnStreamOperation(AMDGPUStreamTy &OtherStream, uint32_t Slot) {
     if (Queue == nullptr)
-      return Plugin::error("Target queue was nullptr");
+      return Plugin::error(ErrorCode::INVALID_NULL_POINTER,
+                           "Target queue was nullptr");
 
     /// The signal that we must wait from the other stream.
     AMDGPUSignalTy *OtherSignal = OtherStream.Slots[Slot].Signal;
@@ -1236,7 +1243,8 @@ struct AMDGPUStreamTy {
                          uint32_t GroupSize, uint64_t StackSize,
                          AMDGPUMemoryManagerTy &MemoryManager) {
     if (Queue == nullptr)
-      return Plugin::error("Target queue was nullptr");
+      return Plugin::error(ErrorCode::INVALID_NULL_POINTER,
+                           "Target queue was nullptr");
 
     // Retrieve an available signal for the operation's output.
     AMDGPUSignalTy *OutputSignal = nullptr;
@@ -1553,7 +1561,8 @@ struct AMDGPUEventTy {
     std::lock_guard<std::mutex> Lock(Mutex);
 
     if (!RecordedStream)
-      return Plugin::error("Event does not have any recorded stream");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Event does not have any recorded stream");
 
     // Synchronizing the same stream. Do nothing.
     if (RecordedStream == &Stream)
@@ -1942,7 +1951,8 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
     else if (WavefrontSize == 64)
       GridValues = getAMDGPUGridValues<64>();
     else
-      return Plugin::error("Unexpected AMDGPU wavefront %d", WavefrontSize);
+      return Plugin::error(ErrorCode::UNSUPPORTED,
+                           "Unexpected AMDGPU wavefront %d", WavefrontSize);
 
     // Get maximum number of workitems per workgroup.
     uint16_t WorkgroupMaxDim[3];
@@ -1958,7 +1968,8 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
 
     GridValues.GV_Max_Teams = GridMaxDim.x / GridValues.GV_Max_WG_Size;
     if (GridValues.GV_Max_Teams == 0)
-      return Plugin::error("Maximum number of teams cannot be zero");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Maximum number of teams cannot be zero");
 
     // Compute the default number of teams.
     uint32_t ComputeUnits = 0;
@@ -2071,7 +2082,8 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
     std::error_code EC = sys::fs::createTemporaryFile("amdgpu-pre-link-jit",
                                                       "o", LinkerInputFilePath);
     if (EC)
-      return Plugin::error("Failed to create temporary file for linker");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to create temporary file for linker");
 
     // Write the file's contents to the output file.
     Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
@@ -2087,11 +2099,12 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
     EC = sys::fs::createTemporaryFile("amdgpu-pre-link-jit", "so",
                                       LinkerOutputFilePath);
     if (EC)
-      return Plugin::error("Failed to create temporary file for linker");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to create temporary file for linker");
 
     const auto &ErrorOrPath = sys::findProgramByName("lld");
     if (!ErrorOrPath)
-      return createStringError(inconvertibleErrorCode(),
+      return createStringError(ErrorCode::HOST_TOOL_NOT_FOUND,
                                "Failed to find `lld` on the PATH.");
 
     std::string LLDPath = ErrorOrPath.get();
@@ -2112,18 +2125,22 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
     std::string Error;
     int RC = sys::ExecuteAndWait(LLDPath, Args, std::nullopt, {}, 0, 0, &Error);
     if (RC)
-      return Plugin::error("Linking optimized bitcode failed: %s",
+      return Plugin::error(ErrorCode::LINK_FAILURE,
+                           "Linking optimized bitcode failed: %s",
                            Error.c_str());
 
     auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(LinkerOutputFilePath);
     if (!BufferOrErr)
-      return Plugin::error("Failed to open temporary file for lld");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to open temporary file for lld");
 
     // Clean up the temporary files afterwards.
     if (sys::fs::remove(LinkerOutputFilePath))
-      return Plugin::error("Failed to remove temporary output file for lld");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to remove temporary output file for lld");
     if (sys::fs::remove(LinkerInputFilePath))
-      return Plugin::error("Failed to remove temporary input file for lld");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to remove temporary input file for lld");
 
     return std::move(*BufferOrErr);
   }
@@ -2139,7 +2156,8 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
     // Allocate and construct the AMDGPU kernel.
     AMDGPUKernelTy *AMDGPUKernel = Plugin.allocate<AMDGPUKernelTy>();
     if (!AMDGPUKernel)
-      return Plugin::error("Failed to allocate memory for AMDGPU kernel");
+      return Plugin::error(ErrorCode::OUT_OF_RESOURCES,
+                           "Failed to allocate memory for AMDGPU kernel");
 
     new (AMDGPUKernel) AMDGPUKernelTy(Name);
 
@@ -2529,7 +2547,8 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
 
   /// Synchronize the current thread with the event.
   Error syncEventImpl(void *EventPtr) override {
-    return Plugin::error("Synchronize event not implemented");
+    return Plugin::error(ErrorCode::UNIMPLEMENTED,
+                         "Synchronize event not implemented");
   }
 
   /// Print information about the device.
@@ -2777,7 +2796,8 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
         return Plugin::check(Status, "Error in getting device memory size: %s");
       }
     }
-    return Plugin::error("getDeviceMemorySize:: no global pool");
+    return Plugin::error(ErrorCode::UNSUPPORTED,
+                         "getDeviceMemorySize:: no global pool");
   }
 
   /// AMDGPU-specific function to get device attributes.
@@ -2981,7 +3001,8 @@ Error AMDGPUDeviceImageTy::loadExecutable(const AMDGPUDeviceTy &Device) {
     return Err;
 
   if (Result)
-    return Plugin::error("Loaded HSA executable does not validate");
+    return Plugin::error(ErrorCode::INVALID_BINARY,
+                         "Loaded HSA executable does not validate");
 
   Status = hsa_code_object_reader_destroy(Reader);
   if (auto Err =
@@ -3016,7 +3037,8 @@ AMDGPUDeviceImageTy::findDeviceSymbol(GenericDeviceTy &Device,
 template <typename ResourceTy>
 Error AMDGPUResourceRef<ResourceTy>::create(GenericDeviceTy &Device) {
   if (Resource)
-    return Plugin::error("Creating an existing resource");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Creating an existing resource");
 
   AMDGPUDeviceTy &AMDGPUDevice = static_cast<AMDGPUDeviceTy &>(Device);
 
@@ -3072,6 +3094,7 @@ struct AMDGPUGlobalHandlerTy final : public GenericGlobalHandlerTy {
     // Check the size of the symbol.
     if (SymbolSize != DeviceGlobal.getSize())
       return Plugin::error(
+          ErrorCode::INVALID_BINARY,
           "Failed to load global '%s' due to size mismatch (%zu != %zu)",
           DeviceGlobal.getName().data(), SymbolSize,
           (size_t)DeviceGlobal.getSize());
@@ -3151,7 +3174,7 @@ struct AMDGPUPluginTy final : public GenericPluginTy {
     // There are kernel agents but there is no host agent. That should be
     // treated as an error.
     if (HostAgents.empty())
-      return Plugin::error("No AMDGPU host agents");
+      return Plugin::error(ErrorCode::BACKEND_FAILURE, "No AMDGPU host agents");
 
     // Initialize the host device using host agents.
     HostDevice = allocate<AMDHostDeviceTy>();
@@ -3341,7 +3364,8 @@ Error AMDGPUKernelTy::launchImpl(GenericDeviceTy &GenericDevice,
                                  AsyncInfoWrapperTy &AsyncInfoWrapper) const {
   if (ArgsSize != LaunchParams.Size &&
       ArgsSize != LaunchParams.Size + getImplicitArgsSize())
-    return Plugin::error("Mismatch of kernel arguments size");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Mismatch of kernel arguments size");
 
   AMDGPUPluginTy &AMDGPUPlugin =
       static_cast<AMDGPUPluginTy &>(GenericDevice.Plugin);
@@ -3461,8 +3485,18 @@ static Error Plugin::check(int32_t Code, const char *ErrFmt, ArgsTy... Args) {
   if (Ret != HSA_STATUS_SUCCESS)
     REPORT("Unrecognized " GETNAME(TARGET_NAME) " error code %d\n", Code);
 
-  return createStringError<ArgsTy..., const char *>(inconvertibleErrorCode(),
-                                                    ErrFmt, Args..., Desc);
+  // TODO: Add more entries to this switch
+  ErrorCode OffloadErrCode;
+  switch (ResultCode) {
+  case HSA_STATUS_ERROR_INVALID_SYMBOL_NAME:
+    OffloadErrCode = ErrorCode::NOT_FOUND;
+    break;
+  default:
+    OffloadErrCode = ErrorCode::UNKNOWN;
+  }
+
+  return createStringError<ArgsTy..., const char *>(OffloadErrCode, ErrFmt,
+                                                    Args..., Desc);
 }
 
 void *AMDGPUMemoryManagerTy::allocate(size_t Size, void *HstPtr,
diff --git a/offload/plugins-nextgen/common/include/PluginInterface.h b/offload/plugins-nextgen/common/include/PluginInterface.h
index 899ae0f9be3f5..0721edc11b3ec 100644
--- a/offload/plugins-nextgen/common/include/PluginInterface.h
+++ b/offload/plugins-nextgen/common/include/PluginInterface.h
@@ -1391,19 +1391,10 @@ static Error error(ErrorCode Code, const char *ErrFmt, ArgsTy... Args) {
   return make_error<OffloadError>(Code, Buffer);
 }
 
-template <typename... ArgsTy>
-static Error error(const char *ErrFmt, ArgsTy... Args) {
-  return error(ErrorCode::UNKNOWN, ErrFmt, Args...);
-}
-
 inline Error error(ErrorCode Code, const char *S) {
   return make_error<OffloadError>(Code, S);
 }
 
-inline Error error(const char *S) {
-  return make_error<OffloadError>(ErrorCode::UNKNOWN, S);
-}
-
 /// Check the plugin-specific error code and return an error or success
 /// accordingly. In case of an error, create a string error with the error
 /// description. The ErrFmt should follow the format:
diff --git a/offload/plugins-nextgen/common/src/GlobalHandler.cpp b/offload/plugins-nextgen/common/src/GlobalHandler.cpp
index 35a70d8eff901..c3c8ef8139a7e 100644
--- a/offload/plugins-nextgen/common/src/GlobalHandler.cpp
+++ b/offload/plugins-nextgen/common/src/GlobalHandler.cpp
@@ -32,7 +32,16 @@ GenericGlobalHandlerTy::getELFObjectFile(DeviceImageTy &Image) {
   assert(utils::elf::isELF(Image.getMemoryBuffer().getBuffer()) &&
          "Input is not an ELF file");
 
-  return ELFObjectFileBase::createELFObjectFile(Image.getMemoryBuffer());
+  auto Expected =
+      ELFObjectFileBase::createELFObjectFile(Image.getMemoryBuffer());
+  if (!Expected) {
+    return handleErrors(Expected.takeError(), [](llvm::StringError &Err) {
+      return llvm::createStringError(ErrorCode::INVALID_BINARY,
+                                     "Error parsing binary: " +
+                                         Err.getMessage());
+    });
+  }
+  return Expected;
 }
 
 Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
@@ -112,20 +121,21 @@ Error GenericGlobalHandlerTy::getGlobalMetadataFromImage(
   // Search the ELF symbol using the symbol name.
   auto SymOrErr = utils::elf::getSymbol(**ELFObj, ImageGlobal.getName());
   if (!SymOrErr)
-    return Plugin::error("Failed ELF lookup of global '%s': %s",
-                         ImageGlobal.getName().data(),
-                         toString(SymOrErr.takeError()).data());
+    return Plugin::error(
+        ErrorCode::NOT_FOUND, "Failed ELF lookup of global '%s': %s",
+        ImageGlobal.getName().data(), toString(SymOrErr.takeError()).data());
 
   if (!SymOrErr->has_value())
-    return Plugin::error("Failed to find global symbol '%s' in the ELF image",
+    return Plugin::error(ErrorCode::NOT_FOUND,
+                         "Failed to find global symbol '%s' in the ELF image",
                          ImageGlobal.getName().data());
 
   auto AddrOrErr = utils::elf::getSymbolAddress(**SymOrErr);
   // Get the section to which the symbol belongs.
   if (!AddrOrErr)
-    return Plugin::error("Failed to get ELF symbol from global '%s': %s",
-                         ImageGlobal.getName().data(),
-                         toString(AddrOrErr.takeError()).data());
+    return Plugin::error(
+        ErrorCode::NOT_FOUND, "Failed to get ELF symbol from global '%s': %s",
+        ImageGlobal.getName().data(), toString(AddrOrErr.takeError()).data());
 
   // Setup the global symbol's address and size.
   ImageGlobal.setPtr(const_cast<void *>(*AddrOrErr));
@@ -143,7 +153,8 @@ Error GenericGlobalHandlerTy::readGlobalFromImage(GenericDeviceTy &Device,
     return Err;
 
   if (ImageGlobal.getSize() != HostGlobal.getSize())
-    return Plugin::error("Transfer failed because global symbol '%s' has "
+    return Plugin::error(ErrorCode::INVALID_BINARY,
+                         "Transfer failed because global symbol '%s' has "
                          "%u bytes in the ELF image but %u bytes on the host",
                          HostGlobal.getName().data(), ImageGlobal.getSize(),
                          HostGlobal.getSize());
@@ -274,7 +285,8 @@ void GPUProfGlobals::dump() const {
 
 Error GPUProfGlobals::write() const {
   if (!__llvm_write_custom_profile)
-    return Plugin::error("Could not find symbol __llvm_write_custom_profile. "
+    return Plugin::error(ErrorCode::INVALID_BINARY,
+                         "Could not find symbol __llvm_write_custom_profile. "
                          "The compiler-rt profiling library must be linked for "
                          "GPU PGO to work.");
 
@@ -307,7 +319,8 @@ Error GPUProfGlobals::write() const {
       TargetTriple.str().c_str(), DataBegin, DataEnd, CountersBegin,
       CountersEnd, NamesBegin, NamesEnd, &Version);
   if (result != 0)
-    return Plugin::error("Error writing GPU PGO data to file");
+    return Plugin::error(ErrorCode::HOST_IO,
+                         "Error writing GPU PGO data to file");
 
   return Plugin::success();
 }
diff --git a/offload/plugins-nextgen/common/src/JIT.cpp b/offload/plugins-nextgen/common/src/JIT.cpp
index affedb1a33687..fe2beaa88fa17 100644
--- a/offload/plugins-nextgen/common/src/JIT.cpp
+++ b/offload/plugins-nextgen/common/src/JIT.cpp
@@ -221,7 +221,7 @@ JITEngine::backend(Module &M, const std::string &ComputeUnitKind,
     raw_fd_stream FD(PostOptIRModuleFileName.get(), EC);
     if (EC)
       return createStringError(
-          EC, "Could not open %s to write the post-opt IR module\n",
+          plugin::ErrorCode::HOST_IO, "Could not open %s to write the post-opt IR module\n",
           PostOptIRModuleFileName.get().c_str());
     M.print(FD, nullptr);
   }
diff --git a/offload/plugins-nextgen/common/src/PluginInterface.cpp b/offload/plugins-nextgen/common/src/PluginInterface.cpp
index 059f14f59c38b..a12c0bd635140 100644
--- a/offload/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/offload/plugins-nextgen/common/src/PluginInterface.cpp
@@ -94,7 +94,8 @@ struct RecordReplayTy {
       return Err;
 
     if (isReplaying() && VAddr != MemoryStart) {
-      return Plugin::error("Record-Replay cannot assign the"
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Record-Replay cannot assign the"
                            "requested recorded address (%p, %p)",
                            VAddr, MemoryStart);
     }
@@ -121,7 +122,8 @@ struct RecordReplayTy {
         break;
     }
     if (!MemoryStart)
-      return Plugin::error("Allocating record/replay memory");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Allocating record/replay memory");
 
     if (VAddr && VAddr != MemoryStart)
       MemoryOffset = uintptr_t(VAddr) - uintptr_t(MemoryStart);
@@ -166,7 +168,8 @@ struct RecordReplayTy {
 
     uint64_t DevMemSize;
     if (Device->getDeviceMemorySize(DevMemSize))
-      return Plugin::error("Cannot determine Device Memory Size");
+      return Plugin::error(ErrorCode::UNKNOWN,
+                           "Cannot determine Device Memory Size");
 
     return preAllocateHeuristic(DevMemSize, DeviceMemorySize, ReqVAddr);
   }
@@ -1078,7 +1081,8 @@ Error PinnedAllocationMapTy::insertEntry(void *HstPtr, void *DevAccessiblePtr,
   // Insert the new entry into the map.
   auto Res = Allocs.insert({HstPtr, DevAccessiblePtr, Size, ExternallyLocked});
   if (!Res.second)
-    return Plugin::error("Cannot insert locked buffer entry");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Cannot insert locked buffer entry");
 
   // Check whether the next entry overlaps with the inserted entry.
   auto It = std::next(Res.first);
@@ -1087,7 +1091,8 @@ Error PinnedAllocationMapTy::insertEntry(void *HstPtr, void *DevAccessiblePtr,
 
   const EntryTy *NextEntry = &(*It);
   if (intersects(NextEntry->HstPtr, NextEntry->Size, HstPtr, Size))
-    return Plugin::error("Partial overlapping not allowed in locked buffers");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Partial overlapping not allowed in locked buffers");
 
   return Plugin::success();
 }
@@ -1098,14 +1103,16 @@ Error PinnedAllocationMapTy::eraseEntry(const EntryTy &Entry) {
   // the code more difficult to read.
   size_t Erased = Allocs.erase({Entry.HstPtr});
   if (!Erased)
-    return Plugin::error("Cannot erase locked buffer entry");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Cannot erase locked buffer entry");
   return Plugin::success();
 }
 
 Error PinnedAllocationMapTy::registerEntryUse(const EntryTy &Entry,
                                               void *HstPtr, size_t Size) {
   if (!contains(Entry.HstPtr, Entry.Size, HstPtr, Size))
-    return Plugin::error("Partial overlapping not allowed in locked buffers");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Partial overlapping not allowed in locked buffers");
 
   ++Entry.References;
   return Plugin::success();
@@ -1113,7 +1120,8 @@ Error PinnedAllocationMapTy::registerEntryUse(const EntryTy &Entry,
 
 Expected<bool> PinnedAllocationMapTy::unregisterEntryUse(const EntryTy &Entry) {
   if (Entry.References == 0)
-    return Plugin::error("Invalid number of references");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Invalid number of references");
 
   // Return whether this was the last user.
   return (--Entry.References == 0);
@@ -1131,7 +1139,8 @@ Error PinnedAllocationMapTy::registerHostBuffer(void *HstPtr,
   // No pinned allocation should intersect.
   const EntryTy *Entry = findIntersecting(HstPtr);
   if (Entry)
-    return Plugin::error("Cannot insert entry due to an existing one");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Cannot insert entry due to an existing one");
 
   // Now insert the new entry.
   return insertEntry(HstPtr, DevAccessiblePtr, Size);
@@ -1144,11 +1153,13 @@ Error PinnedAllocationMapTy::unregisterHostBuffer(void *HstPtr) {
 
   const EntryTy *Entry = findIntersecting(HstPtr);
   if (!Entry)
-    return Plugin::error("Cannot find locked buffer");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Cannot find locked buffer");
 
   // The address in the entry should be the same we are unregistering.
   if (Entry->HstPtr != HstPtr)
-    return Plugin::error("Unexpected host pointer in locked buffer entry");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Unexpected host pointer in locked buffer entry");
 
   // Unregister from the entry.
   auto LastUseOrErr = unregisterEntryUse(*Entry);
@@ -1157,7 +1168,8 @@ Error PinnedAllocationMapTy::unregisterHostBuffer(void *HstPtr) {
 
   // There should be no other references to the pinned allocation.
   if (!(*LastUseOrErr))
-    return Plugin::error("The locked buffer is still being used");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "The locked buffer is still being used");
 
   // Erase the entry from the map.
   return eraseEntry(*Entry);
@@ -1203,7 +1215,8 @@ Error PinnedAllocationMapTy::unlockHostBuffer(void *HstPtr) {
 
   const EntryTy *Entry = findIntersecting(HstPtr);
   if (!Entry)
-    return Plugin::error("Cannot find locked buffer");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Cannot find locked buffer");
 
   // Unregister from the locked buffer. No need to do anything if there are
   // others using the allocation.
@@ -1289,7 +1302,8 @@ Error PinnedAllocationMapTy::unlockUnmappedHostBuffer(void *HstPtr) {
 
   // No entry, but the automatic locking is enabled, so this is an error.
   if (!Entry)
-    return Plugin::error("Locked buffer not found");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Locked buffer not found");
 
   // There is entry, so unregister a user and check whether it was the last one.
   auto LastUseOrErr = unregisterEntryUse(*Entry);
@@ -1312,7 +1326,8 @@ Error PinnedAllocationMapTy::unlockUnmappedHostBuffer(void *HstPtr) {
 
 Error GenericDeviceTy::synchronize(__tgt_async_info *AsyncInfo) {
   if (!AsyncInfo || !AsyncInfo->Queue)
-    return Plugin::error("Invalid async info queue");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Invalid async info queue");
 
   if (auto Err = synchronizeImpl(*AsyncInfo))
     return Err;
@@ -1327,21 +1342,25 @@ Error GenericDeviceTy::synchronize(__tgt_async_info *AsyncInfo) {
 
 Error GenericDeviceTy::queryAsync(__tgt_async_info *AsyncInfo) {
   if (!AsyncInfo || !AsyncInfo->Queue)
-    return Plugin::error("Invalid async info queue");
+    return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                         "Invalid async info queue");
 
   return queryAsyncImpl(*AsyncInfo);
 }
 
 Error GenericDeviceTy::memoryVAMap(void **Addr, void *VAddr, size_t *RSize) {
-  return Plugin::error("Device does not support VA Management");
+  return Plugin::error(ErrorCode::UNSUPPORTED,
+                       "Device does not support VA Management");
 }
 
 Error GenericDeviceTy::memoryVAUnMap(void *VAddr, size_t Size) {
-  return Plugin::error("Device does not support VA Management");
+  return Plugin::error(ErrorCode::UNSUPPORTED,
+                       "Device does not support VA Management");
 }
 
 Error GenericDeviceTy::getDeviceMemorySize(uint64_t &DSize) {
   return Plugin::error(
+      ErrorCode::UNIMPLEMENTED,
       "Missing getDeviceMemorySize implementation (required by RR-heuristic");
 }
 
@@ -1359,7 +1378,8 @@ Expected<void *> GenericDeviceTy::dataAlloc(int64_t Size, void *HostPtr,
     if (MemoryManager) {
       Alloc = MemoryManager->allocate(Size, HostPtr);
       if (!Alloc)
-        return Plugin::error("Failed to allocate from memory manager");
+        return Plugin::error(ErrorCode::OUT_OF_RESOURCES,
+                             "Failed to allocate from memory manager");
       break;
     }
     [[fallthrough]];
@@ -1367,13 +1387,15 @@ Expected<void *> GenericDeviceTy::dataAlloc(int64_t Size, void *HostPtr,
   case TARGET_ALLOC_SHARED:
     Alloc = allocate(Size, HostPtr, Kind);
     if (!Alloc)
-      return Plugin::error("Failed to allocate from device allocator");
+      return Plugin::error(ErrorCode::OUT_OF_RESOURCES,
+                           "Failed to allocate from device allocator");
   }
 
   // Report error if the memory manager or the device allocator did not return
   // any memory buffer.
   if (!Alloc)
-    return Plugin::error("Invalid target data allocation kind or requested "
+    return Plugin::error(ErrorCode::UNIMPLEMENTED,
+                         "Invalid target data allocation kind or requested "
                          "allocator not implemented yet");
 
   // Register allocated buffer as pinned memory if the type is host memory.
@@ -1448,6 +1470,7 @@ Error GenericDeviceTy::dataDelete(void *TgtPtr, TargetAllocTy Kind) {
       Res = MemoryManager->free(TgtPtr);
       if (Res)
         return Plugin::error(
+            ErrorCode::OUT_OF_RESOURCES,
             "Failure to deallocate device pointer %p via memory manager",
             TgtPtr);
       break;
@@ -1458,6 +1481,7 @@ Error GenericDeviceTy::dataDelete(void *TgtPtr, TargetAllocTy Kind) {
     Res = free(TgtPtr, Kind);
     if (Res)
       return Plugin::error(
+          ErrorCode::UNKNOWN,
           "Failure to deallocate device pointer %p via device deallocator",
           TgtPtr);
   }
diff --git a/offload/plugins-nextgen/common/src/RPC.cpp b/offload/plugins-nextgen/common/src/RPC.cpp
index fc90bb2e032f2..ba0d8e9eafed2 100644
--- a/offload/plugins-nextgen/common/src/RPC.cpp
+++ b/offload/plugins-nextgen/common/src/RPC.cpp
@@ -176,6 +176,7 @@ Error RPCServerTy::initDevice(plugin::GenericDeviceTy &Device,
       TARGET_ALLOC_HOST);
   if (!RPCBuffer)
     return plugin::Plugin::error(
+        plugin::ErrorCode::UNKNOWN,
         "Failed to initialize RPC server for device %d", Device.getDeviceId());
 
   // Get the address of the RPC client from the device.
diff --git a/offload/plugins-nextgen/cuda/src/rtl.cpp b/offload/plugins-nextgen/cuda/src/rtl.cpp
index 0d0c4858aa7fa..3f30961554c17 100644
--- a/offload/plugins-nextgen/cuda/src/rtl.cpp
+++ b/offload/plugins-nextgen/cuda/src/rtl.cpp
@@ -134,7 +134,8 @@ struct CUDAKernelTy : public GenericKernelTy {
 
     // Check that the function pointer is valid.
     if (!Func)
-      return Plugin::error("Invalid function for kernel %s", getName());
+      return Plugin::error(ErrorCode::INVALID_BINARY,
+                           "Invalid function for kernel %s", getName());
 
     int MaxThreads;
     Res = cuFuncGetAttribute(&MaxThreads,
@@ -175,7 +176,8 @@ struct CUDAStreamRef final : public GenericDeviceResourceRef {
   /// before calling to this function.
   Error create(GenericDeviceTy &Device) override {
     if (Stream)
-      return Plugin::error("Creating an existing stream");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Creating an existing stream");
 
     CUresult Res = cuStreamCreate(&Stream, CU_STREAM_NON_BLOCKING);
     if (auto Err = Plugin::check(Res, "Error in cuStreamCreate: %s"))
@@ -188,7 +190,8 @@ struct CUDAStreamRef final : public GenericDeviceResourceRef {
   /// must be to a valid stream before calling to this function.
   Error destroy(GenericDeviceTy &Device) override {
     if (!Stream)
-      return Plugin::error("Destroying an invalid stream");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Destroying an invalid stream");
 
     CUresult Res = cuStreamDestroy(Stream);
     if (auto Err = Plugin::check(Res, "Error in cuStreamDestroy: %s"))
@@ -222,7 +225,8 @@ struct CUDAEventRef final : public GenericDeviceResourceRef {
   /// before calling to this function.
   Error create(GenericDeviceTy &Device) override {
     if (Event)
-      return Plugin::error("Creating an existing event");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Creating an existing event");
 
     CUresult Res = cuEventCreate(&Event, CU_EVENT_DEFAULT);
     if (auto Err = Plugin::check(Res, "Error in cuEventCreate: %s"))
@@ -235,7 +239,8 @@ struct CUDAEventRef final : public GenericDeviceResourceRef {
   /// must be to a valid event before calling to this function.
   Error destroy(GenericDeviceTy &Device) override {
     if (!Event)
-      return Plugin::error("Destroying an invalid event");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Destroying an invalid event");
 
     CUresult Res = cuEventDestroy(Event);
     if (auto Err = Plugin::check(Res, "Error in cuEventDestroy: %s"))
@@ -419,7 +424,8 @@ struct CUDADeviceTy : public GenericDeviceTy {
     std::error_code EC = sys::fs::createTemporaryFile("nvptx-pre-link-jit", "s",
                                                       PTXInputFilePath);
     if (EC)
-      return Plugin::error("Failed to create temporary file for ptxas");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to create temporary file for ptxas");
 
     // Write the file's contents to the output file.
     Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
@@ -435,12 +441,14 @@ struct CUDADeviceTy : public GenericDeviceTy {
     EC = sys::fs::createTemporaryFile("nvptx-post-link-jit", "cubin",
                                       PTXOutputFilePath);
     if (EC)
-      return Plugin::error("Failed to create temporary file for ptxas");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to create temporary file for ptxas");
 
     // Try to find `ptxas` in the path to compile the PTX to a binary.
     const auto ErrorOrPath = sys::findProgramByName("ptxas");
     if (!ErrorOrPath)
-      return Plugin::error("Failed to find 'ptxas' on the PATH.");
+      return Plugin::error(ErrorCode::HOST_TOOL_NOT_FOUND,
+                           "Failed to find 'ptxas' on the PATH.");
 
     std::string Arch = getComputeUnitKind();
     StringRef Args[] = {*ErrorOrPath,
@@ -455,17 +463,21 @@ struct CUDADeviceTy : public GenericDeviceTy {
     std::string ErrMsg;
     if (sys::ExecuteAndWait(*ErrorOrPath, Args, std::nullopt, {}, 0, 0,
                             &ErrMsg))
-      return Plugin::error("Running 'ptxas' failed: %s\n", ErrMsg.c_str());
+      return Plugin::error(ErrorCode::ASSEMBLE_FAILURE,
+                           "Running 'ptxas' failed: %s\n", ErrMsg.c_str());
 
     auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(PTXOutputFilePath.data());
     if (!BufferOrErr)
-      return Plugin::error("Failed to open temporary file for ptxas");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to open temporary file for ptxas");
 
     // Clean up the temporary files afterwards.
     if (sys::fs::remove(PTXOutputFilePath))
-      return Plugin::error("Failed to remove temporary file for ptxas");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to remove temporary file for ptxas");
     if (sys::fs::remove(PTXInputFilePath))
-      return Plugin::error("Failed to remove temporary file for ptxas");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to remove temporary file for ptxas");
 
     return std::move(*BufferOrErr);
   }
@@ -475,7 +487,8 @@ struct CUDADeviceTy : public GenericDeviceTy {
     // Allocate and construct the CUDA kernel.
     CUDAKernelTy *CUDAKernel = Plugin.allocate<CUDAKernelTy>();
     if (!CUDAKernel)
-      return Plugin::error("Failed to allocate memory for CUDA kernel");
+      return Plugin::error(ErrorCode::OUT_OF_RESOURCES,
+                           "Failed to allocate memory for CUDA kernel");
 
     new (CUDAKernel) CUDAKernelTy(Name);
 
@@ -658,11 +671,13 @@ struct CUDADeviceTy : public GenericDeviceTy {
     size_t Size = *RSize;
 
     if (Size == 0)
-      return Plugin::error("Memory Map Size must be larger than 0");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Memory Map Size must be larger than 0");
 
     // Check if we have already mapped this address
     if (IHandle != DeviceMMaps.end())
-      return Plugin::error("Address already memory mapped");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Address already memory mapped");
 
     CUmemAllocationProp Prop = {};
     size_t Granularity = 0;
@@ -675,6 +690,7 @@ struct CUDADeviceTy : public GenericDeviceTy {
     if (Size >= Free) {
       *Addr = nullptr;
       return Plugin::error(
+          ErrorCode::OUT_OF_RESOURCES,
           "Cannot map memory size larger than the available device memory");
     }
 
@@ -690,7 +706,8 @@ struct CUDADeviceTy : public GenericDeviceTy {
       return Err;
 
     if (Granularity == 0)
-      return Plugin::error("Wrong device Page size");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Wrong device Page size");
 
     // Ceil to page size.
     Size = utils::roundUp(Size, Granularity);
@@ -732,11 +749,13 @@ struct CUDADeviceTy : public GenericDeviceTy {
     auto IHandle = DeviceMMaps.find(DVAddr);
     // Mapping does not exist
     if (IHandle == DeviceMMaps.end()) {
-      return Plugin::error("Addr is not MemoryMapped");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Addr is not MemoryMapped");
     }
 
     if (IHandle == DeviceMMaps.end())
-      return Plugin::error("Addr is not MemoryMapped");
+      return Plugin::error(ErrorCode::INVALID_ARGUMENT,
+                           "Addr is not MemoryMapped");
 
     CUmemGenericAllocationHandle &AllocHandle = IHandle->second;
 
@@ -1156,7 +1175,8 @@ struct CUDADeviceTy : public GenericDeviceTy {
 
       uint16_t Priority;
       if (NameOrErr->rsplit('_').second.getAsInteger(10, Priority))
-        return Plugin::error("Invalid priority for constructor or destructor");
+        return Plugin::error(ErrorCode::INVALID_BINARY,
+                             "Invalid priority for constructor or destructor");
 
       Funcs.emplace_back(*NameOrErr, Priority);
     }
@@ -1169,7 +1189,8 @@ struct CUDADeviceTy : public GenericDeviceTy {
     void *Buffer =
         allocate(Funcs.size() * sizeof(void *), nullptr, TARGET_ALLOC_DEVICE);
     if (!Buffer)
-      return Plugin::error("Failed to allocate memory for global buffer");
+      return Plugin::error(ErrorCode::OUT_OF_RESOURCES,
+                           "Failed to allocate memory for global buffer");
 
     auto *GlobalPtrStart = reinterpret_cast<uintptr_t *>(Buffer);
     auto *GlobalPtrStop = reinterpret_cast<uintptr_t *>(Buffer) + Funcs.size();
@@ -1217,7 +1238,8 @@ struct CUDADeviceTy : public GenericDeviceTy {
     AsyncInfoWrapper.finalize(Err);
 
     if (free(Buffer, TARGET_ALLOC_DEVICE) != OFFLOAD_SUCCESS)
-      return Plugin::error("Failed to free memory for global buffer");
+      return Plugin::error(ErrorCode::UNKNOWN,
+                           "Failed to free memory for global buffer");
 
     return Err;
   }
@@ -1316,6 +1338,7 @@ class CUDAGlobalHandlerTy final : public GenericGlobalHandlerTy {
 
     if (CUSize != DeviceGlobal.getSize())
       return Plugin::error(
+          ErrorCode::INVALID_BINARY,
           "Failed to load global '%s' due to size mismatch (%zu != %zu)",
           GlobalName, CUSize, (size_t)DeviceGlobal.getSize());
 
@@ -1501,8 +1524,9 @@ static Error Plugin::check(int32_t Code, const char *ErrFmt, ArgsTy... Args) {
   if (Ret != CUDA_SUCCESS)
     REPORT("Unrecognized " GETNAME(TARGET_NAME) " error code %d\n", Code);
 
-  return createStringError<ArgsTy..., const char *>(inconvertibleErrorCode(),
-                                                    ErrFmt, Args..., Desc);
+  // TODO: Create a map for CUDA error codes to Offload error codes
+  return createStringError<ArgsTy..., const char *>(ErrorCode::UNKNOWN, ErrFmt,
+                                                    Args..., Desc);
 }
 
 } // namespace plugin
diff --git a/offload/plugins-nextgen/host/src/rtl.cpp b/offload/plugins-nextgen/host/src/rtl.cpp
index 171c202e3e39e..ca4e83a6897e8 100644
--- a/offload/plugins-nextgen/host/src/rtl.cpp
+++ b/offload/plugins-nextgen/host/src/rtl.cpp
@@ -74,7 +74,8 @@ struct GenELF64KernelTy : public GenericKernelTy {
 
     // Check that the function pointer is valid.
     if (!Global.getPtr())
-      return Plugin::error("Invalid function for kernel %s", getName());
+      return Plugin::error(ErrorCode::INVALID_BINARY,
+                           "Invalid function for kernel %s", getName());
 
     // Save the function pointer.
     Func = (void (*)())Global.getPtr();
@@ -102,7 +103,8 @@ struct GenELF64KernelTy : public GenericKernelTy {
     ffi_status Status = ffi_prep_cif(&Cif, FFI_DEFAULT_ABI, KernelArgs.NumArgs,
                                      &ffi_type_void, ArgTypesPtr);
     if (Status != FFI_OK)
-      return Plugin::error("Error in ffi_prep_cif: %d", Status);
+      return Plugin::error(ErrorCode::UNKNOWN, "Error in ffi_prep_cif: %d",
+                           Status);
 
     // Call the kernel function through libffi.
     long Return;
@@ -155,7 +157,8 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
     // Allocate and construct the kernel.
     GenELF64KernelTy *GenELF64Kernel = Plugin.allocate<GenELF64KernelTy>();
     if (!GenELF64Kernel)
-      return Plugin::error("Failed to allocate memory for GenELF64 kernel");
+      return Plugin::error(ErrorCode::OUT_OF_RESOURCES,
+                           "Failed to allocate memory for GenELF64 kernel");
 
     new (GenELF64Kernel) GenELF64KernelTy(Name);
 
@@ -176,24 +179,28 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
     char TmpFileName[] = "/tmp/tmpfile_XXXXXX";
     int TmpFileFd = mkstemp(TmpFileName);
     if (TmpFileFd == -1)
-      return Plugin::error("Failed to create tmpfile for loading target image");
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to create tmpfile for loading target image");
 
     // Open the temporary file.
     FILE *TmpFile = fdopen(TmpFileFd, "wb");
     if (!TmpFile)
-      return Plugin::error("Failed to open tmpfile %s for loading target image",
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to open tmpfile %s for loading target image",
                            TmpFileName);
 
     // Write the image into the temporary file.
     size_t Written = fwrite(Image->getStart(), Image->getSize(), 1, TmpFile);
     if (Written != 1)
-      return Plugin::error("Failed to write target image to tmpfile %s",
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to write target image to tmpfile %s",
                            TmpFileName);
 
     // Close the temporary file.
     int Ret = fclose(TmpFile);
     if (Ret)
-      return Plugin::error("Failed to close tmpfile %s with the target image",
+      return Plugin::error(ErrorCode::HOST_IO,
+                           "Failed to close tmpfile %s with the target image",
                            TmpFileName);
 
     // Load the temporary file as a dynamic library.
@@ -203,7 +210,8 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
 
     // Check if the loaded library is valid.
     if (!DynLib.isValid())
-      return Plugin::error("Failed to load target image: %s", ErrMsg.c_str());
+      return Plugin::error(ErrorCode::INVALID_BINARY,
+                           "Failed to load target image: %s", ErrMsg.c_str());
 
     // Save a reference of the image's dynamic library.
     Image->setDynamicLibrary(DynLib);
@@ -272,7 +280,8 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
                          AsyncInfoWrapperTy &AsyncInfoWrapper) override {
     // This function should never be called because the function
     // GenELF64PluginTy::isDataExchangable() returns false.
-    return Plugin::error("dataExchangeImpl not supported");
+    return Plugin::error(ErrorCode::UNSUPPORTED,
+                         "dataExchangeImpl not supported");
   }
 
   /// All functions are already synchronous. No need to do anything on this
@@ -289,12 +298,14 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
 
   /// This plugin does not support interoperability
   Error initAsyncInfoImpl(AsyncInfoWrapperTy &AsyncInfoWrapper) override {
-    return Plugin::error("initAsyncInfoImpl not supported");
+    return Plugin::error(ErrorCode::UNSUPPORTED,
+                         "initAsyncInfoImpl not supported");
   }
 
   /// This plugin does not support interoperability
   Error initDeviceInfoImpl(__tgt_device_info *DeviceInfo) override {
-    return Plugin::error("initDeviceInfoImpl not supported");
+    return Plugin::error(ErrorCode::UNSUPPORTED,
+                         "initDeviceInfoImpl not supported");
   }
 
   /// This plugin does not support the event API. Do nothing without failing.
@@ -365,7 +376,8 @@ class GenELF64GlobalHandlerTy final : public GenericGlobalHandlerTy {
     // Get the address of the symbol.
     void *Addr = DynLib.getAddressOfSymbol(GlobalName);
     if (Addr == nullptr) {
-      return Plugin::error("Failed to load global '%s'", GlobalName);
+      return Plugin::error(ErrorCode::NOT_FOUND, "Failed to load global '%s'",
+                           GlobalName);
     }
 
     // Save the pointer to the symbol.
diff --git a/offload/unittests/OffloadAPI/kernel/olGetKernel.cpp b/offload/unittests/OffloadAPI/kernel/olGetKernel.cpp
index bd1b562eac71e..b4c8f4b470315 100644
--- a/offload/unittests/OffloadAPI/kernel/olGetKernel.cpp
+++ b/offload/unittests/OffloadAPI/kernel/olGetKernel.cpp
@@ -31,8 +31,8 @@ TEST_P(olGetKernelTest, InvalidNullKernelPointer) {
 }
 
 // Error code returning from plugin interface not yet supported
-TEST_F(olGetKernelTest, DISABLED_InvalidKernelName) {
+TEST_F(olGetKernelTest, InvalidKernelName) {
   ol_kernel_handle_t Kernel = nullptr;
-  ASSERT_ERROR(OL_ERRC_INVALID_KERNEL_NAME,
+  ASSERT_ERROR(OL_ERRC_NOT_FOUND,
                olGetKernel(Program, "invalid_kernel_name", &Kernel));
 }



More information about the llvm-commits mailing list