Skip to content

Commit 33cfb9f

Browse files
authored
[SYCL] Diagnose unresolved symbols in L0 modules (#5267)
Diagnose an error in the Level Zero version of `piProgramBuild` and `piProgramLink` if the built program has any unresolved symbols. Also, include an error message with a list of the unresolved symbols in the build log, which is incorporated into the `what` string of the exception that the runtime throws. As a result, the user will see a list of the unresolved symbols when the exception terminates the application. Previously, no error was diagnosed from `piProgramBuild` or `piProgramLink` when there were unresolved symbols, but the first call to `piKernelCreate` would fail (without any indication about the cause of the failure).
1 parent c690ac8 commit 33cfb9f

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

sycl/plugins/level_zero/pi_level_zero.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,10 @@ extern "C" {
15891589
// Forward declarations
15901590
decltype(piEventCreate) piEventCreate;
15911591

1592+
static ze_result_t
1593+
checkUnresolvedSymbols(ze_module_handle_t ZeModule,
1594+
ze_module_build_log_handle_t *ZeBuildLog);
1595+
15921596
// This function will ensure compatibility with both Linux and Windows for
15931597
// setting environment variables.
15941598
static bool setEnvVar(const char *name, const char *value) {
@@ -3887,6 +3891,22 @@ pi_result piProgramLink(pi_context Context, pi_uint32 NumDevices,
38873891
return PiResult;
38883892
}
38893893

3894+
// The call to zeModuleCreate does not report an error if there are
3895+
// unresolved symbols because it thinks these could be resolved later via a
3896+
// call to zeModuleDynamicLink. However, modules created with piProgramLink
3897+
// are supposed to be fully linked and ready to use. Therefore, do an extra
3898+
// check now for unresolved symbols. Note that we still create a
3899+
// _pi_program if there are unresolved symbols because the ZeBuildLog tells
3900+
// which symbols are unresolved.
3901+
if (ZeResult == ZE_RESULT_SUCCESS) {
3902+
ZeResult = checkUnresolvedSymbols(ZeModule, &ZeBuildLog);
3903+
if (ZeResult == ZE_RESULT_ERROR_MODULE_LINK_FAILURE) {
3904+
PiResult = PI_LINK_PROGRAM_FAILURE;
3905+
} else if (ZeResult != ZE_RESULT_SUCCESS) {
3906+
return mapError(ZeResult);
3907+
}
3908+
}
3909+
38903910
_pi_program::state State =
38913911
(PiResult == PI_SUCCESS) ? _pi_program::Exe : _pi_program::Invalid;
38923912
*RetProgram = new _pi_program(State, Context, ZeModule, ZeBuildLog);
@@ -3985,6 +4005,18 @@ pi_result piProgramBuild(pi_program Program, pi_uint32 NumDevices,
39854005
ZE_CALL(zeModuleCreate, (ZeContext, ZeDevice, &ZeModuleDesc, &ZeModule,
39864006
&Program->ZeBuildLog));
39874007

4008+
// The call to zeModuleCreate does not report an error if there are
4009+
// unresolved symbols because it thinks these could be resolved later via a
4010+
// call to zeModuleDynamicLink. However, modules created with piProgramBuild
4011+
// are supposed to be fully linked and ready to use. Therefore, do an extra
4012+
// check now for unresolved symbols.
4013+
ze_result_t ZeResult = checkUnresolvedSymbols(ZeModule, &Program->ZeBuildLog);
4014+
if (ZeResult == ZE_RESULT_ERROR_MODULE_LINK_FAILURE) {
4015+
return PI_BUILD_PROGRAM_FAILURE;
4016+
} else if (ZeResult != ZE_RESULT_SUCCESS) {
4017+
return mapError(ZeResult);
4018+
}
4019+
39884020
// We no longer need the IL / native code.
39894021
Program->Code.reset();
39904022

@@ -4111,6 +4143,40 @@ _pi_program::~_pi_program() {
41114143
}
41124144
}
41134145

4146+
// Check to see if a Level Zero module has any unresolved symbols.
4147+
//
4148+
// @param ZeModule The module handle to check.
4149+
// @param ZeBuildLog If there are unresolved symbols, this build log handle is
4150+
// modified to receive information telling which symbols
4151+
// are unresolved.
4152+
//
4153+
// @return ZE_RESULT_ERROR_MODULE_LINK_FAILURE indicates there are unresolved
4154+
// symbols. ZE_RESULT_SUCCESS indicates all symbols are resolved. Any other
4155+
// value indicates there was an error and we cannot tell if symbols are
4156+
// resolved.
4157+
static ze_result_t
4158+
checkUnresolvedSymbols(ze_module_handle_t ZeModule,
4159+
ze_module_build_log_handle_t *ZeBuildLog) {
4160+
4161+
// First check to see if the module has any imported symbols. If there are
4162+
// no imported symbols, it's not possible to have any unresolved symbols. We
4163+
// do this check first because we assume it's faster than the call to
4164+
// zeModuleDynamicLink below.
4165+
ZeStruct<ze_module_properties_t> ZeModuleProps;
4166+
ze_result_t ZeResult =
4167+
ZE_CALL_NOCHECK(zeModuleGetProperties, (ZeModule, &ZeModuleProps));
4168+
if (ZeResult != ZE_RESULT_SUCCESS)
4169+
return ZeResult;
4170+
4171+
// If there are imported symbols, attempt to "link" the module with itself.
4172+
// As a side effect, this will return the error
4173+
// ZE_RESULT_ERROR_MODULE_LINK_FAILURE if there are any unresolved symbols.
4174+
if (ZeModuleProps.flags & ZE_MODULE_PROPERTY_FLAG_IMPORTS) {
4175+
return ZE_CALL_NOCHECK(zeModuleDynamicLink, (1, &ZeModule, ZeBuildLog));
4176+
}
4177+
return ZE_RESULT_SUCCESS;
4178+
}
4179+
41144180
pi_result piKernelCreate(pi_program Program, const char *KernelName,
41154181
pi_kernel *RetKernel) {
41164182

0 commit comments

Comments
 (0)