Skip to content

Commit 55f8d22

Browse files
committed
devicelib: keep <cstring> in device pass; resolve std::mem* via using-decls
The new-hip-tests / HIP7 work needs device-side memset/memcpy plus host string functions to coexist with libstdc++ <cstring> in single-source HIP. Two problems had to be solved together: 1. Host build break. <cstring> does 'using ::memset/::memcpy', so *defining* std::memset/std::memcpy (as the earlier approach did) collides with it: 'target of using declaration conflicts with declaration already in scope'. That broke host compilation on every lane (pocl, macOS, salami, rusticl), and on macOS surfaced as 'call to memcpy is ambiguous' in hip_fp16_gcc.h. Fix: instead of redefining them, declare the __device__ memset/memcpy overloads at global scope and surface them into std:: with using-decls. A duplicate 'using ::memset/::memcpy' is harmless and, placed after the __device__ overloads, makes std::memcpy/std::memset resolve to the device (__chip_*) versions in device code. 2. Library device pass. Library headers (e.g. rocPRIM) reference strcmp/ memset/memcpy in __host__ functions (device-property setup), whose bodies are still parsed during the device pass. Guarding <cstring> out of device compilation (a previous attempt to keep the SPIR-V module small) left those identifiers undeclared and broke the device pass -- hipCUB/rocPRIM/rocRAND failed to build on the x86 Intel GPU libraries lane. Fix: include <cstring> unconditionally. It contributes only declarations, not definitions, so it does not enlarge the module; the using-decls above keep device mem* calls pointing at __chip_*. The DG2 IGC kernel-drop that motivated the device-pass <cstring> guard is tracked/handled separately (PR #1297) and is not reintroduced by this change.
1 parent 27f407c commit 55f8d22

1 file changed

Lines changed: 22 additions & 16 deletions

File tree

include/hip/devicelib/sync_and_util.hh

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@
2929

3030
#include <cstddef>
3131
#include <cstdint>
32-
// This header declares device-side overloads of memset()/memcpy() at global
33-
// scope (below). Without the host <cstring> declarations also in scope, host
34-
// code that calls memset/memcpy/strcmp/etc. (e.g. rocPRIM device headers
35-
// compiled for the host) sees only the __device__ overload and fails with
36-
// "call to __device__ function from __host__ function" or "use of undeclared
37-
// identifier 'strcmp'". Include <cstring> so the host overloads are always
38-
// visible; HIP host/device overloading keeps the two sets distinct.
32+
// Include <cstring> unconditionally. Library headers (e.g. rocPRIM) reference
33+
// strcmp/memset/memcpy/etc. in __host__ functions (e.g. device-property setup),
34+
// and in single-source HIP those bodies are still parsed during the device
35+
// pass -- so the host declarations must be visible in BOTH passes. Guarding
36+
// <cstring> out of device compilation leaves those identifiers undeclared and
37+
// breaks the device pass. This only brings in declarations, not definitions, so
38+
// it does not enlarge the SPIR-V module; the __device__ memset/memcpy overloads
39+
// declared below (surfaced into std:: via using-declarations) ensure device
40+
// callers still resolve to the __chip_* implementations rather than the host
41+
// ones.
3942
#include <cstring>
4043

4144
__device__ constexpr int warpSize = CHIP_DEFAULT_WARP_SIZE;
@@ -148,16 +151,19 @@ extern "C++" inline __device__ void *memcpy(void *dest, const void *src, size_t
148151
return __chip_memcpy(dest, src, n);
149152
}
150153

151-
// Expose device-side memset/memcpy in std:: namespace so that std::memset /
152-
// std::memcpy in device kernels (e.g. rocPRIM) resolve to the __device__
153-
// overloads rather than the __host__ ones injected by <cstring> above.
154+
// Expose the device-side memset/memcpy overloads (declared at global scope
155+
// above) in std:: so that std::memset / std::memcpy in device kernels (e.g.
156+
// rocPRIM) resolve to the __device__ overloads. We use using-declarations
157+
// rather than redefining std::memset/std::memcpy: <cstring> (pulled in
158+
// unconditionally by other host headers such as spdlog, in both host and
159+
// device passes) already does `using ::memset/::memcpy`, and a *second*
160+
// definition of std::memset/std::memcpy collides with it ("target of using
161+
// declaration conflicts with declaration already in scope"). A duplicate
162+
// using-declaration of the same ::memset/::memcpy is harmless, and because it
163+
// appears after the __device__ overloads above it also pulls those into std.
154164
namespace std {
155-
inline __device__ void *memset(void *ptr, int value, size_t size) {
156-
return __chip_memset(ptr, value, size);
157-
}
158-
inline __device__ void *memcpy(void *dest, const void *src, size_t n) {
159-
return __chip_memcpy(dest, src, n);
160-
}
165+
using ::memcpy;
166+
using ::memset;
161167
}
162168

163169
extern "C++" inline __device__ unsigned __activemask()

0 commit comments

Comments
 (0)