Skip to content

Commit 25c75c0

Browse files
committed
[UR] Improve handling of error cases in urProgramLink
Note that this change includes a specification change: urProgramLink now requires the output parameter to contain either nullptr or some unspecified binary on failure. As well as this change, a number of bugs have been fixed: * The Level Zero adapter now correctly returns `UR_RESULT_ERROR_PROGRAM_LINK_FAILURE` when linking fails, rather than `UR_RESULT_ERROR_UNKNOWN`. * A workaround has been added for some OpenCL devices that return `CL_INVALID_BINARY` rather than `CL_LINK_PROGRAM_FAILURE` on linker failure. * The `phProgram` handle is wrapped in a loader handle by the loader even if an error would be returned. This is required by Level Zero, which outputs a "dummy" program to store the linker log. Conformance tests have also been added.
1 parent 9d3bce6 commit 25c75c0

25 files changed

+252
-33
lines changed

include/ur_api.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4277,6 +4277,11 @@ urProgramCompile(
42774277
/// in `phProgram` will contain a binary of the
42784278
/// ::UR_PROGRAM_BINARY_TYPE_EXECUTABLE type for each device in
42794279
/// `hContext`.
4280+
/// - If a non-success code is returned and `phProgram` is not `nullptr`, it
4281+
/// will contain an unspecified program or `nullptr`. Implementations may
4282+
/// use the build log of this program (accessible via
4283+
/// ::urProgramGetBuildInfo) to provide an error log for the linking
4284+
/// failure.
42804285
///
42814286
/// @remarks
42824287
/// _Analogues_
@@ -9278,6 +9283,11 @@ urProgramCompileExp(
92789283
/// in `phProgram` will contain a binary of the
92799284
/// ::UR_PROGRAM_BINARY_TYPE_EXECUTABLE type for each device in
92809285
/// `phDevices`.
9286+
/// - If a non-success code is returned and `phProgram` is not `nullptr`, it
9287+
/// will contain an unspecified program or `nullptr`. Implementations may
9288+
/// use the build log of this program (accessible via
9289+
/// ::urProgramGetBuildInfo) to provide an error log for the linking
9290+
/// failure.
92819291
///
92829292
/// @remarks
92839293
/// _Analogues_

scripts/core/exp-multi-device-compile.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ analogue:
9494
details:
9595
- "The application may call this function from simultaneous threads."
9696
- "Following a successful call to this entry point the program returned in `phProgram` will contain a binary of the $X_PROGRAM_BINARY_TYPE_EXECUTABLE type for each device in `phDevices`."
97+
- "If a non-success code is returned and `phProgram` is not `nullptr`, it will contain an unspecified program or `nullptr`. Implementations may use the build log of this program (accessible via $xProgramGetBuildInfo) to provide an error log for the linking failure."
9798
params:
9899
- type: $x_context_handle_t
99100
name: hContext

scripts/core/program.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ analogue:
223223
details:
224224
- "The application may call this function from simultaneous threads."
225225
- "Following a successful call to this entry point the program returned in `phProgram` will contain a binary of the $X_PROGRAM_BINARY_TYPE_EXECUTABLE type for each device in `hContext`."
226+
- "If a non-success code is returned and `phProgram` is not `nullptr`, it will contain an unspecified program or `nullptr`. Implementations may use the build log of this program (accessible via $xProgramGetBuildInfo) to provide an error log for the linking failure."
226227
params:
227228
- type: $x_context_handle_t
228229
name: hContext

scripts/templates/helper.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,30 @@ def get_pfntables(specs, meta, namespace, tags):
12481248

12491249
return tables
12501250

1251+
"""
1252+
Public:
1253+
returns an expression setting required output parameters to null on entry
1254+
"""
1255+
def get_initial_null_set(obj):
1256+
cname = obj_traits.class_name(obj)
1257+
lvalue = {
1258+
('$xProgram', 'Link'): 'phProgram',
1259+
('$xProgram', 'LinkExp'): 'phProgram',
1260+
}.get((cname, obj['name']))
1261+
if lvalue is not None:
1262+
return 'if (nullptr != {0}) {{*{0} = nullptr;}}'.format(lvalue)
1263+
return ""
1264+
1265+
"""
1266+
Public:
1267+
returns true if the function always wraps output pointers in loader handles
1268+
"""
1269+
def always_wrap_outputs(obj):
1270+
cname = obj_traits.class_name(obj)
1271+
return (cname, obj['name']) in [
1272+
('$xProgram', 'Link'),
1273+
('$xProgram', 'LinkExp'),
1274+
]
12511275

12521276
"""
12531277
Private:

scripts/templates/ldrddi.cpp.mako

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ namespace ur_loader
4949
{
5050
${x}_result_t result = ${X}_RESULT_SUCCESS;<%
5151
add_local = False
52-
%>
52+
%>${th.get_initial_null_set(obj)}
5353

5454
%if re.match(r"\w+AdapterGet$", th.make_func_name(n, tags, obj)):
5555

@@ -271,7 +271,7 @@ namespace ur_loader
271271
del add_local
272272
%>
273273
%for i, item in enumerate(epilogue):
274-
%if 0 == i and not item['release']:
274+
%if 0 == i and not item['release'] and not th.always_wrap_outputs(obj):
275275
if( ${X}_RESULT_SUCCESS != result )
276276
return result;
277277
@@ -309,7 +309,7 @@ namespace ur_loader
309309
${item['factory']}.getInstance( ${item['name']}[ i ], dditable ) );
310310
%else:
311311
// convert platform handle to loader handle
312-
%if item['optional']:
312+
%if item['optional'] or th.always_wrap_outputs(obj):
313313
if( nullptr != ${item['name']} )
314314
*${item['name']} = reinterpret_cast<${item['type']}>(
315315
${item['factory']}.getInstance( *${item['name']}, dditable ) );

scripts/templates/libapi.cpp.mako

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ try {
7777
%elif th.obj_traits.is_loader_only(obj):
7878
return ur_lib::${th.make_func_name(n, tags, obj)}(${", ".join(th.make_param_lines(n, tags, obj, format=["name"]))} );
7979
%else:
80-
auto ${th.make_pfn_name(n, tags, obj)} = ${x}_lib::context->${n}DdiTable.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)};
80+
${th.get_initial_null_set(obj)}auto ${th.make_pfn_name(n, tags, obj)} = ${x}_lib::context->${n}DdiTable.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)};
8181
if( nullptr == ${th.make_pfn_name(n, tags, obj)} )
8282
return ${X}_RESULT_ERROR_UNINITIALIZED;
8383

scripts/templates/nullddi.cpp.mako

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace driver
3838
)
3939
try {
4040
${x}_result_t result = ${X}_RESULT_SUCCESS;
41+
${th.get_initial_null_set(obj)}
4142

4243
// if the driver has created a custom function, then call it instead of using the generic path
4344
auto ${th.make_pfn_name(n, tags, obj)} = d_context.${n}DdiTable.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)};

scripts/templates/trcddi.cpp.mako

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace ur_tracing_layer
3636
${line}
3737
%endfor
3838
)
39-
{
39+
{${th.get_initial_null_set(obj)}
4040
auto ${th.make_pfn_name(n, tags, obj)} = context.${n}DdiTable.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)};
4141

4242
if( nullptr == ${th.make_pfn_name(n, tags, obj)} )

scripts/templates/valddi.cpp.mako

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace ur_validation_layer
4646
${line}
4747
%endfor
4848
)
49-
{
49+
{${th.get_initial_null_set(obj)}
5050
auto ${th.make_pfn_name(n, tags, obj)} = context.${n}DdiTable.${th.get_table_name(n, tags, obj)}.${th.make_pfn_name(n, tags, obj)};
5151

5252
if( nullptr == ${th.make_pfn_name(n, tags, obj)} ) {

source/adapters/cuda/program.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,10 @@ UR_APIEXPORT ur_result_t UR_APICALL urProgramBuild(ur_context_handle_t hContext,
272272

273273
UR_APIEXPORT ur_result_t UR_APICALL urProgramLinkExp(
274274
ur_context_handle_t, uint32_t, ur_device_handle_t *, uint32_t,
275-
const ur_program_handle_t *, const char *, ur_program_handle_t *) {
275+
const ur_program_handle_t *, const char *, ur_program_handle_t *phProgram) {
276+
if (nullptr != phProgram) {
277+
*phProgram = nullptr;
278+
}
276279
return UR_RESULT_ERROR_UNSUPPORTED_FEATURE;
277280
}
278281

@@ -284,6 +287,10 @@ urProgramLink(ur_context_handle_t hContext, uint32_t count,
284287
const ur_program_handle_t *phPrograms, const char *pOptions,
285288
ur_program_handle_t *phProgram) {
286289
ur_result_t Result = UR_RESULT_SUCCESS;
290+
if (nullptr != phProgram) {
291+
*phProgram = nullptr;
292+
}
293+
287294
// All programs must be associated with the same device
288295
for (auto i = 1u; i < count; ++i)
289296
UR_ASSERT(phPrograms[i]->getDevice() == phPrograms[0]->getDevice(),

0 commit comments

Comments
 (0)