• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IntelPython / dpctl / 31105315279

06 Aug 2026 01:18PM UTC coverage: 74.61% (+0.6%) from 74.054%
31105315279

Pull #2206

github

web-flow
Merge 94e8f9b4c into be1985837
Pull Request #2206: Support SYCL source compilation

993 of 1400 branches covered (70.93%)

Branch coverage included in aggregate %.

178 of 197 new or added lines in 2 files covered. (90.36%)

3832 of 5067 relevant lines covered (75.63%)

279.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.18
/libsyclinterface/source/dpctl_sycl_kernel_bundle_interface.cpp
1
//===- dpctl_sycl_kernel_bundle_interface.cpp - Implements C API for
2
//    sycl::kernel_bundle<sycl::bundle_state::executable>  ---------------===//
3
//
4
//                      Data Parallel Control (dpctl)
5
//
6
// Copyright 2020 Intel Corporation
7
//
8
// Licensed under the Apache License, Version 2.0 (the "License");
9
// you may not use this file except in compliance with the License.
10
// You may obtain a copy of the License at
11
//
12
//    http://www.apache.org/licenses/LICENSE-2.0
13
//
14
// Unless required by applicable law or agreed to in writing, software
15
// distributed under the License is distributed on an "AS IS" BASIS,
16
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
// See the License for the specific language governing permissions and
18
// limitations under the License.
19
//
20
//===----------------------------------------------------------------------===//
21
///
22
/// \file
23
/// This file implements the functions declared in
24
/// dpctl_sycl_kernel_bundle_interface.h.
25
///
26
//===----------------------------------------------------------------------===//
27

28
#include "dpctl_sycl_kernel_bundle_interface.h"
29
#include "Config/dpctl_config.h"
30
#include "dpctl_dynamic_lib_helper.h"
31
#include "dpctl_error_handlers.h"
32
#include "dpctl_sycl_type_casters.hpp"
33
#include <CL/cl.h> /* OpenCL headers     */
34
#include <cstdint>
35
#include <sstream>
36
#include <stddef.h>
37
#include <sycl/backend/opencl.hpp>
38
#include <sycl/sycl.hpp> /* Sycl headers       */
39
#include <utility>
40

41
#ifdef DPCTL_ENABLE_L0_PROGRAM_CREATION
42
// Note: include ze_api.h before level_zero.hpp. Make sure clang-format does
43
// not reorder the includes.
44
// clang-format off
45
#include "ze_api.h" /* Level Zero headers */
46
#include <sycl/ext/oneapi/backend/level_zero.hpp>
47
// clang-format on
48
#endif
49

50
using namespace sycl;
51

