36 std::vector<device> DeviceList,
38 : MContext(Context), MDevices(DeviceList), MPropList(PropList) {
39 if (Context->getDevices().size() > 1) {
41 "multiple devices within a context are not supported with "
42 "sycl::program and sycl::kernel",
43 PI_ERROR_INVALID_OPERATION);
48 std::vector<std::shared_ptr<program_impl>> ProgramList,
51 MLinkOptions(LinkOptions), MBuildOptions(LinkOptions) {
53 if (ProgramList.empty()) {
54 throw runtime_error(
"Non-empty vector of programs expected",
55 PI_ERROR_INVALID_VALUE);
60 std::sort(ProgramList.begin(), ProgramList.end());
61 auto It = std::unique(ProgramList.begin(), ProgramList.end());
62 if (It != ProgramList.end()) {
63 throw runtime_error(
"Attempting to link a program with itself",
64 PI_ERROR_INVALID_PROGRAM);
67 MContext = ProgramList[0]->MContext;
68 if (MContext->getDevices().size() > 1) {
70 "multiple devices within a context are not supported with "
71 "sycl::program and sycl::kernel",
72 PI_ERROR_INVALID_OPERATION);
74 MDevices = ProgramList[0]->MDevices;
75 std::vector<device> DevicesSorted;
77 DevicesSorted = sort_devices_by_cl_device_id(MDevices);
79 check_device_feature_support<info::device::is_linker_available>(MDevices);
80 std::list<std::lock_guard<std::mutex>> Locks;
81 for (
const auto &Prg : ProgramList) {
82 Locks.emplace_back(Prg->MMutex);
84 if (Prg->MContext != MContext) {
85 throw invalid_object_error(
86 "Not all programs are associated with the same context",
87 PI_ERROR_INVALID_PROGRAM);
90 std::vector<device> PrgDevicesSorted =
91 sort_devices_by_cl_device_id(Prg->MDevices);
92 if (PrgDevicesSorted != DevicesSorted) {
93 throw invalid_object_error(
94 "Not all programs are associated with the same devices",
95 PI_ERROR_INVALID_PROGRAM);
101 std::vector<RT::PiDevice> Devices(get_pi_devices());
102 std::vector<RT::PiProgram> Programs;
103 bool NonInterOpToLink =
false;
104 for (
const auto &Prg : ProgramList) {
105 if (!Prg->MLinkable && NonInterOpToLink)
107 NonInterOpToLink |= !Prg->MLinkable;
108 Programs.push_back(Prg->MProgram);
112 MContext->getHandleRef(), Devices.size(), Devices.data(),
113 LinkOptions.c_str(), Programs.size(), Programs.data(),
nullptr,
nullptr,
128 : MProgram(Program), MContext(Context), MLinkable(true) {
130 if (MProgram ==
nullptr) {
131 assert(InteropProgram &&
132 "No InteropProgram/PiProgram defined with piextProgramFromNative");
135 InteropProgram, MContext->getHandleRef(),
false, &MProgram);
144 std::vector<RT::PiDevice> PiDevices(NumDevices);
147 PiDevices.data(),
nullptr);
148 std::vector<device> SyclContextDevices =
149 MContext->get_info<info::context::devices>();
154 auto NewEnd = std::remove_if(
155 SyclContextDevices.begin(), SyclContextDevices.end(),
156 [&PiDevices](
const sycl::device &Dev) {
157 return PiDevices.end() ==
158 std::find(PiDevices.begin(), PiDevices.end(),
159 detail::getSyclObjImpl(Dev)->getHandleRef());
161 SyclContextDevices.erase(NewEnd, SyclContextDevices.end());
162 MDevices = SyclContextDevices;
163 assert(!MDevices.empty() &&
"No device found for this program");
166 cl_program_binary_type BinaryType;
169 sizeof(cl_program_binary_type), &BinaryType,
nullptr);
171 throw invalid_object_error(
172 "The native program passed to the program constructor has to be either "
173 "compiled or linked",
174 PI_ERROR_INVALID_PROGRAM);
179 std::vector<char> OptionsVector(Size);
182 OptionsVector.data(),
nullptr);
183 std::string Options(OptionsVector.begin(), OptionsVector.end());
184 switch (BinaryType) {
190 MCompileOptions = Options;
191 MBuildOptions = Options;
197 MBuildOptions = Options;
210 if (!
is_host() && MProgram !=
nullptr) {
219 throw invalid_object_error(
220 "This instance of program doesn't support OpenCL interoperability.",
221 PI_ERROR_INVALID_PROGRAM);
224 return pi::cast<cl_program>(MProgram);
228 std::string CompileOptions,
230 std::lock_guard<std::mutex> Lock(MMutex);
232 MProgramModuleHandle = M;
234 create_pi_program_with_kernel_name(
236 (!CompileOptions.empty()));
237 compile(CompileOptions);
243 std::string CompileOptions) {
244 std::lock_guard<std::mutex> Lock(MMutex);
248 create_cl_program_with_source(KernelSource);
249 compile(CompileOptions);
256 std::string BuildOptions,
258 std::lock_guard<std::mutex> Lock(MMutex);
260 MProgramModuleHandle = Module;
262 MProgramAndKernelCachingAllowed =
true;
263 MBuildOptions = BuildOptions;
267 (!BuildOptions.empty()));
275 std::string BuildOptions) {
276 std::lock_guard<std::mutex> Lock(MMutex);
280 create_cl_program_with_source(KernelSource);
288 std::lock_guard<std::mutex> Lock(MMutex);
291 check_device_feature_support<info::device::is_linker_available>(MDevices);
292 std::vector<RT::PiDevice> Devices(get_pi_devices());
296 LinkOpts = LinkOptions.c_str();
301 if (MProgram !=
nullptr)
305 MContext->getHandleRef(), Devices.size(), Devices.data(), LinkOpts,
306 1, &MProgram,
nullptr,
nullptr, &MProgram);
308 MLinkOptions = LinkOptions;
309 MBuildOptions = LinkOptions;
315 bool IsCreatedFromSource)
const {
318 return !IsCreatedFromSource;
321 std::vector<RT::PiDevice> Devices(get_pi_devices());
328 Device, MProgram, KernelName.c_str(), &function_ptr);
329 if (Err != PI_SUCCESS &&
330 Err != PI_ERROR_FUNCTION_ADDRESS_IS_NOT_AVAILABLE &&
331 Err != PI_ERROR_INVALID_KERNEL_NAME)
333 "Error from piextGetDeviceFunctionPointer when called by program",
335 if (Err == PI_SUCCESS || Err == PI_ERROR_FUNCTION_ADDRESS_IS_NOT_AVAILABLE)
343 std::shared_ptr<program_impl> PtrToSelf,
344 bool IsCreatedFromSource)
const {
347 if (IsCreatedFromSource)
348 throw invalid_object_error(
"This instance of program is a host instance",
349 PI_ERROR_INVALID_PROGRAM);
351 return createSyclObjFromImpl<kernel>(
352 std::make_shared<kernel_impl>(MContext, PtrToSelf));
354 return createSyclObjFromImpl<kernel>(
355 std::make_shared<kernel_impl>(get_pi_kernel(KernelName), MContext,
356 PtrToSelf, IsCreatedFromSource,
nullptr));
364 std::vector<std::vector<char>> Result;
366 std::vector<size_t> BinarySizes(MDevices.size());
369 sizeof(size_t) * BinarySizes.size(), BinarySizes.data(),
nullptr);
371 std::vector<char *> Pointers;
372 for (
size_t I = 0; I < BinarySizes.size(); ++I) {
373 Result.emplace_back(BinarySizes[I]);
374 Pointers.push_back(Result[I].data());
377 sizeof(
char *) * Pointers.size(),
378 Pointers.data(),
nullptr);
382 void program_impl::create_cl_program_with_source(
const std::string &Source) {
383 assert(!MProgram &&
"This program already has an encapsulated cl_program");
384 const char *Src = Source.c_str();
385 size_t Size = Source.size();
389 MContext->getHandleRef(), 1, &Src, &Size, &MProgram);
391 if (Err == PI_ERROR_INVALID_OPERATION) {
393 "program::compile_with_source is not supported by the selected backend",
394 PI_ERROR_INVALID_OPERATION);
397 if (Err != PI_SUCCESS) {
398 Plugin.
reportPiError(Err,
"create_cl_program_with_source()");
402 void program_impl::compile(
const std::string &Options) {
403 check_device_feature_support<info::device::is_compiler_available>(MDevices);
404 std::vector<RT::PiDevice> Devices(get_pi_devices());
405 const detail::plugin &Plugin =
getPlugin();
408 CompileOpts = Options.c_str();
411 MProgram, Devices.size(), Devices.data(), CompileOpts, 0,
nullptr,
412 nullptr,
nullptr,
nullptr);
414 if (Err != PI_SUCCESS) {
416 "Program compilation error:\n" +
420 MCompileOptions = Options;
421 MBuildOptions = Options;
424 void program_impl::build(
const std::string &Options) {
425 check_device_feature_support<info::device::is_compiler_available>(MDevices);
426 std::vector<RT::PiDevice> Devices(get_pi_devices());
427 const detail::plugin &Plugin =
getPlugin();
430 MProgram, Devices.size(), Devices.data(), Options.c_str(),
nullptr,
433 if (Err != PI_SUCCESS) {
435 "Program build error:\n" +
439 MBuildOptions = Options;
442 std::vector<RT::PiDevice> program_impl::get_pi_devices()
const {
443 std::vector<RT::PiDevice> PiDevices;
444 for (
const auto &Device : MDevices) {
450 RT::PiKernel program_impl::get_pi_kernel(
const std::string &KernelName)
const {
454 std::tie(Kernel, std::ignore, std::ignore) =
460 const detail::plugin &Plugin =
getPlugin();
462 MProgram, KernelName.c_str(), &Kernel);
463 if (Err == PI_ERROR_INVALID_KERNEL_NAME) {
464 throw invalid_object_error(
465 "This instance of program does not contain the kernel requested",
468 Plugin.checkPiResult(Err);
480 program_impl::sort_devices_by_cl_device_id(std::vector<device> Devices) {
481 std::sort(Devices.begin(), Devices.end(),
482 [](
const device &id1,
const device &id2) {
483 return (detail::getSyclObjImpl(id1)->getHandleRef() <
484 detail::getSyclObjImpl(id2)->getHandleRef());
489 void program_impl::throw_if_state_is(
program_state State)
const {
490 if (MState == State) {
491 throw invalid_object_error(
"Invalid program state",
492 PI_ERROR_INVALID_PROGRAM);
496 void program_impl::throw_if_state_is_not(
program_state State)
const {
497 if (MState != State) {
498 throw invalid_object_error(
"Invalid program state",
499 PI_ERROR_INVALID_PROGRAM);
503 void program_impl::create_pi_program_with_kernel_name(
505 bool JITCompilationIsRequired) {
506 assert(!MProgram &&
"This program already has an encapsulated PI program");
509 RTDeviceBinaryImage &Img = PM.getDeviceImage(
510 Module, KernelName,
get_context(), FirstDevice, JITCompilationIsRequired);
511 MProgram = PM.createPIProgram(Img,
get_context(), {FirstDevice});
517 throw sycl::ext::oneapi::experimental::spec_const_error(
518 "Invalid program state", PI_ERROR_INVALID_PROGRAM);
520 auto LockGuard = MContext->getKernelProgramCache().acquireCachedPrograms();
522 SC.
set(ValSize, ValAddr);
533 auto LockGuard = Ctx->getKernelProgramCache().acquireCachedPrograms();
536 for (SCItTy SCIt : SCRange) {
537 auto SCEntry = SpecConstRegistry.find((*SCIt)->Name);
538 if (SCEntry == SpecConstRegistry.end())
542 assert(SC.
isSet() &&
"uninitialized spec constant");
553 while (!Descriptors.
empty()) {
554 auto [Id, Offset, Size] =
555 Descriptors.
consume<uint32_t, uint32_t, uint32_t>();