Files
2026-07-13 13:33:03 +08:00

988 lines
54 KiB
Common Lisp
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifdef MNN_SUPPORT_FP16
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
#endif
#define GLOBAL_SIZE_3_DIMS \
__private const int global_size_dim0, __private const int global_size_dim1, __private const int global_size_dim2,
#define DEAL_NON_UNIFORM_DIM3(input1, input2, input3) \
if (input1 >= global_size_dim0 || input2 >= global_size_dim1 || input3 >= global_size_dim2) { \
return; \
}
#define GLOBAL_SIZE_2_DIMS \
__private const int global_size_dim0, __private const int global_size_dim1,
#define DEAL_NON_UNIFORM_DIM2(input1, input2) \
if (input1 >= global_size_dim0 || input2 >= global_size_dim1) { \
return; \
}
#define DEAL_OUTER_SEQLEN_NOT_ALIGN(length) \
if(4 * sl + 3 >= length) {\
temp_3 = (FLOAT4)0;\
}\
if(4 * sl + 2 >= length) {\
temp_2 = (FLOAT4)0;\
}\
if(4 * sl + 1 >= length) {\
temp_1 = (FLOAT4)0;\
}
#define DEAL_INNER_HEADDIM_NOT_ALIGN(length) \
if(hd * 4 + 3 >= length) {\
temp_0.w = (FLOAT)0;\
temp_1.w = (FLOAT)0;\
temp_2.w = (FLOAT)0;\
temp_3.w = (FLOAT)0;\
}\
if(hd * 4 + 2 >= length) {\
temp_0.z = (FLOAT)0;\
temp_1.z = (FLOAT)0;\
temp_2.z = (FLOAT)0;\
temp_3.z = (FLOAT)0;\
}\
if(hd * 4 + 1 >= length) {\
temp_0.y = (FLOAT)0;\
temp_1.y = (FLOAT)0;\
temp_2.y = (FLOAT)0;\
temp_3.y = (FLOAT)0;\
}
#ifdef VALUE_C4
static inline FLOAT load_c4_value(__global const FLOAT* value,
const int seq_storage,
const int token,
const int channel) {
return value[((channel >> 2) * seq_storage + token) * 4 + (channel & 3)];
}
static inline FLOAT4 load_c4_value4(__global const FLOAT* value,
const int seq_storage,
const int token,
const int channel,
const int head_dim_offset,
const int head_dim) {
return (FLOAT4)(
load_c4_value(value, seq_storage, token, channel),
(head_dim_offset + 1 >= head_dim) ? (FLOAT)0 : load_c4_value(value, seq_storage, token, channel + 1),
(head_dim_offset + 2 >= head_dim) ? (FLOAT)0 : load_c4_value(value, seq_storage, token, channel + 2),
(head_dim_offset + 3 >= head_dim) ? (FLOAT)0 : load_c4_value(value, seq_storage, token, channel + 3));
}
#endif
__kernel void rearrange_qkv(GLOBAL_SIZE_3_DIMS
__global const FLOAT *input_q, //[batch, seqLenQ/4, headNum, headDim, seqLenQ_4]
__global const FLOAT *input_k, // [batch, seqLenKV/4, headNum/group, headDim, seqLenKV_4]
__global const FLOAT *input_v, // [batch, seqLenKV/4, headNum/group, headDim, seqLenKV_4]
__global FLOAT *output_q, // [batch*headNum, ROUND_UP(headDim, mTileHDK), ROUND_UP(seqLenQ, mTileQ)]
__global FLOAT *output_k, // [batch*headNum/group, ROUND_UP(headDim, mTileHDK), ROUND_UP(seqLenKV, mTileKV)]
__global FLOAT *output_v, // [batch*headNum/group, ROUND_UP(seqLenKV, mTileKV), ROUND_UP(headDim, mTileHDN)]
#ifdef SAVE_KV
__global FLOAT *past_k, // [batch, headNum/group, headDim, seqLenKV_4]
__global FLOAT *past_v, // [batch, headNum/group, seqLenKV_4, headDim]
#endif
__private const int4 tile, // [mTileQ, mTileKV, mTileHDK, mTileHDN]
__private const int4 shape,// [seqLenQ, seqLenKV, headNum, headDim]
__private const int4 param, // [group, batch, max_len, past_len]
__private const int maxLenKV
) {
const int sl = get_global_id(0); // seqLen/4 : max(seqLenPackQ/4, seqLenPackKV/4)
const int hd = get_global_id(1); // headDim/4 : max(headDimPackQK/4, headDimPackV/4)
const int z = get_global_id(2); // batch * headNum
DEAL_NON_UNIFORM_DIM3(sl, hd, z);
const int seqLenQ = shape.x;
const int seqLenKV = shape.y;
const int headNum = shape.z;
const int headDim = shape.w;
const int group = param.x;
const int batch = param.y;
const int b = z % batch;
const int hn = z / batch;
const int seqLenQ_4 = (seqLenQ + 3) / 4;
//const int in_offset_q = (((b * seqLenQ_4 + sl) * headNum + hn) * headDim + 4 * hd) * 4;
const int in_offset_q = (((b * seqLenQ + sl * 4) * headNum + hn) * headDim + 4 * hd);
const int seqLenPackQ = ((seqLenQ + tile.x - 1) / tile.x) * tile.x;
const int headDimPackQK = ((headDim + tile.z - 1) / tile.z) * tile.z;
const int out_offset_q = (((b * headNum + hn) * headDimPackQK + hd * 4) * seqLenPackQ + sl * 4);
if(sl * 4 < seqLenPackQ && hd * 4 < headDimPackQK) {
if(sl * 4 >= seqLenQ || hd * 4 >= headDim) {
vstore4((FLOAT4)0, 0, output_q + out_offset_q);
vstore4((FLOAT4)0, 0, output_q + out_offset_q + seqLenPackQ);
vstore4((FLOAT4)0, 0, output_q + out_offset_q + 2 * seqLenPackQ);
vstore4((FLOAT4)0, 0, output_q + out_offset_q + 3 * seqLenPackQ);
} else {
FLOAT4 temp_0 = vload4(0, input_q + in_offset_q);
FLOAT4 temp_1 = (sl * 4 + 1 >= seqLenQ) ? (FLOAT4)0 : vload4(0, input_q + in_offset_q + headNum*headDim);
FLOAT4 temp_2 = (sl * 4 + 2 >= seqLenQ) ? (FLOAT4)0 : vload4(0, input_q + in_offset_q + 2*headNum*headDim);
FLOAT4 temp_3 = (sl * 4 + 3 >= seqLenQ) ? (FLOAT4)0 : vload4(0, input_q + in_offset_q + 3*headNum*headDim);
#ifdef HEADDIM_LEAVE
DEAL_INNER_HEADDIM_NOT_ALIGN(headDim)
#endif
#ifdef SEQLEN_LEAVE
DEAL_OUTER_SEQLEN_NOT_ALIGN(seqLenQ)
#endif
vstore4((FLOAT4)(temp_0.s0, temp_1.s0, temp_2.s0, temp_3.s0), 0, output_q + out_offset_q);
vstore4((FLOAT4)(temp_0.s1, temp_1.s1, temp_2.s1, temp_3.s1), 0, output_q + out_offset_q + seqLenPackQ);
vstore4((FLOAT4)(temp_0.s2, temp_1.s2, temp_2.s2, temp_3.s2), 0, output_q + out_offset_q + 2 * seqLenPackQ);
vstore4((FLOAT4)(temp_0.s3, temp_1.s3, temp_2.s3, temp_3.s3), 0, output_q + out_offset_q + 3 * seqLenPackQ);
}
}
if(hn >= headNum / group) {
return;
}
const int seqLenPackKV = ((seqLenKV + tile.y - 1) / tile.y) * tile.y;
const int headDimPackV = ((headDim + tile.w - 1) / tile.w) * tile.w;
const int seqLenKV_4 = (seqLenKV + 3) / 4;
const int in_offset_kv = (((b * seqLenKV + sl*4) * headNum/group + hn) * headDim + 4 * hd);
const int past_offset_k = (((b * headNum/group + hn) * headDim + hd * 4) * maxLenKV + sl*4);
const int past_offset_v = (((b * headNum/group + hn) * maxLenKV + sl*4) * headDim + 4 * hd);
if(sl * 4 < seqLenPackKV && hd * 4 < headDimPackQK) {
const int out_offset_k = (((b * headNum/group + hn) * headDimPackQK + hd * 4) * seqLenPackKV + sl * 4);
if(sl * 4 >= seqLenKV || hd * 4 >= headDim) {
vstore4((FLOAT4)0, 0, output_k + out_offset_k);
vstore4((FLOAT4)0, 0, output_k + out_offset_k + seqLenPackKV);
vstore4((FLOAT4)0, 0, output_k + out_offset_k + 2 * seqLenPackKV);
vstore4((FLOAT4)0, 0, output_k + out_offset_k + 3 * seqLenPackKV);
} else {
FLOAT4 temp_0 = vload4(0, input_k + in_offset_kv);
FLOAT4 temp_1 = (sl * 4 + 1 >= seqLenKV) ? (FLOAT4)0 : vload4(0, input_k + in_offset_kv + headNum*headDim/group);
FLOAT4 temp_2 = (sl * 4 + 2 >= seqLenKV) ? (FLOAT4)0 : vload4(0, input_k + in_offset_kv + 2*headNum*headDim/group);
FLOAT4 temp_3 = (sl * 4 + 3 >= seqLenKV) ? (FLOAT4)0 : vload4(0, input_k + in_offset_kv + 3*headNum*headDim/group);
#ifdef HEADDIM_LEAVE
DEAL_INNER_HEADDIM_NOT_ALIGN(headDim)
#endif
#ifdef SEQLEN_LEAVE
DEAL_OUTER_SEQLEN_NOT_ALIGN(seqLenKV)
#endif
FLOAT4 key0 = (FLOAT4)(temp_0.s0, temp_1.s0, temp_2.s0, temp_3.s0);
FLOAT4 key1 = (FLOAT4)(temp_0.s1, temp_1.s1, temp_2.s1, temp_3.s1);
FLOAT4 key2 = (FLOAT4)(temp_0.s2, temp_1.s2, temp_2.s2, temp_3.s2);
FLOAT4 key3 = (FLOAT4)(temp_0.s3, temp_1.s3, temp_2.s3, temp_3.s3);
vstore4(key0, 0, output_k + out_offset_k);
vstore4(key1, 0, output_k + out_offset_k + seqLenPackKV);
vstore4(key2, 0, output_k + out_offset_k + 2 * seqLenPackKV);
vstore4(key3, 0, output_k + out_offset_k + 3 * seqLenPackKV);
// pastK
#ifdef SAVE_KV
vstore4(key0, 0, past_k + past_offset_k);
vstore4(key1, 0, past_k + past_offset_k + maxLenKV);
vstore4(key2, 0, past_k + past_offset_k + 2*maxLenKV);
vstore4(key3, 0, past_k + past_offset_k + 3*maxLenKV);
#endif
}
}
if(sl * 4 < seqLenPackKV && hd * 4 < headDimPackV) {
const int out_offset_v = (((b * headNum/group + hn) * seqLenPackKV + sl * 4) * headDimPackV + hd * 4);
if(sl * 4 >= seqLenKV || hd * 4 >= headDim) {
vstore4((FLOAT4)0, 0, output_v + out_offset_v);
vstore4((FLOAT4)0, 0, output_v + out_offset_v + headDimPackV);
vstore4((FLOAT4)0, 0, output_v + out_offset_v + 2 * headDimPackV);
vstore4((FLOAT4)0, 0, output_v + out_offset_v + 3 * headDimPackV);
} else {
#ifdef VALUE_C4
const int value_seq_storage = batch * seqLenKV;
const int value_channel = hn * headDim + 4 * hd;
const int value_token = b * seqLenKV + sl * 4;
FLOAT4 temp_0 = load_c4_value4(input_v, value_seq_storage, value_token, value_channel, 4 * hd, headDim);
FLOAT4 temp_1 = (sl * 4 + 1 >= seqLenKV) ? (FLOAT4)0 :
load_c4_value4(input_v, value_seq_storage, value_token + 1, value_channel, 4 * hd, headDim);
FLOAT4 temp_2 = (sl * 4 + 2 >= seqLenKV) ? (FLOAT4)0 :
load_c4_value4(input_v, value_seq_storage, value_token + 2, value_channel, 4 * hd, headDim);
FLOAT4 temp_3 = (sl * 4 + 3 >= seqLenKV) ? (FLOAT4)0 :
load_c4_value4(input_v, value_seq_storage, value_token + 3, value_channel, 4 * hd, headDim);
#else
FLOAT4 temp_0 = vload4(0, input_v + in_offset_kv);
FLOAT4 temp_1 = (sl * 4 + 1 >= seqLenKV) ? (FLOAT4)0 : vload4(0, input_v + in_offset_kv + headNum*headDim/group);
FLOAT4 temp_2 = (sl * 4 + 2 >= seqLenKV) ? (FLOAT4)0 : vload4(0, input_v + in_offset_kv + 2*headNum*headDim/group);
FLOAT4 temp_3 = (sl * 4 + 3 >= seqLenKV) ? (FLOAT4)0 : vload4(0, input_v + in_offset_kv + 3*headNum*headDim/group);
#endif
#ifdef HEADDIM_LEAVE
DEAL_INNER_HEADDIM_NOT_ALIGN(headDim)
#endif
#ifdef SEQLEN_LEAVE
DEAL_OUTER_SEQLEN_NOT_ALIGN(seqLenKV)
#endif
vstore4(temp_0, 0, output_v + out_offset_v);
vstore4(temp_1, 0, output_v + out_offset_v + headDimPackV);
vstore4(temp_2, 0, output_v + out_offset_v + 2 * headDimPackV);
vstore4(temp_3, 0, output_v + out_offset_v + 3 * headDimPackV);
// pastV
#ifdef SAVE_KV
vstore4(temp_0, 0, past_v + past_offset_v);
vstore4(temp_1, 0, past_v + past_offset_v + headDim);
vstore4(temp_2, 0, past_v + past_offset_v + 2*headDim);
vstore4(temp_3, 0, past_v + past_offset_v + 3*headDim);
#endif
}
}
}
#ifndef MASK_DTYPE
#define MASK_DTYPE FLOAT
#define MASK_DTYPE4 FLOAT4
#endif
__kernel void rearrange_mask(GLOBAL_SIZE_3_DIMS
__global const MASK_DTYPE *input_mask, // [batch, 1, seqLenQ, seqLenKV, 4]
__global MASK_DTYPE *output_mask, // [batch, ROUND_UP(seqLenQ, mTileQ), ROUND_UP(seqLenKV, mTileKV)]
const int4 shape // [seqLenQ, seqLenKV, mTileQ, mTileKV]
) {
const int sl = get_global_id(0); // seqLen_4
const int sl_kv = get_global_id(1); // seqLenKV_4
const int b = get_global_id(2); // Batch
DEAL_NON_UNIFORM_DIM3(sl, sl_kv, b);
const int seq_len_pack = ((shape.x + shape.z - 1) / shape.z) * shape.z;
const int seq_len_kv_pack = ((shape.y + shape.w - 1) / shape.w) * shape.w;
int in_offset = ((b * shape.x + sl * 4) * shape.y + sl_kv * 4);
int out_offset = (b * seq_len_pack + sl * 4) * seq_len_kv_pack + sl_kv * 4;
if(sl * 4 >= shape.x || sl_kv * 4 >= shape.y) {
vstore4((MASK_DTYPE4)0, 0, output_mask + out_offset);
vstore4((MASK_DTYPE4)0, 0, output_mask + out_offset + seq_len_kv_pack);
vstore4((MASK_DTYPE4)0, 0, output_mask + out_offset + seq_len_kv_pack * 2);
vstore4((MASK_DTYPE4)0, 0, output_mask + out_offset + seq_len_kv_pack * 3);
} else {
int y_down_align4 = (shape.y / 4 * 4);
MASK_DTYPE4 temp_0, temp_1, temp_2, temp_3;
if(sl_kv * 4 < y_down_align4) {
temp_0 = vload4(0, input_mask + in_offset);
temp_1 = (sl * 4 + 1 >= shape.x) ? (MASK_DTYPE4)0 : vload4(0, input_mask + in_offset + shape.y);
temp_2 = (sl * 4 + 2 >= shape.x) ? (MASK_DTYPE4)0 : vload4(0, input_mask + in_offset + shape.y * 2);
temp_3 = (sl * 4 + 3 >= shape.x) ? (MASK_DTYPE4)0 : vload4(0, input_mask + in_offset + shape.y * 3);
} else if(sl_kv * 4 + 1 == shape.y){
temp_0 = (MASK_DTYPE4)(input_mask[in_offset], 0, 0, 0);
temp_1 = (sl * 4 + 1 >= shape.x) ? (MASK_DTYPE4)0 : (MASK_DTYPE4)(input_mask[in_offset + shape.y], 0, 0, 0);//vload4(0, input_mask + in_offset + shape.y);
temp_2 = (sl * 4 + 2 >= shape.x) ? (MASK_DTYPE4)0 : (MASK_DTYPE4)(input_mask[in_offset + shape.y*2], 0, 0, 0);//vload4(0, input_mask + in_offset + shape.y * 2);
temp_3 = (sl * 4 + 3 >= shape.x) ? (MASK_DTYPE4)0 : (MASK_DTYPE4)(input_mask[in_offset + shape.y*3], 0, 0, 0);//vload4(0, input_mask + in_offset + shape.y * 3);
} else if(sl_kv * 4 + 2 == shape.y){
temp_0 = (MASK_DTYPE4)(input_mask[in_offset], input_mask[in_offset+1], 0, 0);
temp_1 = (sl * 4 + 1 >= shape.x) ? (MASK_DTYPE4)0 : (FLOAT4)(input_mask[in_offset + shape.y], input_mask[in_offset + shape.y + 1], 0, 0);//vload4(0, input_mask + in_offset + shape.y);
temp_2 = (sl * 4 + 2 >= shape.x) ? (MASK_DTYPE4)0 : (MASK_DTYPE4)(input_mask[in_offset + shape.y*2], input_mask[in_offset + shape.y*2 + 1], 0, 0);//vload4(0, input_mask + in_offset + shape.y * 2);
temp_3 = (sl * 4 + 3 >= shape.x) ? (MASK_DTYPE4)0 : (MASK_DTYPE4)(input_mask[in_offset + shape.y*3], input_mask[in_offset + shape.y*3 + 1], 0, 0);//vload4(0, input_mask + in_offset + shape.y * 3);
} else if(sl_kv * 4 + 3 == shape.y){
temp_0 = (MASK_DTYPE4)(input_mask[in_offset], input_mask[in_offset+1], input_mask[in_offset+2], 0);
temp_1 = (sl * 4 + 1 >= shape.x) ? (MASK_DTYPE4)0 : (MASK_DTYPE4)(input_mask[in_offset + shape.y], input_mask[in_offset + shape.y + 1], input_mask[in_offset + shape.y + 2], 0);//vload4(0, input_mask + in_offset + shape.y);
temp_2 = (sl * 4 + 2 >= shape.x) ? (MASK_DTYPE4)0 : (MASK_DTYPE4)(input_mask[in_offset + shape.y*2], input_mask[in_offset + shape.y*2 + 1], input_mask[in_offset + shape.y*2 + 2], 0);//vload4(0, input_mask + in_offset + shape.y * 2);
temp_3 = (sl * 4 + 3 >= shape.x) ? (MASK_DTYPE4)0 : (MASK_DTYPE4)(input_mask[in_offset + shape.y*3], input_mask[in_offset + shape.y*3 + 1], input_mask[in_offset + shape.y*3 + 2], 0);//vload4(0, input_mask + in_offset + shape.y * 3);
}
vstore4(temp_0, 0, output_mask + out_offset);
vstore4(temp_1, 0, output_mask + out_offset + seq_len_kv_pack);
vstore4(temp_2, 0, output_mask + out_offset + 2 * seq_len_kv_pack);
vstore4(temp_3, 0, output_mask + out_offset + 3 * seq_len_kv_pack);
}
}
__kernel void qkv_transpose_output(GLOBAL_SIZE_3_DIMS
__global const FLOAT *input, // [Batch * mNumHead, ROUND_UP(mHeadDim, mTileHDN), ROUND_UP(seqLen, mTileQ)]
__global FLOAT *output, // [Batch, seqLen/4, mNumHead mHeadDim, 4] (or NC4HW4 when ATTENTION_C4)
__private const int tile_q,
__private const int tile_hdn,
__private const int seq_len,
__private const int head_num,
__private const int head_dim,
__private const int batch
) {
const int sl = get_global_id(0); // seqLen_4
const int hd = get_global_id(1); // mHeadDim_4
const int z = get_global_id(2); // Batch * mNumHead
DEAL_NON_UNIFORM_DIM3(sl, hd, z);
const int b = z / head_num;
const int hn = z % head_num;
const int seq_len_pack = ((seq_len + tile_q - 1) / tile_q) * tile_q;
const int head_dim_pack = ((head_dim + tile_hdn - 1) / tile_hdn) * tile_hdn;
const int offset_inp = ((b * head_num + hn) * head_dim_pack + 4 * hd) * seq_len_pack + 4 * sl;
// Q
FLOAT4 temp_0 = vload4(0, input + offset_inp);
FLOAT4 temp_1 = vload4(0, input + offset_inp + seq_len_pack);
FLOAT4 temp_2 = vload4(0, input + offset_inp + 2 * seq_len_pack);
FLOAT4 temp_3 = vload4(0, input + offset_inp + 3 * seq_len_pack);
#ifdef ATTENTION_C4
// output is NC4HW4: [(head_num*head_dim)/4, batch*seq_len, 4], channel = hn*head_dim + 4*hd.
// Must match matmul_qkv_prefill's ATTENTION_C4 output layout so o_proj reads it correctly.
const int channel4 = (hn * head_dim + 4 * hd) >> 2;
const int seq_storage = seq_len * batch;
const int output_offset = (channel4 * seq_storage + (b * seq_len + sl * 4)) * 4;
vstore4((FLOAT4)(temp_0.s0, temp_1.s0, temp_2.s0, temp_3.s0), 0, output + output_offset);
if(4 * sl + 1 >= seq_len) return;
vstore4((FLOAT4)(temp_0.s1, temp_1.s1, temp_2.s1, temp_3.s1), 0, output + output_offset + 4);
if(4 * sl + 2 >= seq_len) return;
vstore4((FLOAT4)(temp_0.s2, temp_1.s2, temp_2.s2, temp_3.s2), 0, output + output_offset + 8);
if(4 * sl + 3 >= seq_len) return;
vstore4((FLOAT4)(temp_0.s3, temp_1.s3, temp_2.s3, temp_3.s3), 0, output + output_offset + 12);
#else
const int offset_out = (((b * seq_len + sl*4) * head_num + hn) * head_dim + 4 * hd);
vstore4((FLOAT4)(temp_0.s0, temp_1.s0, temp_2.s0, temp_3.s0), 0, output + offset_out);
if(4 * sl + 1 >= seq_len) return;
vstore4((FLOAT4)(temp_0.s1, temp_1.s1, temp_2.s1, temp_3.s1), 0, output + offset_out + head_num*head_dim);
if(4 * sl + 2 >= seq_len) return;
vstore4((FLOAT4)(temp_0.s2, temp_1.s2, temp_2.s2, temp_3.s2), 0, output + offset_out + 2*head_num*head_dim);
if(4 * sl + 3 >= seq_len) return;
vstore4((FLOAT4)(temp_0.s3, temp_1.s3, temp_2.s3, temp_3.s3), 0, output + offset_out + 3*head_num*head_dim);
#endif
}
#ifndef NUMHEAD_GROUP_SIZE
#define NUMHEAD_GROUP_SIZE 1
#endif
__kernel void rearrange_q(GLOBAL_SIZE_3_DIMS
__global const FLOAT *query, // [batch query_seq_len head_num head_dim]
__global FLOAT *query_tmp, // [batch head_num head_dim_4 query_seq_len_4]
__private const int seq_len,
__private const int head_dim,
__private const int head_num) {
/*
the kernel assume head_dim is multiple of 4.
*/
const int x = get_global_id(0); // query_seq_len/4
const int y = get_global_id(1); // head_dim/4
int z = get_global_id(2);
DEAL_NON_UNIFORM_DIM3(x, y, z);
const int b = z / head_num;// batch
z = z % head_num;// head_num
const int x4 = x << 2;
const int y4 = y << 2;
const int seq_len4 = (seq_len + 3) / 4 * 4;;
const int stride = head_num * head_dim;
int query_offset = ((b * seq_len + x4) * head_num + z) * head_dim + y4;
FLOAT4 query_vec0 = vload4(0, query + query_offset); query_offset += stride;
FLOAT4 query_vec1 = (x4 + 1 >= seq_len) ? (FLOAT4)0 : vload4(0, query + query_offset); query_offset += stride;
FLOAT4 query_vec2 = (x4 + 2 >= seq_len) ? (FLOAT4)0 : vload4(0, query + query_offset); query_offset += stride;
FLOAT4 query_vec3 = (x4 + 3 >= seq_len) ? (FLOAT4)0 : vload4(0, query + query_offset);
const int queryout_offset = ((b * head_num + z) * head_dim + y4) * seq_len4 + x4;
vstore4((FLOAT4)(query_vec0.s0, query_vec1.s0, query_vec2.s0, query_vec3.s0), 0, query_tmp + queryout_offset);
vstore4((FLOAT4)(query_vec0.s1, query_vec1.s1, query_vec2.s1, query_vec3.s1), 0, query_tmp + queryout_offset + seq_len4);
vstore4((FLOAT4)(query_vec0.s2, query_vec1.s2, query_vec2.s2, query_vec3.s2), 0, query_tmp + queryout_offset + seq_len4 + seq_len4);
vstore4((FLOAT4)(query_vec0.s3, query_vec1.s3, query_vec2.s3, query_vec3.s3), 0, query_tmp + queryout_offset + seq_len4 + seq_len4 + seq_len4);
}
__kernel void rearrange_k(GLOBAL_SIZE_3_DIMS
__global const FLOAT *key, // [batch key_seq_len kv_head_num head_dim]
__global FLOAT *past_key, // [batch kv_head_num head_dim max_length]
__private const int past_len, // prefill = 0, decode = past_key len
__private const int max_len,
__private const int seq_len,
__private const int kv_head_num,
__private const int head_num,
__private const int head_dim) {
const int x = get_global_id(0); // seq_len decode = 1
const int y = get_global_id(1); // head_dim
int z = get_global_id(2); //
DEAL_NON_UNIFORM_DIM3(x, y, z);
const int b = z / kv_head_num;
z = z % kv_head_num;
const int y4 = y << 2;
#ifdef OPENCL_PREFILL_ATTENTION
const int x4 = x << 2;
const int stride = kv_head_num * head_dim;
int key_offset = ((b * seq_len + x4) * kv_head_num + z) * head_dim + y4;
FLOAT4 key_vec0 = vload4(0, key + key_offset); key_offset += stride;
FLOAT4 key_vec1 = (x4 + 1 >= seq_len) ? (FLOAT4)0 : vload4(0, key + key_offset); key_offset += stride;
FLOAT4 key_vec2 = (x4 + 2 >= seq_len) ? (FLOAT4)0 : vload4(0, key + key_offset); key_offset += stride;
FLOAT4 key_vec3 = (x4 + 3 >= seq_len) ? (FLOAT4)0 : vload4(0, key + key_offset);
const int output_offset = ((b * kv_head_num + z) * head_dim + y4) * max_len + past_len + x4;
vstore4((FLOAT4)(key_vec0.s0, key_vec1.s0, key_vec2.s0, key_vec3.s0), 0, past_key + output_offset);
vstore4((FLOAT4)(key_vec0.s1, key_vec1.s1, key_vec2.s1, key_vec3.s1), 0, past_key + output_offset + max_len);
vstore4((FLOAT4)(key_vec0.s2, key_vec1.s2, key_vec2.s2, key_vec3.s2), 0, past_key + output_offset + max_len + max_len);
vstore4((FLOAT4)(key_vec0.s3, key_vec1.s3, key_vec2.s3, key_vec3.s3), 0, past_key + output_offset + max_len + max_len + max_len);
#else
FLOAT4 key_vec = vload4(0, key + (b * kv_head_num + z) * head_dim + y4);
const int output_offset = ((b * kv_head_num + z) * head_dim + y4) * max_len + past_len;
past_key[output_offset] = key_vec.s0;
past_key[output_offset + max_len] = key_vec.s1;
past_key[output_offset + max_len + max_len] = key_vec.s2;
past_key[output_offset + max_len + max_len + max_len] = key_vec.s3;
#endif
}
__kernel void rearrange_v(GLOBAL_SIZE_3_DIMS
__global const FLOAT *value, // [batch value_seq_len kv_head_num head_dim]
__global FLOAT *past_value, // [batch kv_head_num max_length head_dim]
__private const int past_len,
__private const int max_len,
__private const int seq_len,
__private const int kv_head_num,
__private const int head_dim) {
const int x = get_global_id(0); // head_dim
const int y = get_global_id(1); // seq_len decode = 1
int z = get_global_id(2); // kv_head_num
DEAL_NON_UNIFORM_DIM3(x, y, z);
const int b = z / kv_head_num;
z = z % kv_head_num;
const int x4 = x << 2;
#ifdef OPENCL_PREFILL_ATTENTION
const int y4 = y << 2;
const int stride = kv_head_num * head_dim;
#ifdef VALUE_C4
const int value_seq_storage = (global_size_dim2 / kv_head_num) * seq_len;
const int value_channel = z * head_dim + x4;
const int value_token = b * seq_len + y4;
FLOAT4 value_vec0 = load_c4_value4(value, value_seq_storage, value_token, value_channel, x4, head_dim);
FLOAT4 value_vec1 = (y4 + 1 >= seq_len) ? (FLOAT4)0 :
load_c4_value4(value, value_seq_storage, value_token + 1, value_channel, x4, head_dim);
FLOAT4 value_vec2 = (y4 + 2 >= seq_len) ? (FLOAT4)0 :
load_c4_value4(value, value_seq_storage, value_token + 2, value_channel, x4, head_dim);
FLOAT4 value_vec3 = (y4 + 3 >= seq_len) ? (FLOAT4)0 :
load_c4_value4(value, value_seq_storage, value_token + 3, value_channel, x4, head_dim);
#else
int value_offset = ((b * seq_len + y4) * kv_head_num + z) * head_dim + x4;
FLOAT4 value_vec0 = vload4(0, value + value_offset); value_offset += stride;
FLOAT4 value_vec1 = (y4 + 1 >= seq_len) ? (FLOAT4)0 : vload4(0, value + value_offset); value_offset += stride;
FLOAT4 value_vec2 = (y4 + 2 >= seq_len) ? (FLOAT4)0 : vload4(0, value + value_offset); value_offset += stride;
FLOAT4 value_vec3 = (y4 + 3 >= seq_len) ? (FLOAT4)0 : vload4(0, value + value_offset);
#endif
const int output_offset = ((b * kv_head_num + z) * max_len + past_len + y4) * head_dim + x4;
vstore4(value_vec0, 0, past_value + output_offset);
vstore4(value_vec1, 0, past_value + output_offset + head_dim);
vstore4(value_vec2, 0, past_value + output_offset + head_dim + head_dim);
vstore4(value_vec3, 0, past_value + output_offset + head_dim + head_dim + head_dim);
#else
#ifdef VALUE_C4
const int value_seq_storage = (global_size_dim2 / kv_head_num) * seq_len;
const int value_channel = z * head_dim + x4;
const int value_token = b * seq_len;
FLOAT4 value_vec = load_c4_value4(value, value_seq_storage, value_token, value_channel, x4, head_dim);
#else
FLOAT4 value_vec = vload4(0, value + (b * kv_head_num + z) * head_dim + x4);
#endif
const int output_offset = ((b * kv_head_num + z) * max_len + past_len) * head_dim + x4;
vstore4(value_vec, 0, past_value + output_offset);
#endif
}
__kernel void rearrange_mask_shortprefill(GLOBAL_SIZE_3_DIMS
#ifdef ADD_MASK
__global const FLOAT* mask,
__global FLOAT* maskout,
#else
__global const int* mask, // [1 1 query_seq_len mask_key_seq_len4]
__global int* maskout, // [1 1 mask_key_seq_len4 query_seq_len4]
#endif
__private const int query_seq_len,
__private const int mask_key_seq_len){
const int x = get_global_id(0); // query_seq_len4
const int y = get_global_id(1); // mask_key_seq_len4
const int z = get_global_id(2); // batch
DEAL_NON_UNIFORM_DIM3(x, y, z);
const int x4 = x << 2;
const int y4 = y << 2;
float4 mask_tmp0, mask_tmp1, mask_tmp2, mask_tmp3;
float4 mask0, mask1, mask2, mask3;
int mask_offset = x4 * mask_key_seq_len + y4;
if(x4 + 3 < query_seq_len && y4 + 3 < mask_key_seq_len){
mask_tmp0 = convert_float4(vload4(0, mask + mask_offset)); mask_offset += mask_key_seq_len;
mask_tmp1 = convert_float4(vload4(0, mask + mask_offset)); mask_offset += mask_key_seq_len;
mask_tmp2 = convert_float4(vload4(0, mask + mask_offset)); mask_offset += mask_key_seq_len;
mask_tmp3 = convert_float4(vload4(0, mask + mask_offset));
} else{
if(y4 + 3 < mask_key_seq_len){
mask_tmp0 = convert_float4(vload4(0, mask + mask_offset)); mask_offset += mask_key_seq_len;
mask_tmp1 = (x4 + 1 >= query_seq_len) ? (float4)0 : convert_float4(vload4(0, mask + mask_offset)); mask_offset += mask_key_seq_len;
mask_tmp2 = (x4 + 2 >= query_seq_len) ? (float4)0 : convert_float4(vload4(0, mask + mask_offset)); mask_offset += mask_key_seq_len;
mask_tmp3 = (x4 + 3 >= query_seq_len) ? (float4)0 : convert_float4(vload4(0, mask + mask_offset));
} else if(y4 + 1 == mask_key_seq_len){
mask_tmp0 = (float4)(mask[mask_offset], 0, 0, 0); mask_offset += mask_key_seq_len;
mask_tmp1 = (x4 + 1 >= query_seq_len) ? (float4)0 : (float4)(mask[mask_offset], 0, 0, 0); mask_offset += mask_key_seq_len;
mask_tmp2 = (x4 + 2 >= query_seq_len) ? (float4)0 : (float4)(mask[mask_offset], 0, 0, 0); mask_offset += mask_key_seq_len;
mask_tmp3 = (x4 + 3 >= query_seq_len) ? (float4)0 : (float4)(mask[mask_offset], 0, 0, 0);
}else if(y4 + 2 == mask_key_seq_len){
mask_tmp0 = (float4)(mask[mask_offset], mask[mask_offset + 1], 0, 0); mask_offset += mask_key_seq_len;
mask_tmp1 = (x4 + 1 >= query_seq_len) ? (float4)0 : (float4)(mask[mask_offset], mask[mask_offset + 1], 0, 0); mask_offset += mask_key_seq_len;
mask_tmp2 = (x4 + 2 >= query_seq_len) ? (float4)0 : (float4)(mask[mask_offset], mask[mask_offset + 1], 0, 0); mask_offset += mask_key_seq_len;
mask_tmp3 = (x4 + 3 >= query_seq_len) ? (float4)0 : (float4)(mask[mask_offset], mask[mask_offset + 1], 0, 0);
}else if(y4 + 3 == mask_key_seq_len){
mask_tmp0 = (float4)(mask[mask_offset], mask[mask_offset + 1], mask[mask_offset + 2], 0); mask_offset += mask_key_seq_len;
mask_tmp1 = (x4 + 1 >= query_seq_len) ? (float4)0 : (float4)(mask[mask_offset], mask[mask_offset + 1], mask[mask_offset + 2], 0); mask_offset += mask_key_seq_len;
mask_tmp2 = (x4 + 2 >= query_seq_len) ? (float4)0 : (float4)(mask[mask_offset], mask[mask_offset + 1], mask[mask_offset + 2], 0); mask_offset += mask_key_seq_len;
mask_tmp3 = (x4 + 3 >= query_seq_len) ? (float4)0 : (float4)(mask[mask_offset], mask[mask_offset + 1], mask[mask_offset + 2], 0);
}
}
mask0 = (float4)(mask_tmp0.s0, mask_tmp1.s0, mask_tmp2.s0, mask_tmp3.s0);
mask1 = (float4)(mask_tmp0.s1, mask_tmp1.s1, mask_tmp2.s1, mask_tmp3.s1);
mask2 = (float4)(mask_tmp0.s2, mask_tmp1.s2, mask_tmp2.s2, mask_tmp3.s2);
mask3 = (float4)(mask_tmp0.s3, mask_tmp1.s3, mask_tmp2.s3, mask_tmp3.s3);
int query_seq_len4 = ((query_seq_len + 3) / 4) * 4;
int output_offset = y4 * query_seq_len4 + x4;
#ifdef ADD_MASK
vstore4(CONVERT_FLOAT4(mask0), 0, maskout + output_offset);
vstore4(CONVERT_FLOAT4(mask1), 0, maskout + output_offset + query_seq_len4);
vstore4(CONVERT_FLOAT4(mask2), 0, maskout + output_offset + query_seq_len4 + query_seq_len4);
vstore4(CONVERT_FLOAT4(mask3), 0, maskout + output_offset + query_seq_len4 + query_seq_len4 + query_seq_len4);
#else
vstore4(convert_int4(mask0), 0, maskout + output_offset);
vstore4(convert_int4(mask1), 0, maskout + output_offset + query_seq_len4);
vstore4(convert_int4(mask2), 0, maskout + output_offset + query_seq_len4 + query_seq_len4);
vstore4(convert_int4(mask3), 0, maskout + output_offset + query_seq_len4 + query_seq_len4 + query_seq_len4);
#endif
}
__kernel void matmul_qk_div_mask_prefill(GLOBAL_SIZE_3_DIMS
__global const FLOAT *query, // [batch head_num head_dim_4 query_seq_len_4]
__global const FLOAT *past_key, // [batch kv_head_num head_dim_4 kv_max_length]
#ifdef ADD_MASK
__global const FLOAT* mask,
#elif defined(SET_MASK)
__global const int* mask, // [1 1 query_seq_len mask_key_seq_len]
#else
__global const FLOAT* mask,
#endif
__global FLOAT *qk, // [batch head_num kv_seq_length query_seq_len_4]
__private const float scale,
__private const int query_seq_len,
__private const int mask_key_seq_len,
__private const int key_seq_len,
__private const int max_len,
__private const int head_num,
__private const int head_dim) {
const int x = get_global_id(0); // query_seq_len
const int y = get_global_id(1); // kv_seq_length
const int z = get_global_id(2); // head_num * batch
DEAL_NON_UNIFORM_DIM3(x, y, z);
const int x4 = x << 2;
const int y4 = y << 2;
const int query_seq_len4 = (query_seq_len + 3) / 4 * 4;;
const int query_offset = z * head_dim * query_seq_len4 + x4;
const int past_offset = (z / NUMHEAD_GROUP_SIZE) * head_dim * max_len + y4;
float4 out0 = 0, out1 = 0, out2 = 0, out3 = 0;
for(int i = 0; i < head_dim / 4; ++i){
int i4 = i << 2;
float4 query_vec0 = convert_float4(vload4(0, query + query_offset + i4 * query_seq_len4));
float4 query_vec1 = convert_float4(vload4(0, query + query_offset + (i4 + 1) * query_seq_len4));
float4 query_vec2 = convert_float4(vload4(0, query + query_offset + (i4 + 2) * query_seq_len4));
float4 query_vec3 = convert_float4(vload4(0, query + query_offset + (i4 + 3) * query_seq_len4));
float4 past_vec0 = convert_float4(vload4(0, past_key + past_offset + i4 * max_len));
float4 past_vec1 = convert_float4(vload4(0, past_key + past_offset + (i4 + 1) * max_len));
float4 past_vec2 = convert_float4(vload4(0, past_key + past_offset + (i4 + 2) * max_len));
float4 past_vec3 = convert_float4(vload4(0, past_key + past_offset + (i4 + 3) * max_len));
out0 = mad((float4)past_vec0.s0, query_vec0, out0);
out0 = mad((float4)past_vec1.s0, query_vec1, out0);
out0 = mad((float4)past_vec2.s0, query_vec2, out0);
out0 = mad((float4)past_vec3.s0, query_vec3, out0);
out1 = mad((float4)past_vec0.s1, query_vec0, out1);
out1 = mad((float4)past_vec1.s1, query_vec1, out1);
out1 = mad((float4)past_vec2.s1, query_vec2, out1);
out1 = mad((float4)past_vec3.s1, query_vec3, out1);
out2 = mad((float4)past_vec0.s2, query_vec0, out2);
out2 = mad((float4)past_vec1.s2, query_vec1, out2);
out2 = mad((float4)past_vec2.s2, query_vec2, out2);
out2 = mad((float4)past_vec3.s2, query_vec3, out2);
out3 = mad((float4)past_vec0.s3, query_vec0, out3);
out3 = mad((float4)past_vec1.s3, query_vec1, out3);
out3 = mad((float4)past_vec2.s3, query_vec2, out3);
out3 = mad((float4)past_vec3.s3, query_vec3, out3);
}
out0 *= (float4)scale;
out1 *= (float4)scale;
out2 *= (float4)scale;
out3 *= (float4)scale;
{
#if defined(ADD_MASK) || defined(SET_MASK)
int query_seq_len4 = ((query_seq_len + 3) / 4) * 4;
int mask_clp = y4 + mask_key_seq_len - key_seq_len;
int mask_offset = mask_clp * query_seq_len4 + x4;
float4 mask0 = mask_clp >= 0 && mask_clp < mask_key_seq_len ? convert_float4(vload4(0, mask + mask_offset)) : 0; mask_offset += query_seq_len4;
float4 mask1 = mask_clp + 1 >= 0 && mask_clp + 1 < mask_key_seq_len? convert_float4(vload4(0, mask + mask_offset)) : 0; mask_offset += query_seq_len4;
float4 mask2 = mask_clp + 2 >= 0 && mask_clp + 2 < mask_key_seq_len? convert_float4(vload4(0, mask + mask_offset)) : 0; mask_offset += query_seq_len4;
float4 mask3 = mask_clp + 3 >= 0 && mask_clp + 3 < mask_key_seq_len? convert_float4(vload4(0, mask + mask_offset)) : 0;
#endif
#ifdef ADD_MASK
out0 += mask0;
out1 += mask1;
out2 += mask2;
out3 += mask3;
#elif defined(SET_MASK)
out0 = (mask0 == (float4)0) ? (float4)(-FLT_MAX) : out0;
out1 = (mask1 == (float4)0) ? (float4)(-FLT_MAX) : out1;
out2 = (mask2 == (float4)0) ? (float4)(-FLT_MAX) : out2;
out3 = (mask3 == (float4)0) ? (float4)(-FLT_MAX) : out3;
#elif defined(DEFAULT_MASK)
{
int kv_valid_offset = key_seq_len - query_seq_len;
int k0 = y4 + 0;
int k1 = y4 + 1;
int k2 = y4 + 2;
int k3 = y4 + 3;
int q0 = x4 + 0;
int q1 = x4 + 1;
int q2 = x4 + 2;
int q3 = x4 + 3;
if (k0 > kv_valid_offset + q0) { out0.s0 = -FLT_MAX; }
if (k1 > kv_valid_offset + q0) { out1.s0 = -FLT_MAX; }
if (k2 > kv_valid_offset + q0) { out2.s0 = -FLT_MAX; }
if (k3 > kv_valid_offset + q0) { out3.s0 = -FLT_MAX; }
if (k0 > kv_valid_offset + q1) { out0.s1 = -FLT_MAX; }
if (k1 > kv_valid_offset + q1) { out1.s1 = -FLT_MAX; }
if (k2 > kv_valid_offset + q1) { out2.s1 = -FLT_MAX; }
if (k3 > kv_valid_offset + q1) { out3.s1 = -FLT_MAX; }
if (k0 > kv_valid_offset + q2) { out0.s2 = -FLT_MAX; }
if (k1 > kv_valid_offset + q2) { out1.s2 = -FLT_MAX; }
if (k2 > kv_valid_offset + q2) { out2.s2 = -FLT_MAX; }
if (k3 > kv_valid_offset + q2) { out3.s2 = -FLT_MAX; }
if (k0 > kv_valid_offset + q3) { out0.s3 = -FLT_MAX; }
if (k1 > kv_valid_offset + q3) { out1.s3 = -FLT_MAX; }
if (k2 > kv_valid_offset + q3) { out2.s3 = -FLT_MAX; }
if (k3 > kv_valid_offset + q3) { out3.s3 = -FLT_MAX; }
}
#endif
}
const int qk_offset = (z * key_seq_len + y4) * query_seq_len4 + x4;
vstore4(CONVERT_FLOAT4(out0), 0, qk + qk_offset);
if(y4 + 1 >= key_seq_len) return;
vstore4(CONVERT_FLOAT4(out1), 0, qk + qk_offset + query_seq_len4);
if(y4 + 2 >= key_seq_len) return;
vstore4(CONVERT_FLOAT4(out2), 0, qk + qk_offset + query_seq_len4 + query_seq_len4);
if(y4 + 3 >= key_seq_len) return;
vstore4(CONVERT_FLOAT4(out3), 0, qk + qk_offset + query_seq_len4 + query_seq_len4 + query_seq_len4);
}
__kernel void matmul_qk_decode(GLOBAL_SIZE_2_DIMS
__global const FLOAT *query, // key [1 head_num head_dim]
__global const FLOAT *past_key, // [1 head_num head_dim max_length]
__global FLOAT *qk, // [1 head_num key_seq_len 1]
__private const float scale,
__private const int seq_len,
__private const int max_len,
__private const int head_num,
__private const int head_dim) {
const int x = get_global_id(0); // key_seq_len
const int y = get_global_id(1); // head_num
DEAL_NON_UNIFORM_DIM2(x, y);
const int x4 = x << 2;
const int query_offset = y * head_dim;
const int past_offset = (y / NUMHEAD_GROUP_SIZE) * head_dim * max_len + x4;
float4 out0 = 0;
for(int i = 0; i < head_dim / 4; ++i){
int i4 = i << 2;
float4 query_vec = convert_float4(vload4(0, query + query_offset + i4));
float4 past_vec0 = convert_float4(vload4(0, past_key + past_offset + i4 * max_len));
float4 past_vec1 = convert_float4(vload4(0, past_key + past_offset + (i4 + 1) * max_len));
float4 past_vec2 = convert_float4(vload4(0, past_key + past_offset + (i4 + 2) * max_len));
float4 past_vec3 = convert_float4(vload4(0, past_key + past_offset + (i4 + 3) * max_len));
out0 = mad((float4)query_vec.s0, past_vec0, out0);
out0 = mad((float4)query_vec.s1, past_vec1, out0);
out0 = mad((float4)query_vec.s2, past_vec2, out0);
out0 = mad((float4)query_vec.s3, past_vec3, out0);
}
out0 *= (float4)scale;
const int qk_offset = y * seq_len + x4;
if(x4 + 3 < seq_len){
vstore4(CONVERT_FLOAT4(out0), 0, qk + qk_offset);
}else {
int remain = seq_len - x4;
if(remain == 3){
vstore3(CONVERT_FLOAT3((float3)(out0.s012)), 0, qk + qk_offset);
} else if(remain == 2){
vstore2(CONVERT_FLOAT2((float2)(out0.s01)), 0, qk + qk_offset);
}else if(remain == 1){
qk[qk_offset] = out0.s0;
}
}
}
__kernel void matmul_qkv_prefill(GLOBAL_SIZE_3_DIMS
__global const FLOAT *qk, // qk prefill [batch head_num kv_seq_length query_seq_len]
__global const FLOAT *past_value, // [batch kv_head_num max_len head_dim]
__global FLOAT *output, // [batch query_seq_len head_num head_dim]
__private const int query_seq_len,
__private const int kv_seq_len,
__private const int max_len,
__private const int head_num,
__private const int kv_head_num,
__private const int head_dim,
__private const int batch) {
const int x = get_global_id(0); // head_dim
const int y = get_global_id(1); // query_seq_len
int z = get_global_id(2); // head_num * batch
DEAL_NON_UNIFORM_DIM3(x, y, z);
const int b = z / head_num;
z = z % head_num;
const int x8 = x << 3;
const int y4 = y << 2;
const int query_seq_len4 = (query_seq_len + 3) / 4 * 4;
const int qk_offset = (b * head_num + z) * kv_seq_len * query_seq_len4 + y4;
const int past_offset = ((b * kv_head_num + z / NUMHEAD_GROUP_SIZE) * max_len) * head_dim + x8;
const int loop_end = max(kv_seq_len / 4 - 1, 0);
COMPUTE_FLOAT8 out0 = 0, out1 = 0, out2 = 0, out3 = 0;
for(int i = 0; i < loop_end; ++i){
int i4 = i << 2;
COMPUTE_FLOAT4 qk_vec0 = CONVERT_COMPUTE_FLOAT4(vload4(0, qk + qk_offset + i4 * query_seq_len4));
COMPUTE_FLOAT4 qk_vec1 = CONVERT_COMPUTE_FLOAT4(vload4(0, qk + qk_offset + (i4 + 1) * query_seq_len4));
COMPUTE_FLOAT4 qk_vec2 = CONVERT_COMPUTE_FLOAT4(vload4(0, qk + qk_offset + (i4 + 2) * query_seq_len4));
COMPUTE_FLOAT4 qk_vec3 = CONVERT_COMPUTE_FLOAT4(vload4(0, qk + qk_offset + (i4 + 3) * query_seq_len4));
COMPUTE_FLOAT8 past_vec0 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + i4 * head_dim));
COMPUTE_FLOAT8 past_vec1 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i4 + 1) * head_dim));
COMPUTE_FLOAT8 past_vec2 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i4 + 2) * head_dim));
COMPUTE_FLOAT8 past_vec3 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i4 + 3) * head_dim));
out0 = mad((COMPUTE_FLOAT8)qk_vec0.s0, past_vec0, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec1.s0, past_vec1, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec2.s0, past_vec2, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec3.s0, past_vec3, out0);
out1 = mad((COMPUTE_FLOAT8)qk_vec0.s1, past_vec0, out1);
out1 = mad((COMPUTE_FLOAT8)qk_vec1.s1, past_vec1, out1);
out1 = mad((COMPUTE_FLOAT8)qk_vec2.s1, past_vec2, out1);
out1 = mad((COMPUTE_FLOAT8)qk_vec3.s1, past_vec3, out1);
out2 = mad((COMPUTE_FLOAT8)qk_vec0.s2, past_vec0, out2);
out2 = mad((COMPUTE_FLOAT8)qk_vec1.s2, past_vec1, out2);
out2 = mad((COMPUTE_FLOAT8)qk_vec2.s2, past_vec2, out2);
out2 = mad((COMPUTE_FLOAT8)qk_vec3.s2, past_vec3, out2);
out3 = mad((COMPUTE_FLOAT8)qk_vec0.s3, past_vec0, out3);
out3 = mad((COMPUTE_FLOAT8)qk_vec1.s3, past_vec1, out3);
out3 = mad((COMPUTE_FLOAT8)qk_vec2.s3, past_vec2, out3);
out3 = mad((COMPUTE_FLOAT8)qk_vec3.s3, past_vec3, out3);
}
for(int i = (loop_end << 2); i < kv_seq_len; ++i){
COMPUTE_FLOAT4 qk_vec = CONVERT_COMPUTE_FLOAT4(vload4(0, qk + qk_offset + i * query_seq_len4));
COMPUTE_FLOAT8 past_vec = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + i * head_dim));
out0 = mad((COMPUTE_FLOAT8)qk_vec.s0, past_vec, out0);
out1 = mad((COMPUTE_FLOAT8)qk_vec.s1, past_vec, out1);
out2 = mad((COMPUTE_FLOAT8)qk_vec.s2, past_vec, out2);
out3 = mad((COMPUTE_FLOAT8)qk_vec.s3, past_vec, out3);
}
#ifdef ATTENTION_C4
int output_offset = (z * head_dim + x8) * query_seq_len * batch + (b * query_seq_len + y4) * 4;
const int stride = query_seq_len * batch * 4;
vstore4(CONVERT_FLOAT4(out0.lo), 0, output + output_offset);
vstore4(CONVERT_FLOAT4(out0.hi), 0, output + output_offset + stride);
if(y4 + 1 >= query_seq_len) return;
output_offset += 4;
vstore4(CONVERT_FLOAT4(out1.lo), 0, output + output_offset);
vstore4(CONVERT_FLOAT4(out1.hi), 0, output + output_offset + stride);
if(y4 + 2 >= query_seq_len) return;
output_offset += 4;
vstore4(CONVERT_FLOAT4(out2.lo), 0, output + output_offset);
vstore4(CONVERT_FLOAT4(out2.hi), 0, output + output_offset + stride);
if(y4 + 3 >= query_seq_len) return;
output_offset += 4;
vstore4(CONVERT_FLOAT4(out3.lo), 0, output + output_offset);
vstore4(CONVERT_FLOAT4(out3.hi), 0, output + output_offset + stride);
#else
const int output_offset = ((b * query_seq_len + y4) * head_num + z) * head_dim + x8;
const int stride = head_num * head_dim;
vstore8(CONVERT_FLOAT8(out0), 0, output + output_offset);
if(y4 + 1 >= query_seq_len) return;
vstore8(CONVERT_FLOAT8(out1), 0, output + output_offset + stride);
if(y4 + 2 >= query_seq_len) return;
vstore8(CONVERT_FLOAT8(out2), 0, output + output_offset + stride + stride);
if(y4 + 3 >= query_seq_len) return;
vstore8(CONVERT_FLOAT8(out3), 0, output + output_offset + stride + stride + stride);
#endif
}
__kernel void matmul_qkv_decode_b8(GLOBAL_SIZE_2_DIMS
__global const FLOAT *qk, // qk [1 head_num qk_seq_len 1]
__global const FLOAT *past_value, // [1 head_num max_len head_dim]
__global FLOAT *output, // [1 1 head_num head_dim]
__private const int qk_seq_len,
__private const int max_len,
__private const int head_num,
__private const int kv_head_num,
__private const int head_dim) {
const int x = get_global_id(0); // head_dim
const int y = get_global_id(1); // head_num
DEAL_NON_UNIFORM_DIM2(x, y);
const int x8 = x << 3;
const int qk_offset = y * qk_seq_len;
const int past_offset = ((y / NUMHEAD_GROUP_SIZE) * max_len) * head_dim + x8;
COMPUTE_FLOAT8 out0 = 0;
#ifdef LOOP_UNROLL_4
const int loop_end = max((qk_seq_len + 3) / 4 - 1, 0);
for(int i = 0; i < loop_end; ++i){
int i4 = i << 2;
COMPUTE_FLOAT4 qk_vec = CONVERT_COMPUTE_FLOAT4(vload4(0, qk + qk_offset + i4));
COMPUTE_FLOAT8 past_vec0 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + i4 * head_dim));
COMPUTE_FLOAT8 past_vec1 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i4 + 1) * head_dim));
COMPUTE_FLOAT8 past_vec2 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i4 + 2) * head_dim));
COMPUTE_FLOAT8 past_vec3 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i4 + 3) * head_dim));
out0 = mad((COMPUTE_FLOAT8)qk_vec.s0, past_vec0, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s1, past_vec1, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s2, past_vec2, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s3, past_vec3, out0);
}
for(int i = (loop_end << 2); i < qk_seq_len; ++i){
COMPUTE_FLOAT qk_vec = qk[qk_offset + i];
COMPUTE_FLOAT8 past_vec = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + i * head_dim));
out0 = mad((COMPUTE_FLOAT8)qk_vec, past_vec, out0);
}
#elif (defined LOOP_UNROLL_8)
const int loop_end = max((qk_seq_len + 7) / 8 - 1, 0);
for(int i = 0; i < loop_end; ++i){
int i8 = i << 3;
COMPUTE_FLOAT8 qk_vec = CONVERT_COMPUTE_FLOAT8(vload8(0, qk + qk_offset + i8));
COMPUTE_FLOAT8 past_vec0 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + i8 * head_dim));
COMPUTE_FLOAT8 past_vec1 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i8 + 1) * head_dim));
COMPUTE_FLOAT8 past_vec2 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i8 + 2) * head_dim));
COMPUTE_FLOAT8 past_vec3 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i8 + 3) * head_dim));
COMPUTE_FLOAT8 past_vec4 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i8 + 4) * head_dim));
COMPUTE_FLOAT8 past_vec5 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i8 + 5) * head_dim));
COMPUTE_FLOAT8 past_vec6 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i8 + 6) * head_dim));
COMPUTE_FLOAT8 past_vec7 = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + (i8 + 7) * head_dim));
out0 = mad((COMPUTE_FLOAT8)qk_vec.s0, past_vec0, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s1, past_vec1, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s2, past_vec2, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s3, past_vec3, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s4, past_vec4, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s5, past_vec5, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s6, past_vec6, out0);
out0 = mad((COMPUTE_FLOAT8)qk_vec.s7, past_vec7, out0);
}
for(int i = (loop_end << 3); i < qk_seq_len; ++i){
COMPUTE_FLOAT qk_vec = qk[qk_offset + i];
COMPUTE_FLOAT8 past_vec = CONVERT_COMPUTE_FLOAT8(vload8(0, past_value + past_offset + i * head_dim));
out0 = mad((COMPUTE_FLOAT8)qk_vec, past_vec, out0);
}
#endif
const int output_offset = y * head_dim + x8;
vstore8(CONVERT_FLOAT8(out0), 0, output + output_offset);
}
__kernel void matmul_qkv_decode_b4(GLOBAL_SIZE_2_DIMS
__global const FLOAT *qk, // qk [1 head_num qk_seq_len 1]
__global const FLOAT *past_value, // [1 head_num max_len head_dim]
__global FLOAT *output, // [1 1 head_num head_dim]
__private const int qk_seq_len,
__private const int max_len,
__private const int head_num,
__private const int kv_head_num,
__private const int head_dim) {
const int x = get_global_id(0); // head_dim
const int y = get_global_id(1); // head_num
DEAL_NON_UNIFORM_DIM2(x, y);
const int x4 = x << 2;
const int qk_offset = y * qk_seq_len;
const int past_offset = ((y / NUMHEAD_GROUP_SIZE) * max_len) * head_dim + x4;
COMPUTE_FLOAT4 out0 = 0;
#ifdef LOOP_UNROLL_4
const int loop_end = max((qk_seq_len + 3) / 4 - 1, 0);
for(int i = 0; i < loop_end; ++i){
int i4 = i << 2;
COMPUTE_FLOAT4 qk_vec = CONVERT_COMPUTE_FLOAT4(vload4(0, qk + qk_offset + i4));
COMPUTE_FLOAT4 past_vec0 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + i4 * head_dim));
COMPUTE_FLOAT4 past_vec1 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i4 + 1) * head_dim));
COMPUTE_FLOAT4 past_vec2 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i4 + 2) * head_dim));
COMPUTE_FLOAT4 past_vec3 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i4 + 3) * head_dim));
out0 = mad((COMPUTE_FLOAT4)qk_vec.s0, past_vec0, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s1, past_vec1, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s2, past_vec2, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s3, past_vec3, out0);
}
for(int i = (loop_end << 2); i < qk_seq_len; ++i){
COMPUTE_FLOAT qk_vec = qk[qk_offset + i];
COMPUTE_FLOAT4 past_vec = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + i * head_dim));
out0 = mad((COMPUTE_FLOAT4)qk_vec, past_vec, out0);
}
#elif (defined LOOP_UNROLL_8)
const int loop_end = max((qk_seq_len + 7) / 8 - 1, 0);
for(int i = 0; i < loop_end; ++i){
int i8 = i << 3;
COMPUTE_FLOAT8 qk_vec = CONVERT_COMPUTE_FLOAT8(vload8(0, qk + qk_offset + i8));
COMPUTE_FLOAT4 past_vec0 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + i8 * head_dim));
COMPUTE_FLOAT4 past_vec1 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i8 + 1) * head_dim));
COMPUTE_FLOAT4 past_vec2 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i8 + 2) * head_dim));
COMPUTE_FLOAT4 past_vec3 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i8 + 3) * head_dim));
COMPUTE_FLOAT4 past_vec4 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i8 + 4) * head_dim));
COMPUTE_FLOAT4 past_vec5 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i8 + 5) * head_dim));
COMPUTE_FLOAT4 past_vec6 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i8 + 6) * head_dim));
COMPUTE_FLOAT4 past_vec7 = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + (i8 + 7) * head_dim));
out0 = mad((COMPUTE_FLOAT4)qk_vec.s0, past_vec0, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s1, past_vec1, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s2, past_vec2, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s3, past_vec3, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s4, past_vec4, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s5, past_vec5, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s6, past_vec6, out0);
out0 = mad((COMPUTE_FLOAT4)qk_vec.s7, past_vec7, out0);
}
for(int i = (loop_end << 3); i < qk_seq_len; ++i){
COMPUTE_FLOAT qk_vec = qk[qk_offset + i];
COMPUTE_FLOAT4 past_vec = CONVERT_COMPUTE_FLOAT4(vload4(0, past_value + past_offset + i * head_dim));
out0 = mad((COMPUTE_FLOAT4)qk_vec, past_vec, out0);
}
#endif
const int output_offset = y * head_dim + x4;
vstore4(CONVERT_FLOAT4(out0), 0, output + output_offset);
}