52
namespace
53
{
54
static_assert(__SYCL_COMPILER_VERSION >= __SYCL_COMPILER_VERSION_REQUIRED,
55
              "The compiler does not meet minimum version requirement");
56

57
using namespace dpctl::syclinterface;
58

59
#ifdef __linux__
60
static const char *clLoaderName = DPCTL_LIBCL_LOADER_FILENAME;
61
static const int clLibLoadFlags = RTLD_NOLOAD | RTLD_NOW | RTLD_LOCAL;
62
#elif defined(_WIN64)
63
static const char *clLoaderName = "OpenCL.dll";
64
static const int clLibLoadFlags = 0;
65
#else
66
#error "OpenCL program compilation is unavailable for this platform"
67
#endif
68

69
#define CodeStringSuffix(code)                                                 \
70
    std::string(" (code=") + std::to_string(static_cast<int>(code)) + ")"
6✔
71

72
#define EnumCaseString(code)                                                   \
73
    case code:                                                                 \
2✔
74
        return std::string(#code) + CodeStringSuffix(code)
2✔
75

76
static constexpr backend cl_be = backend::opencl;
77

78
struct cl_loader
79
{
80
public:
81
    static cl_loader &get()
82
    {
11✔
83
        static cl_loader _loader;
11✔
84
        return _loader;
11✔
85
    }
11✔
86

87
    template <typename retTy> retTy getSymbol(const char *name)
88
    {
11✔
89
        if (!opened) {
11!
90
            error_handler("The OpenCL loader dynamic library could not "
×
91
                          "be opened.",
×
92
                          __FILE__, __func__, __LINE__);
×
93

94
            return nullptr;
×
95
        }
×
96
        return clLib.getSymbol<retTy>(name);
11✔
97
    }
11✔
98

99
private:
100
    dpctl::DynamicLibHelper clLib;
101
    bool opened;
102
    cl_loader() : clLib(clLoaderName, clLibLoadFlags), opened(clLib.opened()) {}
2✔
103
};
104

105
typedef cl_program (*clCreateProgramWithSourceFT)(cl_context,
106
                                                  cl_uint,
107
                                                  const char **,
108
                                                  const size_t *,
109
                                                  cl_int *);
110
const char *clCreateProgramWithSource_Name = "clCreateProgramWithSource";
111
clCreateProgramWithSourceFT get_clCreateProgramWithSource()
112
{
30✔
113
    static auto st_clCreateProgramWithSourceF =
30✔
114
        cl_loader::get().getSymbol<clCreateProgramWithSourceFT>(
30✔
115
            clCreateProgramWithSource_Name);
30✔
116

117
    return st_clCreateProgramWithSourceF;
30✔
118
}
30✔
119

120
typedef cl_program (*clCreateProgramWithILFT)(cl_context,
121
                                              const void *,
122
                                              size_t,
123
                                              cl_int *);
124
const char *clCreateProgramWithIL_Name = "clCreateProgramWithIL";
125
clCreateProgramWithILFT get_clCreateProgramWithIL()
126
{
78✔
127
    static auto st_clCreateProgramWithILF =
78✔
128
        cl_loader::get().getSymbol<clCreateProgramWithILFT>(
78✔
129
            clCreateProgramWithIL_Name);
78✔
130

131
    return st_clCreateProgramWithILF;
78✔
132
}
78✔
133
typedef cl_int (*clBuildProgramFT)(cl_program,
134
                                   cl_uint,
135
                                   const cl_device_id *,
136
                                   const char *,
137
                                   void (*)(cl_program, void *),
138
                                   void *);
139
const char *clBuildProgram_Name = "clBuildProgram";
140
clBuildProgramFT get_clBuildProgram()
141
{
108✔
142
    static auto st_clBuildProgramF =
108✔
143
        cl_loader::get().getSymbol<clBuildProgramFT>(clBuildProgram_Name);
108✔
144

145
    return st_clBuildProgramF;
108✔
146
}
108✔
147

148
typedef cl_kernel (*clCreateKernelFT)(cl_program, const char *, cl_int *);
149
const char *clCreateKernel_Name = "clCreateKernel";
150
clCreateKernelFT get_clCreateKernel()
151
{
167✔
152
    static auto st_clCreateKernelF =
167✔
153
        cl_loader::get().getSymbol<clCreateKernelFT>(clCreateKernel_Name);
167✔
154

155
    return st_clCreateKernelF;
167✔
156
}
167✔
157

158
std::string _GetErrorCode_ocl_impl(cl_int code)
159
{
2✔
160
    switch (code) {
2✔
161
        EnumCaseString(CL_BUILD_PROGRAM_FAILURE);
2!
162
        EnumCaseString(CL_INVALID_CONTEXT);
×
163
        EnumCaseString(CL_INVALID_DEVICE);
×
164
        EnumCaseString(CL_INVALID_VALUE);
×
165
        EnumCaseString(CL_OUT_OF_RESOURCES);
×
166
        EnumCaseString(CL_OUT_OF_HOST_MEMORY);
×
167
        EnumCaseString(CL_INVALID_OPERATION);
×
168
        EnumCaseString(CL_INVALID_BINARY);
×
169
    default:
×
170
        return "<< ERROR CODE UNRECOGNIZED >>" + CodeStringSuffix(code);
×
171
    }
2✔
172
}
2✔
173

174
typedef cl_int (*clSetProgramSpecializationConstantFT)(cl_program,
175
                                                       cl_uint,
176
                                                       size_t,
177
                                                       const void *);
178
const char *clSetProgramSpecializationConstant_Name =
179
    "clSetProgramSpecializationConstant";
180
clSetProgramSpecializationConstantFT get_clSetProgramSpecializationConstant()
181
{
2✔
182
    static auto st_clSetProgramSpecializationConstantF =
2✔
183
        cl_loader::get().getSymbol<clSetProgramSpecializationConstantFT>(
2✔
184
            clSetProgramSpecializationConstant_Name);
2✔
185

186
    return st_clSetProgramSpecializationConstantF;
2✔
187
}
2✔
188

189
typedef cl_int (*clReleaseProgramFT)(cl_program);
190
const char *clReleaseProgram_Name = "clReleaseProgram";
191
clReleaseProgramFT get_clReleaseProgram()
192
{
2✔
193
    static auto st_clReleaseProgramF =
2✔
194
        cl_loader::get().getSymbol<clReleaseProgramFT>(clReleaseProgram_Name);
2✔
195

196
    return st_clReleaseProgramF;
2✔
197
}
2✔
198

199
DPCTLSyclKernelBundleRef
200
_CreateKernelBundle_common_ocl_impl(cl_program clProgram,
201
                                    const context &ctx,
202
                                    const device &dev,
203
                                    const char *CompileOpts)
204
{
108✔
205
    backend_traits<cl_be>::return_type<device> clDevice;
108✔
206
    clDevice = get_native<cl_be>(dev);
108✔
207

208
    // Last two pointers are notification function pointer and user-data pointer
209
    // that can be passed to the notification function.
210
    auto clBuildProgramF = get_clBuildProgram();
108✔
211
    if (clBuildProgramF == nullptr) {
108!
212
        auto clReleaseProgramF = get_clReleaseProgram();
×
213
        if (clReleaseProgramF) {
×
214
            clReleaseProgramF(clProgram);
×
215
        }
×
216
        return nullptr;
×
217
    }
×
218
    cl_int build_status =
108✔
219
        clBuildProgramF(clProgram, 1, &clDevice, CompileOpts, nullptr, nullptr);
108✔
220

221
    if (build_status != CL_SUCCESS) {
108✔
222
        error_handler("clBuildProgram failed: " +
2✔
223
                          _GetErrorCode_ocl_impl(build_status),
2✔
224
                      __FILE__, __func__, __LINE__);
2✔
225
        auto clReleaseProgramF = get_clReleaseProgram();
2✔
226
        if (clReleaseProgramF) {
2!
227
            clReleaseProgramF(clProgram);
2✔
228
        }
2✔
229
        return nullptr;
2✔
230
    }
2✔
231

232
    using ekbTy = kernel_bundle<bundle_state::executable>;
106✔
233
    const ekbTy &kb =
106✔
234
        make_kernel_bundle<cl_be, bundle_state::executable>(clProgram, ctx);
106✔
235
    return wrap<ekbTy>(new ekbTy(kb));
106✔
236
}
108✔
237

238
DPCTLSyclKernelBundleRef
239
_CreateKernelBundleWithOCLSource_ocl_impl(const context &ctx,
240
                                          const device &dev,
241
                                          const char *oclSrc,
242
                                          const char *CompileOpts)
243
{
30✔
244
    auto clCreateProgramWithSourceF = get_clCreateProgramWithSource();
30✔
245
    if (clCreateProgramWithSourceF == nullptr) {
30!
246
        return nullptr;
×
247
    }
×
248

249
    backend_traits<cl_be>::return_type<context> clContext;
30✔
250
    clContext = get_native<cl_be>(ctx);
30✔
251

252
    cl_int build_with_source_err_code = CL_SUCCESS;
30✔
253
    cl_program clProgram = clCreateProgramWithSourceF(
30✔
254
        clContext, 1, &oclSrc, nullptr, &build_with_source_err_code);
30✔
255

256
    if (build_with_source_err_code != CL_SUCCESS) {
30!
257
        error_handler("clPCreateProgramWithSource failed with " +
×
258
                          _GetErrorCode_ocl_impl(build_with_source_err_code),
×
259
                      __FILE__, __func__, __LINE__);
×
260
        return nullptr;
×
261
    }
×
262

263
    return _CreateKernelBundle_common_ocl_impl(clProgram, ctx, dev,
30✔
264
                                               CompileOpts);
30✔
265
}
30✔
266

267
DPCTLSyclKernelBundleRef
268
_CreateKernelBundleWithIL_ocl_impl(const context &ctx,
269
                                   const device &dev,
270
                                   const void *IL,
271
                                   size_t il_length,
272
                                   const char *CompileOpts,
273
                                   size_t NumSpecConsts,
274
                                   const DPCTLSpecConst *SpecConsts)
275
{
78✔
276
    auto clCreateProgramWithILF = get_clCreateProgramWithIL();
78✔
277
    if (clCreateProgramWithILF == nullptr) {
78!
278
        return nullptr;
×
279
    }
×
280

281
    backend_traits<cl_be>::return_type<context> clContext;
78✔
282
    clContext = get_native<cl_be>(ctx);
78✔
283

284
    if (NumSpecConsts > 0 && SpecConsts == nullptr) {
78!
285
        error_handler("NumSpecConsts > 0 but SpecConsts is NULL.", __FILE__,
×
286
                      __func__, __LINE__);
×
287
        return nullptr;
×
288
    }
×
289

290
    cl_int create_err_code = CL_SUCCESS;
78✔
291
    cl_program clProgram =
78✔
292
        clCreateProgramWithILF(clContext, IL, il_length, &create_err_code);
78✔
293

294
    if (create_err_code != CL_SUCCESS) {
78!
295
        error_handler("OpenCL program could not be created from the SPIR-V "
×
296
                      "binary. OpenCL Error " +
×
297
                          _GetErrorCode_ocl_impl(create_err_code),
×
298
                      __FILE__, __func__, __LINE__);
×
299
        return nullptr;
×
300
    }
×
301

302
    if (SpecConsts != nullptr && NumSpecConsts > 0) {
78!
303
        auto clSetProgramSpecConstF = get_clSetProgramSpecializationConstant();
2✔
304
        if (clSetProgramSpecConstF) {
2!
305
            for (size_t i = 0; i < NumSpecConsts; ++i) {
6✔
306
                cl_int spec_err = clSetProgramSpecConstF(
4✔
307
                    clProgram, SpecConsts[i].id, SpecConsts[i].size,
4✔
308
                    SpecConsts[i].value);
4✔
309
                if (spec_err != CL_SUCCESS) {
4!
310
                    error_handler(
×
311
                        "clSetProgramSpecializationConstant failed for "
×
312
                        "spec constant id " +
×
313
                            std::to_string(SpecConsts[i].id) +
×
314
                            ". OpenCL Error " +
×
315
                            _GetErrorCode_ocl_impl(spec_err),
×
316
                        __FILE__, __func__, __LINE__);
×
317

318
                    auto clReleaseProgramF = get_clReleaseProgram();
×
319
                    if (clReleaseProgramF) {
×
320
                        clReleaseProgramF(clProgram);
×
321
                    }
×
322

323
                    return nullptr;
×
324
                }
×
325
            }
4✔
326
        }
2✔
327
        else {
×
328
            error_handler("clSetProgramSpecializationConstant is not available "
×
329
                          "in the OpenCL implementation.",
×
330
                          __FILE__, __func__, __LINE__);
×
331

332
            auto clReleaseProgramF = get_clReleaseProgram();
×
333
            if (clReleaseProgramF) {
×
334
                clReleaseProgramF(clProgram);
×
335
            }
×
336

337
            return nullptr;
×
338
        }
×
339
    }
2✔
340

341
    return _CreateKernelBundle_common_ocl_impl(clProgram, ctx, dev,
78✔
342
                                               CompileOpts);
78✔
343
}
78✔
344

345
bool _HasKernel_ocl_impl(const kernel_bundle<bundle_state::executable> &kb,
346
                         const char *kernel_name)
347
{
76✔
348
    auto clCreateKernelF = get_clCreateKernel();
76✔
349
    if (clCreateKernelF == nullptr) {
76!
350
        return false;
×
351
    }
×
352

353
    std::vector<cl_program> oclKB = get_native<cl_be>(kb);
76✔
354

355
    bool found = false;
76✔
356
    for (auto &cl_pr : oclKB) {
76!
357
        cl_int create_kernel_err_code = CL_SUCCESS;
76✔
358
        [[maybe_unused]] cl_kernel try_kern =
76✔
359
            clCreateKernelF(cl_pr, kernel_name, &create_kernel_err_code);
76✔
360
        if (create_kernel_err_code == CL_SUCCESS) {
76!
361
            found = true;
76✔
362
            break;
76✔
363
        }
76✔
364
    }
76✔
365
    return found;
76✔
366
}
76✔
367

368
__dpctl_give DPCTLSyclKernelRef
369
_GetKernel_ocl_impl(const kernel_bundle<bundle_state::executable> &kb,
370
                    const char *kernel_name)
371
{
91✔
372
    auto clCreateKernelF = get_clCreateKernel();
91✔
373
    if (clCreateKernelF == nullptr) {
91!
374
        return nullptr;
×
375
    }
×
376

377
    std::vector<cl_program> oclKB = get_native<cl_be>(kb);
91✔
378

379
    bool found = false;
91✔
380
    cl_kernel ocl_kernel_from_kb;
91✔
381
    for (auto &cl_pr : oclKB) {
91✔
382
        cl_int create_kernel_err_code = CL_SUCCESS;
91✔
383
        cl_kernel try_kern =
91✔
384
            clCreateKernelF(cl_pr, kernel_name, &create_kernel_err_code);
91✔
385
        if (create_kernel_err_code == CL_SUCCESS) {
91✔
386
            found = true;
90✔
387
            ocl_kernel_from_kb = try_kern;
90✔
388
            break;
90✔
389
        }
90✔
390
    }
91✔
391
    if (found) {
91✔
392
        try {
90✔
393
            context ctx = kb.get_context();
90✔
394

395
            const kernel &interop_kernel =
90✔
396
                make_kernel<cl_be>(ocl_kernel_from_kb, ctx);
90✔
397

398
            return wrap<kernel>(new kernel(interop_kernel));
90✔
399
        } catch (std::exception const &e) {
90✔
400
            error_handler(e, __FILE__, __func__, __LINE__);
×
401
            return nullptr;
×
402
        }
×
403
    }
90✔
404
    else {
1✔
405
        error_handler("Kernel " + std::string(kernel_name) + " not found.",
1✔
406
                      __FILE__, __func__, __LINE__);
1✔
407
        return nullptr;
1✔
408
    }
1✔
409
}
91✔
410

411
#ifdef DPCTL_ENABLE_L0_PROGRAM_CREATION
412

413
#ifdef __linux__
414
static const char *zeLoaderName = DPCTL_LIBZE_LOADER_FILENAME;
415
static const int zeLibLoadFlags = RTLD_NOLOAD | RTLD_NOW | RTLD_LOCAL;
416
#elif defined(_WIN64)
417
static const char *zeLoaderName = "ze_loader.dll";
418
static const int zeLibLoadFlags = 0;
419
#else
420
#error "Level Zero program compilation is unavailable for this platform"
421
#endif
422

423
static constexpr sycl::backend ze_be = sycl::backend::ext_oneapi_level_zero;
424

425
struct ze_loader
426
{
427
public:
428
    static ze_loader &get()
429
    {
×
430
        static ze_loader _loader;
×
431
        return _loader;
×
432
    }
×
433

434
    template <typename retTy> retTy getSymbol(const char *name)
435
    {
×
436
        if (!opened) {
×
437
            error_handler("The Level-Zero loader dynamic library could not "
×
438
                          "be opened.",
×
439
                          __FILE__, __func__, __LINE__);
×
440

441
            return nullptr;
×
442
        }
×
443
        return zeLib.getSymbol<retTy>(name);
×
444
    }
×
445

446
private:
447
    dpctl::DynamicLibHelper zeLib;
448
    bool opened;
449
    ze_loader() : zeLib(zeLoaderName, zeLibLoadFlags), opened(zeLib.opened()) {}
×
450
};
451

452
typedef ze_result_t (*zeModuleCreateFT)(ze_context_handle_t,
453
                                        ze_device_handle_t,
454
                                        const ze_module_desc_t *,
455
                                        ze_module_handle_t *,
456
                                        ze_module_build_log_handle_t *);
457
const char *zeModuleCreate_Name = "zeModuleCreate";
458
zeModuleCreateFT get_zeModuleCreate()
459
{
×
460
    static auto st_zeModuleCreateF =
×
461
        ze_loader::get().getSymbol<zeModuleCreateFT>(zeModuleCreate_Name);
×
462

463
    return st_zeModuleCreateF;
×
464
}
×
465

466
typedef ze_result_t (*zeModuleDestroyFT)(ze_module_handle_t);
467
const char *zeModuleDestroy_Name = "zeModuleDestroy";
468
zeModuleDestroyFT get_zeModuleDestroy()
469
{
×
470
    static auto st_zeModuleDestroyF =
×
471
        ze_loader::get().getSymbol<zeModuleDestroyFT>(zeModuleDestroy_Name);
×
472

473
    return st_zeModuleDestroyF;
×
474
}
×
475

476
typedef ze_result_t (*zeKernelCreateFT)(ze_module_handle_t,
477
                                        const ze_kernel_desc_t *,
478
                                        ze_kernel_handle_t *);
479
const char *zeKernelCreate_Name = "zeKernelCreate";
480
zeKernelCreateFT get_zeKernelCreate()
481
{
×
482
    static auto st_zeKernelCreateF =
×
483
        ze_loader::get().getSymbol<zeKernelCreateFT>(zeKernelCreate_Name);
×
484

485
    return st_zeKernelCreateF;
×
486
}
×
487

488
std::string _GetErrorCode_ze_impl(ze_result_t code)
489
{
×
490
    switch (code) {
×
491
        EnumCaseString(ZE_RESULT_ERROR_UNINITIALIZED);
×
492
        EnumCaseString(ZE_RESULT_ERROR_DEVICE_LOST);
×
493
        EnumCaseString(ZE_RESULT_ERROR_INVALID_NULL_HANDLE);
×
494
        EnumCaseString(ZE_RESULT_ERROR_INVALID_NULL_POINTER);
×
495
        EnumCaseString(ZE_RESULT_ERROR_INVALID_ENUMERATION);
×
496
        EnumCaseString(ZE_RESULT_ERROR_INVALID_NATIVE_BINARY);
×
497
        EnumCaseString(ZE_RESULT_ERROR_INVALID_SIZE);
×
498
        EnumCaseString(ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY);
×
499
        EnumCaseString(ZE_RESULT_ERROR_OUT_OF_DEVICE_MEMORY);
×
500
        EnumCaseString(ZE_RESULT_ERROR_MODULE_BUILD_FAILURE);
×
501
        EnumCaseString(ZE_RESULT_ERROR_INVALID_MODULE_UNLINKED);
×
502
    default:
×
503
        return "<< UNRECOGNIZED ZE_RESULT_T CODE >> " + CodeStringSuffix(code);
×
504
    }
×
505
}
×
506

507
__dpctl_give DPCTLSyclKernelBundleRef
508
_CreateKernelBundleWithIL_ze_impl(const context &SyclCtx,
509
                                  const device &SyclDev,
510
                                  const void *IL,
511
                                  size_t il_length,
512
                                  const char *CompileOpts,
513
                                  size_t NumSpecConsts,
514
                                  const DPCTLSpecConst *SpecConsts)
515
{
×
516
    auto zeModuleCreateFn = get_zeModuleCreate();
×
517
    if (zeModuleCreateFn == nullptr) {
×
518
        error_handler("ZeModuleCreateFn is invalid.", __FILE__, __func__,
×
519
                      __LINE__);
×
520
        return nullptr;
×
521
    }
×
522

523
    backend_traits<ze_be>::return_type<context> ZeContext;
×
524
    ZeContext = get_native<ze_be>(SyclCtx);
×
525

526
    backend_traits<ze_be>::return_type<device> ZeDevice;
×
527
    ZeDevice = get_native<ze_be>(SyclDev);
×
528

529
    if (NumSpecConsts > 0 && SpecConsts == nullptr) {
×
530
        error_handler("NumSpecConsts > 0 but SpecConsts is NULL.", __FILE__,
×
531
                      __func__, __LINE__);
×
532
        return nullptr;
×
533
    }
×
534

535
    std::vector<std::uint32_t> spec_ids;
×
536
    std::vector<const void *> spec_values;
×
537

538
    if (SpecConsts != nullptr && NumSpecConsts > 0) {
×
539
        spec_ids.reserve(NumSpecConsts);
×
540
        spec_values.reserve(NumSpecConsts);
×
541
        for (size_t i = 0; i < NumSpecConsts; ++i) {
×
542
            spec_ids.push_back(SpecConsts[i].id);
×
543
            spec_values.push_back(SpecConsts[i].value);
×
544
        }
×
545
    }
×
546
    ze_module_constants_t ZeSpecConstants = {};
×
547
    ZeSpecConstants.numConstants = static_cast<std::uint32_t>(spec_ids.size());
×
548
    ZeSpecConstants.pConstantIds = spec_ids.empty() ? nullptr : spec_ids.data();
×
549
    ZeSpecConstants.pConstantValues =
×
550
        spec_values.empty() ? nullptr : spec_values.data();
×
551

552
    // Populate the Level Zero module descriptions
553
    ze_module_desc_t ZeModuleDesc = {};
×
554
    ZeModuleDesc.stype = ZE_STRUCTURE_TYPE_MODULE_DESC;
×
555
    ZeModuleDesc.format = ZE_MODULE_FORMAT_IL_SPIRV;
×
556
    ZeModuleDesc.inputSize = il_length;
×
557
    ZeModuleDesc.pInputModule = (uint8_t *)IL;
×
558
    ZeModuleDesc.pBuildFlags = CompileOpts;
×
559
    ZeModuleDesc.pConstants = &ZeSpecConstants;
×
560

561
    ze_module_handle_t ZeModule;
×
562

563
    auto ret_code = zeModuleCreateFn(ZeContext, ZeDevice, &ZeModuleDesc,
×
564
                                     &ZeModule, nullptr);
×
565
    if (ret_code != ZE_RESULT_SUCCESS) {
×
566
        error_handler("Module creation failed " +
×
567
                          _GetErrorCode_ze_impl(ret_code),
×
568
                      __FILE__, __func__, __LINE__);
×
569
        return nullptr;
×
570
    }
×
571

572
    try {
×
573
        const auto &kb = make_kernel_bundle<ze_be, bundle_state::executable>(
×
574
            {ZeModule, ext::oneapi::level_zero::ownership::keep}, SyclCtx);
×
575

576
        return wrap<kernel_bundle<bundle_state::executable>>(
×
577
            new kernel_bundle<bundle_state::executable>(kb));
×
578
    } catch (std::exception const &e) {
×
579
        error_handler(e, __FILE__, __func__, __LINE__);
×
580
        auto zeModuleDestroyFn = get_zeModuleDestroy();
×
581
        if (zeModuleDestroyFn) {
×
582
            zeModuleDestroyFn(ZeModule);
×
583
        }
×
584
        return nullptr;
×
585
    }
×
586
}
×
587

588
__dpctl_give DPCTLSyclKernelRef
589
_GetKernel_ze_impl(const kernel_bundle<bundle_state::executable> &kb,
590
                   const char *kernel_name)
591
{
×
592
    auto zeKernelCreateFn = get_zeKernelCreate();
×
593
    if (zeKernelCreateFn == nullptr) {
×
594
        error_handler("Could not load zeKernelCreate function.", __FILE__,
×
595
                      __func__, __LINE__);
×
596
        return nullptr;
×
597
    }
×
598

599
    auto ZeKernelBundle = sycl::get_native<ze_be>(kb);
×
600
    bool found = false;
×
601

602
    // Populate the Level Zero kernel descriptions
603
    ze_kernel_desc_t ZeKernelDescr = {ZE_STRUCTURE_TYPE_KERNEL_DESC, nullptr,
×
604
                                      0, // flags
×
605
                                      kernel_name};
×
606

607
    std::unique_ptr<sycl::kernel> syclInteropKern_ptr;
×
608
    ze_kernel_handle_t ZeKern;
×
609
    for (auto &ZeM : ZeKernelBundle) {
×
610
        ze_result_t ze_status = zeKernelCreateFn(ZeM, &ZeKernelDescr, &ZeKern);
×
611

612
        if (ze_status == ZE_RESULT_SUCCESS) {
×
613
            found = true;
×
614
            const auto &ctx = kb.get_context();
×
615
            const auto &k = make_kernel<ze_be>(
×
616
                {kb, ZeKern, ext::oneapi::level_zero::ownership::keep}, ctx);
×
617
            syclInteropKern_ptr = std::unique_ptr<kernel>(new kernel(k));
×
618
            break;
×
619
        }
×
620
        else {
×
621
            if (ze_status != ZE_RESULT_ERROR_INVALID_KERNEL_NAME) {
×
622
                error_handler("zeKernelCreate failed: " +
×
623
                                  _GetErrorCode_ze_impl(ze_status),
×
624
                              __FILE__, __func__, __LINE__);
×
625
                return nullptr;
×
626
            }
×
627
        }
×
628
    }
×
629

630
    if (found) {
×
631
        return wrap<kernel>(new kernel(*syclInteropKern_ptr));
×
632
    }
×
633
    else {
×
634
        error_handler("Kernel named " + std::string(kernel_name) +
×
635
                          " could not be found.",
×
636
                      __FILE__, __func__, __LINE__, error_level::error);
×
637
        return nullptr;
×
638
    }
×
639
}
×
640

641
bool _HasKernel_ze_impl(const kernel_bundle<bundle_state::executable> &kb,
642
                        const char *kernel_name)
643
{
×
644
    auto zeKernelCreateFn = get_zeKernelCreate();
×
645
    if (zeKernelCreateFn == nullptr) {
×
646
        error_handler("Could not load zeKernelCreate function.", __FILE__,
×
647
                      __func__, __LINE__, error_level::error);
×
648
        return false;
×
649
    }
×
650

651
    auto ZeKernelBundle = sycl::get_native<ze_be>(kb);
×
652

653
    // Populate the Level Zero kernel descriptions
654
    ze_kernel_desc_t ZeKernelDescr = {ZE_STRUCTURE_TYPE_KERNEL_DESC, nullptr,
×
655
                                      0, // flags
×
656
                                      kernel_name};
×
657

658
    std::unique_ptr<sycl::kernel> syclInteropKern_ptr;
×
659
    ze_kernel_handle_t ZeKern;
×
660
    for (auto &ZeM : ZeKernelBundle) {
×
661
        ze_result_t ze_status = zeKernelCreateFn(ZeM, &ZeKernelDescr, &ZeKern);
×
662

663
        if (ze_status == ZE_RESULT_SUCCESS) {
×
664
            return true;
×
665
        }
×
666
        else {
×
667
            if (ze_status != ZE_RESULT_ERROR_INVALID_KERNEL_NAME) {
×
668
                error_handler("zeKernelCreate failed: " +
×
669
                                  _GetErrorCode_ze_impl(ze_status),
×
670
                              __FILE__, __func__, __LINE__, error_level::error);
×
671
                return false;
×
672
            }
×
673
        }
×
674
    }
×
675

676
    return false;
×
677
}
×
678

679
#endif /* #ifdef DPCTL_ENABLE_L0_PROGRAM_CREATION */
680

681
} /* end of anonymous namespace */
682

683
__dpctl_give DPCTLSyclKernelBundleRef
684
DPCTLKernelBundle_CreateFromSpirv(__dpctl_keep const DPCTLSyclContextRef CtxRef,
685
                                  __dpctl_keep const DPCTLSyclDeviceRef DevRef,
686
                                  __dpctl_keep const void *IL,
687
                                  size_t length,
688
                                  const char *CompileOpts,
689
                                  size_t NumSpecConsts,
690
                                  const DPCTLSpecConst *SpecConsts)
691
{
87✔
692
    DPCTLSyclKernelBundleRef KBRef = nullptr;
87✔
693
    if (!CtxRef) {
87✔
694
        error_handler("Cannot create program from SPIR-V as the supplied SYCL "
3✔
695
                      "context is NULL.",
3✔
696
                      __FILE__, __func__, __LINE__);
3✔
697
        return KBRef;
3✔
698
    }
3✔
699
    if (!DevRef) {
84✔
700
        error_handler("Cannot create program from SPIR-V as the supplied SYCL "
3✔
701
                      "device is NULL.",
3✔
702
                      __FILE__, __func__, __LINE__);
3✔
703
        return KBRef;
3✔
704
    }
3✔
705
    if ((!IL) || (length == 0)) {
81!
706
        error_handler("Cannot create program from null SPIR-V buffer.",
3✔
707
                      __FILE__, __func__, __LINE__);
3✔
708
        return KBRef;
3✔
709
    }
3✔
710

711
    context *SyclCtx = unwrap<context>(CtxRef);
78✔
712
    device *SyclDev = unwrap<device>(DevRef);
78✔
713
    // get the backend type
714
    try {
78✔
715
        auto BE = SyclCtx->get_platform().get_backend();
78✔
716
        switch (BE) {
78✔
717
        case backend::opencl:
78!
718
            KBRef = _CreateKernelBundleWithIL_ocl_impl(
78✔
719
                *SyclCtx, *SyclDev, IL, length, CompileOpts, NumSpecConsts,
78✔
720
                SpecConsts);
78✔
721
            break;
78✔
722
        case backend::ext_oneapi_level_zero:
×
723
#ifdef DPCTL_ENABLE_L0_PROGRAM_CREATION
×
724
            KBRef = _CreateKernelBundleWithIL_ze_impl(
×
725
                *SyclCtx, *SyclDev, IL, length, CompileOpts, NumSpecConsts,
×
726
                SpecConsts);
×
727
            break;
×
728
#endif
×
729
        default:
×
730
            std::ostringstream os;
×
731
            os << "Backend " << BE << " is not supported";
×
732
            error_handler(os.str(), __FILE__, __func__, __LINE__);
×
733
            break;
×
734
        }
78✔
735
    } catch (std::exception const &e) {
78✔
736
        error_handler(e, __FILE__, __func__, __LINE__);
×
737
        return nullptr;
×
738
    }
×
739
    return KBRef;
78✔
740
}
78✔
741

742
__dpctl_give DPCTLSyclKernelBundleRef DPCTLKernelBundle_CreateFromOCLSource(
743
    __dpctl_keep const DPCTLSyclContextRef Ctx,
744
    __dpctl_keep const DPCTLSyclDeviceRef Dev,
745
    __dpctl_keep const char *Source,
746
    __dpctl_keep const char *CompileOpts)
747
{
41✔
748
    context *SyclCtx = nullptr;
41✔
749
    device *SyclDev = nullptr;
41✔
750

751
    if (!Ctx) {
41✔
752
        error_handler("Input Ctx is nullptr.", __FILE__, __func__, __LINE__);
10✔
753
        return nullptr;
10✔
754
    }
10✔
755
    if (!Dev) {
31✔
756
        error_handler("Input Dev is nullptr.", __FILE__, __func__, __LINE__);
1✔
757
        return nullptr;
1✔
758
    }
1✔
759
    if (!Source) {
30!
760
        error_handler("Input Source is nullptr.", __FILE__, __func__, __LINE__);
×
761
        return nullptr;
×
762
    }
×
763

764
    SyclCtx = unwrap<context>(Ctx);
30✔
765
    SyclDev = unwrap<device>(Dev);
30✔
766

767
    // get the backend type
768
    auto BE = SyclCtx->get_platform().get_backend();
30✔
769
    switch (BE) {
30✔
770
    case backend::opencl:
30!
771
        try {
30✔
772
            return _CreateKernelBundleWithOCLSource_ocl_impl(
30✔
773
                *SyclCtx, *SyclDev, Source, CompileOpts);
30✔
774
        } catch (std::exception const &e) {
30✔
775
            error_handler(e, __FILE__, __func__, __LINE__);
×
776
            return nullptr;
×
777
        }
×
778
        break;
×
779
    case backend::ext_oneapi_level_zero:
×
780
        error_handler(
×
781
            "CreateFromSource is not supported for Level Zero backend.",
×
782
            __FILE__, __func__, __LINE__);
×
783
        return nullptr;
×
784
    default:
×
785
        error_handler("CreateFromSource is not supported in unknown backend.",
×
786
                      __FILE__, __func__, __LINE__);
×
787
        return nullptr;
×
788
    }
30✔
789
}
30✔
790

791
__dpctl_give DPCTLSyclKernelRef
792
DPCTLKernelBundle_GetKernel(__dpctl_keep DPCTLSyclKernelBundleRef KBRef,
793
                            __dpctl_keep const char *KernelName)
794
{
115✔
795
    if (!KBRef) {
115✔
796
        error_handler("Input KBRef is nullptr", __FILE__, __func__, __LINE__);
21✔
797
        return nullptr;
21✔
798
    }
21✔
799
    if (!KernelName) {
94✔
800
        error_handler("Input KernelName is nullptr", __FILE__, __func__,
3✔
801
                      __LINE__);
3✔
802
        return nullptr;
3✔
803
    }
3✔
804
    auto SyclKB = unwrap<kernel_bundle<bundle_state::executable>>(KBRef);
91✔
805
    sycl::backend be = SyclKB->get_backend();
91✔
806
    switch (be) {
91✔
807
    case sycl::backend::opencl:
91!
808
        return _GetKernel_ocl_impl(*SyclKB, KernelName);
91✔
809
    case sycl::backend::ext_oneapi_level_zero:
×
810
#ifdef DPCTL_ENABLE_L0_PROGRAM_CREATION
×
811
        return _GetKernel_ze_impl(*SyclKB, KernelName);
×
812
#endif
×
813
    default:
×
814
        std::ostringstream os;
×
815
        os << "Backend " << be << " is not supported";
×
816
        error_handler(os.str(), __FILE__, __func__, __LINE__);
×
817
        return nullptr;
×
818
    }
91✔
819
}
91✔
820

821
bool DPCTLKernelBundle_HasKernel(__dpctl_keep DPCTLSyclKernelBundleRef KBRef,
822
                                 __dpctl_keep const char *KernelName)
823
{
82✔
824
    if (!KBRef) {
82✔
825
        error_handler("Input KBRef is nullptr", __FILE__, __func__, __LINE__);
3✔
826
        return false;
3✔
827
    }
3✔
828
    if (!KernelName) {
79✔
829
        error_handler("Input KernelName is nullptr", __FILE__, __func__,
3✔
830
                      __LINE__);
3✔
831
        return false;
3✔
832
    }
3✔
833

834
    auto SyclKB = unwrap<kernel_bundle<bundle_state::executable>>(KBRef);
76✔
835
    sycl::backend be = SyclKB->get_backend();
76✔
836
    switch (be) {
76✔
837
    case sycl::backend::opencl:
76!
838
        return _HasKernel_ocl_impl(*SyclKB, KernelName);
76✔
839
    case sycl::backend::ext_oneapi_level_zero:
×
840
#ifdef DPCTL_ENABLE_L0_PROGRAM_CREATION
×
841
        return _HasKernel_ze_impl(*SyclKB, KernelName);
×
842
#endif
×
843
    default:
×
844
        std::ostringstream os;
×
845
        os << "Backend " << be << " is not supported";
×
846
        error_handler(os.str(), __FILE__, __func__, __LINE__);
×
847
        return false;
×
848
    }
76✔
849
}
76✔
850

851
void DPCTLKernelBundle_Delete(__dpctl_take DPCTLSyclKernelBundleRef KBRef)
852
{
130✔
853
    delete unwrap<kernel_bundle<bundle_state::executable>>(KBRef);
130✔
854
}
130✔
855

856
__dpctl_give DPCTLSyclKernelBundleRef
857
DPCTLKernelBundle_Copy(__dpctl_keep const DPCTLSyclKernelBundleRef KBRef)
858
{
8✔
859
    auto Bundle = unwrap<kernel_bundle<bundle_state::executable>>(KBRef);
8✔
860
    if (!Bundle) {
8✔
861
        error_handler(
3✔
862
            "Cannot copy DPCTLSyclKernelBundleRef as input is a nullptr",
3✔
863
            __FILE__, __func__, __LINE__);
3✔
864
        return nullptr;
3✔
865
    }
3✔
866
    try {
5✔
867
        auto CopiedBundle =
5✔
868
            new kernel_bundle<bundle_state::executable>(*Bundle);
5✔
869
        return wrap<kernel_bundle<bundle_state::executable>>(CopiedBundle);
5✔
870
    } catch (std::exception const &e) {
5✔
871
        error_handler(e, __FILE__, __func__, __LINE__);
×
872
        return nullptr;
×
873
    }
×
874
}
5✔
875

876
using build_option_list_t = std::vector<std::string>;
877

878
__dpctl_give DPCTLBuildOptionListRef DPCTLBuildOptionList_Create()
879
{
20✔
880
    auto BuildOptionList =
20✔
881
        std::unique_ptr<build_option_list_t>(new build_option_list_t());
20✔
882
    auto *RetVal =
20✔
883
        reinterpret_cast<DPCTLBuildOptionListRef>(BuildOptionList.get());
20✔
884
    BuildOptionList.release();
20✔
885
    return RetVal;
20✔
886
}
20✔
887

888
void DPCTLBuildOptionList_Delete(__dpctl_take DPCTLBuildOptionListRef Ref)
889
{
20✔
890
    delete reinterpret_cast<build_option_list_t *>(Ref);
20✔
891
}
20✔
892

893
void DPCTLBuildOptionList_Append(__dpctl_keep DPCTLBuildOptionListRef Ref,
894
                                 __dpctl_keep const char *Option)
895
{
9✔
896
    reinterpret_cast<build_option_list_t *>(Ref)->emplace_back(Option);
9✔
897
}
9✔
898

899
using kernel_name_list_t = std::vector<std::string>;
900

901
__dpctl_give DPCTLKernelNameListRef DPCTLKernelNameList_Create()
902
{
20✔
903
    auto KernelNameList =
20✔
904
        std::unique_ptr<kernel_name_list_t>(new kernel_name_list_t());
20✔
905
    auto *RetVal =
20✔
906
        reinterpret_cast<DPCTLKernelNameListRef>(KernelNameList.get());
20✔
907
    KernelNameList.release();
20✔
908
    return RetVal;
20✔
909
}
20✔
910

911
void DPCTLKernelNameList_Delete(__dpctl_take DPCTLKernelNameListRef Ref)
912
{
20✔
913
    delete reinterpret_cast<kernel_name_list_t *>(Ref);
20✔
914
}
20✔
915

916
void DPCTLKernelNameList_Append(__dpctl_keep DPCTLKernelNameListRef Ref,
917
                                __dpctl_keep const char *Option)
918
{
8✔
919
    reinterpret_cast<kernel_name_list_t *>(Ref)->emplace_back(Option);
8✔
920
}
8✔
921

922
using virtual_header_list_t = std::vector<std::pair<std::string, std::string>>;
923

924
__dpctl_give DPCTLVirtualHeaderListRef DPCTLVirtualHeaderList_Create()
925
{
20✔
926
    auto HeaderList =
20✔
927
        std::unique_ptr<virtual_header_list_t>(new virtual_header_list_t());
20✔
928
    auto *RetVal =
20✔
929
        reinterpret_cast<DPCTLVirtualHeaderListRef>(HeaderList.get());
20✔
930
    HeaderList.release();
20✔
931
    return RetVal;
20✔
932
}
20✔
933

934
void DPCTLVirtualHeaderList_Delete(__dpctl_take DPCTLVirtualHeaderListRef Ref)
935
{
20✔
936
    delete reinterpret_cast<virtual_header_list_t *>(Ref);
20✔
937
}
20✔
938

939
void DPCTLVirtualHeaderList_Append(__dpctl_keep DPCTLVirtualHeaderListRef Ref,
940
                                   __dpctl_keep const char *Name,
941
                                   __dpctl_keep const char *Content)
942
{
15✔
943
    auto Header = std::make_pair<std::string, std::string>(Name, Content);
15✔
944
    reinterpret_cast<virtual_header_list_t *>(Ref)->push_back(Header);
15✔
945
}
15✔
946

947
using kernel_build_log_t = std::string;
948

949
__dpctl_give DPCTLKernelBuildLogRef DPCTLKernelBuildLog_Create()
950
{
20✔
951
    auto BuildLog =
20✔
952
        std::unique_ptr<kernel_build_log_t>(new kernel_build_log_t(""));
20✔
953
    auto *RetVal = reinterpret_cast<DPCTLKernelBuildLogRef>(BuildLog.get());
20✔
954
    BuildLog.release();
20✔
955
    return RetVal;
20✔
956
}
20✔
957

958
void DPCTLKernelBuildLog_Delete(__dpctl_take DPCTLKernelBuildLogRef Ref)
959
{
20✔
960
    delete reinterpret_cast<kernel_build_log_t *>(Ref);
20✔
961
}
20✔
962

963
const char *DPCTLKernelBuildLog_Get(__dpctl_keep DPCTLKernelBuildLogRef Ref)
964
{
1✔
965
    return reinterpret_cast<kernel_build_log_t *>(Ref)->data();
1✔
966
}
1✔
967

968
namespace syclex = sycl::ext::oneapi::experimental;
969

970
#if defined(SYCL_EXT_ONEAPI_KERNEL_COMPILER) &&                                \
971
    defined(__SYCL_COMPILER_VERSION) && !defined(SUPPORTS_SYCL_COMPILATION)
972
// SYCL source code compilation is supported from 2025.1 onwards.
973
#if __SYCL_COMPILER_VERSION >= 20250317u
974
#define SUPPORTS_SYCL_COMPILATION 1
975
#else
976
#define SUPPORTS_SYCL_COMPILATION 0
977
#endif
978
#endif
979

980
bool DPCTLKernelBundle_CreateFromSYCLSource_Available()
981
{
14✔
982
#if (SUPPORTS_SYCL_COMPILATION > 0)
14✔
983
    return true;
14✔
984
#else
985
    return false;
986
#endif
987
}
14✔
988

989
#if (SUPPORTS_SYCL_COMPILATION > 0)
990
// The property for registering names was renamed between DPC++ versions 2025.1
991
// and 2025.2. The original name was `registered_kernel_names`, the new name is
992
// `registered_names`. To select the correct name without being overly reliant
993
// on the SYCL compiler version definition, we forward declare both names and
994
// then select the new name if it is defined (i.e., not only declared).
995
namespace sycl::ext::oneapi::experimental
996
{
997
struct registered_names;
998
struct registered_kernel_names;
999
} // namespace sycl::ext::oneapi::experimental
1000

1001
template <typename NewT, typename FallbackT, typename = void>
1002
struct new_type_if_defined
1003
{
1004
    using type = FallbackT;
1005
};
1006

1007
template <typename NewT, typename FallbackT>
1008
struct new_type_if_defined<NewT, FallbackT, std::void_t<decltype(sizeof(NewT))>>
1009
{
1010
    using type = NewT;
1011
};
1012

1013
using registered_names_property_t =
1014
    new_type_if_defined<syclex::registered_names,
1015
                        syclex::registered_kernel_names>::type;
1016
#endif
1017

1018
__dpctl_give DPCTLSyclKernelBundleRef DPCTLKernelBundle_CreateFromSYCLSource(
1019
    __dpctl_keep const DPCTLSyclContextRef Ctx,
1020
    __dpctl_keep const DPCTLSyclDeviceRef Dev,
1021
    __dpctl_keep const char *Source,
1022
    __dpctl_keep DPCTLVirtualHeaderListRef Headers,
1023
    __dpctl_keep DPCTLKernelNameListRef Names,
1024
    __dpctl_keep DPCTLBuildOptionListRef BuildOptions,
1025
    __dpctl_keep DPCTLKernelBuildLogRef BuildLog)
1026
{
15✔
1027
#if (SUPPORTS_SYCL_COMPILATION > 0)
15✔
1028
    // optional arguments and BuildLog may be NULL, which is equivalent to
1029
    // passing an empty list or discarding the log
1030
    // Writing to the log is routed through a helper
1031
    auto *RawBuildLog = reinterpret_cast<kernel_build_log_t *>(BuildLog);
15✔
1032
    auto set_build_log = [RawBuildLog](const std::string &Msg) {
15✔
1033
        if (RawBuildLog)
5✔
1034
            *RawBuildLog = Msg;
4✔
1035
    };
5✔
1036
    auto fail = [&set_build_log](const char *Msg, int Line) {
15✔
1037
        set_build_log(Msg);
3✔
1038
        error_handler(Msg, __FILE__, "DPCTLKernelBundle_CreateFromSYCLSource",
3✔
1039
                      Line);
3✔
1040
        return nullptr;
3✔
1041
    };
3✔
1042

1043
    if (!Ctx)
15✔
1044
        return fail("Input Ctx is nullptr.", __LINE__);
1✔
1045
    if (!Dev)
14✔
1046
        return fail("Input Dev is nullptr.", __LINE__);
1✔
1047
    if (!Source)
13✔
1048
        return fail("Input Source is nullptr.", __LINE__);
1✔
1049

1050
    static const virtual_header_list_t EmptyHeaders{};
12✔
1051
    static const kernel_name_list_t EmptyNames{};
12✔
1052
    static const build_option_list_t EmptyOptions{};
12✔
1053

1054
    const auto &IncludeFiles =
12✔
1055
        Headers ? *reinterpret_cast<virtual_header_list_t *>(Headers)
12✔
1056
                : EmptyHeaders;
12✔
1057
    const auto &KernelNames =
12✔
1058
        Names ? *reinterpret_cast<kernel_name_list_t *>(Names) : EmptyNames;
12✔
1059
    const auto &Options =
12✔
1060
        BuildOptions ? *reinterpret_cast<build_option_list_t *>(BuildOptions)
12✔
1061
                     : EmptyOptions;
12✔
1062

1063
    context *SyclCtx = unwrap<context>(Ctx);
12✔
1064
    device *SyclDev = unwrap<device>(Dev);
12✔
1065
    if (!SyclDev->ext_oneapi_can_compile(syclex::source_language::sycl)) {
12!
NEW
1066
        set_build_log("Device does not support compilation of SYCL source.");
×
NEW
1067
        return nullptr;
×
NEW
1068
    }
×
1069
    try {
12✔
1070
        std::unique_ptr<kernel_bundle<bundle_state::ext_oneapi_source>>
12✔
1071
            SrcBundle;
12✔
1072
        std::string Src(Source);
12✔
1073
        // The following logic is to work around a bug in DPC++ version 2025.1.
1074
        // This version declares a constructor with no parameters for the
1075
        // `include_files` property, but does not implement it. Therefore, the
1076
        // only way to create `include_files` is with the name and content of
1077
        // the first virtual header, if any.
1078
        if (!IncludeFiles.empty()) {
12✔
1079
            auto IncludeFileIt = IncludeFiles.begin();
8✔
1080
            syclex::include_files IncludeFilesProp{IncludeFileIt->first,
8✔
1081
                                                   IncludeFileIt->second};
8✔
1082
            for (std::advance(IncludeFileIt, 1);
8✔
1083
                 IncludeFileIt != IncludeFiles.end(); ++IncludeFileIt)
15✔
1084
            {
7✔
1085
                IncludeFilesProp.add(IncludeFileIt->first,
7✔
1086
                                     IncludeFileIt->second);
7✔
1087
            }
7✔
1088
            SrcBundle = std::make_unique<
8✔
1089
                kernel_bundle<bundle_state::ext_oneapi_source>>(
8✔
1090
                syclex::create_kernel_bundle_from_source(
8✔
1091
                    *SyclCtx, syclex::source_language::sycl, Src,
8✔
1092
                    syclex::properties{IncludeFilesProp}));
8✔
1093
        }
8✔
1094
        else {
4✔
1095
            SrcBundle = std::make_unique<
4✔
1096
                kernel_bundle<bundle_state::ext_oneapi_source>>(
4✔
1097
                syclex::create_kernel_bundle_from_source(
4✔
1098
                    *SyclCtx, syclex::source_language::sycl, Src));
4✔
1099
        }
4✔
1100

1101
        registered_names_property_t RegisteredNames;
12✔
1102
        for (const std::string &Name : KernelNames) {
12✔
1103
            RegisteredNames.add(Name);
7✔
1104
        }
7✔
1105

1106
        syclex::build_options Opts{Options};
12✔
1107

1108
        std::vector<sycl::device> Devices({*SyclDev});
12✔
1109

1110
        auto ExeBundle = syclex::build(
12✔
1111
            *SrcBundle, Devices, syclex::properties{RegisteredNames, Opts});
12✔
1112
        auto ResultBundle =
12✔
1113
            std::make_unique<sycl::kernel_bundle<bundle_state::executable>>(
12✔
1114
                ExeBundle);
12✔
1115
        return wrap<kernel_bundle<bundle_state::executable>>(
12✔
1116
            ResultBundle.release());
12✔
1117
    } catch (const std::exception &e) {
12✔
1118
        set_build_log(e.what());
2✔
1119
        return nullptr;
2✔
1120
    }
2✔
1121
#else
1122
    return nullptr;
1123
#endif
1124
}
12✔
1125

1126
__dpctl_give DPCTLSyclKernelRef
1127
DPCTLKernelBundle_GetSyclKernel(__dpctl_keep DPCTLSyclKernelBundleRef KBRef,
1128
                                __dpctl_keep const char *KernelName)
1129
{
7✔
1130
#if (SUPPORTS_SYCL_COMPILATION > 0)
7✔
1131
    if (!KBRef) {
7✔
1132
        error_handler("Input KBRef is nullptr", __FILE__, __func__, __LINE__);
1✔
1133
        return nullptr;
1✔
1134
    }
1✔
1135
    if (!KernelName) {
6✔
1136
        error_handler("Input KernelName is nullptr", __FILE__, __func__,
1✔
1137
                      __LINE__);
1✔
1138
        return nullptr;
1✔
1139
    }
1✔
1140
    try {
5✔
1141
        auto KernelBundle =
5✔
1142
            unwrap<sycl::kernel_bundle<bundle_state::executable>>(KBRef);
5✔
1143
        auto Kernel = KernelBundle->ext_oneapi_get_kernel(KernelName);
5✔
1144
        return wrap<sycl::kernel>(new sycl::kernel(Kernel));
5✔
1145
    } catch (const std::exception &e) {
5✔
NEW
1146
        error_handler(e, __FILE__, __func__, __LINE__);
×
NEW
1147
        return nullptr;
×
NEW
1148
    }
×
1149
#else
1150
    return nullptr;
1151
#endif
1152
}
5✔
1153

1154
bool DPCTLKernelBundle_HasSyclKernel(__dpctl_keep DPCTLSyclKernelBundleRef
1155
                                         KBRef,
1156
                                     __dpctl_keep const char *KernelName)
1157
{
9✔
1158
#if (SUPPORTS_SYCL_COMPILATION > 0)
9✔
1159
    if (!KBRef) {
9✔
1160
        error_handler("Input KBRef is nullptr", __FILE__, __func__, __LINE__);
1✔
1161
        return false;
1✔
1162
    }
1✔
1163
    if (!KernelName) {
8✔
1164
        error_handler("Input KernelName is nullptr", __FILE__, __func__,
1✔
1165
                      __LINE__);
1✔
1166
        return false;
1✔
1167
    }
1✔
1168
    try {
7✔
1169
        auto KernelBundle =
7✔
1170
            unwrap<sycl::kernel_bundle<bundle_state::executable>>(KBRef);
7✔
1171
        return KernelBundle->ext_oneapi_has_kernel(KernelName);
7✔
1172
    } catch (const std::exception &e) {
7✔
NEW
1173
        error_handler(e, __FILE__, __func__, __LINE__);
×
NEW
1174
        return false;
×
NEW
1175
    }
×
1176
#else
1177
    return false;
1178
#endif
1179
}
7✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc