Skip to content

Commit f4ad3c1

Browse files
[SYCL][ESIMD][EMU] ESIMD_CPU Kernel launch and ESIMD_EMU backend loading (#4020)
* [SYCL][ESIMD][EMU] ESIMD_CPU Kernel launch and Emulated Intrinsics * This PR is for enabling kernel launching for ESIMD_CPU * esimd_cpu backend is loaded in SYCL runtime * Base PR : #4011 Author: dongkyunahn-intel <[email protected]>
1 parent 0680e5c commit f4ad3c1

File tree

15 files changed

+273
-74
lines changed

15 files changed

+273
-74
lines changed

sycl/CMakeLists.txt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -326,17 +326,17 @@ if(SYCL_BUILD_PI_HIP)
326326
list(APPEND SYCL_TOOLCHAIN_DEPLOY_COMPONENTS libspirv-builtins pi_hip)
327327
endif()
328328

329-
# TODO : Remove 'if (NOT MSVC)' when CM_EMU supports Windows
330-
# environment
331-
if (NOT MSVC)
332-
if (SYCL_BUILD_PI_ESIMD_EMULATOR)
333-
list(APPEND SYCL_TOOLCHAIN_DEPLOY_COMPONENTS pi_esimd_emulator libcmrt-headers)
334-
if (MSVC)
335-
list(APPEND SYCL_TOOLCHAIN_DEPLOY_COMPONENTS libcmrt-libs libcmrt-dlls)
336-
else()
337-
list(APPEND SYCL_TOOLCHAIN_DEPLOY_COMPONENTS libcmrt-sos)
338-
endif()
329+
if (SYCL_BUILD_PI_ESIMD_EMULATOR)
330+
list(APPEND SYCL_TOOLCHAIN_DEPLOY_COMPONENTS pi_esimd_emulator libcmrt-headers)
331+
if (MSVC)
332+
list(APPEND SYCL_TOOLCHAIN_DEPLOY_COMPONENTS libcmrt-libs libcmrt-dlls)
333+
else()
334+
list(APPEND SYCL_TOOLCHAIN_DEPLOY_COMPONENTS libcmrt-sos)
339335
endif()
336+
else()
337+
# TODO/FIXME : Removing empty header file (cm_rt.h) generation when
338+
# the ESIMD_EMULATOR support is enabled by default
339+
file (TOUCH ${SYCL_INCLUDE_BUILD_DIR}/sycl/CL/cm_rt.h)
340340
endif()
341341

342342
# Use it as fake dependency in order to force another command(s) to execute.

sycl/include/CL/sycl/detail/cg_types.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ template <class KernelType, class KernelArgType, int Dims, typename KernelName>
246246
class HostKernel : public HostKernelBase {
247247
using IDBuilder = sycl::detail::Builder;
248248
KernelType MKernel;
249+
// Allowing accessing MKernel from 'ResetHostKernelHelper' method of
250+
// 'sycl::handler'
251+
friend class sycl::handler;
249252

250253
public:
251254
HostKernel(KernelType Kernel) : MKernel(Kernel) {}

sycl/include/CL/sycl/handler.hpp

Lines changed: 124 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,124 @@ class __SYCL_EXPORT handler {
561561
}
562562
}
563563

564+
/* The kernel passed to StoreLambda can take an id, an item or an nd_item as
565+
* its argument. Since esimd plugin directly invokes the kernel (doesn’t use
566+
* piKernelSetArg), the kernel argument type must be known to the plugin.
567+
* However, passing kernel argument type to the plugin requires changing ABI
568+
* in HostKernel class. To overcome this problem, helpers below wrap the
569+
* “original” kernel with a functor that always takes an nd_item as argument.
570+
* A functor is used instead of a lambda because extractArgsAndReqsFromLambda
571+
* needs access to the “original” kernel and keeps references to its internal
572+
* data, i.e. the kernel passed as argument cannot be local in scope. The
573+
* functor itself is again encapsulated in a std::function since functor’s
574+
* type is unknown to the plugin.
575+
*/
576+
577+
// For 'id, item w/wo offset, nd_item' kernel arguments
578+
template <class KernelType, class NormalizedKernelType, int Dims,
579+
typename KernelName>
580+
KernelType *ResetHostKernelHelper(const KernelType &KernelFunc) {
581+
NormalizedKernelType NormalizedKernel(KernelFunc);
582+
auto NormalizedKernelFunc =
583+
std::function<void(const sycl::nd_item<Dims> &)>(NormalizedKernel);
584+
auto HostKernelPtr =
585+
new detail::HostKernel<decltype(NormalizedKernelFunc),
586+
sycl::nd_item<Dims>, Dims, KernelName>(
587+
NormalizedKernelFunc);
588+
MHostKernel.reset(HostKernelPtr);
589+
return &HostKernelPtr->MKernel.template target<NormalizedKernelType>()
590+
->MKernelFunc;
591+
}
592+
593+
// For 'sycl::id<Dims>' kernel argument
594+
template <class KernelType, typename ArgT, int Dims, typename KernelName>
595+
typename std::enable_if<std::is_same<ArgT, sycl::id<Dims>>::value,
596+
KernelType *>::type
597+
ResetHostKernel(const KernelType &KernelFunc) {
598+
struct NormalizedKernelType {
599+
KernelType MKernelFunc;
600+
NormalizedKernelType(const KernelType &KernelFunc)
601+
: MKernelFunc(KernelFunc) {}
602+
void operator()(const nd_item<Dims> &Arg) {
603+
detail::runKernelWithArg(MKernelFunc, Arg.get_global_id());
604+
}
605+
};
606+
return ResetHostKernelHelper<KernelType, struct NormalizedKernelType, Dims,
607+
KernelName>(KernelFunc);
608+
}
609+
610+
// For 'sycl::nd_item<Dims>' kernel argument
611+
template <class KernelType, typename ArgT, int Dims, typename KernelName>
612+
typename std::enable_if<std::is_same<ArgT, sycl::nd_item<Dims>>::value,
613+
KernelType *>::type
614+
ResetHostKernel(const KernelType &KernelFunc) {
615+
struct NormalizedKernelType {
616+
KernelType MKernelFunc;
617+
NormalizedKernelType(const KernelType &KernelFunc)
618+
: MKernelFunc(KernelFunc) {}
619+
void operator()(const nd_item<Dims> &Arg) {
620+
detail::runKernelWithArg(MKernelFunc, Arg);
621+
}
622+
};
623+
return ResetHostKernelHelper<KernelType, struct NormalizedKernelType, Dims,
624+
KernelName>(KernelFunc);
625+
}
626+
627+
// For 'sycl::item<Dims, without_offset>' kernel argument
628+
template <class KernelType, typename ArgT, int Dims, typename KernelName>
629+
typename std::enable_if<std::is_same<ArgT, sycl::item<Dims, false>>::value,
630+
KernelType *>::type
631+
ResetHostKernel(const KernelType &KernelFunc) {
632+
struct NormalizedKernelType {
633+
KernelType MKernelFunc;
634+
NormalizedKernelType(const KernelType &KernelFunc)
635+
: MKernelFunc(KernelFunc) {}
636+
void operator()(const nd_item<Dims> &Arg) {
637+
sycl::item<Dims, false> Item = detail::Builder::createItem<Dims, false>(
638+
Arg.get_global_range(), Arg.get_global_id());
639+
detail::runKernelWithArg(MKernelFunc, Item);
640+
}
641+
};
642+
return ResetHostKernelHelper<KernelType, struct NormalizedKernelType, Dims,
643+
KernelName>(KernelFunc);
644+
}
645+
646+
// For 'sycl::item<Dims, with_offset>' kernel argument
647+
template <class KernelType, typename ArgT, int Dims, typename KernelName>
648+
typename std::enable_if<std::is_same<ArgT, sycl::item<Dims, true>>::value,
649+
KernelType *>::type
650+
ResetHostKernel(const KernelType &KernelFunc) {
651+
struct NormalizedKernelType {
652+
KernelType MKernelFunc;
653+
NormalizedKernelType(const KernelType &KernelFunc)
654+
: MKernelFunc(KernelFunc) {}
655+
void operator()(const nd_item<Dims> &Arg) {
656+
sycl::item<Dims, true> Item = detail::Builder::createItem<Dims, true>(
657+
Arg.get_global_range(), Arg.get_global_id(), Arg.get_offset());
658+
detail::runKernelWithArg(MKernelFunc, Item);
659+
}
660+
};
661+
return ResetHostKernelHelper<KernelType, struct NormalizedKernelType, Dims,
662+
KernelName>(KernelFunc);
663+
}
664+
665+
/* 'wrapper'-based approach using 'NormalizedKernelType' struct is
666+
* not applied for 'void(void)' type kernel and
667+
* 'void(sycl::group<Dims>)'. This is because 'void(void)' type does
668+
* not have argument to normalize and 'void(sycl::group<Dims>)' is
669+
* not supported in ESIMD.
670+
*/
671+
// For 'void' and 'sycl::group<Dims>' kernel argument
672+
template <class KernelType, typename ArgT, int Dims, typename KernelName>
673+
typename std::enable_if<std::is_same<ArgT, void>::value ||
674+
std::is_same<ArgT, sycl::group<Dims>>::value,
675+
KernelType *>::type
676+
ResetHostKernel(const KernelType &KernelFunc) {
677+
MHostKernel.reset(
678+
new detail::HostKernel<KernelType, ArgT, Dims, KernelName>(KernelFunc));
679+
return (KernelType *)(MHostKernel->getPtr());
680+
}
681+
564682
/// Verifies the kernel bundle to be used if any is set. This throws a
565683
/// sycl::exception with error code errc::kernel_not_supported if the used
566684
/// kernel bundle does not contain a suitable device image with the requested
@@ -588,18 +706,19 @@ class __SYCL_EXPORT handler {
588706
"kernel_handler is not yet supported by host device.",
589707
PI_INVALID_OPERATION);
590708
}
591-
MHostKernel.reset(
592-
new detail::HostKernel<KernelType, LambdaArgType, Dims, KernelName>(
593-
KernelFunc));
709+
KernelType *KernelPtr =
710+
ResetHostKernel<KernelType, LambdaArgType, Dims, KernelName>(
711+
KernelFunc);
594712

