Skip to content

Commit cde718e

Browse files
sommerlukasndgrigorian
authored andcommitted
Support compilation from SYCL source code
Enable SYCL source compilation, but only for DPC++ versions that actually support the compilation, based on the __SYCL_COMPILER_VERSION reported. Uses the correct naming for the property based on DPC++ version, detected through C++ type traits to check which property actually refers to a fully defined type. This commit also works around a bug in DPC++ version 2025.1. The constructor with no parameter of class `include_files` was only declared, but never defined. Calling it when creating a SYCL source kernel bundle therefore leads to references to undefined symbols with DPC++ version 2025.1. This change works around this issue by calling an alternative constructor, which is defined in the release. Signed-off-by: Lukas Sommer <lukas.sommer@codeplay.com>
1 parent b205e8c commit cde718e

12 files changed

Lines changed: 1000 additions & 9 deletions

dpctl/_backend.pxd

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,12 @@ cdef extern from "syclinterface/dpctl_sycl_device_interface.h":
287287
_peer_access PT)
288288
cdef void DPCTLDevice_EnablePeerAccess(const DPCTLSyclDeviceRef DRef,
289289
const DPCTLSyclDeviceRef PDRef)
290-
291290
cdef void DPCTLDevice_DisablePeerAccess(const DPCTLSyclDeviceRef DRef,
292291
const DPCTLSyclDeviceRef PDRef)
292+
cdef bool DPCTLDevice_CanCompileSPIRV(const DPCTLSyclDeviceRef DRef)
293+
cdef bool DPCTLDevice_CanCompileOpenCL(const DPCTLSyclDeviceRef DRef)
294+
cdef bool DPCTLDevice_CanCompileSYCL(const DPCTLSyclDeviceRef DRef)
295+
293296

