Skip to content

Commit 349c798

Browse files
authored
[SYCL] Support memset, memcmp in libdevice (#4147)
This PR adds memset and memcmp in libdevice. Latest llvm-spirv can handle llvm.memset intrinsic, so we just rely on "__builtin_memset" which is the same way as memcpy. For memcmp, there is no support we can rely on in latest llvm-spirv, so libdevice provides a simple implementation. Signed-off-by: gejin <[email protected]>
1 parent d3f5419 commit 349c798

File tree

7 files changed

+112
-0
lines changed

7 files changed

+112
-0
lines changed

libdevice/crt_wrapper.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ DEVICE_EXTERN_C
1313
void *memcpy(void *dest, const void *src, size_t n) {
1414
return __devicelib_memcpy(dest, src, n);
1515
}
16+
17+
DEVICE_EXTERN_C
18+
void *memset(void *dest, int c, size_t n) {
19+
return __devicelib_memset(dest, c, n);
20+
}
21+
22+
DEVICE_EXTERN_C
23+
int memcmp(const void *s1, const void *s2, size_t n) {
24+
return __devicelib_memcmp(s1, s2, n);
25+
}
26+
1627
#if defined(_WIN32)
1728
// Truncates a wide (16 or 32 bit) string (wstr) into an ASCII string (str).
1829
// Any non-ASCII characters are replaced by question mark '?'.

libdevice/fallback-cstring.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,83 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "wrapper.h"
10+
#include <cstdint>
1011

1112
#ifdef __SPIR__
13+
DEVICE_EXTERN_C
1214
void *__devicelib_memcpy(void *dest, const void *src, size_t n) {
1315
return __builtin_memcpy(dest, src, n);
1416
}
17+
18+
DEVICE_EXTERN_C
19+
void *__devicelib_memset(void *dest, int c, size_t n) {
20+
return __builtin_memset(dest, c, n);
21+
}
22+
23+
static int __devicelib_memcmp_uint8_aligned(const void *s1, const void *s2,
24+
size_t n) {
25+
const uint8_t *s1_uint8_ptr = reinterpret_cast<const uint8_t *>(s1);
26+
const uint8_t *s2_uint8_ptr = reinterpret_cast<const uint8_t *>(s2);
27+
while (n > 0) {
28+
if (*s1_uint8_ptr == *s2_uint8_ptr) {
29+
s1_uint8_ptr++;
30+
s2_uint8_ptr++;
31+
n--;
32+
} else {
33+
return *s1_uint8_ptr - *s2_uint8_ptr;
34+
}
35+
}
36+
37+
return 0;
38+
}
39+
40+
static int __devicelib_memcmp_uint32_aligned(const void *s1, const void *s2,
41+
size_t n) {
42+
const uint32_t *s1_uint32_ptr = reinterpret_cast<const uint32_t *>(s1);
43+
const uint32_t *s2_uint32_ptr = reinterpret_cast<const uint32_t *>(s2);
44+
while (n >= sizeof(uint32_t)) {
45+
if (*s1_uint32_ptr == *s2_uint32_ptr) {
46+
s1_uint32_ptr++;
47+
s2_uint32_ptr++;
48+
n -= sizeof(uint32_t);
49+
} else {
50+
n = sizeof(uint32_t);
51+
break;
52+
}
53+
}
54+
55+
return (n == 0) ? 0
56+
: __devicelib_memcmp_uint8_aligned(s1_uint32_ptr,
57+
s2_uint32_ptr, n);
58+
}
59+
60+
DEVICE_EXTERN_C
61+
int __devicelib_memcmp(const void *s1, const void *s2, size_t n) {
62+
if (s1 == s2 || n == 0)
63+
return 0;
64+
65+
size_t s1_uint32_mod =
66+
reinterpret_cast<unsigned long>(s1) % alignof(uint32_t);
67+
size_t s2_uint32_mod =
68+
reinterpret_cast<unsigned long>(s2) % alignof(uint32_t);
69+
70+
if (s1_uint32_mod != s2_uint32_mod)
71+
return __devicelib_memcmp_uint8_aligned(s1, s2, n);
72+
73+
if (s1_uint32_mod == 0)
74+
return __devicelib_memcmp_uint32_aligned(s1, s2, n);
75+
76+
size_t head_ua_len = sizeof(uint32_t) - s1_uint32_mod;
77+
int head_cmp = __devicelib_memcmp_uint8_aligned(s1, s2, head_ua_len);
78+
if (head_cmp == 0) {
79+
const uint8_t *s1_aligned_ptr = reinterpret_cast<const uint8_t *>(s1);
80+
const uint8_t *s2_aligned_ptr = reinterpret_cast<const uint8_t *>(s2);
81+
s1_aligned_ptr += head_ua_len;
82+
s2_aligned_ptr += head_ua_len;
83+
return __devicelib_memcmp_uint32_aligned(s1_aligned_ptr, s2_aligned_ptr,
84+
n - head_ua_len);
85+
}
86+
87+
return head_cmp;
88+
}
1589
#endif // __SPIR__

libdevice/wrapper.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
DEVICE_EXTERN_C
2222
void *__devicelib_memcpy(void *dest, const void *src, size_t n);
2323
DEVICE_EXTERN_C
24+
void *__devicelib_memset(void *dest, int c, size_t n);
25+
DEVICE_EXTERN_C
26+
int __devicelib_memcmp(const void *s1, const void *s2, size_t n);
27+
DEVICE_EXTERN_C
2428
void __devicelib_assert_fail(const char *expr, const char *file, int32_t line,
2529
const char *func, uint64_t gid0, uint64_t gid1,
2630
uint64_t gid2, uint64_t lid0, uint64_t lid1,

llvm/tools/sycl-post-link/SYCLDeviceLibReqMask.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ SYCLDeviceLibFuncMap SDLMap = {
159159
{"__devicelib_ctan", DeviceLibExt::cl_intel_devicelib_complex_fp64},
160160
{"__devicelib_ctanh", DeviceLibExt::cl_intel_devicelib_complex_fp64},
161161
{"__devicelib_memcpy", DeviceLibExt::cl_intel_devicelib_cstring},
162+
{"__devicelib_memset", DeviceLibExt::cl_intel_devicelib_cstring},
163+
{"__devicelib_memcmp", DeviceLibExt::cl_intel_devicelib_cstring},
162164
};
163165

164166
// Each fallback device library corresponds to one bit in "require mask" which

sycl/doc/extensions/C-CXX-StandardLibrary/C-CXX-StandardLibrary.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ List of supported functions from C standard library:
7878
- casinf, casin (from <complex.h>)
7979
- cacosf, cacos (from <complex.h>)
8080
- catanf, catan (from <complex.h>)
81+
- memcpy (from <string.h>)
82+
- memset (from <string.h>)
83+
- memcmp (from <string.h>)
8184

8285
All functions are grouped into different device libraries based on
8386
functionalities. C and C++ standard library groups functions and

sycl/doc/extensions/C-CXX-StandardLibrary/DeviceLibExtensions.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,19 @@ Those __devicelib_* functions have the same argument type and return type as cor
229229
complex math functions from <complex.h>, please refer to ISO/IEC 14882:2011 for details. The
230230
"double __complex__" type is C99 complex type and it is an alias to "struct {double, double}"
231231
in LLVM IR and SPIR-V.
232+
233+
cl_intel_devicelib_cstring
234+
==========================
235+
236+
.. code:
237+
void *__devicelib_memcpy(void *dest, const void *src, size_t n);
238+
void *__devicelib_memset(void *dest, int c, size_t n);
239+
int __devicelib_memcmp(const void *s1, const void *s2, size_t n);
240+
241+
Semantic:
242+
Those __devicelib_* functions perform the same operation as the corresponding C string
243+
library functions.
244+
245+
Arguments:
246+
Those __devicelib_* functions have the same argument type and return type as corresponding
247+
string functions from <string.h>, please refer to ISO/IEC 14882:2011 for details.

sycl/include/CL/sycl/builtins.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,6 +1638,8 @@ extern SYCL_EXTERNAL double ldexp(double x, int exp);
16381638
extern SYCL_EXTERNAL double hypot(double x, double y);
16391639

16401640
extern SYCL_EXTERNAL void *memcpy(void *dest, const void *src, size_t n);
1641+
extern SYCL_EXTERNAL void *memset(void *dest, int c, size_t n);
1642+
extern SYCL_EXTERNAL int memcmp(const void *s1, const void *s2, size_t n);
16411643
}
16421644
#ifdef __GLIBC__
16431645
extern "C" {

0 commit comments

Comments
 (0)