Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions libdevice/crt_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ DEVICE_EXTERN_C
void *memcpy(void *dest, const void *src, size_t n) {
return __devicelib_memcpy(dest, src, n);
}

DEVICE_EXTERN_C
void *memset(void *dest, int c, size_t n) {
return __devicelib_memset(dest, c, n);
}

DEVICE_EXTERN_C
int memcmp(const void *s1, const void *s2, size_t n) {
return __devicelib_memcmp(s1, s2, n);
}

#if defined(_WIN32)
// Truncates a wide (16 or 32 bit) string (wstr) into an ASCII string (str).
// Any non-ASCII characters are replaced by question mark '?'.
Expand Down
74 changes: 74 additions & 0 deletions libdevice/fallback-cstring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,83 @@
//===----------------------------------------------------------------------===//

#include "wrapper.h"
#include <cstdint>

#ifdef __SPIR__
DEVICE_EXTERN_C
void *__devicelib_memcpy(void *dest, const void *src, size_t n) {
return __builtin_memcpy(dest, src, n);
}

DEVICE_EXTERN_C
void *__devicelib_memset(void *dest, int c, size_t n) {
return __builtin_memset(dest, c, n);
}

static int __devicelib_memcmp_uint8_aligned(const void *s1, const void *s2,
size_t n) {
const uint8_t *s1_uint8_ptr = reinterpret_cast<const uint8_t *>(s1);
const uint8_t *s2_uint8_ptr = reinterpret_cast<const uint8_t *>(s2);
while (n > 0) {
if (*s1_uint8_ptr == *s2_uint8_ptr) {
s1_uint8_ptr++;
s2_uint8_ptr++;
n--;
} else {
return *s1_uint8_ptr - *s2_uint8_ptr;
}
}

return 0;
}

static int __devicelib_memcmp_uint32_aligned(const void *s1, const void *s2,
size_t n) {
const uint32_t *s1_uint32_ptr = reinterpret_cast<const uint32_t *>(s1);
const uint32_t *s2_uint32_ptr = reinterpret_cast<const uint32_t *>(s2);
while (n >= sizeof(uint32_t)) {
if (*s1_uint32_ptr == *s2_uint32_ptr) {
s1_uint32_ptr++;
s2_uint32_ptr++;
n -= sizeof(uint32_t);
} else {
n = sizeof(uint32_t);
break;
}
}

return (n == 0) ? 0
: __devicelib_memcmp_uint8_aligned(s1_uint32_ptr,
s2_uint32_ptr, n);
}