294297
cdef extern from "syclinterface/dpctl_sycl_device_manager.h":
295298
cdef DPCTLDeviceVectorRef DPCTLDeviceVector_CreateFromArray(
@@ -452,6 +455,51 @@ cdef extern from "syclinterface/dpctl_sycl_kernel_bundle_interface.h":
452455
cdef DPCTLSyclKernelBundleRef DPCTLKernelBundle_Copy(
453456
const DPCTLSyclKernelBundleRef KBRef)
454457

458+
cdef struct DPCTLBuildOptionList
459+
cdef struct DPCTLKernelNameList
460+
cdef struct DPCTLVirtualHeaderList
461+
cdef struct DPCTLKernelBuildLog
462+
ctypedef DPCTLBuildOptionList* DPCTLBuildOptionListRef
463+
ctypedef DPCTLKernelNameList* DPCTLKernelNameListRef
464+
ctypedef DPCTLVirtualHeaderList* DPCTLVirtualHeaderListRef
465+
ctypedef DPCTLKernelBuildLog* DPCTLKernelBuildLogRef
466+
467+
cdef DPCTLBuildOptionListRef DPCTLBuildOptionList_Create()
468+
cdef void DPCTLBuildOptionList_Delete(DPCTLBuildOptionListRef Ref)
469+
cdef void DPCTLBuildOptionList_Append(DPCTLBuildOptionListRef Ref,
470+
const char *Option)
471+
472+
cdef DPCTLKernelNameListRef DPCTLKernelNameList_Create()
473+
cdef void DPCTLKernelNameList_Delete(DPCTLKernelNameListRef Ref)
474+
cdef void DPCTLKernelNameList_Append(DPCTLKernelNameListRef Ref,
475+
const char *Option)
476+
477+
cdef DPCTLVirtualHeaderListRef DPCTLVirtualHeaderList_Create()
478+
cdef void DPCTLVirtualHeaderList_Delete(DPCTLVirtualHeaderListRef Ref)
479+
cdef void DPCTLVirtualHeaderList_Append(DPCTLVirtualHeaderListRef Ref,
480+
const char *Name,
481+
const char *Content)
482+
483+
cdef DPCTLKernelBuildLogRef DPCTLKernelBuildLog_Create()
484+
cdef void DPCTLKernelBuildLog_Delete(DPCTLKernelBuildLogRef Ref)
485+
cdef const char *DPCTLKernelBuildLog_Get(DPCTLKernelBuildLogRef)
486+
487+
cdef DPCTLSyclKernelBundleRef DPCTLKernelBundle_CreateFromSYCLSource(
488+
const DPCTLSyclContextRef Ctx,
489+
const DPCTLSyclDeviceRef Dev,
490+
const char *Source,
491+
DPCTLVirtualHeaderListRef Headers,
492+
DPCTLKernelNameListRef Names,
493+
DPCTLBuildOptionListRef BuildOptions,
494+
DPCTLKernelBuildLogRef BuildLog)
495+
496+
cdef DPCTLSyclKernelRef DPCTLKernelBundle_GetSyclKernel(
497+
DPCTLSyclKernelBundleRef KBRef,
498+
const char *KernelName)
499+
500+
cdef bool DPCTLKernelBundle_HasSyclKernel(DPCTLSyclKernelBundleRef KBRef,
501+
const char *KernelName)
502+
455503

456504
cdef extern from "syclinterface/dpctl_sycl_queue_interface.h":
457505
ctypedef struct _md_local_accessor "MDLocalAccessor":

dpctl/_sycl_device.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,4 @@ cdef public api class SyclDevice(_SyclDevice) [
6161
cdef int get_overall_ordinal(self)
6262
cdef int get_backend_ordinal(self)
6363
cdef int get_backend_and_device_type_ordinal(self)
64+
cpdef bint can_compile(self, str language)

dpctl/_sycl_device.pyx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ from ._backend cimport ( # noqa: E211
2626
DPCTLDefaultSelector_Create,
2727
DPCTLDevice_AreEq,
2828
DPCTLDevice_CanAccessPeer,
29+
DPCTLDevice_CanCompileOpenCL,
30+
DPCTLDevice_CanCompileSPIRV,
31+
DPCTLDevice_CanCompileSYCL,
2932
DPCTLDevice_Copy,
3033
DPCTLDevice_CreateFromSelector,
3134
DPCTLDevice_CreateSubDevicesByAffinity,
@@ -2363,6 +2366,34 @@ cdef class SyclDevice(_SyclDevice):
23632366
raise ValueError("device could not be found")
23642367
return dev_id
23652368

2369+
cpdef bint can_compile(self, str language):
2370+
"""
2371+
Check whether it is possible to create an executable kernel_bundle
2372+
for this device from the given source language.
2373+
2374+
Parameters:
2375+
language
2376+
Input language. Possible values are "spirv" for SPIR-V binary
2377+
files, "opencl" for OpenCL C device code and "sycl" for SYCL
2378+
device code.
2379+
2380+
Returns:
2381+
bool:
2382+
True if compilation is supported, False otherwise.
2383+
2384+
Raises:
2385+
ValueError:
2386+
If an unknown source language is used.
2387+
"""
2388+
if language == "spirv" or language == "spv":
2389+
return DPCTLDevice_CanCompileSPIRV(self._device_ref)
2390+
if language == "opencl" or language == "ocl":
2391+
return DPCTLDevice_CanCompileOpenCL(self._device_ref)
2392+
if language == "sycl":
2393+
return DPCTLDevice_CanCompileSYCL(self._device_ref)
2394+
2395+
raise ValueError(f"Unknown source language {language}")
2396+
23662397

23672398
cdef api DPCTLSyclDeviceRef SyclDevice_GetDeviceRef(SyclDevice dev):
23682399
"""

dpctl/program/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@
2929
create_kernel_bundle_from_spirv,
3030
create_program_from_source,
3131
create_program_from_spirv,
32+
create_program_from_sycl_source,
3233
)
3334

3435
__all__ = [
3536
"create_kernel_bundle_from_source",
3637
"create_kernel_bundle_from_spirv",
3738
"create_program_from_source",
3839
"create_program_from_spirv",
40+
"create_program_from_sycl_source",
3941
"SyclKernel",
4042
"SyclKernelBundle",
4143
"SyclKernelBundleCompilationError",

dpctl/program/_program.pxd

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,11 @@ cdef api class SyclKernelBundle [
5252
binary file.
5353
"""
5454
cdef DPCTLSyclKernelBundleRef _kernel_bundle_ref
55+
cdef bint _is_sycl_source
5556

5657
@staticmethod
57-
cdef SyclKernelBundle _create (DPCTLSyclKernelBundleRef kbref)
58+
cdef SyclKernelBundle _create (DPCTLSyclKernelBundleRef kbref,
59+
bint _is_sycl_source)
5860
cdef DPCTLSyclKernelBundleRef get_kernel_bundle_ref (self)
5961
cpdef SyclKernel get_sycl_kernel(self, str kernel_name)
6062

@@ -69,3 +71,7 @@ cpdef create_program_from_source (SyclQueue q, unicode source, unicode copts=*)
6971
cpdef create_program_from_spirv (
7072
SyclQueue q, const unsigned char[:] IL, unicode copts=*
7173
)
74+
cpdef create_kernel_bundle_from_sycl_source(SyclQueue q, unicode source,
75+
list headers=*,
76+
list registered_names=*,
77+
list copts=*)

dpctl/program/_program.pyx

Lines changed: 150 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ from libc.stdint cimport uint32_t
3131
import warnings
3232

3333
from dpctl._backend cimport ( # noqa: E211, E402;
34+
DPCTLBuildOptionList_Append,
35+
DPCTLBuildOptionList_Create,
36+
DPCTLBuildOptionList_Delete,
37+
DPCTLBuildOptionListRef,
3438
DPCTLKernel_Copy,
3539
DPCTLKernel_Delete,
3640
DPCTLKernel_GetCompileNumSubGroups,
@@ -41,16 +45,31 @@ from dpctl._backend cimport ( # noqa: E211, E402;
4145
DPCTLKernel_GetPreferredWorkGroupSizeMultiple,
4246
DPCTLKernel_GetPrivateMemSize,
4347
DPCTLKernel_GetWorkGroupSize,
48+
DPCTLKernelBuildLog_Create,
49+
DPCTLKernelBuildLog_Delete,
50+
DPCTLKernelBuildLog_Get,
51+
DPCTLKernelBuildLogRef,
4452
DPCTLKernelBundle_Copy,
4553
DPCTLKernelBundle_CreateFromOCLSource,
4654
DPCTLKernelBundle_CreateFromSpirv,
55+
DPCTLKernelBundle_CreateFromSYCLSource,
4756
DPCTLKernelBundle_Delete,
4857
DPCTLKernelBundle_GetKernel,
58+
DPCTLKernelBundle_GetSyclKernel,
4959
DPCTLKernelBundle_HasKernel,
60+
DPCTLKernelBundle_HasSyclKernel,
61+
DPCTLKernelNameList_Append,
62+
DPCTLKernelNameList_Create,
63+
DPCTLKernelNameList_Delete,
64+
DPCTLKernelNameListRef,
5065
DPCTLSyclContextRef,
5166
DPCTLSyclDeviceRef,
5267
DPCTLSyclKernelBundleRef,
5368
DPCTLSyclKernelRef,
69+
DPCTLVirtualHeaderList_Append,
70+
DPCTLVirtualHeaderList_Create,
71+
DPCTLVirtualHeaderList_Delete,
72+
DPCTLVirtualHeaderListRef,
5473
)
5574

5675
__all__ = [
@@ -199,9 +218,11 @@ cdef class SyclKernelBundle:
199218
"""
200219

201220
@staticmethod
202-
cdef SyclKernelBundle _create(DPCTLSyclKernelBundleRef KBRef):
221+
cdef SyclKernelBundle _create(DPCTLSyclKernelBundleRef KBRef,
222+
bint is_sycl_source):
203223
cdef SyclKernelBundle ret = SyclKernelBundle.__new__(SyclKernelBundle)
204224
ret._kernel_bundle_ref = KBRef
225+
ret._is_sycl_source = is_sycl_source
205226
return ret
206227

207228
def __dealloc__(self):
@@ -212,13 +233,24 @@ cdef class SyclKernelBundle:
212233

213234
cpdef SyclKernel get_sycl_kernel(self, str kernel_name):
214235
name = kernel_name.encode("utf8")
236+
if self._is_sycl_source:
237+
return SyclKernel._create(
238+
DPCTLKernelBundle_GetSyclKernel(
239+
self._kernel_bundle_ref, name
240+
),
241+
kernel_name
242+
)
215243
return SyclKernel._create(
216244
DPCTLKernelBundle_GetKernel(self._kernel_bundle_ref, name),
217245
kernel_name
218246
)
219247

220248
def has_sycl_kernel(self, str kernel_name):
221249
name = kernel_name.encode("utf8")
250+
if self._is_sycl_source:
251+
return DPCTLKernelBundle_HasSyclKernel(
252+
self._kernel_bundle_ref, name
253+
)
222254
return DPCTLKernelBundle_HasKernel(self._kernel_bundle_ref, name)
223255

224256
def addressof_ref(self):
@@ -249,7 +281,7 @@ cdef api SyclKernelBundle SyclKernelBundle_Make(DPCTLSyclKernelBundleRef KBRef):
249281
reference.
250282
"""
251283
cdef DPCTLSyclKernelBundleRef copied_KBRef = DPCTLKernelBundle_Copy(KBRef)
252-
return SyclKernelBundle._create(copied_KBRef)
284+
return SyclKernelBundle._create(copied_KBRef, False)
253285

254286

255287
cpdef create_kernel_bundle_from_source(SyclQueue q, str src, str copts=""):
@@ -295,7 +327,7 @@ cpdef create_kernel_bundle_from_source(SyclQueue q, str src, str copts=""):
295327
if KBref is NULL:
296328
raise SyclKernelBundleCompilationError()
297329

298-
return SyclKernelBundle._create(KBref)
330+
return SyclKernelBundle._create(KBref, False)
299331

300332

301333
cpdef create_kernel_bundle_from_spirv(
@@ -342,7 +374,121 @@ cpdef create_kernel_bundle_from_spirv(
342374
if KBref is NULL:
343375
raise SyclKernelBundleCompilationError()
344376

345-
return SyclKernelBundle._create(KBref)
377+
return SyclKernelBundle._create(KBref, False)
378+
379+
380+
cpdef create_kernel_bundle_from_sycl_source(SyclQueue q,
381+
unicode source,
382+
list headers=None,
383+
list registered_names=None,
384+
list copts=None):
385+
"""
386+
Creates an executable SYCL kernel_bundle from SYCL source code.
387+
388+
This uses the DPC++ ``kernel_compiler`` extension to create a
389+
``sycl::kernel_bundle<sycl::bundle_state::executable>`` object from
390+
SYCL source code.
391+
392+
Parameters:
393+
q (:class:`dpctl.SyclQueue`)
394+
The :class:`dpctl.SyclQueue` for which the
395+
:class:`.SyclKernelBundle` is going to be built.
396+
source (unicode)
397+
SYCL source code string.
398+
headers (list)
399+
Optional list of virtual headers, where each entry in the list
400+
needs to be a tuple of header name and header content. See the
401+
documentation of the ``include_files`` property in the DPC++
402+
``kernel_compiler`` extension for more information.
403+
Default: []
404+
registered_names (list, optional)
405+
Optional list of kernel names to register. See the
406+
documentation of the ``registered_names`` property in the DPC++
407+
``kernel_compiler`` extension for more information.
408+
Default: []
409+
copts (list)
410+
Optional list of compilation flags that will be used
411+
when compiling the program. Default: ``""``.
412+
413+
Returns:
414+
kernel_bundle (:class:`.SyclKernelBundle`)
415+
A :class:`.SyclKernelBundle` object wrapping the
416+
``sycl::kernel_bundle<sycl::bundle_state::executable>``
417+
returned by the C API.
418+
419+
Raises:
420+
SyclKernelBundleCompilationError
421+
If a SYCL kernel bundle could not be created. The exception
422+
message contains the build log for more details.
423+
"""
424+
cdef DPCTLSyclKernelBundleRef KBref
425+
cdef DPCTLSyclContextRef CRef = q.get_sycl_context().get_context_ref()
426+
cdef DPCTLSyclDeviceRef DRef = q.get_sycl_device().get_device_ref()
427+
cdef bytes bSrc = source.encode("utf8")
428+
cdef const char *Src = <const char*>bSrc
429+
cdef DPCTLBuildOptionListRef BuildOpts = DPCTLBuildOptionList_Create()
430+
cdef bytes bOpt
431+
cdef const char* sOpt
432+
cdef bytes bName
433+
cdef const char* sName
434+
cdef bytes bContent
435+
cdef const char* sContent
436+
cdef const char* buildLogContent
437+
for opt in copts:
438+
if not isinstance(opt, unicode):
439+
DPCTLBuildOptionList_Delete(BuildOpts)
440+
raise SyclKernelBundleCompilationError()
441+
bOpt = opt.encode("utf8")
442+
sOpt = <const char*>bOpt
443+
DPCTLBuildOptionList_Append(BuildOpts, sOpt)
444+
445+
cdef DPCTLKernelNameListRef KernelNames = DPCTLKernelNameList_Create()
446+
for name in registered_names:
447+
if not isinstance(name, unicode):
448+
DPCTLBuildOptionList_Delete(BuildOpts)
449+
DPCTLKernelNameList_Delete(KernelNames)
450+
raise SyclKernelBundleCompilationError()
451+
bName = name.encode("utf8")
452+
sName = <const char*>bName
453+
DPCTLKernelNameList_Append(KernelNames, sName)
454+
455+
cdef DPCTLVirtualHeaderListRef VirtualHeaders
456+
VirtualHeaders = DPCTLVirtualHeaderList_Create()
457+
458+
for name, content in headers:
459+
if not isinstance(name, unicode) or not isinstance(content, unicode):
460+
DPCTLBuildOptionList_Delete(BuildOpts)
461+
DPCTLKernelNameList_Delete(KernelNames)
462+
DPCTLVirtualHeaderList_Delete(VirtualHeaders)
463+
raise SyclKernelBundleCompilationError()
464+
bName = name.encode("utf8")
465+
sName = <const char*>bName
466+
bContent = content.encode("utf8")
467+
sContent = <const char*>bContent
468+
DPCTLVirtualHeaderList_Append(VirtualHeaders, sName, sContent)
469+
470+
cdef DPCTLKernelBuildLogRef BuildLog
471+
BuildLog = DPCTLKernelBuildLog_Create()
472+
473+
KBref = DPCTLKernelBundle_CreateFromSYCLSource(CRef, DRef, Src,
474+
VirtualHeaders, KernelNames,
475+
BuildOpts, BuildLog)
476+
477+
if KBref is NULL:
478+
buildLogContent = DPCTLKernelBuildLog_Get(BuildLog)
479+
buildLogStr = str(buildLogContent, "utf-8")
480+
DPCTLBuildOptionList_Delete(BuildOpts)
481+
DPCTLKernelNameList_Delete(KernelNames)
482+
DPCTLVirtualHeaderList_Delete(VirtualHeaders)
483+
DPCTLKernelBuildLog_Delete(BuildLog)
484+
raise SyclKernelBundleCompilationError(buildLogStr)
485+
486+
DPCTLBuildOptionList_Delete(BuildOpts)
487+
DPCTLKernelNameList_Delete(KernelNames)
488+
DPCTLVirtualHeaderList_Delete(VirtualHeaders)
489+
DPCTLKernelBuildLog_Delete(BuildLog)
490+
491+
return SyclKernelBundle._create(KBref, True)
346492

347493

348494
cpdef create_program_from_source(SyclQueue q, str src, str copts=""):

0 commit comments

Comments
 (0)