#ifndef GPU_INTEL_INCLUDE_TILE_OPS_H
#define GPU_INTEL_INCLUDE_TILE_OPS_H
#include "gpu/intel/include/generic_vector_ops.h"
#include "gpu/intel/include/types.h"
float __builtin_IB_atomic_max_local_f32(__local float *, float);
float __builtin_IB_atomic_add_local_f32(__local float *, float);
float __builtin_IB_atomic_add_global_f32(__global float *, float);
half __builtin_IB_atomic_add_global_f16(__global half *, half);
__attribute__((overloadable)) float local_atomic_max(local float *p, float v) {
return __builtin_IB_atomic_max_local_f32(p, v);
}
__attribute__((overloadable)) half local_atomic_max(local half *p, half v);
__attribute__((overloadable)) ushort local_atomic_max(
local ushort *p, ushort v);
__attribute__((overloadable)) uint local_atomic_max(local uint *p, uint v) {
return atomic_max(p, v);
}
__attribute__((overloadable)) int local_atomic_max(local int *p, int v) {
return atomic_max(p, v);
}
__attribute__((overloadable)) float local_atomic_add(local float *p, float v) {
return __builtin_IB_atomic_add_local_f32(p, v);
}
__attribute__((overloadable)) half local_atomic_add(local half *p, half v);
__attribute__((overloadable)) ushort local_atomic_add(
local ushort *p, ushort v);
__attribute__((overloadable)) uint local_atomic_add(local uint *p, uint v) {
return atomic_add(p, v);
}
__attribute__((overloadable)) int local_atomic_add(local int *p, int v) {
return atomic_add(p, v);
}
__attribute__((overloadable)) float global_atomic_add(
global float *p, float v) {
return __builtin_IB_atomic_add_global_f32(p, v);
}
__attribute__((overloadable)) half global_atomic_add(global half *p, half v) {
return __builtin_IB_atomic_add_global_f16(p, v);
}
__attribute__((overloadable)) ushort global_atomic_add(
global ushort *p, ushort v);
__attribute__((overloadable)) uint global_atomic_add(global uint *p, uint v) {
return atomic_add(p, v);
}
__attribute__((overloadable)) int global_atomic_add(global int *p, int v) {
return atomic_add(p, v);
}
#define DEF_BLOCK_LOAD_STORE(type, itype, suffix, n) \
__attribute__((overloadable)) type##n block_load( \
const global type *p, int vlen) \
__attribute__((enable_if(vlen == n, "wrong vector length"))) { \
return as_##type##n( \
intel_sub_group_block_read##suffix##n((global void *)p)); \
} \
__attribute__((overloadable)) void block_store( \
global type *p, type##n v) { \
intel_sub_group_block_write##suffix##n( \
(global itype *)p, as_##itype##n(v)); \
} \
__attribute__((overloadable)) void block_store(local type *p, type##n v) { \
intel_sub_group_block_write##suffix##n( \
(local itype *)p, as_##itype##n(v)); \
}
#define DEF_BLOCK_LOAD_STORE1(type, itype, suffix) \
__attribute__((overloadable)) type##1 block_load( \
const global type *p, int vlen) \
__attribute__((enable_if(vlen == 1, "wrong vector length"))) { \
type##1 x; \
x[0] = as_##type( \
intel_sub_group_block_read##suffix((global void *)p)); \
return x; \
} \
__attribute__((overloadable)) void block_store( \
global type *p, type##1 v) { \
intel_sub_group_block_write##suffix( \
(global itype *)p, as_##itype(v[0])); \
} \
__attribute__((overloadable)) void block_store(local type *p, type##1 v) { \
int id = get_sub_group_local_id(); \
((local itype *)p)[id] = as_##itype(v[0]); \
}
#define DEF_BLOCK_LOAD_STORE16(type, itype, suffix) \
__attribute__((overloadable)) type##16 block_load( \
const global type *p, int vlen) \
__attribute__((enable_if(vlen == 16, "wrong vector length"))) { \
type##16 x; \
x.s01234567 = as_##type##8( \
intel_sub_group_block_read##suffix##8((global void *)p)); \
x.s89abcdef = as_##type##8(intel_sub_group_block_read##suffix##8( \
(global void *)(p + 8 * get_sub_group_size()))); \
return x; \
} \
__attribute__((overloadable)) void block_store( \
global type *p, type##16 v) { \
intel_sub_group_block_write##suffix##8( \
(global itype *)p, as_##itype##8(v.s01234567)); \
intel_sub_group_block_write##suffix##8( \
(global itype *)(p + 8 * get_sub_group_size()), \
as_##itype##8(v.s89abcdef)); \
} \
__attribute__((overloadable)) void block_store( \
local type *p, type##16 v) { \
intel_sub_group_block_write##suffix##8( \
(local itype *)p, as_##itype##8(v.s01234567)); \
intel_sub_group_block_write##suffix##8( \
(local itype *)(p + 8 * get_sub_group_size()), \
as_##itype##8(v.s89abcdef)); \
}
#define DEF_BLOCK_LOAD_STORE32(type, itype, suffix) \
__attribute__((overloadable)) type##32 block_load( \
const global type *p, int vlen) \
__attribute__((enable_if(vlen == 32, "wrong vector length"))) { \
type##32 x; \
x = (type##32)(as_##type##8(intel_sub_group_block_read##suffix##8( \
(global void *)p)), \
as_##type##8(intel_sub_group_block_read##suffix##8( \
(global void *)(p + 8 * get_sub_group_size()))), \
as_##type##8(intel_sub_group_block_read##suffix##8( \
(global void *)(p + 16 * get_sub_group_size()))), \
as_##type##8(intel_sub_group_block_read##suffix##8( \
(global void *)(p + 24 * get_sub_group_size())))); \
return x; \
} \
__attribute__((overloadable)) void block_store( \
global type *p, type##32 v) { \
intel_sub_group_block_write##suffix##8((global itype *)p, \
(itype##8)(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7])); \
intel_sub_group_block_write##suffix##8( \
(global itype *)(p + 8 * get_sub_group_size()), \
(itype##8)(v[8], v[9], v[10], v[11], v[12], v[13], v[14], \
v[15])); \
intel_sub_group_block_write##suffix##8( \
(global itype *)(p + 16 * get_sub_group_size()), \
(itype##8)(v[16], v[17], v[18], v[19], v[20], v[21], v[22], \
v[23])); \
intel_sub_group_block_write##suffix##8( \
(global itype *)(p + 24 * get_sub_group_size()), \
(itype##8)(v[24], v[25], v[26], v[27], v[28], v[29], v[30], \
v[31])); \
} \
__attribute__((overloadable)) void block_store( \
local type *p, type##32 v) { \
intel_sub_group_block_write##suffix##8((local itype *)p, \
(itype##8)(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7])); \
intel_sub_group_block_write##suffix##8( \
(local itype *)(p + 8 * get_sub_group_size()), \
(itype##8)(v[8], v[9], v[10], v[11], v[12], v[13], v[14], \
v[15])); \
intel_sub_group_block_write##suffix##8( \
(local itype *)(p + 16 * get_sub_group_size()), \
(itype##8)(v[16], v[17], v[18], v[19], v[20], v[21], v[22], \
v[23])); \
intel_sub_group_block_write##suffix##8( \
(local itype *)(p + 24 * get_sub_group_size()), \
(itype##8)(v[24], v[25], v[26], v[27], v[28], v[29], v[30], \
v[31])); \
}
DEF_BLOCK_LOAD_STORE1(half, ushort, _us)
DEF_BLOCK_LOAD_STORE(half, ushort, _us, 2)
DEF_BLOCK_LOAD_STORE(half, ushort, _us, 4)
DEF_BLOCK_LOAD_STORE(half, ushort, _us, 8)
DEF_BLOCK_LOAD_STORE16(half, ushort, _us)
typedef ushort ushort32 __attribute__((ext_vector_type(32)));
typedef half half32 __attribute__((ext_vector_type(32)));
DEF_BLOCK_LOAD_STORE32(half, ushort, _us)
typedef ushort ushort1 __attribute__((ext_vector_type(1)));
DEF_BLOCK_LOAD_STORE1(ushort, ushort, _us)
DEF_BLOCK_LOAD_STORE(ushort, ushort, _us, 2)
DEF_BLOCK_LOAD_STORE(ushort, ushort, _us, 4)
DEF_BLOCK_LOAD_STORE(ushort, ushort, _us, 8)
DEF_BLOCK_LOAD_STORE16(ushort, ushort, _us)
DEF_BLOCK_LOAD_STORE32(ushort, ushort, _us)
DEF_BLOCK_LOAD_STORE1(uint, uint, )
DEF_BLOCK_LOAD_STORE(uint, uint, , 2)
DEF_BLOCK_LOAD_STORE(uint, uint, , 4)
DEF_BLOCK_LOAD_STORE(uint, uint, , 8)
DEF_BLOCK_LOAD_STORE16(uint, uint, )
typedef uint uint32 __attribute__((ext_vector_type(32)));
DEF_BLOCK_LOAD_STORE32(uint, uint, )
DEF_BLOCK_LOAD_STORE1(float, uint, )
DEF_BLOCK_LOAD_STORE(float, uint, , 2)
DEF_BLOCK_LOAD_STORE(float, uint, , 4)
DEF_BLOCK_LOAD_STORE(float, uint, , 8)
DEF_BLOCK_LOAD_STORE16(float, uint, )
typedef float float32 __attribute__((ext_vector_type(32)));
DEF_BLOCK_LOAD_STORE32(float, uint, )
#define DEF_BLOCK2D_LOAD_STORE(type, itype, vl, SG, suffix, BR, BC) \
itype##vl __builtin_IB_subgroup_block_read_flat_##suffix( \
long, int, int, int, int2); \
void __builtin_IB_subgroup_block_write_flat_##suffix( \
long, int, int, int, int2, itype##vl); \
__attribute__((overloadable)) type##vl block2d_load(const global type *p, \
int w, int h, int ld, int x, int y, int br, int bc, int sg) \
__attribute__((enable_if(br == BR, "wrong #rows"))) \
__attribute__((enable_if(bc == BC, "wrong #columns"))) \
__attribute__((enable_if(sg == SG, "wrong subgroup size"))) { \
ulong pp = as_long(p); \
ulong prem = pp & 0x3F; \
pp &= ~0x3F; \
x += (prem / sizeof(type)); \
w += prem; \
int2 coord = {x, y}; \
return as_##type##vl(__builtin_IB_subgroup_block_read_flat_##suffix( \
pp, w - 1, h - 1, ld - 1, coord)); \
} \
__attribute__((overloadable)) void block2d_store(type##vl v, \
const global type *p, int w, int h, int ld, int x, int y, int br, \
int bc, int sg) \
__attribute__((enable_if(br == BR, "wrong #rows"))) \
__attribute__((enable_if(bc == BC, "wrong #columns"))) \
__attribute__((enable_if(sg == SG, "wrong subgroup size"))) { \
ulong pp = as_long(p); \
ulong prem = pp & 0x3F; \
pp &= ~0x3F; \
x += (prem / sizeof(type)); \
w += prem; \
int2 coord = {x, y}; \
__builtin_IB_subgroup_block_write_flat_##suffix( \
pp, w - 1, h - 1, ld - 1, coord, as_##itype##vl(v)); \
}
DEF_BLOCK2D_LOAD_STORE(half, ushort, 8, 16, u16_m8k16v1, 16, 8)
DEF_BLOCK2D_LOAD_STORE(half, ushort, 8, 16, u16_m4k32v1, 32, 4)
DEF_BLOCK2D_LOAD_STORE(half, ushort, 16, 16, u16_m8k32v1, 32, 8)
DEF_BLOCK2D_LOAD_STORE(ushort, ushort, 8, 16, u16_m8k16v1, 16, 8)
DEF_BLOCK2D_LOAD_STORE(ushort, ushort, 8, 16, u16_m4k32v1, 32, 4)
DEF_BLOCK2D_LOAD_STORE(ushort, ushort, 16, 16, u16_m8k32v1, 32, 8)
DEF_BLOCK2D_LOAD_STORE(float, uint, 8, 16, u32_m8k16v1, 16, 8)
__attribute__((overloadable)) float8 block2d_load(const global float *p, int w,
int h, int ld, int x, int y, int br, int bc, int sg)
__attribute__((enable_if(br == 32, "wrong #rows")))
__attribute__((enable_if(bc == 4, "wrong #columns")))
__attribute__((enable_if(sg == 16, "wrong subgroup size"))) {
float8 lo = block2d_load(p, w, h, ld, x, y, 16, 8, 16);
float8 hi = block2d_load(p, w, h, ld, x + 16, y, 16, 8, 16);
return (float8)(lo[0], hi[0], lo[1], hi[1], lo[2], hi[2], lo[3], hi[3]);
}
__attribute__((overloadable)) void block2d_store(float8 v,
const global float *p, int w, int h, int ld, int x, int y, int br,
int bc, int sg) __attribute__((enable_if(br == 32, "wrong #rows")))
__attribute__((enable_if(bc == 4, "wrong #columns")))
__attribute__((enable_if(sg == 16, "wrong subgroup size"))) {
int lid = get_sub_group_local_id();
int ld_f = ld / (int)sizeof(float);
_Pragma("unroll") for (int c = 0; c < 4; c++) {
global float *col = (global float *)p + (long)(y + c) * ld_f + x;
col[lid] = v[2 * c];
col[16 + lid] = v[2 * c + 1];
}
}
__attribute__((overloadable)) float16 block2d_load(const global float *p, int w,
int h, int ld, int x, int y, int br, int bc, int sg)
__attribute__((enable_if(br == 32, "wrong #rows")))
__attribute__((enable_if(bc == 8, "wrong #columns")))
__attribute__((enable_if(sg == 16, "wrong subgroup size"))) {
float8 lo = block2d_load(p, w, h, ld, x, y, 16, 8, 16);
float8 hi = block2d_load(p, w, h, ld, x + 16, y, 16, 8, 16);
return (float16)(lo[0], hi[0], lo[1], hi[1], lo[2], hi[2], lo[3], hi[3],
lo[4], hi[4], lo[5], hi[5], lo[6], hi[6], lo[7], hi[7]);
}
__attribute__((overloadable)) void block2d_store(float16 v,
const global float *p, int w, int h, int ld, int x, int y, int br,
int bc, int sg) __attribute__((enable_if(br == 32, "wrong #rows")))
__attribute__((enable_if(bc == 8, "wrong #columns")))
__attribute__((enable_if(sg == 16, "wrong subgroup size"))) {
float8 lo = (float8)(v[0], v[2], v[4], v[6], v[8], v[10], v[12], v[14]);
float8 hi = (float8)(v[1], v[3], v[5], v[7], v[9], v[11], v[13], v[15]);
block2d_store(lo, p, w, h, ld, x, y, 16, 8, 16);
block2d_store(hi, p, w, h, ld, x + 16, y, 16, 8, 16);
}
#define tile_fill(t, v) \
do { \
_Pragma("unroll") for (int i = 0; i < sizeof(t.x) / sizeof(t.x[0]); \
i++) t.x[i] \
= v; \
} while (0)
#define tile_elementwise(t, f) \
do { \
_Pragma("unroll") for (int i = 0; i < sizeof(t.x) / sizeof(t.x[0]); \
i++) t.x[i] \
= f(t.x[i]); \
} while (0)
#define tile_elementwise_s(t, f) \
do { \
_Pragma("unroll") for (int i = 0; \
i < sizeof((t).x) / sizeof((t).x[0]); i++) { \
_Pragma("unroll") for (int s = 0; \
s < sizeof((t).x[0]) / sizeof((t).x[0][0]); \
s++)(t) \
.x[i][s] \
= f((t).x[i][s]); \
} \
} while (0)
#define tile_binary(t, t2, f) \
do { \
_Pragma("unroll") for (int i = 0; i < sizeof(t.x) / sizeof(t.x[0]); \
i++) t.x[i] \
= f(t.x[i], t2.x[i]); \
} while (0)
#define tile_store_global_bounds_cvt(_t, _ptr, _ld, _off_r, _off_c, _max_r, \
_max_c, _cvt, _sg, _br, _bc, _nbr, _nbc) \
do { \
for (int _j = 0; _j < (_bc * _nbc); _j++) { \
for (int _i0 = 0; _i0 < (_br * _nbr); _i0 += _sg) { \
int _i = _i0 + get_sub_group_local_id(); \
int _gr = (_off_r) + _j; \
int _gc = (_off_c) + _i; \
if (_gr < (_max_r) && _gc < (_max_c)) \
(_ptr)[(ulong)_gc * (_ld) + _gr] = _cvt( \
tile_access(_t, _i0, _j, _sg, _br, _bc, _nbr)); \
} \
} \
} while (0)
#define tile_copy(t, t_new) \
do { \
_Pragma("unroll") for (int i = 0; i < sizeof(t.x) / sizeof(t.x[0]); \
i++) t_new.x[i] \
= __builtin_convertvector(t.x[i], __typeof__(t_new.x[i])); \
} while (0)
#define tile_convert(t, t_new, conversion_func) \
do { \
_Pragma("unroll") for (int i = 0; i < sizeof(t.x) / sizeof(t.x[0]); \
i++) { \
_Pragma("unroll") for (int s = 0; \
s < sizeof(t.x[0]) / sizeof(t.x[0][0]); \
s++) t_new.x[i][s] \
= conversion_func(t.x[i][s]); \
} \
} while (0)
#define tile_copy_to_vec2(t, t_new, type) \
do { \
_Pragma("unroll") for (int i = 0; i < sizeof(t.x) / sizeof(t.x[0]); \
i++) { \
_Pragma("unroll") for (int s = 0; \
s < sizeof(t.x[0]) / sizeof(t.x[0][0]) / 2; \
s++) { \
type v = {CONVERT_DATA_T(t.x[i][2 * s]), \
CONVERT_DATA_T(t.x[i][2 * s + 1])}; \
t_new.x[i][s] = as_uint(v); \
} \
} \
} while (0)
#define tile_access(t, i0, j, sg, br, bc, nbr) \
(t).x[(i0) / (br) + (nbr) * ((j) / (bc))] \
[((i0) % (br)) / (sg) + ((j) % (bc)) * ((br) / (sg))]
#define xlane_tile_access(t, i, j, sg, br, bc, nbr) \
sub_group_broadcast(tile_access(t, i, j, sg, br, bc, nbr), i % sg)
#define tile_predicated_assignment_t( \
t, sg_offset_r, sg_offset_c, predicate, value, sg, br, bc, nbr, nbc) \
do { \
for (int j = 0; j < (bc * nbc); j++) { \
for (int i0 = 0; i0 < (br * nbr); i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
int offset_r = sg_offset_r + j; \
int offset_c = sg_offset_c + i; \
if (predicate(offset_r, offset_c)) { \
tile_access(t, i0, j, sg, br, bc, nbr) = value; \
} \
} \
} \
} while (0)
#define tile_predicated_assignment( \
t, sg_offset_r, sg_offset_c, predicate, value, sg, br, bc, nbr, nbc) \
do { \
for (int j = 0; j < (bc * nbc); j++) { \
for (int i0 = 0; i0 < (br * nbr); i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
int offset_r = sg_offset_r + i; \
int offset_c = sg_offset_c + j; \
if (predicate(offset_r, offset_c)) { \
tile_access(t, i0, j, sg, br, bc, nbr) = value; \
} \
} \
} \
} while (0)
#define tile_predicated_select_t(t, sg_offset_r, sg_offset_c, predicate, \
true_value, false_value, sg, br, bc, nbr, nbc) \
do { \
for (int j = 0; j < (bc * nbc); j++) { \
for (int i0 = 0; i0 < (br * nbr); i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
int offset_r = sg_offset_r + j; \
int offset_c = sg_offset_c + i; \
tile_access(t, i0, j, sg, br, bc, nbr) \
= predicate(offset_r, offset_c) ? true_value \
: false_value; \
} \
} \
} while (0)
#define tile_predicated_select(t, sg_offset_r, sg_offset_c, predicate, \
true_value, false_value, sg, br, bc, nbr, nbc) \
do { \
for (int j = 0; j < (bc * nbc); j++) { \
for (int i0 = 0; i0 < (br * nbr); i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
int offset_r = sg_offset_r + i; \
int offset_c = sg_offset_c + j; \
tile_access(t, i0, j, sg, br, bc, nbr) \
= predicate(offset_r, offset_c) ? true_value \
: false_value; \
} \
} \
} while (0)
#define DECLARE_2D_TILE_OPS(tile_type, element_type, sg, br, bc, nbr, nbc) \
__attribute__((overloadable)) void tile_load_full(tile_type *t, \
const global element_type *ptr, int ld, int offset_r, \
int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
tile_access(*t, i0, j, sg, br, bc, nbr) = ptr[i]; \
} \
} \
} \
__attribute__((overloadable)) void tile_load_full(tile_type *t, \
const local element_type *ptr, int ld, int offset_r, \
int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
tile_access(*t, i0, j, sg, br, bc, nbr) = ptr[i]; \
} \
} \
} \
__attribute__((overloadable)) void tile_load(tile_type *t, \
const local element_type *ptr, int m, int n, int ld, int offset_r, \
int offset_c) { \
if (m >= offset_r + br * nbr && n >= offset_c + bc * nbc) { \
tile_load_full(t, ptr, ld, offset_r, offset_c); \
return; \
} \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
if (offset_c + j < n) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
if (offset_r + i < m) \
tile_access(*t, i0, j, sg, br, bc, nbr) = ptr[i]; \
} \
} \
} \
} \
__attribute__((overloadable)) void tile_load(tile_type *t, \
const global element_type *ptr, int m, int n, int ld, \
int offset_r, int offset_c) { \
if (m >= offset_r + br * nbr && n >= offset_c + bc * nbc) { \
tile_load_full(t, ptr, ld, offset_r, offset_c); \
return; \
} \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
if (offset_c + j < n) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
if (offset_r + i < m) \
tile_access(*t, i0, j, sg, br, bc, nbr) = ptr[i]; \
} \
} \
} \
} \
__attribute__((overloadable)) void tile_load(tile_type *t, \
const global element_type *ptr, int m, int n, int offset_r, \
int offset_c) { \
tile_load(t, ptr, m, n, m, offset_r, offset_c); \
} \
__attribute__((overloadable)) void tile_load_t_full(tile_type *t, \
const local element_type *ptr, int ld, int offset_r, \
int offset_c) { \
ptr += ld * offset_r + offset_c; \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; \
i0 += sg, ptr += ld * sg) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
= ptr[get_sub_group_local_id() * ld + j]; \
} \
} \
} \
__attribute__((overloadable)) void tile_load_t(tile_type *t, \
const local element_type *ptr, int m, int n, int ld, int offset_r, \
int offset_c) { \
if (m >= offset_r + br * nbr && n >= offset_c + bc * nbc) { \
tile_load_t_full(t, ptr, ld, offset_r, offset_c); \
return; \
} \
ptr += ld * offset_r + offset_c; \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; \
i0 += sg, ptr += ld * sg) { \
int i = i0 + get_sub_group_local_id(); \
if (offset_r + i < m) \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
if (offset_c + j < n) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
= ptr[get_sub_group_local_id() * ld + j]; \
} \
} \
} \
} \
__attribute__((overloadable)) void tile_load_t_full(tile_type *t, \
const global element_type *ptr, int ld, int offset_r, \
int offset_c) { \
ptr += ld * offset_r + offset_c; \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; \
i0 += sg, ptr += ld * sg) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
= ptr[get_sub_group_local_id() * ld + j]; \
} \
} \
} \
__attribute__((overloadable)) void tile_load_t(tile_type *t, \
const global element_type *ptr, int m, int n, int ld, \
int offset_r, int offset_c) { \
if (m >= offset_r + br * nbr && n >= offset_c + bc * nbc) { \
tile_load_t_full(t, ptr, ld, offset_r, offset_c); \
return; \
} \
ptr += ld * offset_r + offset_c; \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; \
i0 += sg, ptr += ld * sg) { \
int i = i0 + get_sub_group_local_id(); \
if (offset_r + i < m) \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
if (offset_c + j < n) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
= ptr[get_sub_group_local_id() * ld + j]; \
} \
} \
} \
} \
__attribute__((overloadable)) void tile_load_t(tile_type *t, \
const global element_type *ptr, int m, int n, int offset_r, \
int offset_c) { \
tile_load_t(t, ptr, m, n, n, offset_r, offset_c); \
} \
__attribute__((overloadable)) void tile_store_t_full(tile_type t, \
local element_type *ptr, int ld, int offset_r, int offset_c) { \
ptr += ld * offset_r + offset_c; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = ld * (i0 + get_sub_group_local_id()); \
ptr[i] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_store_t(tile_type t, \
local element_type *ptr, int m, int n, int ld, int offset_r, \
int offset_c) { \
if (m >= offset_r + br * nbr && n >= offset_c + bc * nbc) { \
tile_store_t_full(t, ptr, ld, offset_r, offset_c); \
return; \
} \
ptr += ld * offset_r + offset_c; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr++) { \
if (offset_c + j < n) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = ld * (i0 + get_sub_group_local_id()); \
if ((offset_r + i0 + get_sub_group_local_id()) < m) \
ptr[i] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
} \
__attribute__((overloadable)) void tile_store_full(tile_type t, \
local element_type *ptr, int ld, int offset_r, int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
ptr[i] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_store(tile_type t, \
local element_type *ptr, int m, int n, int ld, int offset_r, \
int offset_c) { \
if (m >= offset_r + br * nbr && n >= offset_c + bc * nbc) { \
tile_store_full(t, ptr, ld, offset_r, offset_c); \
return; \
} \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
if (offset_c + j < n) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
if (offset_r + i < m) \
ptr[i] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
} \
__attribute__((overloadable)) void tile_store_full(tile_type t, \
global element_type *ptr, int ld, int offset_r, int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
ptr[i] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_store(tile_type t, \
global element_type *ptr, int m, int n, int ld, int offset_r, \
int offset_c) { \
if (m >= offset_r + br * nbr && n >= offset_c + bc * nbc) { \
tile_store_full(t, ptr, ld, offset_r, offset_c); \
return; \
} \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
if (offset_c + j < n) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
if (offset_r + i < m) \
ptr[i] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
} \
__attribute__((overloadable)) void tile_store(tile_type t, \
global element_type *ptr, int m, int n, int offset_r, \
int offset_c) { \
tile_store(t, ptr, m, n, m, offset_r, offset_c); \
} \
__attribute__((overloadable)) void tile_load_t_packed_src1(tile_type *t, \
local element_type *ptr, int panel, int ld, int offset_r, \
int offset_c) { \
offset_c += get_sub_group_local_id(); \
int offset_r0 = offset_r % panel; \
int offset_r1 = offset_r - offset_r0; \
ptr += offset_r0 + panel * offset_c + ld * offset_r1; \
_Pragma("unroll") for (int j0 = 0; j0 < br * nbr; \
j0 += sg, ptr += sg * panel) { \
_Pragma("unroll") for (int i = 0; i < bc * nbc; i++) \
tile_access(*(t), j0, i, sg, br, bc, nbr) \
= ptr[i]; \
} \
} \
__attribute__((overloadable)) void tile_load_packed_src1(tile_type *t, \
local element_type *ptr, int panel, int ld, int offset_r, \
int offset_c) { \
ptr += offset_c * panel; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += panel) \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
int offset_r0 = (offset_r + i) % panel; \
int offset_r1 = (offset_r + i) - offset_r0; \
tile_access(*(t), i0, j, sg, br, bc, nbr) \
= ptr[offset_r0 + offset_r1 * ld]; \
} \
} \
__attribute__((overloadable)) void tile_store_packed_src1(tile_type t, \
local element_type *ptr, int panel, int ld, int offset_r, \
int offset_c) { \
ptr += offset_c * panel; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += panel) \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
int offset_r0 = (offset_r + i) % panel; \
int offset_r1 = (offset_r + i) - offset_r0; \
ptr[offset_r0 + offset_r1 * ld] \
= tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
__attribute__((overloadable)) void tile_store_t_packed_src1(tile_type t, \
local element_type *ptr, int panel, int ld, int offset_r, \
int offset_c) { \
\
offset_c += get_sub_group_local_id(); \
int offset_r0 = offset_r % panel; \
int offset_r1 = offset_r - offset_r0; \
ptr += offset_r0 + panel * offset_c + ld * offset_r1; \
_Pragma("unroll") for (int j0 = 0; j0 < br * nbr; \
j0 += sg, ptr += sg * panel) { \
_Pragma("unroll") for (int i = 0; i < bc * nbc; i++) ptr[i] \
= tile_access(t, j0, i, sg, br, bc, nbr); \
} \
} \
__attribute__((overloadable)) void tile_store_sys_src1(tile_type t, \
local element_type *ptr, int tileR, int tileC, int wg_tile_m, \
int wg_tile_n, int offset_r, int offset_c) { \
const int crosspack = 4 / sizeof(element_type); \
const int tile_panel_size = tileR * tileC; \
const int num_row_panels = wg_tile_m / tileR; \
const int num_col_panels = wg_tile_n / tileC; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
const int in_r = offset_r + i0 + get_sub_group_local_id(); \
const int in_c = offset_c + j; \
\
const int row_panel = in_r \
/ tileR; \
const int col_panel = in_c \
/ tileC; \
const int panel_base \
= (col_panel * num_row_panels + row_panel) \
* tile_panel_size; \
\
\
const int in_panel_row = in_r \
& (tileR - 1); \
const int in_panel_col = in_c \
& (tileC \
- 1); \
const int col_group_offset = (in_panel_col / crosspack) \
* (crosspack * tileR); \
const int sg_lane_offset = in_panel_row \
* crosspack; \
const int crosspack_offset = (in_panel_col \
& (crosspack - 1)); \
const int out_idx = panel_base + col_group_offset \
+ sg_lane_offset + crosspack_offset; \
ptr[out_idx] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_load_sys_src1(tile_type *t, \
local element_type *ptr, int tileR, int tileC, int wg_tile_m, \
int wg_tile_n, int offset_r, int offset_c) { \
const int crosspack = 4 / sizeof(element_type); \
const int tile_panel_size = tileR * tileC; \
const int num_row_panels = wg_tile_m / tileR; \
const int num_col_panels = wg_tile_n / tileC; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
const int in_r = offset_r + i0 + get_sub_group_local_id(); \
const int in_c = offset_c + j; \
\
const int row_panel = in_r \
/ tileR; \
const int col_panel = in_c \
/ tileC; \
const int panel_base \
= (col_panel * num_row_panels + row_panel) \
* tile_panel_size; \
\
\
const int in_panel_row = in_r \
& (tileR - 1); \
const int in_panel_col = in_c \
& (tileC \
- 1); \
const int col_group_offset = (in_panel_col / crosspack) \
* (crosspack * tileR); \
const int sg_lane_offset = in_panel_row \
* crosspack; \
const int crosspack_offset = (in_panel_col \
& (crosspack - 1)); \
const int out_idx = panel_base + col_group_offset \
+ sg_lane_offset + crosspack_offset; \
tile_access(*t, i0, j, sg, br, bc, nbr) = ptr[out_idx]; \
} \
} \
} \
__attribute__((overloadable)) void tile_store_t_sys_src1(tile_type t, \
local element_type *ptr, int ld, int offset_r, int offset_c) { \
offset_c += get_sub_group_local_id(); \
int offset_r0 = offset_r & (sg - 1); \
int offset_r1 = offset_r & ~(sg - 1); \
ptr += offset_r0 + sg * offset_c + ld * offset_r1; \
_Pragma("unroll") for (int j0 = 0; j0 < br * nbr; \
j0 += sg, ptr += sg * sg) { \
_Pragma("unroll") for (int i = 0; i < bc * nbc; i++) ptr[i] \
= tile_access(t, j0, i, sg, br, bc, nbr); \
} \
} \
__attribute__((overloadable)) void tile_store_t_sys_src11(tile_type t, \
local element_type *ptr, int tileR, int tileC, int wg_tile_m, \
int wg_tile_n, int offset_r, int offset_c) { \
const int crosspack = 4 / sizeof(element_type); \
const int tile_panel_size = tileR * tileC; \
const int num_row_panels \
= wg_tile_m / tileR; \
const int num_col_panels = wg_tile_n / tileC; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
const int in_r = offset_r + i0 + get_sub_group_local_id(); \
const int in_c = offset_c + j; \
\
const int row_panel = in_c / tileR; \
const int col_panel = in_r / tileC; \
const int panel_base \
= (col_panel * num_row_panels + row_panel) \
* tile_panel_size; \
\
const int in_panel_row = in_c \
& (tileR - 1); \
const int in_panel_col = in_r \
& (tileC \
- 1); \
const int col_group_offset = (in_panel_col / crosspack) \
* (crosspack * tileR); \
const int sg_lane_offset = in_panel_row \
* crosspack; \
const int crosspack_offset = (in_panel_col \
& (crosspack - 1)); \
const int out_idx = panel_base + col_group_offset \
+ sg_lane_offset + crosspack_offset; \
ptr[out_idx] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_store_sys_src22(tile_type t, \
local element_type *ptr, int panel_n, int wg_tile_m, \
int wg_tile_n, int offset_r, int offset_c) { \
const int crosspack = 16; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
const int in_r = offset_r + i0 + get_sub_group_local_id(); \
const int in_c = offset_c + j; \
\
const int col_panel = in_c / panel_n; \
const int in_panel_c = in_c & (panel_n - 1); \
\
const int col_group_offset = (in_r / crosspack) \
* (crosspack * panel_n); \
const int sg_lane_offset \
= in_panel_c * crosspack; \
const int crosspack_offset = (in_r & (crosspack - 1)); \
const int out_idx = col_panel * (panel_n * wg_tile_m) \
+ col_group_offset + sg_lane_offset \
+ crosspack_offset; \
ptr[out_idx] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_store_t_sys_src22(tile_type t, \
local element_type *ptr, int panel_n, int wg_tile_m, \
int wg_tile_n, int offset_r, int offset_c) { \
const int crosspack = 16; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
const int in_r = offset_r + i0 + get_sub_group_local_id(); \
const int in_c = offset_c + j; \
\
const int col_panel = in_r / panel_n; \
const int in_panel_c = in_r & (panel_n - 1); \
\
const int col_group_offset = (in_c / crosspack) \
* (crosspack * panel_n); \
const int sg_lane_offset \
= in_panel_c * crosspack; \
const int crosspack_offset = (in_c \
& (crosspack - 1)); \
const int out_idx = col_panel * (panel_n * wg_tile_n) \
+ col_group_offset + sg_lane_offset \
+ crosspack_offset; \
ptr[out_idx] = tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_store_t_sys_src2(tile_type t, \
local element_type *ptr, int tile_n, int ld, int offset_r, \
int offset_c) { \
const int cp = 32 / sizeof(element_type); \
offset_c += get_sub_group_local_id(); \
int offset_r0 = offset_r & (cp - 1); \
int offset_r1 = offset_r & ~(cp - 1); \
ptr += offset_r0 + tile_n * offset_r1; \
_Pragma("unroll") for (int j0 = 0; j0 < br * nbr; \
j0 += sg, offset_c += sg) { \
int offset_c0 = offset_c & (tile_n - 1); \
int offset_c1 = offset_c & ~(tile_n - 1); \
local element_type *ptr_j = ptr + cp * offset_c0 + ld * offset_c1; \
_Pragma("unroll") for (int i = 0; i < bc * nbc; i++) { \
*ptr_j = tile_access(t, j0, i, sg, br, bc, nbr); \
ptr_j++; \
if ((~i & (cp - 1)) == 0) ptr_j += cp * (tile_n - 1); \
} \
} \
} \
__attribute__((overloadable)) void tile_load_t_sys_src2(tile_type *t, \
local element_type *ptr, int tile_n, int ld, int offset_r, \
int offset_c) { \
const int cp = 32 / sizeof(element_type); \
offset_c += get_sub_group_local_id(); \
int offset_r0 = offset_r & (cp - 1); \
int offset_r1 = offset_r & ~(cp - 1); \
ptr += offset_r0 + tile_n * offset_r1; \
_Pragma("unroll") for (int j0 = 0; j0 < br * nbr; \
j0 += sg, offset_c += sg) { \
int offset_c0 = offset_c & (tile_n - 1); \
int offset_c1 = offset_c & ~(tile_n - 1); \
local element_type *ptr_j = ptr + cp * offset_c0 + ld * offset_c1; \
_Pragma("unroll") for (int i = 0; i < bc * nbc; i++) { \
tile_access(*t, j0, i, sg, br, bc, nbr) = *ptr_j; \
ptr_j++; \
if ((~i & (cp - 1)) == 0) ptr_j += cp * (tile_n - 1); \
} \
} \
} \
__attribute__((overloadable)) void tile_atomic_max_full(tile_type t, \
local element_type *ptr, int ld, int offset_r, int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
(void)local_atomic_max( \
ptr + i, tile_access(t, i0, j, sg, br, bc, nbr)); \
} \
} \
} \
__attribute__((overloadable)) void tile_atomic_add_full(tile_type t, \
local element_type *ptr, int ld, int offset_r, int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
(void)local_atomic_add( \
ptr + i, tile_access(t, i0, j, sg, br, bc, nbr)); \
} \
} \
} \
__attribute__((overloadable)) void tile_atomic_add_full(tile_type t, \
global element_type *ptr, int ld, int offset_r, int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
(void)global_atomic_add( \
ptr + i, tile_access(t, i0, j, sg, br, bc, nbr)); \
} \
} \
} \
__attribute__((overloadable)) void tile_atomic_add(tile_type t, \
global element_type *ptr, int m, int n, int ld, int offset_r, \
int offset_c) { \
if (m >= (offset_r + (br * nbr)) && n >= (offset_c + (bc * nbc))) { \
tile_atomic_add_full(t, ptr, ld, offset_r, offset_c); \
return; \
} \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
if (offset_c + j < n) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = i0 + get_sub_group_local_id(); \
if (offset_r + i < m) \
(void)global_atomic_add(ptr + i, \
tile_access(t, i0, j, sg, br, bc, nbr)); \
} \
} \
} \
}
#define DECLARE_2D_TILE_VREDUCE(tile_type, sg, br, bc, nbr, nbc, rtile_type, \
rsg, rbr, rbc, rnbr, rnbc) \
__attribute__((overloadable)) void tile_vreduce_add( \
tile_type t, rtile_type *tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*tr, i0, 0, rsg, rbr, rbc, rnbr) \
+= tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_vreduce_max( \
tile_type t, rtile_type *tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*tr, i0, 0, rsg, rbr, rbc, rnbr) \
= max(tile_access(t, i0, j, sg, br, bc, nbr), \
tile_access(*tr, i0, 0, rsg, rbr, rbc, rnbr)); \
} \
} \
} \
__attribute__((overloadable)) void tile_vbroadcast_add( \
tile_type *t, rtile_type tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
+= tile_access(tr, i0, 0, rsg, rbr, rbc, rnbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_vbroadcast_sub( \
tile_type *t, rtile_type tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
-= tile_access(tr, i0, 0, rsg, rbr, rbc, rnbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_vbroadcast_mul( \
tile_type *t, rtile_type tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
*= tile_access(tr, i0, 0, rsg, rbr, rbc, rnbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_vbroadcast_min( \
tile_type *t, rtile_type tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
= min(tile_access(*t, i0, j, sg, br, bc, nbr), \
tile_access(tr, i0, 0, rsg, rbr, rbc, rnbr)); \
} \
} \
}
#define DECLARE_2D_TILE_HREDUCE(tile_type, sg, br, bc, nbr, nbc, rtile_type, \
rsg, rbr, rbc, rnbr, rnbc) \
__attribute__((overloadable)) void tile_hreduce_add( \
tile_type t, rtile_type *tr) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
tile_access(*tr, i0, j, rsg, rbr, rbc, rnbr) \
+= tile_access(t, i0, j, sg, br, bc, nbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_hbroadcast_add( \
tile_type *t, rtile_type tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
+= xlane_tile_access(tr, j, 0, rsg, rbr, rbc, rnbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_hbroadcast_sub( \
tile_type *t, rtile_type tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
-= xlane_tile_access(tr, j, 0, rsg, rbr, rbc, rnbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_hbroadcast_mul( \
tile_type *t, rtile_type tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*t, i0, j, sg, br, bc, nbr) \
*= xlane_tile_access(tr, j, 0, rsg, rbr, rbc, rnbr); \
} \
} \
} \
__attribute__((overloadable)) void tile_hbroadcast_min( \
tile_type *t, rtile_type tr) { \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
tile_access(*t, i0, j, sg, br, bc, nbr) = min( \
tile_access(*t, i0, j, sg, br, bc, nbr), \
xlane_tile_access(tr, j, 0, rsg, rbr, rbc, rnbr)); \
} \
} \
}
#define DECLARE_2D_TILE_RSELECT(tile_type0, sg0, br0, bc0, nbr0, nbc0, \
tile_type1, sg1, br1, bc1, nbr1, nbc1) \
__attribute__((overloadable)) void tile_rselect( \
tile_type0 *t0, tile_type1 t1, int idx) { \
_Pragma("unroll") for (int j = 0; j < bc0 * nbc0; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br0 * nbr0; i0 += sg0) { \
tile_access(*t0, i0, j, sg0, br0, bc0, nbr0) \
= tile_access(t1, i0, j, sg1, br1, bc1, nbr1); \
_Pragma("unroll") for (int z = 1; \
z < (br1 * nbr1 / br0 * nbr0); \
z++) if (z == idx) { \
tile_access(*t0, i0, j, sg0, br0, bc0, nbr0) \
= tile_access(t1, i0 + z * br0 * nbr0, j, sg1, \
br1, bc1, nbr1); \
} \
} \
} \
}
#define DECLARE_2D_TILE_COPY_REBLOCK(tile_type0, sg0, br0, bc0, nbr0, nbc0, \
tile_type1, sg1, br1, bc1, nbr1, nbc1, conversion_func) \
__attribute__((overloadable)) void tile_copy_reblock( \
tile_type0 t0, tile_type1 *t1) { \
_Pragma("unroll") for (int j = 0; j < bc0 * nbc0; j++) { \
_Pragma("unroll") for (int i0 = 0; i0 < br0 * nbr0; i0 += sg0) { \
tile_access(*t1, i0, j, sg1, br1, bc1, nbr1) \
= conversion_func( \
tile_access(t0, i0, j, sg0, br0, bc0, nbr0)); \
} \
} \
}
#define DECLARE_2D_TILE_PRINT(tile_type, element_type, sg, br, bc, nbr, nbc) \
__attribute__((overloadable)) void print_tile(tile_type t, \
const __constant char *format, int wg_x, int wg_y, int wg_z, \
int sg_per_wg_m, int sg_per_wg_n) { \
if (get_group_id(0) == wg_x && get_group_id(1) == wg_y \
&& get_group_id(2) == wg_z) { \
uint sg_ij = sub_group_broadcast(get_local_id(1), 0); \
int sg_i = sg_ij % sg_per_wg_m; \
int sg_j = sg_ij / sg_per_wg_m; \
if (get_local_id(0) == 0 && get_local_id(1) == 0 \
&& get_local_id(2) == 0) \
printf(#tile_type "(%lu,%lu):\n", get_group_id(0), \
get_group_id(1)); \
barrier(CLK_LOCAL_MEM_FENCE); \
for (int sgr = 0; sgr < sg_per_wg_n; sgr++) { \
for (int rr = 0; rr < nbr * br; rr++) { \
barrier(CLK_LOCAL_MEM_FENCE); \
if (get_local_id(0) == 0 && get_local_id(1) == 0) { \
printf("%d: ", sgr *nbr *br + rr); \
} \
barrier(CLK_LOCAL_MEM_FENCE); \
for (int sgc = 0; sgc < sg_per_wg_m; sgc++) { \
if (sg_i == sgc && sg_j == sgr) { \
for (int cc = 0; cc < nbc * bc; cc++) { \
element_type value; \
value = xlane_tile_access( \
t, rr, cc, sg, br, bc, nbr); \
if (get_sub_group_local_id() == 0) \
printf(format, value); \
} \
} \
barrier(CLK_LOCAL_MEM_FENCE); \
} \
if (get_local_id(0) == 0 && get_local_id(1) == 0) \
printf("\n"); \
} \
} \
} \
}
#define DECLARE_2D_TILE(tile_type, element_type, sg, br, bc, nbr, nbc) \
typedef element_type \
__attribute__((ext_vector_type(br * bc / sg))) _e_##tile_type; \
typedef struct { \
_e_##tile_type x[nbr * nbc]; \
} tile_type; \
DECLARE_2D_TILE_OPS(tile_type, element_type, sg, br, bc, nbr, nbc)
#define DECLARE_2D_TILE_BLOCK_OPS( \
tile_type, element_type, sg, br, bc, nbr, nbc) \
__attribute__((overloadable)) void tile_load_block(tile_type *t, \
const global element_type *ptr, int ld, int offset_r, \
int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int jj = 0; jj < nbc; jj++, ptr += ld * bc) { \
_Pragma("unroll") for (int ii = 0; ii < nbr; ii++)(t) \
->x[ii + nbr * jj] \
= block_load(ptr + ii * br, br / sg); \
} \
} \
__attribute__((overloadable)) void tile_store_block(tile_type t, \
global element_type *ptr, int ld, int offset_r, int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int jj = 0; jj < nbc; jj++, ptr += ld * bc) { \
_Pragma("unroll") for (int ii = 0; ii < nbr; ii++) \
block_store(ptr + ii * br, (t).x[ii + nbr * jj]); \
} \
} \
__attribute__((overloadable)) void tile_store_block_packed(tile_type t, \
local element_type *ptr, int panel, int ld, int offset_r, \
int offset_c) { \
\
ptr += offset_c * panel; \
_Pragma("unroll") for (int jj = 0; jj < nbc; jj++, ptr += panel) { \
_Pragma("unroll") for (int ii = 0; ii < nbr; ii++) { \
int offset_r0 = (offset_r + ii * br) % panel; \
int offset_r1 = (offset_r + ii * br) - offset_r0; \
block_store(ptr + offset_r0 + offset_r1 * ld, \
(t).x[ii + nbr * jj]); \
} \
} \
} \
__attribute__((overloadable)) void tile_load_block(tile_type *t, \
const global element_type *ptr, int n, int ld, int offset_r, \
int offset_c) { \
ptr += ld * offset_c + offset_r; \
n -= offset_c; \
_Pragma("unroll") for (int jj = 0; jj < nbc; jj++, ptr += ld * bc) { \
if (jj < n) { \
_Pragma("unroll") for (int ii = 0; ii < nbr; ii++)(t) \
->x[ii + nbr * jj] \
= block_load(ptr + ii * br, br / sg); \
} \
} \
} \
__attribute__((overloadable)) void tile_store_block(tile_type t, \
global element_type *ptr, int n, int ld, int offset_r, \
int offset_c) { \
ptr += ld * offset_c + offset_r; \
n -= offset_c; \
_Pragma("unroll") for (int jj = 0; jj < nbc; jj++, ptr += ld * bc) { \
if (jj < n) { \
_Pragma("unroll") for (int ii = 0; ii < nbr; ii++) \
block_store(ptr + ii * br, (t).x[ii + nbr * jj]); \
} \
} \
}
#define DECLARE_2D_TILE_BLOCK2D_OPS( \
tile_type, element_type, sg, br, bc, nbr, nbc) \
__attribute__((overloadable)) void tile_load_block2d(tile_type *t, \
const global element_type *ptr, int m, int n, int ld, \
int offset_r, int offset_c) { \
const int e = sizeof(element_type); \
_Pragma("unroll") for (int jj = 0; jj < nbc; jj++) { \
_Pragma("unroll") for (int ii = 0; ii < nbr; ii++)(t) \
->x[ii + nbr * jj] \
= block2d_load(ptr, m * e, n, ld * e, offset_r + ii * br, \
offset_c + jj * bc, br, bc, sg); \
} \
} \
__attribute__((overloadable)) void tile_load_block2d(tile_type *t, \
const global element_type *ptr, int m, int n, int offset_r, \
int offset_c) { \
tile_load_block2d(t, ptr, m, n, m, offset_r, offset_c); \
} \
__attribute__((overloadable)) void tile_store_block2d(tile_type t, \
const global element_type *ptr, int m, int n, int ld, \
int offset_r, int offset_c) { \
const int e = sizeof(element_type); \
_Pragma("unroll") for (int jj = 0; jj < nbc; jj++) { \
_Pragma("unroll") for (int ii = 0; ii < nbr; ii++) block2d_store( \
(t).x[ii + nbr * jj], ptr, m *e, n, ld *e, \
offset_r + ii * br, offset_c + jj * bc, br, bc, sg); \
} \
} \
__attribute__((overloadable)) void tile_store_block2d(tile_type t, \
const global element_type *ptr, int m, int n, int offset_r, \
int offset_c) { \
tile_store_block2d(t, ptr, m, n, m, offset_r, offset_c); \
}
#define DECLARE_2D_TILE_LOAD_PACKED_VEC( \
tile_type, element_type, vec_type, sg, br, bc, nbr, nbc) \
__attribute__((overloadable)) void tile_load_packed_vec2(tile_type *t, \
const global element_type *ptr, int m, int n, int ld, \
int offset_r, int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < bc * nbc; j++, ptr += ld) { \
if (offset_c + j < n) { \
_Pragma("unroll") for (int i0 = 0; i0 < br * nbr; i0 += sg) { \
int i = 2 * (i0 + get_sub_group_local_id()); \
vec_type loaded = 0; \
if (offset_r + i < m) loaded.s0 = ptr[i]; \
if (offset_r + i + 1 < m) loaded.s1 = ptr[i + 1]; \
tile_access(*t, i0, j, sg, br, bc, nbr) = as_uint(loaded); \
} \
} \
} \
} \
__attribute__((overloadable)) void tile_load_packed_vec2(tile_type *t, \
const global element_type *ptr, int m, int n, int offset_r, \
int offset_c) { \
tile_load_packed_vec2(t, ptr, m, n, m, offset_r, offset_c); \
}
#define cooperative_prefetch_2d(ptr, r, c, ld, sg_id, n_sg, sg_size, caching) \
cooperative_prefetch_2d_internal((const global uchar *)ptr, \
(r) * sizeof(*(ptr)), c, (ld) * sizeof(*(ptr)), sg_id, n_sg, \
sg_size, caching)
#define cooperative_prefetch_2d_rem( \
ptr, r, c, rmax, cmax, ld, sg_id, n_sg, sg_size, caching) \
cooperative_prefetch_2d_internal((const global uchar *)ptr, \
(r) * sizeof(*(ptr)), c, (rmax) * sizeof(*(ptr)), cmax, \
(ld) * sizeof(*(ptr)), sg_id, n_sg, sg_size, caching)
enum LSC_LDCC {
LSC_LDCC_DEFAULT = 0,
LSC_LDCC_L1UC_L3UC = 1,
LSC_LDCC_L1UC_L3C = 2,
LSC_LDCC_L1C_L3UC = 3,
LSC_LDCC_L1C_L3C = 4,
LSC_LDCC_L1S_L3UC = 5,
LSC_LDCC_L1S_L3C = 6,
LSC_LDCC_L1IAR_L3C = 7,
};
extern void __builtin_IB_lsc_prefetch_global_uchar(
const __global uchar *base, int immElemOff, enum LSC_LDCC cacheOpt);
extern void __builtin_IB_lsc_prefetch_global_uint(
const __global uint *base, int immElemOff, enum LSC_LDCC cacheOpt);
__attribute__((overloadable)) void cooperative_prefetch_2d_internal(
const global uchar *ptr, uint rbytes, uint c, uint ld_bytes, uint sg_id,
uint n_sg, uint sg_size, enum LSC_LDCC caching) {
const uint cl_per_col = (rbytes + 63) >> 6;
const uint cl = cl_per_col * c;
const uint cl_per_sg = (cl + n_sg - 1) / n_sg;
const uint cl_iters = (cl_per_sg + sg_size - 1) / sg_size;
#pragma unroll
for (uint ii_cl = 0; ii_cl < cl_iters; ii_cl++) {
uint i_cl = (ii_cl * cl_per_sg + sg_id) * sg_size
+ get_sub_group_local_id();
if (i_cl < cl) {
uint r_cl = i_cl % cl_per_col;
uint c_cl = i_cl / cl_per_col;
uint pf_off = r_cl * 64 + c_cl * ld_bytes;
const global uint *p = (const global uint *)(ptr + pf_off);
__builtin_IB_lsc_prefetch_global_uint(p, 0, caching);
}
}
}
__attribute__((overloadable)) void cooperative_prefetch_2d_internal(
const global uchar *ptr, uint rbytes, uint c, uint rbytes_max,
uint c_max, uint ld_bytes, uint sg_id, uint n_sg, uint sg_size,
enum LSC_LDCC caching) {
const uint cl_per_col = (rbytes_max + 63) >> 6;
const uint cl = cl_per_col * c_max;
const uint cl_per_sg = (cl + n_sg - 1) / n_sg;
const uint cl_iters = (cl_per_sg + sg_size - 1) / sg_size;
const uint max_off = rbytes - 1 + (c - 1) * ld_bytes;
#pragma unroll
for (uint ii_cl = 0; ii_cl < cl_iters; ii_cl++) {
uint i_cl = (ii_cl * cl_per_sg + sg_id) * sg_size
+ get_sub_group_local_id();
if (i_cl < cl) {
uint r_cl = i_cl % cl_per_col;
uint c_cl = i_cl / cl_per_col;
uint pf_off = min(r_cl * 64 + c_cl * ld_bytes, max_off);
const global uchar *pp = ptr + pf_off;
__builtin_IB_lsc_prefetch_global_uchar(pp, 0, caching);
}
}
}
#define DECLARE_2D_TILE_SLM_ADD(tile_type, element_type, sg, br, bc, nbr, nbc) \
__attribute__((overloadable)) inline void tile_slm_add(tile_type addend, \
local element_type *ptr, int ld, int offset_r, int offset_c) { \
ptr += ld * offset_c + offset_r; \
_Pragma("unroll") for (int j = 0; j < (bc) * (nbc); j++, ptr += ld) { \
_Pragma("unroll") for (int i0 = 0; i0 < (br) * (nbr); \
i0 += (sg)) { \
int i = i0 + get_sub_group_local_id(); \
ptr[i] += tile_access(addend, i0, j, sg, br, bc, nbr); \
} \
} \
}
#define DECLARE_2D_TILE_SLM_ADD_T( \
tile_type, element_type, sg, br, bc, nbr, nbc) \
__attribute__((overloadable)) inline void tile_slm_add_t(tile_type addend, \
local element_type *ptr, int ld, int offset_r, int offset_c) { \
ptr += ld * offset_r + offset_c; \
_Pragma("unroll") for (int j = 0; j < (bc) * (nbc); j++, ptr++) { \
_Pragma("unroll") for (int i0 = 0; i0 < (br) * (nbr); \
i0 += (sg)) { \
int i = ld * (i0 + get_sub_group_local_id()); \
ptr[i] += tile_access(addend, i0, j, sg, br, bc, nbr); \
} \
} \
}
#endif