DEVICE_EXTERN_C
int __devicelib_memcmp(const void *s1, const void *s2, size_t n) {
if (s1 == s2 || n == 0)
return 0;

size_t s1_uint32_mod =
reinterpret_cast<unsigned long>(s1) % alignof(uint32_t);
size_t s2_uint32_mod =
reinterpret_cast<unsigned long>(s2) % alignof(uint32_t);

if (s1_uint32_mod != s2_uint32_mod)
return __devicelib_memcmp_uint8_aligned(s1, s2, n);

if (s1_uint32_mod == 0)
return __devicelib_memcmp_uint32_aligned(s1, s2, n);

size_t head_ua_len = sizeof(uint32_t) - s1_uint32_mod;
int head_cmp = __devicelib_memcmp_uint8_aligned(s1, s2, head_ua_len);
if (head_cmp == 0) {
const uint8_t *s1_aligned_ptr = reinterpret_cast<const uint8_t *>(s1);
const uint8_t *s2_aligned_ptr = reinterpret_cast<const uint8_t *>(s2);
s1_aligned_ptr += head_ua_len;
s2_aligned_ptr += head_ua_len;
return __devicelib_memcmp_uint32_aligned(s1_aligned_ptr, s2_aligned_ptr,
n - head_ua_len);
}

return head_cmp;
}
#endif // __SPIR__
4 changes: 4 additions & 0 deletions libdevice/wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
DEVICE_EXTERN_C
void *__devicelib_memcpy(void *dest, const void *src, size_t n);
DEVICE_EXTERN_C
void *__devicelib_memset(void *dest, int c, size_t n);
DEVICE_EXTERN_C
int __devicelib_memcmp(const void *s1, const void *s2, size_t n);
DEVICE_EXTERN_C
void __devicelib_assert_fail(const char *expr, const char *file, int32_t line,
const char *func, uint64_t gid0, uint64_t gid1,
uint64_t gid2, uint64_t lid0, uint64_t lid1,
Expand Down
2 changes: 2 additions & 0 deletions llvm/tools/sycl-post-link/SYCLDeviceLibReqMask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ SYCLDeviceLibFuncMap SDLMap = {
{"__devicelib_ctan", DeviceLibExt::cl_intel_devicelib_complex_fp64},
{"__devicelib_ctanh", DeviceLibExt::cl_intel_devicelib_complex_fp64},
{"__devicelib_memcpy", DeviceLibExt::cl_intel_devicelib_cstring},
{"__devicelib_memset", DeviceLibExt::cl_intel_devicelib_cstring},
{"__devicelib_memcmp", DeviceLibExt::cl_intel_devicelib_cstring},
};

// Each fallback device library corresponds to one bit in "require mask" which
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ List of supported functions from C standard library:
- casinf, casin (from <complex.h>)
- cacosf, cacos (from <complex.h>)
- catanf, catan (from <complex.h>)
- memcpy (from <string.h>)
- memset (from <string.h>)
- memcmp (from <string.h>)

All functions are grouped into different device libraries based on
functionalities. C and C++ standard library groups functions and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,19 @@ Those __devicelib_* functions have the same argument type and return type as cor
complex math functions from <complex.h>, please refer to ISO/IEC 14882:2011 for details. The
"double __complex__" type is C99 complex type and it is an alias to "struct {double, double}"
in LLVM IR and SPIR-V.

cl_intel_devicelib_cstring
==========================

.. code:
void *__devicelib_memcpy(void *dest, const void *src, size_t n);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this work for any combination of address spaces pointed to by dest and src? Might be worth adding a note. Std C library is not concerned with address spaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @kbobrovs
I think no matter what combination of address spaces pointed to by dest and src is, it should work if we can "read" from src and "write" to "dest". Is this correct?
Thanks very much.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. I would expect this to work with any combination. My point that such details should be added to the user API description.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it will only work for __generic address space pointers. Is there a way in DPC++ to specify __generic pointer explicitly?

Copy link
Contributor

@kbobrovs kbobrovs Aug 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default, function pointer arguments are generic. But users needs to understand if he/she can do e.g.

int arr[100]; // local variable in a function, resides in the private address space
...
auto *s1 = local_accessor.get_pointer();
auto *s2 = &arr[0];
__devicelib_memcpy(s1, s2, 100);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @kbobrovs and @vzakhari
__devicelib_memcpy is called by memcpy whose input pointer parameter is standard C/C++ pointer with address space.
So, if developer calls memcpy in SYCL device, the pointer is a generic_space pointer. And no matter where the input generic pointer points to, developers should ensure that they have access to the memory.
I also created a PR for memory function test: intel/llvm-test-suite#371 which includes some basic tests and alignment test, I will update it to add some tests covering different address space memory.
Thanks very much.

void *__devicelib_memset(void *dest, int c, size_t n);
int __devicelib_memcmp(const void *s1, const void *s2, size_t n);

Semantic:
Those __devicelib_* functions perform the same operation as the corresponding C string
library functions.

Arguments:
Those __devicelib_* functions have the same argument type and return type as corresponding
string functions from <string.h>, please refer to ISO/IEC 14882:2011 for details.
2 changes: 2 additions & 0 deletions sycl/include/CL/sycl/builtins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,8 @@ extern SYCL_EXTERNAL double ldexp(double x, int exp);
extern SYCL_EXTERNAL double hypot(double x, double y);

extern SYCL_EXTERNAL void *memcpy(void *dest, const void *src, size_t n);
extern SYCL_EXTERNAL void *memset(void *dest, int c, size_t n);
extern SYCL_EXTERNAL int memcmp(const void *s1, const void *s2, size_t n);
}
#ifdef __GLIBC__
extern "C" {
Expand Down