diff --git a/unified-runtime/source/adapters/offload/program.cpp b/unified-runtime/source/adapters/offload/program.cpp index ec73469bfb883..fa5246c8a7e58 100644 --- a/unified-runtime/source/adapters/offload/program.cpp +++ b/unified-runtime/source/adapters/offload/program.cpp @@ -97,6 +97,7 @@ UR_APIEXPORT ur_result_t UR_APICALL urProgramCreateWithBinary( Program->URContext = hContext; Program->Binary = RealBinary; Program->BinarySizeInBytes = RealLength; + Program->BinaryType = UR_PROGRAM_BINARY_TYPE_COMPILED_OBJECT; // Parse properties if (pProperties) { @@ -160,24 +161,68 @@ urProgramCreateWithIL(ur_context_handle_t hContext, const void *pIL, } UR_APIEXPORT ur_result_t UR_APICALL urProgramBuild(ur_context_handle_t, - ur_program_handle_t, - const char *) { + ur_program_handle_t hProgram, + const char *pOptions) { // Do nothing, program is built upon creation + if (pOptions && *pOptions) { + hProgram->Error = "Liboffload doesn't support link options"; + return UR_RESULT_ERROR_PROGRAM_LINK_FAILURE; + } + hProgram->BinaryType = UR_PROGRAM_BINARY_TYPE_EXECUTABLE; return UR_RESULT_SUCCESS; } -UR_APIEXPORT ur_result_t UR_APICALL urProgramBuildExp(ur_program_handle_t, - uint32_t, - ur_device_handle_t *, - const char *) { +UR_APIEXPORT ur_result_t UR_APICALL +urProgramBuildExp(ur_program_handle_t hProgram, uint32_t, ur_device_handle_t *, + const char *pOptions) { // Do nothing, program is built upon creation + if (pOptions && *pOptions) { + hProgram->Error = "Liboffload doesn't support link options"; + return UR_RESULT_ERROR_PROGRAM_LINK_FAILURE; + } + hProgram->BinaryType = UR_PROGRAM_BINARY_TYPE_EXECUTABLE; return UR_RESULT_SUCCESS; } -UR_APIEXPORT ur_result_t UR_APICALL urProgramCompile(ur_context_handle_t, - ur_program_handle_t, - const char *) { +UR_APIEXPORT ur_result_t UR_APICALL urProgramCompile( + ur_context_handle_t, ur_program_handle_t hProgram, const char *pOptions) { // Do nothing, program is built upon creation + if (pOptions && *pOptions) { + hProgram->Error = "Liboffload doesn't support link options"; + return UR_RESULT_ERROR_PROGRAM_LINK_FAILURE; + } + hProgram->BinaryType = UR_PROGRAM_BINARY_TYPE_COMPILED_OBJECT; + return UR_RESULT_SUCCESS; +} + +UR_APIEXPORT ur_result_t UR_APICALL +urProgramLink(ur_context_handle_t hContext, uint32_t count, + const ur_program_handle_t *phPrograms, const char *pOptions, + ur_program_handle_t *phProgram) { + if (count > 1) { + *phProgram = ur_program_handle_t_::newErrorProgram( + hContext, nullptr, 0, + "Liboffload does not support linking multiple binaries"); + return UR_RESULT_ERROR_PROGRAM_LINK_FAILURE; + } + if (pOptions) { + *phProgram = ur_program_handle_t_::newErrorProgram( + hContext, nullptr, 0, "Liboffload does not support linker options"); + return UR_RESULT_ERROR_PROGRAM_LINK_FAILURE; + } + assert(count == 1); + + // Offload programs are already fully linked on creation, just create a new + // program containing it + auto *InProgram = *phPrograms; + ur_program_handle_t Program = new ur_program_handle_t_{}; + Program->URContext = hContext; + Program->Binary = InProgram->Binary; + Program->BinarySizeInBytes = InProgram->BinarySizeInBytes; + Program->GlobalIDMD = InProgram->GlobalIDMD; + Program->BinaryType = UR_PROGRAM_BINARY_TYPE_EXECUTABLE; + *phProgram = Program; + return UR_RESULT_SUCCESS; } @@ -230,6 +275,28 @@ urProgramGetInfo(ur_program_handle_t hProgram, ur_program_info_t propName, return UR_RESULT_SUCCESS; } +UR_APIEXPORT ur_result_t UR_APICALL +urProgramGetBuildInfo(ur_program_handle_t hProgram, ur_device_handle_t, + ur_program_build_info_t propName, size_t propSize, + void *pPropValue, size_t *pPropSizeRet) { + UrReturnHelper ReturnValue(propSize, pPropValue, pPropSizeRet); + switch (propName) { + case UR_PROGRAM_BUILD_INFO_STATUS: + return ReturnValue(hProgram->Error.empty() ? UR_PROGRAM_BUILD_STATUS_SUCCESS + : UR_PROGRAM_BUILD_STATUS_ERROR); + case UR_PROGRAM_BUILD_INFO_OPTIONS: + return ReturnValue(""); + case UR_PROGRAM_BUILD_INFO_LOG: + return ReturnValue(hProgram->Error.c_str()); + case UR_PROGRAM_BUILD_INFO_BINARY_TYPE: + return ReturnValue(hProgram->BinaryType); + default: + return UR_RESULT_ERROR_INVALID_ENUMERATION; + } + + return UR_RESULT_SUCCESS; +} + UR_APIEXPORT ur_result_t UR_APICALL urProgramRetain(ur_program_handle_t hProgram) { hProgram->RefCount++; @@ -239,11 +306,12 @@ urProgramRetain(ur_program_handle_t hProgram) { UR_APIEXPORT ur_result_t UR_APICALL urProgramRelease(ur_program_handle_t hProgram) { if (--hProgram->RefCount == 0) { - auto Res = olDestroyProgram(hProgram->OffloadProgram); - if (Res) { - return offloadResultToUR(Res); + if (hProgram->OffloadProgram) { + if (auto Res = olDestroyProgram(hProgram->OffloadProgram)) { + return offloadResultToUR(Res); + } + delete hProgram; } - delete hProgram; } return UR_RESULT_SUCCESS; diff --git a/unified-runtime/source/adapters/offload/program.hpp b/unified-runtime/source/adapters/offload/program.hpp index 0f93fe68d93d0..8bf48f5232efe 100644 --- a/unified-runtime/source/adapters/offload/program.hpp +++ b/unified-runtime/source/adapters/offload/program.hpp @@ -22,4 +22,23 @@ struct ur_program_handle_t_ : RefCounted { size_t BinarySizeInBytes; // A mapping from mangled global names -> names in the binary std::unordered_map GlobalIDMD; + // The UR offload backend doesn't draw distinctions between these types (we + // always have a fully built binary), but we need to track what state we are + // pretending to be in + ur_program_binary_type_t BinaryType; + std::string Error; + + static ur_program_handle_t_ *newErrorProgram(ur_context_handle_t Context, + const uint8_t *Binary, + size_t BinarySizeInBytes, + std::string &&Error) { + return new ur_program_handle_t_{{}, + nullptr, + Context, + Binary, + BinarySizeInBytes, + {}, + UR_PROGRAM_BINARY_TYPE_NONE, + Error}; + } }; diff --git a/unified-runtime/source/adapters/offload/ur_interface_loader.cpp b/unified-runtime/source/adapters/offload/ur_interface_loader.cpp index 17e5a74679511..b7caf06e93124 100644 --- a/unified-runtime/source/adapters/offload/ur_interface_loader.cpp +++ b/unified-runtime/source/adapters/offload/ur_interface_loader.cpp @@ -90,12 +90,12 @@ UR_DLLEXPORT ur_result_t UR_APICALL urGetProgramProcAddrTable( pDdiTable->pfnCreateWithBinary = urProgramCreateWithBinary; pDdiTable->pfnCreateWithIL = urProgramCreateWithIL; pDdiTable->pfnCreateWithNativeHandle = urProgramCreateWithNativeHandle; - pDdiTable->pfnGetBuildInfo = nullptr; + pDdiTable->pfnGetBuildInfo = urProgramGetBuildInfo; pDdiTable->pfnGetFunctionPointer = urProgramGetFunctionPointer; pDdiTable->pfnGetGlobalVariablePointer = urProgramGetGlobalVariablePointer; pDdiTable->pfnGetInfo = urProgramGetInfo; pDdiTable->pfnGetNativeHandle = urProgramGetNativeHandle; - pDdiTable->pfnLink = nullptr; + pDdiTable->pfnLink = urProgramLink; pDdiTable->pfnRelease = urProgramRelease; pDdiTable->pfnRetain = urProgramRetain; pDdiTable->pfnSetSpecializationConstants = diff --git a/unified-runtime/test/conformance/program/urProgramBuild.cpp b/unified-runtime/test/conformance/program/urProgramBuild.cpp index 106d0f5ea617e..19cadf08cf522 100644 --- a/unified-runtime/test/conformance/program/urProgramBuild.cpp +++ b/unified-runtime/test/conformance/program/urProgramBuild.cpp @@ -30,29 +30,28 @@ TEST_P(urProgramBuildTest, InvalidNullHandleProgram) { } TEST_P(urProgramBuildTest, BuildFailure) { - UUR_KNOWN_FAILURE_ON(uur::CUDA{}, uur::HIP{}); - - ur_program_handle_t program = nullptr; - std::shared_ptr> il_binary; - UUR_RETURN_ON_FATAL_FAILURE(uur::KernelsEnvironment::instance->LoadSource( - "build_failure", platform, il_binary)); - if (!il_binary) { - // The build failure we are testing for happens at SYCL compile time on - // AMD and Nvidia, so no binary exists to check for a build failure - GTEST_SKIP() << "Build failure test not supported on AMD/Nvidia yet"; - return; + // The build failure we are testing for happens at SYCL compile time on + // AMD and Nvidia, so no binary exists to check for a build failure + ur_backend_t backend; + ASSERT_SUCCESS(urPlatformGetInfo(platform, UR_PLATFORM_INFO_BACKEND, + sizeof(ur_backend_t), &backend, nullptr)); + if (backend == UR_BACKEND_HIP || backend == UR_BACKEND_CUDA || + backend == UR_BACKEND_OFFLOAD) { + GTEST_SKIP() + << "Build failure test not supported on AMD/Nvidia/Offload yet"; } - // TODO: This seems to fail on opencl/device combination used in the Github // runners (`2023.16.12.0.12_195853.xmain-hotfix`). It segfaults, so we just // skip the test so other tests can run - ur_backend_t backend; - ASSERT_SUCCESS(urPlatformGetInfo(platform, UR_PLATFORM_INFO_BACKEND, - sizeof(ur_backend_t), &backend, nullptr)); if (backend == UR_BACKEND_OPENCL) { GTEST_SKIP() << "Skipping opencl build failure test - segfaults on CI"; } + ur_program_handle_t program = nullptr; + std::shared_ptr> il_binary; + UUR_RETURN_ON_FATAL_FAILURE(uur::KernelsEnvironment::instance->LoadSource( + "build_failure", platform, il_binary)); + ASSERT_EQ_RESULT(UR_RESULT_SUCCESS, urProgramCreateWithIL(context, il_binary->data(), il_binary->size(), nullptr, &program)); diff --git a/unified-runtime/test/conformance/program/urProgramLink.cpp b/unified-runtime/test/conformance/program/urProgramLink.cpp index f9be218020688..0d6a3e666559d 100644 --- a/unified-runtime/test/conformance/program/urProgramLink.cpp +++ b/unified-runtime/test/conformance/program/urProgramLink.cpp @@ -94,6 +94,10 @@ struct urProgramLinkErrorTest : uur::urQueueTest { if (backend == UR_BACKEND_CUDA) { GTEST_SKIP(); } + // Not meaningful for liboffload + if (backend == UR_BACKEND_OFFLOAD) { + GTEST_SKIP(); + } std::shared_ptr> il_binary{}; UUR_RETURN_ON_FATAL_FAILURE(uur::KernelsEnvironment::instance->LoadSource(