Files
TheRock/compiler/amd-llvm/amd/device-libs/opencl/src/misc/amdblit.cl
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

904 lines
25 KiB
Common Lisp

/*===--------------------------------------------------------------------------
* ROCm Device Libraries
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
*===------------------------------------------------------------------------*/
#if !defined NO_BLIT
#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable
typedef enum BatchMemOpType {
STREAM_WAIT_VALUE_32 = 0x1,
STREAM_WRITE_VALUE_32 = 0x2,
STREAM_WAIT_VALUE_64 = 0x4,
STREAM_WRITE_VALUE_64 = 0x5,
STREAM_MEM_OP_BARRIER = 0x6, // Currently not supported
STREAM_MEM_OP_FLUSH_REMOTE_WRITES = 0x3 // Currently not supported
} BatchMemOpType;
typedef union streamBatchMemOpParams_union {
BatchMemOpType operation;
struct streamMemOpWaitValueParams_t{
BatchMemOpType operation;
atomic_ulong* address;
union {
uint value;
ulong value64;
};
uint flags;
atomic_ulong* alias; // Not valid for AMD backend
} waitValue;
struct streamMemOpWriteValueParams_t{
BatchMemOpType operation;
atomic_ulong* address;
union {
uint value;
ulong value64;
};
uint flags;
atomic_ulong* alias; // Not valid for AMD backend
} writeValue;
struct streamMemOpFlushRemoteWritesParams_t{ // Currently not supported
BatchMemOpType operation;
uint flags;
} flushRemoteWrites;
struct streamMemOpMemoryBarrierParams_t{ // Currently not supported
BatchMemOpType operation;
uint flags;
} memoryBarrier;
ulong pad[6];
} BatchMemOpParams;
static const uint SplitCount = 3;
__attribute__((always_inline)) void
__amd_copyBufferToImage(
__global uint *src,
__write_only image2d_array_t dst,
ulong4 srcOrigin,
int4 dstOrigin,
int4 size,
uint4 format,
ulong4 pitch)
{
ulong idxSrc;
int4 coordsDst;
uint4 pixel;
__global uint* srcUInt = src;
__global ushort* srcUShort = (__global ushort*)src;
__global uchar* srcUChar = (__global uchar*)src;
ushort tmpUShort;
uint tmpUInt;
coordsDst.x = get_global_id(0);
coordsDst.y = get_global_id(1);
coordsDst.z = get_global_id(2);
coordsDst.w = 0;
if ((coordsDst.x >= size.x) ||
(coordsDst.y >= size.y) ||
(coordsDst.z >= size.z)) {
return;
}
idxSrc = (coordsDst.z * pitch.y +
coordsDst.y * pitch.x + coordsDst.x) *
format.z + srcOrigin.x;
coordsDst.x += dstOrigin.x;
coordsDst.y += dstOrigin.y;
coordsDst.z += dstOrigin.z;
// Check components
switch (format.x) {
case 1:
// Check size
if (format.y == 1) {
pixel.x = (uint)srcUChar[idxSrc];
}
else if (format.y == 2) {
pixel.x = (uint)srcUShort[idxSrc];
}
else {
pixel.x = srcUInt[idxSrc];
}
break;
case 2:
// Check size
if (format.y == 1) {
tmpUShort = srcUShort[idxSrc];
pixel.x = (uint)(tmpUShort & 0xff);
pixel.y = (uint)(tmpUShort >> 8);
}
else if (format.y == 2) {
tmpUInt = srcUInt[idxSrc];
pixel.x = (tmpUInt & 0xffff);
pixel.y = (tmpUInt >> 16);
}
else {
pixel.x = srcUInt[idxSrc++];
pixel.y = srcUInt[idxSrc];
}
break;
case 4:
// Check size
if (format.y == 1) {
tmpUInt = srcUInt[idxSrc];
pixel.x = tmpUInt & 0xff;
pixel.y = (tmpUInt >> 8) & 0xff;
pixel.z = (tmpUInt >> 16) & 0xff;
pixel.w = (tmpUInt >> 24) & 0xff;
}
else if (format.y == 2) {
tmpUInt = srcUInt[idxSrc++];
pixel.x = tmpUInt & 0xffff;
pixel.y = (tmpUInt >> 16);
tmpUInt = srcUInt[idxSrc];
pixel.z = tmpUInt & 0xffff;
pixel.w = (tmpUInt >> 16);
}
else {
pixel.x = srcUInt[idxSrc++];
pixel.y = srcUInt[idxSrc++];
pixel.z = srcUInt[idxSrc++];
pixel.w = srcUInt[idxSrc];
}
break;
}
// Write the final pixel
write_imageui(dst, coordsDst, pixel);
}
__attribute__((always_inline)) void
__amd_copyImageToBuffer(
__read_only image2d_array_t src,
__global uint* dstUInt,
__global ushort* dstUShort,
__global uchar* dstUChar,
int4 srcOrigin,
ulong4 dstOrigin,
int4 size,
uint4 format,
ulong4 pitch)
{
ulong idxDst;
int4 coordsSrc;
uint4 texel;
coordsSrc.x = get_global_id(0);
coordsSrc.y = get_global_id(1);
coordsSrc.z = get_global_id(2);
coordsSrc.w = 0;
if ((coordsSrc.x >= size.x) ||
(coordsSrc.y >= size.y) ||
(coordsSrc.z >= size.z)) {
return;
}
idxDst = (coordsSrc.z * pitch.y + coordsSrc.y * pitch.x +
coordsSrc.x) * format.z + dstOrigin.x;
coordsSrc.x += srcOrigin.x;
coordsSrc.y += srcOrigin.y;
coordsSrc.z += srcOrigin.z;
texel = read_imageui(src, coordsSrc);
// Check components
switch (format.x) {
case 1:
// Check size
switch (format.y) {
case 1:
dstUChar[idxDst] = (uchar)texel.x;
break;
case 2:
dstUShort[idxDst] = (ushort)texel.x;
break;
case 4:
dstUInt[idxDst] = texel.x;
break;
}
break;
case 2:
// Check size
switch (format.y) {
case 1:
dstUShort[idxDst] = (ushort)texel.x |
((ushort)texel.y << 8);
break;
case 2:
dstUInt[idxDst] = texel.x | (texel.y << 16);
break;
case 4:
dstUInt[idxDst++] = texel.x;
dstUInt[idxDst] = texel.y;
break;
}
break;
case 4:
// Check size
switch (format.y) {
case 1:
dstUInt[idxDst] = (uint)texel.x |
(texel.y << 8) |
(texel.z << 16) |
(texel.w << 24);
break;
case 2:
dstUInt[idxDst++] = texel.x | (texel.y << 16);
dstUInt[idxDst] = texel.z | (texel.w << 16);
break;
case 4:
dstUInt[idxDst++] = texel.x;
dstUInt[idxDst++] = texel.y;
dstUInt[idxDst++] = texel.z;
dstUInt[idxDst] = texel.w;
break;
}
break;
}
}
__attribute__((always_inline)) void
__amd_copyImage(
__read_only image2d_array_t src,
__write_only image2d_array_t dst,
int4 srcOrigin,
int4 dstOrigin,
int4 size)
{
int4 coordsDst;
int4 coordsSrc;
coordsDst.x = get_global_id(0);
coordsDst.y = get_global_id(1);
coordsDst.z = get_global_id(2);
coordsDst.w = 0;
if ((coordsDst.x >= size.x) ||
(coordsDst.y >= size.y) ||
(coordsDst.z >= size.z)) {
return;
}
coordsSrc = srcOrigin + coordsDst;
coordsDst += dstOrigin;
uint4 texel;
texel = read_imageui(src, coordsSrc);
write_imageui(dst, coordsDst, texel);
}
__attribute__((always_inline)) void
__amd_copyImage1DA(
__read_only image2d_array_t src,
__write_only image2d_array_t dst,
int4 srcOrigin,
int4 dstOrigin,
int4 size)
{
int4 coordsDst;
int4 coordsSrc;
coordsDst.x = get_global_id(0);
coordsDst.y = get_global_id(1);
coordsDst.z = get_global_id(2);
coordsDst.w = 0;
if ((coordsDst.x >= size.x) ||
(coordsDst.y >= size.y) ||
(coordsDst.z >= size.z)) {
return;
}
coordsSrc = srcOrigin + coordsDst;
coordsDst += dstOrigin;
if (srcOrigin.w != 0) {
coordsSrc.z = coordsSrc.y;
coordsSrc.y = 0;
}
if (dstOrigin.w != 0) {
coordsDst.z = coordsDst.y;
coordsDst.y = 0;
}
uint4 texel;
texel = read_imageui(src, coordsSrc);
write_imageui(dst, coordsDst, texel);
}
__attribute__((always_inline)) void
__amd_copyBufferRect(
__global uchar* src,
__global uchar* dst,
ulong4 srcRect,
ulong4 dstRect,
ulong4 size)
{
ulong x = get_global_id(0);
ulong y = get_global_id(1);
ulong z = get_global_id(2);
if ((x >= size.x) ||
(y >= size.y) ||
(z >= size.z)) {
return;
}
ulong offsSrc = srcRect.z + x + y * srcRect.x + z * srcRect.y;
ulong offsDst = dstRect.z + x + y * dstRect.x + z * dstRect.y;
dst[offsDst] = src[offsSrc];
}
__attribute__((always_inline)) void
__amd_copyBufferRectAligned(
__global uint* src,
__global uint* dst,
ulong4 srcRect,
ulong4 dstRect,
ulong4 size)
{
ulong x = get_global_id(0);
ulong y = get_global_id(1);
ulong z = get_global_id(2);
if ((x >= size.x) ||
(y >= size.y) ||
(z >= size.z)) {
return;
}
ulong offsSrc = srcRect.z + x + y * srcRect.x + z * srcRect.y;
ulong offsDst = dstRect.z + x + y * dstRect.x + z * dstRect.y;
if (size.w == 16) {
__global uint4* src4 = (__global uint4*)src;
__global uint4* dst4 = (__global uint4*)dst;
dst4[offsDst] = src4[offsSrc];
}
else {
dst[offsDst] = src[offsSrc];
}
}
__attribute__((always_inline)) void
__amd_copyBuffer(
__global uchar* srcI,
__global uchar* dstI,
ulong srcOrigin,
ulong dstOrigin,
ulong size,
uint remain)
{
ulong id = get_global_id(0);
if (id >= size) {
return;
}
__global uchar* src = srcI + srcOrigin;
__global uchar* dst = dstI + dstOrigin;
if (remain == 8) {
dst[id] = src[id];
}
else {
if (id < (size - 1)) {
__global uint* srcD = (__global uint*)(src);
__global uint* dstD = (__global uint*)(dst);
dstD[id] = srcD[id];
}
else {
for (uint i = 0; i < remain; ++i) {
dst[id * 4 + i] = src[id * 4 + i];
}
}
}
}
__attribute__((always_inline)) void
__amd_copyBufferAligned(
__global uint* src,
__global uint* dst,
ulong srcOrigin,
ulong dstOrigin,
ulong size,
uint alignment)
{
ulong id = get_global_id(0);
if (id >= size) {
return;
}
ulong offsSrc = id + srcOrigin;
ulong offsDst = id + dstOrigin;
if (alignment == 16) {
__global uint4* src4 = (__global uint4*)src;
__global uint4* dst4 = (__global uint4*)dst;
dst4[offsDst] = src4[offsSrc];
}
else {
dst[offsDst] = src[offsSrc];
}
}
__attribute__((always_inline)) void
__amd_copyBufferExt(
__global uchar* srcI,
__global uchar* dstI,
ulong srcOrigin,
ulong dstOrigin,
ulong size,
uint remainder,
uint aligned_size,
ulong end_ptr,
uint next_chunk) {
ulong id = get_global_id(0);
ulong id_remainder = id;
__global uchar* src = srcI + srcOrigin;
__global uchar* dst = dstI + dstOrigin;
if (aligned_size == sizeof(ulong2)) {
__global ulong2* srcD = (__global ulong2*)(src);
__global ulong2* dstD = (__global ulong2*)(dst);
while ((ulong)(&dstD[id]) < end_ptr) {
dstD[id] = srcD[id];
id += next_chunk;
}
} else {
__global uint* srcD = (__global uint*)(src);
__global uint* dstD = (__global uint*)(dst);
while ((ulong)(&dstD[id]) < end_ptr) {
dstD[id] = srcD[id];
id += next_chunk;
}
}
if ((remainder != 0) && (id_remainder == 0)) {
for (ulong i = size - remainder; i < size; ++i) {
dst[i] = src[i];
}
}
}
__attribute__((always_inline)) void __amd_fillBufferUnAligned(__global void* __restrict buf,
__constant uchar* __restrict pattern,
int body_pattern, ulong2 body_tile_pattern,
ulong body_tile_count, ulong body_tile_passes,
ulong stride, ulong pattern_size,
ulong tail_offset, __global uchar* __restrict body_ptr,
__global uchar* __restrict body_tail_ptr,
__global uchar* __restrict tail_ptr,
__global ulong2* __restrict element_tiled,
ushort4 counts, int isAligned) {
ulong id = get_global_id(0);
// Handle head, body and tail in the first warp only.
// count values are each <= 4, so all unaligned work fits in 32 lanes.
// Skip when buffer is 16-byte aligned (no head/body/body_tail/tail regions).
if (!isAligned && id < 32) {
__global uchar* head_ptr = (__global uchar*)buf;
const uint lane = (uint)id;
const uint head_end = (uint)counts.s0;
const uint body_end = head_end + (uint)counts.s1;
const uint body_tail_end = body_end + (uint)counts.s2;
const uint tail_end = body_tail_end + (uint)counts.s3;
if (lane < head_end) {
head_ptr[lane] = pattern[lane & (pattern_size - 1)];
} else if (lane < body_end) {
((__global int*)body_ptr)[lane - head_end] = body_pattern;
} else if (lane < body_tail_end) {
((__global int*)body_tail_ptr)[lane - body_end] = body_pattern;
} else if (lane < tail_end) {
const ulong tail_byte_idx = (ulong)(lane - body_tail_end);
tail_ptr[tail_byte_idx] =
pattern[(tail_offset + tail_byte_idx) & (pattern_size - 1)];
}
}
// We pass in the number of passes from the CPU to get the best code-gen
// We use the number of passes and the size to get correct behiaviour
for (ulong j = 0; (j < body_tile_passes) && (j * stride + id < body_tile_count); ++j) {
element_tiled[j * stride + id] = body_tile_pattern;
}
}
__attribute__((always_inline)) void
__amd_fillBuffer(
__global uchar* bufUChar,
__global uint* bufUInt,
__constant uchar* pattern,
uint patternSize,
ulong offset,
ulong size)
{
ulong id = get_global_id(0);
if (id >= size) {
return;
}
if (bufUInt) {
__global uint* element = &bufUInt[offset + id * patternSize];
__constant uint* pt = (__constant uint*)pattern;
for (uint i = 0; i < patternSize; ++i) {
element[i] = pt[i];
}
}
else {
__global uchar* element = &bufUChar[offset + id * patternSize];
for (uint i = 0; i < patternSize; ++i) {
element[i] = pattern[i];
}
}
}
__attribute__((always_inline)) void
__amd_fillBufferAligned(
__global uchar* bufUChar,
__global ushort* bufUShort,
__global uint* bufUInt,
__global ulong* bufULong,
__constant uchar* pattern,
uint patternSize,
ulong offset,
ulong size)
{
ulong id = get_global_id(0);
if (id >= size) {
return;
}
if (bufULong) {
__global ulong* element = &bufULong[offset + id * patternSize];
__constant ulong* pt = (__constant ulong*)pattern;
for (uint i = 0; i < patternSize; ++i) {
element[i] = pt[i];
}
}
else if (bufUInt) {
__global uint* element = &bufUInt[offset + id * patternSize];
__constant uint* pt = (__constant uint*)pattern;
for (uint i = 0; i < patternSize; ++i) {
element[i] = pt[i];
}
}
else if (bufUShort) {
__global ushort* element = &bufUShort[offset + id * patternSize];
__constant ushort* pt = (__constant ushort*)pattern;
for (uint i = 0; i < patternSize; ++i) {
element[i] = pt[i];
}
}
else {
__global uchar* element = &bufUChar[offset + id * patternSize];
for (uint i = 0; i < patternSize; ++i) {
element[i] = pattern[i];
}
}
}
__attribute__((always_inline)) void
__amd_fillBufferAlignedExt(
__global uchar* bufUChar,
__global ushort* bufUShort,
__global uint* bufUInt,
__global ulong* bufULong,
__global ulong2* bufULong2,
__constant uchar* pattern,
uint pattern_size,
ulong offset,
ulong end_ptr,
uint next_chunk)
{
int id = get_global_id(0);
long cur_id = offset + id * pattern_size;
if (bufULong2) {
__global ulong2* element = &bufULong2[cur_id];
__constant ulong2* pt = (__constant ulong2*)pattern;
while ((ulong)element < end_ptr) {
for (uint i = 0; i < pattern_size; ++i) {
element[i] = pt[i];
}
element += next_chunk;
}
} else if (bufULong) {
__global ulong* element = &bufULong[cur_id];
__constant ulong* pt = (__constant ulong*)pattern;
while ((ulong)element < end_ptr) {
for (uint i = 0; i < pattern_size; ++i) {
element[i] = pt[i];
}
element += next_chunk;
}
} else if (bufUInt) {
__global uint* element = &bufUInt[cur_id];
__constant uint* pt = (__constant uint*)pattern;
while ((ulong)element < end_ptr) {
for (uint i = 0; i < pattern_size; ++i) {
element[i] = pt[i];
}
element += next_chunk;
}
} else if (bufUShort) {
__global ushort* element = &bufUShort[cur_id];
__constant ushort* pt = (__constant ushort*)pattern;
while ((ulong)element < end_ptr) {
for (uint i = 0; i < pattern_size; ++i) {
element[i] = pt[i];
}
element += next_chunk;
}
} else {
__global uchar* element = &bufUChar[cur_id];
while ((ulong)element < end_ptr) {
for (uint i = 0; i < pattern_size; ++i) {
element[i] = pattern[i];
}
element += next_chunk;
}
}
}
__attribute__((always_inline)) void
__amd_fillBufferAligned2D(__global uchar* bufUChar,
__global ushort* bufUShort,
__global uint* bufUInt,
__global ulong* bufULong,
__constant uchar* pattern,
uint patternSize,
ulong origin,
ulong width,
ulong height,
ulong pitch)
{
ulong tid_x = get_global_id(0);
ulong tid_y = get_global_id(1);
if (tid_x >= width || tid_y >= height) {
return;
}
ulong offset = (tid_y * pitch + tid_x);
if (bufULong) {
__global ulong* element = &bufULong[origin + offset];
__constant ulong* pt = (__constant ulong*)pattern;
for (uint i = 0; i < patternSize; ++i) {
element[i] = pt[i];
}
} else if (bufUInt) {
__global uint* element = &bufUInt[origin + offset];
__constant uint* pt = (__constant uint*)pattern;
for (uint i = 0; i < patternSize; ++i) {
element[i] = pt[i];
}
} else if (bufUShort) {
__global ushort* element = &bufUShort[origin + offset];
__constant ushort* pt = (__constant ushort*)pattern;
for (uint i = 0; i < patternSize; ++i) {
element[i] = pt[i];
}
} else if (bufUChar) {
__global uchar* element = &bufUChar[origin + offset];
__constant uchar* pt = (__constant uchar*)pattern;
for (uint i = 0; i < patternSize; ++i) {
element[i] = pt[i];
}
}
}
__attribute__((always_inline)) void
__amd_fillImage(
__write_only image2d_array_t image,
float4 patternFLOAT4,
int4 patternINT4,
uint4 patternUINT4,
int4 origin,
int4 size,
uint type)
{
int4 coords;
coords.x = get_global_id(0);
coords.y = get_global_id(1);
coords.z = get_global_id(2);
coords.w = 0;
if ((coords.x >= size.x) ||
(coords.y >= size.y) ||
(coords.z >= size.z)) {
return;
}
coords += origin;
int SizeX = get_global_size(0);
int AdjustedSizeX = size.x + origin.x;
for (uint i = 0; i < SplitCount; ++i) {
// Check components
switch (type) {
case 0:
write_imagef(image, coords, patternFLOAT4);
break;
case 1:
write_imagei(image, coords, patternINT4);
break;
case 2:
write_imageui(image, coords, patternUINT4);
break;
}
coords.x += SizeX;
if (coords.x >= AdjustedSizeX) return;
}
}
__attribute__((always_inline)) void
__amd_streamOpsWrite(
__global atomic_uint* ptrUint,
__global atomic_ulong* ptrUlong,
ulong value) {
// The launch parameters for this shader is a 1 grid work-item
// 32-bit write
if (ptrUint) {
atomic_store_explicit(ptrUint, (uint)value, memory_order_relaxed, memory_scope_all_svm_devices);
}
// 64-bit write
else {
atomic_store_explicit(ptrUlong, value, memory_order_relaxed, memory_scope_all_svm_devices);
}
}
__attribute__((always_inline)) void
__amd_streamOpsIncrement(
__global atomic_uint* ptrUint,
__global atomic_ulong* ptrUlong,
ulong value) {
if (ptrUint) {
atomic_fetch_add_explicit (ptrUint, value, memory_order_relaxed, memory_scope_all_svm_devices);
} else {
atomic_fetch_add_explicit (ptrUlong, value, memory_order_relaxed, memory_scope_all_svm_devices);
}
}
__attribute__((always_inline)) void
__amd_streamOpsDecrement(
__global atomic_uint* ptrUint,
__global atomic_ulong* ptrUlong,
ulong value) {
__attribute__((atomic(remote_memory, fine_grained_memory)))
{
if (ptrUint) {
__scoped_atomic_fetch_sub((volatile uint*)ptrUint, (uint)value, memory_order_relaxed, __MEMORY_SCOPE_SYSTEM);
} else {
__scoped_atomic_fetch_sub((volatile ulong*)ptrUlong, value, memory_order_relaxed, __MEMORY_SCOPE_SYSTEM);
}
}
}
__attribute__((always_inline)) void
__amd_streamOpsWait(
__global atomic_uint* ptrUint,
__global atomic_ulong* ptrUlong,
ulong value, ulong compareOp, ulong mask) {
// The launch parameters for this shader is a 1 grid work-item
switch (compareOp) {
case 0: //GEQ
if (ptrUint) {
while ((int)(atomic_load_explicit(ptrUint, memory_order_relaxed,
memory_scope_all_svm_devices) & (uint)mask) < (uint)value) {
__builtin_amdgcn_s_sleep(1);
}
}
else {
while ((long)(atomic_load_explicit(ptrUlong, memory_order_relaxed,
memory_scope_all_svm_devices) & mask) < value) {
__builtin_amdgcn_s_sleep(1);
}
}
break;
case 1: // EQ
if (ptrUint) {
while ((atomic_load_explicit(ptrUint, memory_order_relaxed,
memory_scope_all_svm_devices) & (uint)mask) != (uint)value) {
__builtin_amdgcn_s_sleep(1);
}
}
else {
while ((atomic_load_explicit(ptrUlong, memory_order_relaxed,
memory_scope_all_svm_devices) & mask) != value) {
__builtin_amdgcn_s_sleep(1);
}
}
break;
case 2: //AND
if (ptrUint) {
while (!((atomic_load_explicit(ptrUint, memory_order_relaxed,
memory_scope_all_svm_devices) & (uint)mask) & (uint)value)) {
__builtin_amdgcn_s_sleep(1);
}
}
else {
while (!((atomic_load_explicit(ptrUlong, memory_order_relaxed,
memory_scope_all_svm_devices) & mask) & value)) {
__builtin_amdgcn_s_sleep(1);
}
}
break;
case 3: //NOR
if (ptrUint) {
while (((atomic_load_explicit(ptrUint, memory_order_relaxed,
memory_scope_all_svm_devices) | (uint)value) & (uint)mask) == (uint)mask) {
__builtin_amdgcn_s_sleep(1);
}
}
else {
while (((atomic_load_explicit(ptrUlong, memory_order_relaxed,
memory_scope_all_svm_devices) | value) & mask) == mask) {
__builtin_amdgcn_s_sleep(1);
}
}
break;
}
}
// The kernel calling this function must be launched with 'count' workgroups each of size 1
__attribute__((always_inline)) void
__amd_batchMemOp(__global BatchMemOpParams* param,
uint count) {
ulong id = get_global_id(0);
switch (param[id].operation) {
case STREAM_WAIT_VALUE_32:
__amd_streamOpsWait((__global atomic_uint*)param[id].waitValue.address, NULL,
(uint)param[id].waitValue.value, (uint)param[id].waitValue.flags,
(ulong)~0UL);
break;
case STREAM_WRITE_VALUE_32:
__amd_streamOpsWrite((__global atomic_uint*)param[id].writeValue.address, NULL,
(uint)param[id].writeValue.value);
break;
case STREAM_WAIT_VALUE_64:
__amd_streamOpsWait(NULL, (__global atomic_ulong*)param[id].waitValue.address,
(ulong)param[id].waitValue.value64, (uint)param[id].waitValue.flags,
(ulong)~0UL);
break;
case STREAM_WRITE_VALUE_64:
__amd_streamOpsWrite(NULL, (__global atomic_ulong*)param[id].writeValue.address,
(ulong)param[id].writeValue.value64);
break;
default:
break;
}
}
#endif