595713
using KI = sycl::detail::KernelInfo<KernelName>;
596714
// Empty name indicates that the compilation happens without integration
597715
// header, so don't perform things that require it.
598716
if (KI::getName() != nullptr && KI::getName()[0] != '\0') {
599717
// TODO support ESIMD in no-integration-header case too.
600718
MArgs.clear();
601-
extractArgsAndReqsFromLambda(MHostKernel->getPtr(), KI::getNumParams(),
602-
&KI::getParamDesc(0), KI::isESIMD());
719+
extractArgsAndReqsFromLambda(reinterpret_cast<char *>(KernelPtr),
720+
KI::getNumParams(), &KI::getParamDesc(0),
721+
KI::isESIMD());
603722
MKernelName = KI::getName();
604723
MOSModuleHandle = detail::OSUtil::getOSModuleHandle(KI::getName());
605724
} else {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//==-------- atomic_intrin.hpp - Atomic intrinsic definition file ----------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
#pragma once
9+
10+
#include <CL/sycl/exception.hpp>
11+
12+
// This function implements atomic update of pre-existing variable in the
13+
// absense of C++ 20's atomic_ref.
14+
template <typename Ty> Ty atomic_add_fetch(Ty *ptr, Ty val) {
15+
#ifdef _WIN32
16+
// TODO: Windows will be supported soon
17+
throw cl::sycl::feature_not_supported();
18+
#else
19+
return __atomic_add_fetch(ptr, val, __ATOMIC_RELAXED);
20+
#endif
21+
}

sycl/include/sycl/ext/intel/experimental/esimd/emu/detail/esimd_emulator_device_interface.hpp

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -65,56 +65,8 @@ struct ESIMDEmuPluginOpaqueData {
6565
uintptr_t version;
6666
void *data;
6767
};
68-
// The table below shows the correspondence between the \c version
69-
// and the contents of the \c data field:
70-
// version == 0, data is ESIMDDeviceInterface*
7168

72-
ESIMDDeviceInterface *getESIMDDeviceInterface() {
73-
// TODO (performance) cache the interface pointer, can make a difference
74-
// when calling fine-grained libCM APIs through it (like memory access in a
75-
// tight loop)
76-
void *PIOpaqueData = nullptr;
77-
78-
PIOpaqueData =
79-
getPluginOpaqueData<cl::sycl::backend::ext_intel_esimd_emulator>(nullptr);
80-
81-
ESIMDEmuPluginOpaqueData *OpaqueData =
82-
reinterpret_cast<ESIMDEmuPluginOpaqueData *>(PIOpaqueData);
83-
84-
// First check if opaque data version is compatible.
85-
if (OpaqueData->version != ESIMD_EMULATOR_PLUGIN_OPAQUE_DATA_VERSION) {
86-
// NOTE: the version check should always be '!=' as layouts of different
87-
// versions of PluginOpaqueData is not backward compatible, unlike
88-
// layout of the ESIMDDeviceInterface.
89-
90-
std::cerr << __FUNCTION__ << std::endl
91-
<< "Opaque data returned by ESIMD Emu plugin is incompatible with"
92-
<< "the one used in current implementation." << std::endl
93-
<< "Returned version : " << OpaqueData->version << std::endl
94-
<< "Required version : "
95-
<< ESIMD_EMULATOR_PLUGIN_OPAQUE_DATA_VERSION << std::endl;
96-
throw cl::sycl::feature_not_supported();
97-
}
98-
// Opaque data version is OK, can cast the 'data' field.
99-
ESIMDDeviceInterface *Interface =
100-
reinterpret_cast<ESIMDDeviceInterface *>(OpaqueData->data);
101-
102-
// Now check that device interface version is compatible.
103-
if (Interface->version < ESIMD_DEVICE_INTERFACE_VERSION) {
104-
std::cerr << __FUNCTION__ << std::endl
105-
<< "The device interface version provided from plug-in "
106-
<< "library is behind required device interface version"
107-
<< std::endl
108-
<< "Found version : " << Interface->version << std::endl
109-
<< "Required version :" << ESIMD_DEVICE_INTERFACE_VERSION
110-
<< std::endl;
111-
throw cl::sycl::feature_not_supported();
112-
}
113-
return Interface;
114-
}
115-
116-
#undef ESIMD_DEVICE_INTERFACE_VERSION
117-
#undef ESIMD_EMULATOR_PLUGIN_OPAQUE_DATA_VERSION
69+
__SYCL_EXPORT ESIMDDeviceInterface *getESIMDDeviceInterface();
11870

11971
} // namespace detail
12072
} // namespace sycl

