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

1419 lines
65 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_DIM2 \
__private int global_size_dim0, __private int global_size_dim1,
#define UNIFORM_BOUNDRY_CHECK(index0, index1) \
if(index0 >= global_size_dim0 || index1 >= global_size_dim1) { \
return; \
}
#define UCHAR4_TO_CHAR8(a, c) \
a.s0 = (c.s0 >> 4); a.s1 = (c.s0 & 15); a.s2 = (c.s1 >> 4); a.s3 = (c.s1 & 15); a.s4 = (c.s2 >> 4); a.s5 = (c.s2 & 15); a.s6 = (c.s3 >> 4); a.s7 = (c.s3 & 15);
// 2bit unpack: 2 packed bytes (b0,b1) → 8 chars, unsigned [0,3].
// Origin offset is folded into the dequant `offset` (or asym bias) by the caller.
#define UCHAR2_TO_CHAR8_W2(a, b0, b1) \
a.s0 = (char)((b0 >> 6) & 3); \
a.s1 = (char)((b0 >> 4) & 3); \
a.s2 = (char)((b0 >> 2) & 3); \
a.s3 = (char)((b0 >> 0) & 3); \
a.s4 = (char)((b1 >> 6) & 3); \
a.s5 = (char)((b1 >> 4) & 3); \
a.s6 = (char)((b1 >> 2) & 3); \
a.s7 = (char)((b1 >> 0) & 3);
// 3bit unpack: 2 low bytes + 1 high byte → 8 chars, unsigned [0,7].
// Origin offset is folded into the dequant `offset` (or asym bias) by the caller.
#define UCHAR3_TO_CHAR8_W3(a, b0, b1, h) \
a.s0 = (char)(((b0 >> 6) & 3) | (((h >> 7) & 1) << 2)); \
a.s1 = (char)(((b0 >> 4) & 3) | (((h >> 6) & 1) << 2)); \
a.s2 = (char)(((b0 >> 2) & 3) | (((h >> 5) & 1) << 2)); \
a.s3 = (char)(((b0 >> 0) & 3) | (((h >> 4) & 1) << 2)); \
a.s4 = (char)(((b1 >> 6) & 3) | (((h >> 3) & 1) << 2)); \
a.s5 = (char)(((b1 >> 4) & 3) | (((h >> 2) & 1) << 2)); \
a.s6 = (char)(((b1 >> 2) & 3) | (((h >> 1) & 1) << 2)); \
a.s7 = (char)(((b1 >> 0) & 3) | (((h >> 0) & 1) << 2));
__constant sampler_t SAMPLER = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;
#ifdef USE_IMAGE1D_INPUT
#ifdef MNN_SUPPORT_FP16
#define RI_F(i, coord) read_imageh(i, coord)
#else
#define RI_F(i, coord) read_imagef(i, coord)
#endif
#define LOAD_INPUT4(offset) CONVERT_COMPUTE_FLOAT4(RI_F(input, (offset) >> 2))
#define LOAD_INPUT16(offset) (COMPUTE_FLOAT16)(LOAD_INPUT4(offset), LOAD_INPUT4((offset) + 4), LOAD_INPUT4((offset) + 8), LOAD_INPUT4((offset) + 12))
#else
#define LOAD_INPUT4(offset) CONVERT_COMPUTE_FLOAT4(vload4(0, input + (offset)))
#define LOAD_INPUT16(offset) CONVERT_COMPUTE_FLOAT16(vload16(0, input + (offset)))
#endif
__kernel void inverse_quant_weight(GLOBAL_SIZE_DIM2
#ifdef USE_IMAGE
__read_only image2d_t weight,
#else
#if QUANT_BIT == 8
__global const char *weight,
#else
__global const uchar *weight,
#endif
#endif
__global const FLOAT *dequantScaleOffset,
__global FLOAT* output,
__private const int inputChannel,
__private const int inputChannel4Align,
__private const int outputChannelAlign,
__private const int outputChannel4Align,
__private const int blockDim,
__private const float coef){
const int x = get_global_id(0); //ic
const int y = get_global_id(1); //oc
UNIFORM_BOUNDRY_CHECK(x, y);
#if QUANT_BIT == 2 || QUANT_BIT == 3 || QUANT_BIT == 4
const int ic = x << 2;
const int oc = y << 3;
const int output_offset = ic * outputChannelAlign + oc;
#ifdef ASYMMETRIC
COMPUTE_FLOAT8 scale, offset;
{
COMPUTE_FLOAT16 ScaleOffset = CONVERT_COMPUTE_FLOAT16(convert_float16(vload16(0, dequantScaleOffset + ((ic / blockDim) * outputChannel4Align + oc) * 2)) / coef);
scale = ScaleOffset.s02468ace;
offset = ScaleOffset.s13579bdf;
}
#else
COMPUTE_FLOAT8 scale = CONVERT_COMPUTE_FLOAT8(convert_float8(vload8(0, dequantScaleOffset + (ic / blockDim) * outputChannel4Align + oc)) / coef);
#if QUANT_BIT == 2
COMPUTE_FLOAT8 offset = (COMPUTE_FLOAT8)(-2) * scale;
#elif QUANT_BIT == 3
COMPUTE_FLOAT8 offset = (COMPUTE_FLOAT8)(-4) * scale;
#else
COMPUTE_FLOAT8 offset = (COMPUTE_FLOAT8)(-8) * scale;
#endif
#endif
COMPUTE_FLOAT8 weights0, weights1, weights2, weights3;
{
#if QUANT_BIT == 4
#ifdef USE_IMAGE
uchar16 charWeightsInt40 = as_uchar16(read_imagei(weight, SAMPLER, (int2)(x, y)));
#else
uchar16 charWeightsInt40 = vload16(x, weight + y * inputChannel4Align * 4);
#endif
char8 charWeights0;
UCHAR4_TO_CHAR8(charWeights0, charWeightsInt40.s0123);
weights0 = CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
UCHAR4_TO_CHAR8(charWeights0, charWeightsInt40.s4567);
weights1 = ic + 1 >= inputChannel ? 0 : CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
UCHAR4_TO_CHAR8(charWeights0, charWeightsInt40.s89ab);
weights2 = ic + 2 >= inputChannel ? 0 : CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
UCHAR4_TO_CHAR8(charWeights0, charWeightsInt40.scdef);
weights3 = ic + 3 >= inputChannel ? 0 : CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
#elif QUANT_BIT == 2
// 2bit storage: 8 bytes per (4IC × 8OC) tile, weight_offset row stride = inputChannel4Align * 2
uchar8 charWeightsInt20 = vload8(x, weight + y * inputChannel4Align * 2);
char8 charWeights0;
UCHAR2_TO_CHAR8_W2(charWeights0, charWeightsInt20.s0, charWeightsInt20.s1);
weights0 = CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
UCHAR2_TO_CHAR8_W2(charWeights0, charWeightsInt20.s2, charWeightsInt20.s3);
weights1 = ic + 1 >= inputChannel ? 0 : CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
UCHAR2_TO_CHAR8_W2(charWeights0, charWeightsInt20.s4, charWeightsInt20.s5);
weights2 = ic + 2 >= inputChannel ? 0 : CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
UCHAR2_TO_CHAR8_W2(charWeights0, charWeightsInt20.s6, charWeightsInt20.s7);
weights3 = ic + 3 >= inputChannel ? 0 : CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
#elif QUANT_BIT == 3
// 3bit storage: 12 bytes per (4IC × 8OC) tile, row stride = inputChannel4Align * 3
const int base = y * inputChannel4Align * 3 + x * 12;
uchar8 charWeightsInt30Lo = vload8(0, weight + base);
uchar4 charWeightsInt30Hi = vload4(0, weight + base + 8);
char8 charWeights0;
UCHAR3_TO_CHAR8_W3(charWeights0, charWeightsInt30Lo.s0, charWeightsInt30Lo.s1, charWeightsInt30Hi.s0);
weights0 = CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
UCHAR3_TO_CHAR8_W3(charWeights0, charWeightsInt30Lo.s2, charWeightsInt30Lo.s3, charWeightsInt30Hi.s1);
weights1 = ic + 1 >= inputChannel ? 0 : CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
UCHAR3_TO_CHAR8_W3(charWeights0, charWeightsInt30Lo.s4, charWeightsInt30Lo.s5, charWeightsInt30Hi.s2);
weights2 = ic + 2 >= inputChannel ? 0 : CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
UCHAR3_TO_CHAR8_W3(charWeights0, charWeightsInt30Lo.s6, charWeightsInt30Lo.s7, charWeightsInt30Hi.s3);
weights3 = ic + 3 >= inputChannel ? 0 : CONVERT_COMPUTE_FLOAT8(charWeights0) * scale + offset;
#endif
}
vstore8(CONVERT_FLOAT8(weights0), 0, output+output_offset);
vstore8(CONVERT_FLOAT8(weights1), 0, output+output_offset+outputChannelAlign);
vstore8(CONVERT_FLOAT8(weights2), 0, output+output_offset+2*outputChannelAlign);
vstore8(CONVERT_FLOAT8(weights3), 0, output+output_offset+3*outputChannelAlign);
#elif QUANT_BIT == 8
const int ic = x << 1;
const int oc = y << 3;
const int output_offset = ic * outputChannelAlign + oc;
#ifdef ASYMMETRIC
COMPUTE_FLOAT8 scale, offset;
{
COMPUTE_FLOAT16 ScaleOffset = CONVERT_COMPUTE_FLOAT16(convert_float16(vload16(0, dequantScaleOffset + ((ic / blockDim) * outputChannel4Align + oc) * 2)) / coef);
scale = ScaleOffset.s02468ace;
offset = ScaleOffset.s13579bdf;
}
#else
COMPUTE_FLOAT8 scale = CONVERT_COMPUTE_FLOAT8(convert_float8(vload8(0, dequantScaleOffset + (ic / blockDim) * outputChannel4Align + oc)) / coef);
#endif
COMPUTE_FLOAT8 weights0, weights1;
{
#ifdef USE_IMAGE
COMPUTE_FLOAT16 wei = CONVERT_COMPUTE_FLOAT16(as_char16(read_imagei(weight, SAMPLER, (int2)(x, y))));
#else
COMPUTE_FLOAT16 wei = CONVERT_COMPUTE_FLOAT16(vload16(x, weight + y * inputChannel4Align * 8));
#endif
#ifdef ASYMMETRIC
weights0 = wei.s01234567 * scale + offset;
weights1 = ic + 1 >= inputChannel ? 0 : wei.s89abcdef * scale + offset;
#else
weights0 = wei.s01234567 * scale;
weights1 = ic + 1 >= inputChannel ? 0 : wei.s89abcdef * scale;
#endif
}
vstore8(CONVERT_FLOAT8(weights0), 0, output+output_offset);
vstore8(CONVERT_FLOAT8(weights1), 0, output+output_offset+outputChannelAlign);
#endif
}
__kernel void gemm_c4nhw4_to_nhwc(GLOBAL_SIZE_DIM2
__global const FLOAT* input,
__global FLOAT* output,
__private const int bhw,
__private const int channel,
__private const int channelAlign
){
const int x = get_global_id(0); //b/4
const int y = get_global_id(1); //c/4
UNIFORM_BOUNDRY_CHECK(x, y);
const int out_b_idx = x << 2;
const int out_c_idx = y << 2;
const int bhw4 = bhw << 2;
const int input_offset = y * bhw4 + out_b_idx * 4;
FLOAT4 in0, in1, in2, in3;
if(out_c_idx + 3 < channel && out_b_idx + 3 < bhw){
in0 = vload4(0, input + input_offset);
in1 = vload4(0, input + input_offset + 4);
in2 = vload4(0, input + input_offset + 8);
in3 = vload4(0, input + input_offset + 12);
} else{
if(out_c_idx + 3 < channel){
in0 = vload4(0, input + input_offset);
in1 = out_b_idx + 1 < bhw ? vload4(0, input + input_offset + 4) : 0;
in2 = out_b_idx + 2 < bhw ? vload4(0, input + input_offset + 8) : 0;
in3 = out_b_idx + 3 < bhw ? vload4(0, input + input_offset + 12) : 0;
} else if(out_c_idx + 1 == channel){
in0 = (FLOAT4)(input[input_offset], 0, 0, 0);
in1 = out_b_idx + 1 < bhw ? (FLOAT4)(input[input_offset + 4], 0, 0, 0) : 0;
in2 = out_b_idx + 2 < bhw ? (FLOAT4)(input[input_offset + 8], 0, 0, 0) : 0;
in3 = out_b_idx + 3 < bhw ? (FLOAT4)(input[input_offset + 12], 0, 0, 0) : 0;
} else if(out_c_idx + 2 == channel){
in0 = (FLOAT4)(input[input_offset], input[input_offset + 1], 0, 0);
in1 = out_b_idx + 1 < bhw ? (FLOAT4)(input[input_offset + 4], input[input_offset + 5], 0, 0) : 0;
in2 = out_b_idx + 2 < bhw ? (FLOAT4)(input[input_offset + 8], input[input_offset + 9], 0, 0) : 0;
in3 = out_b_idx + 3 < bhw ? (FLOAT4)(input[input_offset + 12], input[input_offset + 13], 0, 0) : 0;
} else if(out_c_idx + 3 == channel){
in0 = (FLOAT4)(input[input_offset], input[input_offset + 1], input[input_offset + 2], 0);
in1 = out_b_idx + 1 < bhw ? (FLOAT4)(input[input_offset + 4], input[input_offset + 5], input[input_offset + 6], 0) : 0;
in2 = out_b_idx + 2 < bhw ? (FLOAT4)(input[input_offset + 8], input[input_offset + 9], input[input_offset + 10], 0) : 0;
in3 = out_b_idx + 3 < bhw ? (FLOAT4)(input[input_offset + 12], input[input_offset + 13], input[input_offset + 14], 0) : 0;
}
}
int out_offset = out_b_idx * channelAlign + out_c_idx;
vstore4(in0, 0, output + out_offset);
vstore4(in1, 0, output + out_offset + channelAlign);
vstore4(in2, 0, output + out_offset + channelAlign + channelAlign);
vstore4(in3, 0, output + out_offset + channelAlign + channelAlign + channelAlign);
}
__kernel void gemm_nhwc_to_c4nhw4(GLOBAL_SIZE_DIM2
__global const FLOAT* input,
__global FLOAT* output,
__private const int bhw,
__private const int channelAlign
){
const int x = get_global_id(0); //b/4
const int y = get_global_id(1); //c/4
UNIFORM_BOUNDRY_CHECK(x, y);
const int out_b_idx = x << 2;
const int out_c_idx = y << 2;
const int bhw4 = bhw << 2;
const int input_offset = out_b_idx * channelAlign + out_c_idx;
FLOAT4 in0 = vload4(0, input + input_offset);
FLOAT4 in1 = vload4(0, input + input_offset + channelAlign);
FLOAT4 in2 = vload4(0, input + input_offset + channelAlign + channelAlign);
FLOAT4 in3 = vload4(0, input + input_offset + channelAlign + channelAlign + channelAlign);
int out_offset = y * bhw4 + out_b_idx * 4;
vstore4(in0, 0, output + out_offset);
if(out_b_idx + 1 >= bhw) return;
vstore4(in1, 0, output + out_offset + 4);
if(out_b_idx + 2 >= bhw) return;
vstore4(in2, 0, output + out_offset + 8);
if(out_b_idx + 3 >= bhw) return;
vstore4(in3, 0, output + out_offset + 12);
}
#define UCHAR4_TO_FLOAT8(b, scale, offset) \
wei.s0 = CONVERT_FLOAT((b.s0 >> 4)); \
wei.s1 = CONVERT_FLOAT((b.s0 & 15)); \
wei.s2 = CONVERT_FLOAT((b.s1 >> 4)); \
wei.s3 = CONVERT_FLOAT((b.s1 & 15)); \
wei.s4 = CONVERT_FLOAT((b.s2 >> 4)); \
wei.s5 = CONVERT_FLOAT((b.s2 & 15)); \
wei.s6 = CONVERT_FLOAT((b.s3 >> 4)); \
wei.s7 = CONVERT_FLOAT((b.s3 & 15)); \
wei = wei * scale + offset;
__kernel void gemm_b4_c8_int4_buf(GLOBAL_SIZE_DIM2
#ifdef USE_IMAGE1D_INPUT
__read_only image1d_buffer_t input,
#else
__global const FLOAT* input,
#endif
#ifdef USE_IMAGE
__read_only image2d_t weight,
#else
__global const uchar *weight,
#endif
__global const FLOAT *dequantScaleOffset,
__global const FLOAT *bias,
__global FLOAT* output,
__private const int bhw,
__private const int dstChannelAlign,
__private const int srcChannelAlign,
__private const int blockNum,
__private const int blockDim,
__private const float coef) {
const int x = get_global_id(0); //b/4
const int y = get_global_id(1); //c/8
UNIFORM_BOUNDRY_CHECK(x, y);
const int out_b_idx = x << 2;
const int out_c_idx = y << 1;
COMPUTE_FLOAT8 out0 = CONVERT_COMPUTE_FLOAT8(vload8(0, bias + (out_c_idx << 2)));
COMPUTE_FLOAT8 out1 = out0;
COMPUTE_FLOAT8 out2 = out0;
COMPUTE_FLOAT8 out3 = out0;
const int bhw4 = bhw << 2;
const int input_offset = out_b_idx * 4;
int out_offset = out_c_idx * bhw4 + out_b_idx * 4;
#ifndef USE_IMAGE
const int weight_offset = y * srcChannelAlign * 4;
#endif
const int loop = (blockDim + 4 - 1) / 4;
#if INPUT_CHANNEL_LEAVES_NUM != 0
const int loop_end = max(loop - 1, 0);
#else
const int loop_end = loop;
#endif
#if INPUT_BATCH_LEAVES_NUM != 0
if(out_b_idx + 3 >= bhw){
for (int i = 0; i < blockNum; i++){
#ifdef ASYMMETRIC
COMPUTE_FLOAT8 scale, offset;
{
COMPUTE_FLOAT16 scaleOffset = CONVERT_COMPUTE_FLOAT16(convert_float16(vload16(0, dequantScaleOffset + (out_c_idx << 3) + i * dstChannelAlign * 2)) / coef);
scale = scaleOffset.s02468ace;
offset = scaleOffset.s13579bdf;
}
#else
COMPUTE_FLOAT8 scale = CONVERT_COMPUTE_FLOAT8(convert_float8(vload8(0, dequantScaleOffset + (out_c_idx << 2) + i * dstChannelAlign)) / coef);
COMPUTE_FLOAT8 offset = (COMPUTE_FLOAT8)(-8) * scale;
#endif
for (int j = 0; j < loop_end; j++) {
int k = i * loop + j;
COMPUTE_FLOAT8 wei;
#ifdef USE_IMAGE
uchar16 charWeightsInt40 = as_uchar16(read_imagei(weight, SAMPLER, (int2)(k, y)));
#else
uchar16 charWeightsInt40 = vload16(k, weight + weight_offset);
#endif
COMPUTE_FLOAT4 in0 = LOAD_INPUT4(input_offset + k * bhw4);
#if INPUT_BATCH_LEAVES_NUM >= 2
COMPUTE_FLOAT4 in1 = LOAD_INPUT4(input_offset + k * bhw4 + 4);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
COMPUTE_FLOAT4 in2 = LOAD_INPUT4(input_offset + k * bhw4 + 8);
#endif
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s0, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s0, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s0, wei, out2);
#endif
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s1, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s1, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s1, wei, out2);
#endif
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s2, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s2, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s2, wei, out2);
#endif
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.scdef, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s3, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s3, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s3, wei, out2);
#endif
}
}
#if INPUT_CHANNEL_LEAVES_NUM != 0
{
int k = i * loop + loop_end;
COMPUTE_FLOAT8 wei;
COMPUTE_FLOAT4 in0 = LOAD_INPUT4(input_offset + k * bhw4);
#if INPUT_BATCH_LEAVES_NUM >= 2
COMPUTE_FLOAT4 in1 = LOAD_INPUT4(input_offset + k * bhw4 + 4);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
COMPUTE_FLOAT4 in2 = LOAD_INPUT4(input_offset + k * bhw4 + 8);
#endif
#ifdef USE_IMAGE
uchar16 charWeightsInt40 = as_uchar16(read_imagei(weight, SAMPLER, (int2)(k, y)));
#else
uchar16 charWeightsInt40 = vload16(k, weight + weight_offset);
#endif
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s0, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s0, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s0, wei, out2);
#endif
}
#if INPUT_CHANNEL_LEAVES_NUM >= 2
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s1, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s1, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s1, wei, out2);
#endif
}
#endif
#if INPUT_CHANNEL_LEAVES_NUM >= 3
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s2, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s2, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s2, wei, out2);
#endif
}
#endif
}
#endif
}
} else {
#endif
for (int i = 0; i < blockNum; i++){
#ifdef ASYMMETRIC
COMPUTE_FLOAT8 scale, offset;
{
COMPUTE_FLOAT16 scaleOffset = CONVERT_COMPUTE_FLOAT16(convert_float16(vload16(0, dequantScaleOffset + (out_c_idx << 3) + i * dstChannelAlign * 2)) / coef);
scale = scaleOffset.s02468ace;
offset = scaleOffset.s13579bdf;
}
#else
COMPUTE_FLOAT8 scale = CONVERT_COMPUTE_FLOAT8(convert_float8(vload8(0, dequantScaleOffset + (out_c_idx << 2) + i * dstChannelAlign)) / coef);
COMPUTE_FLOAT8 offset = (COMPUTE_FLOAT8)(-8) * scale;
#endif
for (int j = 0; j < loop_end; j++) {
int k = i * loop + j;
COMPUTE_FLOAT8 wei;
COMPUTE_FLOAT16 in = LOAD_INPUT16(input_offset + k * bhw4);
#ifdef USE_IMAGE
uchar16 charWeightsInt40 = as_uchar16(read_imagei(weight, SAMPLER, (int2)(k, y)));
#else
uchar16 charWeightsInt40 = vload16(k, weight + weight_offset);
#endif
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in.s0, wei, out0);
out1 = mad((COMPUTE_FLOAT8)in.s4, wei, out1);
out2 = mad((COMPUTE_FLOAT8)in.s8, wei, out2);
out3 = mad((COMPUTE_FLOAT8)in.sc, wei, out3);
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in.s1, wei, out0);
out1 = mad((COMPUTE_FLOAT8)in.s5, wei, out1);
out2 = mad((COMPUTE_FLOAT8)in.s9, wei, out2);
out3 = mad((COMPUTE_FLOAT8)in.sd, wei, out3);
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in.s2, wei, out0);
out1 = mad((COMPUTE_FLOAT8)in.s6, wei, out1);
out2 = mad((COMPUTE_FLOAT8)in.sa, wei, out2);
out3 = mad((COMPUTE_FLOAT8)in.se, wei, out3);
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.scdef, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in.s3, wei, out0);
out1 = mad((COMPUTE_FLOAT8)in.s7, wei, out1);
out2 = mad((COMPUTE_FLOAT8)in.sb, wei, out2);
out3 = mad((COMPUTE_FLOAT8)in.sf, wei, out3);
}
}
#if INPUT_CHANNEL_LEAVES_NUM != 0
{
int k = i * loop + loop_end;
COMPUTE_FLOAT8 wei;
COMPUTE_FLOAT16 in = LOAD_INPUT16(input_offset + k * bhw4);
#ifdef USE_IMAGE
uchar16 charWeightsInt40 = as_uchar16(read_imagei(weight, SAMPLER, (int2)(k, y)));
#else
uchar16 charWeightsInt40 = vload16(k, weight + weight_offset);
#endif
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in.s0, wei, out0);
out1 = mad((COMPUTE_FLOAT8)in.s4, wei, out1);
out2 = mad((COMPUTE_FLOAT8)in.s8, wei, out2);
out3 = mad((COMPUTE_FLOAT8)in.sc, wei, out3);
}
#if INPUT_CHANNEL_LEAVES_NUM >= 2
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in.s1, wei, out0);
out1 = mad((COMPUTE_FLOAT8)in.s5, wei, out1);
out2 = mad((COMPUTE_FLOAT8)in.s9, wei, out2);
out3 = mad((COMPUTE_FLOAT8)in.sd, wei, out3);
}
#endif
#if INPUT_CHANNEL_LEAVES_NUM >= 3
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in.s2, wei, out0);
out1 = mad((COMPUTE_FLOAT8)in.s6, wei, out1);
out2 = mad((COMPUTE_FLOAT8)in.sa, wei, out2);
out3 = mad((COMPUTE_FLOAT8)in.se, wei, out3);
}
#endif
}
#endif
}
#if INPUT_BATCH_LEAVES_NUM != 0
}
#endif
#ifdef RELU
out0 = fmax(out0, (COMPUTE_FLOAT8)0);
out1 = fmax(out1, (COMPUTE_FLOAT8)0);
out2 = fmax(out2, (COMPUTE_FLOAT8)0);
out3 = fmax(out3, (COMPUTE_FLOAT8)0);
#endif
#ifdef RELU6
out0 = clamp(out0, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out1 = clamp(out1, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out2 = clamp(out2, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out3 = clamp(out3, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
#endif
#if INPUT_BATCH_LEAVES_NUM != 0
if(out_b_idx + 3 >= bhw){
#if INPUT_BATCH_LEAVES_NUM == 3
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s0123, out1.s0123)), 0, output+out_offset);
vstore4(CONVERT_FLOAT4(out2.s0123), 0, output+out_offset+8);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s4567, out1.s4567)), 0, output+out_offset+bhw4);
vstore4(CONVERT_FLOAT4(out2.s4567), 0, output+out_offset+bhw4+8);
}
#elif INPUT_BATCH_LEAVES_NUM == 2
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s0123, out1.s0123)), 0, output+out_offset);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s4567, out1.s4567)), 0, output+out_offset+bhw4);
}
#elif INPUT_BATCH_LEAVES_NUM == 1
vstore4(CONVERT_FLOAT4(out0.s0123), 0, output+out_offset);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore4(CONVERT_FLOAT4(out0.s4567), 0, output+out_offset+bhw4);
}
#endif
}else{
#endif
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out0.s0123, out1.s0123, out2.s0123, out3.s0123)), 0, output+out_offset);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out0.s4567, out1.s4567, out2.s4567, out3.s4567)), 0, output+out_offset+bhw4);
}
#if INPUT_BATCH_LEAVES_NUM != 0
}
#endif
}
__kernel void gemm_b8_c8_int4_buf(GLOBAL_SIZE_DIM2
#ifdef USE_IMAGE1D_INPUT
__read_only image1d_buffer_t input,
#else
__global const FLOAT* input,
#endif
#ifdef USE_IMAGE
__read_only image2d_t weight,
#else
__global const uchar *weight,
#endif
__global const FLOAT *dequantScaleOffset,
__global const FLOAT *bias,
__global FLOAT* output,
__private const int bhw,
__private const int dstChannelAlign,
__private const int srcChannelAlign,
__private const int blockNum,
__private const int blockDim,
__private const float coef) {
const int x = get_global_id(0); //b/8
const int y = get_global_id(1); //c/8
UNIFORM_BOUNDRY_CHECK(x, y);
const int out_b_idx = x << 3; // 8 batches per work-item
const int out_c_idx = y << 1; // 8 channels (2 * float4)
COMPUTE_FLOAT8 out0 = CONVERT_COMPUTE_FLOAT8(vload8(0, bias + (out_c_idx << 2)));
COMPUTE_FLOAT8 out1 = out0;
COMPUTE_FLOAT8 out2 = out0;
COMPUTE_FLOAT8 out3 = out0;
COMPUTE_FLOAT8 out4 = out0;
COMPUTE_FLOAT8 out5 = out0;
COMPUTE_FLOAT8 out6 = out0;
COMPUTE_FLOAT8 out7 = out0;
const int bhw4 = bhw << 2;
const int input_offset = out_b_idx * 4;
int out_offset = out_c_idx * bhw4 + out_b_idx * 4;
#ifndef USE_IMAGE
const int weight_offset = y * srcChannelAlign * 4;
#endif
const int loop = (blockDim + 4 - 1) / 4;
#if INPUT_CHANNEL_LEAVES_NUM != 0
const int loop_end = max(loop - 1, 0);
#else
const int loop_end = loop;
#endif
#if INPUT_BATCH_LEAVES_NUM != 0
if(out_b_idx + 7 >= bhw){
// Tail path: handle remaining 1-7 batches
for (int i = 0; i < blockNum; i++){
#ifdef ASYMMETRIC
COMPUTE_FLOAT8 scale, offset;
{
COMPUTE_FLOAT16 scaleOffset = CONVERT_COMPUTE_FLOAT16(convert_float16(vload16(0, dequantScaleOffset + (out_c_idx << 3) + i * dstChannelAlign * 2)) / coef);
scale = scaleOffset.s02468ace;
offset = scaleOffset.s13579bdf;
}
#else
COMPUTE_FLOAT8 scale = CONVERT_COMPUTE_FLOAT8(convert_float8(vload8(0, dequantScaleOffset + (out_c_idx << 2) + i * dstChannelAlign)) / coef);
COMPUTE_FLOAT8 offset = (COMPUTE_FLOAT8)(-8) * scale;
#endif
for (int j = 0; j < loop_end; j++) {
int k = i * loop + j;
COMPUTE_FLOAT8 wei;
#ifdef USE_IMAGE
uchar16 charWeightsInt40 = as_uchar16(read_imagei(weight, SAMPLER, (int2)(k, y)));
#else
uchar16 charWeightsInt40 = vload16(k, weight + weight_offset);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 4
// First 4 batches are always valid
COMPUTE_FLOAT16 inA = LOAD_INPUT16(input_offset + k * bhw4);
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s0, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s4, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.s8, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sc, wei, out3);
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s1, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s5, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.s9, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sd, wei, out3);
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s2, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s6, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.sa, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.se, wei, out3);
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.scdef, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s3, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s7, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.sb, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sf, wei, out3);
}
// Remaining batches (4..6)
{
COMPUTE_FLOAT16 inB = LOAD_INPUT16(input_offset + 16 + k * bhw4);
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out4 = mad((COMPUTE_FLOAT8)inB.s0, wei, out4);
#if INPUT_BATCH_LEAVES_NUM >= 6
out5 = mad((COMPUTE_FLOAT8)inB.s4, wei, out5);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 7
out6 = mad((COMPUTE_FLOAT8)inB.s8, wei, out6);
#endif
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out4 = mad((COMPUTE_FLOAT8)inB.s1, wei, out4);
#if INPUT_BATCH_LEAVES_NUM >= 6
out5 = mad((COMPUTE_FLOAT8)inB.s5, wei, out5);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 7
out6 = mad((COMPUTE_FLOAT8)inB.s9, wei, out6);
#endif
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out4 = mad((COMPUTE_FLOAT8)inB.s2, wei, out4);
#if INPUT_BATCH_LEAVES_NUM >= 6
out5 = mad((COMPUTE_FLOAT8)inB.s6, wei, out5);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 7
out6 = mad((COMPUTE_FLOAT8)inB.sa, wei, out6);
#endif
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.scdef, scale, offset);
out4 = mad((COMPUTE_FLOAT8)inB.s3, wei, out4);
#if INPUT_BATCH_LEAVES_NUM >= 6
out5 = mad((COMPUTE_FLOAT8)inB.s7, wei, out5);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 7
out6 = mad((COMPUTE_FLOAT8)inB.sb, wei, out6);
#endif
}
}
#else
// INPUT_BATCH_LEAVES_NUM < 4: only 1-3 valid batches
COMPUTE_FLOAT4 in0 = LOAD_INPUT4(input_offset + k * bhw4);
#if INPUT_BATCH_LEAVES_NUM >= 2
COMPUTE_FLOAT4 in1 = LOAD_INPUT4(input_offset + k * bhw4 + 4);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
COMPUTE_FLOAT4 in2 = LOAD_INPUT4(input_offset + k * bhw4 + 8);
#endif
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s0, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s0, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s0, wei, out2);
#endif
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s1, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s1, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s1, wei, out2);
#endif
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s2, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s2, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s2, wei, out2);
#endif
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.scdef, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s3, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s3, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s3, wei, out2);
#endif
}
#endif
}
#if INPUT_CHANNEL_LEAVES_NUM != 0
{
int k = i * loop + loop_end;
COMPUTE_FLOAT8 wei;
#ifdef USE_IMAGE
uchar16 charWeightsInt40 = as_uchar16(read_imagei(weight, SAMPLER, (int2)(k, y)));
#else
uchar16 charWeightsInt40 = vload16(k, weight + weight_offset);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 4
COMPUTE_FLOAT16 inA = LOAD_INPUT16(input_offset + k * bhw4);
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s0, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s4, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.s8, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sc, wei, out3);
}
#if INPUT_CHANNEL_LEAVES_NUM >= 2
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s1, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s5, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.s9, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sd, wei, out3);
}
#endif
#if INPUT_CHANNEL_LEAVES_NUM >= 3
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s2, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s6, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.sa, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.se, wei, out3);
}
#endif
{
COMPUTE_FLOAT16 inB = LOAD_INPUT16(input_offset + 16 + k * bhw4);
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out4 = mad((COMPUTE_FLOAT8)inB.s0, wei, out4);
#if INPUT_BATCH_LEAVES_NUM >= 6
out5 = mad((COMPUTE_FLOAT8)inB.s4, wei, out5);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 7
out6 = mad((COMPUTE_FLOAT8)inB.s8, wei, out6);
#endif
}
#if INPUT_CHANNEL_LEAVES_NUM >= 2
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out4 = mad((COMPUTE_FLOAT8)inB.s1, wei, out4);
#if INPUT_BATCH_LEAVES_NUM >= 6
out5 = mad((COMPUTE_FLOAT8)inB.s5, wei, out5);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 7
out6 = mad((COMPUTE_FLOAT8)inB.s9, wei, out6);
#endif
}
#endif
#if INPUT_CHANNEL_LEAVES_NUM >= 3
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out4 = mad((COMPUTE_FLOAT8)inB.s2, wei, out4);
#if INPUT_BATCH_LEAVES_NUM >= 6
out5 = mad((COMPUTE_FLOAT8)inB.s6, wei, out5);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 7
out6 = mad((COMPUTE_FLOAT8)inB.sa, wei, out6);
#endif
}
#endif
}
#else
COMPUTE_FLOAT4 in0 = LOAD_INPUT4(input_offset + k * bhw4);
#if INPUT_BATCH_LEAVES_NUM >= 2
COMPUTE_FLOAT4 in1 = LOAD_INPUT4(input_offset + k * bhw4 + 4);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
COMPUTE_FLOAT4 in2 = LOAD_INPUT4(input_offset + k * bhw4 + 8);
#endif
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s0, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s0, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s0, wei, out2);
#endif
}
#if INPUT_CHANNEL_LEAVES_NUM >= 2
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s1, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s1, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s1, wei, out2);
#endif
}
#endif
#if INPUT_CHANNEL_LEAVES_NUM >= 3
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)in0.s2, wei, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s2, wei, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s2, wei, out2);
#endif
}
#endif
#endif
}
#endif
}
} else {
#endif
for (int i = 0; i < blockNum; i++){
#ifdef ASYMMETRIC
COMPUTE_FLOAT8 scale, offset;
{
COMPUTE_FLOAT16 scaleOffset = CONVERT_COMPUTE_FLOAT16(convert_float16(vload16(0, dequantScaleOffset + (out_c_idx << 3) + i * dstChannelAlign * 2)) / coef);
scale = scaleOffset.s02468ace;
offset = scaleOffset.s13579bdf;
}
#else
COMPUTE_FLOAT8 scale = CONVERT_COMPUTE_FLOAT8(convert_float8(vload8(0, dequantScaleOffset + (out_c_idx << 2) + i * dstChannelAlign)) / coef);
COMPUTE_FLOAT8 offset = (COMPUTE_FLOAT8)(-8) * scale;
#endif
for (int j = 0; j < loop_end; j++) {
int k = i * loop + j;
COMPUTE_FLOAT8 wei;
#ifdef USE_IMAGE
uchar16 charWeightsInt40 = as_uchar16(read_imagei(weight, SAMPLER, (int2)(k, y)));
#else
uchar16 charWeightsInt40 = vload16(k, weight + weight_offset);
#endif
COMPUTE_FLOAT16 inA = LOAD_INPUT16(input_offset + k * bhw4);
COMPUTE_FLOAT16 inB = LOAD_INPUT16(input_offset + 16 + k * bhw4);
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s0, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s4, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.s8, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sc, wei, out3);
out4 = mad((COMPUTE_FLOAT8)inB.s0, wei, out4);
out5 = mad((COMPUTE_FLOAT8)inB.s4, wei, out5);
out6 = mad((COMPUTE_FLOAT8)inB.s8, wei, out6);
out7 = mad((COMPUTE_FLOAT8)inB.sc, wei, out7);
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s1, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s5, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.s9, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sd, wei, out3);
out4 = mad((COMPUTE_FLOAT8)inB.s1, wei, out4);
out5 = mad((COMPUTE_FLOAT8)inB.s5, wei, out5);
out6 = mad((COMPUTE_FLOAT8)inB.s9, wei, out6);
out7 = mad((COMPUTE_FLOAT8)inB.sd, wei, out7);
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s2, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s6, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.sa, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.se, wei, out3);
out4 = mad((COMPUTE_FLOAT8)inB.s2, wei, out4);
out5 = mad((COMPUTE_FLOAT8)inB.s6, wei, out5);
out6 = mad((COMPUTE_FLOAT8)inB.sa, wei, out6);
out7 = mad((COMPUTE_FLOAT8)inB.se, wei, out7);
}
{
UCHAR4_TO_FLOAT8(charWeightsInt40.scdef, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s3, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s7, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.sb, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sf, wei, out3);
out4 = mad((COMPUTE_FLOAT8)inB.s3, wei, out4);
out5 = mad((COMPUTE_FLOAT8)inB.s7, wei, out5);
out6 = mad((COMPUTE_FLOAT8)inB.sb, wei, out6);
out7 = mad((COMPUTE_FLOAT8)inB.sf, wei, out7);
}
}
#if INPUT_CHANNEL_LEAVES_NUM != 0
{
int k = i * loop + loop_end;
COMPUTE_FLOAT8 wei;
#ifdef USE_IMAGE
uchar16 charWeightsInt40 = as_uchar16(read_imagei(weight, SAMPLER, (int2)(k, y)));
#else
uchar16 charWeightsInt40 = vload16(k, weight + weight_offset);
#endif
COMPUTE_FLOAT16 inA = LOAD_INPUT16(input_offset + k * bhw4);
COMPUTE_FLOAT16 inB = LOAD_INPUT16(input_offset + 16 + k * bhw4);
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s0123, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s0, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s4, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.s8, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sc, wei, out3);
out4 = mad((COMPUTE_FLOAT8)inB.s0, wei, out4);
out5 = mad((COMPUTE_FLOAT8)inB.s4, wei, out5);
out6 = mad((COMPUTE_FLOAT8)inB.s8, wei, out6);
out7 = mad((COMPUTE_FLOAT8)inB.sc, wei, out7);
}
#if INPUT_CHANNEL_LEAVES_NUM >= 2
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s4567, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s1, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s5, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.s9, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.sd, wei, out3);
out4 = mad((COMPUTE_FLOAT8)inB.s1, wei, out4);
out5 = mad((COMPUTE_FLOAT8)inB.s5, wei, out5);
out6 = mad((COMPUTE_FLOAT8)inB.s9, wei, out6);
out7 = mad((COMPUTE_FLOAT8)inB.sd, wei, out7);
}
#endif
#if INPUT_CHANNEL_LEAVES_NUM >= 3
{
UCHAR4_TO_FLOAT8(charWeightsInt40.s89ab, scale, offset);
out0 = mad((COMPUTE_FLOAT8)inA.s2, wei, out0);
out1 = mad((COMPUTE_FLOAT8)inA.s6, wei, out1);
out2 = mad((COMPUTE_FLOAT8)inA.sa, wei, out2);
out3 = mad((COMPUTE_FLOAT8)inA.se, wei, out3);
out4 = mad((COMPUTE_FLOAT8)inB.s2, wei, out4);
out5 = mad((COMPUTE_FLOAT8)inB.s6, wei, out5);
out6 = mad((COMPUTE_FLOAT8)inB.sa, wei, out6);
out7 = mad((COMPUTE_FLOAT8)inB.se, wei, out7);
}
#endif
}
#endif
}
#if INPUT_BATCH_LEAVES_NUM != 0
}
#endif
#ifdef RELU
out0 = fmax(out0, (COMPUTE_FLOAT8)0);
out1 = fmax(out1, (COMPUTE_FLOAT8)0);
out2 = fmax(out2, (COMPUTE_FLOAT8)0);
out3 = fmax(out3, (COMPUTE_FLOAT8)0);
out4 = fmax(out4, (COMPUTE_FLOAT8)0);
out5 = fmax(out5, (COMPUTE_FLOAT8)0);
out6 = fmax(out6, (COMPUTE_FLOAT8)0);
out7 = fmax(out7, (COMPUTE_FLOAT8)0);
#endif
#ifdef RELU6
out0 = clamp(out0, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out1 = clamp(out1, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out2 = clamp(out2, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out3 = clamp(out3, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out4 = clamp(out4, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out5 = clamp(out5, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out6 = clamp(out6, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out7 = clamp(out7, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
#endif
#if INPUT_BATCH_LEAVES_NUM != 0
if(out_b_idx + 7 >= bhw){
#if INPUT_BATCH_LEAVES_NUM >= 4
// First 4 batches are always valid
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out0.s0123, out1.s0123, out2.s0123, out3.s0123)), 0, output+out_offset);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out0.s4567, out1.s4567, out2.s4567, out3.s4567)), 0, output+out_offset+bhw4);
}
// Write remaining valid batches (4..6)
#if INPUT_BATCH_LEAVES_NUM == 4
// No remaining batches
#elif INPUT_BATCH_LEAVES_NUM == 5
{
int off2 = out_offset + 16;
vstore4(CONVERT_FLOAT4(out4.s0123), 0, output+off2);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore4(CONVERT_FLOAT4(out4.s4567), 0, output+off2+bhw4);
}
}
#elif INPUT_BATCH_LEAVES_NUM == 6
{
int off2 = out_offset + 16;
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out4.s0123, out5.s0123)), 0, output+off2);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out4.s4567, out5.s4567)), 0, output+off2+bhw4);
}
}
#elif INPUT_BATCH_LEAVES_NUM == 7
{
int off2 = out_offset + 16;
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out4.s0123, out5.s0123)), 0, output+off2);
vstore4(CONVERT_FLOAT4(out6.s0123), 0, output+off2+8);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out4.s4567, out5.s4567)), 0, output+off2+bhw4);
vstore4(CONVERT_FLOAT4(out6.s4567), 0, output+off2+bhw4+8);
}
}
#endif
#elif INPUT_BATCH_LEAVES_NUM == 3
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s0123, out1.s0123)), 0, output+out_offset);
vstore4(CONVERT_FLOAT4(out2.s0123), 0, output+out_offset+8);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s4567, out1.s4567)), 0, output+out_offset+bhw4);
vstore4(CONVERT_FLOAT4(out2.s4567), 0, output+out_offset+bhw4+8);
}
#elif INPUT_BATCH_LEAVES_NUM == 2
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s0123, out1.s0123)), 0, output+out_offset);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s4567, out1.s4567)), 0, output+out_offset+bhw4);
}
#elif INPUT_BATCH_LEAVES_NUM == 1
vstore4(CONVERT_FLOAT4(out0.s0123), 0, output+out_offset);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore4(CONVERT_FLOAT4(out0.s4567), 0, output+out_offset+bhw4);
}
#endif
} else {
#endif
// Write all 8 batches
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out0.s0123, out1.s0123, out2.s0123, out3.s0123)), 0, output+out_offset);
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out4.s0123, out5.s0123, out6.s0123, out7.s0123)), 0, output+out_offset+16);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out0.s4567, out1.s4567, out2.s4567, out3.s4567)), 0, output+out_offset+bhw4);
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out4.s4567, out5.s4567, out6.s4567, out7.s4567)), 0, output+out_offset+bhw4+16);
}
#if INPUT_BATCH_LEAVES_NUM != 0
}
#endif
}
__kernel void gemm_b4_c8_int8_buf(GLOBAL_SIZE_DIM2
#ifdef USE_IMAGE1D_INPUT
__read_only image1d_buffer_t input,
#else
__global const FLOAT* input,
#endif
#ifdef USE_IMAGE
__read_only image2d_t weight,
#else
__global const char *weight,
#endif
__global const FLOAT *dequantScaleOffset,
__global const FLOAT *bias,
__global FLOAT* output,
__private const int bhw,
__private const int dstChannelAlign,
__private const int srcChannelAlign,
__private const int blockNum,
__private const int blockDim,
__private const float coef) {
const int x = get_global_id(0); //b/4
const int y = get_global_id(1); //c/8
UNIFORM_BOUNDRY_CHECK(x, y);
const int out_b_idx = x << 2;
const int out_c_idx = y << 1;
COMPUTE_FLOAT8 out0 = CONVERT_COMPUTE_FLOAT8(vload8(0, bias + (out_c_idx << 2)));
COMPUTE_FLOAT8 out1 = out0;
COMPUTE_FLOAT8 out2 = out0;
COMPUTE_FLOAT8 out3 = out0;
const int bhw4 = bhw << 2;
const int input_offset = out_b_idx * 4;
int out_offset = out_c_idx * bhw4 + out_b_idx * 4;
#ifndef USE_IMAGE
const int weight_offset = y * srcChannelAlign * 8;
#endif
const int loop = (blockDim + 4 - 1) / 4;
#if INPUT_CHANNEL_LEAVES_NUM != 0
const int loop_end = max(loop - 1, 0);
#else
const int loop_end = loop;
#endif
#if INPUT_BATCH_LEAVES_NUM != 0
if(out_b_idx + 3 >= bhw){
for (int i = 0; i < blockNum; i++){
COMPUTE_FLOAT16 scale, offset;
{
#ifdef ASYMMETRIC
COMPUTE_FLOAT16 scaleOffset = CONVERT_COMPUTE_FLOAT16(convert_float16(vload16(0, dequantScaleOffset + (out_c_idx << 3) + i * dstChannelAlign * 2)) / coef);
scale = (COMPUTE_FLOAT16)(scaleOffset.s02468ace, scaleOffset.s02468ace);
offset = (COMPUTE_FLOAT16)(scaleOffset.s13579bdf, scaleOffset.s13579bdf);
#else
scale.s01234567 = CONVERT_COMPUTE_FLOAT8(convert_float8(vload8(0, dequantScaleOffset + (out_c_idx << 2) + i * dstChannelAlign)) / coef);
scale.s89abcdef = scale.s01234567;
offset = 0;
#endif
}
for (int j = 0; j < loop_end; j++) {
int k = i * loop + j;
int k2 = k << 1;
#ifdef USE_IMAGE
COMPUTE_FLOAT16 wei0 = CONVERT_COMPUTE_FLOAT16(as_char16(read_imagei(weight, SAMPLER, (int2)(k2, y)))) * scale + offset;
COMPUTE_FLOAT16 wei1 = CONVERT_COMPUTE_FLOAT16(as_char16(read_imagei(weight, SAMPLER, (int2)(k2 + 1, y)))) * scale + offset;
#else
COMPUTE_FLOAT16 wei0 = CONVERT_COMPUTE_FLOAT16(vload16(k2, weight + weight_offset)) * scale + offset;
COMPUTE_FLOAT16 wei1 = CONVERT_COMPUTE_FLOAT16(vload16(k2 + 1, weight + weight_offset)) * scale + offset;
#endif
COMPUTE_FLOAT4 in0 = LOAD_INPUT4(input_offset + k * bhw4);
#if INPUT_BATCH_LEAVES_NUM >= 2
COMPUTE_FLOAT4 in1 = LOAD_INPUT4(input_offset + k * bhw4 + 4);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
COMPUTE_FLOAT4 in2 = LOAD_INPUT4(input_offset + k * bhw4 + 8);
#endif
{
out0 = mad((COMPUTE_FLOAT8)in0.s0, wei0.s01234567, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s0, wei0.s01234567, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s0, wei0.s01234567, out2);
#endif
}
{
out0 = mad((COMPUTE_FLOAT8)in0.s1, wei0.s89abcdef, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s1, wei0.s89abcdef, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s1, wei0.s89abcdef, out2);
#endif
}
{
out0 = mad((COMPUTE_FLOAT8)in0.s2, wei1.s01234567, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s2, wei1.s01234567, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s2, wei1.s01234567, out2);
#endif
}
{
out0 = mad((COMPUTE_FLOAT8)in0.s3, wei1.s89abcdef, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s3, wei1.s89abcdef, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s3, wei1.s89abcdef, out2);
#endif
}
}
#if INPUT_CHANNEL_LEAVES_NUM != 0
{
int k = i * loop + loop_end;
int k2 = k << 1;
COMPUTE_FLOAT4 in0 = LOAD_INPUT4(input_offset + k * bhw4);
#if INPUT_BATCH_LEAVES_NUM >= 2
COMPUTE_FLOAT4 in1 = LOAD_INPUT4(input_offset + k * bhw4 + 4);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
COMPUTE_FLOAT4 in2 = LOAD_INPUT4(input_offset + k * bhw4 + 8);
#endif
#ifdef USE_IMAGE
COMPUTE_FLOAT16 wei0 = CONVERT_COMPUTE_FLOAT16(as_char16(read_imagei(weight, SAMPLER, (int2)(k2, y)))) * scale + offset;
COMPUTE_FLOAT16 wei1 = CONVERT_COMPUTE_FLOAT16(as_char16(read_imagei(weight, SAMPLER, (int2)(k2 + 1, y)))) * scale + offset;
#else
COMPUTE_FLOAT16 wei0 = CONVERT_COMPUTE_FLOAT16(vload16(k2, weight + weight_offset)) * scale + offset;
COMPUTE_FLOAT16 wei1 = CONVERT_COMPUTE_FLOAT16(vload16(k2 + 1, weight + weight_offset)) * scale + offset;
#endif
{
out0 = mad((COMPUTE_FLOAT8)in0.s0, wei0.s01234567, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s0, wei0.s01234567, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s0, wei0.s01234567, out2);
#endif
}
#if INPUT_CHANNEL_LEAVES_NUM >= 2
{
out0 = mad((COMPUTE_FLOAT8)in0.s1, wei0.s89abcdef, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s1, wei0.s89abcdef, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s1, wei0.s89abcdef, out2);
#endif
}
#endif
#if INPUT_CHANNEL_LEAVES_NUM >= 3
{
out0 = mad((COMPUTE_FLOAT8)in0.s2, wei1.s01234567, out0);
#if INPUT_BATCH_LEAVES_NUM >= 2
out1 = mad((COMPUTE_FLOAT8)in1.s2, wei1.s01234567, out1);
#endif
#if INPUT_BATCH_LEAVES_NUM >= 3
out2 = mad((COMPUTE_FLOAT8)in2.s2, wei1.s01234567, out2);
#endif
}
#endif
}
#endif
}
} else {
#endif
for (int i = 0; i < blockNum; i++){
COMPUTE_FLOAT16 scale, offset;
{
#ifdef ASYMMETRIC
COMPUTE_FLOAT16 scaleOffset = CONVERT_COMPUTE_FLOAT16(convert_float16(vload16(0, dequantScaleOffset + (out_c_idx << 3) + i * dstChannelAlign * 2)) / coef);
scale = (COMPUTE_FLOAT16)(scaleOffset.s02468ace, scaleOffset.s02468ace);
offset = (COMPUTE_FLOAT16)(scaleOffset.s13579bdf, scaleOffset.s13579bdf);
#else
scale.s01234567 = CONVERT_COMPUTE_FLOAT8(convert_float8(vload8(0, dequantScaleOffset + (out_c_idx << 2) + i * dstChannelAlign)) / coef);
scale.s89abcdef = scale.s01234567;
offset = 0;
#endif
}
for (int j = 0; j < loop_end; j++) {
int k = i * loop + j;
int k2 = k << 1;
COMPUTE_FLOAT16 in = LOAD_INPUT16(input_offset + k * bhw4);
#ifdef USE_IMAGE
COMPUTE_FLOAT16 wei0 = CONVERT_COMPUTE_FLOAT16(as_char16(read_imagei(weight, SAMPLER, (int2)(k2, y)))) * scale + offset;
COMPUTE_FLOAT16 wei1 = CONVERT_COMPUTE_FLOAT16(as_char16(read_imagei(weight, SAMPLER, (int2)(k2 + 1, y)))) * scale + offset;
#else
COMPUTE_FLOAT16 wei0 = CONVERT_COMPUTE_FLOAT16(vload16(k2, weight + weight_offset)) * scale + offset;
COMPUTE_FLOAT16 wei1 = CONVERT_COMPUTE_FLOAT16(vload16(k2 + 1, weight + weight_offset)) * scale + offset;
#endif
{
out0 = mad((COMPUTE_FLOAT8)in.s0, wei0.s01234567, out0);
out1 = mad((COMPUTE_FLOAT8)in.s4, wei0.s01234567, out1);
out2 = mad((COMPUTE_FLOAT8)in.s8, wei0.s01234567, out2);
out3 = mad((COMPUTE_FLOAT8)in.sc, wei0.s01234567, out3);
}
{
out0 = mad((COMPUTE_FLOAT8)in.s1, wei0.s89abcdef, out0);
out1 = mad((COMPUTE_FLOAT8)in.s5, wei0.s89abcdef, out1);
out2 = mad((COMPUTE_FLOAT8)in.s9, wei0.s89abcdef, out2);
out3 = mad((COMPUTE_FLOAT8)in.sd, wei0.s89abcdef, out3);
}
{
out0 = mad((COMPUTE_FLOAT8)in.s2, wei1.s01234567, out0);
out1 = mad((COMPUTE_FLOAT8)in.s6, wei1.s01234567, out1);
out2 = mad((COMPUTE_FLOAT8)in.sa, wei1.s01234567, out2);
out3 = mad((COMPUTE_FLOAT8)in.se, wei1.s01234567, out3);
}
{
out0 = mad((COMPUTE_FLOAT8)in.s3, wei1.s89abcdef, out0);
out1 = mad((COMPUTE_FLOAT8)in.s7, wei1.s89abcdef, out1);
out2 = mad((COMPUTE_FLOAT8)in.sb, wei1.s89abcdef, out2);
out3 = mad((COMPUTE_FLOAT8)in.sf, wei1.s89abcdef, out3);
}
}
#if INPUT_CHANNEL_LEAVES_NUM != 0
{
int k = i * loop + loop_end;
int k2 = k << 1;
COMPUTE_FLOAT16 in = LOAD_INPUT16(input_offset + k * bhw4);
#ifdef USE_IMAGE
COMPUTE_FLOAT16 wei0 = CONVERT_COMPUTE_FLOAT16(as_char16(read_imagei(weight, SAMPLER, (int2)(k2, y)))) * scale + offset;
COMPUTE_FLOAT16 wei1 = CONVERT_COMPUTE_FLOAT16(as_char16(read_imagei(weight, SAMPLER, (int2)(k2 + 1, y)))) * scale + offset;
#else
COMPUTE_FLOAT16 wei0 = CONVERT_COMPUTE_FLOAT16(vload16(k2, weight + weight_offset)) * scale + offset;
COMPUTE_FLOAT16 wei1 = CONVERT_COMPUTE_FLOAT16(vload16(k2 + 1, weight + weight_offset)) * scale + offset;
#endif
{
out0 = mad((COMPUTE_FLOAT8)in.s0, wei0.s01234567, out0);
out1 = mad((COMPUTE_FLOAT8)in.s4, wei0.s01234567, out1);
out2 = mad((COMPUTE_FLOAT8)in.s8, wei0.s01234567, out2);
out3 = mad((COMPUTE_FLOAT8)in.sc, wei0.s01234567, out3);
}
#if INPUT_CHANNEL_LEAVES_NUM >= 2
{
out0 = mad((COMPUTE_FLOAT8)in.s1, wei0.s89abcdef, out0);
out1 = mad((COMPUTE_FLOAT8)in.s5, wei0.s89abcdef, out1);
out2 = mad((COMPUTE_FLOAT8)in.s9, wei0.s89abcdef, out2);
out3 = mad((COMPUTE_FLOAT8)in.sd, wei0.s89abcdef, out3);
}
#endif
#if INPUT_CHANNEL_LEAVES_NUM >= 3
{
out0 = mad((COMPUTE_FLOAT8)in.s2, wei1.s01234567, out0);
out1 = mad((COMPUTE_FLOAT8)in.s6, wei1.s01234567, out1);
out2 = mad((COMPUTE_FLOAT8)in.sa, wei1.s01234567, out2);
out3 = mad((COMPUTE_FLOAT8)in.se, wei1.s01234567, out3);
}
#endif
}
#endif
}
#if INPUT_BATCH_LEAVES_NUM != 0
}
#endif
#ifdef RELU
out0 = fmax(out0, (COMPUTE_FLOAT8)0);
out1 = fmax(out1, (COMPUTE_FLOAT8)0);
out2 = fmax(out2, (COMPUTE_FLOAT8)0);
out3 = fmax(out3, (COMPUTE_FLOAT8)0);
#endif
#ifdef RELU6
out0 = clamp(out0, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out1 = clamp(out1, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out2 = clamp(out2, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
out3 = clamp(out3, (COMPUTE_FLOAT8)0, (COMPUTE_FLOAT8)6);
#endif
#if INPUT_BATCH_LEAVES_NUM != 0
if(out_b_idx + 3 >= bhw){
#if INPUT_BATCH_LEAVES_NUM == 3
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s0123, out1.s0123)), 0, output+out_offset);
vstore4(CONVERT_FLOAT4(out2.s0123), 0, output+out_offset+8);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s4567, out1.s4567)), 0, output+out_offset+bhw4);
vstore4(CONVERT_FLOAT4(out2.s4567), 0, output+out_offset+bhw4+8);
}
#elif INPUT_BATCH_LEAVES_NUM == 2
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s0123, out1.s0123)), 0, output+out_offset);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore8(CONVERT_FLOAT8((COMPUTE_FLOAT8)(out0.s4567, out1.s4567)), 0, output+out_offset+bhw4);
}
#elif INPUT_BATCH_LEAVES_NUM == 1
vstore4(CONVERT_FLOAT4(out0.s0123), 0, output+out_offset);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore4(CONVERT_FLOAT4(out0.s4567), 0, output+out_offset+bhw4);
}
#endif
}else{
#endif
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out0.s0123, out1.s0123, out2.s0123, out3.s0123)), 0, output+out_offset);
if((out_c_idx << 2) + 4 < dstChannelAlign){
vstore16(CONVERT_FLOAT16((COMPUTE_FLOAT16)(out0.s4567, out1.s4567, out2.s4567, out3.s4567)), 0, output+out_offset+bhw4);
}
#if INPUT_BATCH_LEAVES_NUM != 0
}
#endif
}