sycl/source/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ set(SYCL_SOURCES
176176
"sampler.cpp"
177177
"stream.cpp"
178178
"spirv_ops.cpp"
179+
"esimd_emulator_device_interface.cpp"
179180
"$<$<PLATFORM_ID:Windows>:detail/windows_pi.cpp>"
180181
"$<$<OR:$<PLATFORM_ID:Linux>,$<PLATFORM_ID:Darwin>>:detail/posix_pi.cpp>"
181182
"$<$<PLATFORM_ID:Windows>:abi_replacements_windows.cpp>"

sycl/source/detail/config.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,14 @@ getSyclDeviceTypeMap() {
169169
}
170170

171171
// Array is used by SYCL_DEVICE_FILTER and SYCL_DEVICE_ALLOWLIST
172-
const std::array<std::pair<std::string, backend>, 6> &getSyclBeMap() {
173-
static const std::array<std::pair<std::string, backend>, 6> SyclBeMap = {
172+
const std::array<std::pair<std::string, backend>, 7> &getSyclBeMap() {
173+
static const std::array<std::pair<std::string, backend>, 7> SyclBeMap = {
174174
{{"host", backend::host},
175175
{"opencl", backend::opencl},
176176
{"level_zero", backend::ext_oneapi_level_zero},
177177
{"cuda", backend::ext_oneapi_cuda},
178178
{"hip", backend::ext_oneapi_hip},
179+
{"esimd_emulator", backend::ext_intel_esimd_emulator},
179180
{"*", backend::all}}};
180181
return SyclBeMap;
181182
}

sycl/source/detail/config.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,13 @@ template <> class SYCLConfig<SYCL_BE> {
134134
return BackendPtr;
135135

136136
const char *ValStr = BaseT::getRawValue();
137-
const std::array<std::pair<std::string, backend>, 5> SyclBeMap = {
137+
const std::array<std::pair<std::string, backend>, 6> SyclBeMap = {
138138
{{"PI_OPENCL", backend::opencl},
139139
{"PI_LEVEL_ZERO", backend::ext_oneapi_level_zero},
140140
{"PI_LEVEL0", backend::ext_oneapi_level_zero}, // for backward
141141
// compatibility
142142
{"PI_CUDA", backend::ext_oneapi_cuda},
143+
{"PI_ESIMD_EMULATOR", backend::ext_intel_esimd_emulator},
143144
{"PI_HIP", backend::ext_oneapi_hip}}};
144145
if (ValStr) {
145146
auto It = std::find_if(
@@ -149,7 +150,8 @@ template <> class SYCLConfig<SYCL_BE> {
149150
});
150151
if (It == SyclBeMap.end())
151152
pi::die("Invalid backend. "
152-
"Valid values are PI_OPENCL/PI_LEVEL_ZERO/PI_CUDA/PI_HIP");
153+
"Valid values are "
154+
"PI_OPENCL/PI_LEVEL_ZERO/PI_CUDA/PI_ESIMD_EMULATOR/PI_HIP");
153155
static backend Backend = It->second;
154156
BackendPtr = &Backend;
155157
}
@@ -243,7 +245,7 @@ const std::array<std::pair<std::string, info::device_type>, 5> &
243245
getSyclDeviceTypeMap();
244246

245247
// Array is used by SYCL_DEVICE_FILTER and SYCL_DEVICE_ALLOWLIST
246-
const std::array<std::pair<std::string, backend>, 6> &getSyclBeMap();
248+
const std::array<std::pair<std::string, backend>, 7> &getSyclBeMap();
247249

248250
template <> class SYCLConfig<SYCL_DEVICE_FILTER> {
249251
using BaseT = SYCLConfigBase<SYCL_DEVICE_FILTER>;

sycl/source/detail/device_filter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ device_filter::device_filter(const std::string &FilterString) {
9191
std::string Message =
9292
std::string("Invalid device filter: ") + FilterString +
9393
"\nPossible backend values are "
94-
"{host,opencl,level_zero,cuda,hip,*}.\n"
94+
"{host,opencl,level_zero,cuda,hip,esimd_emulator*}.\n"
9595
"Possible device types are {host,cpu,gpu,acc,*}.\n"
9696
"Device number should be an non-negative integer.\n";
9797
throw cl::sycl::invalid_parameter_error(Message, PI_INVALID_VALUE);

sycl/source/detail/pi.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,14 @@ std::vector<std::pair<std::string, backend>> findPlugins() {
285285
backend::ext_oneapi_level_zero);
286286
PluginNames.emplace_back(__SYCL_CUDA_PLUGIN_NAME, backend::ext_oneapi_cuda);
287287
PluginNames.emplace_back(__SYCL_HIP_PLUGIN_NAME, backend::ext_oneapi_hip);
288+
PluginNames.emplace_back(__SYCL_ESIMD_EMULATOR_PLUGIN_NAME,
289+
backend::ext_intel_esimd_emulator);
288290
} else {
289291
std::vector<device_filter> Filters = FilterList->get();
290292
bool OpenCLFound = false;
291293
bool LevelZeroFound = false;
292294
bool CudaFound = false;
295+
bool EsimdCpuFound = false;
293296
bool HIPFound = false;
294297
for (const device_filter &Filter : Filters) {
295298
backend Backend = Filter.Backend;
@@ -310,6 +313,12 @@ std::vector<std::pair<std::string, backend>> findPlugins() {
310313
backend::ext_oneapi_cuda);
311314
CudaFound = true;
312315
}
316+
if (!EsimdCpuFound && (Backend == backend::ext_intel_esimd_emulator ||
317+
Backend == backend::all)) {
318+
PluginNames.emplace_back(__SYCL_ESIMD_EMULATOR_PLUGIN_NAME,
319+
backend::ext_intel_esimd_emulator);
320+
EsimdCpuFound = true;
321+
}
313322
if (!HIPFound &&
314323
(Backend == backend::ext_oneapi_hip || Backend == backend::all)) {
315324
PluginNames.emplace_back(__SYCL_HIP_PLUGIN_NAME,
@@ -429,6 +438,12 @@ static void initializePlugins(std::vector<plugin> &Plugins) {
429438
// Use the LEVEL_ZERO plugin as the GlobalPlugin
430439
GlobalPlugin = std::make_shared<plugin>(
431440
PluginInformation, backend::ext_oneapi_level_zero, Library);
441+
} else if (InteropBE == backend::ext_intel_esimd_emulator &&
442+
PluginNames[I].first.find("esimd_emulator") !=
443+
std::string::npos) {
444+
// Use the ESIMD_EMULATOR plugin as the GlobalPlugin
445+
GlobalPlugin = std::make_shared<plugin>(
446+
PluginInformation, backend::ext_intel_esimd_emulator, Library);
432447
}
433448
Plugins.emplace_back(
434449
plugin(PluginInformation, PluginNames[I].second, Library));

0 commit comments

Comments
 (0)