Spaces:
Runtime error
Runtime error
Upload folder using huggingface_hub (part 5)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/flash_attn_f32_q8_0.cl +1791 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/flash_attn_pre_f16.cl +156 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gated_delta_net.cl +249 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gelu.cl +89 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32.cl +162 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32_ns.cl +374 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_q8_1_dp4a.cl +186 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_f32_ns.cl +324 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_q8_1_dp4a.cl +165 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_1_f32_ns.cl +326 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_f32_ns.cl +348 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_q8_1_dp4a.cl +202 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_0_f32_ns.cl +328 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_1_f32_ns.cl +330 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_k_f32_ns.cl +356 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_f32_ns.cl +335 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_q8_1_dp4a.cl +196 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q8_0_f32_ns.cl +221 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q8_1_dp4a.cl +221 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_iq4_nl_f32.cl +150 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_iq4_nl_q8_1_dp4a.cl +143 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q1_0_f32.cl +94 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_0_f32.cl +139 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_0_q8_1_dp4a.cl +127 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_1_f32.cl +132 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_k_f32.cl +172 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_k_q8_1_dp4a.cl +281 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_0_f32.cl +131 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_0_q8_1_dp4a.cl +235 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_1_f32.cl +134 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_k_f32.cl +176 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_k_q8_1_dp4a.cl +164 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q6_k_f32.cl +140 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q6_k_q8_1_dp4a.cl +144 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q8_0_f32.cl +129 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q8_0_q8_1_dp4a.cl +212 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_xmem_f16_f32_os8.cl +233 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_mxfp4_f32.cl +156 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_mxfp4_f32_ns.cl +257 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_0_f32_ns.cl +120 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_1_f32_ns.cl +123 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_k_f32_ns.cl +266 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_0_f32_ns.cl +123 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_1_f32_ns.cl +125 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_k_f32_ns.cl +160 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q6_k_f32_ns.cl +141 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_iq4_nl_f32.cl +302 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q1_0_f32.cl +121 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32.cl +274 -0
- backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32_spec.cl +268 -0
backend/llama.cpp/ggml/src/ggml-opencl/kernels/flash_attn_f32_q8_0.cl
ADDED
|
@@ -0,0 +1,1791 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#ifdef cl_khr_integer_dot_product
|
| 3 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 4 |
+
#define FA_HAVE_INT_DOT 1
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
#ifdef cl_khr_subgroup_shuffle
|
| 8 |
+
#pragma OPENCL EXTENSION cl_khr_subgroup_shuffle : enable
|
| 9 |
+
#define HAS_SUBGROUP_SHUFFLE 1
|
| 10 |
+
#elif defined(cl_qcom_subgroup_shuffle)
|
| 11 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_shuffle : enable
|
| 12 |
+
#define HAS_SUBGROUP_SHUFFLE 1
|
| 13 |
+
#endif
|
| 14 |
+
|
| 15 |
+
// Flash attention: Q=f32, K=q8_0, V=q8_0.
|
| 16 |
+
|
| 17 |
+
#define ACC_TYPE float
|
| 18 |
+
#define ACC_TYPE4 float4
|
| 19 |
+
#define Q_DATA_TYPE4 float4
|
| 20 |
+
#define O_DATA_TYPE4 float4
|
| 21 |
+
#define MASK_DATA_TYPE half
|
| 22 |
+
#define CONVERT_Q_ACC4(x) (x)
|
| 23 |
+
#define CONVERT_O_DATA4(x) (x)
|
| 24 |
+
|
| 25 |
+
#define DK_VEC (DK/4)
|
| 26 |
+
#define DV_VEC (DV/4)
|
| 27 |
+
|
| 28 |
+
#ifndef FA_SG
|
| 29 |
+
#define FA_SG 64
|
| 30 |
+
#endif
|
| 31 |
+
#define Q1_WG_SIZE FA_SG
|
| 32 |
+
|
| 33 |
+
// The kernels are built with -cl-finite-math-only. On some older Adreno GPUs,
|
| 34 |
+
// infinite operand can cause undefined behavior and miscompilation for exp.
|
| 35 |
+
// Therefore, a large negative value is used instead.
|
| 36 |
+
#define FA_M_INIT (-3.0e38f)
|
| 37 |
+
|
| 38 |
+
// q8_0 block: 2B scale (half) + 32B int8 quants.
|
| 39 |
+
#define QK8_0 32
|
| 40 |
+
#define Q8_0_BLOCK_SIZE 34
|
| 41 |
+
|
| 42 |
+
#define DK_Q8_BLOCKS (DK / QK8_0)
|
| 43 |
+
#define DV_Q8_BLOCKS (DV / QK8_0)
|
| 44 |
+
|
| 45 |
+
inline float dot_q8_0_f32(const global char * block_ptr, ACC_TYPE4 * q_slice) {
|
| 46 |
+
float d = vload_half(0, (const global half *)block_ptr);
|
| 47 |
+
const global char * qs = block_ptr + 2;
|
| 48 |
+
|
| 49 |
+
float sum = 0.0f;
|
| 50 |
+
#pragma unroll
|
| 51 |
+
for (int i = 0; i < 8; i++) {
|
| 52 |
+
float4 qv = (float4)((float)qs[i*4], (float)qs[i*4+1], (float)qs[i*4+2], (float)qs[i*4+3]);
|
| 53 |
+
sum += dot(q_slice[i], qv);
|
| 54 |
+
}
|
| 55 |
+
return sum * d;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
#ifdef FA_HAVE_INT_DOT
|
| 59 |
+
inline uint pack_i8x4(char a, char b, char c, char d) {
|
| 60 |
+
return ((uint)(uchar)a) |
|
| 61 |
+
((uint)(uchar)b) << 8 |
|
| 62 |
+
((uint)(uchar)c) << 16 |
|
| 63 |
+
((uint)(uchar)d) << 24;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
inline float quant_q_block_int8_packed(const ACC_TYPE4 * q_block,
|
| 67 |
+
uint * out_packed) {
|
| 68 |
+
float amax = 0.0f;
|
| 69 |
+
#pragma unroll
|
| 70 |
+
for (int i = 0; i < 8; ++i) {
|
| 71 |
+
float4 av = fabs(q_block[i]);
|
| 72 |
+
amax = fmax(amax, fmax(fmax(av.s0, av.s1), fmax(av.s2, av.s3)));
|
| 73 |
+
}
|
| 74 |
+
float qd = amax / 127.0f;
|
| 75 |
+
float qid = (amax > 0.0f) ? 127.0f / amax : 0.0f;
|
| 76 |
+
|
| 77 |
+
#pragma unroll
|
| 78 |
+
for (int i = 0; i < 8; ++i) {
|
| 79 |
+
float4 v = q_block[i] * qid;
|
| 80 |
+
char a = (char)((int)round(v.s0));
|
| 81 |
+
char b = (char)((int)round(v.s1));
|
| 82 |
+
char c = (char)((int)round(v.s2));
|
| 83 |
+
char d = (char)((int)round(v.s3));
|
| 84 |
+
out_packed[i] = pack_i8x4(a, b, c, d);
|
| 85 |
+
}
|
| 86 |
+
return qd;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
inline float dot_q8_0_int(const global char * k_block_ptr,
|
| 90 |
+
const uint * q_packed,
|
| 91 |
+
float q_d) {
|
| 92 |
+
float kd = vload_half(0, (const global half *)k_block_ptr);
|
| 93 |
+
const global uchar * k_qs = (const global uchar *)(k_block_ptr + 2);
|
| 94 |
+
|
| 95 |
+
// k_qs is 2-byte aligned; pack chars per iteration rather than cast to uint*.
|
| 96 |
+
int sum = 0;
|
| 97 |
+
#pragma unroll
|
| 98 |
+
for (int i = 0; i < 8; ++i) {
|
| 99 |
+
uint k_packed =
|
| 100 |
+
(uint)k_qs[i*4 + 0] |
|
| 101 |
+
((uint)k_qs[i*4 + 1]) << 8 |
|
| 102 |
+
((uint)k_qs[i*4 + 2]) << 16 |
|
| 103 |
+
((uint)k_qs[i*4 + 3]) << 24;
|
| 104 |
+
sum = dot_acc_sat_4x8packed_ss_int(q_packed[i], k_packed, sum);
|
| 105 |
+
}
|
| 106 |
+
return (float)sum * q_d * kd;
|
| 107 |
+
}
|
| 108 |
+
#endif // FA_HAVE_INT_DOT
|
| 109 |
+
|
| 110 |
+
inline void dequant_q8_0_f32(const global char * block_ptr, ACC_TYPE4 * out) {
|
| 111 |
+
float d = vload_half(0, (const global half *)block_ptr);
|
| 112 |
+
const global char * qs = block_ptr + 2;
|
| 113 |
+
|
| 114 |
+
#pragma unroll
|
| 115 |
+
for (int i = 0; i < 8; i++) {
|
| 116 |
+
out[i] = d * (float4)((float)qs[i*4], (float)qs[i*4+1], (float)qs[i*4+2], (float)qs[i*4+3]);
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
// max_bias<=0 returns 1.0 so score += 1.0 * mask[k] stays a no-op multiplier.
|
| 121 |
+
inline float get_alibi_slope(float max_bias, int head_idx, int n_head_log2, float m0, float m1) {
|
| 122 |
+
if (max_bias <= 0.0f) return 1.0f;
|
| 123 |
+
float base = (head_idx < n_head_log2) ? m0 : m1;
|
| 124 |
+
int exph = (head_idx < n_head_log2) ? (head_idx + 1) : (2*(head_idx - n_head_log2) + 1);
|
| 125 |
+
return pow(base, (float)exph);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
// q1 decode: one query row per WG, threads sweep KV positions.
|
| 129 |
+
__kernel void flash_attn_f32_q8_0_q1(
|
| 130 |
+
const global void * q_void, ulong q_offset,
|
| 131 |
+
const global void * k_void, ulong k_offset,
|
| 132 |
+
const global void * v_void, ulong v_offset,
|
| 133 |
+
global void * o_void, ulong o_offset,
|
| 134 |
+
const float scale,
|
| 135 |
+
const int n_q,
|
| 136 |
+
const int n_kv,
|
| 137 |
+
const int is_causal,
|
| 138 |
+
const int n_head,
|
| 139 |
+
const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
|
| 140 |
+
const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
|
| 141 |
+
const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
|
| 142 |
+
const ulong o_nb1, const ulong o_nb2, const ulong o_nb3,
|
| 143 |
+
const float max_bias,
|
| 144 |
+
const float m0,
|
| 145 |
+
const float m1,
|
| 146 |
+
const int n_head_log2,
|
| 147 |
+
const float logit_softcap,
|
| 148 |
+
const int n_head_kv,
|
| 149 |
+
const global void* mask_void,
|
| 150 |
+
const ulong mask_offset,
|
| 151 |
+
const ulong mask_nb1,
|
| 152 |
+
const ulong mask_nb2,
|
| 153 |
+
const ulong mask_nb3,
|
| 154 |
+
const int mask_ne2,
|
| 155 |
+
const int mask_ne3,
|
| 156 |
+
const global void* sinks_void,
|
| 157 |
+
const ulong sinks_offset
|
| 158 |
+
) {
|
| 159 |
+
const int tid = get_local_id(0);
|
| 160 |
+
const int head_batch_idx = get_global_id(1);
|
| 161 |
+
|
| 162 |
+
const int batch_idx = head_batch_idx / n_head;
|
| 163 |
+
const int head_idx = head_batch_idx % n_head;
|
| 164 |
+
|
| 165 |
+
const int gqa_ratio = n_head / n_head_kv;
|
| 166 |
+
const int head_kv_idx = head_idx / gqa_ratio;
|
| 167 |
+
|
| 168 |
+
const global char* q_base = (const global char*)q_void + q_offset;
|
| 169 |
+
const global char* k_base = (const global char*)k_void + k_offset;
|
| 170 |
+
const global char* v_base = (const global char*)v_void + v_offset;
|
| 171 |
+
global char* o_base = (global char*)o_void + o_offset;
|
| 172 |
+
|
| 173 |
+
const global char* mask_base = NULL;
|
| 174 |
+
if (mask_void != NULL) {
|
| 175 |
+
const int mask_head_idx = head_idx % mask_ne2;
|
| 176 |
+
const int mask_batch_idx = batch_idx % mask_ne3;
|
| 177 |
+
mask_base = (const global char*)mask_void + mask_offset + mask_batch_idx * mask_nb3 + mask_head_idx * mask_nb2;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
ACC_TYPE4 q_priv[DK_VEC];
|
| 181 |
+
const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2;
|
| 182 |
+
const global Q_DATA_TYPE4* q_ptr = (const global Q_DATA_TYPE4*)(q_base + q_row_offset);
|
| 183 |
+
#pragma unroll
|
| 184 |
+
for (int i = 0; i < DK_VEC; ++i) {
|
| 185 |
+
q_priv[i] = CONVERT_Q_ACC4(q_ptr[i]);
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
#ifdef FA_HAVE_INT_DOT
|
| 189 |
+
// Quantise Q once per thread; q_priv stays as fp for the V accumulate.
|
| 190 |
+
uint q_packed[DK_Q8_BLOCKS * 8];
|
| 191 |
+
float q_d_scale[DK_Q8_BLOCKS];
|
| 192 |
+
#pragma unroll
|
| 193 |
+
for (int b = 0; b < DK_Q8_BLOCKS; ++b) {
|
| 194 |
+
q_d_scale[b] = quant_q_block_int8_packed(&q_priv[b * 8], &q_packed[b * 8]);
|
| 195 |
+
}
|
| 196 |
+
#endif
|
| 197 |
+
|
| 198 |
+
float slope = get_alibi_slope(max_bias, head_idx, n_head_log2, m0, m1);
|
| 199 |
+
|
| 200 |
+
const global ACC_TYPE* sinks_ptr = NULL;
|
| 201 |
+
if (sinks_void != NULL) {
|
| 202 |
+
sinks_ptr = (const global ACC_TYPE*)((const global char*)sinks_void + sinks_offset);
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
// One-pass online softmax: per-thread maintains running (m_i, l_i, o_acc),
|
| 206 |
+
// updating each as new K positions are processed. Eliminates the second
|
| 207 |
+
// K read of the original two-pass implementation. After the loop, threads
|
| 208 |
+
// are merged via the standard FA-2 cross-thread reduction (rescale each
|
| 209 |
+
// thread's l_i and o_acc by alpha=exp(m_i_thread - m_final), then sum).
|
| 210 |
+
ACC_TYPE m_i = (sinks_ptr != NULL) ? sinks_ptr[head_idx] : FA_M_INIT;
|
| 211 |
+
ACC_TYPE l_i = 0.0f;
|
| 212 |
+
ACC_TYPE4 o_acc[DV_VEC];
|
| 213 |
+
#pragma unroll
|
| 214 |
+
for (int i = 0; i < DV_VEC; ++i) o_acc[i] = (ACC_TYPE4)(0.0f);
|
| 215 |
+
|
| 216 |
+
for (int k_idx = tid; k_idx < n_kv; k_idx += Q1_WG_SIZE) {
|
| 217 |
+
const global char* k_row = k_base + batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_idx * k_nb1;
|
| 218 |
+
const global char* v_row = v_base + batch_idx * v_nb3 + head_kv_idx * v_nb2 + k_idx * v_nb1;
|
| 219 |
+
|
| 220 |
+
ACC_TYPE score = 0.0f;
|
| 221 |
+
#pragma unroll
|
| 222 |
+
for (int b = 0; b < DK_Q8_BLOCKS; b++) {
|
| 223 |
+
#ifdef FA_HAVE_INT_DOT
|
| 224 |
+
score += dot_q8_0_int(k_row + b * Q8_0_BLOCK_SIZE,
|
| 225 |
+
&q_packed[b * 8], q_d_scale[b]);
|
| 226 |
+
#else
|
| 227 |
+
score += dot_q8_0_f32(k_row + b * Q8_0_BLOCK_SIZE, &q_priv[b * 8]);
|
| 228 |
+
#endif
|
| 229 |
+
}
|
| 230 |
+
score *= scale;
|
| 231 |
+
|
| 232 |
+
if (mask_base != NULL) {
|
| 233 |
+
const global MASK_DATA_TYPE* mask_ptr = (const global MASK_DATA_TYPE*)(mask_base);
|
| 234 |
+
score += slope * (ACC_TYPE)mask_ptr[k_idx];
|
| 235 |
+
}
|
| 236 |
+
if (logit_softcap > 0.0f) {
|
| 237 |
+
score = logit_softcap * tanh(score / logit_softcap);
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
// Online softmax step.
|
| 241 |
+
const ACC_TYPE m_new = max(m_i, score);
|
| 242 |
+
const ACC_TYPE alpha = exp(m_i - m_new);
|
| 243 |
+
const ACC_TYPE p = exp(score - m_new);
|
| 244 |
+
|
| 245 |
+
l_i = alpha * l_i + p;
|
| 246 |
+
#pragma unroll
|
| 247 |
+
for (int i = 0; i < DV_VEC; ++i) o_acc[i] *= alpha;
|
| 248 |
+
|
| 249 |
+
#pragma unroll
|
| 250 |
+
for (int b = 0; b < DV_Q8_BLOCKS; b++) {
|
| 251 |
+
ACC_TYPE4 v_dequant[8];
|
| 252 |
+
dequant_q8_0_f32(v_row + b * Q8_0_BLOCK_SIZE, v_dequant);
|
| 253 |
+
#pragma unroll
|
| 254 |
+
for (int i = 0; i < 8; i++) {
|
| 255 |
+
o_acc[b * 8 + i] = mad(p, v_dequant[i], o_acc[b * 8 + i]);
|
| 256 |
+
}
|
| 257 |
+
}
|
| 258 |
+
|
| 259 |
+
m_i = m_new;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
// Cross-thread reduce: max(m_i) -> m_final, then rescale per-thread l_i
|
| 263 |
+
// and o_acc by alpha = exp(m_i_thread - m_final) before sum-reduce.
|
| 264 |
+
__local ACC_TYPE local_m[Q1_WG_SIZE];
|
| 265 |
+
local_m[tid] = m_i;
|
| 266 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 267 |
+
#pragma unroll
|
| 268 |
+
for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
|
| 269 |
+
if (tid < s) local_m[tid] = max(local_m[tid], local_m[tid + s]);
|
| 270 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 271 |
+
}
|
| 272 |
+
const ACC_TYPE m_final = local_m[0];
|
| 273 |
+
|
| 274 |
+
const ACC_TYPE alpha_final = exp(m_i - m_final);
|
| 275 |
+
l_i *= alpha_final;
|
| 276 |
+
#pragma unroll
|
| 277 |
+
for (int i = 0; i < DV_VEC; ++i) o_acc[i] *= alpha_final;
|
| 278 |
+
|
| 279 |
+
__local ACC_TYPE local_l[Q1_WG_SIZE];
|
| 280 |
+
__local ACC_TYPE4 local_o_comp[Q1_WG_SIZE];
|
| 281 |
+
local_l[tid] = l_i;
|
| 282 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 283 |
+
#pragma unroll
|
| 284 |
+
for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
|
| 285 |
+
if (tid < s) local_l[tid] += local_l[tid + s];
|
| 286 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
const ulong o_row_offset = batch_idx * o_nb3 + head_idx * o_nb1;
|
| 290 |
+
global O_DATA_TYPE4 *o_row = (global O_DATA_TYPE4 *)(o_base + o_row_offset);
|
| 291 |
+
ACC_TYPE l_final = local_l[0];
|
| 292 |
+
|
| 293 |
+
if (sinks_ptr != NULL) {
|
| 294 |
+
l_final += exp(sinks_ptr[head_idx] - m_final);
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
if (l_final > 0.0f) {
|
| 298 |
+
const ACC_TYPE l_inv = 1.0f / l_final;
|
| 299 |
+
for (int i = 0; i < DV_VEC; i++) {
|
| 300 |
+
local_o_comp[tid] = o_acc[i];
|
| 301 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 302 |
+
#pragma unroll
|
| 303 |
+
for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
|
| 304 |
+
if (tid < s) local_o_comp[tid] += local_o_comp[tid + s];
|
| 305 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 306 |
+
}
|
| 307 |
+
if (tid == 0) {
|
| 308 |
+
o_row[i] = CONVERT_O_DATA4(local_o_comp[0] * l_inv);
|
| 309 |
+
}
|
| 310 |
+
}
|
| 311 |
+
} else if (tid == 0) {
|
| 312 |
+
#pragma unroll
|
| 313 |
+
for (int i = 0; i < DV_VEC; ++i) o_row[i] = (O_DATA_TYPE4)(0.0f);
|
| 314 |
+
}
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
#ifdef cl_intel_subgroups
|
| 318 |
+
#pragma OPENCL EXTENSION cl_intel_subgroups : enable
|
| 319 |
+
#else
|
| 320 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 321 |
+
#endif
|
| 322 |
+
|
| 323 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 324 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 325 |
+
#define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
|
| 326 |
+
#else
|
| 327 |
+
#define REQD_SUBGROUP_SIZE_64
|
| 328 |
+
#endif
|
| 329 |
+
|
| 330 |
+
#define VEC_NSG 4
|
| 331 |
+
#define VEC_WG_SIZE (Q1_WG_SIZE * VEC_NSG)
|
| 332 |
+
#define Q1V_DV_PER_THREAD ((DV_VEC + Q1_WG_SIZE - 1) / Q1_WG_SIZE)
|
| 333 |
+
|
| 334 |
+
inline float4 dequant_q8_0_lane(const global char * block_ptr, int lane) {
|
| 335 |
+
const float d = vload_half(0, (const global half *)block_ptr);
|
| 336 |
+
const global char * qs = block_ptr + 2 + lane * 4;
|
| 337 |
+
return d * (float4)((float)qs[0], (float)qs[1], (float)qs[2], (float)qs[3]);
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
REQD_SUBGROUP_SIZE_64
|
| 341 |
+
__kernel void flash_attn_f32_q8_0_q1_vec(
|
| 342 |
+
const global void * q_void, ulong q_offset,
|
| 343 |
+
const global void * k_void, ulong k_offset,
|
| 344 |
+
const global void * v_void, ulong v_offset,
|
| 345 |
+
global void * o_void, ulong o_offset,
|
| 346 |
+
const float scale,
|
| 347 |
+
const int n_q,
|
| 348 |
+
const int n_kv,
|
| 349 |
+
const int is_causal,
|
| 350 |
+
const int n_head,
|
| 351 |
+
const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
|
| 352 |
+
const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
|
| 353 |
+
const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
|
| 354 |
+
const ulong o_nb1, const ulong o_nb2, const ulong o_nb3,
|
| 355 |
+
const float max_bias,
|
| 356 |
+
const float m0,
|
| 357 |
+
const float m1,
|
| 358 |
+
const int n_head_log2,
|
| 359 |
+
const float logit_softcap,
|
| 360 |
+
const int n_head_kv,
|
| 361 |
+
const global void* mask_void,
|
| 362 |
+
const ulong mask_offset,
|
| 363 |
+
const ulong mask_nb1,
|
| 364 |
+
const ulong mask_nb2,
|
| 365 |
+
const ulong mask_nb3,
|
| 366 |
+
const int mask_ne2,
|
| 367 |
+
const int mask_ne3,
|
| 368 |
+
const global void* sinks_void,
|
| 369 |
+
const ulong sinks_offset
|
| 370 |
+
) {
|
| 371 |
+
const int tid = get_local_id(0);
|
| 372 |
+
const int sgid = tid / Q1_WG_SIZE;
|
| 373 |
+
const int tid_sg = tid % Q1_WG_SIZE;
|
| 374 |
+
const int head_batch_idx = get_global_id(1);
|
| 375 |
+
|
| 376 |
+
const int batch_idx = head_batch_idx / n_head;
|
| 377 |
+
const int head_idx = head_batch_idx % n_head;
|
| 378 |
+
|
| 379 |
+
const int gqa_ratio = n_head / n_head_kv;
|
| 380 |
+
const int head_kv_idx = head_idx / gqa_ratio;
|
| 381 |
+
|
| 382 |
+
const global char * q_base = (const global char *) q_void + q_offset;
|
| 383 |
+
const global char * k_base = (const global char *) k_void + k_offset;
|
| 384 |
+
const global char * v_base = (const global char *) v_void + v_offset;
|
| 385 |
+
global char * o_base = (global char *) o_void + o_offset;
|
| 386 |
+
|
| 387 |
+
const global char * mask_base = NULL;
|
| 388 |
+
if (mask_void != NULL) {
|
| 389 |
+
const int mask_head_idx = head_idx % mask_ne2;
|
| 390 |
+
const int mask_batch_idx = batch_idx % mask_ne3;
|
| 391 |
+
mask_base = (const global char *) mask_void + mask_offset +
|
| 392 |
+
mask_batch_idx * mask_nb3 + mask_head_idx * mask_nb2;
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
__local ACC_TYPE4 q_shared[DK_VEC];
|
| 396 |
+
{
|
| 397 |
+
const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2;
|
| 398 |
+
const global Q_DATA_TYPE4 * q_ptr = (const global Q_DATA_TYPE4 *) (q_base + q_row_offset);
|
| 399 |
+
for (int i = tid; i < DK_VEC; i += VEC_WG_SIZE) {
|
| 400 |
+
q_shared[i] = CONVERT_Q_ACC4(q_ptr[i]);
|
| 401 |
+
}
|
| 402 |
+
}
|
| 403 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 404 |
+
|
| 405 |
+
const float slope = get_alibi_slope(max_bias, head_idx, n_head_log2, m0, m1);
|
| 406 |
+
|
| 407 |
+
const global ACC_TYPE * sinks_ptr = NULL;
|
| 408 |
+
if (sinks_void != NULL) {
|
| 409 |
+
sinks_ptr = (const global ACC_TYPE *) ((const global char *) sinks_void + sinks_offset);
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
ACC_TYPE4 o_acc[Q1V_DV_PER_THREAD];
|
| 413 |
+
#pragma unroll
|
| 414 |
+
for (int i = 0; i < Q1V_DV_PER_THREAD; ++i) o_acc[i] = (ACC_TYPE4)(0.0f);
|
| 415 |
+
|
| 416 |
+
ACC_TYPE m_i = FA_M_INIT;
|
| 417 |
+
ACC_TYPE l_i = 0.0f;
|
| 418 |
+
|
| 419 |
+
const int kv_per_sg = (n_kv + VEC_NSG - 1) / VEC_NSG;
|
| 420 |
+
const int kv_start = sgid * kv_per_sg;
|
| 421 |
+
const int kv_end = min(n_kv, kv_start + kv_per_sg);
|
| 422 |
+
|
| 423 |
+
for (int k_idx = kv_start; k_idx < kv_end; ++k_idx) {
|
| 424 |
+
const global char * k_row = k_base + batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_idx * k_nb1;
|
| 425 |
+
const global char * v_row = v_base + batch_idx * v_nb3 + head_kv_idx * v_nb2 + k_idx * v_nb1;
|
| 426 |
+
|
| 427 |
+
ACC_TYPE4 dot4 = (ACC_TYPE4)(0.0f);
|
| 428 |
+
for (int qk = tid_sg; qk < DK_VEC; qk += Q1_WG_SIZE) {
|
| 429 |
+
const int block_idx = qk / 8;
|
| 430 |
+
const int lane = qk % 8;
|
| 431 |
+
const float4 k_v = dequant_q8_0_lane(k_row + block_idx * Q8_0_BLOCK_SIZE, lane);
|
| 432 |
+
dot4 = mad(q_shared[qk], k_v, dot4);
|
| 433 |
+
}
|
| 434 |
+
ACC_TYPE dot_partial = dot4.s0 + dot4.s1 + dot4.s2 + dot4.s3;
|
| 435 |
+
ACC_TYPE score = sub_group_reduce_add(dot_partial) * scale;
|
| 436 |
+
|
| 437 |
+
if (mask_base != NULL) {
|
| 438 |
+
const global MASK_DATA_TYPE * mask_ptr = (const global MASK_DATA_TYPE *) mask_base;
|
| 439 |
+
score += slope * (ACC_TYPE) mask_ptr[k_idx];
|
| 440 |
+
}
|
| 441 |
+
if (logit_softcap > 0.0f) {
|
| 442 |
+
score = logit_softcap * tanh(score / logit_softcap);
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
const ACC_TYPE m_new = max(m_i, score);
|
| 446 |
+
const ACC_TYPE scale_prev = native_exp(m_i - m_new);
|
| 447 |
+
const ACC_TYPE p = native_exp(score - m_new);
|
| 448 |
+
|
| 449 |
+
int idx = 0;
|
| 450 |
+
for (int dv = tid_sg; dv < DV_VEC; dv += Q1_WG_SIZE, ++idx) {
|
| 451 |
+
const int block_idx = dv / 8;
|
| 452 |
+
const int lane = dv % 8;
|
| 453 |
+
const float4 v_v = dequant_q8_0_lane(v_row + block_idx * Q8_0_BLOCK_SIZE, lane);
|
| 454 |
+
o_acc[idx] = mad(p, v_v, o_acc[idx] * scale_prev);
|
| 455 |
+
}
|
| 456 |
+
l_i = l_i * scale_prev + p;
|
| 457 |
+
m_i = m_new;
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
__local ACC_TYPE sg_m[VEC_NSG];
|
| 461 |
+
__local ACC_TYPE sg_l[VEC_NSG];
|
| 462 |
+
__local ACC_TYPE4 sg_o[VEC_NSG][DV_VEC];
|
| 463 |
+
|
| 464 |
+
if (tid_sg == 0) {
|
| 465 |
+
sg_m[sgid] = m_i;
|
| 466 |
+
sg_l[sgid] = l_i;
|
| 467 |
+
}
|
| 468 |
+
{
|
| 469 |
+
int idx = 0;
|
| 470 |
+
for (int dv = tid_sg; dv < DV_VEC; dv += Q1_WG_SIZE, ++idx) {
|
| 471 |
+
sg_o[sgid][dv] = o_acc[idx];
|
| 472 |
+
}
|
| 473 |
+
}
|
| 474 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 475 |
+
|
| 476 |
+
if (sgid == 0) {
|
| 477 |
+
ACC_TYPE m_final = sg_m[0];
|
| 478 |
+
#pragma unroll
|
| 479 |
+
for (int s = 1; s < VEC_NSG; ++s) {
|
| 480 |
+
m_final = max(m_final, sg_m[s]);
|
| 481 |
+
}
|
| 482 |
+
if (sinks_ptr != NULL) {
|
| 483 |
+
m_final = max(m_final, sinks_ptr[head_idx]);
|
| 484 |
+
}
|
| 485 |
+
|
| 486 |
+
ACC_TYPE l_final = 0.0f;
|
| 487 |
+
#pragma unroll
|
| 488 |
+
for (int s = 0; s < VEC_NSG; ++s) {
|
| 489 |
+
l_final += sg_l[s] * native_exp(sg_m[s] - m_final);
|
| 490 |
+
}
|
| 491 |
+
if (sinks_ptr != NULL) {
|
| 492 |
+
l_final += native_exp(sinks_ptr[head_idx] - m_final);
|
| 493 |
+
}
|
| 494 |
+
const ACC_TYPE l_inv = (l_final > 0.0f) ? (1.0f / l_final) : 0.0f;
|
| 495 |
+
|
| 496 |
+
const ulong o_row_offset = batch_idx * o_nb3 + head_idx * o_nb1;
|
| 497 |
+
global O_DATA_TYPE4 * o_row = (global O_DATA_TYPE4 *) (o_base + o_row_offset);
|
| 498 |
+
|
| 499 |
+
int idx = 0;
|
| 500 |
+
for (int dv = tid_sg; dv < DV_VEC; dv += Q1_WG_SIZE, ++idx) {
|
| 501 |
+
ACC_TYPE4 o_merged = (ACC_TYPE4)(0.0f);
|
| 502 |
+
#pragma unroll
|
| 503 |
+
for (int s = 0; s < VEC_NSG; ++s) {
|
| 504 |
+
const ACC_TYPE alpha = native_exp(sg_m[s] - m_final);
|
| 505 |
+
o_merged = mad((ACC_TYPE4)(alpha), sg_o[s][dv], o_merged);
|
| 506 |
+
}
|
| 507 |
+
o_row[dv] = CONVERT_O_DATA4(o_merged * l_inv);
|
| 508 |
+
}
|
| 509 |
+
}
|
| 510 |
+
}
|
| 511 |
+
|
| 512 |
+
// Flash-decoding split pass for q8_0 KV. Partial record: [m, l, O[DV]].
|
| 513 |
+
// Merge kernel from flash_attn_f32_f16.cl is type-agnostic and reused.
|
| 514 |
+
#define FA_PARTIAL_FLOATS (2 + DV)
|
| 515 |
+
|
| 516 |
+
__kernel void flash_attn_f32_q8_0_q1_split(
|
| 517 |
+
const global void * q_void, ulong q_offset,
|
| 518 |
+
const global void * k_void, ulong k_offset,
|
| 519 |
+
const global void * v_void, ulong v_offset,
|
| 520 |
+
const float scale,
|
| 521 |
+
const int n_q,
|
| 522 |
+
const int n_kv,
|
| 523 |
+
const int n_head,
|
| 524 |
+
const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
|
| 525 |
+
const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
|
| 526 |
+
const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
|
| 527 |
+
const float max_bias,
|
| 528 |
+
const float m0,
|
| 529 |
+
const float m1,
|
| 530 |
+
const int n_head_log2,
|
| 531 |
+
const float logit_softcap,
|
| 532 |
+
const int n_head_kv,
|
| 533 |
+
const global void * mask_void,
|
| 534 |
+
const ulong mask_offset,
|
| 535 |
+
const ulong mask_nb1,
|
| 536 |
+
const ulong mask_nb2,
|
| 537 |
+
const ulong mask_nb3,
|
| 538 |
+
const int mask_ne2,
|
| 539 |
+
const int mask_ne3,
|
| 540 |
+
global float * partial_void,
|
| 541 |
+
const int n_splits,
|
| 542 |
+
const int kv_per_split
|
| 543 |
+
) {
|
| 544 |
+
const int tid = get_local_id(0);
|
| 545 |
+
const int head_batch_idx = get_global_id(1);
|
| 546 |
+
const int split_q_idx = get_global_id(2);
|
| 547 |
+
const int split_idx = split_q_idx % n_splits;
|
| 548 |
+
const int q_idx = split_q_idx / n_splits;
|
| 549 |
+
const int batch_idx = head_batch_idx / n_head;
|
| 550 |
+
const int head_idx = head_batch_idx % n_head;
|
| 551 |
+
const int gqa_ratio = n_head / n_head_kv;
|
| 552 |
+
const int head_kv_idx = head_idx / gqa_ratio;
|
| 553 |
+
|
| 554 |
+
const int kv_start = split_idx * kv_per_split;
|
| 555 |
+
const int kv_end = min(kv_start + kv_per_split, n_kv);
|
| 556 |
+
|
| 557 |
+
const ulong record_stride = (ulong) FA_PARTIAL_FLOATS;
|
| 558 |
+
const ulong record_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
|
| 559 |
+
* n_splits + split_idx);
|
| 560 |
+
global float * rec = partial_void + record_idx * record_stride;
|
| 561 |
+
global float4 * rec_o = (global float4 *) (rec + 2);
|
| 562 |
+
|
| 563 |
+
if (kv_start >= kv_end) {
|
| 564 |
+
// Empty split: leave sentinel partial for merge.
|
| 565 |
+
if (tid == 0) {
|
| 566 |
+
rec[0] = FA_M_INIT;
|
| 567 |
+
rec[1] = 0.0f;
|
| 568 |
+
}
|
| 569 |
+
return;
|
| 570 |
+
}
|
| 571 |
+
|
| 572 |
+
const global char * q_base = (const global char *) q_void + q_offset;
|
| 573 |
+
const global char * k_base = (const global char *) k_void + k_offset;
|
| 574 |
+
const global char * v_base = (const global char *) v_void + v_offset;
|
| 575 |
+
|
| 576 |
+
const global char * mask_base = NULL;
|
| 577 |
+
if (mask_void != NULL) {
|
| 578 |
+
const int mask_head_idx = head_idx % mask_ne2;
|
| 579 |
+
const int mask_batch_idx = batch_idx % mask_ne3;
|
| 580 |
+
mask_base = (const global char *) mask_void + mask_offset +
|
| 581 |
+
mask_batch_idx * mask_nb3 + mask_head_idx * mask_nb2 +
|
| 582 |
+
(ulong) q_idx * mask_nb1;
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
ACC_TYPE4 q_priv[DK_VEC];
|
| 586 |
+
const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2 + (ulong) q_idx * q_nb1;
|
| 587 |
+
const global Q_DATA_TYPE4 * q_ptr = (const global Q_DATA_TYPE4 *) (q_base + q_row_offset);
|
| 588 |
+
#pragma unroll
|
| 589 |
+
for (int i = 0; i < DK_VEC; ++i) {
|
| 590 |
+
q_priv[i] = CONVERT_Q_ACC4(q_ptr[i]);
|
| 591 |
+
}
|
| 592 |
+
|
| 593 |
+
#ifdef FA_HAVE_INT_DOT
|
| 594 |
+
uint q_packed[DK_Q8_BLOCKS * 8];
|
| 595 |
+
float q_d_scale[DK_Q8_BLOCKS];
|
| 596 |
+
#pragma unroll
|
| 597 |
+
for (int b = 0; b < DK_Q8_BLOCKS; ++b) {
|
| 598 |
+
q_d_scale[b] = quant_q_block_int8_packed(&q_priv[b * 8], &q_packed[b * 8]);
|
| 599 |
+
}
|
| 600 |
+
#endif
|
| 601 |
+
|
| 602 |
+
const float slope = get_alibi_slope(max_bias, head_idx, n_head_log2, m0, m1);
|
| 603 |
+
|
| 604 |
+
// One-pass online softmax (FA-2): single sweep over the split's K range,
|
| 605 |
+
// updating per-thread (m_i, l_i, o_acc) per position. Eliminates the
|
| 606 |
+
// second K read of the original two-pass implementation.
|
| 607 |
+
ACC_TYPE m_i = FA_M_INIT;
|
| 608 |
+
ACC_TYPE l_i = 0.0f;
|
| 609 |
+
ACC_TYPE4 o_acc[DV_VEC];
|
| 610 |
+
#pragma unroll
|
| 611 |
+
for (int i = 0; i < DV_VEC; ++i) o_acc[i] = (ACC_TYPE4)(0.0f);
|
| 612 |
+
|
| 613 |
+
for (int k_idx = kv_start + tid; k_idx < kv_end; k_idx += Q1_WG_SIZE) {
|
| 614 |
+
const global char * k_row = k_base + batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_idx * k_nb1;
|
| 615 |
+
const global char * v_row = v_base + batch_idx * v_nb3 + head_kv_idx * v_nb2 + k_idx * v_nb1;
|
| 616 |
+
ACC_TYPE score = 0.0f;
|
| 617 |
+
#pragma unroll
|
| 618 |
+
for (int b = 0; b < DK_Q8_BLOCKS; ++b) {
|
| 619 |
+
#ifdef FA_HAVE_INT_DOT
|
| 620 |
+
score += dot_q8_0_int(k_row + b * Q8_0_BLOCK_SIZE, &q_packed[b * 8], q_d_scale[b]);
|
| 621 |
+
#else
|
| 622 |
+
score += dot_q8_0_f32(k_row + b * Q8_0_BLOCK_SIZE, &q_priv[b * 8]);
|
| 623 |
+
#endif
|
| 624 |
+
}
|
| 625 |
+
score *= scale;
|
| 626 |
+
if (mask_base != NULL) {
|
| 627 |
+
const global MASK_DATA_TYPE * mask_ptr = (const global MASK_DATA_TYPE *) (mask_base);
|
| 628 |
+
score += slope * (ACC_TYPE) mask_ptr[k_idx];
|
| 629 |
+
}
|
| 630 |
+
if (logit_softcap > 0.0f) {
|
| 631 |
+
score = logit_softcap * tanh(score / logit_softcap);
|
| 632 |
+
}
|
| 633 |
+
|
| 634 |
+
// Online softmax step.
|
| 635 |
+
const ACC_TYPE m_new = max(m_i, score);
|
| 636 |
+
const ACC_TYPE alpha = exp(m_i - m_new);
|
| 637 |
+
const ACC_TYPE p = exp(score - m_new);
|
| 638 |
+
|
| 639 |
+
l_i = alpha * l_i + p;
|
| 640 |
+
#pragma unroll
|
| 641 |
+
for (int i = 0; i < DV_VEC; ++i) o_acc[i] *= alpha;
|
| 642 |
+
|
| 643 |
+
#pragma unroll
|
| 644 |
+
for (int b = 0; b < DV_Q8_BLOCKS; ++b) {
|
| 645 |
+
ACC_TYPE4 v_dequant[8];
|
| 646 |
+
dequant_q8_0_f32(v_row + b * Q8_0_BLOCK_SIZE, v_dequant);
|
| 647 |
+
#pragma unroll
|
| 648 |
+
for (int i = 0; i < 8; ++i) {
|
| 649 |
+
o_acc[b * 8 + i] = mad(p, v_dequant[i], o_acc[b * 8 + i]);
|
| 650 |
+
}
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
m_i = m_new;
|
| 654 |
+
}
|
| 655 |
+
|
| 656 |
+
// Cross-thread reduce: max(m_i) -> m_c, then rescale per-thread l_i and
|
| 657 |
+
// o_acc by alpha = exp(m_i_thread - m_c) before sum-reduce.
|
| 658 |
+
__local ACC_TYPE local_m[Q1_WG_SIZE];
|
| 659 |
+
local_m[tid] = m_i;
|
| 660 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 661 |
+
#pragma unroll
|
| 662 |
+
for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
|
| 663 |
+
if (tid < s) local_m[tid] = max(local_m[tid], local_m[tid + s]);
|
| 664 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 665 |
+
}
|
| 666 |
+
const ACC_TYPE m_c = local_m[0];
|
| 667 |
+
|
| 668 |
+
const ACC_TYPE alpha_final = exp(m_i - m_c);
|
| 669 |
+
l_i *= alpha_final;
|
| 670 |
+
#pragma unroll
|
| 671 |
+
for (int i = 0; i < DV_VEC; ++i) o_acc[i] *= alpha_final;
|
| 672 |
+
|
| 673 |
+
__local ACC_TYPE local_l[Q1_WG_SIZE];
|
| 674 |
+
__local ACC_TYPE4 local_o[Q1_WG_SIZE];
|
| 675 |
+
local_l[tid] = l_i;
|
| 676 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 677 |
+
#pragma unroll
|
| 678 |
+
for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
|
| 679 |
+
if (tid < s) local_l[tid] += local_l[tid + s];
|
| 680 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 681 |
+
}
|
| 682 |
+
const ACC_TYPE l_c = local_l[0];
|
| 683 |
+
|
| 684 |
+
if (tid == 0) {
|
| 685 |
+
rec[0] = (float) m_c;
|
| 686 |
+
rec[1] = (float) l_c;
|
| 687 |
+
}
|
| 688 |
+
for (int i = 0; i < DV_VEC; ++i) {
|
| 689 |
+
local_o[tid] = o_acc[i];
|
| 690 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 691 |
+
#pragma unroll
|
| 692 |
+
for (int s = Q1_WG_SIZE / 2; s > 0; s >>= 1) {
|
| 693 |
+
if (tid < s) local_o[tid] += local_o[tid + s];
|
| 694 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 695 |
+
}
|
| 696 |
+
if (tid == 0) {
|
| 697 |
+
rec_o[i] = local_o[0];
|
| 698 |
+
}
|
| 699 |
+
}
|
| 700 |
+
}
|
| 701 |
+
|
| 702 |
+
// Prefill: q8_0 K/V, n_q > 1. BLOCK_M × BLOCK_N tiling.
|
| 703 |
+
// K path keeps packed int8 in local for dp4a QK dot; V path dequant -> half in local.
|
| 704 |
+
// Requires DK % QK8_0 == 0 and DV % QK8_0 == 0 (gated in supports_op).
|
| 705 |
+
#define KV_DATA_TYPE4 half4
|
| 706 |
+
#define CONVERT_KV_ACC4(x) convert_float4(x)
|
| 707 |
+
|
| 708 |
+
#define DK_Q8_BLOCKS_PREFILL (DK / QK8_0)
|
| 709 |
+
#define DV_Q8_BLOCKS_PREFILL (DV / QK8_0)
|
| 710 |
+
|
| 711 |
+
// N_SPLIT>1 splits DK/DV across N_SPLIT threads per query row; needs
|
| 712 |
+
// sub_group_shuffle_xor and DK_Q8_BLOCKS_PREFILL % N_SPLIT == 0.
|
| 713 |
+
#ifndef N_SPLIT
|
| 714 |
+
#define N_SPLIT 1
|
| 715 |
+
#endif
|
| 716 |
+
|
| 717 |
+
#if N_SPLIT > 1
|
| 718 |
+
#define SPLIT_DK_VEC (DK_VEC / N_SPLIT)
|
| 719 |
+
#define SPLIT_DV_VEC (DV_VEC / N_SPLIT)
|
| 720 |
+
#define SPLIT_DK_Q8_BLOCKS (DK_Q8_BLOCKS_PREFILL / N_SPLIT)
|
| 721 |
+
#define WG_SIZE (BLOCK_M * N_SPLIT)
|
| 722 |
+
#else
|
| 723 |
+
#define SPLIT_DK_VEC DK_VEC
|
| 724 |
+
#define SPLIT_DV_VEC DV_VEC
|
| 725 |
+
#define SPLIT_DK_Q8_BLOCKS DK_Q8_BLOCKS_PREFILL
|
| 726 |
+
#define WG_SIZE BLOCK_M
|
| 727 |
+
#endif
|
| 728 |
+
|
| 729 |
+
// FA_V_STRATEGY: 0 = dequant V to half in local (default); 2 = keep packed
|
| 730 |
+
// int8 in local, dequant in the accumulate loop (smaller local, slightly slower).
|
| 731 |
+
#ifndef FA_V_STRATEGY
|
| 732 |
+
#define FA_V_STRATEGY 0
|
| 733 |
+
#endif
|
| 734 |
+
|
| 735 |
+
#ifndef MQ_GQA
|
| 736 |
+
#define MQ_GQA 4
|
| 737 |
+
#endif
|
| 738 |
+
#ifndef MQ_NSG_SPLIT
|
| 739 |
+
#define MQ_NSG_SPLIT 4
|
| 740 |
+
#endif
|
| 741 |
+
#define MQ_SPLIT_WG_SIZE_Q8 (Q1_WG_SIZE * MQ_NSG_SPLIT)
|
| 742 |
+
|
| 743 |
+
REQD_SUBGROUP_SIZE_64
|
| 744 |
+
__kernel void flash_attn_f32_q8_0_q1_vec_mq_split(
|
| 745 |
+
const global void * q_void, ulong q_offset,
|
| 746 |
+
const global void * k_void, ulong k_offset,
|
| 747 |
+
const global void * v_void, ulong v_offset,
|
| 748 |
+
const float scale,
|
| 749 |
+
const int n_q,
|
| 750 |
+
const int n_kv,
|
| 751 |
+
const int n_head,
|
| 752 |
+
const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
|
| 753 |
+
const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
|
| 754 |
+
const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
|
| 755 |
+
const float max_bias,
|
| 756 |
+
const float m0,
|
| 757 |
+
const float m1,
|
| 758 |
+
const int n_head_log2,
|
| 759 |
+
const float logit_softcap,
|
| 760 |
+
const int n_head_kv,
|
| 761 |
+
const global void * mask_void,
|
| 762 |
+
const ulong mask_offset,
|
| 763 |
+
const ulong mask_nb1,
|
| 764 |
+
const ulong mask_nb2,
|
| 765 |
+
const ulong mask_nb3,
|
| 766 |
+
const int mask_ne2,
|
| 767 |
+
const int mask_ne3,
|
| 768 |
+
global float * partial_void,
|
| 769 |
+
const int n_splits,
|
| 770 |
+
const int kv_per_split
|
| 771 |
+
) {
|
| 772 |
+
const int tid = get_local_id(0);
|
| 773 |
+
const int sgid = tid / Q1_WG_SIZE;
|
| 774 |
+
const int tid_sg = tid % Q1_WG_SIZE;
|
| 775 |
+
const int kvhead_batch_idx = get_global_id(1);
|
| 776 |
+
const int split_q_idx = get_global_id(2);
|
| 777 |
+
const int split_idx = split_q_idx % n_splits;
|
| 778 |
+
const int q_idx = split_q_idx / n_splits;
|
| 779 |
+
|
| 780 |
+
const int batch_idx = kvhead_batch_idx / n_head_kv;
|
| 781 |
+
const int head_kv_idx = kvhead_batch_idx % n_head_kv;
|
| 782 |
+
|
| 783 |
+
const int kv_start = split_idx * kv_per_split;
|
| 784 |
+
const int kv_end = min(kv_start + kv_per_split, n_kv);
|
| 785 |
+
|
| 786 |
+
const ulong record_stride = (ulong) FA_PARTIAL_FLOATS;
|
| 787 |
+
|
| 788 |
+
if (kv_start >= kv_end) {
|
| 789 |
+
// Empty split — write sentinel for each of the MQ_GQA Q-heads.
|
| 790 |
+
if (tid == 0) {
|
| 791 |
+
#pragma unroll
|
| 792 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 793 |
+
const int head_idx = head_kv_idx * MQ_GQA + h;
|
| 794 |
+
const ulong rec_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
|
| 795 |
+
* n_splits + split_idx);
|
| 796 |
+
global float * rec = partial_void + rec_idx * record_stride;
|
| 797 |
+
rec[0] = FA_M_INIT;
|
| 798 |
+
rec[1] = 0.0f;
|
| 799 |
+
}
|
| 800 |
+
}
|
| 801 |
+
return;
|
| 802 |
+
}
|
| 803 |
+
|
| 804 |
+
const global char * q_base = (const global char *) q_void + q_offset;
|
| 805 |
+
const global char * k_base = (const global char *) k_void + k_offset;
|
| 806 |
+
const global char * v_base = (const global char *) v_void + v_offset;
|
| 807 |
+
|
| 808 |
+
__local ACC_TYPE4 q_shared[MQ_GQA * DK_VEC];
|
| 809 |
+
for (int i = tid; i < MQ_GQA * DK_VEC; i += MQ_SPLIT_WG_SIZE_Q8) {
|
| 810 |
+
const int h = i / DK_VEC;
|
| 811 |
+
const int k = i % DK_VEC;
|
| 812 |
+
const int head_idx = head_kv_idx * MQ_GQA + h;
|
| 813 |
+
const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2 + (ulong) q_idx * q_nb1;
|
| 814 |
+
const global Q_DATA_TYPE4 * q_ptr = (const global Q_DATA_TYPE4 *) (q_base + q_row_offset);
|
| 815 |
+
q_shared[h * DK_VEC + k] = CONVERT_Q_ACC4(q_ptr[k]);
|
| 816 |
+
}
|
| 817 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 818 |
+
|
| 819 |
+
float slope[MQ_GQA];
|
| 820 |
+
#pragma unroll
|
| 821 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 822 |
+
slope[h] = get_alibi_slope(max_bias, head_kv_idx * MQ_GQA + h, n_head_log2, m0, m1);
|
| 823 |
+
}
|
| 824 |
+
|
| 825 |
+
const global char * mask_base[MQ_GQA];
|
| 826 |
+
if (mask_void != NULL) {
|
| 827 |
+
const int mask_batch_idx = batch_idx % mask_ne3;
|
| 828 |
+
const global char * mask_base_b = (const global char *) mask_void + mask_offset +
|
| 829 |
+
mask_batch_idx * mask_nb3 +
|
| 830 |
+
(ulong) q_idx * mask_nb1;
|
| 831 |
+
#pragma unroll
|
| 832 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 833 |
+
const int head_idx = head_kv_idx * MQ_GQA + h;
|
| 834 |
+
const int mask_head_idx = head_idx % mask_ne2;
|
| 835 |
+
mask_base[h] = mask_base_b + mask_head_idx * mask_nb2;
|
| 836 |
+
}
|
| 837 |
+
} else {
|
| 838 |
+
#pragma unroll
|
| 839 |
+
for (int h = 0; h < MQ_GQA; ++h) mask_base[h] = NULL;
|
| 840 |
+
}
|
| 841 |
+
|
| 842 |
+
ACC_TYPE4 o_acc[MQ_GQA][Q1V_DV_PER_THREAD];
|
| 843 |
+
ACC_TYPE m_i[MQ_GQA];
|
| 844 |
+
ACC_TYPE l_i[MQ_GQA];
|
| 845 |
+
#pragma unroll
|
| 846 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 847 |
+
m_i[h] = FA_M_INIT;
|
| 848 |
+
l_i[h] = 0.0f;
|
| 849 |
+
#pragma unroll
|
| 850 |
+
for (int i = 0; i < Q1V_DV_PER_THREAD; ++i) o_acc[h][i] = (ACC_TYPE4)(0.0f);
|
| 851 |
+
}
|
| 852 |
+
|
| 853 |
+
const int kv_len = kv_end - kv_start;
|
| 854 |
+
const int kv_per_sg = (kv_len + MQ_NSG_SPLIT - 1) / MQ_NSG_SPLIT;
|
| 855 |
+
const int kv_lo = kv_start + sgid * kv_per_sg;
|
| 856 |
+
const int kv_hi = min(kv_end, kv_lo + kv_per_sg);
|
| 857 |
+
|
| 858 |
+
for (int k_idx = kv_lo; k_idx < kv_hi; ++k_idx) {
|
| 859 |
+
const global char * k_row = k_base + batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_idx * k_nb1;
|
| 860 |
+
const global char * v_row = v_base + batch_idx * v_nb3 + head_kv_idx * v_nb2 + k_idx * v_nb1;
|
| 861 |
+
|
| 862 |
+
ACC_TYPE4 dot4[MQ_GQA];
|
| 863 |
+
#pragma unroll
|
| 864 |
+
for (int h = 0; h < MQ_GQA; ++h) dot4[h] = (ACC_TYPE4)(0.0f);
|
| 865 |
+
|
| 866 |
+
for (int qk = tid_sg; qk < DK_VEC; qk += Q1_WG_SIZE) {
|
| 867 |
+
const int block_idx = qk / 8;
|
| 868 |
+
const int lane = qk % 8;
|
| 869 |
+
const float4 k_v = dequant_q8_0_lane(k_row + block_idx * Q8_0_BLOCK_SIZE, lane);
|
| 870 |
+
#pragma unroll
|
| 871 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 872 |
+
dot4[h] = mad(q_shared[h * DK_VEC + qk], k_v, dot4[h]);
|
| 873 |
+
}
|
| 874 |
+
}
|
| 875 |
+
|
| 876 |
+
ACC_TYPE score[MQ_GQA];
|
| 877 |
+
#pragma unroll
|
| 878 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 879 |
+
const ACC_TYPE dot_partial = dot4[h].s0 + dot4[h].s1 + dot4[h].s2 + dot4[h].s3;
|
| 880 |
+
ACC_TYPE s = sub_group_reduce_add(dot_partial) * scale;
|
| 881 |
+
if (mask_base[h] != NULL) {
|
| 882 |
+
const global MASK_DATA_TYPE * mask_ptr = (const global MASK_DATA_TYPE *) mask_base[h];
|
| 883 |
+
s += slope[h] * (ACC_TYPE) mask_ptr[k_idx];
|
| 884 |
+
}
|
| 885 |
+
if (logit_softcap > 0.0f) {
|
| 886 |
+
s = logit_softcap * tanh(s / logit_softcap);
|
| 887 |
+
}
|
| 888 |
+
score[h] = s;
|
| 889 |
+
}
|
| 890 |
+
|
| 891 |
+
ACC_TYPE p_h[MQ_GQA];
|
| 892 |
+
ACC_TYPE sp_h[MQ_GQA];
|
| 893 |
+
#pragma unroll
|
| 894 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 895 |
+
const ACC_TYPE m_new = max(m_i[h], score[h]);
|
| 896 |
+
sp_h[h] = native_exp(m_i[h] - m_new);
|
| 897 |
+
p_h[h] = native_exp(score[h] - m_new);
|
| 898 |
+
l_i[h] = l_i[h] * sp_h[h] + p_h[h];
|
| 899 |
+
m_i[h] = m_new;
|
| 900 |
+
}
|
| 901 |
+
|
| 902 |
+
int idx = 0;
|
| 903 |
+
for (int dv = tid_sg; dv < DV_VEC; dv += Q1_WG_SIZE, ++idx) {
|
| 904 |
+
const int block_idx = dv / 8;
|
| 905 |
+
const int lane = dv % 8;
|
| 906 |
+
const float4 v_v = dequant_q8_0_lane(v_row + block_idx * Q8_0_BLOCK_SIZE, lane);
|
| 907 |
+
#pragma unroll
|
| 908 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 909 |
+
o_acc[h][idx] = mad(p_h[h], v_v, o_acc[h][idx] * sp_h[h]);
|
| 910 |
+
}
|
| 911 |
+
}
|
| 912 |
+
}
|
| 913 |
+
|
| 914 |
+
__local ACC_TYPE sg_m[MQ_GQA][MQ_NSG_SPLIT];
|
| 915 |
+
__local ACC_TYPE sg_l[MQ_GQA][MQ_NSG_SPLIT];
|
| 916 |
+
__local ACC_TYPE4 sg_o[MQ_NSG_SPLIT][DV_VEC];
|
| 917 |
+
|
| 918 |
+
if (tid_sg == 0) {
|
| 919 |
+
#pragma unroll
|
| 920 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 921 |
+
sg_m[h][sgid] = m_i[h];
|
| 922 |
+
sg_l[h][sgid] = l_i[h];
|
| 923 |
+
}
|
| 924 |
+
}
|
| 925 |
+
|
| 926 |
+
#pragma unroll
|
| 927 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 928 |
+
{
|
| 929 |
+
int idx = 0;
|
| 930 |
+
for (int dv_idx = tid_sg; dv_idx < DV_VEC; dv_idx += Q1_WG_SIZE, ++idx) {
|
| 931 |
+
sg_o[sgid][dv_idx] = o_acc[h][idx];
|
| 932 |
+
}
|
| 933 |
+
}
|
| 934 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 935 |
+
|
| 936 |
+
if (sgid == 0) {
|
| 937 |
+
const int head_idx = head_kv_idx * MQ_GQA + h;
|
| 938 |
+
|
| 939 |
+
ACC_TYPE m_c = sg_m[h][0];
|
| 940 |
+
#pragma unroll
|
| 941 |
+
for (int s = 1; s < MQ_NSG_SPLIT; ++s) {
|
| 942 |
+
m_c = max(m_c, sg_m[h][s]);
|
| 943 |
+
}
|
| 944 |
+
ACC_TYPE l_c = 0.0f;
|
| 945 |
+
#pragma unroll
|
| 946 |
+
for (int s = 0; s < MQ_NSG_SPLIT; ++s) {
|
| 947 |
+
l_c += sg_l[h][s] * native_exp(sg_m[h][s] - m_c);
|
| 948 |
+
}
|
| 949 |
+
|
| 950 |
+
const ulong rec_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
|
| 951 |
+
* n_splits + split_idx);
|
| 952 |
+
global float * rec = partial_void + rec_idx * record_stride;
|
| 953 |
+
global float4 * rec_o = (global float4 *) (rec + 2);
|
| 954 |
+
|
| 955 |
+
if (tid_sg == 0) {
|
| 956 |
+
rec[0] = (float) m_c;
|
| 957 |
+
rec[1] = (float) l_c;
|
| 958 |
+
}
|
| 959 |
+
for (int dv_idx = tid_sg; dv_idx < DV_VEC; dv_idx += Q1_WG_SIZE) {
|
| 960 |
+
ACC_TYPE4 o_merged = (ACC_TYPE4)(0.0f);
|
| 961 |
+
#pragma unroll
|
| 962 |
+
for (int s = 0; s < MQ_NSG_SPLIT; ++s) {
|
| 963 |
+
const ACC_TYPE alpha = native_exp(sg_m[h][s] - m_c);
|
| 964 |
+
o_merged = mad((ACC_TYPE4)(alpha), sg_o[s][dv_idx], o_merged);
|
| 965 |
+
}
|
| 966 |
+
rec_o[dv_idx] = o_merged;
|
| 967 |
+
}
|
| 968 |
+
}
|
| 969 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 970 |
+
}
|
| 971 |
+
}
|
| 972 |
+
|
| 973 |
+
// flash_attn_f32_q8_0_q1_vec_mq_split_c8 — cluster-parallel variant of the MQ
|
| 974 |
+
// split above, port of the f16/q4_0 c8 kernels
|
| 975 |
+
|
| 976 |
+
#ifdef HAS_SUBGROUP_SHUFFLE
|
| 977 |
+
|
| 978 |
+
#ifndef FA_CL_C
|
| 979 |
+
#define FA_CL_C 8
|
| 980 |
+
#endif
|
| 981 |
+
|
| 982 |
+
// Lane striping requires DK/DV to divide across the cluster (see f16 c8).
|
| 983 |
+
#if (DK_VEC % FA_CL_C) == 0 && (DV_VEC % FA_CL_C) == 0
|
| 984 |
+
#define FA_CL_NCL (Q1_WG_SIZE / FA_CL_C) // clusters (position streams) per subgroup
|
| 985 |
+
#define FA_CL_DKQ (DK_VEC / FA_CL_C) // K quartets per lane per row
|
| 986 |
+
#define FA_CL_DVQ (DV_VEC / FA_CL_C) // V quartets (o_acc float4s) per lane per head
|
| 987 |
+
|
| 988 |
+
#ifdef FA_C8_NO_SG_PIN
|
| 989 |
+
#define FA_C8_SG_ATTR_Q8
|
| 990 |
+
#else
|
| 991 |
+
#define FA_C8_SG_ATTR_Q8 REQD_SUBGROUP_SIZE_64
|
| 992 |
+
#endif
|
| 993 |
+
|
| 994 |
+
FA_C8_SG_ATTR_Q8
|
| 995 |
+
__kernel void flash_attn_f32_q8_0_q1_vec_mq_split_c8(
|
| 996 |
+
const global void * q_void, ulong q_offset,
|
| 997 |
+
const global void * k_void, ulong k_offset,
|
| 998 |
+
const global void * v_void, ulong v_offset,
|
| 999 |
+
const float scale,
|
| 1000 |
+
const int n_q,
|
| 1001 |
+
const int n_kv,
|
| 1002 |
+
const int n_head,
|
| 1003 |
+
const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
|
| 1004 |
+
const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
|
| 1005 |
+
const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
|
| 1006 |
+
const float max_bias,
|
| 1007 |
+
const float m0,
|
| 1008 |
+
const float m1,
|
| 1009 |
+
const int n_head_log2,
|
| 1010 |
+
const float logit_softcap,
|
| 1011 |
+
const int n_head_kv,
|
| 1012 |
+
const global void * mask_void,
|
| 1013 |
+
const ulong mask_offset,
|
| 1014 |
+
const ulong mask_nb1,
|
| 1015 |
+
const ulong mask_nb2,
|
| 1016 |
+
const ulong mask_nb3,
|
| 1017 |
+
const int mask_ne2,
|
| 1018 |
+
const int mask_ne3,
|
| 1019 |
+
global float * partial_void,
|
| 1020 |
+
const int n_splits,
|
| 1021 |
+
const int kv_per_split
|
| 1022 |
+
) {
|
| 1023 |
+
const int tid = get_local_id(0);
|
| 1024 |
+
const int sgid = tid / Q1_WG_SIZE;
|
| 1025 |
+
const int tid_sg = tid % Q1_WG_SIZE;
|
| 1026 |
+
const int cl = tid_sg / FA_CL_C; // cluster id
|
| 1027 |
+
const int lic = tid_sg % FA_CL_C; // lane in cluster
|
| 1028 |
+
const int kvhead_batch_idx = get_global_id(1);
|
| 1029 |
+
const int split_q_idx = get_global_id(2);
|
| 1030 |
+
const int split_idx = split_q_idx % n_splits;
|
| 1031 |
+
const int q_idx = split_q_idx / n_splits;
|
| 1032 |
+
|
| 1033 |
+
const int batch_idx = kvhead_batch_idx / n_head_kv;
|
| 1034 |
+
const int head_kv_idx = kvhead_batch_idx % n_head_kv;
|
| 1035 |
+
|
| 1036 |
+
const int kv_start = split_idx * kv_per_split;
|
| 1037 |
+
const int kv_end = min(kv_start + kv_per_split, n_kv);
|
| 1038 |
+
|
| 1039 |
+
const ulong record_stride = (ulong) FA_PARTIAL_FLOATS;
|
| 1040 |
+
|
| 1041 |
+
if (kv_start >= kv_end) {
|
| 1042 |
+
if (tid == 0) {
|
| 1043 |
+
#pragma unroll
|
| 1044 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1045 |
+
const int head_idx = head_kv_idx * MQ_GQA + h;
|
| 1046 |
+
const ulong rec_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
|
| 1047 |
+
* n_splits + split_idx);
|
| 1048 |
+
global float * rec = partial_void + rec_idx * record_stride;
|
| 1049 |
+
rec[0] = FA_M_INIT;
|
| 1050 |
+
rec[1] = 0.0f;
|
| 1051 |
+
}
|
| 1052 |
+
}
|
| 1053 |
+
return;
|
| 1054 |
+
}
|
| 1055 |
+
|
| 1056 |
+
const global char * q_base = (const global char *) q_void + q_offset;
|
| 1057 |
+
const global char * k_base = (const global char *) k_void + k_offset;
|
| 1058 |
+
const global char * v_base = (const global char *) v_void + v_offset;
|
| 1059 |
+
|
| 1060 |
+
// Stage MQ_GQA Q rows in __local once (uniform across WG).
|
| 1061 |
+
__local ACC_TYPE4 q_shared[MQ_GQA * DK_VEC];
|
| 1062 |
+
for (int i = tid; i < MQ_GQA * DK_VEC; i += MQ_SPLIT_WG_SIZE_Q8) {
|
| 1063 |
+
const int h = i / DK_VEC;
|
| 1064 |
+
const int k = i % DK_VEC;
|
| 1065 |
+
const int head_idx = head_kv_idx * MQ_GQA + h;
|
| 1066 |
+
const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2 + (ulong) q_idx * q_nb1;
|
| 1067 |
+
const global Q_DATA_TYPE4 * q_ptr = (const global Q_DATA_TYPE4 *) (q_base + q_row_offset);
|
| 1068 |
+
q_shared[h * DK_VEC + k] = CONVERT_Q_ACC4(q_ptr[k]);
|
| 1069 |
+
}
|
| 1070 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 1071 |
+
|
| 1072 |
+
float slope[MQ_GQA];
|
| 1073 |
+
#pragma unroll
|
| 1074 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1075 |
+
slope[h] = get_alibi_slope(max_bias, head_kv_idx * MQ_GQA + h, n_head_log2, m0, m1);
|
| 1076 |
+
}
|
| 1077 |
+
|
| 1078 |
+
const global char * mask_base[MQ_GQA];
|
| 1079 |
+
if (mask_void != NULL) {
|
| 1080 |
+
const int mask_batch_idx = batch_idx % mask_ne3;
|
| 1081 |
+
const global char * mask_base_b = (const global char *) mask_void + mask_offset +
|
| 1082 |
+
mask_batch_idx * mask_nb3 +
|
| 1083 |
+
(ulong) q_idx * mask_nb1;
|
| 1084 |
+
#pragma unroll
|
| 1085 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1086 |
+
const int head_idx = head_kv_idx * MQ_GQA + h;
|
| 1087 |
+
const int mask_head_idx = head_idx % mask_ne2;
|
| 1088 |
+
mask_base[h] = mask_base_b + mask_head_idx * mask_nb2;
|
| 1089 |
+
}
|
| 1090 |
+
} else {
|
| 1091 |
+
#pragma unroll
|
| 1092 |
+
for (int h = 0; h < MQ_GQA; ++h) mask_base[h] = NULL;
|
| 1093 |
+
}
|
| 1094 |
+
|
| 1095 |
+
// Per-CLUSTER online state; o_acc holds this lane's V quartets {lic + FA_CL_C*i}.
|
| 1096 |
+
ACC_TYPE4 o_acc[MQ_GQA][FA_CL_DVQ];
|
| 1097 |
+
ACC_TYPE m_i[MQ_GQA];
|
| 1098 |
+
ACC_TYPE l_i[MQ_GQA];
|
| 1099 |
+
#pragma unroll
|
| 1100 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1101 |
+
m_i[h] = FA_M_INIT;
|
| 1102 |
+
l_i[h] = 0.0f;
|
| 1103 |
+
#pragma unroll
|
| 1104 |
+
for (int i = 0; i < FA_CL_DVQ; ++i) o_acc[h][i] = (ACC_TYPE4)(0.0f);
|
| 1105 |
+
}
|
| 1106 |
+
|
| 1107 |
+
const int kv_len = kv_end - kv_start;
|
| 1108 |
+
const int kv_per_sg = (kv_len + MQ_NSG_SPLIT - 1) / MQ_NSG_SPLIT;
|
| 1109 |
+
const int kv_lo = kv_start + sgid * kv_per_sg;
|
| 1110 |
+
const int kv_hi = min(kv_end, kv_lo + kv_per_sg);
|
| 1111 |
+
|
| 1112 |
+
// Uniform trip count; tail clamps the row address and drops the score to
|
| 1113 |
+
// FA_M_INIT (p underflows to 0) so shuffles stay convergent.
|
| 1114 |
+
const int n_iter = (kv_hi - kv_lo + FA_CL_NCL - 1) / FA_CL_NCL;
|
| 1115 |
+
const ulong k_row_base = batch_idx * k_nb3 + head_kv_idx * k_nb2;
|
| 1116 |
+
const ulong v_row_base = batch_idx * v_nb3 + head_kv_idx * v_nb2;
|
| 1117 |
+
|
| 1118 |
+
for (int it = 0; it < n_iter; ++it) {
|
| 1119 |
+
const int k_idx = kv_lo + cl + it * FA_CL_NCL;
|
| 1120 |
+
const int valid = k_idx < kv_hi;
|
| 1121 |
+
const int k_safe = valid ? k_idx : (kv_hi - 1);
|
| 1122 |
+
|
| 1123 |
+
const global char * k_row = k_base + k_row_base + (ulong) k_safe * k_nb1;
|
| 1124 |
+
const global char * v_row = v_base + v_row_base + (ulong) k_safe * v_nb1;
|
| 1125 |
+
|
| 1126 |
+
// Float-dequant K dot over this lane's quartets of the cluster's row.
|
| 1127 |
+
ACC_TYPE4 dot4[MQ_GQA];
|
| 1128 |
+
#pragma unroll
|
| 1129 |
+
for (int h = 0; h < MQ_GQA; ++h) dot4[h] = (ACC_TYPE4)(0.0f);
|
| 1130 |
+
#pragma unroll
|
| 1131 |
+
for (int i = 0; i < FA_CL_DKQ; ++i) {
|
| 1132 |
+
const int qk = lic + FA_CL_C * i;
|
| 1133 |
+
const float4 k_v = dequant_q8_0_lane(k_row + (qk / 8) * Q8_0_BLOCK_SIZE, qk % 8);
|
| 1134 |
+
#pragma unroll
|
| 1135 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1136 |
+
dot4[h] = mad(q_shared[h * DK_VEC + qk], k_v, dot4[h]);
|
| 1137 |
+
}
|
| 1138 |
+
}
|
| 1139 |
+
|
| 1140 |
+
// Cluster-reduce (xor steps < FA_CL_C stay inside the cluster) + score.
|
| 1141 |
+
ACC_TYPE score[MQ_GQA];
|
| 1142 |
+
#pragma unroll
|
| 1143 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1144 |
+
ACC_TYPE s = dot4[h].s0 + dot4[h].s1 + dot4[h].s2 + dot4[h].s3;
|
| 1145 |
+
#pragma unroll
|
| 1146 |
+
for (int step = 1; step < FA_CL_C; step <<= 1) {
|
| 1147 |
+
s += sub_group_shuffle_xor(s, step);
|
| 1148 |
+
}
|
| 1149 |
+
s *= scale;
|
| 1150 |
+
if (mask_base[h] != NULL) {
|
| 1151 |
+
const global MASK_DATA_TYPE * mask_ptr = (const global MASK_DATA_TYPE *) mask_base[h];
|
| 1152 |
+
s += slope[h] * (ACC_TYPE) mask_ptr[k_safe];
|
| 1153 |
+
}
|
| 1154 |
+
if (logit_softcap > 0.0f) {
|
| 1155 |
+
s = logit_softcap * tanh(s / logit_softcap);
|
| 1156 |
+
}
|
| 1157 |
+
score[h] = valid ? s : FA_M_INIT;
|
| 1158 |
+
}
|
| 1159 |
+
|
| 1160 |
+
// Per-cluster online update (serial chain depth n_iter, not kv_per_sg).
|
| 1161 |
+
ACC_TYPE p_h[MQ_GQA];
|
| 1162 |
+
ACC_TYPE sp_h[MQ_GQA];
|
| 1163 |
+
#pragma unroll
|
| 1164 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1165 |
+
const ACC_TYPE m_new = max(m_i[h], score[h]);
|
| 1166 |
+
sp_h[h] = native_exp(m_i[h] - m_new);
|
| 1167 |
+
p_h[h] = native_exp(score[h] - m_new);
|
| 1168 |
+
l_i[h] = l_i[h] * sp_h[h] + p_h[h];
|
| 1169 |
+
m_i[h] = m_new;
|
| 1170 |
+
}
|
| 1171 |
+
|
| 1172 |
+
// V accumulate on this lane's quartets (p = 0 on tail -> inert).
|
| 1173 |
+
#pragma unroll
|
| 1174 |
+
for (int i = 0; i < FA_CL_DVQ; ++i) {
|
| 1175 |
+
const int dv = lic + FA_CL_C * i;
|
| 1176 |
+
const float4 v_v = dequant_q8_0_lane(v_row + (dv / 8) * Q8_0_BLOCK_SIZE, dv % 8);
|
| 1177 |
+
#pragma unroll
|
| 1178 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1179 |
+
o_acc[h][i] = mad(p_h[h], v_v, o_acc[h][i] * sp_h[h]);
|
| 1180 |
+
}
|
| 1181 |
+
}
|
| 1182 |
+
}
|
| 1183 |
+
|
| 1184 |
+
// Merge stage 1: fold cluster partials inside the subgroup via shuffles.
|
| 1185 |
+
#pragma unroll
|
| 1186 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1187 |
+
ACC_TYPE m_c = m_i[h];
|
| 1188 |
+
#pragma unroll
|
| 1189 |
+
for (int step = FA_CL_C; step < Q1_WG_SIZE; step <<= 1) {
|
| 1190 |
+
m_c = max(m_c, sub_group_shuffle_xor(m_c, step));
|
| 1191 |
+
}
|
| 1192 |
+
const ACC_TYPE alpha = native_exp(m_i[h] - m_c);
|
| 1193 |
+
ACC_TYPE l_c = l_i[h] * alpha;
|
| 1194 |
+
#pragma unroll
|
| 1195 |
+
for (int step = FA_CL_C; step < Q1_WG_SIZE; step <<= 1) {
|
| 1196 |
+
l_c += sub_group_shuffle_xor(l_c, step);
|
| 1197 |
+
}
|
| 1198 |
+
#pragma unroll
|
| 1199 |
+
for (int i = 0; i < FA_CL_DVQ; ++i) {
|
| 1200 |
+
ACC_TYPE4 o = o_acc[h][i] * alpha;
|
| 1201 |
+
#pragma unroll
|
| 1202 |
+
for (int step = FA_CL_C; step < Q1_WG_SIZE; step <<= 1) {
|
| 1203 |
+
o.s0 += sub_group_shuffle_xor(o.s0, step);
|
| 1204 |
+
o.s1 += sub_group_shuffle_xor(o.s1, step);
|
| 1205 |
+
o.s2 += sub_group_shuffle_xor(o.s2, step);
|
| 1206 |
+
o.s3 += sub_group_shuffle_xor(o.s3, step);
|
| 1207 |
+
}
|
| 1208 |
+
o_acc[h][i] = o;
|
| 1209 |
+
}
|
| 1210 |
+
m_i[h] = m_c;
|
| 1211 |
+
l_i[h] = l_c;
|
| 1212 |
+
}
|
| 1213 |
+
|
| 1214 |
+
// Merge stage 2: baseline cross-subgroup LDS merge (o published by
|
| 1215 |
+
// cluster 0's lanes; layout identical to the baseline sg_o).
|
| 1216 |
+
__local ACC_TYPE sg_m[MQ_GQA][MQ_NSG_SPLIT];
|
| 1217 |
+
__local ACC_TYPE sg_l[MQ_GQA][MQ_NSG_SPLIT];
|
| 1218 |
+
__local ACC_TYPE4 sg_o[MQ_NSG_SPLIT][DV_VEC];
|
| 1219 |
+
|
| 1220 |
+
if (tid_sg == 0) {
|
| 1221 |
+
#pragma unroll
|
| 1222 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1223 |
+
sg_m[h][sgid] = m_i[h];
|
| 1224 |
+
sg_l[h][sgid] = l_i[h];
|
| 1225 |
+
}
|
| 1226 |
+
}
|
| 1227 |
+
|
| 1228 |
+
#pragma unroll
|
| 1229 |
+
for (int h = 0; h < MQ_GQA; ++h) {
|
| 1230 |
+
if (cl == 0) {
|
| 1231 |
+
#pragma unroll
|
| 1232 |
+
for (int i = 0; i < FA_CL_DVQ; ++i) {
|
| 1233 |
+
sg_o[sgid][lic + FA_CL_C * i] = o_acc[h][i];
|
| 1234 |
+
}
|
| 1235 |
+
}
|
| 1236 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 1237 |
+
|
| 1238 |
+
if (sgid == 0) {
|
| 1239 |
+
const int head_idx = head_kv_idx * MQ_GQA + h;
|
| 1240 |
+
|
| 1241 |
+
ACC_TYPE m_c = sg_m[h][0];
|
| 1242 |
+
#pragma unroll
|
| 1243 |
+
for (int s = 1; s < MQ_NSG_SPLIT; ++s) {
|
| 1244 |
+
m_c = max(m_c, sg_m[h][s]);
|
| 1245 |
+
}
|
| 1246 |
+
ACC_TYPE l_c = 0.0f;
|
| 1247 |
+
#pragma unroll
|
| 1248 |
+
for (int s = 0; s < MQ_NSG_SPLIT; ++s) {
|
| 1249 |
+
l_c += sg_l[h][s] * native_exp(sg_m[h][s] - m_c);
|
| 1250 |
+
}
|
| 1251 |
+
|
| 1252 |
+
const ulong rec_idx = ((((ulong) batch_idx * n_head + head_idx) * n_q + q_idx)
|
| 1253 |
+
* n_splits + split_idx);
|
| 1254 |
+
global float * rec = partial_void + rec_idx * record_stride;
|
| 1255 |
+
global float4 * rec_o = (global float4 *) (rec + 2);
|
| 1256 |
+
|
| 1257 |
+
if (tid_sg == 0) {
|
| 1258 |
+
rec[0] = (float) m_c;
|
| 1259 |
+
rec[1] = (float) l_c;
|
| 1260 |
+
}
|
| 1261 |
+
for (int dv_idx = tid_sg; dv_idx < DV_VEC; dv_idx += Q1_WG_SIZE) {
|
| 1262 |
+
ACC_TYPE4 o_merged = (ACC_TYPE4)(0.0f);
|
| 1263 |
+
#pragma unroll
|
| 1264 |
+
for (int s = 0; s < MQ_NSG_SPLIT; ++s) {
|
| 1265 |
+
const ACC_TYPE alpha = native_exp(sg_m[h][s] - m_c);
|
| 1266 |
+
o_merged = mad((ACC_TYPE4)(alpha), sg_o[s][dv_idx], o_merged);
|
| 1267 |
+
}
|
| 1268 |
+
rec_o[dv_idx] = o_merged;
|
| 1269 |
+
}
|
| 1270 |
+
}
|
| 1271 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 1272 |
+
}
|
| 1273 |
+
}
|
| 1274 |
+
|
| 1275 |
+
#endif // DK_VEC/DV_VEC divisible by FA_CL_C
|
| 1276 |
+
#endif // HAS_SUBGROUP_SHUFFLE (q1_vec_mq_split_c8)
|
| 1277 |
+
|
| 1278 |
+
__kernel void flash_attn_f32_q8_0(
|
| 1279 |
+
const global void * q_void, ulong q_offset,
|
| 1280 |
+
const global void * k_void, ulong k_offset,
|
| 1281 |
+
const global void * v_void, ulong v_offset,
|
| 1282 |
+
global void * o_void, ulong o_offset,
|
| 1283 |
+
const float scale,
|
| 1284 |
+
const int n_q,
|
| 1285 |
+
const int n_kv,
|
| 1286 |
+
const int is_causal,
|
| 1287 |
+
const int n_head,
|
| 1288 |
+
const ulong q_nb1, const ulong q_nb2, const ulong q_nb3,
|
| 1289 |
+
const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
|
| 1290 |
+
const ulong v_nb1, const ulong v_nb2, const ulong v_nb3,
|
| 1291 |
+
const ulong o_nb1, const ulong o_nb2, const ulong o_nb3,
|
| 1292 |
+
const float max_bias,
|
| 1293 |
+
const float m0,
|
| 1294 |
+
const float m1,
|
| 1295 |
+
const int n_head_log2,
|
| 1296 |
+
const float logit_softcap,
|
| 1297 |
+
const int n_head_kv,
|
| 1298 |
+
const global void* mask_void,
|
| 1299 |
+
const ulong mask_offset,
|
| 1300 |
+
const ulong mask_nb1,
|
| 1301 |
+
const ulong mask_nb2,
|
| 1302 |
+
const ulong mask_nb3,
|
| 1303 |
+
const int mask_ne2,
|
| 1304 |
+
const int mask_ne3,
|
| 1305 |
+
const global void* sinks_void,
|
| 1306 |
+
const ulong sinks_offset,
|
| 1307 |
+
// blk: per-(qblock,kvblock) class from flash_attn_blk_f16
|
| 1308 |
+
// (0=masked, 1=mixed, 2=unmasked). NULL disables the prepass opt.
|
| 1309 |
+
const global void * blk_void
|
| 1310 |
+
) {
|
| 1311 |
+
const int tid = get_local_id(0);
|
| 1312 |
+
const int block_q_idx = get_group_id(0);
|
| 1313 |
+
const int head_batch_idx = get_global_id(1);
|
| 1314 |
+
|
| 1315 |
+
#if N_SPLIT > 1
|
| 1316 |
+
const int q_lane = tid / N_SPLIT;
|
| 1317 |
+
const int split_idx = tid % N_SPLIT;
|
| 1318 |
+
#else
|
| 1319 |
+
const int q_lane = tid;
|
| 1320 |
+
const int split_idx = 0;
|
| 1321 |
+
#endif
|
| 1322 |
+
const int my_query_row = block_q_idx * BLOCK_M + q_lane;
|
| 1323 |
+
const int query_valid = my_query_row < n_q;
|
| 1324 |
+
|
| 1325 |
+
const int batch_idx = head_batch_idx / n_head;
|
| 1326 |
+
const int head_idx = head_batch_idx % n_head;
|
| 1327 |
+
|
| 1328 |
+
const int gqa_ratio = n_head / n_head_kv;
|
| 1329 |
+
const int head_kv_idx = head_idx / gqa_ratio;
|
| 1330 |
+
const int mask_head_idx = mask_void != NULL ? head_idx % mask_ne2 : 0;
|
| 1331 |
+
const int mask_batch_idx = mask_void != NULL ? batch_idx % mask_ne3 : 0;
|
| 1332 |
+
|
| 1333 |
+
const global char * q_base = (const global char *) q_void + q_offset;
|
| 1334 |
+
const global char * k_base = (const global char *) k_void + k_offset;
|
| 1335 |
+
const global char * v_base = (const global char *) v_void + v_offset;
|
| 1336 |
+
global char * o_base = (global char *) o_void + o_offset;
|
| 1337 |
+
|
| 1338 |
+
const global char * mask_base = NULL;
|
| 1339 |
+
if (mask_void != NULL) {
|
| 1340 |
+
mask_base = (const global char *) mask_void + mask_offset +
|
| 1341 |
+
mask_batch_idx * mask_nb3 + mask_head_idx * mask_nb2;
|
| 1342 |
+
}
|
| 1343 |
+
|
| 1344 |
+
// BLK_PREPASS_BM may differ from this kernel's BLOCK_M; scale q-block idx.
|
| 1345 |
+
#ifndef BLK_PREPASS_BM
|
| 1346 |
+
#define BLK_PREPASS_BM BLOCK_M
|
| 1347 |
+
#endif
|
| 1348 |
+
const global char * blk_base = NULL;
|
| 1349 |
+
int n_kv_blocks = 0;
|
| 1350 |
+
if (blk_void != NULL) {
|
| 1351 |
+
n_kv_blocks = (n_kv + BLOCK_N - 1) / BLOCK_N;
|
| 1352 |
+
const int n_q_blocks_prepass = (n_q + BLK_PREPASS_BM - 1) / BLK_PREPASS_BM;
|
| 1353 |
+
const int prepass_q_block = (block_q_idx * BLOCK_M) / BLK_PREPASS_BM;
|
| 1354 |
+
blk_base = (const global char *) blk_void +
|
| 1355 |
+
(((mask_batch_idx * mask_ne2) + mask_head_idx) * n_q_blocks_prepass + prepass_q_block) * n_kv_blocks;
|
| 1356 |
+
}
|
| 1357 |
+
|
| 1358 |
+
const int dk_off_vec = split_idx * SPLIT_DK_VEC;
|
| 1359 |
+
ACC_TYPE4 q_priv[SPLIT_DK_VEC];
|
| 1360 |
+
if (query_valid) {
|
| 1361 |
+
const ulong q_row_offset = batch_idx * q_nb3 + head_idx * q_nb2 + my_query_row * q_nb1;
|
| 1362 |
+
const global float4 * q_ptr = (const global float4 *) (q_base + q_row_offset);
|
| 1363 |
+
#pragma unroll
|
| 1364 |
+
for (int i = 0; i < SPLIT_DK_VEC; ++i) {
|
| 1365 |
+
q_priv[i] = q_ptr[dk_off_vec + i];
|
| 1366 |
+
}
|
| 1367 |
+
} else {
|
| 1368 |
+
#pragma unroll
|
| 1369 |
+
for (int i = 0; i < SPLIT_DK_VEC; ++i) q_priv[i] = (ACC_TYPE4)(0.0f);
|
| 1370 |
+
}
|
| 1371 |
+
|
| 1372 |
+
#ifdef FA_HAVE_INT_DOT
|
| 1373 |
+
uint q_packed_pf[SPLIT_DK_Q8_BLOCKS * 8];
|
| 1374 |
+
float q_d_pf[SPLIT_DK_Q8_BLOCKS];
|
| 1375 |
+
#pragma unroll
|
| 1376 |
+
for (int b = 0; b < SPLIT_DK_Q8_BLOCKS; ++b) {
|
| 1377 |
+
q_d_pf[b] = quant_q_block_int8_packed(&q_priv[b * 8], &q_packed_pf[b * 8]);
|
| 1378 |
+
}
|
| 1379 |
+
#endif
|
| 1380 |
+
|
| 1381 |
+
const int dv_off_vec = split_idx * SPLIT_DV_VEC;
|
| 1382 |
+
ACC_TYPE4 o_acc[SPLIT_DV_VEC];
|
| 1383 |
+
#pragma unroll
|
| 1384 |
+
for (int i = 0; i < SPLIT_DV_VEC; ++i) o_acc[i] = (ACC_TYPE4)(0.0f);
|
| 1385 |
+
|
| 1386 |
+
ACC_TYPE m_i = FA_M_INIT;
|
| 1387 |
+
ACC_TYPE l_i = 0.0f;
|
| 1388 |
+
|
| 1389 |
+
float slope = get_alibi_slope(max_bias, head_idx, n_head_log2, m0, m1);
|
| 1390 |
+
|
| 1391 |
+
#ifdef FA_HAVE_INT_DOT
|
| 1392 |
+
__local uint l_k_packed[BLOCK_N][DK_Q8_BLOCKS_PREFILL * 8];
|
| 1393 |
+
__local float l_k_scale [BLOCK_N][DK_Q8_BLOCKS_PREFILL];
|
| 1394 |
+
#else
|
| 1395 |
+
__local half4 l_k[BLOCK_N][DK_VEC];
|
| 1396 |
+
#endif
|
| 1397 |
+
|
| 1398 |
+
#if FA_V_STRATEGY == 2
|
| 1399 |
+
__local uint l_v_packed[BLOCK_N][DV_Q8_BLOCKS_PREFILL * 8];
|
| 1400 |
+
__local float l_v_scale [BLOCK_N][DV_Q8_BLOCKS_PREFILL];
|
| 1401 |
+
#else
|
| 1402 |
+
__local half4 l_v[BLOCK_N][DV_VEC];
|
| 1403 |
+
#endif
|
| 1404 |
+
|
| 1405 |
+
for (int k_start = 0; k_start < n_kv; k_start += BLOCK_N) {
|
| 1406 |
+
// Skip fully-masked KV tiles (uniform branch across WG).
|
| 1407 |
+
char blk_cur = 1;
|
| 1408 |
+
if (blk_base != NULL) {
|
| 1409 |
+
blk_cur = blk_base[k_start / BLOCK_N];
|
| 1410 |
+
if (blk_cur == 0) continue;
|
| 1411 |
+
}
|
| 1412 |
+
|
| 1413 |
+
{
|
| 1414 |
+
#ifdef FA_HAVE_INT_DOT
|
| 1415 |
+
const int k_blocks_per_row = DK_Q8_BLOCKS_PREFILL;
|
| 1416 |
+
const int n_blocks_total = BLOCK_N * k_blocks_per_row;
|
| 1417 |
+
for (int i = tid; i < n_blocks_total; i += WG_SIZE) {
|
| 1418 |
+
const int row = i / k_blocks_per_row;
|
| 1419 |
+
const int blk = i % k_blocks_per_row;
|
| 1420 |
+
const int k_row_idx = k_start + row;
|
| 1421 |
+
if (k_row_idx < n_kv) {
|
| 1422 |
+
const ulong k_row_off = batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_row_idx * k_nb1;
|
| 1423 |
+
const global char * blk_ptr = k_base + k_row_off + blk * Q8_0_BLOCK_SIZE;
|
| 1424 |
+
const float df = (float) vload_half(0, (const global half *) blk_ptr);
|
| 1425 |
+
const global uchar * qs = (const global uchar *)(blk_ptr + 2);
|
| 1426 |
+
l_k_scale[row][blk] = df;
|
| 1427 |
+
#pragma unroll
|
| 1428 |
+
for (int j = 0; j < 8; ++j) {
|
| 1429 |
+
uint k_packed =
|
| 1430 |
+
(uint) qs[j*4 + 0] |
|
| 1431 |
+
((uint) qs[j*4 + 1]) << 8 |
|
| 1432 |
+
((uint) qs[j*4 + 2]) << 16 |
|
| 1433 |
+
((uint) qs[j*4 + 3]) << 24;
|
| 1434 |
+
l_k_packed[row][blk * 8 + j] = k_packed;
|
| 1435 |
+
}
|
| 1436 |
+
} else {
|
| 1437 |
+
l_k_scale[row][blk] = 0.0f;
|
| 1438 |
+
#pragma unroll
|
| 1439 |
+
for (int j = 0; j < 8; ++j) l_k_packed[row][blk * 8 + j] = 0u;
|
| 1440 |
+
}
|
| 1441 |
+
}
|
| 1442 |
+
#else
|
| 1443 |
+
// Fallback: dequant q8_0 -> half in local memory.
|
| 1444 |
+
const int k_blocks_per_row = DK / QK8_0;
|
| 1445 |
+
const int n_blocks_total = BLOCK_N * k_blocks_per_row;
|
| 1446 |
+
for (int i = tid; i < n_blocks_total; i += WG_SIZE) {
|
| 1447 |
+
const int row = i / k_blocks_per_row;
|
| 1448 |
+
const int blk = i % k_blocks_per_row;
|
| 1449 |
+
const int k_row_idx = k_start + row;
|
| 1450 |
+
if (k_row_idx < n_kv) {
|
| 1451 |
+
const ulong k_row_off = batch_idx * k_nb3 + head_kv_idx * k_nb2 + k_row_idx * k_nb1;
|
| 1452 |
+
const global char * blk_ptr = k_base + k_row_off + blk * Q8_0_BLOCK_SIZE;
|
| 1453 |
+
const float df = (float) vload_half(0, (const global half *) blk_ptr);
|
| 1454 |
+
const global char * qs = blk_ptr + 2;
|
| 1455 |
+
#pragma unroll
|
| 1456 |
+
for (int j = 0; j < 8; ++j) {
|
| 1457 |
+
const float4 v = df * (float4)((float) qs[j*4 + 0],
|
| 1458 |
+
(float) qs[j*4 + 1],
|
| 1459 |
+
(float) qs[j*4 + 2],
|
| 1460 |
+
(float) qs[j*4 + 3]);
|
| 1461 |
+
l_k[row][blk * 8 + j] = (half4)((half) v.s0, (half) v.s1, (half) v.s2, (half) v.s3);
|
| 1462 |
+
}
|
| 1463 |
+
} else {
|
| 1464 |
+
#pragma unroll
|
| 1465 |
+
for (int j = 0; j < 8; ++j) l_k[row][blk * 8 + j] = (half4)(0.0h);
|
| 1466 |
+
}
|
| 1467 |
+
}
|
| 1468 |
+
#endif
|
| 1469 |
+
}
|
| 1470 |
+
// V tile load — strategy-dependent.
|
| 1471 |
+
#if FA_V_STRATEGY == 2
|
| 1472 |
+
{
|
| 1473 |
+
// Int8 packed V in local memory + per-block scale. Accumulate
|
| 1474 |
+
// step unpacks inline.
|
| 1475 |
+
const int v_blocks_per_row = DV_Q8_BLOCKS_PREFILL;
|
| 1476 |
+
const int n_blocks_total = BLOCK_N * v_blocks_per_row;
|
| 1477 |
+
for (int i = tid; i < n_blocks_total; i += WG_SIZE) {
|
| 1478 |
+
const int row = i / v_blocks_per_row;
|
| 1479 |
+
const int blk = i % v_blocks_per_row;
|
| 1480 |
+
const int v_row_idx = k_start + row;
|
| 1481 |
+
if (v_row_idx < n_kv) {
|
| 1482 |
+
const ulong v_row_off = batch_idx * v_nb3 + head_kv_idx * v_nb2 + v_row_idx * v_nb1;
|
| 1483 |
+
const global char * blk_ptr = v_base + v_row_off + blk * Q8_0_BLOCK_SIZE;
|
| 1484 |
+
const float df = (float) vload_half(0, (const global half *) blk_ptr);
|
| 1485 |
+
const global uchar * qs = (const global uchar *)(blk_ptr + 2);
|
| 1486 |
+
l_v_scale[row][blk] = df;
|
| 1487 |
+
#pragma unroll
|
| 1488 |
+
for (int j = 0; j < 8; ++j) {
|
| 1489 |
+
uint v_packed =
|
| 1490 |
+
(uint) qs[j*4 + 0] |
|
| 1491 |
+
((uint) qs[j*4 + 1]) << 8 |
|
| 1492 |
+
((uint) qs[j*4 + 2]) << 16 |
|
| 1493 |
+
((uint) qs[j*4 + 3]) << 24;
|
| 1494 |
+
l_v_packed[row][blk * 8 + j] = v_packed;
|
| 1495 |
+
}
|
| 1496 |
+
} else {
|
| 1497 |
+
l_v_scale[row][blk] = 0.0f;
|
| 1498 |
+
#pragma unroll
|
| 1499 |
+
for (int j = 0; j < 8; ++j) l_v_packed[row][blk * 8 + j] = 0u;
|
| 1500 |
+
}
|
| 1501 |
+
}
|
| 1502 |
+
}
|
| 1503 |
+
#else
|
| 1504 |
+
{
|
| 1505 |
+
// Default: dequant V -> half in local memory.
|
| 1506 |
+
const int v_blocks_per_row = DV / QK8_0;
|
| 1507 |
+
const int n_blocks_total = BLOCK_N * v_blocks_per_row;
|
| 1508 |
+
for (int i = tid; i < n_blocks_total; i += WG_SIZE) {
|
| 1509 |
+
const int row = i / v_blocks_per_row;
|
| 1510 |
+
const int blk = i % v_blocks_per_row;
|
| 1511 |
+
const int v_row_idx = k_start + row;
|
| 1512 |
+
if (v_row_idx < n_kv) {
|
| 1513 |
+
const ulong v_row_off = batch_idx * v_nb3 + head_kv_idx * v_nb2 + v_row_idx * v_nb1;
|
| 1514 |
+
const global char * blk_ptr = v_base + v_row_off + blk * Q8_0_BLOCK_SIZE;
|
| 1515 |
+
const float df = (float) vload_half(0, (const global half *) blk_ptr);
|
| 1516 |
+
const global char * qs = blk_ptr + 2;
|
| 1517 |
+
#pragma unroll
|
| 1518 |
+
for (int j = 0; j < 8; ++j) {
|
| 1519 |
+
const float4 v = df * (float4)((float) qs[j*4 + 0],
|
| 1520 |
+
(float) qs[j*4 + 1],
|
| 1521 |
+
(float) qs[j*4 + 2],
|
| 1522 |
+
(float) qs[j*4 + 3]);
|
| 1523 |
+
l_v[row][blk * 8 + j] = (half4)((half) v.s0, (half) v.s1, (half) v.s2, (half) v.s3);
|
| 1524 |
+
}
|
| 1525 |
+
} else {
|
| 1526 |
+
#pragma unroll
|
| 1527 |
+
for (int j = 0; j < 8; ++j) l_v[row][blk * 8 + j] = (half4)(0.0h);
|
| 1528 |
+
}
|
| 1529 |
+
}
|
| 1530 |
+
}
|
| 1531 |
+
#endif
|
| 1532 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 1533 |
+
|
| 1534 |
+
// QK dot + online softmax. N_SPLIT>1 reduces per-thread partials via shuffle_xor.
|
| 1535 |
+
#if N_SPLIT > 1
|
| 1536 |
+
{
|
| 1537 |
+
#else
|
| 1538 |
+
if (query_valid) {
|
| 1539 |
+
#endif
|
| 1540 |
+
const int k_blk_base = split_idx * SPLIT_DK_Q8_BLOCKS;
|
| 1541 |
+
for (int j = 0; j < BLOCK_N; j += 4) {
|
| 1542 |
+
const int k_row0 = k_start + j;
|
| 1543 |
+
const int k_row1 = k_start + j + 1;
|
| 1544 |
+
const int k_row2 = k_start + j + 2;
|
| 1545 |
+
const int k_row3 = k_start + j + 3;
|
| 1546 |
+
|
| 1547 |
+
ACC_TYPE s0, s1, s2, s3;
|
| 1548 |
+
#ifdef FA_HAVE_INT_DOT
|
| 1549 |
+
// dp4a-accelerated QK dot over owned blocks.
|
| 1550 |
+
s0 = 0.0f; s1 = 0.0f; s2 = 0.0f; s3 = 0.0f;
|
| 1551 |
+
#pragma unroll
|
| 1552 |
+
for (int b_local = 0; b_local < SPLIT_DK_Q8_BLOCKS; ++b_local) {
|
| 1553 |
+
const int b = k_blk_base + b_local;
|
| 1554 |
+
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;
|
| 1555 |
+
#pragma unroll
|
| 1556 |
+
for (int g = 0; g < 8; ++g) {
|
| 1557 |
+
const uint qp = q_packed_pf[b_local * 8 + g];
|
| 1558 |
+
sum0 = dot_acc_sat_4x8packed_ss_int(qp, l_k_packed[j ][b * 8 + g], sum0);
|
| 1559 |
+
sum1 = dot_acc_sat_4x8packed_ss_int(qp, l_k_packed[j+1][b * 8 + g], sum1);
|
| 1560 |
+
sum2 = dot_acc_sat_4x8packed_ss_int(qp, l_k_packed[j+2][b * 8 + g], sum2);
|
| 1561 |
+
sum3 = dot_acc_sat_4x8packed_ss_int(qp, l_k_packed[j+3][b * 8 + g], sum3);
|
| 1562 |
+
}
|
| 1563 |
+
const float qd = q_d_pf[b_local];
|
| 1564 |
+
s0 += (float)sum0 * qd * l_k_scale[j ][b];
|
| 1565 |
+
s1 += (float)sum1 * qd * l_k_scale[j+1][b];
|
| 1566 |
+
s2 += (float)sum2 * qd * l_k_scale[j+2][b];
|
| 1567 |
+
s3 += (float)sum3 * qd * l_k_scale[j+3][b];
|
| 1568 |
+
}
|
| 1569 |
+
#else
|
| 1570 |
+
ACC_TYPE4 dot_acc0 = (ACC_TYPE4)(0.0f);
|
| 1571 |
+
ACC_TYPE4 dot_acc1 = (ACC_TYPE4)(0.0f);
|
| 1572 |
+
ACC_TYPE4 dot_acc2 = (ACC_TYPE4)(0.0f);
|
| 1573 |
+
ACC_TYPE4 dot_acc3 = (ACC_TYPE4)(0.0f);
|
| 1574 |
+
#pragma unroll
|
| 1575 |
+
for (int k = 0; k < SPLIT_DK_VEC; ++k) {
|
| 1576 |
+
const ACC_TYPE4 qk = q_priv[k];
|
| 1577 |
+
const int k_abs = dk_off_vec + k;
|
| 1578 |
+
dot_acc0 = mad(qk, CONVERT_KV_ACC4(l_k[j ][k_abs]), dot_acc0);
|
| 1579 |
+
dot_acc1 = mad(qk, CONVERT_KV_ACC4(l_k[j+1][k_abs]), dot_acc1);
|
| 1580 |
+
dot_acc2 = mad(qk, CONVERT_KV_ACC4(l_k[j+2][k_abs]), dot_acc2);
|
| 1581 |
+
dot_acc3 = mad(qk, CONVERT_KV_ACC4(l_k[j+3][k_abs]), dot_acc3);
|
| 1582 |
+
}
|
| 1583 |
+
s0 = dot_acc0.s0 + dot_acc0.s1 + dot_acc0.s2 + dot_acc0.s3;
|
| 1584 |
+
s1 = dot_acc1.s0 + dot_acc1.s1 + dot_acc1.s2 + dot_acc1.s3;
|
| 1585 |
+
s2 = dot_acc2.s0 + dot_acc2.s1 + dot_acc2.s2 + dot_acc2.s3;
|
| 1586 |
+
s3 = dot_acc3.s0 + dot_acc3.s1 + dot_acc3.s2 + dot_acc3.s3;
|
| 1587 |
+
#endif
|
| 1588 |
+
|
| 1589 |
+
#if N_SPLIT > 1
|
| 1590 |
+
// Power-of-2 N_SPLIT: shuffle_xor butterfly. N_SPLIT=3 (DK=96): 3-way shuffle.
|
| 1591 |
+
#if (N_SPLIT & (N_SPLIT - 1)) == 0
|
| 1592 |
+
#pragma unroll
|
| 1593 |
+
for (int step = 1; step < N_SPLIT; step <<= 1) {
|
| 1594 |
+
s0 += sub_group_shuffle_xor(s0, step);
|
| 1595 |
+
s1 += sub_group_shuffle_xor(s1, step);
|
| 1596 |
+
s2 += sub_group_shuffle_xor(s2, step);
|
| 1597 |
+
s3 += sub_group_shuffle_xor(s3, step);
|
| 1598 |
+
}
|
| 1599 |
+
#else
|
| 1600 |
+
const uint tri_base = (get_sub_group_local_id() / N_SPLIT) * N_SPLIT;
|
| 1601 |
+
s0 = sub_group_shuffle(s0, tri_base + 0) + sub_group_shuffle(s0, tri_base + 1) + sub_group_shuffle(s0, tri_base + 2);
|
| 1602 |
+
s1 = sub_group_shuffle(s1, tri_base + 0) + sub_group_shuffle(s1, tri_base + 1) + sub_group_shuffle(s1, tri_base + 2);
|
| 1603 |
+
s2 = sub_group_shuffle(s2, tri_base + 0) + sub_group_shuffle(s2, tri_base + 1) + sub_group_shuffle(s2, tri_base + 2);
|
| 1604 |
+
s3 = sub_group_shuffle(s3, tri_base + 0) + sub_group_shuffle(s3, tri_base + 1) + sub_group_shuffle(s3, tri_base + 2);
|
| 1605 |
+
#endif
|
| 1606 |
+
if (!query_valid) { s0 = FA_M_INIT; s1 = FA_M_INIT; s2 = FA_M_INIT; s3 = FA_M_INIT; }
|
| 1607 |
+
#endif
|
| 1608 |
+
s0 *= scale; s1 *= scale; s2 *= scale; s3 *= scale;
|
| 1609 |
+
|
| 1610 |
+
if (is_causal) {
|
| 1611 |
+
const int causal_limit = n_kv - n_q + my_query_row;
|
| 1612 |
+
if (k_row0 > causal_limit) s0 = FA_M_INIT;
|
| 1613 |
+
if (k_row1 > causal_limit) s1 = FA_M_INIT;
|
| 1614 |
+
if (k_row2 > causal_limit) s2 = FA_M_INIT;
|
| 1615 |
+
if (k_row3 > causal_limit) s3 = FA_M_INIT;
|
| 1616 |
+
}
|
| 1617 |
+
if (k_row0 >= n_kv) s0 = FA_M_INIT;
|
| 1618 |
+
if (k_row1 >= n_kv) s1 = FA_M_INIT;
|
| 1619 |
+
if (k_row2 >= n_kv) s2 = FA_M_INIT;
|
| 1620 |
+
if (k_row3 >= n_kv) s3 = FA_M_INIT;
|
| 1621 |
+
|
| 1622 |
+
if (query_valid && mask_base != NULL && blk_cur != 2) {
|
| 1623 |
+
const global MASK_DATA_TYPE * mask_ptr =
|
| 1624 |
+
(const global MASK_DATA_TYPE *) (mask_base + my_query_row * mask_nb1);
|
| 1625 |
+
if (k_row0 < n_kv) s0 += slope * (ACC_TYPE) mask_ptr[k_row0];
|
| 1626 |
+
if (k_row1 < n_kv) s1 += slope * (ACC_TYPE) mask_ptr[k_row1];
|
| 1627 |
+
if (k_row2 < n_kv) s2 += slope * (ACC_TYPE) mask_ptr[k_row2];
|
| 1628 |
+
if (k_row3 < n_kv) s3 += slope * (ACC_TYPE) mask_ptr[k_row3];
|
| 1629 |
+
}
|
| 1630 |
+
if (logit_softcap > 0.0f) {
|
| 1631 |
+
s0 = logit_softcap * tanh(s0 / logit_softcap);
|
| 1632 |
+
s1 = logit_softcap * tanh(s1 / logit_softcap);
|
| 1633 |
+
s2 = logit_softcap * tanh(s2 / logit_softcap);
|
| 1634 |
+
s3 = logit_softcap * tanh(s3 / logit_softcap);
|
| 1635 |
+
}
|
| 1636 |
+
|
| 1637 |
+
const ACC_TYPE m_new = max(m_i, max(max(s0, s1), max(s2, s3)));
|
| 1638 |
+
// Whole tile masked (m_new == FA_M_INIT): force the exp() args
|
| 1639 |
+
// far negative so the tile contributes 0, not exp(0)=1.
|
| 1640 |
+
const ACC_TYPE m_exp = (m_new == FA_M_INIT) ? 0.0f : m_new;
|
| 1641 |
+
const ACC_TYPE scale_prev = native_exp(m_i - m_exp);
|
| 1642 |
+
const ACC_TYPE p0 = native_exp(s0 - m_exp);
|
| 1643 |
+
const ACC_TYPE p1 = native_exp(s1 - m_exp);
|
| 1644 |
+
const ACC_TYPE p2 = native_exp(s2 - m_exp);
|
| 1645 |
+
const ACC_TYPE p3 = native_exp(s3 - m_exp);
|
| 1646 |
+
|
| 1647 |
+
#if FA_V_STRATEGY == 2
|
| 1648 |
+
#pragma unroll
|
| 1649 |
+
for (int b_local = 0; b_local < DV_Q8_BLOCKS_PREFILL / N_SPLIT; ++b_local) {
|
| 1650 |
+
const int b_abs = split_idx * (DV_Q8_BLOCKS_PREFILL / N_SPLIT) + b_local;
|
| 1651 |
+
const float d0 = l_v_scale[j ][b_abs];
|
| 1652 |
+
const float d1 = l_v_scale[j+1][b_abs];
|
| 1653 |
+
const float d2 = l_v_scale[j+2][b_abs];
|
| 1654 |
+
const float d3 = l_v_scale[j+3][b_abs];
|
| 1655 |
+
#pragma unroll
|
| 1656 |
+
for (int g = 0; g < 8; ++g) {
|
| 1657 |
+
const int lane_abs = b_abs * 8 + g;
|
| 1658 |
+
const int lane_local = b_local * 8 + g;
|
| 1659 |
+
uint pk0 = l_v_packed[j ][lane_abs];
|
| 1660 |
+
uint pk1 = l_v_packed[j+1][lane_abs];
|
| 1661 |
+
uint pk2 = l_v_packed[j+2][lane_abs];
|
| 1662 |
+
uint pk3 = l_v_packed[j+3][lane_abs];
|
| 1663 |
+
float4 v0 = d0 * (float4)((float)(char)(pk0 & 0xff), (float)(char)((pk0>>8)&0xff), (float)(char)((pk0>>16)&0xff), (float)(char)((pk0>>24)&0xff));
|
| 1664 |
+
float4 v1 = d1 * (float4)((float)(char)(pk1 & 0xff), (float)(char)((pk1>>8)&0xff), (float)(char)((pk1>>16)&0xff), (float)(char)((pk1>>24)&0xff));
|
| 1665 |
+
float4 v2 = d2 * (float4)((float)(char)(pk2 & 0xff), (float)(char)((pk2>>8)&0xff), (float)(char)((pk2>>16)&0xff), (float)(char)((pk2>>24)&0xff));
|
| 1666 |
+
float4 v3 = d3 * (float4)((float)(char)(pk3 & 0xff), (float)(char)((pk3>>8)&0xff), (float)(char)((pk3>>16)&0xff), (float)(char)((pk3>>24)&0xff));
|
| 1667 |
+
o_acc[lane_local] = mad(p3, v3,
|
| 1668 |
+
mad(p2, v2,
|
| 1669 |
+
mad(p1, v1,
|
| 1670 |
+
mad(p0, v0,
|
| 1671 |
+
o_acc[lane_local] * scale_prev))));
|
| 1672 |
+
}
|
| 1673 |
+
}
|
| 1674 |
+
#else // FA_V_STRATEGY == 0
|
| 1675 |
+
#pragma unroll
|
| 1676 |
+
for (int i = 0; i < SPLIT_DV_VEC; ++i) {
|
| 1677 |
+
const int i_abs = dv_off_vec + i;
|
| 1678 |
+
o_acc[i] = mad(p3, CONVERT_KV_ACC4(l_v[j+3][i_abs]),
|
| 1679 |
+
mad(p2, CONVERT_KV_ACC4(l_v[j+2][i_abs]),
|
| 1680 |
+
mad(p1, CONVERT_KV_ACC4(l_v[j+1][i_abs]),
|
| 1681 |
+
mad(p0, CONVERT_KV_ACC4(l_v[j ][i_abs]),
|
| 1682 |
+
o_acc[i] * scale_prev))));
|
| 1683 |
+
}
|
| 1684 |
+
#endif
|
| 1685 |
+
l_i = l_i * scale_prev + p0 + p1 + p2 + p3;
|
| 1686 |
+
m_i = m_new;
|
| 1687 |
+
}
|
| 1688 |
+
}
|
| 1689 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 1690 |
+
}
|
| 1691 |
+
|
| 1692 |
+
// Write output. With N_SPLIT>1 each thread writes its SPLIT_DV_VEC slice.
|
| 1693 |
+
if (query_valid) {
|
| 1694 |
+
if (sinks_void != NULL) {
|
| 1695 |
+
const global ACC_TYPE * sinks_ptr =
|
| 1696 |
+
(const global ACC_TYPE *) ((const global char *) sinks_void + sinks_offset);
|
| 1697 |
+
const ACC_TYPE m_sink = sinks_ptr[head_idx];
|
| 1698 |
+
const ACC_TYPE m_final = max(m_i, m_sink);
|
| 1699 |
+
const ACC_TYPE scale_o = exp(m_i - m_final);
|
| 1700 |
+
#pragma unroll
|
| 1701 |
+
for (int i = 0; i < SPLIT_DV_VEC; ++i) o_acc[i] *= scale_o;
|
| 1702 |
+
l_i = l_i * scale_o + exp(m_sink - m_final);
|
| 1703 |
+
m_i = m_final;
|
| 1704 |
+
}
|
| 1705 |
+
const ACC_TYPE l_inv = (l_i > 0.0f) ? (1.0f / l_i) : 0.0f;
|
| 1706 |
+
const ulong o_row_offset = batch_idx * o_nb3 + my_query_row * o_nb2 + head_idx * o_nb1;
|
| 1707 |
+
global float4 * o_row = (global float4 *) (o_base + o_row_offset);
|
| 1708 |
+
if (l_inv > 0.0f) {
|
| 1709 |
+
#pragma unroll
|
| 1710 |
+
for (int i = 0; i < SPLIT_DV_VEC; ++i) o_row[dv_off_vec + i] = o_acc[i] * l_inv;
|
| 1711 |
+
} else {
|
| 1712 |
+
#pragma unroll
|
| 1713 |
+
for (int i = 0; i < SPLIT_DV_VEC; ++i) o_row[dv_off_vec + i] = (float4)(0.0f);
|
| 1714 |
+
}
|
| 1715 |
+
}
|
| 1716 |
+
}
|
| 1717 |
+
|
| 1718 |
+
// FD Pass 2: merge split partials. Identical across q4_0/q8_0/f16; each FA
|
| 1719 |
+
// source owns a copy since kernels compile per-source-program.
|
| 1720 |
+
__kernel void flash_attn_f32_merge(
|
| 1721 |
+
const global float * partial_void,
|
| 1722 |
+
global void * o_void,
|
| 1723 |
+
const ulong o_offset,
|
| 1724 |
+
const int n_head,
|
| 1725 |
+
const int n_splits,
|
| 1726 |
+
const ulong o_nb1, const ulong o_nb2, const ulong o_nb3,
|
| 1727 |
+
const global void * sinks_void,
|
| 1728 |
+
const ulong sinks_offset,
|
| 1729 |
+
const int n_q
|
| 1730 |
+
) {
|
| 1731 |
+
const int lane = get_local_id(0);
|
| 1732 |
+
const int head_batch_idx = get_global_id(1);
|
| 1733 |
+
const int q_idx = get_global_id(2);
|
| 1734 |
+
const int batch_idx = head_batch_idx / n_head;
|
| 1735 |
+
const int head_idx = head_batch_idx % n_head;
|
| 1736 |
+
|
| 1737 |
+
const ulong record_stride = (ulong) FA_PARTIAL_FLOATS;
|
| 1738 |
+
const ulong record_idx_0 = (((ulong) batch_idx * n_head + head_idx) * n_q + q_idx) * n_splits;
|
| 1739 |
+
const global float * rec0 = partial_void + record_idx_0 * record_stride;
|
| 1740 |
+
|
| 1741 |
+
__local ACC_TYPE m_final_shared;
|
| 1742 |
+
__local ACC_TYPE l_final_shared;
|
| 1743 |
+
if (lane == 0) {
|
| 1744 |
+
ACC_TYPE m = FA_M_INIT;
|
| 1745 |
+
for (int c = 0; c < n_splits; ++c) {
|
| 1746 |
+
const ACC_TYPE m_c = rec0[c * record_stride + 0];
|
| 1747 |
+
m = max(m, m_c);
|
| 1748 |
+
}
|
| 1749 |
+
ACC_TYPE m_sink = 0.0f;
|
| 1750 |
+
bool has_sink = false;
|
| 1751 |
+
if (sinks_void != NULL) {
|
| 1752 |
+
const global ACC_TYPE * sinks_ptr =
|
| 1753 |
+
(const global ACC_TYPE *) ((const global char *) sinks_void + sinks_offset);
|
| 1754 |
+
m_sink = sinks_ptr[head_idx];
|
| 1755 |
+
has_sink = true;
|
| 1756 |
+
m = max(m, m_sink);
|
| 1757 |
+
}
|
| 1758 |
+
ACC_TYPE l = 0.0f;
|
| 1759 |
+
for (int c = 0; c < n_splits; ++c) {
|
| 1760 |
+
const ACC_TYPE m_c = rec0[c * record_stride + 0];
|
| 1761 |
+
const ACC_TYPE l_c = rec0[c * record_stride + 1];
|
| 1762 |
+
if (m_c > FA_M_INIT) {
|
| 1763 |
+
l += l_c * exp(m_c - m);
|
| 1764 |
+
}
|
| 1765 |
+
}
|
| 1766 |
+
if (has_sink) {
|
| 1767 |
+
l += exp(m_sink - m);
|
| 1768 |
+
}
|
| 1769 |
+
m_final_shared = m;
|
| 1770 |
+
l_final_shared = l;
|
| 1771 |
+
}
|
| 1772 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 1773 |
+
const ACC_TYPE m_final = m_final_shared;
|
| 1774 |
+
const ACC_TYPE l_final = l_final_shared;
|
| 1775 |
+
const ACC_TYPE l_inv = (l_final > 0.0f) ? (1.0f / l_final) : 0.0f;
|
| 1776 |
+
|
| 1777 |
+
ACC_TYPE4 o = (ACC_TYPE4)(0.0f);
|
| 1778 |
+
for (int c = 0; c < n_splits; ++c) {
|
| 1779 |
+
const global float * rec_c = rec0 + c * record_stride;
|
| 1780 |
+
const ACC_TYPE m_c = rec_c[0];
|
| 1781 |
+
if (m_c <= FA_M_INIT) continue;
|
| 1782 |
+
const global float4 * rec_oc = (const global float4 *) (rec_c + 2);
|
| 1783 |
+
const ACC_TYPE scale_c = exp(m_c - m_final);
|
| 1784 |
+
o = mad((ACC_TYPE4)(scale_c), rec_oc[lane], o);
|
| 1785 |
+
}
|
| 1786 |
+
o = o * l_inv;
|
| 1787 |
+
|
| 1788 |
+
const ulong o_row_offset = (ulong) batch_idx * o_nb3 + (ulong) q_idx * o_nb2 + (ulong) head_idx * o_nb1;
|
| 1789 |
+
global O_DATA_TYPE4 * o_row = (global O_DATA_TYPE4 *) ((global char *) o_void + o_offset + o_row_offset);
|
| 1790 |
+
o_row[lane] = CONVERT_O_DATA4(o);
|
| 1791 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/flash_attn_pre_f16.cl
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
|
| 3 |
+
__kernel void flash_attn_kv_pad_f16(
|
| 4 |
+
const global void * k_void, ulong k_offset,
|
| 5 |
+
const global void * v_void, ulong v_offset,
|
| 6 |
+
global void * k_pad_void,
|
| 7 |
+
global void * v_pad_void,
|
| 8 |
+
const int n_kv,
|
| 9 |
+
const int n_head_kv,
|
| 10 |
+
const int n_batch,
|
| 11 |
+
const ulong k_nb1, const ulong k_nb2, const ulong k_nb3,
|
| 12 |
+
const ulong v_nb1, const ulong v_nb2, const ulong v_nb3
|
| 13 |
+
) {
|
| 14 |
+
const int row_idx = get_global_id(0);
|
| 15 |
+
const int head_kv_idx = get_global_id(1);
|
| 16 |
+
const int batch_idx = get_global_id(2);
|
| 17 |
+
|
| 18 |
+
if (row_idx >= BLOCK_N || head_kv_idx >= n_head_kv || batch_idx >= n_batch) {
|
| 19 |
+
return;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
const int tail_start = n_kv - (n_kv % BLOCK_N);
|
| 23 |
+
const int src_row_idx = tail_start + row_idx;
|
| 24 |
+
|
| 25 |
+
const global char * k_src = (const global char *) k_void + k_offset;
|
| 26 |
+
const global char * v_src = (const global char *) v_void + v_offset;
|
| 27 |
+
global char * k_pad = (global char *) k_pad_void;
|
| 28 |
+
global char * v_pad = (global char *) v_pad_void;
|
| 29 |
+
|
| 30 |
+
const ulong k_dst_offset = ((ulong) batch_idx * (ulong) n_head_kv + (ulong) head_kv_idx) * ((ulong) BLOCK_N * k_nb1) + (ulong) row_idx * k_nb1;
|
| 31 |
+
const ulong v_dst_offset = ((ulong) batch_idx * (ulong) n_head_kv + (ulong) head_kv_idx) * ((ulong) BLOCK_N * v_nb1) + (ulong) row_idx * v_nb1;
|
| 32 |
+
|
| 33 |
+
if (src_row_idx < n_kv) {
|
| 34 |
+
const ulong k_src_offset = (ulong) batch_idx * k_nb3 + (ulong) head_kv_idx * k_nb2 + (ulong) src_row_idx * k_nb1;
|
| 35 |
+
const ulong v_src_offset = (ulong) batch_idx * v_nb3 + (ulong) head_kv_idx * v_nb2 + (ulong) src_row_idx * v_nb1;
|
| 36 |
+
|
| 37 |
+
for (ulong i = 0; i < k_nb1; ++i) {
|
| 38 |
+
k_pad[k_dst_offset + i] = k_src[k_src_offset + i];
|
| 39 |
+
}
|
| 40 |
+
for (ulong i = 0; i < v_nb1; ++i) {
|
| 41 |
+
v_pad[v_dst_offset + i] = v_src[v_src_offset + i];
|
| 42 |
+
}
|
| 43 |
+
} else {
|
| 44 |
+
for (ulong i = 0; i < k_nb1; ++i) {
|
| 45 |
+
k_pad[k_dst_offset + i] = 0;
|
| 46 |
+
}
|
| 47 |
+
for (ulong i = 0; i < v_nb1; ++i) {
|
| 48 |
+
v_pad[v_dst_offset + i] = 0;
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
__kernel void flash_attn_mask_pad_f16(
|
| 54 |
+
const global void * mask_void, ulong mask_offset,
|
| 55 |
+
global void * mask_pad_void,
|
| 56 |
+
const int n_q,
|
| 57 |
+
const int n_kv,
|
| 58 |
+
const ulong mask_nb1,
|
| 59 |
+
const ulong mask_nb2,
|
| 60 |
+
const ulong mask_nb3,
|
| 61 |
+
const int mask_ne2,
|
| 62 |
+
const int mask_ne3
|
| 63 |
+
) {
|
| 64 |
+
const int col_idx = get_global_id(0);
|
| 65 |
+
const int q_row = get_global_id(1);
|
| 66 |
+
const int mask_slice = get_global_id(2);
|
| 67 |
+
|
| 68 |
+
if (col_idx >= BLOCK_N || q_row >= n_q || mask_slice >= mask_ne2 * mask_ne3) {
|
| 69 |
+
return;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
const int tail_start = n_kv - (n_kv % BLOCK_N);
|
| 73 |
+
const int src_col_idx = tail_start + col_idx;
|
| 74 |
+
const int mask_head_idx = mask_slice % mask_ne2;
|
| 75 |
+
const int mask_batch_idx = mask_slice / mask_ne2;
|
| 76 |
+
|
| 77 |
+
const global char * mask_src_base = (const global char *) mask_void + mask_offset +
|
| 78 |
+
(ulong) mask_batch_idx * mask_nb3 +
|
| 79 |
+
(ulong) mask_head_idx * mask_nb2 +
|
| 80 |
+
(ulong) q_row * mask_nb1;
|
| 81 |
+
const global half * mask_src = (const global half *) mask_src_base;
|
| 82 |
+
|
| 83 |
+
global half * mask_pad = (global half *) mask_pad_void;
|
| 84 |
+
const ulong dst_idx =
|
| 85 |
+
(((ulong) mask_batch_idx * (ulong) mask_ne2 + (ulong) mask_head_idx) * (ulong) n_q + (ulong) q_row) * (ulong) BLOCK_N +
|
| 86 |
+
(ulong) col_idx;
|
| 87 |
+
|
| 88 |
+
mask_pad[dst_idx] = src_col_idx < n_kv ? mask_src[src_col_idx] : (half) (-INFINITY);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
// Per-KV-tile mask class. 0=all -inf (skip tile), 1=mixed (apply mask),
|
| 92 |
+
// 2=all zero, no -inf (skip mask lookup). Causal diagonal tiles are class 1.
|
| 93 |
+
__kernel void flash_attn_blk_f16(
|
| 94 |
+
const global void * mask_void, ulong mask_offset,
|
| 95 |
+
global char * blk,
|
| 96 |
+
const int n_q,
|
| 97 |
+
const int n_kv,
|
| 98 |
+
const ulong mask_nb1,
|
| 99 |
+
const ulong mask_nb2,
|
| 100 |
+
const ulong mask_nb3,
|
| 101 |
+
const int mask_ne2,
|
| 102 |
+
const int mask_ne3
|
| 103 |
+
) {
|
| 104 |
+
const int kv_block_idx = get_global_id(0);
|
| 105 |
+
const int q_block_idx = get_global_id(1);
|
| 106 |
+
const int mask_slice = get_global_id(2);
|
| 107 |
+
|
| 108 |
+
const int n_q_blocks = (n_q + BLOCK_M - 1) / BLOCK_M;
|
| 109 |
+
const int n_kv_blocks = (n_kv + BLOCK_N - 1) / BLOCK_N;
|
| 110 |
+
if (kv_block_idx >= n_kv_blocks || q_block_idx >= n_q_blocks || mask_slice >= mask_ne2 * mask_ne3) {
|
| 111 |
+
return;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
const int mask_head_idx = mask_slice % mask_ne2;
|
| 115 |
+
const int mask_batch_idx = mask_slice / mask_ne2;
|
| 116 |
+
const int q_start = q_block_idx * BLOCK_M;
|
| 117 |
+
const int k_start = kv_block_idx * BLOCK_N;
|
| 118 |
+
const int q_count = min(BLOCK_M, n_q - q_start);
|
| 119 |
+
const int k_count = min(BLOCK_N, n_kv - k_start);
|
| 120 |
+
|
| 121 |
+
const half neg_max_half = (half) (-65504.0f);
|
| 122 |
+
char has_unmasked = 0;
|
| 123 |
+
char has_masked = 0;
|
| 124 |
+
char has_nonzero = 0;
|
| 125 |
+
|
| 126 |
+
const global char * mask_base = (const global char *) mask_void + mask_offset +
|
| 127 |
+
(ulong) mask_batch_idx * mask_nb3 +
|
| 128 |
+
(ulong) mask_head_idx * mask_nb2;
|
| 129 |
+
|
| 130 |
+
for (int qi = 0; qi < q_count; ++qi) {
|
| 131 |
+
const global half * mask_row = (const global half *) (mask_base + (ulong) (q_start + qi) * mask_nb1) + k_start;
|
| 132 |
+
for (int ki = 0; ki < k_count; ++ki) {
|
| 133 |
+
const half v = mask_row[ki];
|
| 134 |
+
if (v <= neg_max_half) {
|
| 135 |
+
has_masked = 1;
|
| 136 |
+
} else {
|
| 137 |
+
has_unmasked = 1;
|
| 138 |
+
if (v != (half) 0.0f) {
|
| 139 |
+
has_nonzero = 1;
|
| 140 |
+
}
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
if (has_masked && has_unmasked) break; // mixed tile — short-circuit.
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
char res;
|
| 147 |
+
if (has_unmasked == 0) {
|
| 148 |
+
res = 0;
|
| 149 |
+
} else if (has_masked || has_nonzero) {
|
| 150 |
+
res = 1;
|
| 151 |
+
} else {
|
| 152 |
+
res = 2;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
blk[((ulong) mask_slice * (ulong) n_q_blocks + (ulong) q_block_idx) * (ulong) n_kv_blocks + (ulong) kv_block_idx] = res;
|
| 156 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gated_delta_net.cl
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 2 |
+
|
| 3 |
+
#ifdef cl_intel_required_subgroup_size
|
| 4 |
+
#pragma OPENCL EXTENSION cl_intel_required_subgroup_size : enable
|
| 5 |
+
#define INTEL_GPU 1
|
| 6 |
+
#define REQD_SUBGROUP_SIZE_16 __attribute__((intel_reqd_sub_group_size(16)))
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_32 __attribute__((intel_reqd_sub_group_size(32)))
|
| 8 |
+
#elif defined(cl_qcom_reqd_sub_group_size)
|
| 9 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 10 |
+
#define ADRENO_GPU 1
|
| 11 |
+
#define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
|
| 12 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 13 |
+
#endif
|
| 14 |
+
|
| 15 |
+
#ifndef S_V
|
| 16 |
+
#define S_V 128
|
| 17 |
+
#endif
|
| 18 |
+
#ifndef KDA
|
| 19 |
+
#define KDA 0
|
| 20 |
+
#endif
|
| 21 |
+
#ifndef SUBGROUP_SIZE
|
| 22 |
+
#define SUBGROUP_SIZE 64
|
| 23 |
+
#endif
|
| 24 |
+
#ifndef LANES_PER_COLUMN
|
| 25 |
+
#define LANES_PER_COLUMN 8
|
| 26 |
+
#endif
|
| 27 |
+
#ifndef COLS_PER_LANE_GROUP
|
| 28 |
+
#define COLS_PER_LANE_GROUP 1
|
| 29 |
+
#endif
|
| 30 |
+
#ifndef SUBGROUPS_PER_WG
|
| 31 |
+
#define SUBGROUPS_PER_WG 1
|
| 32 |
+
#endif
|
| 33 |
+
#ifndef USE_QCOM_SUBGROUP_SHUFFLE
|
| 34 |
+
#define USE_QCOM_SUBGROUP_SHUFFLE 0
|
| 35 |
+
#endif
|
| 36 |
+
|
| 37 |
+
#define WG_SIZE (SUBGROUP_SIZE * SUBGROUPS_PER_WG)
|
| 38 |
+
#define LANE_GROUPS_PER_SG (SUBGROUP_SIZE / LANES_PER_COLUMN)
|
| 39 |
+
#define COLS_PER_SG (LANE_GROUPS_PER_SG * COLS_PER_LANE_GROUP)
|
| 40 |
+
#define COLS_PER_WG (SUBGROUPS_PER_WG * COLS_PER_SG)
|
| 41 |
+
#define ROWS_PER_LANE (S_V / LANES_PER_COLUMN)
|
| 42 |
+
|
| 43 |
+
#if USE_QCOM_SUBGROUP_SHUFFLE
|
| 44 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_shuffle : enable
|
| 45 |
+
#endif
|
| 46 |
+
|
| 47 |
+
// XOR-based parallel sum
|
| 48 |
+
// This does a reduction across groups of LANES_PER_COLUMN
|
| 49 |
+
static inline float reduce_add_shmem(float partial, __local float * temp, uint lane) {
|
| 50 |
+
#if USE_QCOM_SUBGROUP_SHUFFLE
|
| 51 |
+
#pragma unroll
|
| 52 |
+
for (uint s = LANES_PER_COLUMN / 2u; s > 0u; s >>= 1u) {
|
| 53 |
+
partial += qcom_sub_group_shuffle_xor(partial, s, CLK_SUB_GROUP_SHUFFLE_WIDTH_WAVE_SIZE_QCOM, partial);
|
| 54 |
+
}
|
| 55 |
+
return partial;
|
| 56 |
+
#else
|
| 57 |
+
temp[lane] = partial;
|
| 58 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 59 |
+
#pragma unroll
|
| 60 |
+
for (uint s = LANES_PER_COLUMN / 2u; s > 0u; s >>= 1u) {
|
| 61 |
+
float other = temp[lane ^ s];
|
| 62 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 63 |
+
temp[lane] += other;
|
| 64 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 65 |
+
}
|
| 66 |
+
const float result = temp[lane];
|
| 67 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 68 |
+
return result;
|
| 69 |
+
#endif
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
#define REDUCE_PARTIAL(partial, temp_ptr, lid) \
|
| 73 |
+
((LANES_PER_COLUMN == 1u) ? (partial) : reduce_add_shmem((partial), (temp_ptr), (lid)))
|
| 74 |
+
|
| 75 |
+
// force compiler to optimize kernel for a specific fixed work-group size
|
| 76 |
+
__attribute__((reqd_work_group_size(WG_SIZE, 1, 1)))
|
| 77 |
+
#ifdef INTEL_GPU
|
| 78 |
+
REQD_SUBGROUP_SIZE_32
|
| 79 |
+
#elif defined (ADRENO_GPU)
|
| 80 |
+
REQD_SUBGROUP_SIZE_64
|
| 81 |
+
#endif
|
| 82 |
+
kernel void kernel_gated_delta_net(
|
| 83 |
+
global const char * q_buf, ulong off_q,
|
| 84 |
+
global const char * k_buf, ulong off_k,
|
| 85 |
+
global const char * v_buf, ulong off_v,
|
| 86 |
+
global const char * g_buf, ulong off_g,
|
| 87 |
+
global const char * beta_buf, ulong off_beta,
|
| 88 |
+
global const char * state_buf, ulong off_state,
|
| 89 |
+
global char * dst_buf, ulong off_dst,
|
| 90 |
+
uint H_v,
|
| 91 |
+
uint n_tokens,
|
| 92 |
+
uint n_seqs,
|
| 93 |
+
uint s_off,
|
| 94 |
+
uint sq1, uint sq2, uint sq3,
|
| 95 |
+
uint sv1, uint sv2, uint sv3,
|
| 96 |
+
uint sb1, uint sb2, uint sb3,
|
| 97 |
+
uint H_k,
|
| 98 |
+
uint rq3,
|
| 99 |
+
float scale,
|
| 100 |
+
uint K) {
|
| 101 |
+
|
| 102 |
+
global const float * data_q = (global const float *)(q_buf + off_q);
|
| 103 |
+
global const float * data_k = (global const float *)(k_buf + off_k);
|
| 104 |
+
global const float * data_v = (global const float *)(v_buf + off_v);
|
| 105 |
+
global const float * data_g = (global const float *)(g_buf + off_g);
|
| 106 |
+
global const float * data_beta = (global const float *)(beta_buf + off_beta);
|
| 107 |
+
global const float * data_state = (global const float *)(state_buf + off_state);
|
| 108 |
+
global float * data_dst = (global float *)(dst_buf + off_dst);
|
| 109 |
+
|
| 110 |
+
const uint head_id = get_group_id(0);
|
| 111 |
+
const uint seq_id = get_group_id(1);
|
| 112 |
+
const uint tid = (uint)get_local_id(0);
|
| 113 |
+
|
| 114 |
+
const uint sg_id = get_sub_group_id(); // subgroup id
|
| 115 |
+
const uint sg_lid = get_sub_group_local_id(); // subgroup lane id
|
| 116 |
+
|
| 117 |
+
const uint lane = sg_lid % LANES_PER_COLUMN;
|
| 118 |
+
const uint lane_group = sg_lid / LANES_PER_COLUMN;
|
| 119 |
+
const uint wg_col_base = get_group_id(2) * COLS_PER_WG;
|
| 120 |
+
const uint sg_col_base = wg_col_base + sg_id * COLS_PER_SG;
|
| 121 |
+
|
| 122 |
+
const uint iq1 = head_id % H_k; // head index for Q and K
|
| 123 |
+
const uint iq3 = seq_id / rq3; // seq index for Q and K
|
| 124 |
+
|
| 125 |
+
const uint state_size = S_V * S_V;
|
| 126 |
+
// input state holds s0 only [S_v, S_v, H, n_seqs]: per-seq stride is H*D.
|
| 127 |
+
const uint state_base = (seq_id * H_v + head_id) * state_size;
|
| 128 |
+
const uint q_off_base = iq3 * sq3 + iq1 * sq1;
|
| 129 |
+
const uint v_off_base = seq_id * sv3 + head_id * sv1;
|
| 130 |
+
const uint gb_off_base = seq_id * sb3 + head_id * sb1;
|
| 131 |
+
const uint state_out_base = (seq_id * H_v + head_id) * state_size;
|
| 132 |
+
const uint state_size_per_snap = state_size * H_v * n_seqs;
|
| 133 |
+
|
| 134 |
+
__local float reduce_temp[WG_SIZE];
|
| 135 |
+
__local float * temp_ptr = reduce_temp + sg_id * SUBGROUP_SIZE;
|
| 136 |
+
|
| 137 |
+
float s_shard[COLS_PER_LANE_GROUP][ROWS_PER_LANE];
|
| 138 |
+
#pragma unroll
|
| 139 |
+
for (uint cg = 0; cg < COLS_PER_LANE_GROUP; cg++) {
|
| 140 |
+
const uint col = sg_col_base + cg * LANE_GROUPS_PER_SG + lane_group;
|
| 141 |
+
#pragma unroll
|
| 142 |
+
for (uint r = 0; r < ROWS_PER_LANE; r++) {
|
| 143 |
+
s_shard[cg][r] = data_state[state_base + col * S_V + r * LANES_PER_COLUMN + lane];
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
// snapshot slot mapping: slot 0 = most recent state, slot s = s tokens back.
|
| 148 |
+
// When n_tokens < K only slots 0..n_tokens-1 are written; older slots are caller-owned.
|
| 149 |
+
uint attn_off = (seq_id * n_tokens * H_v + head_id) * S_V;
|
| 150 |
+
|
| 151 |
+
for (uint t = 0; t < n_tokens; t++) {
|
| 152 |
+
const uint q_off = q_off_base + t * sq2;
|
| 153 |
+
const uint k_off = q_off;
|
| 154 |
+
const uint v_off = v_off_base + t * sv2;
|
| 155 |
+
const uint gb_off = gb_off_base + t * sb2;
|
| 156 |
+
const float beta_val = data_beta[gb_off];
|
| 157 |
+
|
| 158 |
+
float k_reg[ROWS_PER_LANE];
|
| 159 |
+
float q_reg[ROWS_PER_LANE];
|
| 160 |
+
#if KDA
|
| 161 |
+
float g_exp[ROWS_PER_LANE];
|
| 162 |
+
#pragma unroll
|
| 163 |
+
for (uint r = 0; r < ROWS_PER_LANE; r++) {
|
| 164 |
+
const uint i = r * LANES_PER_COLUMN + lane;
|
| 165 |
+
k_reg[r] = data_k[k_off + i];
|
| 166 |
+
q_reg[r] = data_q[q_off + i];
|
| 167 |
+
g_exp[r] = exp(data_g[gb_off * S_V + i]);
|
| 168 |
+
}
|
| 169 |
+
#else
|
| 170 |
+
const float g_val = exp(data_g[gb_off]);
|
| 171 |
+
|
| 172 |
+
#pragma unroll
|
| 173 |
+
for (uint r = 0; r < ROWS_PER_LANE; r++) {
|
| 174 |
+
const uint i = r * LANES_PER_COLUMN + lane;
|
| 175 |
+
k_reg[r] = data_k[k_off + i];
|
| 176 |
+
q_reg[r] = data_q[q_off + i];
|
| 177 |
+
}
|
| 178 |
+
#endif
|
| 179 |
+
|
| 180 |
+
#pragma unroll
|
| 181 |
+
for (uint cg = 0; cg < COLS_PER_LANE_GROUP; cg++) {
|
| 182 |
+
const uint col = sg_col_base + cg * LANE_GROUPS_PER_SG + lane_group;
|
| 183 |
+
float v_val = data_v[v_off + col];
|
| 184 |
+
|
| 185 |
+
float kv_shard = 0.0f;
|
| 186 |
+
#pragma unroll
|
| 187 |
+
for (uint r = 0; r < ROWS_PER_LANE; r++) {
|
| 188 |
+
#if KDA
|
| 189 |
+
float gs = g_exp[r] * s_shard[cg][r];
|
| 190 |
+
kv_shard += gs * k_reg[r];
|
| 191 |
+
#else
|
| 192 |
+
kv_shard += s_shard[cg][r] * k_reg[r];
|
| 193 |
+
#endif
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
#if !KDA
|
| 197 |
+
kv_shard *= g_val; // Applied once instead of ROWS_PER_LANE times
|
| 198 |
+
#endif
|
| 199 |
+
|
| 200 |
+
const float kv_col = REDUCE_PARTIAL(kv_shard, temp_ptr, sg_lid);
|
| 201 |
+
|
| 202 |
+
const float delta_col = (v_val - kv_col) * beta_val;
|
| 203 |
+
|
| 204 |
+
float attn_partial = 0.0f;
|
| 205 |
+
#pragma unroll
|
| 206 |
+
for (uint r = 0; r < ROWS_PER_LANE; r++) {
|
| 207 |
+
#if KDA
|
| 208 |
+
float gs = g_exp[r] * s_shard[cg][r];
|
| 209 |
+
#else
|
| 210 |
+
float gs = g_val * s_shard[cg][r];
|
| 211 |
+
#endif
|
| 212 |
+
s_shard[cg][r] = gs + k_reg[r] * delta_col;
|
| 213 |
+
attn_partial += s_shard[cg][r] * q_reg[r];
|
| 214 |
+
}
|
| 215 |
+
const float attn_col = REDUCE_PARTIAL(attn_partial, temp_ptr, sg_lid);
|
| 216 |
+
|
| 217 |
+
if (lane == 0) {
|
| 218 |
+
data_dst[attn_off + col] = attn_col * scale;
|
| 219 |
+
}
|
| 220 |
+
}
|
| 221 |
+
attn_off += S_V * H_v;
|
| 222 |
+
|
| 223 |
+
if (K > 1u) {
|
| 224 |
+
const int target_slot = (int)n_tokens - 1 - (int)t;
|
| 225 |
+
if (target_slot >= 0 && target_slot < (int)K) {
|
| 226 |
+
#pragma unroll
|
| 227 |
+
for (uint cg = 0; cg < COLS_PER_LANE_GROUP; cg++) {
|
| 228 |
+
const uint col = sg_col_base + cg * LANE_GROUPS_PER_SG + lane_group;
|
| 229 |
+
const uint slot_base = s_off + (uint)target_slot * state_size_per_snap + state_out_base;
|
| 230 |
+
#pragma unroll
|
| 231 |
+
for (uint r = 0; r < ROWS_PER_LANE; r++) {
|
| 232 |
+
data_dst[slot_base + col * S_V + r * LANES_PER_COLUMN + lane] = s_shard[cg][r];
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
}
|
| 236 |
+
}
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
if (K == 1u) {
|
| 240 |
+
#pragma unroll
|
| 241 |
+
for (uint cg = 0; cg < COLS_PER_LANE_GROUP; cg++) {
|
| 242 |
+
const uint col = sg_col_base + cg * LANE_GROUPS_PER_SG + lane_group;
|
| 243 |
+
#pragma unroll
|
| 244 |
+
for (uint r = 0; r < ROWS_PER_LANE; r++) {
|
| 245 |
+
data_dst[s_off + state_base + col * S_V + r * LANES_PER_COLUMN + lane] = s_shard[cg][r];
|
| 246 |
+
}
|
| 247 |
+
}
|
| 248 |
+
}
|
| 249 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gelu.cl
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
|
| 3 |
+
//------------------------------------------------------------------------------
|
| 4 |
+
// gelu
|
| 5 |
+
//------------------------------------------------------------------------------
|
| 6 |
+
#define GELU_COEF_A 0.044715f
|
| 7 |
+
#define GELU_QUICK_COEF -1.702f
|
| 8 |
+
#define SQRT_2_OVER_PI 0.79788456080286535587989211986876f
|
| 9 |
+
#define SQRT_2_INV 0.70710678118654752440084436210484f
|
| 10 |
+
|
| 11 |
+
kernel void kernel_gelu(
|
| 12 |
+
global float * src0,
|
| 13 |
+
ulong offset0,
|
| 14 |
+
global float * dst,
|
| 15 |
+
ulong offsetd
|
| 16 |
+
) {
|
| 17 |
+
src0 = (global float*)((global char*)src0 + offset0);
|
| 18 |
+
dst = (global float*)((global char*)dst + offsetd);
|
| 19 |
+
|
| 20 |
+
float x = src0[get_global_id(0)];
|
| 21 |
+
|
| 22 |
+
dst[get_global_id(0)] = 0.5f*x*(1.0f + tanh(SQRT_2_OVER_PI*x*(1.0f + GELU_COEF_A*x*x)));
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
kernel void kernel_gelu_4(
|
| 26 |
+
global float4 * src0,
|
| 27 |
+
ulong offset0,
|
| 28 |
+
global float4 * dst,
|
| 29 |
+
ulong offsetd
|
| 30 |
+
) {
|
| 31 |
+
src0 = (global float4*)((global char*)src0 + offset0);
|
| 32 |
+
dst = (global float4*)((global char*)dst + offsetd);
|
| 33 |
+
|
| 34 |
+
float4 x = src0[get_global_id(0)];
|
| 35 |
+
|
| 36 |
+
dst[get_global_id(0)] = 0.5f*x*(1.0f + tanh(SQRT_2_OVER_PI*x*(1.0f + GELU_COEF_A*x*x)));
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
kernel void kernel_gelu_erf(
|
| 40 |
+
global float * src0,
|
| 41 |
+
ulong offset0,
|
| 42 |
+
global float * dst,
|
| 43 |
+
ulong offsetd
|
| 44 |
+
) {
|
| 45 |
+
src0 = (global float*)((global char*)src0 + offset0);
|
| 46 |
+
dst = (global float*)((global char*)dst + offsetd);
|
| 47 |
+
|
| 48 |
+
float x = src0[get_global_id(0)];
|
| 49 |
+
dst[get_global_id(0)] = 0.5f*x*(1.0f + erf(x*SQRT_2_INV));
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
kernel void kernel_gelu_erf_4(
|
| 53 |
+
global float4 * src0,
|
| 54 |
+
ulong offset0,
|
| 55 |
+
global float4 * dst,
|
| 56 |
+
ulong offsetd
|
| 57 |
+
) {
|
| 58 |
+
src0 = (global float4*)((global char*)src0 + offset0);
|
| 59 |
+
dst = (global float4*)((global char*)dst + offsetd);
|
| 60 |
+
|
| 61 |
+
float4 x = src0[get_global_id(0)];
|
| 62 |
+
dst[get_global_id(0)] = 0.5f*x*(1.0f + erf(x*SQRT_2_INV));
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
kernel void kernel_gelu_quick(
|
| 66 |
+
global float * src0,
|
| 67 |
+
ulong offset0,
|
| 68 |
+
global float * dst,
|
| 69 |
+
ulong offsetd
|
| 70 |
+
) {
|
| 71 |
+
src0 = (global float*)((global char*)src0 + offset0);
|
| 72 |
+
dst = (global float*)((global char*)dst + offsetd);
|
| 73 |
+
|
| 74 |
+
float x = src0[get_global_id(0)];
|
| 75 |
+
dst[get_global_id(0)] = x*(1.0f/(1.0f+exp(GELU_QUICK_COEF*x)));
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
kernel void kernel_gelu_quick_4(
|
| 79 |
+
global float4 * src0,
|
| 80 |
+
ulong offset0,
|
| 81 |
+
global float4 * dst,
|
| 82 |
+
ulong offsetd
|
| 83 |
+
) {
|
| 84 |
+
src0 = (global float4*)((global char*)src0 + offset0);
|
| 85 |
+
dst = (global float4*)((global char*)dst + offsetd);
|
| 86 |
+
|
| 87 |
+
float4 x = src0[get_global_id(0)];
|
| 88 |
+
dst[get_global_id(0)] = x*(1.0f/(1.0f+exp(GELU_QUICK_COEF*x)));
|
| 89 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32.cl
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_MXFP4 32
|
| 6 |
+
#define N_SIMDGROUP 2
|
| 7 |
+
#define SIMDGROUP_WIDTH 64
|
| 8 |
+
|
| 9 |
+
static inline half8 mxfp4_to_fp16_packed8(ushort2 fp4x8) { //, ushort 0x0E00, ushort 0x8000) {
|
| 10 |
+
ushort2 fp16_packed_a_0, fp16_packed_b_0, bias_a, bias_b, sign_a, sign_b;
|
| 11 |
+
fp16_packed_a_0.lo = (fp4x8.s0 << 9) & 0x0E00;
|
| 12 |
+
fp16_packed_a_0.hi = (fp4x8.s0 << 5) & 0x0E00;
|
| 13 |
+
fp16_packed_b_0.lo = (fp4x8.s0 << 1) & 0x0E00;
|
| 14 |
+
fp16_packed_b_0.hi = (fp4x8.s0 >> 3) & 0x0E00;
|
| 15 |
+
|
| 16 |
+
bias_a.lo = (fp16_packed_a_0.lo != 0) ? 0x3800 : 0x0;
|
| 17 |
+
bias_a.hi = (fp16_packed_a_0.hi != 0) ? 0x3800 : 0x0;
|
| 18 |
+
bias_b.lo = (fp16_packed_b_0.lo != 0) ? 0x3800 : 0x0;
|
| 19 |
+
bias_b.hi = (fp16_packed_b_0.hi != 0) ? 0x3800 : 0x0;
|
| 20 |
+
|
| 21 |
+
fp16_packed_a_0.lo = (fp16_packed_a_0.lo != 0x0200) ? fp16_packed_a_0.lo : 0x0;
|
| 22 |
+
fp16_packed_a_0.hi = (fp16_packed_a_0.hi != 0x0200) ? fp16_packed_a_0.hi : 0x0;
|
| 23 |
+
fp16_packed_b_0.lo = (fp16_packed_b_0.lo != 0x0200) ? fp16_packed_b_0.lo : 0x0;
|
| 24 |
+
fp16_packed_b_0.hi = (fp16_packed_b_0.hi != 0x0200) ? fp16_packed_b_0.hi : 0x0;
|
| 25 |
+
|
| 26 |
+
sign_a.lo = (fp4x8.s0 << 12) & 0x8000;
|
| 27 |
+
sign_a.hi = (fp4x8.s0 << 8) & 0x8000;
|
| 28 |
+
sign_b.lo = (fp4x8.s0 << 4) & 0x8000;
|
| 29 |
+
sign_b.hi = fp4x8.s0 & 0x8000;
|
| 30 |
+
|
| 31 |
+
fp16_packed_a_0 = sign_a + bias_a + fp16_packed_a_0;
|
| 32 |
+
fp16_packed_b_0 = sign_b + bias_b + fp16_packed_b_0;
|
| 33 |
+
|
| 34 |
+
ushort2 fp16_packed_a_1, fp16_packed_b_1;
|
| 35 |
+
fp16_packed_a_1.lo = (fp4x8.s1 << 9) & 0x0E00;
|
| 36 |
+
fp16_packed_a_1.hi = (fp4x8.s1 << 5) & 0x0E00;
|
| 37 |
+
fp16_packed_b_1.lo = (fp4x8.s1 << 1) & 0x0E00;
|
| 38 |
+
fp16_packed_b_1.hi = (fp4x8.s1 >> 3) & 0x0E00;
|
| 39 |
+
|
| 40 |
+
bias_a.lo = (fp16_packed_a_1.lo != 0) ? 0x3800 : 0x0;
|
| 41 |
+
bias_a.hi = (fp16_packed_a_1.hi != 0) ? 0x3800 : 0x0;
|
| 42 |
+
bias_b.lo = (fp16_packed_b_1.lo != 0) ? 0x3800 : 0x0;
|
| 43 |
+
bias_b.hi = (fp16_packed_b_1.hi != 0) ? 0x3800 : 0x0;
|
| 44 |
+
|
| 45 |
+
fp16_packed_a_1.lo = (fp16_packed_a_1.lo != 0x0200) ? fp16_packed_a_1.lo : 0x0;
|
| 46 |
+
fp16_packed_a_1.hi = (fp16_packed_a_1.hi != 0x0200) ? fp16_packed_a_1.hi : 0x0;
|
| 47 |
+
fp16_packed_b_1.lo = (fp16_packed_b_1.lo != 0x0200) ? fp16_packed_b_1.lo : 0x0;
|
| 48 |
+
fp16_packed_b_1.hi = (fp16_packed_b_1.hi != 0x0200) ? fp16_packed_b_1.hi : 0x0;
|
| 49 |
+
|
| 50 |
+
sign_a.lo = (fp4x8.s1 << 12) & 0x8000;
|
| 51 |
+
sign_a.hi = (fp4x8.s1 << 8) & 0x8000;
|
| 52 |
+
sign_b.lo = (fp4x8.s1 << 4) & 0x8000;
|
| 53 |
+
sign_b.hi = fp4x8.s1 & 0x8000;
|
| 54 |
+
|
| 55 |
+
fp16_packed_a_1 = sign_a + bias_a + fp16_packed_a_1;
|
| 56 |
+
fp16_packed_b_1 = sign_b + bias_b + fp16_packed_b_1;
|
| 57 |
+
|
| 58 |
+
return as_half8((ushort8)(fp16_packed_a_0, fp16_packed_b_0, fp16_packed_a_1, fp16_packed_b_1));
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
static inline float e8m0_to_fp32(uchar x) {
|
| 62 |
+
int bits;
|
| 63 |
+
bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
|
| 64 |
+
return as_float(bits);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 69 |
+
__kernel void kernel_gemm_moe_mxfp4_f32(
|
| 70 |
+
__global uint4 * src0_q,
|
| 71 |
+
__global uchar * src0_e,
|
| 72 |
+
__read_only image1d_buffer_t src1,
|
| 73 |
+
__global ushort4 * src2,
|
| 74 |
+
__global float * dst,
|
| 75 |
+
ulong offsetd,
|
| 76 |
+
int ne00,
|
| 77 |
+
int ne01,
|
| 78 |
+
int tile_size
|
| 79 |
+
) {
|
| 80 |
+
uint i01 = get_global_id(0);
|
| 81 |
+
uint i20 = get_global_id(2);
|
| 82 |
+
uint sgid = get_local_id(1);
|
| 83 |
+
uint slid = get_sub_group_local_id();
|
| 84 |
+
|
| 85 |
+
ushort4 router = src2[i20];
|
| 86 |
+
ushort expert_id = router.x;
|
| 87 |
+
ushort i11 = router.y;
|
| 88 |
+
ushort i1 = router.z;
|
| 89 |
+
ushort tile_id = router.w;
|
| 90 |
+
|
| 91 |
+
if (tile_id * tile_size + i01 >= ne01) { // handle edge case when ne01 is not multiple of tile_size
|
| 92 |
+
return;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
uint expert_offset = expert_id * ne00 * ne01 / 32;
|
| 96 |
+
uint tile_offset = expert_offset + tile_id * tile_size + i01;
|
| 97 |
+
|
| 98 |
+
__private float sum = 0.0f; // each thread calculate partial sum of one output
|
| 99 |
+
|
| 100 |
+
// loop along ne00 in block granularity, skip 4 blocks every iter
|
| 101 |
+
for (uint ib00 = sgid; ib00 < (ne00 / QK_MXFP4); ib00 += N_SIMDGROUP) {
|
| 102 |
+
// load one block of q
|
| 103 |
+
uint4 regQ = src0_q[tile_offset + ib00 * ne01];
|
| 104 |
+
// convert 8 fp4 to fp16
|
| 105 |
+
half8 fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s0));
|
| 106 |
+
|
| 107 |
+
uint offset = i11 * ne00 / 4 + ib00 * 8;
|
| 108 |
+
float4 shared_y4;
|
| 109 |
+
shared_y4 = read_imagef(src1, (offset + 0));
|
| 110 |
+
float4 acc = shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
|
| 111 |
+
|
| 112 |
+
shared_y4 = read_imagef(src1, (offset + 4));
|
| 113 |
+
acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s1));
|
| 117 |
+
|
| 118 |
+
shared_y4 = read_imagef(src1, (offset + 1));
|
| 119 |
+
acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
|
| 120 |
+
|
| 121 |
+
shared_y4 = read_imagef(src1, (offset + 5));
|
| 122 |
+
acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s2));
|
| 126 |
+
|
| 127 |
+
shared_y4 = read_imagef(src1, (offset + 2));
|
| 128 |
+
acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
|
| 129 |
+
|
| 130 |
+
shared_y4 = read_imagef(src1, (offset + 6));
|
| 131 |
+
acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s3));
|
| 135 |
+
|
| 136 |
+
shared_y4 = read_imagef(src1, (offset + 3));
|
| 137 |
+
acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
|
| 138 |
+
|
| 139 |
+
shared_y4 = read_imagef(src1, (offset + 7));
|
| 140 |
+
acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
|
| 141 |
+
|
| 142 |
+
uchar regE = src0_e[tile_offset + ib00 * ne01];
|
| 143 |
+
sum += e8m0_to_fp32(regE) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
// reduction in local memory, assumes #subgroups=4
|
| 147 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 148 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 149 |
+
// if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 150 |
+
// if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 151 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 152 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 153 |
+
// if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 154 |
+
// if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 155 |
+
|
| 156 |
+
// 1 outputs per thread in subgroup 0
|
| 157 |
+
if (sgid == 0) {
|
| 158 |
+
dst = dst + (offsetd >> 2);
|
| 159 |
+
dst[i01 + tile_id * tile_size + i1 * ne01] = sum;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_f32_ns.cl
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_K 16
|
| 8 |
+
#define TILESIZE_M 64
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
static inline half8 mxfp4_to_fp16_packed8(ushort2 fp4x8) {
|
| 13 |
+
ushort2 fp16_packed_a_0, fp16_packed_b_0, bias_a, bias_b, sign_a, sign_b;
|
| 14 |
+
fp16_packed_a_0.lo = (fp4x8.s0 << 9) & 0x0E00;
|
| 15 |
+
fp16_packed_a_0.hi = (fp4x8.s0 << 5) & 0x0E00;
|
| 16 |
+
fp16_packed_b_0.lo = (fp4x8.s0 << 1) & 0x0E00;
|
| 17 |
+
fp16_packed_b_0.hi = (fp4x8.s0 >> 3) & 0x0E00;
|
| 18 |
+
|
| 19 |
+
bias_a.lo = (fp16_packed_a_0.lo != 0) ? 0x3800 : 0x0;
|
| 20 |
+
bias_a.hi = (fp16_packed_a_0.hi != 0) ? 0x3800 : 0x0;
|
| 21 |
+
bias_b.lo = (fp16_packed_b_0.lo != 0) ? 0x3800 : 0x0;
|
| 22 |
+
bias_b.hi = (fp16_packed_b_0.hi != 0) ? 0x3800 : 0x0;
|
| 23 |
+
|
| 24 |
+
fp16_packed_a_0.lo = (fp16_packed_a_0.lo != 0x0200) ? fp16_packed_a_0.lo : 0x0;
|
| 25 |
+
fp16_packed_a_0.hi = (fp16_packed_a_0.hi != 0x0200) ? fp16_packed_a_0.hi : 0x0;
|
| 26 |
+
fp16_packed_b_0.lo = (fp16_packed_b_0.lo != 0x0200) ? fp16_packed_b_0.lo : 0x0;
|
| 27 |
+
fp16_packed_b_0.hi = (fp16_packed_b_0.hi != 0x0200) ? fp16_packed_b_0.hi : 0x0;
|
| 28 |
+
|
| 29 |
+
sign_a.lo = (fp4x8.s0 << 12) & 0x8000;
|
| 30 |
+
sign_a.hi = (fp4x8.s0 << 8) & 0x8000;
|
| 31 |
+
sign_b.lo = (fp4x8.s0 << 4) & 0x8000;
|
| 32 |
+
sign_b.hi = fp4x8.s0 & 0x8000;
|
| 33 |
+
|
| 34 |
+
fp16_packed_a_0 = sign_a + bias_a + fp16_packed_a_0;
|
| 35 |
+
fp16_packed_b_0 = sign_b + bias_b + fp16_packed_b_0;
|
| 36 |
+
|
| 37 |
+
ushort2 fp16_packed_a_1, fp16_packed_b_1;
|
| 38 |
+
fp16_packed_a_1.lo = (fp4x8.s1 << 9) & 0x0E00;
|
| 39 |
+
fp16_packed_a_1.hi = (fp4x8.s1 << 5) & 0x0E00;
|
| 40 |
+
fp16_packed_b_1.lo = (fp4x8.s1 << 1) & 0x0E00;
|
| 41 |
+
fp16_packed_b_1.hi = (fp4x8.s1 >> 3) & 0x0E00;
|
| 42 |
+
|
| 43 |
+
bias_a.lo = (fp16_packed_a_1.lo != 0) ? 0x3800 : 0x0;
|
| 44 |
+
bias_a.hi = (fp16_packed_a_1.hi != 0) ? 0x3800 : 0x0;
|
| 45 |
+
bias_b.lo = (fp16_packed_b_1.lo != 0) ? 0x3800 : 0x0;
|
| 46 |
+
bias_b.hi = (fp16_packed_b_1.hi != 0) ? 0x3800 : 0x0;
|
| 47 |
+
|
| 48 |
+
fp16_packed_a_1.lo = (fp16_packed_a_1.lo != 0x0200) ? fp16_packed_a_1.lo : 0x0;
|
| 49 |
+
fp16_packed_a_1.hi = (fp16_packed_a_1.hi != 0x0200) ? fp16_packed_a_1.hi : 0x0;
|
| 50 |
+
fp16_packed_b_1.lo = (fp16_packed_b_1.lo != 0x0200) ? fp16_packed_b_1.lo : 0x0;
|
| 51 |
+
fp16_packed_b_1.hi = (fp16_packed_b_1.hi != 0x0200) ? fp16_packed_b_1.hi : 0x0;
|
| 52 |
+
|
| 53 |
+
sign_a.lo = (fp4x8.s1 << 12) & 0x8000;
|
| 54 |
+
sign_a.hi = (fp4x8.s1 << 8) & 0x8000;
|
| 55 |
+
sign_b.lo = (fp4x8.s1 << 4) & 0x8000;
|
| 56 |
+
sign_b.hi = fp4x8.s1 & 0x8000;
|
| 57 |
+
|
| 58 |
+
fp16_packed_a_1 = sign_a + bias_a + fp16_packed_a_1;
|
| 59 |
+
fp16_packed_b_1 = sign_b + bias_b + fp16_packed_b_1;
|
| 60 |
+
|
| 61 |
+
return as_half8((ushort8)(fp16_packed_a_0, fp16_packed_b_0, fp16_packed_a_1, fp16_packed_b_1));
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
#define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
|
| 66 |
+
acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 67 |
+
acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 68 |
+
acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 69 |
+
acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 70 |
+
acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 71 |
+
acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 72 |
+
acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 73 |
+
acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 74 |
+
acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
|
| 75 |
+
acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
|
| 76 |
+
acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
|
| 77 |
+
acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
|
| 78 |
+
acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
|
| 79 |
+
acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
|
| 80 |
+
acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
|
| 81 |
+
acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
|
| 82 |
+
acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 83 |
+
acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 84 |
+
acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 85 |
+
acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 86 |
+
acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 87 |
+
acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 88 |
+
acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 89 |
+
acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 90 |
+
acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
|
| 91 |
+
acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
|
| 92 |
+
acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
|
| 93 |
+
acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
|
| 94 |
+
acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
|
| 95 |
+
acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
|
| 96 |
+
acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
|
| 97 |
+
acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
|
| 98 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 99 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 100 |
+
acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 101 |
+
acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 102 |
+
acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 103 |
+
acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 104 |
+
acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 105 |
+
acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 106 |
+
acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 107 |
+
acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 108 |
+
acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
|
| 109 |
+
acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
|
| 110 |
+
acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
|
| 111 |
+
acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
|
| 112 |
+
acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
|
| 113 |
+
acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
|
| 114 |
+
acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
|
| 115 |
+
acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
|
| 116 |
+
acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 117 |
+
acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 118 |
+
acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 119 |
+
acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 120 |
+
acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 121 |
+
acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 122 |
+
acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 123 |
+
acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 124 |
+
acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
|
| 125 |
+
acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
|
| 126 |
+
acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
|
| 127 |
+
acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
|
| 128 |
+
acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
|
| 129 |
+
acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
|
| 130 |
+
acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
|
| 131 |
+
acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
|
| 132 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 133 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 134 |
+
|
| 135 |
+
// Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
|
| 136 |
+
// accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
|
| 137 |
+
// non-skipped path is byte-identical; it just lets the caller skip empty
|
| 138 |
+
// 8-column groups at finer granularity. Uses a private half8 `acc8`.
|
| 139 |
+
#define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
|
| 140 |
+
acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 141 |
+
acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 142 |
+
acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 143 |
+
acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 144 |
+
acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 145 |
+
acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 146 |
+
acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 147 |
+
acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 148 |
+
acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 149 |
+
acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 150 |
+
acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 151 |
+
acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 152 |
+
acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 153 |
+
acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 154 |
+
acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 155 |
+
acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 156 |
+
c_reg += convert_float8(acc8); \
|
| 157 |
+
acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 158 |
+
acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 159 |
+
acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 160 |
+
acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 161 |
+
acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 162 |
+
acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 163 |
+
acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 164 |
+
acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 165 |
+
acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 166 |
+
acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 167 |
+
acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 168 |
+
acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 169 |
+
acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 170 |
+
acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 171 |
+
acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 172 |
+
acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 173 |
+
c_reg += convert_float8(acc8); \
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
static inline half e8m0_to_fp16(uchar x) {
|
| 177 |
+
ushort bits;
|
| 178 |
+
bits = (ushort)(x) - (ushort)(112);
|
| 179 |
+
bits = ((bits & 0x00E0) != 0) ? 0x7C00 : (bits << 10);
|
| 180 |
+
return as_half(bits);
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
static inline float e8m0_to_fp32(uchar x) {
|
| 184 |
+
int bits;
|
| 185 |
+
bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
|
| 186 |
+
return as_float(bits);
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
__attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
|
| 191 |
+
kernel void kernel_gemm_moe_mxfp4_f32_ns(
|
| 192 |
+
__read_only image1d_buffer_t src0_q,
|
| 193 |
+
__global uchar * src0_d,
|
| 194 |
+
__read_only image1d_buffer_t src1,
|
| 195 |
+
__global uint * src2,
|
| 196 |
+
__global ushort * src2_emap,
|
| 197 |
+
__write_only image1d_buffer_t dst,
|
| 198 |
+
__global int * total_tiles,
|
| 199 |
+
uint ne00,
|
| 200 |
+
uint ne01,
|
| 201 |
+
uint is_ragged,
|
| 202 |
+
uint skip_gran
|
| 203 |
+
) {
|
| 204 |
+
uint block_id_m = get_global_id(1); // m_tile
|
| 205 |
+
uint block_id_n = get_global_id(2); // n_tile
|
| 206 |
+
|
| 207 |
+
// Boundary check
|
| 208 |
+
if (block_id_n >= total_tiles[0]) {
|
| 209 |
+
return;
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
// Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
|
| 213 |
+
// padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
|
| 214 |
+
// the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
|
| 215 |
+
// Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
|
| 216 |
+
// lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
|
| 217 |
+
// trailing. Find the valid-token count V and round it UP to the skip granularity
|
| 218 |
+
// skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
|
| 219 |
+
// A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
|
| 220 |
+
// dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
|
| 221 |
+
uint n_active = TILESIZE_N;
|
| 222 |
+
if (is_ragged && skip_gran < TILESIZE_N) {
|
| 223 |
+
uint n_valid = TILESIZE_N;
|
| 224 |
+
for (uint _t = 0; _t < TILESIZE_N; ++_t) {
|
| 225 |
+
if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
|
| 226 |
+
}
|
| 227 |
+
n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
|
| 228 |
+
}
|
| 229 |
+
// Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
|
| 230 |
+
bool skip_g1 = (8u >= n_active);
|
| 231 |
+
bool skip_g2 = (16u >= n_active);
|
| 232 |
+
bool skip_g3 = (24u >= n_active);
|
| 233 |
+
|
| 234 |
+
__private half16 reg_a;
|
| 235 |
+
__private float32 reg_c = (float32)(0);
|
| 236 |
+
__local half4 shared_b[128];
|
| 237 |
+
|
| 238 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 239 |
+
|
| 240 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 241 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 242 |
+
|
| 243 |
+
uint sub_block_id_m = get_local_id(0);
|
| 244 |
+
uint2 b_global_offset;
|
| 245 |
+
b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
|
| 246 |
+
b_global_offset.y = b_global_offset.x + (16 * ne00);
|
| 247 |
+
uint2 b_local_offset;
|
| 248 |
+
b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
|
| 249 |
+
b_local_offset.y = b_local_offset.x + 16;
|
| 250 |
+
|
| 251 |
+
// Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
|
| 252 |
+
for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
|
| 253 |
+
// First sub-block
|
| 254 |
+
uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 255 |
+
uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
|
| 256 |
+
uint b_sub_offset = col * ne00 + step;
|
| 257 |
+
|
| 258 |
+
// Load scale for current mxfp4 block
|
| 259 |
+
uint s_offset = s_sub_offset + get_global_id(0);
|
| 260 |
+
float s = e8m0_to_fp32(src0_d[s_offset]);
|
| 261 |
+
|
| 262 |
+
// Load 16 fp4 (64-bits) in transposed layout
|
| 263 |
+
uint2 mxfp4x16;
|
| 264 |
+
mxfp4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 265 |
+
mxfp4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 266 |
+
|
| 267 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 268 |
+
float8 bx8_f32;
|
| 269 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 270 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 271 |
+
// Convert to half and store to LM to share within the subgroup
|
| 272 |
+
half8 bx8_f16 = convert_half8(bx8_f32);
|
| 273 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 274 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 275 |
+
|
| 276 |
+
// Dequantization
|
| 277 |
+
reg_a.lo = mxfp4_to_fp16_packed8(as_ushort2(mxfp4x16.lo)) * s;
|
| 278 |
+
reg_a.hi = mxfp4_to_fp16_packed8(as_ushort2(mxfp4x16.hi)) * s;
|
| 279 |
+
|
| 280 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 281 |
+
|
| 282 |
+
// 32 16x16 fp16 dot product with 8 elements reduction for better precision
|
| 283 |
+
half8 acc8;
|
| 284 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 285 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 286 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 287 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 288 |
+
|
| 289 |
+
// Repeat for second sub-block
|
| 290 |
+
uint half_step = step + TILESIZE_K;
|
| 291 |
+
q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 292 |
+
b_sub_offset = col * ne00 + half_step;
|
| 293 |
+
|
| 294 |
+
// Load next 16 fp4 (64-bits) in transposed layout
|
| 295 |
+
mxfp4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 296 |
+
mxfp4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 297 |
+
|
| 298 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 299 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 300 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 301 |
+
// Convert to half and store to LM to share within the subgroup
|
| 302 |
+
bx8_f16 = convert_half8(bx8_f32);
|
| 303 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 304 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 305 |
+
|
| 306 |
+
// Dequantization
|
| 307 |
+
reg_a.lo = mxfp4_to_fp16_packed8(as_ushort2(mxfp4x16.lo)) * s;
|
| 308 |
+
reg_a.hi = mxfp4_to_fp16_packed8(as_ushort2(mxfp4x16.hi)) * s;
|
| 309 |
+
|
| 310 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 311 |
+
|
| 312 |
+
// 32 16x16 fp16 dot product with 3-levels reduction for better precision
|
| 313 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 314 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 315 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 316 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
|
| 320 |
+
return;
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
// Load poster router and share in LM
|
| 324 |
+
__local uint out_idx[TILESIZE_N];
|
| 325 |
+
|
| 326 |
+
if (get_local_id(0) < TILESIZE_N) {
|
| 327 |
+
uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
|
| 328 |
+
if (idx == 0xFFFFFFFF) {
|
| 329 |
+
idx = src2[block_id_n * TILESIZE_N + 0];
|
| 330 |
+
}
|
| 331 |
+
out_idx[get_local_id(0)] = idx * ne01;
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 335 |
+
|
| 336 |
+
// Scatter results back to original position in output grid
|
| 337 |
+
uint m_offset = row + get_local_id(0);
|
| 338 |
+
|
| 339 |
+
write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
|
| 340 |
+
write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
|
| 341 |
+
write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
|
| 342 |
+
write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
|
| 343 |
+
write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
|
| 344 |
+
write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
|
| 345 |
+
write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
|
| 346 |
+
write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
|
| 347 |
+
write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
|
| 348 |
+
write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
|
| 349 |
+
write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
|
| 350 |
+
write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
|
| 351 |
+
write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
|
| 352 |
+
write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
|
| 353 |
+
write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
|
| 354 |
+
write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
|
| 355 |
+
write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
|
| 356 |
+
write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
|
| 357 |
+
write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
|
| 358 |
+
write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
|
| 359 |
+
write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
|
| 360 |
+
write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
|
| 361 |
+
write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
|
| 362 |
+
write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
|
| 363 |
+
write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
|
| 364 |
+
write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
|
| 365 |
+
write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
|
| 366 |
+
write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
|
| 367 |
+
write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
|
| 368 |
+
write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
|
| 369 |
+
write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
|
| 370 |
+
|
| 371 |
+
// Store zero padding parts to the index of first output in tile, override correct result in the end
|
| 372 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 373 |
+
write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
|
| 374 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_mxfp4_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_M 64
|
| 8 |
+
#define TILESIZE_N 32
|
| 9 |
+
|
| 10 |
+
// 2*mxfp4_value as signed int8, packed 4 codes per uint. Divergent nibble
|
| 11 |
+
// lookups read a __constant *uint* array + shift, never a byte array
|
| 12 |
+
// (byte-indexed __constant loads serialize on Adreno and are far slower).
|
| 13 |
+
// idx 0-3: 0, 1, 2, 3 = 0x03020100
|
| 14 |
+
// idx 4-7: 4, 6, 8, 12 = 0x0C080604
|
| 15 |
+
// idx 8-11: 0, -1, -2, -3 = 0xFDFEFF00 (-1=0xFF,-2=0xFE,-3=0xFD)
|
| 16 |
+
// idx 12-15:-4, -6, -8,-12 = 0xF4F8FAFC (-4=0xFC,-6=0xFA,-8=0xF8,-12=0xF4)
|
| 17 |
+
__constant uint mxfp4_i8x4[4] = {
|
| 18 |
+
0x03020100u, 0x0C080604u, 0xFDFEFF00u, 0xF4F8FAFCu
|
| 19 |
+
};
|
| 20 |
+
inline uint mxfp4_code(uint n) {
|
| 21 |
+
return (mxfp4_i8x4[n >> 2] >> ((n & 3u) * 8u)) & 0xFFu;
|
| 22 |
+
}
|
| 23 |
+
// 4 nibbles in the low 16 bits of u -> 4 codebook int8, packed for dp4a.
|
| 24 |
+
inline uint mxfp4_pack(ushort u) {
|
| 25 |
+
return mxfp4_code((uint)( u & 0xF))
|
| 26 |
+
| (mxfp4_code((uint)((u >> 4) & 0xF)) << 8)
|
| 27 |
+
| (mxfp4_code((uint)((u >> 8) & 0xF)) << 16)
|
| 28 |
+
| (mxfp4_code((uint)((u >> 12) & 0xF)) << 24);
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
static inline float e8m0_to_fp32(uchar x) {
|
| 32 |
+
int bits;
|
| 33 |
+
bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
|
| 34 |
+
return as_float(bits);
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
// One token's dp4a dot (8 uints = 32 K elems) + mxfp4 block-scale epilogue.
|
| 38 |
+
// blk_scale already carries the 0.5 factor (== 0.5 * 2^e).
|
| 39 |
+
#define MOE_MXFP4_DP4A_T(t) do { \
|
| 40 |
+
int raw = 0; \
|
| 41 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[0], sh_qa[t][0], raw); \
|
| 42 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[1], sh_qa[t][1], raw); \
|
| 43 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[2], sh_qa[t][2], raw); \
|
| 44 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[3], sh_qa[t][3], raw); \
|
| 45 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[4], sh_qa[t][4], raw); \
|
| 46 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[5], sh_qa[t][5], raw); \
|
| 47 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[6], sh_qa[t][6], raw); \
|
| 48 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[7], sh_qa[t][7], raw); \
|
| 49 |
+
acc[t] += blk_scale * (float)sh_d[t] * (float)raw; \
|
| 50 |
+
} while (0)
|
| 51 |
+
|
| 52 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 53 |
+
kernel void kernel_gemm_moe_mxfp4_q8_1_dp4a(
|
| 54 |
+
__read_only image1d_buffer_t src0_q, // mxfp4 codes (transposed, packed nibbles)
|
| 55 |
+
__global uchar * src0_e, // e8m0 per-32-block scale
|
| 56 |
+
__global uint * src1_qa, // q8_1 activations: int8 quants (as uint, 4/elem)
|
| 57 |
+
__global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
|
| 58 |
+
__global uint * src2, // post-router (orig out positions)
|
| 59 |
+
__global ushort * src2_emap, // tile -> expert id
|
| 60 |
+
__write_only image1d_buffer_t dst,
|
| 61 |
+
__global int * total_tiles,
|
| 62 |
+
uint ne00,
|
| 63 |
+
uint ne01,
|
| 64 |
+
int is_ragged // 1: compute only real tokens per tile
|
| 65 |
+
) {
|
| 66 |
+
const uint block_id_m = get_global_id(1); // m_tile
|
| 67 |
+
const uint block_id_n = get_global_id(2); // n_tile
|
| 68 |
+
|
| 69 |
+
if (block_id_n >= total_tiles[0]) {
|
| 70 |
+
return;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
const uint lid = get_local_id(0); // 0..63, == this WI's output row in the M-tile
|
| 74 |
+
|
| 75 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 76 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 77 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 78 |
+
|
| 79 |
+
const uint num_blocks = ne00 >> 5; // blocks-of-32 per token
|
| 80 |
+
const uint row_idx = row + lid;
|
| 81 |
+
|
| 82 |
+
const uint ne00_u = ne00 >> 2; // ne00 in uint (int8x4) units
|
| 83 |
+
|
| 84 |
+
__local uint sh_qa[TILESIZE_N][8]; // 32 tokens x 8 uints (32 int8) = 1 KiB
|
| 85 |
+
__local half sh_d[TILESIZE_N];
|
| 86 |
+
|
| 87 |
+
// Real token count for this tile.
|
| 88 |
+
// Real tokens are packed contiguously at the tile start; padded slots hold
|
| 89 |
+
// 0xFFFFFFFF (only the last tile of each expert is partial). is_ragged skips
|
| 90 |
+
// the dp4a/staging/scatter for padded slots; is_ragged==0 forces n_real=32.
|
| 91 |
+
__local uint sh_src2[TILESIZE_N];
|
| 92 |
+
__local int sh_nreal;
|
| 93 |
+
if (lid < TILESIZE_N) {
|
| 94 |
+
sh_src2[lid] = src2[col + lid];
|
| 95 |
+
}
|
| 96 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 97 |
+
if (lid == 0) {
|
| 98 |
+
int nr = TILESIZE_N;
|
| 99 |
+
if (is_ragged) {
|
| 100 |
+
nr = 0;
|
| 101 |
+
#pragma unroll
|
| 102 |
+
for (int t = 0; t < TILESIZE_N; ++t) {
|
| 103 |
+
if (sh_src2[t] != 0xFFFFFFFFu) ++nr;
|
| 104 |
+
}
|
| 105 |
+
}
|
| 106 |
+
sh_nreal = nr;
|
| 107 |
+
}
|
| 108 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 109 |
+
const int n_real = sh_nreal;
|
| 110 |
+
|
| 111 |
+
float acc[TILESIZE_N];
|
| 112 |
+
#pragma unroll
|
| 113 |
+
for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
|
| 114 |
+
|
| 115 |
+
for (uint step = 0; step < ne00; step += 32) {
|
| 116 |
+
const uint sub = step >> 5; // 32-block index along K
|
| 117 |
+
|
| 118 |
+
// e8m0 block scale for this WI's row, this 32-block (folded x0.5)
|
| 119 |
+
const uint e_offset = row_idx + sub * ne01 + expert_id * num_blocks * ne01;
|
| 120 |
+
const float blk_scale = 0.5f * e8m0_to_fp32(src0_e[e_offset]);
|
| 121 |
+
|
| 122 |
+
// repack this WI's 32 weight nibbles into 8 dp4a uints
|
| 123 |
+
const uint qoff0 = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 124 |
+
const uint qoff1 = row + ((ne01 * (step + 16)) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 125 |
+
const uint r0 = read_imageui(src0_q, qoff0 + lid).x;
|
| 126 |
+
const uint r1 = read_imageui(src0_q, qoff0 + lid + ne01).x;
|
| 127 |
+
const uint r2 = read_imageui(src0_q, qoff1 + lid).x;
|
| 128 |
+
const uint r3 = read_imageui(src0_q, qoff1 + lid + ne01).x;
|
| 129 |
+
uint qw[8];
|
| 130 |
+
qw[0] = mxfp4_pack((ushort)(r0)); qw[1] = mxfp4_pack((ushort)(r0 >> 16));
|
| 131 |
+
qw[2] = mxfp4_pack((ushort)(r1)); qw[3] = mxfp4_pack((ushort)(r1 >> 16));
|
| 132 |
+
qw[4] = mxfp4_pack((ushort)(r2)); qw[5] = mxfp4_pack((ushort)(r2 >> 16));
|
| 133 |
+
qw[6] = mxfp4_pack((ushort)(r3)); qw[7] = mxfp4_pack((ushort)(r3 >> 16));
|
| 134 |
+
|
| 135 |
+
// cooperatively stage the n_real-token x 32-K int8 activations
|
| 136 |
+
const uint stage_lim = (uint)n_real * 8;
|
| 137 |
+
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
| 138 |
+
const uint t = idx >> 3;
|
| 139 |
+
const uint u = idx & 7;
|
| 140 |
+
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
| 141 |
+
}
|
| 142 |
+
if (lid < (uint)n_real) {
|
| 143 |
+
sh_d[lid] = src1_da[(col + lid) * num_blocks + sub];
|
| 144 |
+
}
|
| 145 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 146 |
+
|
| 147 |
+
// Full tiles keep the fully-unrolled 32-wide loop; partial tiles run only n_real
|
| 148 |
+
if (n_real == TILESIZE_N) {
|
| 149 |
+
#pragma unroll
|
| 150 |
+
for (int t = 0; t < TILESIZE_N; ++t) { MOE_MXFP4_DP4A_T(t); }
|
| 151 |
+
} else {
|
| 152 |
+
#pragma unroll 4
|
| 153 |
+
for (int t = 0; t < n_real; ++t) { MOE_MXFP4_DP4A_T(t); }
|
| 154 |
+
}
|
| 155 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
if (row_idx >= ne01) {
|
| 159 |
+
return;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
// scatter results to original output rows (reuse sh_src2 from the top)
|
| 163 |
+
__local uint out_idx[TILESIZE_N];
|
| 164 |
+
if (lid < TILESIZE_N) {
|
| 165 |
+
uint idx = sh_src2[lid];
|
| 166 |
+
if (idx == 0xFFFFFFFF) {
|
| 167 |
+
idx = sh_src2[0];
|
| 168 |
+
}
|
| 169 |
+
out_idx[lid] = idx * ne01;
|
| 170 |
+
}
|
| 171 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 172 |
+
|
| 173 |
+
const uint m_offset = row + lid;
|
| 174 |
+
if (n_real == TILESIZE_N) {
|
| 175 |
+
#pragma unroll
|
| 176 |
+
for (int t = 1; t < TILESIZE_N; ++t) {
|
| 177 |
+
write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 178 |
+
}
|
| 179 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 180 |
+
write_imagef(dst, out_idx[0] + m_offset, acc[0]);
|
| 181 |
+
} else {
|
| 182 |
+
for (int t = 0; t < n_real; ++t) {
|
| 183 |
+
write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_f32_ns.cl
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_K 16
|
| 8 |
+
#define TILESIZE_M 64
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
#define dequantize_q4_0(q4, a_f16, scale) \
|
| 13 |
+
a_f16.s0 = (half)((q4.s0 & 0x000F) - 8) * scale; \
|
| 14 |
+
a_f16.s1 = (half)(((q4.s0 & 0x00F0) >> 4) - 8) * scale; \
|
| 15 |
+
a_f16.s2 = (half)(((q4.s0 & 0x0F00) >> 8) - 8) * scale; \
|
| 16 |
+
a_f16.s3 = (half)(((q4.s0 & 0xF000) >> 12) - 8) * scale; \
|
| 17 |
+
a_f16.s4 = (half)((q4.s1 & 0x000F) - 8) * scale; \
|
| 18 |
+
a_f16.s5 = (half)(((q4.s1 & 0x00F0) >> 4) - 8) * scale; \
|
| 19 |
+
a_f16.s6 = (half)(((q4.s1 & 0x0F00) >> 8) - 8) * scale; \
|
| 20 |
+
a_f16.s7 = (half)(((q4.s1 & 0xF000) >> 12) - 8) * scale; \
|
| 21 |
+
a_f16.s8 = (half)((q4.s2 & 0x000F) - 8) * scale; \
|
| 22 |
+
a_f16.s9 = (half)(((q4.s2 & 0x00F0) >> 4) - 8) * scale; \
|
| 23 |
+
a_f16.sa = (half)(((q4.s2 & 0x0F00) >> 8) - 8) * scale; \
|
| 24 |
+
a_f16.sb = (half)(((q4.s2 & 0xF000) >> 12) - 8) * scale; \
|
| 25 |
+
a_f16.sc = (half)((q4.s3 & 0x000F) - 8) * scale; \
|
| 26 |
+
a_f16.sd = (half)(((q4.s3 & 0x00F0) >> 4) - 8) * scale; \
|
| 27 |
+
a_f16.se = (half)(((q4.s3 & 0x0F00) >> 8) - 8) * scale; \
|
| 28 |
+
a_f16.sf = (half)(((q4.s3 & 0xF000) >> 12) - 8) * scale; \
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
#define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
|
| 32 |
+
acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 33 |
+
acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 34 |
+
acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 35 |
+
acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 36 |
+
acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 37 |
+
acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 38 |
+
acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 39 |
+
acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 40 |
+
acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
|
| 41 |
+
acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
|
| 42 |
+
acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
|
| 43 |
+
acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
|
| 44 |
+
acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
|
| 45 |
+
acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
|
| 46 |
+
acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
|
| 47 |
+
acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
|
| 48 |
+
acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 49 |
+
acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 50 |
+
acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 51 |
+
acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 52 |
+
acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 53 |
+
acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 54 |
+
acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 55 |
+
acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 56 |
+
acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
|
| 57 |
+
acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
|
| 58 |
+
acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
|
| 59 |
+
acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
|
| 60 |
+
acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
|
| 61 |
+
acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
|
| 62 |
+
acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
|
| 63 |
+
acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
|
| 64 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 65 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 66 |
+
acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 67 |
+
acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 68 |
+
acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 69 |
+
acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 70 |
+
acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 71 |
+
acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 72 |
+
acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 73 |
+
acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 74 |
+
acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
|
| 75 |
+
acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
|
| 76 |
+
acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
|
| 77 |
+
acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
|
| 78 |
+
acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
|
| 79 |
+
acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
|
| 80 |
+
acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
|
| 81 |
+
acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
|
| 82 |
+
acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 83 |
+
acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 84 |
+
acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 85 |
+
acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 86 |
+
acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 87 |
+
acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 88 |
+
acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 89 |
+
acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 90 |
+
acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
|
| 91 |
+
acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
|
| 92 |
+
acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
|
| 93 |
+
acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
|
| 94 |
+
acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
|
| 95 |
+
acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
|
| 96 |
+
acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
|
| 97 |
+
acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
|
| 98 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 99 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 100 |
+
|
| 101 |
+
// Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
|
| 102 |
+
// accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
|
| 103 |
+
// non-skipped path is byte-identical; it just lets the caller skip empty
|
| 104 |
+
// 8-column groups at finer granularity. Uses a private half8 `acc8`.
|
| 105 |
+
#define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
|
| 106 |
+
acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 107 |
+
acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 108 |
+
acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 109 |
+
acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 110 |
+
acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 111 |
+
acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 112 |
+
acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 113 |
+
acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 114 |
+
acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 115 |
+
acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 116 |
+
acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 117 |
+
acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 118 |
+
acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 119 |
+
acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 120 |
+
acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 121 |
+
acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 122 |
+
c_reg += convert_float8(acc8); \
|
| 123 |
+
acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 124 |
+
acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 125 |
+
acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 126 |
+
acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 127 |
+
acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 128 |
+
acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 129 |
+
acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 130 |
+
acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 131 |
+
acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 132 |
+
acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 133 |
+
acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 134 |
+
acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 135 |
+
acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 136 |
+
acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 137 |
+
acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 138 |
+
acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 139 |
+
c_reg += convert_float8(acc8); \
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
__attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
|
| 143 |
+
kernel void kernel_gemm_moe_q4_0_f32_ns(
|
| 144 |
+
__read_only image1d_buffer_t src0_q,
|
| 145 |
+
__global half * src0_d,
|
| 146 |
+
__read_only image1d_buffer_t src1,
|
| 147 |
+
__global uint * src2,
|
| 148 |
+
__global ushort * src2_emap,
|
| 149 |
+
__write_only image1d_buffer_t dst,
|
| 150 |
+
__global int * total_tiles,
|
| 151 |
+
uint ne00,
|
| 152 |
+
uint ne01,
|
| 153 |
+
uint is_ragged,
|
| 154 |
+
uint skip_gran
|
| 155 |
+
) {
|
| 156 |
+
uint block_id_m = get_global_id(1); // m_tile
|
| 157 |
+
uint block_id_n = get_global_id(2); // n_tile
|
| 158 |
+
|
| 159 |
+
// Boundary check
|
| 160 |
+
if (block_id_n >= total_tiles[0]) {
|
| 161 |
+
return;
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
// Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
|
| 165 |
+
// padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
|
| 166 |
+
// the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
|
| 167 |
+
// Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
|
| 168 |
+
// lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
|
| 169 |
+
// trailing. Find the valid-token count V and round it UP to the skip granularity
|
| 170 |
+
// skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
|
| 171 |
+
// A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
|
| 172 |
+
// dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
|
| 173 |
+
uint n_active = TILESIZE_N;
|
| 174 |
+
if (is_ragged && skip_gran < TILESIZE_N) {
|
| 175 |
+
uint n_valid = TILESIZE_N;
|
| 176 |
+
for (uint _t = 0; _t < TILESIZE_N; ++_t) {
|
| 177 |
+
if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
|
| 178 |
+
}
|
| 179 |
+
n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
|
| 180 |
+
}
|
| 181 |
+
// Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
|
| 182 |
+
bool skip_g1 = (8u >= n_active);
|
| 183 |
+
bool skip_g2 = (16u >= n_active);
|
| 184 |
+
bool skip_g3 = (24u >= n_active);
|
| 185 |
+
|
| 186 |
+
__private half16 reg_a;
|
| 187 |
+
__private float32 reg_c = (float32)(0);
|
| 188 |
+
__local half4 shared_b[128];
|
| 189 |
+
|
| 190 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 191 |
+
|
| 192 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 193 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 194 |
+
|
| 195 |
+
uint sub_block_id_m = get_local_id(0);
|
| 196 |
+
uint2 b_global_offset;
|
| 197 |
+
b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
|
| 198 |
+
b_global_offset.y = b_global_offset.x + (16 * ne00);
|
| 199 |
+
uint2 b_local_offset;
|
| 200 |
+
b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
|
| 201 |
+
b_local_offset.y = b_local_offset.x + 16;
|
| 202 |
+
|
| 203 |
+
// Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
|
| 204 |
+
for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
|
| 205 |
+
// First sub-block
|
| 206 |
+
uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 207 |
+
uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
|
| 208 |
+
uint b_sub_offset = col * ne00 + step;
|
| 209 |
+
|
| 210 |
+
// Load scale for current Q4_0 block
|
| 211 |
+
uint s_offset = s_sub_offset + get_global_id(0);
|
| 212 |
+
half s = src0_d[s_offset];
|
| 213 |
+
|
| 214 |
+
// Load 16 q (64-bits) in transposed layout
|
| 215 |
+
uint2 q4x16;
|
| 216 |
+
q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 217 |
+
q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 218 |
+
|
| 219 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 220 |
+
float8 bx8_f32;
|
| 221 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 222 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 223 |
+
// Convert to half and store to LM to share within the subgroup
|
| 224 |
+
half8 bx8_f16 = convert_half8(bx8_f32);
|
| 225 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 226 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 227 |
+
|
| 228 |
+
// Dequantization
|
| 229 |
+
dequantize_q4_0(as_ushort4(q4x16), reg_a, s);
|
| 230 |
+
|
| 231 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 232 |
+
|
| 233 |
+
// 32 16x16 fp16 dot product with 8 elements reduction for better precision
|
| 234 |
+
half8 acc8;
|
| 235 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 236 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 237 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 238 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 239 |
+
|
| 240 |
+
// Repeat for second sub-block
|
| 241 |
+
uint half_step = step + TILESIZE_K;
|
| 242 |
+
q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 243 |
+
b_sub_offset = col * ne00 + half_step;
|
| 244 |
+
|
| 245 |
+
// Load next 16 q (64-bits) in transposed layout
|
| 246 |
+
q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 247 |
+
q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 248 |
+
|
| 249 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 250 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 251 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 252 |
+
// Convert to half and store to LM to share within the subgroup
|
| 253 |
+
bx8_f16 = convert_half8(bx8_f32);
|
| 254 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 255 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 256 |
+
|
| 257 |
+
// Dequantization
|
| 258 |
+
dequantize_q4_0(as_ushort4(q4x16), reg_a, s);
|
| 259 |
+
|
| 260 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 261 |
+
|
| 262 |
+
// 32 16x16 fp16 dot product with 3-levels reduction for better precision
|
| 263 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 264 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 265 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 266 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
|
| 270 |
+
return;
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
// Load poster router and share in LM
|
| 274 |
+
__local uint out_idx[TILESIZE_N];
|
| 275 |
+
|
| 276 |
+
if (get_local_id(0) < TILESIZE_N) {
|
| 277 |
+
uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
|
| 278 |
+
if (idx == 0xFFFFFFFF) {
|
| 279 |
+
idx = src2[block_id_n * TILESIZE_N + 0];
|
| 280 |
+
}
|
| 281 |
+
out_idx[get_local_id(0)] = idx * ne01;
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 285 |
+
|
| 286 |
+
// Scatter results back to original position in output grid
|
| 287 |
+
uint m_offset = row + get_local_id(0);
|
| 288 |
+
|
| 289 |
+
write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
|
| 290 |
+
write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
|
| 291 |
+
write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
|
| 292 |
+
write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
|
| 293 |
+
write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
|
| 294 |
+
write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
|
| 295 |
+
write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
|
| 296 |
+
write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
|
| 297 |
+
write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
|
| 298 |
+
write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
|
| 299 |
+
write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
|
| 300 |
+
write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
|
| 301 |
+
write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
|
| 302 |
+
write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
|
| 303 |
+
write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
|
| 304 |
+
write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
|
| 305 |
+
write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
|
| 306 |
+
write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
|
| 307 |
+
write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
|
| 308 |
+
write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
|
| 309 |
+
write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
|
| 310 |
+
write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
|
| 311 |
+
write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
|
| 312 |
+
write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
|
| 313 |
+
write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
|
| 314 |
+
write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
|
| 315 |
+
write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
|
| 316 |
+
write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
|
| 317 |
+
write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
|
| 318 |
+
write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
|
| 319 |
+
write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
|
| 320 |
+
|
| 321 |
+
// Store zero padding parts to the index of first output in tile, override correct result in the end
|
| 322 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 323 |
+
write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
|
| 324 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_0_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_M 64
|
| 8 |
+
#define TILESIZE_N 32
|
| 9 |
+
|
| 10 |
+
// Expand the 4 nibbles held in the low 16 bits of `u` into 4 bytes (one nibble
|
| 11 |
+
// per byte, value 0..15), packed for the int8 dp4a. The -8 zero-point is applied
|
| 12 |
+
// in the epilogue via the activation sum term (cheaper than biasing every byte).
|
| 13 |
+
#define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
|
| 14 |
+
(((uint)((u) & 0x00F0u)) << 4) | \
|
| 15 |
+
(((uint)((u) & 0x0F00u)) << 8) | \
|
| 16 |
+
(((uint)((u) & 0xF000u)) << 12) )
|
| 17 |
+
|
| 18 |
+
// One token's dp4a dot (8 uints = 32 K elems) + q4_0 scale/zero-point epilogue.
|
| 19 |
+
#define MOE_Q40_DP4A_T(t) do { \
|
| 20 |
+
int raw = 0; \
|
| 21 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[0], sh_qa[t][0], raw); \
|
| 22 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[1], sh_qa[t][1], raw); \
|
| 23 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[2], sh_qa[t][2], raw); \
|
| 24 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[3], sh_qa[t][3], raw); \
|
| 25 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[4], sh_qa[t][4], raw); \
|
| 26 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[5], sh_qa[t][5], raw); \
|
| 27 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[6], sh_qa[t][6], raw); \
|
| 28 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[7], sh_qa[t][7], raw); \
|
| 29 |
+
acc[t] += d_val * ((float)sh_d[t] * (float)raw - 8.0f * (float)sh_s[t]); \
|
| 30 |
+
} while (0)
|
| 31 |
+
|
| 32 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 33 |
+
kernel void kernel_gemm_moe_q4_0_q8_1_dp4a(
|
| 34 |
+
__read_only image1d_buffer_t src0_q, // q4_0 weights (transposed, packed nibbles)
|
| 35 |
+
__global half * src0_d, // per-32-block scale
|
| 36 |
+
__global uint * src1_qa, // q8_1 activations: int8 quants (as uint, 4/elem)
|
| 37 |
+
__global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
|
| 38 |
+
__global half * src1_sa, // q8_1 per-block sum*d [tok_slot * ne00/32]
|
| 39 |
+
__global uint * src2, // post-router (orig out positions)
|
| 40 |
+
__global ushort * src2_emap,// tile -> expert id
|
| 41 |
+
__write_only image1d_buffer_t dst,
|
| 42 |
+
__global int * total_tiles,
|
| 43 |
+
uint ne00,
|
| 44 |
+
uint ne01,
|
| 45 |
+
int is_ragged // 1: compute only real tokens per tile
|
| 46 |
+
) {
|
| 47 |
+
const uint block_id_m = get_global_id(1); // m_tile
|
| 48 |
+
const uint block_id_n = get_global_id(2); // n_tile
|
| 49 |
+
|
| 50 |
+
if (block_id_n >= total_tiles[0]) {
|
| 51 |
+
return;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
const uint lid = get_local_id(0); // 0..63, == this WI's output row in the M-tile
|
| 55 |
+
|
| 56 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 57 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 58 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 59 |
+
|
| 60 |
+
const uint num_blocks = ne00 >> 5; // blocks-of-32 per token
|
| 61 |
+
const uint row_idx = row + lid;
|
| 62 |
+
|
| 63 |
+
const uint ne00_u = ne00 >> 2; // ne00 in uint (int8x4) units
|
| 64 |
+
|
| 65 |
+
__local uint sh_qa[TILESIZE_N][8]; // 32 tokens x 8 uints (32 int8) = 1 KiB
|
| 66 |
+
__local half sh_d[TILESIZE_N];
|
| 67 |
+
__local half sh_s[TILESIZE_N];
|
| 68 |
+
|
| 69 |
+
// Real-token count for this tile
|
| 70 |
+
__local uint sh_src2[TILESIZE_N];
|
| 71 |
+
__local int sh_nreal;
|
| 72 |
+
if (lid < TILESIZE_N) {
|
| 73 |
+
sh_src2[lid] = src2[col + lid];
|
| 74 |
+
}
|
| 75 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 76 |
+
if (lid == 0) {
|
| 77 |
+
int nr = TILESIZE_N;
|
| 78 |
+
if (is_ragged) {
|
| 79 |
+
nr = 0;
|
| 80 |
+
#pragma unroll
|
| 81 |
+
for (int t = 0; t < TILESIZE_N; ++t) {
|
| 82 |
+
if (sh_src2[t] != 0xFFFFFFFFu) ++nr;
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
sh_nreal = nr;
|
| 86 |
+
}
|
| 87 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 88 |
+
const int n_real = sh_nreal;
|
| 89 |
+
|
| 90 |
+
float acc[TILESIZE_N];
|
| 91 |
+
#pragma unroll
|
| 92 |
+
for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
|
| 93 |
+
|
| 94 |
+
for (uint step = 0; step < ne00; step += 32) {
|
| 95 |
+
const uint sub = step >> 5; // 32-block index along K
|
| 96 |
+
|
| 97 |
+
// per-32-block scale for this WI's row
|
| 98 |
+
const uint d_offset = row_idx + sub * ne01 + expert_id * num_blocks * ne01;
|
| 99 |
+
const float d_val = (float)src0_d[d_offset];
|
| 100 |
+
|
| 101 |
+
// repack this WI's 32 weight nibbles into 8 dp4a uints
|
| 102 |
+
const uint qoff0 = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 103 |
+
const uint qoff1 = row + ((ne01 * (step + 16)) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 104 |
+
const uint r0 = read_imageui(src0_q, qoff0 + lid).x;
|
| 105 |
+
const uint r1 = read_imageui(src0_q, qoff0 + lid + ne01).x;
|
| 106 |
+
const uint r2 = read_imageui(src0_q, qoff1 + lid).x;
|
| 107 |
+
const uint r3 = read_imageui(src0_q, qoff1 + lid + ne01).x;
|
| 108 |
+
uint qw[8];
|
| 109 |
+
qw[0] = EXP4(r0); qw[1] = EXP4(r0 >> 16);
|
| 110 |
+
qw[2] = EXP4(r1); qw[3] = EXP4(r1 >> 16);
|
| 111 |
+
qw[4] = EXP4(r2); qw[5] = EXP4(r2 >> 16);
|
| 112 |
+
qw[6] = EXP4(r3); qw[7] = EXP4(r3 >> 16);
|
| 113 |
+
|
| 114 |
+
// cooperatively stage the n_real-token x 32-K int8 activations
|
| 115 |
+
const uint stage_lim = (uint)n_real * 8;
|
| 116 |
+
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
| 117 |
+
const uint t = idx >> 3;
|
| 118 |
+
const uint u = idx & 7;
|
| 119 |
+
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
| 120 |
+
}
|
| 121 |
+
if (lid < (uint)n_real) {
|
| 122 |
+
sh_d[lid] = src1_da[(col + lid) * num_blocks + sub];
|
| 123 |
+
sh_s[lid] = src1_sa[(col + lid) * num_blocks + sub];
|
| 124 |
+
}
|
| 125 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 126 |
+
|
| 127 |
+
if (n_real == TILESIZE_N) {
|
| 128 |
+
#pragma unroll
|
| 129 |
+
for (int t = 0; t < TILESIZE_N; ++t) { MOE_Q40_DP4A_T(t); }
|
| 130 |
+
} else {
|
| 131 |
+
#pragma unroll 4
|
| 132 |
+
for (int t = 0; t < n_real; ++t) { MOE_Q40_DP4A_T(t); }
|
| 133 |
+
}
|
| 134 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
if (row_idx >= ne01) {
|
| 138 |
+
return;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
// scatter results to original output rows (reuse sh_src2 from the top)
|
| 142 |
+
__local uint out_idx[TILESIZE_N];
|
| 143 |
+
if (lid < TILESIZE_N) {
|
| 144 |
+
uint idx = sh_src2[lid];
|
| 145 |
+
if (idx == 0xFFFFFFFF) {
|
| 146 |
+
idx = sh_src2[0];
|
| 147 |
+
}
|
| 148 |
+
out_idx[lid] = idx * ne01;
|
| 149 |
+
}
|
| 150 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 151 |
+
|
| 152 |
+
const uint m_offset = row + lid;
|
| 153 |
+
if (n_real == TILESIZE_N) {
|
| 154 |
+
#pragma unroll
|
| 155 |
+
for (int t = 1; t < TILESIZE_N; ++t) {
|
| 156 |
+
write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 157 |
+
}
|
| 158 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 159 |
+
write_imagef(dst, out_idx[0] + m_offset, acc[0]);
|
| 160 |
+
} else {
|
| 161 |
+
for (int t = 0; t < n_real; ++t) {
|
| 162 |
+
write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 163 |
+
}
|
| 164 |
+
}
|
| 165 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_1_f32_ns.cl
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_K 16
|
| 8 |
+
#define TILESIZE_M 64
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
#define dequantize_q4_1(q4, a_f16, scale, m) \
|
| 13 |
+
a_f16.s0 = (half)(q4.s0 & 0x000F) * scale + m; \
|
| 14 |
+
a_f16.s1 = (half)((q4.s0 & 0x00F0) >> 4) * scale + m; \
|
| 15 |
+
a_f16.s2 = (half)((q4.s0 & 0x0F00) >> 8) * scale + m; \
|
| 16 |
+
a_f16.s3 = (half)((q4.s0 & 0xF000) >> 12) * scale + m; \
|
| 17 |
+
a_f16.s4 = (half)(q4.s1 & 0x000F) * scale + m; \
|
| 18 |
+
a_f16.s5 = (half)((q4.s1 & 0x00F0) >> 4) * scale + m; \
|
| 19 |
+
a_f16.s6 = (half)((q4.s1 & 0x0F00) >> 8) * scale + m; \
|
| 20 |
+
a_f16.s7 = (half)((q4.s1 & 0xF000) >> 12) * scale + m; \
|
| 21 |
+
a_f16.s8 = (half)(q4.s2 & 0x000F) * scale + m; \
|
| 22 |
+
a_f16.s9 = (half)((q4.s2 & 0x00F0) >> 4) * scale + m; \
|
| 23 |
+
a_f16.sa = (half)((q4.s2 & 0x0F00) >> 8) * scale + m; \
|
| 24 |
+
a_f16.sb = (half)((q4.s2 & 0xF000) >> 12) * scale + m; \
|
| 25 |
+
a_f16.sc = (half)(q4.s3 & 0x000F) * scale + m; \
|
| 26 |
+
a_f16.sd = (half)((q4.s3 & 0x00F0) >> 4) * scale + m; \
|
| 27 |
+
a_f16.se = (half)((q4.s3 & 0x0F00) >> 8) * scale + m; \
|
| 28 |
+
a_f16.sf = (half)((q4.s3 & 0xF000) >> 12) * scale + m; \
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
#define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
|
| 32 |
+
acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 33 |
+
acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 34 |
+
acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 35 |
+
acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 36 |
+
acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 37 |
+
acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 38 |
+
acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 39 |
+
acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 40 |
+
acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
|
| 41 |
+
acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
|
| 42 |
+
acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
|
| 43 |
+
acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
|
| 44 |
+
acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
|
| 45 |
+
acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
|
| 46 |
+
acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
|
| 47 |
+
acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
|
| 48 |
+
acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 49 |
+
acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 50 |
+
acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 51 |
+
acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 52 |
+
acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 53 |
+
acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 54 |
+
acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 55 |
+
acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 56 |
+
acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
|
| 57 |
+
acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
|
| 58 |
+
acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
|
| 59 |
+
acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
|
| 60 |
+
acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
|
| 61 |
+
acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
|
| 62 |
+
acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
|
| 63 |
+
acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
|
| 64 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 65 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 66 |
+
acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 67 |
+
acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 68 |
+
acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 69 |
+
acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 70 |
+
acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 71 |
+
acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 72 |
+
acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 73 |
+
acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 74 |
+
acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
|
| 75 |
+
acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
|
| 76 |
+
acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
|
| 77 |
+
acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
|
| 78 |
+
acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
|
| 79 |
+
acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
|
| 80 |
+
acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
|
| 81 |
+
acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
|
| 82 |
+
acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 83 |
+
acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 84 |
+
acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 85 |
+
acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 86 |
+
acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 87 |
+
acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 88 |
+
acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 89 |
+
acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 90 |
+
acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
|
| 91 |
+
acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
|
| 92 |
+
acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
|
| 93 |
+
acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
|
| 94 |
+
acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
|
| 95 |
+
acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
|
| 96 |
+
acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
|
| 97 |
+
acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
|
| 98 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 99 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 100 |
+
|
| 101 |
+
// Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
|
| 102 |
+
// accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
|
| 103 |
+
// non-skipped path is byte-identical; it just lets the caller skip empty
|
| 104 |
+
// 8-column groups at finer granularity. Uses a private half8 `acc8`.
|
| 105 |
+
#define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
|
| 106 |
+
acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 107 |
+
acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 108 |
+
acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 109 |
+
acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 110 |
+
acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 111 |
+
acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 112 |
+
acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 113 |
+
acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 114 |
+
acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 115 |
+
acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 116 |
+
acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 117 |
+
acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 118 |
+
acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 119 |
+
acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 120 |
+
acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 121 |
+
acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 122 |
+
c_reg += convert_float8(acc8); \
|
| 123 |
+
acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 124 |
+
acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 125 |
+
acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 126 |
+
acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 127 |
+
acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 128 |
+
acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 129 |
+
acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 130 |
+
acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 131 |
+
acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 132 |
+
acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 133 |
+
acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 134 |
+
acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 135 |
+
acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 136 |
+
acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 137 |
+
acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 138 |
+
acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 139 |
+
c_reg += convert_float8(acc8); \
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
__attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
|
| 143 |
+
kernel void kernel_gemm_moe_q4_1_f32_ns(
|
| 144 |
+
__read_only image1d_buffer_t src0_q,
|
| 145 |
+
__global half * src0_d,
|
| 146 |
+
__global half * src0_m,
|
| 147 |
+
__read_only image1d_buffer_t src1,
|
| 148 |
+
__global uint * src2,
|
| 149 |
+
__global ushort * src2_emap,
|
| 150 |
+
__write_only image1d_buffer_t dst,
|
| 151 |
+
__global int * total_tiles,
|
| 152 |
+
uint ne00,
|
| 153 |
+
uint ne01,
|
| 154 |
+
uint is_ragged,
|
| 155 |
+
uint skip_gran
|
| 156 |
+
) {
|
| 157 |
+
uint block_id_m = get_global_id(1); // m_tile
|
| 158 |
+
uint block_id_n = get_global_id(2); // n_tile
|
| 159 |
+
|
| 160 |
+
// Boundary check
|
| 161 |
+
if (block_id_n >= total_tiles[0]) {
|
| 162 |
+
return;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
// Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
|
| 166 |
+
// padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
|
| 167 |
+
// the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
|
| 168 |
+
// Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
|
| 169 |
+
// lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
|
| 170 |
+
// trailing. Find the valid-token count V and round it UP to the skip granularity
|
| 171 |
+
// skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
|
| 172 |
+
// A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
|
| 173 |
+
// dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
|
| 174 |
+
uint n_active = TILESIZE_N;
|
| 175 |
+
if (is_ragged && skip_gran < TILESIZE_N) {
|
| 176 |
+
uint n_valid = TILESIZE_N;
|
| 177 |
+
for (uint _t = 0; _t < TILESIZE_N; ++_t) {
|
| 178 |
+
if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
|
| 179 |
+
}
|
| 180 |
+
n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
|
| 181 |
+
}
|
| 182 |
+
// Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
|
| 183 |
+
bool skip_g1 = (8u >= n_active);
|
| 184 |
+
bool skip_g2 = (16u >= n_active);
|
| 185 |
+
bool skip_g3 = (24u >= n_active);
|
| 186 |
+
|
| 187 |
+
__private half16 reg_a;
|
| 188 |
+
__private float32 reg_c = (float32)(0);
|
| 189 |
+
__local half4 shared_b[128];
|
| 190 |
+
|
| 191 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 192 |
+
|
| 193 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 194 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 195 |
+
|
| 196 |
+
uint sub_block_id_m = get_local_id(0);
|
| 197 |
+
uint2 b_global_offset;
|
| 198 |
+
b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
|
| 199 |
+
b_global_offset.y = b_global_offset.x + (16 * ne00);
|
| 200 |
+
uint2 b_local_offset;
|
| 201 |
+
b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
|
| 202 |
+
b_local_offset.y = b_local_offset.x + 16;
|
| 203 |
+
|
| 204 |
+
// Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
|
| 205 |
+
for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
|
| 206 |
+
// First sub-block
|
| 207 |
+
uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 208 |
+
uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
|
| 209 |
+
uint b_sub_offset = col * ne00 + step;
|
| 210 |
+
|
| 211 |
+
// Load scale and m for current Q4_1 block
|
| 212 |
+
uint sm_offset = s_sub_offset + get_global_id(0);
|
| 213 |
+
half s = src0_d[sm_offset];
|
| 214 |
+
half m = src0_m[sm_offset];
|
| 215 |
+
|
| 216 |
+
// Load 16 q (64-bits) in transposed layout
|
| 217 |
+
uint2 q4x16;
|
| 218 |
+
q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 219 |
+
q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 220 |
+
|
| 221 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 222 |
+
float8 bx8_f32;
|
| 223 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 224 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 225 |
+
// Convert to half and store to LM to share within the subgroup
|
| 226 |
+
half8 bx8_f16 = convert_half8(bx8_f32);
|
| 227 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 228 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 229 |
+
|
| 230 |
+
// Dequantization
|
| 231 |
+
dequantize_q4_1(as_ushort4(q4x16), reg_a, s, m);
|
| 232 |
+
|
| 233 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 234 |
+
|
| 235 |
+
// 32 16x16 fp16 dot product with 8 elements reduction for better precision
|
| 236 |
+
half8 acc8;
|
| 237 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 238 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 239 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 240 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 241 |
+
|
| 242 |
+
// Repeat for second sub-block
|
| 243 |
+
uint half_step = step + TILESIZE_K;
|
| 244 |
+
q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 245 |
+
b_sub_offset = col * ne00 + half_step;
|
| 246 |
+
|
| 247 |
+
// Load next 16 q (64-bits) in transposed layout
|
| 248 |
+
q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 249 |
+
q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 250 |
+
|
| 251 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 252 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 253 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 254 |
+
// Convert to half and store to LM to share within the subgroup
|
| 255 |
+
bx8_f16 = convert_half8(bx8_f32);
|
| 256 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 257 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 258 |
+
|
| 259 |
+
// Dequantization
|
| 260 |
+
dequantize_q4_1(as_ushort4(q4x16), reg_a, s, m);
|
| 261 |
+
|
| 262 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 263 |
+
|
| 264 |
+
// 32 16x16 fp16 dot product with 3-levels reduction for better precision
|
| 265 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 266 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 267 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 268 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
|
| 272 |
+
return;
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
// Load poster router and share in LM
|
| 276 |
+
__local uint out_idx[TILESIZE_N];
|
| 277 |
+
|
| 278 |
+
if (get_local_id(0) < TILESIZE_N) {
|
| 279 |
+
uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
|
| 280 |
+
if (idx == 0xFFFFFFFF) {
|
| 281 |
+
idx = src2[block_id_n * TILESIZE_N + 0];
|
| 282 |
+
}
|
| 283 |
+
out_idx[get_local_id(0)] = idx * ne01;
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 287 |
+
|
| 288 |
+
// Scatter results back to original position in output grid
|
| 289 |
+
uint m_offset = row + get_local_id(0);
|
| 290 |
+
|
| 291 |
+
write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
|
| 292 |
+
write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
|
| 293 |
+
write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
|
| 294 |
+
write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
|
| 295 |
+
write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
|
| 296 |
+
write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
|
| 297 |
+
write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
|
| 298 |
+
write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
|
| 299 |
+
write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
|
| 300 |
+
write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
|
| 301 |
+
write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
|
| 302 |
+
write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
|
| 303 |
+
write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
|
| 304 |
+
write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
|
| 305 |
+
write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
|
| 306 |
+
write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
|
| 307 |
+
write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
|
| 308 |
+
write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
|
| 309 |
+
write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
|
| 310 |
+
write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
|
| 311 |
+
write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
|
| 312 |
+
write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
|
| 313 |
+
write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
|
| 314 |
+
write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
|
| 315 |
+
write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
|
| 316 |
+
write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
|
| 317 |
+
write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
|
| 318 |
+
write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
|
| 319 |
+
write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
|
| 320 |
+
write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
|
| 321 |
+
write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
|
| 322 |
+
|
| 323 |
+
// Store zero padding parts to the index of first output in tile, override correct result in the end
|
| 324 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 325 |
+
write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
|
| 326 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_f32_ns.cl
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_K 16
|
| 8 |
+
#define TILESIZE_M 64
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
#define QK_K 256
|
| 11 |
+
#define K_SCALE_SIZE 12
|
| 12 |
+
|
| 13 |
+
inline void get_scale_min_k4(
|
| 14 |
+
int j,
|
| 15 |
+
global const uchar * q,
|
| 16 |
+
uchar * d,
|
| 17 |
+
uchar * m
|
| 18 |
+
) {
|
| 19 |
+
if (j < 4) {
|
| 20 |
+
*d = q[j] & 63;
|
| 21 |
+
*m = q[j+4] & 63;
|
| 22 |
+
} else {
|
| 23 |
+
*d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
|
| 24 |
+
*m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
#define dequantize_q4_k(q4, a_f16, scale, minv) \
|
| 29 |
+
a_f16.s0 = (half)((float)(q4.s0 & 0x000F) * scale - minv); \
|
| 30 |
+
a_f16.s1 = (half)((float)((q4.s0 & 0x00F0) >> 4) * scale - minv); \
|
| 31 |
+
a_f16.s2 = (half)((float)((q4.s0 & 0x0F00) >> 8) * scale - minv); \
|
| 32 |
+
a_f16.s3 = (half)((float)((q4.s0 & 0xF000) >> 12) * scale - minv); \
|
| 33 |
+
a_f16.s4 = (half)((float)(q4.s1 & 0x000F) * scale - minv); \
|
| 34 |
+
a_f16.s5 = (half)((float)((q4.s1 & 0x00F0) >> 4) * scale - minv); \
|
| 35 |
+
a_f16.s6 = (half)((float)((q4.s1 & 0x0F00) >> 8) * scale - minv); \
|
| 36 |
+
a_f16.s7 = (half)((float)((q4.s1 & 0xF000) >> 12) * scale - minv); \
|
| 37 |
+
a_f16.s8 = (half)((float)(q4.s2 & 0x000F) * scale - minv); \
|
| 38 |
+
a_f16.s9 = (half)((float)((q4.s2 & 0x00F0) >> 4) * scale - minv); \
|
| 39 |
+
a_f16.sa = (half)((float)((q4.s2 & 0x0F00) >> 8) * scale - minv); \
|
| 40 |
+
a_f16.sb = (half)((float)((q4.s2 & 0xF000) >> 12) * scale - minv); \
|
| 41 |
+
a_f16.sc = (half)((float)(q4.s3 & 0x000F) * scale - minv); \
|
| 42 |
+
a_f16.sd = (half)((float)((q4.s3 & 0x00F0) >> 4) * scale - minv); \
|
| 43 |
+
a_f16.se = (half)((float)((q4.s3 & 0x0F00) >> 8) * scale - minv); \
|
| 44 |
+
a_f16.sf = (half)((float)((q4.s3 & 0xF000) >> 12) * scale - minv); \
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
#define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
|
| 48 |
+
acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 49 |
+
acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 50 |
+
acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 51 |
+
acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 52 |
+
acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 53 |
+
acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 54 |
+
acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 55 |
+
acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 56 |
+
acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
|
| 57 |
+
acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
|
| 58 |
+
acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
|
| 59 |
+
acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
|
| 60 |
+
acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
|
| 61 |
+
acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
|
| 62 |
+
acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
|
| 63 |
+
acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
|
| 64 |
+
acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 65 |
+
acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 66 |
+
acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 67 |
+
acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 68 |
+
acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 69 |
+
acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 70 |
+
acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 71 |
+
acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 72 |
+
acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
|
| 73 |
+
acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
|
| 74 |
+
acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
|
| 75 |
+
acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
|
| 76 |
+
acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
|
| 77 |
+
acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
|
| 78 |
+
acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
|
| 79 |
+
acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
|
| 80 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 81 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 82 |
+
acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 83 |
+
acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 84 |
+
acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 85 |
+
acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 86 |
+
acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 87 |
+
acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 88 |
+
acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 89 |
+
acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 90 |
+
acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
|
| 91 |
+
acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
|
| 92 |
+
acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
|
| 93 |
+
acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
|
| 94 |
+
acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
|
| 95 |
+
acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
|
| 96 |
+
acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
|
| 97 |
+
acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
|
| 98 |
+
acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 99 |
+
acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 100 |
+
acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 101 |
+
acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 102 |
+
acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 103 |
+
acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 104 |
+
acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 105 |
+
acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 106 |
+
acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
|
| 107 |
+
acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
|
| 108 |
+
acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
|
| 109 |
+
acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
|
| 110 |
+
acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
|
| 111 |
+
acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
|
| 112 |
+
acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
|
| 113 |
+
acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
|
| 114 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 115 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 116 |
+
|
| 117 |
+
// Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
|
| 118 |
+
// accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
|
| 119 |
+
// non-skipped path is byte-identical; it just lets the caller skip empty
|
| 120 |
+
// 8-column groups at finer granularity. Uses a private half8 `acc8`.
|
| 121 |
+
#define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
|
| 122 |
+
acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 123 |
+
acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 124 |
+
acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 125 |
+
acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 126 |
+
acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 127 |
+
acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 128 |
+
acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 129 |
+
acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 130 |
+
acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 131 |
+
acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 132 |
+
acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 133 |
+
acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 134 |
+
acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 135 |
+
acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 136 |
+
acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 137 |
+
acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 138 |
+
c_reg += convert_float8(acc8); \
|
| 139 |
+
acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 140 |
+
acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 141 |
+
acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 142 |
+
acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 143 |
+
acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 144 |
+
acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 145 |
+
acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 146 |
+
acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 147 |
+
acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 148 |
+
acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 149 |
+
acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 150 |
+
acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 151 |
+
acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 152 |
+
acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 153 |
+
acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 154 |
+
acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 155 |
+
c_reg += convert_float8(acc8); \
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 159 |
+
kernel void kernel_gemm_moe_q4_k_f32_ns(
|
| 160 |
+
__read_only image1d_buffer_t src0_q,
|
| 161 |
+
__global half * src0_d,
|
| 162 |
+
__global half * src0_dm,
|
| 163 |
+
__global uchar * src0_s,
|
| 164 |
+
__read_only image1d_buffer_t src1,
|
| 165 |
+
__global uint * src2,
|
| 166 |
+
__global ushort * src2_emap,
|
| 167 |
+
__write_only image1d_buffer_t dst,
|
| 168 |
+
__global int * total_tiles,
|
| 169 |
+
uint ne00,
|
| 170 |
+
uint ne01,
|
| 171 |
+
uint is_ragged,
|
| 172 |
+
uint skip_gran
|
| 173 |
+
) {
|
| 174 |
+
uint block_id_m = get_global_id(1); // m_tile
|
| 175 |
+
uint block_id_n = get_global_id(2); // n_tile
|
| 176 |
+
|
| 177 |
+
// Boundary check
|
| 178 |
+
if (block_id_n >= total_tiles[0]) {
|
| 179 |
+
return;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
// Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
|
| 183 |
+
// lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
|
| 184 |
+
// trailing. Find the valid-token count V and round it UP to the skip granularity
|
| 185 |
+
// skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
|
| 186 |
+
// A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
|
| 187 |
+
// dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
|
| 188 |
+
uint n_active = TILESIZE_N;
|
| 189 |
+
if (is_ragged && skip_gran < TILESIZE_N) {
|
| 190 |
+
uint n_valid = TILESIZE_N;
|
| 191 |
+
for (uint _t = 0; _t < TILESIZE_N; ++_t) {
|
| 192 |
+
if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
|
| 193 |
+
}
|
| 194 |
+
n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
|
| 195 |
+
}
|
| 196 |
+
// Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
|
| 197 |
+
bool skip_g1 = (8u >= n_active);
|
| 198 |
+
bool skip_g2 = (16u >= n_active);
|
| 199 |
+
bool skip_g3 = (24u >= n_active);
|
| 200 |
+
|
| 201 |
+
__private half16 reg_a;
|
| 202 |
+
__private float32 reg_c = (float32)(0);
|
| 203 |
+
__local half4 shared_b[128];
|
| 204 |
+
|
| 205 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 206 |
+
|
| 207 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 208 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 209 |
+
|
| 210 |
+
uint sub_block_id_m = get_local_id(0);
|
| 211 |
+
uint2 b_global_offset;
|
| 212 |
+
b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
|
| 213 |
+
b_global_offset.y = b_global_offset.x + (16 * ne00);
|
| 214 |
+
uint2 b_local_offset;
|
| 215 |
+
b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
|
| 216 |
+
b_local_offset.y = b_local_offset.x + 16;
|
| 217 |
+
|
| 218 |
+
uint num_superblocks = ne00 / QK_K;
|
| 219 |
+
uint scales_per_row = num_superblocks * K_SCALE_SIZE;
|
| 220 |
+
uint row_idx = row + get_global_id(0);
|
| 221 |
+
|
| 222 |
+
// Loop along K axis, 32 elements per iteration (one sub-block), divided into 2 halves of 16
|
| 223 |
+
for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
|
| 224 |
+
uint sub = step / 32;
|
| 225 |
+
uint sb = sub / 8;
|
| 226 |
+
uint j = sub % 8;
|
| 227 |
+
|
| 228 |
+
// Load d and dm for super-block
|
| 229 |
+
uint d_offset = row + sb * ne01 + expert_id * num_superblocks * ne01 + get_global_id(0);
|
| 230 |
+
half d_val = src0_d[d_offset];
|
| 231 |
+
half dm_val = src0_dm[d_offset];
|
| 232 |
+
|
| 233 |
+
// Load sub-block scale and min
|
| 234 |
+
global const uchar * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * K_SCALE_SIZE;
|
| 235 |
+
uchar sv, mn;
|
| 236 |
+
get_scale_min_k4(j, sc, &sv, &mn);
|
| 237 |
+
|
| 238 |
+
float scale = (float)d_val * (float)sv;
|
| 239 |
+
float minv = (float)dm_val * (float)mn;
|
| 240 |
+
|
| 241 |
+
// First sub-block (16 elements)
|
| 242 |
+
uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 243 |
+
uint b_sub_offset = col * ne00 + step;
|
| 244 |
+
|
| 245 |
+
// Load 16 q (64-bits) in transposed layout
|
| 246 |
+
uint2 q4x16;
|
| 247 |
+
q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 248 |
+
q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 249 |
+
|
| 250 |
+
// Load 16x32 floats from matrix B
|
| 251 |
+
float8 bx8_f32;
|
| 252 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 253 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 254 |
+
half8 bx8_f16 = convert_half8(bx8_f32);
|
| 255 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 256 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 257 |
+
|
| 258 |
+
// Dequantization
|
| 259 |
+
dequantize_q4_k(as_ushort4(q4x16), reg_a, scale, minv);
|
| 260 |
+
|
| 261 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 262 |
+
|
| 263 |
+
half8 acc8;
|
| 264 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 265 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 266 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 267 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 268 |
+
|
| 269 |
+
// Second half (next 16 elements, same sub-block scale)
|
| 270 |
+
uint half_step = step + TILESIZE_K;
|
| 271 |
+
q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 272 |
+
b_sub_offset = col * ne00 + half_step;
|
| 273 |
+
|
| 274 |
+
q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 275 |
+
q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 276 |
+
|
| 277 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 278 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 279 |
+
bx8_f16 = convert_half8(bx8_f32);
|
| 280 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 281 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 282 |
+
|
| 283 |
+
dequantize_q4_k(as_ushort4(q4x16), reg_a, scale, minv);
|
| 284 |
+
|
| 285 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 286 |
+
|
| 287 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 288 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 289 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 290 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
|
| 294 |
+
return;
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
// Load post router and share in LM
|
| 298 |
+
__local uint out_idx[TILESIZE_N];
|
| 299 |
+
|
| 300 |
+
if (get_local_id(0) < TILESIZE_N) {
|
| 301 |
+
uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
|
| 302 |
+
if (idx == 0xFFFFFFFF) {
|
| 303 |
+
idx = src2[block_id_n * TILESIZE_N + 0];
|
| 304 |
+
}
|
| 305 |
+
out_idx[get_local_id(0)] = idx * ne01;
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 309 |
+
|
| 310 |
+
// Scatter results back to original position in output grid
|
| 311 |
+
uint m_offset = row + get_local_id(0);
|
| 312 |
+
|
| 313 |
+
write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
|
| 314 |
+
write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
|
| 315 |
+
write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
|
| 316 |
+
write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
|
| 317 |
+
write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
|
| 318 |
+
write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
|
| 319 |
+
write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
|
| 320 |
+
write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
|
| 321 |
+
write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
|
| 322 |
+
write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
|
| 323 |
+
write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
|
| 324 |
+
write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
|
| 325 |
+
write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
|
| 326 |
+
write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
|
| 327 |
+
write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
|
| 328 |
+
write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
|
| 329 |
+
write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
|
| 330 |
+
write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
|
| 331 |
+
write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
|
| 332 |
+
write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
|
| 333 |
+
write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
|
| 334 |
+
write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
|
| 335 |
+
write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
|
| 336 |
+
write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
|
| 337 |
+
write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
|
| 338 |
+
write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
|
| 339 |
+
write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
|
| 340 |
+
write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
|
| 341 |
+
write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
|
| 342 |
+
write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
|
| 343 |
+
write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
|
| 344 |
+
|
| 345 |
+
// Store zero padding parts to the index of first output in tile
|
| 346 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 347 |
+
write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
|
| 348 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q4_k_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
// q4_K subblock (32 elems): w_i = scale*q_i - minv, q_i in [0,15], scale =
|
| 8 |
+
// d_super*sv6, minv = dmin_super*mn6. With activation block (a_d, a_s, qa[32]):
|
| 9 |
+
// Sum_i w_i * a_i = scale * a_d * dp4a(q, qa) - minv * a_s
|
| 10 |
+
// where a_s = a_d * Sum(qa) (the q8_1 "s" field)
|
| 11 |
+
|
| 12 |
+
#define TILESIZE_M 64
|
| 13 |
+
#define TILESIZE_N 32
|
| 14 |
+
#define QK_K 256
|
| 15 |
+
#define K_SCALE_SIZE 12
|
| 16 |
+
|
| 17 |
+
inline void get_scale_min_k4(
|
| 18 |
+
int j,
|
| 19 |
+
global const uchar * q,
|
| 20 |
+
uchar * d,
|
| 21 |
+
uchar * m
|
| 22 |
+
) {
|
| 23 |
+
if (j < 4) {
|
| 24 |
+
*d = q[j] & 63;
|
| 25 |
+
*m = q[j+4] & 63;
|
| 26 |
+
} else {
|
| 27 |
+
*d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
|
| 28 |
+
*m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
// Expand the 4 nibbles held in the low 16 bits of `u` into 4 bytes (one nibble
|
| 33 |
+
// per byte, value 0..15), packed for the int8 dp4a.
|
| 34 |
+
#define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
|
| 35 |
+
(((uint)((u) & 0x00F0u)) << 4) | \
|
| 36 |
+
(((uint)((u) & 0x0F00u)) << 8) | \
|
| 37 |
+
(((uint)((u) & 0xF000u)) << 12) )
|
| 38 |
+
|
| 39 |
+
// One token's dp4a dot (8 uints = 32 K elems) + q4_K scale/min epilogue into acc[t].
|
| 40 |
+
#define MOE_Q4K_DP4A_T(t) do { \
|
| 41 |
+
int raw = 0; \
|
| 42 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[0], sh_qa[t][0], raw); \
|
| 43 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[1], sh_qa[t][1], raw); \
|
| 44 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[2], sh_qa[t][2], raw); \
|
| 45 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[3], sh_qa[t][3], raw); \
|
| 46 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[4], sh_qa[t][4], raw); \
|
| 47 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[5], sh_qa[t][5], raw); \
|
| 48 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[6], sh_qa[t][6], raw); \
|
| 49 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw[7], sh_qa[t][7], raw); \
|
| 50 |
+
acc[t] += scale * (float)sh_d[t] * (float)raw - minv * (float)sh_s[t]; \
|
| 51 |
+
} while (0)
|
| 52 |
+
|
| 53 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 54 |
+
kernel void kernel_gemm_moe_q4_k_q8_1_dp4a(
|
| 55 |
+
__read_only image1d_buffer_t src0_q, // q4_K weights (transposed, packed nibbles)
|
| 56 |
+
__global half * src0_d, // per-superblock scale
|
| 57 |
+
__global half * src0_dm, // per-superblock min
|
| 58 |
+
__global uchar * src0_s, // 6-bit scale/min codes
|
| 59 |
+
__global uint * src1_qa, // q8_1 activations: int8 quants (as uint, 4/elem)
|
| 60 |
+
__global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
|
| 61 |
+
__global half * src1_sa, // q8_1 per-block sum*d [tok_slot * ne00/32]
|
| 62 |
+
__global uint * src2, // post-router (orig out positions)
|
| 63 |
+
__global ushort * src2_emap,// tile -> expert id
|
| 64 |
+
__write_only image1d_buffer_t dst,
|
| 65 |
+
__global int * total_tiles,
|
| 66 |
+
uint ne00,
|
| 67 |
+
uint ne01,
|
| 68 |
+
int is_ragged // 1: compute only real tokens per tile
|
| 69 |
+
) {
|
| 70 |
+
const uint block_id_m = get_global_id(1); // m_tile
|
| 71 |
+
const uint block_id_n = get_global_id(2); // n_tile
|
| 72 |
+
|
| 73 |
+
if (block_id_n >= total_tiles[0]) {
|
| 74 |
+
return;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
const uint lid = get_local_id(0); // 0..63, == this WI's output row in the M-tile
|
| 78 |
+
|
| 79 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 80 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 81 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 82 |
+
|
| 83 |
+
const uint num_superblocks = ne00 / QK_K;
|
| 84 |
+
const uint scales_per_row = num_superblocks * K_SCALE_SIZE;
|
| 85 |
+
const uint row_idx = row + lid;
|
| 86 |
+
|
| 87 |
+
const uint ne00_u = ne00 >> 2; // ne00 in uint (int8x4) units
|
| 88 |
+
const uint ne00_b = ne00 >> 5; // blocks-of-32 per token
|
| 89 |
+
|
| 90 |
+
__local uint sh_qa[TILESIZE_N][8]; // 32 tokens x 8 uints (32 int8) = 1 KiB
|
| 91 |
+
__local half sh_d[TILESIZE_N];
|
| 92 |
+
__local half sh_s[TILESIZE_N];
|
| 93 |
+
|
| 94 |
+
// Real token count for this tile
|
| 95 |
+
__local uint sh_src2[TILESIZE_N];
|
| 96 |
+
__local int sh_nreal;
|
| 97 |
+
if (lid < TILESIZE_N) {
|
| 98 |
+
sh_src2[lid] = src2[col + lid];
|
| 99 |
+
}
|
| 100 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 101 |
+
if (lid == 0) {
|
| 102 |
+
int nr = TILESIZE_N;
|
| 103 |
+
if (is_ragged) {
|
| 104 |
+
nr = 0;
|
| 105 |
+
#pragma unroll
|
| 106 |
+
for (int t = 0; t < TILESIZE_N; ++t) {
|
| 107 |
+
if (sh_src2[t] != 0xFFFFFFFFu) ++nr;
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
sh_nreal = nr;
|
| 111 |
+
}
|
| 112 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 113 |
+
const int n_real = sh_nreal;
|
| 114 |
+
|
| 115 |
+
float acc[TILESIZE_N];
|
| 116 |
+
#pragma unroll
|
| 117 |
+
for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
|
| 118 |
+
|
| 119 |
+
for (uint step = 0; step < ne00; step += 32) {
|
| 120 |
+
const uint sub = step >> 5; // subblock index along K
|
| 121 |
+
const uint sb = sub >> 3; // superblock index
|
| 122 |
+
const uint j = sub & 7; // subblock within superblock
|
| 123 |
+
|
| 124 |
+
// --- weight scale / min for this WI's row, this subblock ---
|
| 125 |
+
const uint d_offset = row + sb * ne01 + expert_id * num_superblocks * ne01 + lid;
|
| 126 |
+
const float d_val = (float)src0_d[d_offset];
|
| 127 |
+
const float dm_val = (float)src0_dm[d_offset];
|
| 128 |
+
|
| 129 |
+
global const uchar * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * K_SCALE_SIZE;
|
| 130 |
+
uchar sv, mn;
|
| 131 |
+
get_scale_min_k4(j, sc, &sv, &mn);
|
| 132 |
+
const float scale = d_val * (float)sv;
|
| 133 |
+
const float minv = dm_val * (float)mn;
|
| 134 |
+
|
| 135 |
+
// --- repack this WI's 32 weight nibbles into 8 dp4a uints ---
|
| 136 |
+
const uint qoff0 = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 137 |
+
const uint qoff1 = row + ((ne01 * (step + 16)) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 138 |
+
const uint r0 = read_imageui(src0_q, qoff0 + lid).x;
|
| 139 |
+
const uint r1 = read_imageui(src0_q, qoff0 + lid + ne01).x;
|
| 140 |
+
const uint r2 = read_imageui(src0_q, qoff1 + lid).x;
|
| 141 |
+
const uint r3 = read_imageui(src0_q, qoff1 + lid + ne01).x;
|
| 142 |
+
uint qw[8];
|
| 143 |
+
qw[0] = EXP4(r0); qw[1] = EXP4(r0 >> 16);
|
| 144 |
+
qw[2] = EXP4(r1); qw[3] = EXP4(r1 >> 16);
|
| 145 |
+
qw[4] = EXP4(r2); qw[5] = EXP4(r2 >> 16);
|
| 146 |
+
qw[6] = EXP4(r3); qw[7] = EXP4(r3 >> 16);
|
| 147 |
+
|
| 148 |
+
// --- cooperatively stage the n_real-token x 32-K int8 activations to LDS ---
|
| 149 |
+
const uint stage_lim = (uint)n_real * 8;
|
| 150 |
+
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
| 151 |
+
const uint t = idx >> 3;
|
| 152 |
+
const uint u = idx & 7;
|
| 153 |
+
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
| 154 |
+
}
|
| 155 |
+
if (lid < (uint)n_real) {
|
| 156 |
+
sh_d[lid] = src1_da[(col + lid) * ne00_b + sub];
|
| 157 |
+
sh_s[lid] = src1_sa[(col + lid) * ne00_b + sub];
|
| 158 |
+
}
|
| 159 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 160 |
+
|
| 161 |
+
// dp4a - each real token sum over 8 uints (32 K), then scale/min
|
| 162 |
+
// Full tiles keep the fully-unrolled 32-wide loop;
|
| 163 |
+
// partial tiles run only n_real (saves the padded-slot dp4a + staging).
|
| 164 |
+
if (n_real == TILESIZE_N) {
|
| 165 |
+
#pragma unroll
|
| 166 |
+
for (int t = 0; t < TILESIZE_N; ++t) { MOE_Q4K_DP4A_T(t); }
|
| 167 |
+
} else {
|
| 168 |
+
#pragma unroll 4
|
| 169 |
+
for (int t = 0; t < n_real; ++t) { MOE_Q4K_DP4A_T(t); }
|
| 170 |
+
}
|
| 171 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
if (row_idx >= ne01) {
|
| 175 |
+
return;
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
// scatter results to original output rows
|
| 179 |
+
__local uint out_idx[TILESIZE_N];
|
| 180 |
+
if (lid < TILESIZE_N) {
|
| 181 |
+
uint idx = sh_src2[lid];
|
| 182 |
+
if (idx == 0xFFFFFFFF) {
|
| 183 |
+
idx = sh_src2[0];
|
| 184 |
+
}
|
| 185 |
+
out_idx[lid] = idx * ne01;
|
| 186 |
+
}
|
| 187 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 188 |
+
|
| 189 |
+
const uint m_offset = row + lid;
|
| 190 |
+
if (n_real == TILESIZE_N) {
|
| 191 |
+
#pragma unroll
|
| 192 |
+
for (int t = 1; t < TILESIZE_N; ++t) {
|
| 193 |
+
write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 194 |
+
}
|
| 195 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 196 |
+
write_imagef(dst, out_idx[0] + m_offset, acc[0]);
|
| 197 |
+
} else {
|
| 198 |
+
for (int t = 0; t < n_real; ++t) {
|
| 199 |
+
write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_0_f32_ns.cl
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_K 16
|
| 8 |
+
#define TILESIZE_M 64
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
#define dequantize_q5_0(qs5x16, qh5x16, a_f16, scale) \
|
| 13 |
+
a_f16.s0 = (half)((( qs5x16.s0 & 0x000F) | (( qh5x16.s0 & 0x01) << 4)) - 16) * scale; \
|
| 14 |
+
a_f16.s1 = (half)((((qs5x16.s0 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 1) & 0x01) << 4)) - 16) * scale; \
|
| 15 |
+
a_f16.s2 = (half)((((qs5x16.s0 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 2) & 0x01) << 4)) - 16) * scale; \
|
| 16 |
+
a_f16.s3 = (half)((((qs5x16.s0 & 0xF000) >> 12) | (((qh5x16.s0 >> 3) & 0x01) << 4)) - 16) * scale; \
|
| 17 |
+
a_f16.s4 = (half)((( qs5x16.s1 & 0x000F) | (((qh5x16.s0 >> 4) & 0x01) << 4)) - 16) * scale; \
|
| 18 |
+
a_f16.s5 = (half)((((qs5x16.s1 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 5) & 0x01) << 4)) - 16) * scale; \
|
| 19 |
+
a_f16.s6 = (half)((((qs5x16.s1 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 6) & 0x01) << 4)) - 16) * scale; \
|
| 20 |
+
a_f16.s7 = (half)((((qs5x16.s1 & 0xF000) >> 12) | (((qh5x16.s0 >> 7) & 0x01) << 4)) - 16) * scale; \
|
| 21 |
+
a_f16.s8 = (half)((( qs5x16.s2 & 0x000F) | (( qh5x16.s1 & 0x01) << 4)) - 16) * scale; \
|
| 22 |
+
a_f16.s9 = (half)((((qs5x16.s2 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 1) & 0x01) << 4)) - 16) * scale; \
|
| 23 |
+
a_f16.sa = (half)((((qs5x16.s2 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 2) & 0x01) << 4)) - 16) * scale; \
|
| 24 |
+
a_f16.sb = (half)((((qs5x16.s2 & 0xF000) >> 12) | (((qh5x16.s1 >> 3) & 0x01) << 4)) - 16) * scale; \
|
| 25 |
+
a_f16.sc = (half)((( qs5x16.s3 & 0x000F) | (((qh5x16.s1 >> 4) & 0x01) << 4)) - 16) * scale; \
|
| 26 |
+
a_f16.sd = (half)((((qs5x16.s3 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 5) & 0x01) << 4)) - 16) * scale; \
|
| 27 |
+
a_f16.se = (half)((((qs5x16.s3 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 6) & 0x01) << 4)) - 16) * scale; \
|
| 28 |
+
a_f16.sf = (half)((((qs5x16.s3 & 0xF000) >> 12) | (((qh5x16.s1 >> 7) & 0x01) << 4)) - 16) * scale; \
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
#define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
|
| 32 |
+
acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 33 |
+
acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 34 |
+
acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 35 |
+
acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 36 |
+
acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 37 |
+
acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 38 |
+
acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 39 |
+
acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 40 |
+
acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
|
| 41 |
+
acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
|
| 42 |
+
acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
|
| 43 |
+
acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
|
| 44 |
+
acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
|
| 45 |
+
acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
|
| 46 |
+
acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
|
| 47 |
+
acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
|
| 48 |
+
acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 49 |
+
acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 50 |
+
acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 51 |
+
acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 52 |
+
acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 53 |
+
acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 54 |
+
acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 55 |
+
acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 56 |
+
acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
|
| 57 |
+
acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
|
| 58 |
+
acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
|
| 59 |
+
acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
|
| 60 |
+
acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
|
| 61 |
+
acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
|
| 62 |
+
acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
|
| 63 |
+
acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
|
| 64 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 65 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 66 |
+
acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 67 |
+
acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 68 |
+
acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 69 |
+
acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 70 |
+
acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 71 |
+
acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 72 |
+
acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 73 |
+
acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 74 |
+
acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
|
| 75 |
+
acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
|
| 76 |
+
acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
|
| 77 |
+
acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
|
| 78 |
+
acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
|
| 79 |
+
acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
|
| 80 |
+
acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
|
| 81 |
+
acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
|
| 82 |
+
acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 83 |
+
acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 84 |
+
acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 85 |
+
acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 86 |
+
acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 87 |
+
acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 88 |
+
acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 89 |
+
acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 90 |
+
acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
|
| 91 |
+
acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
|
| 92 |
+
acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
|
| 93 |
+
acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
|
| 94 |
+
acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
|
| 95 |
+
acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
|
| 96 |
+
acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
|
| 97 |
+
acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
|
| 98 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 99 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 100 |
+
|
| 101 |
+
// Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
|
| 102 |
+
// accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
|
| 103 |
+
// non-skipped path is byte-identical; it just lets the caller skip empty
|
| 104 |
+
// 8-column groups at finer granularity. Uses a private half8 `acc8`.
|
| 105 |
+
#define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
|
| 106 |
+
acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 107 |
+
acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 108 |
+
acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 109 |
+
acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 110 |
+
acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 111 |
+
acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 112 |
+
acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 113 |
+
acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 114 |
+
acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 115 |
+
acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 116 |
+
acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 117 |
+
acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 118 |
+
acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 119 |
+
acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 120 |
+
acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 121 |
+
acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 122 |
+
c_reg += convert_float8(acc8); \
|
| 123 |
+
acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 124 |
+
acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 125 |
+
acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 126 |
+
acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 127 |
+
acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 128 |
+
acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 129 |
+
acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 130 |
+
acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 131 |
+
acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 132 |
+
acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 133 |
+
acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 134 |
+
acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 135 |
+
acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 136 |
+
acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 137 |
+
acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 138 |
+
acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 139 |
+
c_reg += convert_float8(acc8); \
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
__attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
|
| 143 |
+
kernel void kernel_gemm_moe_q5_0_f32_ns(
|
| 144 |
+
__read_only image1d_buffer_t src0_qs,
|
| 145 |
+
__global uint * src0_qh,
|
| 146 |
+
__global half * src0_d,
|
| 147 |
+
__read_only image1d_buffer_t src1,
|
| 148 |
+
__global uint * src2,
|
| 149 |
+
__global ushort * src2_emap,
|
| 150 |
+
__write_only image1d_buffer_t dst,
|
| 151 |
+
__global int * total_tiles,
|
| 152 |
+
uint ne00,
|
| 153 |
+
uint ne01,
|
| 154 |
+
uint is_ragged,
|
| 155 |
+
uint skip_gran
|
| 156 |
+
) {
|
| 157 |
+
uint block_id_m = get_global_id(1); // m_tile
|
| 158 |
+
uint block_id_n = get_global_id(2); // n_tile
|
| 159 |
+
|
| 160 |
+
// Boundary check
|
| 161 |
+
if (block_id_n >= total_tiles[0]) {
|
| 162 |
+
return;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
// Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
|
| 166 |
+
// padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
|
| 167 |
+
// the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
|
| 168 |
+
// Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
|
| 169 |
+
// lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
|
| 170 |
+
// trailing. Find the valid-token count V and round it UP to the skip granularity
|
| 171 |
+
// skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
|
| 172 |
+
// A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
|
| 173 |
+
// dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
|
| 174 |
+
uint n_active = TILESIZE_N;
|
| 175 |
+
if (is_ragged && skip_gran < TILESIZE_N) {
|
| 176 |
+
uint n_valid = TILESIZE_N;
|
| 177 |
+
for (uint _t = 0; _t < TILESIZE_N; ++_t) {
|
| 178 |
+
if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
|
| 179 |
+
}
|
| 180 |
+
n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
|
| 181 |
+
}
|
| 182 |
+
// Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
|
| 183 |
+
bool skip_g1 = (8u >= n_active);
|
| 184 |
+
bool skip_g2 = (16u >= n_active);
|
| 185 |
+
bool skip_g3 = (24u >= n_active);
|
| 186 |
+
|
| 187 |
+
__private half16 reg_a;
|
| 188 |
+
__private float32 reg_c = (float32)(0);
|
| 189 |
+
__local half4 shared_b[128];
|
| 190 |
+
|
| 191 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 192 |
+
|
| 193 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 194 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 195 |
+
|
| 196 |
+
uint sub_block_id_m = get_local_id(0);
|
| 197 |
+
uint2 b_global_offset;
|
| 198 |
+
b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
|
| 199 |
+
b_global_offset.y = b_global_offset.x + (16 * ne00);
|
| 200 |
+
uint2 b_local_offset;
|
| 201 |
+
b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
|
| 202 |
+
b_local_offset.y = b_local_offset.x + 16;
|
| 203 |
+
|
| 204 |
+
// Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
|
| 205 |
+
for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
|
| 206 |
+
// First sub-block
|
| 207 |
+
uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 208 |
+
uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
|
| 209 |
+
uint b_sub_offset = col * ne00 + step;
|
| 210 |
+
|
| 211 |
+
// Load scale for current Q5_0 block
|
| 212 |
+
uint blk_offset = s_sub_offset + get_global_id(0);
|
| 213 |
+
half s = src0_d[blk_offset];
|
| 214 |
+
|
| 215 |
+
// Load 32 qh (5-th bit of each Q5) for the entire block
|
| 216 |
+
uchar4 qhx32 = as_uchar4(src0_qh[blk_offset]);
|
| 217 |
+
|
| 218 |
+
// Load 16 qs (half block) in transposed layout
|
| 219 |
+
uint2 qsx16;
|
| 220 |
+
qsx16.x = read_imageui(src0_qs, q_sub_offset + sub_block_id_m).x;
|
| 221 |
+
qsx16.y = read_imageui(src0_qs, q_sub_offset + sub_block_id_m + ne01).x;
|
| 222 |
+
|
| 223 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 224 |
+
float8 bx8_f32;
|
| 225 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 226 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 227 |
+
// Convert to half and store to LM to share within the subgroup
|
| 228 |
+
half8 bx8_f16 = convert_half8(bx8_f32);
|
| 229 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 230 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 231 |
+
|
| 232 |
+
// Dequantization
|
| 233 |
+
dequantize_q5_0(as_ushort4(qsx16), qhx32.lo, reg_a, s);
|
| 234 |
+
|
| 235 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 236 |
+
|
| 237 |
+
// 32 16x16 fp16 dot product with 8 elements reduction for better precision
|
| 238 |
+
half8 acc8;
|
| 239 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 240 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 241 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 242 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 243 |
+
|
| 244 |
+
// Repeat for second sub-block
|
| 245 |
+
uint half_step = step + TILESIZE_K;
|
| 246 |
+
q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 247 |
+
b_sub_offset = col * ne00 + half_step;
|
| 248 |
+
|
| 249 |
+
// Load next 16 qs in transposed layout
|
| 250 |
+
qsx16.x = read_imageui(src0_qs, q_sub_offset + sub_block_id_m).x;
|
| 251 |
+
qsx16.y = read_imageui(src0_qs, q_sub_offset + sub_block_id_m + ne01).x;
|
| 252 |
+
|
| 253 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 254 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 255 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 256 |
+
// Convert to half and store to LM to share within the subgroup
|
| 257 |
+
bx8_f16 = convert_half8(bx8_f32);
|
| 258 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 259 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 260 |
+
|
| 261 |
+
// Dequantization
|
| 262 |
+
dequantize_q5_0(as_ushort4(qsx16), qhx32.hi, reg_a, s);
|
| 263 |
+
|
| 264 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 265 |
+
|
| 266 |
+
// 32 16x16 fp16 dot product with 3-levels reduction for better precision
|
| 267 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 268 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 269 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 270 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
|
| 274 |
+
return;
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
// Load poster router and share in LM
|
| 278 |
+
__local uint out_idx[TILESIZE_N];
|
| 279 |
+
|
| 280 |
+
if (get_local_id(0) < TILESIZE_N) {
|
| 281 |
+
uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
|
| 282 |
+
if (idx == 0xFFFFFFFF) {
|
| 283 |
+
idx = src2[block_id_n * TILESIZE_N + 0];
|
| 284 |
+
}
|
| 285 |
+
out_idx[get_local_id(0)] = idx * ne01;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 289 |
+
|
| 290 |
+
// Scatter results back to original position in output grid
|
| 291 |
+
uint m_offset = row + get_local_id(0);
|
| 292 |
+
|
| 293 |
+
write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
|
| 294 |
+
write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
|
| 295 |
+
write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
|
| 296 |
+
write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
|
| 297 |
+
write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
|
| 298 |
+
write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
|
| 299 |
+
write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
|
| 300 |
+
write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
|
| 301 |
+
write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
|
| 302 |
+
write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
|
| 303 |
+
write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
|
| 304 |
+
write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
|
| 305 |
+
write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
|
| 306 |
+
write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
|
| 307 |
+
write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
|
| 308 |
+
write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
|
| 309 |
+
write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
|
| 310 |
+
write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
|
| 311 |
+
write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
|
| 312 |
+
write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
|
| 313 |
+
write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
|
| 314 |
+
write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
|
| 315 |
+
write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
|
| 316 |
+
write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
|
| 317 |
+
write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
|
| 318 |
+
write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
|
| 319 |
+
write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
|
| 320 |
+
write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
|
| 321 |
+
write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
|
| 322 |
+
write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
|
| 323 |
+
write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
|
| 324 |
+
|
| 325 |
+
// Store zero padding parts to the index of first output in tile, override correct result in the end
|
| 326 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 327 |
+
write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
|
| 328 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_1_f32_ns.cl
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_K 16
|
| 8 |
+
#define TILESIZE_M 64
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
#define dequantize_q5_1(qs5x16, qh5x16, a_f16, scale, m) \
|
| 13 |
+
a_f16.s0 = (half)((( qs5x16.s0 & 0x000F) | (( qh5x16.s0 & 0x01) << 4)) * scale + m); \
|
| 14 |
+
a_f16.s1 = (half)((((qs5x16.s0 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 1) & 0x01) << 4)) * scale + m); \
|
| 15 |
+
a_f16.s2 = (half)((((qs5x16.s0 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 2) & 0x01) << 4)) * scale + m); \
|
| 16 |
+
a_f16.s3 = (half)((((qs5x16.s0 & 0xF000) >> 12) | (((qh5x16.s0 >> 3) & 0x01) << 4)) * scale + m); \
|
| 17 |
+
a_f16.s4 = (half)((( qs5x16.s1 & 0x000F) | (((qh5x16.s0 >> 4) & 0x01) << 4)) * scale + m); \
|
| 18 |
+
a_f16.s5 = (half)((((qs5x16.s1 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 5) & 0x01) << 4)) * scale + m); \
|
| 19 |
+
a_f16.s6 = (half)((((qs5x16.s1 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 6) & 0x01) << 4)) * scale + m); \
|
| 20 |
+
a_f16.s7 = (half)((((qs5x16.s1 & 0xF000) >> 12) | (((qh5x16.s0 >> 7) & 0x01) << 4)) * scale + m); \
|
| 21 |
+
a_f16.s8 = (half)((( qs5x16.s2 & 0x000F) | (( qh5x16.s1 & 0x01) << 4)) * scale + m); \
|
| 22 |
+
a_f16.s9 = (half)((((qs5x16.s2 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 1) & 0x01) << 4)) * scale + m); \
|
| 23 |
+
a_f16.sa = (half)((((qs5x16.s2 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 2) & 0x01) << 4)) * scale + m); \
|
| 24 |
+
a_f16.sb = (half)((((qs5x16.s2 & 0xF000) >> 12) | (((qh5x16.s1 >> 3) & 0x01) << 4)) * scale + m); \
|
| 25 |
+
a_f16.sc = (half)((( qs5x16.s3 & 0x000F) | (((qh5x16.s1 >> 4) & 0x01) << 4)) * scale + m); \
|
| 26 |
+
a_f16.sd = (half)((((qs5x16.s3 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 5) & 0x01) << 4)) * scale + m); \
|
| 27 |
+
a_f16.se = (half)((((qs5x16.s3 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 6) & 0x01) << 4)) * scale + m); \
|
| 28 |
+
a_f16.sf = (half)((((qs5x16.s3 & 0xF000) >> 12) | (((qh5x16.s1 >> 7) & 0x01) << 4)) * scale + m); \
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
#define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
|
| 32 |
+
acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 33 |
+
acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 34 |
+
acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 35 |
+
acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 36 |
+
acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 37 |
+
acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 38 |
+
acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 39 |
+
acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 40 |
+
acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
|
| 41 |
+
acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
|
| 42 |
+
acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
|
| 43 |
+
acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
|
| 44 |
+
acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
|
| 45 |
+
acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
|
| 46 |
+
acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
|
| 47 |
+
acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
|
| 48 |
+
acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 49 |
+
acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 50 |
+
acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 51 |
+
acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 52 |
+
acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 53 |
+
acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 54 |
+
acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 55 |
+
acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 56 |
+
acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
|
| 57 |
+
acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
|
| 58 |
+
acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
|
| 59 |
+
acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
|
| 60 |
+
acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
|
| 61 |
+
acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
|
| 62 |
+
acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
|
| 63 |
+
acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
|
| 64 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 65 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 66 |
+
acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 67 |
+
acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 68 |
+
acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 69 |
+
acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 70 |
+
acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 71 |
+
acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 72 |
+
acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 73 |
+
acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 74 |
+
acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
|
| 75 |
+
acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
|
| 76 |
+
acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
|
| 77 |
+
acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
|
| 78 |
+
acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
|
| 79 |
+
acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
|
| 80 |
+
acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
|
| 81 |
+
acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
|
| 82 |
+
acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 83 |
+
acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 84 |
+
acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 85 |
+
acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 86 |
+
acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 87 |
+
acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 88 |
+
acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 89 |
+
acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 90 |
+
acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
|
| 91 |
+
acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
|
| 92 |
+
acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
|
| 93 |
+
acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
|
| 94 |
+
acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
|
| 95 |
+
acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
|
| 96 |
+
acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
|
| 97 |
+
acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
|
| 98 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 99 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 100 |
+
|
| 101 |
+
// Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
|
| 102 |
+
// accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
|
| 103 |
+
// non-skipped path is byte-identical; it just lets the caller skip empty
|
| 104 |
+
// 8-column groups at finer granularity. Uses a private half8 `acc8`.
|
| 105 |
+
#define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
|
| 106 |
+
acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 107 |
+
acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 108 |
+
acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 109 |
+
acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 110 |
+
acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 111 |
+
acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 112 |
+
acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 113 |
+
acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 114 |
+
acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 115 |
+
acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 116 |
+
acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 117 |
+
acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 118 |
+
acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 119 |
+
acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 120 |
+
acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 121 |
+
acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 122 |
+
c_reg += convert_float8(acc8); \
|
| 123 |
+
acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 124 |
+
acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 125 |
+
acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 126 |
+
acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 127 |
+
acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 128 |
+
acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 129 |
+
acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 130 |
+
acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 131 |
+
acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 132 |
+
acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 133 |
+
acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 134 |
+
acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 135 |
+
acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 136 |
+
acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 137 |
+
acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 138 |
+
acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 139 |
+
c_reg += convert_float8(acc8); \
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
__attribute__((qcom_wave_pair_mode(1))) // 1=force single 2=force pair
|
| 143 |
+
kernel void kernel_gemm_moe_q5_1_f32_ns(
|
| 144 |
+
__read_only image1d_buffer_t src0_qs,
|
| 145 |
+
__global uint * src0_qh,
|
| 146 |
+
__global half * src0_d,
|
| 147 |
+
__global half * src0_m,
|
| 148 |
+
__read_only image1d_buffer_t src1,
|
| 149 |
+
__global uint * src2,
|
| 150 |
+
__global ushort * src2_emap,
|
| 151 |
+
__write_only image1d_buffer_t dst,
|
| 152 |
+
__global int * total_tiles,
|
| 153 |
+
uint ne00,
|
| 154 |
+
uint ne01,
|
| 155 |
+
uint is_ragged,
|
| 156 |
+
uint skip_gran
|
| 157 |
+
) {
|
| 158 |
+
uint block_id_m = get_global_id(1); // m_tile
|
| 159 |
+
uint block_id_n = get_global_id(2); // n_tile
|
| 160 |
+
|
| 161 |
+
// Boundary check
|
| 162 |
+
if (block_id_n >= total_tiles[0]) {
|
| 163 |
+
return;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
// Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
|
| 167 |
+
// padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
|
| 168 |
+
// the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
|
| 169 |
+
// Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
|
| 170 |
+
// lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
|
| 171 |
+
// trailing. Find the valid-token count V and round it UP to the skip granularity
|
| 172 |
+
// skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
|
| 173 |
+
// A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
|
| 174 |
+
// dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
|
| 175 |
+
uint n_active = TILESIZE_N;
|
| 176 |
+
if (is_ragged && skip_gran < TILESIZE_N) {
|
| 177 |
+
uint n_valid = TILESIZE_N;
|
| 178 |
+
for (uint _t = 0; _t < TILESIZE_N; ++_t) {
|
| 179 |
+
if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
|
| 180 |
+
}
|
| 181 |
+
n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
|
| 182 |
+
}
|
| 183 |
+
// Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
|
| 184 |
+
bool skip_g1 = (8u >= n_active);
|
| 185 |
+
bool skip_g2 = (16u >= n_active);
|
| 186 |
+
bool skip_g3 = (24u >= n_active);
|
| 187 |
+
|
| 188 |
+
__private half16 reg_a;
|
| 189 |
+
__private float32 reg_c = (float32)(0);
|
| 190 |
+
__local half4 shared_b[128];
|
| 191 |
+
|
| 192 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 193 |
+
|
| 194 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 195 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 196 |
+
|
| 197 |
+
uint sub_block_id_m = get_local_id(0);
|
| 198 |
+
uint2 b_global_offset;
|
| 199 |
+
b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
|
| 200 |
+
b_global_offset.y = b_global_offset.x + (16 * ne00);
|
| 201 |
+
uint2 b_local_offset;
|
| 202 |
+
b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
|
| 203 |
+
b_local_offset.y = b_local_offset.x + 16;
|
| 204 |
+
|
| 205 |
+
// Loop along K axis, 32 elements (one block) for each iteration, divided into 2 sub-blocks
|
| 206 |
+
for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
|
| 207 |
+
// First sub-block
|
| 208 |
+
uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 209 |
+
uint s_sub_offset = row + ((ne01 * step) >> 5) + ((expert_id * ne00 * ne01) >> 5);
|
| 210 |
+
uint b_sub_offset = col * ne00 + step;
|
| 211 |
+
|
| 212 |
+
// Load scale and m for current Q5_1 block
|
| 213 |
+
uint blk_offset = s_sub_offset + get_global_id(0);
|
| 214 |
+
half s = src0_d[blk_offset];
|
| 215 |
+
half m = src0_m[blk_offset];
|
| 216 |
+
|
| 217 |
+
// Load 32 qh (5-th bit of each Q5) for the entire block
|
| 218 |
+
uchar4 qhx32 = as_uchar4(src0_qh[blk_offset]);
|
| 219 |
+
|
| 220 |
+
// Load 16 qs (half block) in transposed layout
|
| 221 |
+
uint2 qsx16;
|
| 222 |
+
qsx16.x = read_imageui(src0_qs, q_sub_offset + sub_block_id_m).x;
|
| 223 |
+
qsx16.y = read_imageui(src0_qs, q_sub_offset + sub_block_id_m + ne01).x;
|
| 224 |
+
|
| 225 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 226 |
+
float8 bx8_f32;
|
| 227 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 228 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 229 |
+
// Convert to half and store to LM to share within the subgroup
|
| 230 |
+
half8 bx8_f16 = convert_half8(bx8_f32);
|
| 231 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 232 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 233 |
+
|
| 234 |
+
// Dequantization
|
| 235 |
+
dequantize_q5_1(as_ushort4(qsx16), qhx32.lo, reg_a, s, m);
|
| 236 |
+
|
| 237 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 238 |
+
|
| 239 |
+
// 32 16x16 fp16 dot product with 8 elements reduction for better precision
|
| 240 |
+
half8 acc8;
|
| 241 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 242 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 243 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 244 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 245 |
+
|
| 246 |
+
// Repeat for second sub-block
|
| 247 |
+
uint half_step = step + TILESIZE_K;
|
| 248 |
+
q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 249 |
+
b_sub_offset = col * ne00 + half_step;
|
| 250 |
+
|
| 251 |
+
// Load next 16 qs in transposed layout
|
| 252 |
+
qsx16.x = read_imageui(src0_qs, q_sub_offset + sub_block_id_m).x;
|
| 253 |
+
qsx16.y = read_imageui(src0_qs, q_sub_offset + sub_block_id_m + ne01).x;
|
| 254 |
+
|
| 255 |
+
// Load 16x32 floats from matrix B, each fiber out of 64 in a sub-group loads 8 elements
|
| 256 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 257 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 258 |
+
// Convert to half and store to LM to share within the subgroup
|
| 259 |
+
bx8_f16 = convert_half8(bx8_f32);
|
| 260 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 261 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 262 |
+
|
| 263 |
+
// Dequantization
|
| 264 |
+
dequantize_q5_1(as_ushort4(qsx16), qhx32.hi, reg_a, s, m);
|
| 265 |
+
|
| 266 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 267 |
+
|
| 268 |
+
// 32 16x16 fp16 dot product with 3-levels reduction for better precision
|
| 269 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 270 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 271 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 272 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
|
| 276 |
+
return;
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
// Load poster router and share in LM
|
| 280 |
+
__local uint out_idx[TILESIZE_N];
|
| 281 |
+
|
| 282 |
+
if (get_local_id(0) < TILESIZE_N) {
|
| 283 |
+
uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
|
| 284 |
+
if (idx == 0xFFFFFFFF) {
|
| 285 |
+
idx = src2[block_id_n * TILESIZE_N + 0];
|
| 286 |
+
}
|
| 287 |
+
out_idx[get_local_id(0)] = idx * ne01;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 291 |
+
|
| 292 |
+
// Scatter results back to original position in output grid
|
| 293 |
+
uint m_offset = row + get_local_id(0);
|
| 294 |
+
|
| 295 |
+
write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
|
| 296 |
+
write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
|
| 297 |
+
write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
|
| 298 |
+
write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
|
| 299 |
+
write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
|
| 300 |
+
write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
|
| 301 |
+
write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
|
| 302 |
+
write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
|
| 303 |
+
write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
|
| 304 |
+
write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
|
| 305 |
+
write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
|
| 306 |
+
write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
|
| 307 |
+
write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
|
| 308 |
+
write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
|
| 309 |
+
write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
|
| 310 |
+
write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
|
| 311 |
+
write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
|
| 312 |
+
write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
|
| 313 |
+
write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
|
| 314 |
+
write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
|
| 315 |
+
write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
|
| 316 |
+
write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
|
| 317 |
+
write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
|
| 318 |
+
write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
|
| 319 |
+
write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
|
| 320 |
+
write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
|
| 321 |
+
write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
|
| 322 |
+
write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
|
| 323 |
+
write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
|
| 324 |
+
write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
|
| 325 |
+
write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
|
| 326 |
+
|
| 327 |
+
// Store zero padding parts to the index of first output in tile, override correct result in the end
|
| 328 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 329 |
+
write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
|
| 330 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q5_k_f32_ns.cl
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_K 16
|
| 8 |
+
#define TILESIZE_M 64
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
#define QK_K 256
|
| 11 |
+
#define K_SCALE_SIZE 12
|
| 12 |
+
|
| 13 |
+
inline void get_scale_min_k4(
|
| 14 |
+
int j,
|
| 15 |
+
global const uchar * q,
|
| 16 |
+
uchar * d,
|
| 17 |
+
uchar * m
|
| 18 |
+
) {
|
| 19 |
+
if (j < 4) {
|
| 20 |
+
*d = q[j] & 63;
|
| 21 |
+
*m = q[j+4] & 63;
|
| 22 |
+
} else {
|
| 23 |
+
*d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
|
| 24 |
+
*m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
#define dequantize_q5_k(qs5x16, qh5x16, a_f16, scale, m) \
|
| 29 |
+
a_f16.s0 = (half)((float)(( qs5x16.s0 & 0x000F) | (( qh5x16.s0 & 0x01) << 4)) * scale + m); \
|
| 30 |
+
a_f16.s1 = (half)((float)((((qs5x16.s0 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 1) & 0x01) << 4)) * scale + m)); \
|
| 31 |
+
a_f16.s2 = (half)((float)((((qs5x16.s0 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 2) & 0x01) << 4)) * scale + m)); \
|
| 32 |
+
a_f16.s3 = (half)((float)((((qs5x16.s0 & 0xF000) >> 12) | (((qh5x16.s0 >> 3) & 0x01) << 4)) * scale + m)); \
|
| 33 |
+
a_f16.s4 = (half)((float)((( qs5x16.s1 & 0x000F) | (((qh5x16.s0 >> 4) & 0x01) << 4)) * scale + m)); \
|
| 34 |
+
a_f16.s5 = (half)((float)((((qs5x16.s1 & 0x00F0) >> 4 ) | (((qh5x16.s0 >> 5) & 0x01) << 4)) * scale + m)); \
|
| 35 |
+
a_f16.s6 = (half)((float)(((qs5x16.s1 & 0x0F00) >> 8 ) | (((qh5x16.s0 >> 6) & 0x01) << 4)) * scale + m); \
|
| 36 |
+
a_f16.s7 = (half)((float)((((qs5x16.s1 & 0xF000) >> 12) | (((qh5x16.s0 >> 7) & 0x01) << 4)) * scale + m)); \
|
| 37 |
+
a_f16.s8 = (half)((float)((( qs5x16.s2 & 0x000F) | (( qh5x16.s1 & 0x01) << 4)) * scale + m)); \
|
| 38 |
+
a_f16.s9 = (half)((float)((((qs5x16.s2 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 1) & 0x01) << 4)) * scale + m)); \
|
| 39 |
+
a_f16.sa = (half)((float)((((qs5x16.s2 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 2) & 0x01) << 4)) * scale + m)); \
|
| 40 |
+
a_f16.sb = (half)((float)((((qs5x16.s2 & 0xF000) >> 12) | (((qh5x16.s1 >> 3) & 0x01) << 4)) * scale + m)); \
|
| 41 |
+
a_f16.sc = (half)((float)((( qs5x16.s3 & 0x000F) | (((qh5x16.s1 >> 4) & 0x01) << 4)) * scale + m)); \
|
| 42 |
+
a_f16.sd = (half)((float)((((qs5x16.s3 & 0x00F0) >> 4 ) | (((qh5x16.s1 >> 5) & 0x01) << 4)) * scale + m)); \
|
| 43 |
+
a_f16.se = (half)((float)((((qs5x16.s3 & 0x0F00) >> 8 ) | (((qh5x16.s1 >> 6) & 0x01) << 4)) * scale + m)); \
|
| 44 |
+
a_f16.sf = (half)((float)((((qs5x16.s3 & 0xF000) >> 12) | (((qh5x16.s1 >> 7) & 0x01) << 4)) * scale + m)); \
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
#define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
|
| 48 |
+
acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 49 |
+
acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 50 |
+
acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 51 |
+
acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 52 |
+
acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 53 |
+
acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 54 |
+
acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 55 |
+
acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 56 |
+
acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
|
| 57 |
+
acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
|
| 58 |
+
acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
|
| 59 |
+
acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
|
| 60 |
+
acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
|
| 61 |
+
acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
|
| 62 |
+
acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
|
| 63 |
+
acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
|
| 64 |
+
acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 65 |
+
acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 66 |
+
acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 67 |
+
acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 68 |
+
acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 69 |
+
acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 70 |
+
acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 71 |
+
acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 72 |
+
acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
|
| 73 |
+
acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
|
| 74 |
+
acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
|
| 75 |
+
acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
|
| 76 |
+
acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
|
| 77 |
+
acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
|
| 78 |
+
acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
|
| 79 |
+
acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
|
| 80 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 81 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 82 |
+
acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 83 |
+
acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 84 |
+
acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 85 |
+
acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 86 |
+
acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 87 |
+
acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 88 |
+
acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 89 |
+
acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 90 |
+
acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
|
| 91 |
+
acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
|
| 92 |
+
acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
|
| 93 |
+
acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
|
| 94 |
+
acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
|
| 95 |
+
acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
|
| 96 |
+
acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
|
| 97 |
+
acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
|
| 98 |
+
acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 99 |
+
acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 100 |
+
acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 101 |
+
acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 102 |
+
acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 103 |
+
acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 104 |
+
acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 105 |
+
acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 106 |
+
acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
|
| 107 |
+
acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
|
| 108 |
+
acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
|
| 109 |
+
acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
|
| 110 |
+
acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
|
| 111 |
+
acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
|
| 112 |
+
acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
|
| 113 |
+
acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
|
| 114 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 115 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 116 |
+
|
| 117 |
+
// Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
|
| 118 |
+
// accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
|
| 119 |
+
// non-skipped path is byte-identical; it just lets the caller skip empty
|
| 120 |
+
// 8-column groups at finer granularity. Uses a private half8 `acc8`.
|
| 121 |
+
#define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
|
| 122 |
+
acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 123 |
+
acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 124 |
+
acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 125 |
+
acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 126 |
+
acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 127 |
+
acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 128 |
+
acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 129 |
+
acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 130 |
+
acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 131 |
+
acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 132 |
+
acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 133 |
+
acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 134 |
+
acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 135 |
+
acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 136 |
+
acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 137 |
+
acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 138 |
+
c_reg += convert_float8(acc8); \
|
| 139 |
+
acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 140 |
+
acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 141 |
+
acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 142 |
+
acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 143 |
+
acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 144 |
+
acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 145 |
+
acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 146 |
+
acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 147 |
+
acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 148 |
+
acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 149 |
+
acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 150 |
+
acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 151 |
+
acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 152 |
+
acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 153 |
+
acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 154 |
+
acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 155 |
+
c_reg += convert_float8(acc8); \
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 159 |
+
kernel void kernel_gemm_moe_q5_k_f32_ns(
|
| 160 |
+
__read_only image1d_buffer_t src0_q,
|
| 161 |
+
__global uint * src0_qh,
|
| 162 |
+
__global uchar * src0_s,
|
| 163 |
+
__global half * src0_d,
|
| 164 |
+
__global half * src0_dm,
|
| 165 |
+
__read_only image1d_buffer_t src1,
|
| 166 |
+
__global uint * src2,
|
| 167 |
+
__global ushort * src2_emap,
|
| 168 |
+
__write_only image1d_buffer_t dst,
|
| 169 |
+
__global int * total_tiles,
|
| 170 |
+
uint ne00,
|
| 171 |
+
uint ne01,
|
| 172 |
+
uint is_ragged,
|
| 173 |
+
uint skip_gran
|
| 174 |
+
) {
|
| 175 |
+
uint block_id_m = get_global_id(1); // m_tile
|
| 176 |
+
uint block_id_n = get_global_id(2); // n_tile
|
| 177 |
+
|
| 178 |
+
// Boundary check
|
| 179 |
+
if (block_id_n >= total_tiles[0]) {
|
| 180 |
+
return;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
// Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
|
| 184 |
+
// padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
|
| 185 |
+
// the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
|
| 186 |
+
// Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
|
| 187 |
+
// lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
|
| 188 |
+
// trailing. Find the valid-token count V and round it UP to the skip granularity
|
| 189 |
+
// skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
|
| 190 |
+
// A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
|
| 191 |
+
// dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
|
| 192 |
+
uint n_active = TILESIZE_N;
|
| 193 |
+
if (is_ragged && skip_gran < TILESIZE_N) {
|
| 194 |
+
uint n_valid = TILESIZE_N;
|
| 195 |
+
for (uint _t = 0; _t < TILESIZE_N; ++_t) {
|
| 196 |
+
if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
|
| 197 |
+
}
|
| 198 |
+
n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
|
| 199 |
+
}
|
| 200 |
+
// Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
|
| 201 |
+
bool skip_g1 = (8u >= n_active);
|
| 202 |
+
bool skip_g2 = (16u >= n_active);
|
| 203 |
+
bool skip_g3 = (24u >= n_active);
|
| 204 |
+
|
| 205 |
+
__private half16 reg_a;
|
| 206 |
+
__private float32 reg_c = (float32)(0);
|
| 207 |
+
__local half4 shared_b[128];
|
| 208 |
+
|
| 209 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 210 |
+
|
| 211 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 212 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 213 |
+
|
| 214 |
+
uint sub_block_id_m = get_local_id(0);
|
| 215 |
+
uint2 b_global_offset;
|
| 216 |
+
b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
|
| 217 |
+
b_global_offset.y = b_global_offset.x + (16 * ne00);
|
| 218 |
+
uint2 b_local_offset;
|
| 219 |
+
b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
|
| 220 |
+
b_local_offset.y = b_local_offset.x + 16;
|
| 221 |
+
|
| 222 |
+
uint num_superblocks = ne00 / QK_K;
|
| 223 |
+
uint scales_per_row = num_superblocks * K_SCALE_SIZE;
|
| 224 |
+
uint row_idx = row + get_global_id(0);
|
| 225 |
+
|
| 226 |
+
// Loop along K axis, 32 elements per iteration (one sub-block), divided into 2 halves of 16
|
| 227 |
+
for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
|
| 228 |
+
uint sub = step / 32;
|
| 229 |
+
uint sb = sub / 8;
|
| 230 |
+
uint j = sub % 8;
|
| 231 |
+
|
| 232 |
+
// Load d and dm for super-block
|
| 233 |
+
uint d_offset = row + sb * ne01 + expert_id * num_superblocks * ne01 + get_global_id(0);
|
| 234 |
+
half d_val = src0_d[d_offset];
|
| 235 |
+
half dm_val = src0_dm[d_offset];
|
| 236 |
+
|
| 237 |
+
// Load sub-block scale and min
|
| 238 |
+
global const uchar * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * K_SCALE_SIZE;
|
| 239 |
+
uchar sv, mn;
|
| 240 |
+
get_scale_min_k4(j, sc, &sv, &mn);
|
| 241 |
+
|
| 242 |
+
float scale = (float)d_val * (float)sv;
|
| 243 |
+
float minv = -(float)dm_val * (float)mn;
|
| 244 |
+
|
| 245 |
+
// qh is stored at sub-block granularity
|
| 246 |
+
uint qh_offset = row + sub * ne01 + expert_id * num_superblocks * 8 * ne01 + get_global_id(0);
|
| 247 |
+
uchar4 qhx32 = as_uchar4(src0_qh[qh_offset]);
|
| 248 |
+
|
| 249 |
+
// First sub-block (16 elements)
|
| 250 |
+
uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 251 |
+
uint b_sub_offset = col * ne00 + step;
|
| 252 |
+
|
| 253 |
+
// Load 16 q (64-bits) in transposed layout
|
| 254 |
+
uint2 q4x16;
|
| 255 |
+
q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 256 |
+
q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 257 |
+
|
| 258 |
+
// Load 16x32 floats from matrix B
|
| 259 |
+
float8 bx8_f32;
|
| 260 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 261 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 262 |
+
half8 bx8_f16 = convert_half8(bx8_f32);
|
| 263 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 264 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 265 |
+
|
| 266 |
+
// Dequantization
|
| 267 |
+
dequantize_q5_k(as_ushort4(q4x16), qhx32.lo, reg_a, scale, minv);
|
| 268 |
+
|
| 269 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 270 |
+
|
| 271 |
+
half8 acc8;
|
| 272 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 273 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 274 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 275 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 276 |
+
|
| 277 |
+
// Second half
|
| 278 |
+
uint half_step = step + TILESIZE_K;
|
| 279 |
+
q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 280 |
+
b_sub_offset = col * ne00 + half_step;
|
| 281 |
+
|
| 282 |
+
q4x16.x = read_imageui(src0_q, q_sub_offset + sub_block_id_m).x;
|
| 283 |
+
q4x16.y = read_imageui(src0_q, q_sub_offset + sub_block_id_m + ne01).x;
|
| 284 |
+
|
| 285 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 286 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 287 |
+
bx8_f16 = convert_half8(bx8_f32);
|
| 288 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 289 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 290 |
+
|
| 291 |
+
dequantize_q5_k(as_ushort4(q4x16), qhx32.hi, reg_a, scale, minv);
|
| 292 |
+
|
| 293 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 294 |
+
|
| 295 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 296 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 297 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 298 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
|
| 302 |
+
return;
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
// Load post router and share in LM
|
| 306 |
+
__local uint out_idx[TILESIZE_N];
|
| 307 |
+
|
| 308 |
+
if (get_local_id(0) < TILESIZE_N) {
|
| 309 |
+
uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
|
| 310 |
+
if (idx == 0xFFFFFFFF) {
|
| 311 |
+
idx = src2[block_id_n * TILESIZE_N + 0];
|
| 312 |
+
}
|
| 313 |
+
out_idx[get_local_id(0)] = idx * ne01;
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 317 |
+
|
| 318 |
+
// Scatter results back to original position in output grid
|
| 319 |
+
uint m_offset = row + get_local_id(0);
|
| 320 |
+
|
| 321 |
+
write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
|
| 322 |
+
write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
|
| 323 |
+
write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
|
| 324 |
+
write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
|
| 325 |
+
write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
|
| 326 |
+
write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
|
| 327 |
+
write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
|
| 328 |
+
write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
|
| 329 |
+
write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
|
| 330 |
+
write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
|
| 331 |
+
write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
|
| 332 |
+
write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
|
| 333 |
+
write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
|
| 334 |
+
write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
|
| 335 |
+
write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
|
| 336 |
+
write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
|
| 337 |
+
write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
|
| 338 |
+
write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
|
| 339 |
+
write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
|
| 340 |
+
write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
|
| 341 |
+
write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
|
| 342 |
+
write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
|
| 343 |
+
write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
|
| 344 |
+
write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
|
| 345 |
+
write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
|
| 346 |
+
write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
|
| 347 |
+
write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
|
| 348 |
+
write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
|
| 349 |
+
write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
|
| 350 |
+
write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
|
| 351 |
+
write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
|
| 352 |
+
|
| 353 |
+
// Store zero padding parts to the index of first output in tile
|
| 354 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 355 |
+
write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
|
| 356 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_f32_ns.cl
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_K 16
|
| 8 |
+
#define TILESIZE_M 64
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
#define QK_K 256
|
| 11 |
+
|
| 12 |
+
#define dequantize_q6_k(qs16, qh16, a_f16, scale) \
|
| 13 |
+
a_f16.s0 = (half)(((float)(( qs16.s0 & 0x000F) | ((uint)(( qh16 ) & 0x3) << 4)) - 32.f) * scale); \
|
| 14 |
+
a_f16.s1 = (half)(((float)((( qs16.s0 >> 4) & 0x000F) | ((uint)(( qh16 >> 2) & 0x3) << 4)) - 32.f) * scale); \
|
| 15 |
+
a_f16.s2 = (half)(((float)((( qs16.s0 >> 8) & 0x000F) | ((uint)(( qh16 >> 4) & 0x3) << 4)) - 32.f) * scale); \
|
| 16 |
+
a_f16.s3 = (half)(((float)((( qs16.s0 >>12) & 0x000F) | ((uint)(( qh16 >> 6) & 0x3) << 4)) - 32.f) * scale); \
|
| 17 |
+
a_f16.s4 = (half)(((float)(( qs16.s1 & 0x000F) | ((uint)(( qh16 >> 8) & 0x3) << 4)) - 32.f) * scale); \
|
| 18 |
+
a_f16.s5 = (half)(((float)((( qs16.s1 >> 4) & 0x000F) | ((uint)(( qh16 >> 10) & 0x3) << 4)) - 32.f) * scale); \
|
| 19 |
+
a_f16.s6 = (half)(((float)((( qs16.s1 >> 8) & 0x000F) | ((uint)(( qh16 >> 12) & 0x3) << 4)) - 32.f) * scale); \
|
| 20 |
+
a_f16.s7 = (half)(((float)((( qs16.s1 >>12) & 0x000F) | ((uint)(( qh16 >> 14) & 0x3) << 4)) - 32.f) * scale); \
|
| 21 |
+
a_f16.s8 = (half)(((float)(( qs16.s2 & 0x000F) | ((uint)(( qh16 >> 16) & 0x3) << 4)) - 32.f) * scale); \
|
| 22 |
+
a_f16.s9 = (half)(((float)((( qs16.s2 >> 4) & 0x000F) | ((uint)(( qh16 >> 18) & 0x3) << 4)) - 32.f) * scale); \
|
| 23 |
+
a_f16.sa = (half)(((float)((( qs16.s2 >> 8) & 0x000F) | ((uint)(( qh16 >> 20) & 0x3) << 4)) - 32.f) * scale); \
|
| 24 |
+
a_f16.sb = (half)(((float)((( qs16.s2 >>12) & 0x000F) | ((uint)(( qh16 >> 22) & 0x3) << 4)) - 32.f) * scale); \
|
| 25 |
+
a_f16.sc = (half)(((float)(( qs16.s3 & 0x000F) | ((uint)(( qh16 >> 24) & 0x3) << 4)) - 32.f) * scale); \
|
| 26 |
+
a_f16.sd = (half)(((float)((( qs16.s3 >> 4) & 0x000F) | ((uint)(( qh16 >> 26) & 0x3) << 4)) - 32.f) * scale); \
|
| 27 |
+
a_f16.se = (half)(((float)((( qs16.s3 >> 8) & 0x000F) | ((uint)(( qh16 >> 28) & 0x3) << 4)) - 32.f) * scale); \
|
| 28 |
+
a_f16.sf = (half)(((float)((( qs16.s3 >>12) & 0x000F) | ((uint)(( qh16 >> 30) & 0x3) << 4)) - 32.f) * scale); \
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
#define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
|
| 32 |
+
acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 33 |
+
acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 34 |
+
acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 35 |
+
acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 36 |
+
acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 37 |
+
acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 38 |
+
acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 39 |
+
acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 40 |
+
acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
|
| 41 |
+
acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
|
| 42 |
+
acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
|
| 43 |
+
acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
|
| 44 |
+
acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
|
| 45 |
+
acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
|
| 46 |
+
acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
|
| 47 |
+
acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
|
| 48 |
+
acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 49 |
+
acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 50 |
+
acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 51 |
+
acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 52 |
+
acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 53 |
+
acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 54 |
+
acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 55 |
+
acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 56 |
+
acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
|
| 57 |
+
acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
|
| 58 |
+
acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
|
| 59 |
+
acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
|
| 60 |
+
acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
|
| 61 |
+
acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
|
| 62 |
+
acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
|
| 63 |
+
acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
|
| 64 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 65 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 66 |
+
acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 67 |
+
acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 68 |
+
acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 69 |
+
acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 70 |
+
acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 71 |
+
acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 72 |
+
acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 73 |
+
acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 74 |
+
acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
|
| 75 |
+
acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
|
| 76 |
+
acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
|
| 77 |
+
acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
|
| 78 |
+
acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
|
| 79 |
+
acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
|
| 80 |
+
acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
|
| 81 |
+
acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
|
| 82 |
+
acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 83 |
+
acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 84 |
+
acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 85 |
+
acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 86 |
+
acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 87 |
+
acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 88 |
+
acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 89 |
+
acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 90 |
+
acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
|
| 91 |
+
acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
|
| 92 |
+
acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
|
| 93 |
+
acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
|
| 94 |
+
acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
|
| 95 |
+
acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
|
| 96 |
+
acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
|
| 97 |
+
acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
|
| 98 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 99 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 100 |
+
|
| 101 |
+
// Quarter-tile variant: computes 8 output columns (one skip-group) into a float8
|
| 102 |
+
// accumulator. Same reduction order / flush cadence as dotx16_reduce8, so the
|
| 103 |
+
// non-skipped path is byte-identical; it just lets the caller skip empty
|
| 104 |
+
// 8-column groups at finer granularity. Uses a private half8 `acc8`.
|
| 105 |
+
#define dotx8_reduce4(a_reg, b_lm, c_reg, lm_offset) \
|
| 106 |
+
acc8.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 107 |
+
acc8.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 108 |
+
acc8.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 109 |
+
acc8.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 110 |
+
acc8.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 111 |
+
acc8.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 112 |
+
acc8.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 113 |
+
acc8.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 114 |
+
acc8.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 115 |
+
acc8.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 116 |
+
acc8.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 117 |
+
acc8.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 118 |
+
acc8.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 119 |
+
acc8.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 120 |
+
acc8.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 121 |
+
acc8.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 122 |
+
c_reg += convert_float8(acc8); \
|
| 123 |
+
acc8.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 124 |
+
acc8.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 125 |
+
acc8.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 126 |
+
acc8.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 127 |
+
acc8.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 128 |
+
acc8.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 129 |
+
acc8.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 130 |
+
acc8.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 131 |
+
acc8.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 132 |
+
acc8.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 133 |
+
acc8.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 134 |
+
acc8.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 135 |
+
acc8.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 136 |
+
acc8.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 137 |
+
acc8.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 138 |
+
acc8.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 139 |
+
c_reg += convert_float8(acc8); \
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 143 |
+
kernel void kernel_gemm_moe_q6_k_f32_ns(
|
| 144 |
+
__read_only image1d_buffer_t src0_ql,
|
| 145 |
+
__global uint * src0_qh,
|
| 146 |
+
__global char * src0_s,
|
| 147 |
+
__global half * src0_d,
|
| 148 |
+
__read_only image1d_buffer_t src1,
|
| 149 |
+
__global uint * src2,
|
| 150 |
+
__global ushort * src2_emap,
|
| 151 |
+
__write_only image1d_buffer_t dst,
|
| 152 |
+
__global int * total_tiles,
|
| 153 |
+
uint ne00,
|
| 154 |
+
uint ne01,
|
| 155 |
+
uint is_ragged,
|
| 156 |
+
uint skip_gran
|
| 157 |
+
) {
|
| 158 |
+
uint block_id_m = get_global_id(1); // m_tile
|
| 159 |
+
uint block_id_n = get_global_id(2); // n_tile
|
| 160 |
+
|
| 161 |
+
// Boundary check
|
| 162 |
+
if (block_id_n >= total_tiles[0]) {
|
| 163 |
+
return;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
// Ragged tile-skip: when is_ragged and the upper 16 token-slots of this tile are all
|
| 167 |
+
// padding (router 0xFFFFFFFF), skip the second (reg_c.hi) dotx16_reduce8 half -> ~half
|
| 168 |
+
// the GEMM dot for sparse tiles. Numerically identical (the skipped lanes are padding).
|
| 169 |
+
// Ragged tile-skip: tokens are packed contiguously per expert (moe_scatter fills
|
| 170 |
+
// lanes 0..V-1, moe_fill pre-pads the rest), so router padding (0xFFFFFFFF) is always
|
| 171 |
+
// trailing. Find the valid-token count V and round it UP to the skip granularity
|
| 172 |
+
// skip_gran (columns per skip-group: 8 = quarter, 16 = half/legacy, 32 = disabled).
|
| 173 |
+
// A 8-column group g is all-padding iff its first column (8*g) >= n_active, so its
|
| 174 |
+
// dotx8_reduce4 is skipped. Numerically identical (skipped lanes are padding).
|
| 175 |
+
uint n_active = TILESIZE_N;
|
| 176 |
+
if (is_ragged && skip_gran < TILESIZE_N) {
|
| 177 |
+
uint n_valid = TILESIZE_N;
|
| 178 |
+
for (uint _t = 0; _t < TILESIZE_N; ++_t) {
|
| 179 |
+
if (src2[block_id_n * TILESIZE_N + _t] == 0xFFFFFFFFu) { n_valid = _t; break; }
|
| 180 |
+
}
|
| 181 |
+
n_active = min((uint)TILESIZE_N, ((n_valid + skip_gran - 1) / skip_gran) * skip_gran);
|
| 182 |
+
}
|
| 183 |
+
// Group 0 (cols 0-7) always runs; groups 1-3 skip when fully padding.
|
| 184 |
+
bool skip_g1 = (8u >= n_active);
|
| 185 |
+
bool skip_g2 = (16u >= n_active);
|
| 186 |
+
bool skip_g3 = (24u >= n_active);
|
| 187 |
+
|
| 188 |
+
__private half16 reg_a;
|
| 189 |
+
__private float32 reg_c = (float32)(0);
|
| 190 |
+
__local half4 shared_b[128];
|
| 191 |
+
|
| 192 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 193 |
+
|
| 194 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 195 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 196 |
+
|
| 197 |
+
uint sub_block_id_m = get_local_id(0);
|
| 198 |
+
uint2 b_global_offset;
|
| 199 |
+
b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
|
| 200 |
+
b_global_offset.y = b_global_offset.x + (16 * ne00);
|
| 201 |
+
uint2 b_local_offset;
|
| 202 |
+
b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
|
| 203 |
+
b_local_offset.y = b_local_offset.x + 16;
|
| 204 |
+
|
| 205 |
+
uint num_superblocks = ne00 / QK_K;
|
| 206 |
+
uint scales_per_row = num_superblocks * 16;
|
| 207 |
+
uint row_idx = row + get_global_id(0);
|
| 208 |
+
|
| 209 |
+
// Loop along K axis, 32 elements per iteration (one sub-block), divided into 2 halves of 16
|
| 210 |
+
for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
|
| 211 |
+
uint sub = step / 32; // 32-element group index
|
| 212 |
+
uint sb = sub / 8; // super-block index
|
| 213 |
+
uint j = sub % 8; // group within super-block
|
| 214 |
+
|
| 215 |
+
// Load d for super-block
|
| 216 |
+
uint d_offset = row + sb * ne01 + expert_id * num_superblocks * ne01 + get_global_id(0);
|
| 217 |
+
half d_val = src0_d[d_offset];
|
| 218 |
+
|
| 219 |
+
// Load sub-block scales
|
| 220 |
+
global const char * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * 16;
|
| 221 |
+
float scale0 = (float)d_val * (float)sc[j * 2];
|
| 222 |
+
float scale1 = (float)d_val * (float)sc[j * 2 + 1];
|
| 223 |
+
|
| 224 |
+
uint qh_base = row + (sub * 2) * ne01 + expert_id * (num_superblocks * 16) * ne01 + get_global_id(0);
|
| 225 |
+
uint qh_first16 = src0_qh[qh_base];
|
| 226 |
+
uint qh_second16 = src0_qh[qh_base + ne01];
|
| 227 |
+
|
| 228 |
+
// First half (16 elements)
|
| 229 |
+
uint q_sub_offset = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 230 |
+
uint b_sub_offset = col * ne00 + step;
|
| 231 |
+
|
| 232 |
+
// Load 16 ql nibbles (2 uints) from image
|
| 233 |
+
uint2 q4x16;
|
| 234 |
+
q4x16.x = read_imageui(src0_ql, q_sub_offset + sub_block_id_m).x;
|
| 235 |
+
q4x16.y = read_imageui(src0_ql, q_sub_offset + sub_block_id_m + ne01).x;
|
| 236 |
+
|
| 237 |
+
// Load 16x32 floats from matrix B
|
| 238 |
+
float8 bx8_f32;
|
| 239 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 240 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 241 |
+
half8 bx8_f16 = convert_half8(bx8_f32);
|
| 242 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 243 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 244 |
+
|
| 245 |
+
// Dequantize first 16 elements (scale0)
|
| 246 |
+
dequantize_q6_k(as_ushort4(q4x16), qh_first16, reg_a, scale0);
|
| 247 |
+
|
| 248 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 249 |
+
|
| 250 |
+
half8 acc8;
|
| 251 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 252 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 253 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 254 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 255 |
+
|
| 256 |
+
// Second half
|
| 257 |
+
uint half_step = step + TILESIZE_K;
|
| 258 |
+
q_sub_offset = row + ((ne01 * half_step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 259 |
+
b_sub_offset = col * ne00 + half_step;
|
| 260 |
+
|
| 261 |
+
q4x16.x = read_imageui(src0_ql, q_sub_offset + sub_block_id_m).x;
|
| 262 |
+
q4x16.y = read_imageui(src0_ql, q_sub_offset + sub_block_id_m + ne01).x;
|
| 263 |
+
|
| 264 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 265 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 266 |
+
bx8_f16 = convert_half8(bx8_f32);
|
| 267 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 268 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 269 |
+
|
| 270 |
+
dequantize_q6_k(as_ushort4(q4x16), qh_second16, reg_a, scale1);
|
| 271 |
+
|
| 272 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 273 |
+
|
| 274 |
+
dotx8_reduce4(reg_a, shared_b, reg_c.lo.lo, 0);
|
| 275 |
+
if (!skip_g1) { dotx8_reduce4(reg_a, shared_b, reg_c.lo.hi, 8); }
|
| 276 |
+
if (!skip_g2) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.lo, 16); }
|
| 277 |
+
if (!skip_g3) { dotx8_reduce4(reg_a, shared_b, reg_c.hi.hi, 24); }
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
|
| 281 |
+
return;
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
// Load post router and share in LM
|
| 285 |
+
__local uint out_idx[TILESIZE_N];
|
| 286 |
+
|
| 287 |
+
if (get_local_id(0) < TILESIZE_N) {
|
| 288 |
+
uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
|
| 289 |
+
if (idx == 0xFFFFFFFF) {
|
| 290 |
+
idx = src2[block_id_n * TILESIZE_N + 0];
|
| 291 |
+
}
|
| 292 |
+
out_idx[get_local_id(0)] = idx * ne01;
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 296 |
+
|
| 297 |
+
// Scatter results back to original position in output grid
|
| 298 |
+
uint m_offset = row + get_local_id(0);
|
| 299 |
+
|
| 300 |
+
write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
|
| 301 |
+
write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
|
| 302 |
+
write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
|
| 303 |
+
write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
|
| 304 |
+
write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
|
| 305 |
+
write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
|
| 306 |
+
write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
|
| 307 |
+
write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
|
| 308 |
+
write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
|
| 309 |
+
write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
|
| 310 |
+
write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
|
| 311 |
+
write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
|
| 312 |
+
write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
|
| 313 |
+
write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
|
| 314 |
+
write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
|
| 315 |
+
write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
|
| 316 |
+
write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
|
| 317 |
+
write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
|
| 318 |
+
write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
|
| 319 |
+
write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
|
| 320 |
+
write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
|
| 321 |
+
write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
|
| 322 |
+
write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
|
| 323 |
+
write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
|
| 324 |
+
write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
|
| 325 |
+
write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
|
| 326 |
+
write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
|
| 327 |
+
write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
|
| 328 |
+
write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
|
| 329 |
+
write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
|
| 330 |
+
write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
|
| 331 |
+
|
| 332 |
+
// Store zero padding parts to the index of first output in tile
|
| 333 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 334 |
+
write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
|
| 335 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q6_k_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_N 32
|
| 8 |
+
#define QK_K 256
|
| 9 |
+
|
| 10 |
+
// 4 nibbles in the low 16 bits of `u` -> 4 bytes (value 0..15, in bits 0-3).
|
| 11 |
+
#define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
|
| 12 |
+
(((uint)((u) & 0x00F0u)) << 4) | \
|
| 13 |
+
(((uint)((u) & 0x0F00u)) << 8) | \
|
| 14 |
+
(((uint)((u) & 0xF000u)) << 12) )
|
| 15 |
+
|
| 16 |
+
// 4 2-bit highs in byte `b` (8 bits) -> 4 bytes, value 0..3 in bits 4-5
|
| 17 |
+
// (pre-multiplied by 16 so it ORs with the EXP4 nibble to form q6 in 0..63).
|
| 18 |
+
#define EXP2(b) ( (((uint)((b) & 0x03u)) << 4) | \
|
| 19 |
+
(((uint)((b) & 0x0Cu)) << 10) | \
|
| 20 |
+
(((uint)((b) & 0x30u)) << 16) | \
|
| 21 |
+
(((uint)((b) & 0xC0u)) << 22) )
|
| 22 |
+
|
| 23 |
+
// q6 (0..63, bits 0-5 of each byte) -> (q6-32) as a signed int8 per byte.
|
| 24 |
+
// Flipping bit5 subtracts 32 in 6-bit two's complement; then replicate bit5
|
| 25 |
+
// into bits 6-7 to sign-extend to int8. Per-byte, no inter-byte carry.
|
| 26 |
+
inline uint SIGN6(uint q6p) {
|
| 27 |
+
uint x = q6p ^ 0x20202020u;
|
| 28 |
+
uint s = x & 0x20202020u;
|
| 29 |
+
return x | (s << 1) | (s << 2);
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
inline int dp4a_q6(uint qw0, uint qw1, uint qw2, uint qw3,
|
| 33 |
+
uint a0, uint a1, uint a2, uint a3) {
|
| 34 |
+
int raw = 0;
|
| 35 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw0, a0, raw);
|
| 36 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw1, a1, raw);
|
| 37 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw2, a2, raw);
|
| 38 |
+
raw = dot_acc_sat_4x8packed_ss_int(qw3, a3, raw);
|
| 39 |
+
return raw;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
// One token's q6_K dp4a dot (two halves, per-16 scales) + epilogue into acc[t].
|
| 43 |
+
#define MOE_Q6K_DP4A_T(t) do { \
|
| 44 |
+
const int raw1 = dp4a_q6(qw[0], qw[1], qw[2], qw[3], sh_qa[t][0], sh_qa[t][1], sh_qa[t][2], sh_qa[t][3]); \
|
| 45 |
+
const int raw2 = dp4a_q6(qw[4], qw[5], qw[6], qw[7], sh_qa[t][4], sh_qa[t][5], sh_qa[t][6], sh_qa[t][7]); \
|
| 46 |
+
const float a_d = (float)sh_d[t]; \
|
| 47 |
+
acc[t] += scale0 * a_d * (float)raw1 + scale1 * a_d * (float)raw2; \
|
| 48 |
+
} while (0)
|
| 49 |
+
|
| 50 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 51 |
+
kernel void kernel_gemm_moe_q6_k_q8_1_dp4a(
|
| 52 |
+
__read_only image1d_buffer_t src0_ql, // q6_K low nibbles (image, q4_K-style layout)
|
| 53 |
+
__global uint * src0_qh, // q6_K high 2-bit (16 elems/uint)
|
| 54 |
+
__global char * src0_s, // int8 scales (one per 16 elems)
|
| 55 |
+
__global half * src0_d, // per-superblock scale
|
| 56 |
+
__global uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem)
|
| 57 |
+
__global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
|
| 58 |
+
__global uint * src2, // post-router (orig out positions)
|
| 59 |
+
__global ushort * src2_emap, // tile -> expert id
|
| 60 |
+
__write_only image1d_buffer_t dst,
|
| 61 |
+
__global int * total_tiles,
|
| 62 |
+
uint ne00,
|
| 63 |
+
uint ne01,
|
| 64 |
+
int is_ragged // 1: compute only real tokens per tile
|
| 65 |
+
) {
|
| 66 |
+
const uint block_id_m = get_global_id(1);
|
| 67 |
+
const uint block_id_n = get_global_id(2);
|
| 68 |
+
|
| 69 |
+
if (block_id_n >= total_tiles[0]) {
|
| 70 |
+
return;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
const uint lid = get_local_id(0); // 0..63 -> row within M-tile
|
| 74 |
+
|
| 75 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 76 |
+
const uint row = block_id_m * 64;
|
| 77 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 78 |
+
|
| 79 |
+
const uint num_superblocks = ne00 / QK_K;
|
| 80 |
+
const uint scales_per_row = num_superblocks * 16;
|
| 81 |
+
const uint row_idx = row + lid;
|
| 82 |
+
|
| 83 |
+
const uint ne00_u = ne00 >> 2;
|
| 84 |
+
const uint ne00_b = ne00 >> 5;
|
| 85 |
+
|
| 86 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 87 |
+
__local half sh_d[TILESIZE_N];
|
| 88 |
+
|
| 89 |
+
// Real token count for this tile
|
| 90 |
+
__local uint sh_src2[TILESIZE_N];
|
| 91 |
+
__local int sh_nreal;
|
| 92 |
+
if (lid < TILESIZE_N) {
|
| 93 |
+
sh_src2[lid] = src2[col + lid];
|
| 94 |
+
}
|
| 95 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 96 |
+
if (lid == 0) {
|
| 97 |
+
int nr = TILESIZE_N;
|
| 98 |
+
if (is_ragged) {
|
| 99 |
+
nr = 0;
|
| 100 |
+
#pragma unroll
|
| 101 |
+
for (int t = 0; t < TILESIZE_N; ++t) {
|
| 102 |
+
if (sh_src2[t] != 0xFFFFFFFFu) ++nr;
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
sh_nreal = nr;
|
| 106 |
+
}
|
| 107 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 108 |
+
const int n_real = sh_nreal;
|
| 109 |
+
|
| 110 |
+
float acc[TILESIZE_N];
|
| 111 |
+
#pragma unroll
|
| 112 |
+
for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
|
| 113 |
+
|
| 114 |
+
for (uint step = 0; step < ne00; step += 32) {
|
| 115 |
+
const uint sub = step >> 5;
|
| 116 |
+
const uint sb = sub >> 3;
|
| 117 |
+
const uint j = sub & 7;
|
| 118 |
+
|
| 119 |
+
const float d_val = (float)src0_d[row + sb * ne01 + expert_id * num_superblocks * ne01 + lid];
|
| 120 |
+
global const char * sc = src0_s + (expert_id * ne01 + row_idx) * scales_per_row + sb * 16;
|
| 121 |
+
const float scale0 = d_val * (float)sc[j * 2];
|
| 122 |
+
const float scale1 = d_val * (float)sc[j * 2 + 1];
|
| 123 |
+
|
| 124 |
+
// high bits: one uint covers 16 elems; first/second 16 of this 32-block
|
| 125 |
+
const uint qh_base = row + (sub * 2) * ne01 + expert_id * (num_superblocks * 16) * ne01 + lid;
|
| 126 |
+
const uint qh1 = src0_qh[qh_base];
|
| 127 |
+
const uint qh2 = src0_qh[qh_base + ne01];
|
| 128 |
+
|
| 129 |
+
// low nibbles: same image layout as q4_K (8 ushorts over the 32 K)
|
| 130 |
+
const uint qoff0 = row + ((ne01 * step) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 131 |
+
const uint qoff1 = row + ((ne01 * (step + 16)) >> 3) + ((expert_id * ne00 * ne01) >> 3);
|
| 132 |
+
const uint r0 = read_imageui(src0_ql, qoff0 + lid).x;
|
| 133 |
+
const uint r1 = read_imageui(src0_ql, qoff0 + lid + ne01).x;
|
| 134 |
+
const uint r2 = read_imageui(src0_ql, qoff1 + lid).x;
|
| 135 |
+
const uint r3 = read_imageui(src0_ql, qoff1 + lid + ne01).x;
|
| 136 |
+
|
| 137 |
+
uint qw[8];
|
| 138 |
+
qw[0] = SIGN6(EXP4(r0) | EXP2((qh1) & 0xFFu));
|
| 139 |
+
qw[1] = SIGN6(EXP4(r0 >> 16) | EXP2((qh1 >> 8) & 0xFFu));
|
| 140 |
+
qw[2] = SIGN6(EXP4(r1) | EXP2((qh1 >> 16) & 0xFFu));
|
| 141 |
+
qw[3] = SIGN6(EXP4(r1 >> 16) | EXP2((qh1 >> 24) & 0xFFu));
|
| 142 |
+
qw[4] = SIGN6(EXP4(r2) | EXP2((qh2) & 0xFFu));
|
| 143 |
+
qw[5] = SIGN6(EXP4(r2 >> 16) | EXP2((qh2 >> 8) & 0xFFu));
|
| 144 |
+
qw[6] = SIGN6(EXP4(r3) | EXP2((qh2 >> 16) & 0xFFu));
|
| 145 |
+
qw[7] = SIGN6(EXP4(r3 >> 16) | EXP2((qh2 >> 24) & 0xFFu));
|
| 146 |
+
|
| 147 |
+
const uint stage_lim = (uint)n_real * 8;
|
| 148 |
+
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
| 149 |
+
const uint t = idx >> 3;
|
| 150 |
+
const uint u = idx & 7;
|
| 151 |
+
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
| 152 |
+
}
|
| 153 |
+
if (lid < (uint)n_real) {
|
| 154 |
+
sh_d[lid] = src1_da[(col + lid) * ne00_b + sub];
|
| 155 |
+
}
|
| 156 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 157 |
+
|
| 158 |
+
// Full tiles keep the fully-unrolled 32-wide loop; partial tiles run n_real.
|
| 159 |
+
if (n_real == TILESIZE_N) {
|
| 160 |
+
#pragma unroll
|
| 161 |
+
for (int t = 0; t < TILESIZE_N; ++t) { MOE_Q6K_DP4A_T(t); }
|
| 162 |
+
} else {
|
| 163 |
+
#pragma unroll 4
|
| 164 |
+
for (int t = 0; t < n_real; ++t) { MOE_Q6K_DP4A_T(t); }
|
| 165 |
+
}
|
| 166 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
if (row_idx >= ne01) {
|
| 170 |
+
return;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
__local uint out_idx[TILESIZE_N];
|
| 174 |
+
if (lid < TILESIZE_N) {
|
| 175 |
+
uint idx = sh_src2[lid];
|
| 176 |
+
if (idx == 0xFFFFFFFF) {
|
| 177 |
+
idx = sh_src2[0];
|
| 178 |
+
}
|
| 179 |
+
out_idx[lid] = idx * ne01;
|
| 180 |
+
}
|
| 181 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 182 |
+
|
| 183 |
+
const uint m_offset = row + lid;
|
| 184 |
+
if (n_real == TILESIZE_N) {
|
| 185 |
+
#pragma unroll
|
| 186 |
+
for (int t = 1; t < TILESIZE_N; ++t) {
|
| 187 |
+
write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 188 |
+
}
|
| 189 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 190 |
+
write_imagef(dst, out_idx[0] + m_offset, acc[0]);
|
| 191 |
+
} else {
|
| 192 |
+
for (int t = 0; t < n_real; ++t) {
|
| 193 |
+
write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 194 |
+
}
|
| 195 |
+
}
|
| 196 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q8_0_f32_ns.cl
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load: enable
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load: enable
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_extra_vector_types : enable
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_K 16
|
| 8 |
+
#define TILESIZE_M 64
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
|
| 11 |
+
// q8_0: 16 signed int8 weights (one uint4 = 16 chars) -> half16, scaled.
|
| 12 |
+
#define dequantize_q8_0(q4, a_f16, scale) \
|
| 13 |
+
a_f16 = convert_half16(as_char16(q4)) * scale;
|
| 14 |
+
|
| 15 |
+
#define dotx16_reduce8(a_reg, b_lm, c_reg, lm_offset) \
|
| 16 |
+
acc.s0 = dot(a_reg.s0123, b_lm[lm_offset + 0]); \
|
| 17 |
+
acc.s1 = dot(a_reg.s0123, b_lm[lm_offset + 1]); \
|
| 18 |
+
acc.s2 = dot(a_reg.s0123, b_lm[lm_offset + 2]); \
|
| 19 |
+
acc.s3 = dot(a_reg.s0123, b_lm[lm_offset + 3]); \
|
| 20 |
+
acc.s4 = dot(a_reg.s0123, b_lm[lm_offset + 4]); \
|
| 21 |
+
acc.s5 = dot(a_reg.s0123, b_lm[lm_offset + 5]); \
|
| 22 |
+
acc.s6 = dot(a_reg.s0123, b_lm[lm_offset + 6]); \
|
| 23 |
+
acc.s7 = dot(a_reg.s0123, b_lm[lm_offset + 7]); \
|
| 24 |
+
acc.s8 = dot(a_reg.s0123, b_lm[lm_offset + 8]); \
|
| 25 |
+
acc.s9 = dot(a_reg.s0123, b_lm[lm_offset + 9]); \
|
| 26 |
+
acc.sa = dot(a_reg.s0123, b_lm[lm_offset + 10]); \
|
| 27 |
+
acc.sb = dot(a_reg.s0123, b_lm[lm_offset + 11]); \
|
| 28 |
+
acc.sc = dot(a_reg.s0123, b_lm[lm_offset + 12]); \
|
| 29 |
+
acc.sd = dot(a_reg.s0123, b_lm[lm_offset + 13]); \
|
| 30 |
+
acc.se = dot(a_reg.s0123, b_lm[lm_offset + 14]); \
|
| 31 |
+
acc.sf = dot(a_reg.s0123, b_lm[lm_offset + 15]); \
|
| 32 |
+
acc.s0 += dot(a_reg.s4567, b_lm[lm_offset + 32]); \
|
| 33 |
+
acc.s1 += dot(a_reg.s4567, b_lm[lm_offset + 33]); \
|
| 34 |
+
acc.s2 += dot(a_reg.s4567, b_lm[lm_offset + 34]); \
|
| 35 |
+
acc.s3 += dot(a_reg.s4567, b_lm[lm_offset + 35]); \
|
| 36 |
+
acc.s4 += dot(a_reg.s4567, b_lm[lm_offset + 36]); \
|
| 37 |
+
acc.s5 += dot(a_reg.s4567, b_lm[lm_offset + 37]); \
|
| 38 |
+
acc.s6 += dot(a_reg.s4567, b_lm[lm_offset + 38]); \
|
| 39 |
+
acc.s7 += dot(a_reg.s4567, b_lm[lm_offset + 39]); \
|
| 40 |
+
acc.s8 += dot(a_reg.s4567, b_lm[lm_offset + 40]); \
|
| 41 |
+
acc.s9 += dot(a_reg.s4567, b_lm[lm_offset + 41]); \
|
| 42 |
+
acc.sa += dot(a_reg.s4567, b_lm[lm_offset + 42]); \
|
| 43 |
+
acc.sb += dot(a_reg.s4567, b_lm[lm_offset + 43]); \
|
| 44 |
+
acc.sc += dot(a_reg.s4567, b_lm[lm_offset + 44]); \
|
| 45 |
+
acc.sd += dot(a_reg.s4567, b_lm[lm_offset + 45]); \
|
| 46 |
+
acc.se += dot(a_reg.s4567, b_lm[lm_offset + 46]); \
|
| 47 |
+
acc.sf += dot(a_reg.s4567, b_lm[lm_offset + 47]); \
|
| 48 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 49 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 50 |
+
acc.s0 = dot(a_reg.s89ab, b_lm[lm_offset + 64]); \
|
| 51 |
+
acc.s1 = dot(a_reg.s89ab, b_lm[lm_offset + 65]); \
|
| 52 |
+
acc.s2 = dot(a_reg.s89ab, b_lm[lm_offset + 66]); \
|
| 53 |
+
acc.s3 = dot(a_reg.s89ab, b_lm[lm_offset + 67]); \
|
| 54 |
+
acc.s4 = dot(a_reg.s89ab, b_lm[lm_offset + 68]); \
|
| 55 |
+
acc.s5 = dot(a_reg.s89ab, b_lm[lm_offset + 69]); \
|
| 56 |
+
acc.s6 = dot(a_reg.s89ab, b_lm[lm_offset + 70]); \
|
| 57 |
+
acc.s7 = dot(a_reg.s89ab, b_lm[lm_offset + 71]); \
|
| 58 |
+
acc.s8 = dot(a_reg.s89ab, b_lm[lm_offset + 72]); \
|
| 59 |
+
acc.s9 = dot(a_reg.s89ab, b_lm[lm_offset + 73]); \
|
| 60 |
+
acc.sa = dot(a_reg.s89ab, b_lm[lm_offset + 74]); \
|
| 61 |
+
acc.sb = dot(a_reg.s89ab, b_lm[lm_offset + 75]); \
|
| 62 |
+
acc.sc = dot(a_reg.s89ab, b_lm[lm_offset + 76]); \
|
| 63 |
+
acc.sd = dot(a_reg.s89ab, b_lm[lm_offset + 77]); \
|
| 64 |
+
acc.se = dot(a_reg.s89ab, b_lm[lm_offset + 78]); \
|
| 65 |
+
acc.sf = dot(a_reg.s89ab, b_lm[lm_offset + 79]); \
|
| 66 |
+
acc.s0 += dot(a_reg.scdef, b_lm[lm_offset + 96]); \
|
| 67 |
+
acc.s1 += dot(a_reg.scdef, b_lm[lm_offset + 97]); \
|
| 68 |
+
acc.s2 += dot(a_reg.scdef, b_lm[lm_offset + 98]); \
|
| 69 |
+
acc.s3 += dot(a_reg.scdef, b_lm[lm_offset + 99]); \
|
| 70 |
+
acc.s4 += dot(a_reg.scdef, b_lm[lm_offset + 100]); \
|
| 71 |
+
acc.s5 += dot(a_reg.scdef, b_lm[lm_offset + 101]); \
|
| 72 |
+
acc.s6 += dot(a_reg.scdef, b_lm[lm_offset + 102]); \
|
| 73 |
+
acc.s7 += dot(a_reg.scdef, b_lm[lm_offset + 103]); \
|
| 74 |
+
acc.s8 += dot(a_reg.scdef, b_lm[lm_offset + 104]); \
|
| 75 |
+
acc.s9 += dot(a_reg.scdef, b_lm[lm_offset + 105]); \
|
| 76 |
+
acc.sa += dot(a_reg.scdef, b_lm[lm_offset + 106]); \
|
| 77 |
+
acc.sb += dot(a_reg.scdef, b_lm[lm_offset + 107]); \
|
| 78 |
+
acc.sc += dot(a_reg.scdef, b_lm[lm_offset + 108]); \
|
| 79 |
+
acc.sd += dot(a_reg.scdef, b_lm[lm_offset + 109]); \
|
| 80 |
+
acc.se += dot(a_reg.scdef, b_lm[lm_offset + 110]); \
|
| 81 |
+
acc.sf += dot(a_reg.scdef, b_lm[lm_offset + 111]); \
|
| 82 |
+
c_reg.lo += convert_float8(acc.lo); \
|
| 83 |
+
c_reg.hi += convert_float8(acc.hi); \
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 87 |
+
kernel void kernel_gemm_moe_q8_0_f32_ns(
|
| 88 |
+
__global char * src0_q, // flat q8_0 quants [n_expert*ne01*ne00]
|
| 89 |
+
__global half * src0_d, // flat q8_0 scales [n_expert*ne01*nb]
|
| 90 |
+
__read_only image1d_buffer_t src1, // reordered activations (f32)
|
| 91 |
+
__global uint * src2, // post-router out indices
|
| 92 |
+
__global ushort * src2_emap,// expert per tile
|
| 93 |
+
__write_only image1d_buffer_t dst,
|
| 94 |
+
__global int * total_tiles,
|
| 95 |
+
uint ne00,
|
| 96 |
+
uint ne01
|
| 97 |
+
) {
|
| 98 |
+
uint block_id_m = get_global_id(1); // m_tile
|
| 99 |
+
uint block_id_n = get_global_id(2); // n_tile
|
| 100 |
+
|
| 101 |
+
if (block_id_n >= total_tiles[0]) {
|
| 102 |
+
return;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
__private half16 reg_a;
|
| 106 |
+
__private float32 reg_c = (float32)(0);
|
| 107 |
+
__local half4 shared_b[128];
|
| 108 |
+
|
| 109 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 110 |
+
|
| 111 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 112 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 113 |
+
|
| 114 |
+
const uint nb = ne00 >> 5; // blocks per row (ne00/32)
|
| 115 |
+
const uint w_row = expert_id * ne01 + row + get_local_id(0); // this lane's output row
|
| 116 |
+
__global char * w_q = src0_q + (ulong)w_row * ne00; // char base for the row
|
| 117 |
+
__global half * w_d = src0_d + (ulong)w_row * nb; // scale base for the row
|
| 118 |
+
|
| 119 |
+
uint sub_block_id_m = get_local_id(0);
|
| 120 |
+
uint2 b_global_offset;
|
| 121 |
+
b_global_offset.x = ((sub_block_id_m & 3) << 2) + (sub_block_id_m >> 2) * ne00;
|
| 122 |
+
b_global_offset.y = b_global_offset.x + (16 * ne00);
|
| 123 |
+
uint2 b_local_offset;
|
| 124 |
+
b_local_offset.x = (sub_block_id_m & 3) * 32 + (sub_block_id_m >> 2);
|
| 125 |
+
b_local_offset.y = b_local_offset.x + 16;
|
| 126 |
+
|
| 127 |
+
// Loop along K axis, 32 elements per iteration, split into 2 sub-blocks.
|
| 128 |
+
for (uint step = 0; step < ne00; step += TILESIZE_K * 2) {
|
| 129 |
+
half s = w_d[step >> 5]; // one q8_0 scale per 32-element block
|
| 130 |
+
|
| 131 |
+
// First sub-block: 16 weights (16 chars = one uint4) at K=step
|
| 132 |
+
uint4 q8x16 = *((__global uint4 *)(w_q + step));
|
| 133 |
+
|
| 134 |
+
uint b_sub_offset = col * ne00 + step;
|
| 135 |
+
float8 bx8_f32;
|
| 136 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 137 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 138 |
+
half8 bx8_f16 = convert_half8(bx8_f32);
|
| 139 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 140 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 141 |
+
|
| 142 |
+
dequantize_q8_0(q8x16, reg_a, s);
|
| 143 |
+
|
| 144 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 145 |
+
|
| 146 |
+
half16 acc;
|
| 147 |
+
dotx16_reduce8(reg_a, shared_b, reg_c.lo, 0);
|
| 148 |
+
dotx16_reduce8(reg_a, shared_b, reg_c.hi, 16);
|
| 149 |
+
|
| 150 |
+
// Second sub-block: next 16 weights at K=step+16
|
| 151 |
+
uint half_step = step + TILESIZE_K;
|
| 152 |
+
q8x16 = *((__global uint4 *)(w_q + half_step));
|
| 153 |
+
b_sub_offset = col * ne00 + half_step;
|
| 154 |
+
|
| 155 |
+
bx8_f32.lo = read_imagef(src1, (b_sub_offset + b_global_offset.x) / 4);
|
| 156 |
+
bx8_f32.hi = read_imagef(src1, (b_sub_offset + b_global_offset.y) / 4);
|
| 157 |
+
bx8_f16 = convert_half8(bx8_f32);
|
| 158 |
+
shared_b[b_local_offset.x] = bx8_f16.lo;
|
| 159 |
+
shared_b[b_local_offset.y] = bx8_f16.hi;
|
| 160 |
+
|
| 161 |
+
dequantize_q8_0(q8x16, reg_a, s);
|
| 162 |
+
|
| 163 |
+
sub_group_barrier(CLK_LOCAL_MEM_FENCE);
|
| 164 |
+
|
| 165 |
+
dotx16_reduce8(reg_a, shared_b, reg_c.lo, 0);
|
| 166 |
+
dotx16_reduce8(reg_a, shared_b, reg_c.hi, 16);
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
if ((get_global_id(0) + block_id_m * TILESIZE_M) >= ne01) {
|
| 170 |
+
return;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
__local uint out_idx[TILESIZE_N];
|
| 174 |
+
|
| 175 |
+
if (get_local_id(0) < TILESIZE_N) {
|
| 176 |
+
uint idx = src2[block_id_n * TILESIZE_N + get_local_id(0)];
|
| 177 |
+
if (idx == 0xFFFFFFFF) {
|
| 178 |
+
idx = src2[block_id_n * TILESIZE_N + 0];
|
| 179 |
+
}
|
| 180 |
+
out_idx[get_local_id(0)] = idx * ne01;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 184 |
+
|
| 185 |
+
uint m_offset = row + get_local_id(0);
|
| 186 |
+
|
| 187 |
+
write_imagef(dst, out_idx[1] + m_offset, (reg_c.s1));
|
| 188 |
+
write_imagef(dst, out_idx[2] + m_offset, (reg_c.s2));
|
| 189 |
+
write_imagef(dst, out_idx[3] + m_offset, (reg_c.s3));
|
| 190 |
+
write_imagef(dst, out_idx[4] + m_offset, (reg_c.s4));
|
| 191 |
+
write_imagef(dst, out_idx[5] + m_offset, (reg_c.s5));
|
| 192 |
+
write_imagef(dst, out_idx[6] + m_offset, (reg_c.s6));
|
| 193 |
+
write_imagef(dst, out_idx[7] + m_offset, (reg_c.s7));
|
| 194 |
+
write_imagef(dst, out_idx[8] + m_offset, (reg_c.s8));
|
| 195 |
+
write_imagef(dst, out_idx[9] + m_offset, (reg_c.s9));
|
| 196 |
+
write_imagef(dst, out_idx[10] + m_offset, (reg_c.sa));
|
| 197 |
+
write_imagef(dst, out_idx[11] + m_offset, (reg_c.sb));
|
| 198 |
+
write_imagef(dst, out_idx[12] + m_offset, (reg_c.sc));
|
| 199 |
+
write_imagef(dst, out_idx[13] + m_offset, (reg_c.sd));
|
| 200 |
+
write_imagef(dst, out_idx[14] + m_offset, (reg_c.se));
|
| 201 |
+
write_imagef(dst, out_idx[15] + m_offset, (reg_c.sf));
|
| 202 |
+
write_imagef(dst, out_idx[16] + m_offset, (reg_c.sg));
|
| 203 |
+
write_imagef(dst, out_idx[17] + m_offset, (reg_c.sh));
|
| 204 |
+
write_imagef(dst, out_idx[18] + m_offset, (reg_c.si));
|
| 205 |
+
write_imagef(dst, out_idx[19] + m_offset, (reg_c.sj));
|
| 206 |
+
write_imagef(dst, out_idx[20] + m_offset, (reg_c.sk));
|
| 207 |
+
write_imagef(dst, out_idx[21] + m_offset, (reg_c.sl));
|
| 208 |
+
write_imagef(dst, out_idx[22] + m_offset, (reg_c.sm));
|
| 209 |
+
write_imagef(dst, out_idx[23] + m_offset, (reg_c.sn));
|
| 210 |
+
write_imagef(dst, out_idx[24] + m_offset, (reg_c.so));
|
| 211 |
+
write_imagef(dst, out_idx[25] + m_offset, (reg_c.sp));
|
| 212 |
+
write_imagef(dst, out_idx[26] + m_offset, (reg_c.sq));
|
| 213 |
+
write_imagef(dst, out_idx[27] + m_offset, (reg_c.sr));
|
| 214 |
+
write_imagef(dst, out_idx[28] + m_offset, (reg_c.ss));
|
| 215 |
+
write_imagef(dst, out_idx[29] + m_offset, (reg_c.st));
|
| 216 |
+
write_imagef(dst, out_idx[30] + m_offset, (reg_c.su));
|
| 217 |
+
write_imagef(dst, out_idx[31] + m_offset, (reg_c.sv));
|
| 218 |
+
|
| 219 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 220 |
+
write_imagef(dst, out_idx[0] + m_offset, (reg_c.s0));
|
| 221 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_moe_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
// Generic int8 dp4a MoE GEMM, specialized versions also exist
|
| 8 |
+
// MOE_QT:
|
| 9 |
+
// 4 (q4_K)/41(q4_1)/40(q4_0) NIBBLE image low nibbles -> EXP4
|
| 10 |
+
// 5 (q5_K)/51(q5_1)/50(q5_0) NIBBLE+HI image nibbles + qh high-bit plane
|
| 11 |
+
// 6 (q6_K) Q6 image nibbles + qh 2-bit -> SIGN6((nibble|hi2))
|
| 12 |
+
// 80(q8_0)/82(mxfp4) INT8 global int8 codes (mxfp4: convert applies kvalues LUT)
|
| 13 |
+
|
| 14 |
+
#define TILESIZE_M 64
|
| 15 |
+
#define TILESIZE_N 32
|
| 16 |
+
#define QK_K 256
|
| 17 |
+
|
| 18 |
+
#ifndef MOE_QT
|
| 19 |
+
#define MOE_QT 4
|
| 20 |
+
#endif
|
| 21 |
+
|
| 22 |
+
// 4 nibbles in low 16 bits of u -> 4 bytes (value 0..15)
|
| 23 |
+
#define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
|
| 24 |
+
(((uint)((u) & 0x00F0u)) << 4) | \
|
| 25 |
+
(((uint)((u) & 0x0F00u)) << 8) | \
|
| 26 |
+
(((uint)((u) & 0xF000u)) << 12) )
|
| 27 |
+
// 4 2-bit highs in byte b -> 4 bytes, bits 4-5 (q6_K)
|
| 28 |
+
#define EXP2(b) ( (((uint)((b) & 0x03u)) << 4) | \
|
| 29 |
+
(((uint)((b) & 0x0Cu)) << 10) | \
|
| 30 |
+
(((uint)((b) & 0x30u)) << 16) | \
|
| 31 |
+
(((uint)((b) & 0xC0u)) << 22) )
|
| 32 |
+
|
| 33 |
+
// q6 (0..63) -> (q6-32) signed int8/byte (no inter-byte carry)
|
| 34 |
+
inline uint SIGN6(uint q6p){ uint x=q6p^0x20202020u; uint s=x&0x20202020u; return x|(s<<1)|(s<<2); }
|
| 35 |
+
|
| 36 |
+
// 4 high bits (one per element, in bits 0..3 of h) -> bit4 of each of 4 bytes (5-bit hi)
|
| 37 |
+
#define EXP1(h) ( (((uint)((h) & 0x1u)) << 4) | \
|
| 38 |
+
(((uint)((h) & 0x2u)) << 11) | \
|
| 39 |
+
(((uint)((h) & 0x4u)) << 18) | \
|
| 40 |
+
(((uint)((h) & 0x8u)) << 25) )
|
| 41 |
+
|
| 42 |
+
// per-type weight params + per-32-step unpack into qw[8] (8 int8 uints)
|
| 43 |
+
#if MOE_QT == 4 || MOE_QT == 41 || MOE_QT == 40
|
| 44 |
+
#define WEIGHT_PARAMS __read_only image1d_buffer_t src0_q,
|
| 45 |
+
#define LOAD_QW(step, sub) \
|
| 46 |
+
uint qw[8]; { \
|
| 47 |
+
const uint qoff0 = row + ((ne01*(step))>>3) + ((expert_id*ne00*ne01)>>3); \
|
| 48 |
+
const uint qoff1 = row + ((ne01*((step)+16))>>3) + ((expert_id*ne00*ne01)>>3); \
|
| 49 |
+
const uint r0=read_imageui(src0_q,qoff0+lid).x, r1=read_imageui(src0_q,qoff0+lid+ne01).x; \
|
| 50 |
+
const uint r2=read_imageui(src0_q,qoff1+lid).x, r3=read_imageui(src0_q,qoff1+lid+ne01).x; \
|
| 51 |
+
qw[0]=EXP4(r0); qw[1]=EXP4(r0>>16); qw[2]=EXP4(r1); qw[3]=EXP4(r1>>16); \
|
| 52 |
+
qw[4]=EXP4(r2); qw[5]=EXP4(r2>>16); qw[6]=EXP4(r3); qw[7]=EXP4(r3>>16); }
|
| 53 |
+
|
| 54 |
+
#elif MOE_QT == 5 || MOE_QT == 51 || MOE_QT == 50
|
| 55 |
+
// low nibbles via image (q4_K layout) + high-bit plane src0_qh: 1 uint per 32-block
|
| 56 |
+
// (bit i = high bit of element i). qh laid out [expert][block][row] to match the
|
| 57 |
+
// existing q5_0 trans4 convert
|
| 58 |
+
#define WEIGHT_PARAMS __read_only image1d_buffer_t src0_q, __global uint * src0_qh,
|
| 59 |
+
#define LOAD_QW(step, sub) \
|
| 60 |
+
uint qw[8]; { \
|
| 61 |
+
const uint qoff0 = row + ((ne01*(step))>>3) + ((expert_id*ne00*ne01)>>3); \
|
| 62 |
+
const uint qoff1 = row + ((ne01*((step)+16))>>3) + ((expert_id*ne00*ne01)>>3); \
|
| 63 |
+
const uint r0=read_imageui(src0_q,qoff0+lid).x, r1=read_imageui(src0_q,qoff0+lid+ne01).x; \
|
| 64 |
+
const uint r2=read_imageui(src0_q,qoff1+lid).x, r3=read_imageui(src0_q,qoff1+lid+ne01).x; \
|
| 65 |
+
const uint h = src0_qh[row_idx + (sub)*ne01 + expert_id*(ne00>>5)*ne01]; \
|
| 66 |
+
qw[0]=EXP4(r0)|EXP1(h); qw[1]=EXP4(r0>>16)|EXP1(h>>4); \
|
| 67 |
+
qw[2]=EXP4(r1)|EXP1(h>>8); qw[3]=EXP4(r1>>16)|EXP1(h>>12); \
|
| 68 |
+
qw[4]=EXP4(r2)|EXP1(h>>16); qw[5]=EXP4(r2>>16)|EXP1(h>>20); \
|
| 69 |
+
qw[6]=EXP4(r3)|EXP1(h>>24); qw[7]=EXP4(r3>>16)|EXP1(h>>28); }
|
| 70 |
+
|
| 71 |
+
#elif MOE_QT == 6
|
| 72 |
+
#define WEIGHT_PARAMS __read_only image1d_buffer_t src0_ql, __global uint * src0_qh,
|
| 73 |
+
#define LOAD_QW(step, sub) \
|
| 74 |
+
uint qw[8]; { \
|
| 75 |
+
const uint qoff0 = row + ((ne01*(step))>>3) + ((expert_id*ne00*ne01)>>3); \
|
| 76 |
+
const uint qoff1 = row + ((ne01*((step)+16))>>3) + ((expert_id*ne00*ne01)>>3); \
|
| 77 |
+
const uint r0=read_imageui(src0_ql,qoff0+lid).x, r1=read_imageui(src0_ql,qoff0+lid+ne01).x; \
|
| 78 |
+
const uint r2=read_imageui(src0_ql,qoff1+lid).x, r3=read_imageui(src0_ql,qoff1+lid+ne01).x; \
|
| 79 |
+
const uint qhb = row + ((sub)*2)*ne01 + expert_id*((ne00>>5)*2)*ne01 + lid; \
|
| 80 |
+
const uint qh1=src0_qh[qhb], qh2=src0_qh[qhb+ne01]; \
|
| 81 |
+
qw[0]=SIGN6(EXP4(r0)|EXP2(qh1&0xFFu)); qw[1]=SIGN6(EXP4(r0>>16)|EXP2((qh1>>8)&0xFFu)); \
|
| 82 |
+
qw[2]=SIGN6(EXP4(r1)|EXP2((qh1>>16)&0xFFu)); qw[3]=SIGN6(EXP4(r1>>16)|EXP2((qh1>>24)&0xFFu)); \
|
| 83 |
+
qw[4]=SIGN6(EXP4(r2)|EXP2(qh2&0xFFu)); qw[5]=SIGN6(EXP4(r2>>16)|EXP2((qh2>>8)&0xFFu)); \
|
| 84 |
+
qw[6]=SIGN6(EXP4(r3)|EXP2((qh2>>16)&0xFFu)); qw[7]=SIGN6(EXP4(r3>>16)|EXP2((qh2>>24)&0xFFu)); }
|
| 85 |
+
|
| 86 |
+
#elif MOE_QT == 80 || MOE_QT == 82
|
| 87 |
+
// 8-bit direct: int8 codes 8 uints / 32-block, [expert][row][8*sub]. mxfp4: the
|
| 88 |
+
// convert resolves kvalues_mxfp4[nibble] -> int8 and stores the e8m0_half scale.
|
| 89 |
+
#define WEIGHT_PARAMS __global uint * src0_q8,
|
| 90 |
+
#define LOAD_QW(step, sub) \
|
| 91 |
+
uint qw[8]; { \
|
| 92 |
+
const uint qb = (expert_id*ne01 + row_idx)*(ne00>>2) + (sub)*8; \
|
| 93 |
+
qw[0]=src0_q8[qb+0]; qw[1]=src0_q8[qb+1]; qw[2]=src0_q8[qb+2]; qw[3]=src0_q8[qb+3]; \
|
| 94 |
+
qw[4]=src0_q8[qb+4]; qw[5]=src0_q8[qb+5]; qw[6]=src0_q8[qb+6]; qw[7]=src0_q8[qb+7]; }
|
| 95 |
+
#else
|
| 96 |
+
#error "unknown MOE_QT"
|
| 97 |
+
#endif
|
| 98 |
+
|
| 99 |
+
inline int dp4a4(uint w0,uint w1,uint w2,uint w3,uint a0,uint a1,uint a2,uint a3){
|
| 100 |
+
int r=0; r=dot_acc_sat_4x8packed_ss_int(w0,a0,r); r=dot_acc_sat_4x8packed_ss_int(w1,a1,r);
|
| 101 |
+
r=dot_acc_sat_4x8packed_ss_int(w2,a2,r); r=dot_acc_sat_4x8packed_ss_int(w3,a3,r); return r; }
|
| 102 |
+
|
| 103 |
+
// One token's two-half dp4a + uniform scale/min epilogue into acc[t].
|
| 104 |
+
#define MOE_DP4A_T(t) do { \
|
| 105 |
+
const int raw1 = dp4a4(qw[0],qw[1],qw[2],qw[3], sh_qa[t][0],sh_qa[t][1],sh_qa[t][2],sh_qa[t][3]); \
|
| 106 |
+
const int raw2 = dp4a4(qw[4],qw[5],qw[6],qw[7], sh_qa[t][4],sh_qa[t][5],sh_qa[t][6],sh_qa[t][7]); \
|
| 107 |
+
const float a_d = (float)sh_d[t]; \
|
| 108 |
+
acc[t] += sc0*a_d*(float)raw1 + sc1*a_d*(float)raw2 - mn*(float)sh_s[t]; \
|
| 109 |
+
} while (0)
|
| 110 |
+
|
| 111 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 112 |
+
kernel void kernel_gemm_moe_q8_1_dp4a(
|
| 113 |
+
WEIGHT_PARAMS // per-type native weight buffer(s)
|
| 114 |
+
__global half * src0_scale,// uniform f16 16/superblock (per-16), [expert,row]
|
| 115 |
+
__global half * src0_min, // uniform f16 8/superblock (per-32), [expert,row]
|
| 116 |
+
__global uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem)
|
| 117 |
+
__global half * src1_da, // q8_1 per-block scale [tok_slot * ne00/32]
|
| 118 |
+
__global half * src1_sa, // q8_1 per-block sum*d [tok_slot * ne00/32]
|
| 119 |
+
__global uint * src2, // post-router (orig out positions)
|
| 120 |
+
__global ushort * src2_emap, // tile -> expert id
|
| 121 |
+
__write_only image1d_buffer_t dst,
|
| 122 |
+
__global int * total_tiles,
|
| 123 |
+
uint ne00,
|
| 124 |
+
uint ne01,
|
| 125 |
+
int is_ragged,
|
| 126 |
+
int has_min // 0 for symmetric types (q8_0/q6_K/q4_0/...): skip min read
|
| 127 |
+
) {
|
| 128 |
+
const uint block_id_m = get_global_id(1);
|
| 129 |
+
const uint block_id_n = get_global_id(2);
|
| 130 |
+
if (block_id_n >= total_tiles[0]) return;
|
| 131 |
+
|
| 132 |
+
const uint lid = get_local_id(0); // 0..63 -> output row within M-tile
|
| 133 |
+
const ushort expert_id = src2_emap[block_id_n];
|
| 134 |
+
const uint row = block_id_m * TILESIZE_M;
|
| 135 |
+
const uint col = block_id_n * TILESIZE_N;
|
| 136 |
+
const uint row_idx = row + lid;
|
| 137 |
+
|
| 138 |
+
// Scale/min are laid out FLAT per-32-block (2 per-16-segment scales + 1 min per
|
| 139 |
+
// 32-block), so K only needs to be a multiple of 32 — works for the 32-block
|
| 140 |
+
// types (q8_0/q5_0/q4_0/...) as well as the K-quants (K%256==0, same bytes).
|
| 141 |
+
const uint nblk32 = ne00 / 32;
|
| 142 |
+
const uint sc_per_row = nblk32 * 2;
|
| 143 |
+
const uint mn_per_row = nblk32;
|
| 144 |
+
const uint ne00_u = ne00 >> 2;
|
| 145 |
+
const uint ne00_b = ne00 >> 5;
|
| 146 |
+
|
| 147 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 148 |
+
__local half sh_d[TILESIZE_N];
|
| 149 |
+
__local half sh_s[TILESIZE_N];
|
| 150 |
+
|
| 151 |
+
__local uint sh_src2[TILESIZE_N];
|
| 152 |
+
__local int sh_nreal;
|
| 153 |
+
if (lid < TILESIZE_N) sh_src2[lid] = src2[col + lid];
|
| 154 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 155 |
+
if (lid == 0) {
|
| 156 |
+
int nr = TILESIZE_N;
|
| 157 |
+
if (is_ragged) { nr = 0;
|
| 158 |
+
#pragma unroll
|
| 159 |
+
for (int t = 0; t < TILESIZE_N; ++t) if (sh_src2[t] != 0xFFFFFFFFu) ++nr; }
|
| 160 |
+
sh_nreal = nr;
|
| 161 |
+
}
|
| 162 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 163 |
+
const int n_real = sh_nreal;
|
| 164 |
+
|
| 165 |
+
float acc[TILESIZE_N];
|
| 166 |
+
#pragma unroll
|
| 167 |
+
for (int t = 0; t < TILESIZE_N; ++t) acc[t] = 0.0f;
|
| 168 |
+
|
| 169 |
+
for (uint step = 0; step < ne00; step += 32) {
|
| 170 |
+
const uint sub = step >> 5; // 32-block index along K
|
| 171 |
+
|
| 172 |
+
// uniform pre-decoded scale (2 per-16-seg) + min (1) for this row, this 32-block
|
| 173 |
+
__global half * scl = src0_scale + (expert_id*ne01 + row_idx)*sc_per_row + sub*2;
|
| 174 |
+
const float sc0 = (float)scl[0];
|
| 175 |
+
const float sc1 = (float)scl[1];
|
| 176 |
+
float mn = 0.0f;
|
| 177 |
+
if (has_min) mn = (float)src0_min[(expert_id*ne01 + row_idx)*mn_per_row + sub];
|
| 178 |
+
|
| 179 |
+
LOAD_QW(step, sub)
|
| 180 |
+
|
| 181 |
+
const uint stage_lim = (uint)n_real * 8;
|
| 182 |
+
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
| 183 |
+
const uint t = idx >> 3, u = idx & 7;
|
| 184 |
+
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
| 185 |
+
}
|
| 186 |
+
if (lid < (uint)n_real) {
|
| 187 |
+
sh_d[lid] = src1_da[(col + lid) * ne00_b + sub];
|
| 188 |
+
sh_s[lid] = src1_sa[(col + lid) * ne00_b + sub];
|
| 189 |
+
}
|
| 190 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 191 |
+
|
| 192 |
+
if (n_real == TILESIZE_N) {
|
| 193 |
+
#pragma unroll
|
| 194 |
+
for (int t = 0; t < TILESIZE_N; ++t) { MOE_DP4A_T(t); }
|
| 195 |
+
} else {
|
| 196 |
+
#pragma unroll 4
|
| 197 |
+
for (int t = 0; t < n_real; ++t) { MOE_DP4A_T(t); }
|
| 198 |
+
}
|
| 199 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
if (row_idx >= ne01) return;
|
| 203 |
+
|
| 204 |
+
__local uint out_idx[TILESIZE_N];
|
| 205 |
+
if (lid < TILESIZE_N) {
|
| 206 |
+
uint idx = sh_src2[lid];
|
| 207 |
+
if (idx == 0xFFFFFFFF) idx = sh_src2[0];
|
| 208 |
+
out_idx[lid] = idx * ne01;
|
| 209 |
+
}
|
| 210 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 211 |
+
|
| 212 |
+
const uint m_offset = row + lid;
|
| 213 |
+
if (n_real == TILESIZE_N) {
|
| 214 |
+
#pragma unroll
|
| 215 |
+
for (int t = 1; t < TILESIZE_N; ++t) write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 216 |
+
barrier(CLK_GLOBAL_MEM_FENCE);
|
| 217 |
+
write_imagef(dst, out_idx[0] + m_offset, acc[0]);
|
| 218 |
+
} else {
|
| 219 |
+
for (int t = 0; t < n_real; ++t) write_imagef(dst, out_idx[t] + m_offset, acc[t]);
|
| 220 |
+
}
|
| 221 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_iq4_nl_f32.cl
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#define ADRENO_GPU 1
|
| 6 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 7 |
+
#endif
|
| 8 |
+
|
| 9 |
+
constant half kvalues_iq4nl[16] = {
|
| 10 |
+
(half)-127.f, (half)-104.f, (half)-83.f, (half)-65.f,
|
| 11 |
+
(half) -49.f, (half) -35.f, (half)-22.f, (half)-10.f,
|
| 12 |
+
(half) 1.f, (half) 13.f, (half) 25.f, (half) 38.f,
|
| 13 |
+
(half) 53.f, (half) 69.f, (half) 89.f, (half)113.f
|
| 14 |
+
};
|
| 15 |
+
|
| 16 |
+
// Packed LUT: 2 FP16 values per uint, 8 unique constant loads instead of 16
|
| 17 |
+
constant uint iq4nl_packed[8] = {
|
| 18 |
+
0xD680D7F0u, // idx 0,1: -127, -104
|
| 19 |
+
0xD410D530u, // idx 2,3: -83, -65
|
| 20 |
+
0xD060D220u, // idx 4,5: -49, -35
|
| 21 |
+
0xC900CD80u, // idx 6,7: -22, -10
|
| 22 |
+
0x4A803C00u, // idx 8,9: 1, 13
|
| 23 |
+
0x50C04E40u, // idx 10,11: 25, 38
|
| 24 |
+
0x545052A0u, // idx 12,13: 53, 69
|
| 25 |
+
0x57105590u // idx 14,15: 89, 113
|
| 26 |
+
};
|
| 27 |
+
|
| 28 |
+
// Packed dequant: 1 uint constant load (8-way divergence) + shift + as_half
|
| 29 |
+
#define IQ4_NL_DEQUANT(nibble) as_half((ushort)(iq4nl_packed[(nibble) >> 1] >> (((nibble) & 1u) << 4)))
|
| 30 |
+
|
| 31 |
+
#ifdef ADRENO_GPU
|
| 32 |
+
REQD_SUBGROUP_SIZE_128
|
| 33 |
+
#endif
|
| 34 |
+
|
| 35 |
+
kernel void kernel_gemm_noshuffle_iq4_nl_f32(
|
| 36 |
+
global const ushort * src0_q,
|
| 37 |
+
global const half * src0_d,
|
| 38 |
+
read_only image1d_buffer_t src1,
|
| 39 |
+
global float * dst,
|
| 40 |
+
ulong offsetd,
|
| 41 |
+
int m,
|
| 42 |
+
int n,
|
| 43 |
+
int k,
|
| 44 |
+
int n_no_padding
|
| 45 |
+
) {
|
| 46 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 47 |
+
|
| 48 |
+
int m_4 = m >> 2;
|
| 49 |
+
int n_4 = n >> 2;
|
| 50 |
+
|
| 51 |
+
int gy = get_global_id(0);
|
| 52 |
+
int gx = get_global_id(1);
|
| 53 |
+
int gx_2 = gx << 2;
|
| 54 |
+
|
| 55 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
| 56 |
+
half8 B;
|
| 57 |
+
half4 dequantized_weights;
|
| 58 |
+
|
| 59 |
+
global const ushort * weight_ptr = src0_q + gx_2;
|
| 60 |
+
global const half * scale_ptr = src0_d + gx_2;
|
| 61 |
+
|
| 62 |
+
for (int i = 0; i < k; i += 4) {
|
| 63 |
+
B.s0123 = read_imageh(src1, gy*2 + (i)*(n_4));
|
| 64 |
+
B.s4567 = read_imageh(src1, gy*2 + (i)*(n_4)+1);
|
| 65 |
+
|
| 66 |
+
ushort4 bits4 = vload4(0, weight_ptr + (i/4)*(m));
|
| 67 |
+
|
| 68 |
+
half4 scale = vload4(0, scale_ptr + (i/32)*(m));
|
| 69 |
+
|
| 70 |
+
// j=0
|
| 71 |
+
dequantized_weights.s0 = IQ4_NL_DEQUANT(bits4.s0 & 0x000Fu) * scale.s0;
|
| 72 |
+
dequantized_weights.s1 = IQ4_NL_DEQUANT(bits4.s1 & 0x000Fu) * scale.s1;
|
| 73 |
+
dequantized_weights.s2 = IQ4_NL_DEQUANT(bits4.s2 & 0x000Fu) * scale.s2;
|
| 74 |
+
dequantized_weights.s3 = IQ4_NL_DEQUANT(bits4.s3 & 0x000Fu) * scale.s3;
|
| 75 |
+
c0 += B * dequantized_weights.s0;
|
| 76 |
+
c1 += B * dequantized_weights.s1;
|
| 77 |
+
c2 += B * dequantized_weights.s2;
|
| 78 |
+
c3 += B * dequantized_weights.s3;
|
| 79 |
+
|
| 80 |
+
// j=1
|
| 81 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+1)*(n_4));
|
| 82 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+1)*(n_4)+1);
|
| 83 |
+
dequantized_weights.s0 = IQ4_NL_DEQUANT((bits4.s0 >> 4) & 0x000Fu) * scale.s0;
|
| 84 |
+
dequantized_weights.s1 = IQ4_NL_DEQUANT((bits4.s1 >> 4) & 0x000Fu) * scale.s1;
|
| 85 |
+
dequantized_weights.s2 = IQ4_NL_DEQUANT((bits4.s2 >> 4) & 0x000Fu) * scale.s2;
|
| 86 |
+
dequantized_weights.s3 = IQ4_NL_DEQUANT((bits4.s3 >> 4) & 0x000Fu) * scale.s3;
|
| 87 |
+
c0 += B * dequantized_weights.s0;
|
| 88 |
+
c1 += B * dequantized_weights.s1;
|
| 89 |
+
c2 += B * dequantized_weights.s2;
|
| 90 |
+
c3 += B * dequantized_weights.s3;
|
| 91 |
+
|
| 92 |
+
// j=2
|
| 93 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+2)*(n_4));
|
| 94 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+2)*(n_4)+1);
|
| 95 |
+
dequantized_weights.s0 = IQ4_NL_DEQUANT((bits4.s0 >> 8) & 0x000Fu) * scale.s0;
|
| 96 |
+
dequantized_weights.s1 = IQ4_NL_DEQUANT((bits4.s1 >> 8) & 0x000Fu) * scale.s1;
|
| 97 |
+
dequantized_weights.s2 = IQ4_NL_DEQUANT((bits4.s2 >> 8) & 0x000Fu) * scale.s2;
|
| 98 |
+
dequantized_weights.s3 = IQ4_NL_DEQUANT((bits4.s3 >> 8) & 0x000Fu) * scale.s3;
|
| 99 |
+
c0 += B * dequantized_weights.s0;
|
| 100 |
+
c1 += B * dequantized_weights.s1;
|
| 101 |
+
c2 += B * dequantized_weights.s2;
|
| 102 |
+
c3 += B * dequantized_weights.s3;
|
| 103 |
+
|
| 104 |
+
// j=3
|
| 105 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+3)*(n_4));
|
| 106 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+3)*(n_4)+1);
|
| 107 |
+
dequantized_weights.s0 = IQ4_NL_DEQUANT((bits4.s0 >> 12) & 0x000Fu) * scale.s0;
|
| 108 |
+
dequantized_weights.s1 = IQ4_NL_DEQUANT((bits4.s1 >> 12) & 0x000Fu) * scale.s1;
|
| 109 |
+
dequantized_weights.s2 = IQ4_NL_DEQUANT((bits4.s2 >> 12) & 0x000Fu) * scale.s2;
|
| 110 |
+
dequantized_weights.s3 = IQ4_NL_DEQUANT((bits4.s3 >> 12) & 0x000Fu) * scale.s3;
|
| 111 |
+
c0 += B * dequantized_weights.s0;
|
| 112 |
+
c1 += B * dequantized_weights.s1;
|
| 113 |
+
c2 += B * dequantized_weights.s2;
|
| 114 |
+
c3 += B * dequantized_weights.s3;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
int idx = (gy<<3)*m + (gx<<2);
|
| 118 |
+
|
| 119 |
+
if(idx+3 < m*n_no_padding){
|
| 120 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 121 |
+
idx += m;
|
| 122 |
+
}
|
| 123 |
+
if(idx+3 < m*n_no_padding){
|
| 124 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 125 |
+
idx += m;
|
| 126 |
+
}
|
| 127 |
+
if(idx+3 < m*n_no_padding){
|
| 128 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 129 |
+
idx += m;
|
| 130 |
+
}
|
| 131 |
+
if(idx+3 < m*n_no_padding){
|
| 132 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 133 |
+
idx += m;
|
| 134 |
+
}
|
| 135 |
+
if(idx+3 < m*n_no_padding){
|
| 136 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 137 |
+
idx += m;
|
| 138 |
+
}
|
| 139 |
+
if(idx+3 < m*n_no_padding){
|
| 140 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 141 |
+
idx += m;
|
| 142 |
+
}
|
| 143 |
+
if(idx+3 < m*n_no_padding){
|
| 144 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 145 |
+
idx += m;
|
| 146 |
+
}
|
| 147 |
+
if(idx+3 < m*n_no_padding){
|
| 148 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 149 |
+
}
|
| 150 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_iq4_nl_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
// Weight layout, feature-major:
|
| 8 |
+
// src0_q[row + (k/4)*m] ushort = 4 nibbles (K = 4*grp .. +3)
|
| 9 |
+
// src0_d[row + (k/32)*m] half = per-32-block scale
|
| 10 |
+
|
| 11 |
+
#define TILESIZE_N 32
|
| 12 |
+
|
| 13 |
+
// IQ4_NL non-linear codebook as signed int8, packed 4 codes per uint.
|
| 14 |
+
// divergent nibble lookups read a small __constant uint array + shift,
|
| 15 |
+
// never a byte array because byte-indexed __constant loads serialize on Adreno and tank perf
|
| 16 |
+
// idx 0-3: -127,-104,-83,-65 = 0x81,0x98,0xAD,0xBF
|
| 17 |
+
// idx 4-7: -49,-35,-22,-10 = 0xCF,0xDD,0xEA,0xF6
|
| 18 |
+
// idx 8-11: 1, 13, 25, 38 = 0x01,0x0D,0x19,0x26
|
| 19 |
+
// idx 12-15: 53, 69, 89,113 = 0x35,0x45,0x59,0x71
|
| 20 |
+
__constant uint kvalues_iq4nl_i8x4[4] = {
|
| 21 |
+
0xBFAD9881u, 0xF6EADDCFu, 0x26190D01u, 0x71594535u
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
// nibble (0..15) -> its codebook byte in the low 8 bits.
|
| 25 |
+
inline uint iq4nl_code(uint n) {
|
| 26 |
+
return (kvalues_iq4nl_i8x4[n >> 2] >> ((n & 3u) * 8u)) & 0xFFu;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
// 4 nibbles in low 16 bits of u -> 4 codebook int8, packed for dp4a.
|
| 30 |
+
inline uint iq4nl_pack(ushort u) {
|
| 31 |
+
return iq4nl_code((uint)( u & 0xF))
|
| 32 |
+
| (iq4nl_code((uint)((u >> 4) & 0xF)) << 8)
|
| 33 |
+
| (iq4nl_code((uint)((u >> 8) & 0xF)) << 16)
|
| 34 |
+
| (iq4nl_code((uint)((u >> 12) & 0xF)) << 24);
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
inline int dot8_q8a(uint8 qw, __local const uint * a) {
|
| 38 |
+
int r = 0;
|
| 39 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
|
| 40 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
|
| 41 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
|
| 42 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
|
| 43 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
|
| 44 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
|
| 45 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
|
| 46 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
|
| 47 |
+
return r;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 51 |
+
kernel void kernel_gemm_noshuffle_iq4_nl_q8_1_dp4a(
|
| 52 |
+
__global const ushort * src0_q, // IQ4_NL nibbles (4/ushort, feature-major)
|
| 53 |
+
__global const half * src0_d, // per-32-block scale, feature-major
|
| 54 |
+
__global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
|
| 55 |
+
__global const half * src1_da, // q8_1 per-block scale [N, K/32]
|
| 56 |
+
__global float * dst,
|
| 57 |
+
ulong offsetd,
|
| 58 |
+
int m, // output features (rows)
|
| 59 |
+
int n_no_padding, // tokens (cols)
|
| 60 |
+
int k // K (== ne00)
|
| 61 |
+
) {
|
| 62 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 63 |
+
|
| 64 |
+
const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
|
| 65 |
+
const uint block_id_m = get_global_id(1);
|
| 66 |
+
const uint block_id_n = get_global_id(2);
|
| 67 |
+
|
| 68 |
+
const uint row = block_id_m * 64 + lid;
|
| 69 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 70 |
+
const bool row_valid = row < (uint)m;
|
| 71 |
+
const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
|
| 72 |
+
|
| 73 |
+
const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
|
| 74 |
+
const uint k_b = (uint)k >> 5; // blocks-of-32 along K
|
| 75 |
+
|
| 76 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 77 |
+
__local half sh_d[TILESIZE_N];
|
| 78 |
+
|
| 79 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 80 |
+
float4 acc[NGROUPS];
|
| 81 |
+
#pragma unroll
|
| 82 |
+
for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
|
| 83 |
+
|
| 84 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 85 |
+
const uint sub = step >> 5;
|
| 86 |
+
|
| 87 |
+
const float d_w = (float)src0_d[rrow + sub * (uint)m];
|
| 88 |
+
|
| 89 |
+
// 8 weight uints (32 codebook int8) for this row, this 32-block.
|
| 90 |
+
const uint qsbase = rrow + (step >> 2) * (uint)m;
|
| 91 |
+
uint8 qw;
|
| 92 |
+
qw.s0 = iq4nl_pack(src0_q[qsbase + 0 * m]);
|
| 93 |
+
qw.s1 = iq4nl_pack(src0_q[qsbase + 1 * m]);
|
| 94 |
+
qw.s2 = iq4nl_pack(src0_q[qsbase + 2 * m]);
|
| 95 |
+
qw.s3 = iq4nl_pack(src0_q[qsbase + 3 * m]);
|
| 96 |
+
qw.s4 = iq4nl_pack(src0_q[qsbase + 4 * m]);
|
| 97 |
+
qw.s5 = iq4nl_pack(src0_q[qsbase + 5 * m]);
|
| 98 |
+
qw.s6 = iq4nl_pack(src0_q[qsbase + 6 * m]);
|
| 99 |
+
qw.s7 = iq4nl_pack(src0_q[qsbase + 7 * m]);
|
| 100 |
+
|
| 101 |
+
// cooperatively stage the 32-token x 32-K int8 activations to lm
|
| 102 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 103 |
+
const uint t = idx >> 3;
|
| 104 |
+
const uint u = idx & 7;
|
| 105 |
+
const uint c = col_base + t;
|
| 106 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 107 |
+
}
|
| 108 |
+
if (lid < TILESIZE_N) {
|
| 109 |
+
const uint c = col_base + lid;
|
| 110 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 111 |
+
}
|
| 112 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 113 |
+
|
| 114 |
+
#define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
|
| 115 |
+
#pragma unroll
|
| 116 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 117 |
+
const int b = g * 4;
|
| 118 |
+
float4 rf;
|
| 119 |
+
rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
|
| 120 |
+
rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
|
| 121 |
+
acc[g] += d_w * LD4(sh_d, b) * rf;
|
| 122 |
+
}
|
| 123 |
+
#undef LD4
|
| 124 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
if (!row_valid) {
|
| 128 |
+
return;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
// dst is [token, feature] row-major (stride m): dst[col*m + row].
|
| 132 |
+
#pragma unroll
|
| 133 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 134 |
+
const uint b = (uint)(g * 4);
|
| 135 |
+
const float4 a = acc[g];
|
| 136 |
+
const uint c0 = col_base + b;
|
| 137 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 138 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 139 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 140 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 141 |
+
}
|
| 142 |
+
#undef NGROUPS
|
| 143 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q1_0_f32.cl
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
// each work-item computes a 4 (rows of A / m) x 8 (cols of B / n) output tile.
|
| 11 |
+
#ifdef ADRENO_GPU
|
| 12 |
+
REQD_SUBGROUP_SIZE_128
|
| 13 |
+
#endif
|
| 14 |
+
kernel void kernel_gemm_noshuffle_q1_0_f32(
|
| 15 |
+
global const uint * src0_q,
|
| 16 |
+
global const half * src0_d,
|
| 17 |
+
read_only image1d_buffer_t src1,
|
| 18 |
+
global float * dst,
|
| 19 |
+
int k,
|
| 20 |
+
int m,
|
| 21 |
+
int n,
|
| 22 |
+
int n_no_padding,
|
| 23 |
+
ulong offsetd
|
| 24 |
+
) {
|
| 25 |
+
int n_4 = n >> 2;
|
| 26 |
+
|
| 27 |
+
int gy = get_global_id(0);
|
| 28 |
+
int gx = get_global_id(1);
|
| 29 |
+
int gx_2 = gx << 2;
|
| 30 |
+
dst = (global float *)((global char*)dst + offsetd);
|
| 31 |
+
|
| 32 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
| 33 |
+
half8 B;
|
| 34 |
+
|
| 35 |
+
global const uint* wptr = src0_q + gx_2;
|
| 36 |
+
global const half* sptr = src0_d + gx_2;
|
| 37 |
+
|
| 38 |
+
// 32 weights per uint32, 128 weights (one block / one scale) per 4 uint32.
|
| 39 |
+
for (int i = 0; i < k; i += 32) {
|
| 40 |
+
uint4 pack4 = vload4(0, wptr + (i / 32) * m); // 4 rows, 32 K-values each
|
| 41 |
+
half4 scale = vload4(0, sptr + (i / 128) * m); // 4 rows, one scale per 128
|
| 42 |
+
|
| 43 |
+
for (int j = 0; j < 32; ++j) {
|
| 44 |
+
B.s0123 = read_imageh(src1, gy * 2 + (i + j) * n_4);
|
| 45 |
+
B.s4567 = read_imageh(src1, gy * 2 + (i + j) * n_4 + 1);
|
| 46 |
+
|
| 47 |
+
// sign bit -> +-1 (half arithmetic avoids unsigned underflow)
|
| 48 |
+
half4 wj = (half4)(
|
| 49 |
+
2.0h * (half)((pack4.s0 >> j) & 1u) - 1.0h,
|
| 50 |
+
2.0h * (half)((pack4.s1 >> j) & 1u) - 1.0h,
|
| 51 |
+
2.0h * (half)((pack4.s2 >> j) & 1u) - 1.0h,
|
| 52 |
+
2.0h * (half)((pack4.s3 >> j) & 1u) - 1.0h) * scale;
|
| 53 |
+
|
| 54 |
+
c0 += B * wj.s0;
|
| 55 |
+
c1 += B * wj.s1;
|
| 56 |
+
c2 += B * wj.s2;
|
| 57 |
+
c3 += B * wj.s3;
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
int idx = (gy << 3) * m + (gx << 2);
|
| 62 |
+
|
| 63 |
+
if(idx+3 < m*n_no_padding){
|
| 64 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 65 |
+
idx += m;
|
| 66 |
+
}
|
| 67 |
+
if(idx+3 < m*n_no_padding){
|
| 68 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 69 |
+
idx += m;
|
| 70 |
+
}
|
| 71 |
+
if(idx+3 < m*n_no_padding){
|
| 72 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 73 |
+
idx += m;
|
| 74 |
+
}
|
| 75 |
+
if(idx+3 < m*n_no_padding){
|
| 76 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 77 |
+
idx += m;
|
| 78 |
+
}
|
| 79 |
+
if(idx+3 < m*n_no_padding){
|
| 80 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 81 |
+
idx += m;
|
| 82 |
+
}
|
| 83 |
+
if(idx+3 < m*n_no_padding){
|
| 84 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 85 |
+
idx += m;
|
| 86 |
+
}
|
| 87 |
+
if(idx+3 < m*n_no_padding){
|
| 88 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 89 |
+
idx += m;
|
| 90 |
+
}
|
| 91 |
+
if(idx+3 < m*n_no_padding){
|
| 92 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 93 |
+
}
|
| 94 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_0_f32.cl
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// src0_q, src0_d, src1 are transposed as a preprocessing step
|
| 2 |
+
// 4-bit weights are transposed in groups of 4 (unsigned short int)
|
| 3 |
+
// consider weights originally "next to each other", now "on top of each other"
|
| 4 |
+
// each fiber computes a 8x4 tile of output elements
|
| 5 |
+
// using unshuffled weights
|
| 6 |
+
|
| 7 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 8 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 9 |
+
|
| 10 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 11 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 12 |
+
#define ADRENO_GPU 1
|
| 13 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 14 |
+
#endif
|
| 15 |
+
|
| 16 |
+
#ifdef ADRENO_GPU
|
| 17 |
+
REQD_SUBGROUP_SIZE_128
|
| 18 |
+
#endif
|
| 19 |
+
|
| 20 |
+
kernel void kernel_gemm_noshuffle_q4_0_f32(
|
| 21 |
+
global const ushort * src0_q, // quantized A
|
| 22 |
+
global const half * src0_d, // A scales
|
| 23 |
+
__read_only image1d_buffer_t src1, // B (1d image)
|
| 24 |
+
global float * dst, // C
|
| 25 |
+
int m, // M
|
| 26 |
+
int n, // N with padding
|
| 27 |
+
int k, // K
|
| 28 |
+
int n_no_padding // N without padding
|
| 29 |
+
) {
|
| 30 |
+
|
| 31 |
+
int m_4 = m >> 2;
|
| 32 |
+
int n_4 = n >> 2;
|
| 33 |
+
|
| 34 |
+
int gy = get_global_id(0);
|
| 35 |
+
int gx = get_global_id(1);
|
| 36 |
+
int gx_2 = gx << 2;
|
| 37 |
+
|
| 38 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0; // 8x4 output elements
|
| 39 |
+
half8 B; // registers for activations
|
| 40 |
+
half4 dequantized_weights; // registers for dequantized weights
|
| 41 |
+
__global const ushort* weight_ptr = src0_q + gx_2; // pointer for weights
|
| 42 |
+
__global const half* scale_ptr = src0_d + gx_2; // pointer for scales
|
| 43 |
+
|
| 44 |
+
for(int i=0; i<k; i+=4){ //loop through K dimension
|
| 45 |
+
|
| 46 |
+
B.s0123 = read_imageh(src1, gy*2 + (i)*(n_4));
|
| 47 |
+
B.s4567 = read_imageh(src1, gy*2 + (i)*(n_4)+1);
|
| 48 |
+
|
| 49 |
+
// keep (i/4) and (i/32) in parenthesis, rounds down
|
| 50 |
+
// load 4 consecutive groups of 4 weights
|
| 51 |
+
ushort4 bits4 = vload4(0, weight_ptr + (i/4)*(m)); // (i/4) because weights grouped in 4s
|
| 52 |
+
|
| 53 |
+
// load 4 consecutive scales
|
| 54 |
+
half4 scale = vload4(0, scale_ptr + (i/32)*(m));// (i/32) because 1 scale per 32 elements
|
| 55 |
+
|
| 56 |
+
// j=0
|
| 57 |
+
dequantized_weights.s0 = ((bits4.s0 & (0x000F)) - 8) * scale.s0; // dequantize a row of the 16 weights
|
| 58 |
+
dequantized_weights.s1 = ((bits4.s1 & (0x000F)) - 8) * scale.s1;
|
| 59 |
+
dequantized_weights.s2 = ((bits4.s2 & (0x000F)) - 8) * scale.s2;
|
| 60 |
+
dequantized_weights.s3 = ((bits4.s3 & (0x000F)) - 8) * scale.s3;
|
| 61 |
+
c0 += B * dequantized_weights.s0; // vector-scalar multiplication to accumulate
|
| 62 |
+
c1 += B * dequantized_weights.s1;
|
| 63 |
+
c2 += B * dequantized_weights.s2;
|
| 64 |
+
c3 += B * dequantized_weights.s3;
|
| 65 |
+
|
| 66 |
+
// j=1
|
| 67 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+1)*(n_4));
|
| 68 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+1)*(n_4)+1);
|
| 69 |
+
dequantized_weights.s0 = (((bits4.s0 & (0x00F0)) >> 4) - 8) * scale.s0; // dequantize a row of the 16 weights
|
| 70 |
+
dequantized_weights.s1 = (((bits4.s1 & (0x00F0)) >> 4) - 8) * scale.s1;
|
| 71 |
+
dequantized_weights.s2 = (((bits4.s2 & (0x00F0)) >> 4) - 8) * scale.s2;
|
| 72 |
+
dequantized_weights.s3 = (((bits4.s3 & (0x00F0)) >> 4) - 8) * scale.s3;
|
| 73 |
+
c0 += B * dequantized_weights.s0; //vector-scalar multiplication to accumulate
|
| 74 |
+
c1 += B * dequantized_weights.s1;
|
| 75 |
+
c2 += B * dequantized_weights.s2;
|
| 76 |
+
c3 += B * dequantized_weights.s3;
|
| 77 |
+
|
| 78 |
+
// j=2
|
| 79 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+2)*(n_4));
|
| 80 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+2)*(n_4)+1);
|
| 81 |
+
dequantized_weights.s0 = (((bits4.s0 & (0x0F00)) >> 8) - 8) * scale.s0; // dequantize a row of the 16 weights
|
| 82 |
+
dequantized_weights.s1 = (((bits4.s1 & (0x0F00)) >> 8) - 8) * scale.s1;
|
| 83 |
+
dequantized_weights.s2 = (((bits4.s2 & (0x0F00)) >> 8) - 8) * scale.s2;
|
| 84 |
+
dequantized_weights.s3 = (((bits4.s3 & (0x0F00)) >> 8) - 8) * scale.s3;
|
| 85 |
+
c0 += B * dequantized_weights.s0; // vector-scalar multiplication to accumulate
|
| 86 |
+
c1 += B * dequantized_weights.s1;
|
| 87 |
+
c2 += B * dequantized_weights.s2;
|
| 88 |
+
c3 += B * dequantized_weights.s3;
|
| 89 |
+
|
| 90 |
+
// j=3
|
| 91 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+3)*(n_4));
|
| 92 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+3)*(n_4)+1);
|
| 93 |
+
dequantized_weights.s0 = (((bits4.s0 & (0xF000)) >> 12) - 8) * scale.s0; // dequantize a row of the 16 weights
|
| 94 |
+
dequantized_weights.s1 = (((bits4.s1 & (0xF000)) >> 12) - 8) * scale.s1;
|
| 95 |
+
dequantized_weights.s2 = (((bits4.s2 & (0xF000)) >> 12) - 8) * scale.s2;
|
| 96 |
+
dequantized_weights.s3 = (((bits4.s3 & (0xF000)) >> 12) - 8) * scale.s3;
|
| 97 |
+
c0 += B * dequantized_weights.s0; // vector-scalar multiplication to accumulate
|
| 98 |
+
c1 += B * dequantized_weights.s1;
|
| 99 |
+
c2 += B * dequantized_weights.s2;
|
| 100 |
+
c3 += B * dequantized_weights.s3;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
int idx = (gy<<3)*m + (gx<<2); // vectorized store 16 elements
|
| 104 |
+
|
| 105 |
+
// conditional check if store is to a valid location. Required when N is not a multiple of 8
|
| 106 |
+
// if statements allow registers to be reused for each store
|
| 107 |
+
// provides a performance boost due to reduced register footprint, which increases number of concurrent waves
|
| 108 |
+
if(idx+3 < m*n_no_padding){
|
| 109 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 110 |
+
idx += m;
|
| 111 |
+
}
|
| 112 |
+
if(idx+3 < m*n_no_padding){
|
| 113 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 114 |
+
idx += m;
|
| 115 |
+
}
|
| 116 |
+
if(idx+3 < m*n_no_padding){
|
| 117 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 118 |
+
idx += m;
|
| 119 |
+
}
|
| 120 |
+
if(idx+3 < m*n_no_padding){
|
| 121 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 122 |
+
idx += m;
|
| 123 |
+
}
|
| 124 |
+
if(idx+3 < m*n_no_padding){
|
| 125 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 126 |
+
idx += m;
|
| 127 |
+
}
|
| 128 |
+
if(idx+3 < m*n_no_padding){
|
| 129 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 130 |
+
idx += m;
|
| 131 |
+
}
|
| 132 |
+
if(idx+3 < m*n_no_padding){
|
| 133 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 134 |
+
idx += m;
|
| 135 |
+
}
|
| 136 |
+
if(idx+3 < m*n_no_padding){
|
| 137 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 138 |
+
}
|
| 139 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_0_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_N 32
|
| 8 |
+
|
| 9 |
+
// Expand the 4 nibbles in the low 16 bits of u into 4 bytes (value 0..15),
|
| 10 |
+
// packed for the int8 dp4a. The -8 zero-point is applied via the sum term.
|
| 11 |
+
#define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
|
| 12 |
+
(((uint)((u) & 0x00F0u)) << 4) | \
|
| 13 |
+
(((uint)((u) & 0x0F00u)) << 8) | \
|
| 14 |
+
(((uint)((u) & 0xF000u)) << 12) )
|
| 15 |
+
|
| 16 |
+
inline int dot8_q8a(uint8 qw, __local const uint * a) {
|
| 17 |
+
int r = 0;
|
| 18 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
|
| 19 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
|
| 20 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
|
| 21 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
|
| 22 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
|
| 23 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
|
| 24 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
|
| 25 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
|
| 26 |
+
return r;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 30 |
+
kernel void kernel_gemm_noshuffle_q4_0_q8_1_dp4a(
|
| 31 |
+
__global const ushort * src0_q, // q4_0 nibbles (4/ushort, feature-major)
|
| 32 |
+
__global const half * src0_d, // per-32-block scale, feature-major
|
| 33 |
+
__global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
|
| 34 |
+
__global const half * src1_da, // q8_1 per-block scale [N, K/32]
|
| 35 |
+
__global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
|
| 36 |
+
__global float * dst,
|
| 37 |
+
ulong offsetd,
|
| 38 |
+
int m, // output features (rows)
|
| 39 |
+
int n_no_padding, // tokens (cols)
|
| 40 |
+
int k // K (== ne00)
|
| 41 |
+
) {
|
| 42 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 43 |
+
|
| 44 |
+
const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
|
| 45 |
+
const uint block_id_m = get_global_id(1);
|
| 46 |
+
const uint block_id_n = get_global_id(2);
|
| 47 |
+
|
| 48 |
+
const uint row = block_id_m * 64 + lid;
|
| 49 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 50 |
+
const bool row_valid = row < (uint)m;
|
| 51 |
+
const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
|
| 52 |
+
|
| 53 |
+
const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
|
| 54 |
+
const uint k_b = (uint)k >> 5; // blocks-of-32 along K
|
| 55 |
+
|
| 56 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 57 |
+
__local half sh_d[TILESIZE_N];
|
| 58 |
+
__local half sh_s[TILESIZE_N];
|
| 59 |
+
|
| 60 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 61 |
+
float4 acc[NGROUPS];
|
| 62 |
+
#pragma unroll
|
| 63 |
+
for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
|
| 64 |
+
|
| 65 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 66 |
+
const uint sub = step >> 5;
|
| 67 |
+
|
| 68 |
+
const float d_w = (float)src0_d[rrow + sub * (uint)m];
|
| 69 |
+
|
| 70 |
+
// 8 weight uints (32 nibbles) for this row, this 32-block. Feature-major:
|
| 71 |
+
// src0_q[row + (k/4 + u)*m], k/4 = step/4 (= step>>2). EXP4 -> dp4a int8.
|
| 72 |
+
const uint qsbase = rrow + (step >> 2) * (uint)m;
|
| 73 |
+
uint8 qw;
|
| 74 |
+
qw.s0 = EXP4(src0_q[qsbase + 0 * m]);
|
| 75 |
+
qw.s1 = EXP4(src0_q[qsbase + 1 * m]);
|
| 76 |
+
qw.s2 = EXP4(src0_q[qsbase + 2 * m]);
|
| 77 |
+
qw.s3 = EXP4(src0_q[qsbase + 3 * m]);
|
| 78 |
+
qw.s4 = EXP4(src0_q[qsbase + 4 * m]);
|
| 79 |
+
qw.s5 = EXP4(src0_q[qsbase + 5 * m]);
|
| 80 |
+
qw.s6 = EXP4(src0_q[qsbase + 6 * m]);
|
| 81 |
+
qw.s7 = EXP4(src0_q[qsbase + 7 * m]);
|
| 82 |
+
|
| 83 |
+
// cooperatively stage the 32-token x 32-K int8 activations to LDS
|
| 84 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 85 |
+
const uint t = idx >> 3;
|
| 86 |
+
const uint u = idx & 7;
|
| 87 |
+
const uint c = col_base + t;
|
| 88 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 89 |
+
}
|
| 90 |
+
if (lid < TILESIZE_N) {
|
| 91 |
+
const uint c = col_base + lid;
|
| 92 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 93 |
+
sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
|
| 94 |
+
}
|
| 95 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 96 |
+
|
| 97 |
+
#define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
|
| 98 |
+
#pragma unroll
|
| 99 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 100 |
+
const int b = g * 4;
|
| 101 |
+
float4 rf;
|
| 102 |
+
rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
|
| 103 |
+
rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
|
| 104 |
+
// q4_0: w = d*(q-8) -> d_w * (a_d * dp4a(q,qa) - 8 * a_s)
|
| 105 |
+
acc[g] += d_w * (LD4(sh_d, b) * rf - 8.0f * LD4(sh_s, b));
|
| 106 |
+
}
|
| 107 |
+
#undef LD4
|
| 108 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
if (!row_valid) {
|
| 112 |
+
return;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
// dst is [token, feature] row-major (stride m): dst[col*m + row].
|
| 116 |
+
#pragma unroll
|
| 117 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 118 |
+
const uint b = (uint)(g * 4);
|
| 119 |
+
const float4 a = acc[g];
|
| 120 |
+
const uint c0 = col_base + b;
|
| 121 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 122 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 123 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 124 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 125 |
+
}
|
| 126 |
+
#undef NGROUPS
|
| 127 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_1_f32.cl
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
#ifdef ADRENO_GPU
|
| 11 |
+
REQD_SUBGROUP_SIZE_128
|
| 12 |
+
#endif
|
| 13 |
+
|
| 14 |
+
kernel void kernel_gemm_noshuffle_q4_1_f32(
|
| 15 |
+
global const ushort * src0_q,
|
| 16 |
+
global const half * src0_d,
|
| 17 |
+
global const half * src0_m,
|
| 18 |
+
read_only image1d_buffer_t src1,
|
| 19 |
+
global float * dst,
|
| 20 |
+
ulong offsetd,
|
| 21 |
+
int m,
|
| 22 |
+
int n,
|
| 23 |
+
int k,
|
| 24 |
+
int n_no_padding
|
| 25 |
+
) {
|
| 26 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 27 |
+
|
| 28 |
+
int m_4 = m >> 2;
|
| 29 |
+
int n_4 = n >> 2;
|
| 30 |
+
|
| 31 |
+
int gy = get_global_id(0);
|
| 32 |
+
int gx = get_global_id(1);
|
| 33 |
+
int gx_2 = gx << 2;
|
| 34 |
+
|
| 35 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
| 36 |
+
half8 B;
|
| 37 |
+
half4 dequantized_weights;
|
| 38 |
+
|
| 39 |
+
global const ushort* weight_ptr = src0_q + gx_2;
|
| 40 |
+
global const half* scale_ptr = src0_d + gx_2;
|
| 41 |
+
global const half* min_ptr = src0_m + gx_2;
|
| 42 |
+
|
| 43 |
+
for(int i = 0; i < k; i += 4) {
|
| 44 |
+
B.s0123 = read_imageh(src1, gy*2 + (i)*(n_4));
|
| 45 |
+
B.s4567 = read_imageh(src1, gy*2 + (i)*(n_4)+1);
|
| 46 |
+
|
| 47 |
+
ushort4 bits4 = vload4(0, weight_ptr + (i/4)*(m));
|
| 48 |
+
|
| 49 |
+
half4 scale = vload4(0, scale_ptr + (i/32)*(m));
|
| 50 |
+
half4 minv = vload4(0, min_ptr + (i/32)*(m));
|
| 51 |
+
|
| 52 |
+
// j=0
|
| 53 |
+
dequantized_weights.s0 = (bits4.s0 & (0x000F)) * scale.s0 + minv.s0;
|
| 54 |
+
dequantized_weights.s1 = (bits4.s1 & (0x000F)) * scale.s1 + minv.s1;
|
| 55 |
+
dequantized_weights.s2 = (bits4.s2 & (0x000F)) * scale.s2 + minv.s2;
|
| 56 |
+
dequantized_weights.s3 = (bits4.s3 & (0x000F)) * scale.s3 + minv.s3;
|
| 57 |
+
c0 += B * dequantized_weights.s0;
|
| 58 |
+
c1 += B * dequantized_weights.s1;
|
| 59 |
+
c2 += B * dequantized_weights.s2;
|
| 60 |
+
c3 += B * dequantized_weights.s3;
|
| 61 |
+
|
| 62 |
+
// j=1
|
| 63 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+1)*(n_4));
|
| 64 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+1)*(n_4)+1);
|
| 65 |
+
dequantized_weights.s0 = ((bits4.s0 & (0x00F0)) >> 4) * scale.s0 + minv.s0;
|
| 66 |
+
dequantized_weights.s1 = ((bits4.s1 & (0x00F0)) >> 4) * scale.s1 + minv.s1;
|
| 67 |
+
dequantized_weights.s2 = ((bits4.s2 & (0x00F0)) >> 4) * scale.s2 + minv.s2;
|
| 68 |
+
dequantized_weights.s3 = ((bits4.s3 & (0x00F0)) >> 4) * scale.s3 + minv.s3;
|
| 69 |
+
c0 += B * dequantized_weights.s0;
|
| 70 |
+
c1 += B * dequantized_weights.s1;
|
| 71 |
+
c2 += B * dequantized_weights.s2;
|
| 72 |
+
c3 += B * dequantized_weights.s3;
|
| 73 |
+
|
| 74 |
+
// j=2
|
| 75 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+2)*(n_4));
|
| 76 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+2)*(n_4)+1);
|
| 77 |
+
dequantized_weights.s0 = ((bits4.s0 & (0x0F00)) >> 8) * scale.s0 + minv.s0;
|
| 78 |
+
dequantized_weights.s1 = ((bits4.s1 & (0x0F00)) >> 8) * scale.s1 + minv.s1;
|
| 79 |
+
dequantized_weights.s2 = ((bits4.s2 & (0x0F00)) >> 8) * scale.s2 + minv.s2;
|
| 80 |
+
dequantized_weights.s3 = ((bits4.s3 & (0x0F00)) >> 8) * scale.s3 + minv.s3;
|
| 81 |
+
c0 += B * dequantized_weights.s0;
|
| 82 |
+
c1 += B * dequantized_weights.s1;
|
| 83 |
+
c2 += B * dequantized_weights.s2;
|
| 84 |
+
c3 += B * dequantized_weights.s3;
|
| 85 |
+
|
| 86 |
+
// j=3
|
| 87 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+3)*(n_4));
|
| 88 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+3)*(n_4)+1);
|
| 89 |
+
dequantized_weights.s0 = ((bits4.s0 & (0xF000)) >> 12) * scale.s0 + minv.s0;
|
| 90 |
+
dequantized_weights.s1 = ((bits4.s1 & (0xF000)) >> 12) * scale.s1 + minv.s1;
|
| 91 |
+
dequantized_weights.s2 = ((bits4.s2 & (0xF000)) >> 12) * scale.s2 + minv.s2;
|
| 92 |
+
dequantized_weights.s3 = ((bits4.s3 & (0xF000)) >> 12) * scale.s3 + minv.s3;
|
| 93 |
+
c0 += B * dequantized_weights.s0;
|
| 94 |
+
c1 += B * dequantized_weights.s1;
|
| 95 |
+
c2 += B * dequantized_weights.s2;
|
| 96 |
+
c3 += B * dequantized_weights.s3;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
int idx = (gy<<3)*m + (gx<<2);
|
| 100 |
+
|
| 101 |
+
if(idx+3 < m*n_no_padding){
|
| 102 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 103 |
+
idx += m;
|
| 104 |
+
}
|
| 105 |
+
if(idx+3 < m*n_no_padding){
|
| 106 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 107 |
+
idx += m;
|
| 108 |
+
}
|
| 109 |
+
if(idx+3 < m*n_no_padding){
|
| 110 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 111 |
+
idx += m;
|
| 112 |
+
}
|
| 113 |
+
if(idx+3 < m*n_no_padding){
|
| 114 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 115 |
+
idx += m;
|
| 116 |
+
}
|
| 117 |
+
if(idx+3 < m*n_no_padding){
|
| 118 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 119 |
+
idx += m;
|
| 120 |
+
}
|
| 121 |
+
if(idx+3 < m*n_no_padding){
|
| 122 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 123 |
+
idx += m;
|
| 124 |
+
}
|
| 125 |
+
if(idx+3 < m*n_no_padding){
|
| 126 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 127 |
+
idx += m;
|
| 128 |
+
}
|
| 129 |
+
if(idx+3 < m*n_no_padding){
|
| 130 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 131 |
+
}
|
| 132 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_k_f32.cl
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
|
| 3 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 5 |
+
#define ADRENO_GPU 1
|
| 6 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 7 |
+
#endif
|
| 8 |
+
#define QK_K 256
|
| 9 |
+
#define K_SCALE_SIZE 12
|
| 10 |
+
|
| 11 |
+
inline void get_scale_min_k4(
|
| 12 |
+
int j,
|
| 13 |
+
global const uchar * q,
|
| 14 |
+
uchar * d,
|
| 15 |
+
uchar * m,
|
| 16 |
+
uchar mask_d6,
|
| 17 |
+
uchar mask_d4,
|
| 18 |
+
uchar mask_hi2
|
| 19 |
+
) {
|
| 20 |
+
if (j < 4) {
|
| 21 |
+
*d = q[j] & mask_d6;
|
| 22 |
+
*m = q[j+4] & mask_d6;
|
| 23 |
+
} else {
|
| 24 |
+
*d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
|
| 25 |
+
*m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
#ifdef ADRENO_GPU
|
| 30 |
+
REQD_SUBGROUP_SIZE_128
|
| 31 |
+
#endif
|
| 32 |
+
kernel void kernel_gemm_noshuffle_q4_k_f32(
|
| 33 |
+
global const ushort * src0_q,
|
| 34 |
+
global const uchar * src0_s,
|
| 35 |
+
global const half * src0_d,
|
| 36 |
+
global const half * src0_dm,
|
| 37 |
+
read_only image1d_buffer_t src1,
|
| 38 |
+
global float * dst,
|
| 39 |
+
ulong offsetd,
|
| 40 |
+
int m,
|
| 41 |
+
int n,
|
| 42 |
+
int k,
|
| 43 |
+
int n_no_padding,
|
| 44 |
+
uchar mask_d6,
|
| 45 |
+
uchar mask_d4,
|
| 46 |
+
uchar mask_hi2
|
| 47 |
+
) {
|
| 48 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 49 |
+
int n_4 = n >> 2;
|
| 50 |
+
int gy = get_global_id(0);
|
| 51 |
+
int gx = get_global_id(1);
|
| 52 |
+
int gx_2 = gx << 2;
|
| 53 |
+
|
| 54 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
| 55 |
+
half8 B;
|
| 56 |
+
half4 dequantized_weights;
|
| 57 |
+
|
| 58 |
+
int num_blocks_K = k / QK_K;
|
| 59 |
+
|
| 60 |
+
global const ushort * weight_ptr = src0_q + gx_2;
|
| 61 |
+
global const half * d_ptr = src0_d + gx_2;
|
| 62 |
+
global const half * dm_ptr = src0_dm + gx_2;
|
| 63 |
+
|
| 64 |
+
for (int i = 0; i < k; i += 32) {
|
| 65 |
+
int sb_idx = i / QK_K;
|
| 66 |
+
int sub_idx = (i / 32) % 8;
|
| 67 |
+
|
| 68 |
+
half4 d = vload4(0, d_ptr + sb_idx * m);
|
| 69 |
+
half4 dm = vload4(0, dm_ptr + sb_idx * m);
|
| 70 |
+
|
| 71 |
+
global const uchar * sc0 = src0_s + (gx_2+0) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 72 |
+
global const uchar * sc1 = src0_s + (gx_2+1) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 73 |
+
global const uchar * sc2 = src0_s + (gx_2+2) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 74 |
+
global const uchar * sc3 = src0_s + (gx_2+3) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 75 |
+
|
| 76 |
+
uchar sv0, mn0, sv1, mn1, sv2, mn2, sv3, mn3;
|
| 77 |
+
get_scale_min_k4(sub_idx, sc0, &sv0, &mn0, mask_d6, mask_d4, mask_hi2);
|
| 78 |
+
get_scale_min_k4(sub_idx, sc1, &sv1, &mn1, mask_d6, mask_d4, mask_hi2);
|
| 79 |
+
get_scale_min_k4(sub_idx, sc2, &sv2, &mn2, mask_d6, mask_d4, mask_hi2);
|
| 80 |
+
get_scale_min_k4(sub_idx, sc3, &sv3, &mn3, mask_d6, mask_d4, mask_hi2);
|
| 81 |
+
|
| 82 |
+
half4 scale = convert_half4(convert_float4(d) * convert_float4((uchar4)(sv0, sv1, sv2, sv3)));
|
| 83 |
+
half4 mval = convert_half4(convert_float4(dm) * convert_float4((uchar4)(mn0, mn1, mn2, mn3)));
|
| 84 |
+
|
| 85 |
+
for (int l = 0; l < 32; l += 4) {
|
| 86 |
+
int ki = i + l;
|
| 87 |
+
ushort4 bits4 = vload4(0, weight_ptr + (ki/4) * m);
|
| 88 |
+
|
| 89 |
+
// j=0
|
| 90 |
+
B.s0123 = read_imageh(src1, gy*2 + (ki+0) * n_4);
|
| 91 |
+
B.s4567 = read_imageh(src1, gy*2+1 + (ki+0) * n_4);
|
| 92 |
+
dequantized_weights.s0 = (bits4.s0 & 0x000F) * scale.s0 - mval.s0;
|
| 93 |
+
dequantized_weights.s1 = (bits4.s1 & 0x000F) * scale.s1 - mval.s1;
|
| 94 |
+
dequantized_weights.s2 = (bits4.s2 & 0x000F) * scale.s2 - mval.s2;
|
| 95 |
+
dequantized_weights.s3 = (bits4.s3 & 0x000F) * scale.s3 - mval.s3;
|
| 96 |
+
c0 += B * dequantized_weights.s0;
|
| 97 |
+
c1 += B * dequantized_weights.s1;
|
| 98 |
+
c2 += B * dequantized_weights.s2;
|
| 99 |
+
c3 += B * dequantized_weights.s3;
|
| 100 |
+
|
| 101 |
+
// j=1
|
| 102 |
+
B.s0123 = read_imageh(src1, gy*2 + (ki+1) * n_4);
|
| 103 |
+
B.s4567 = read_imageh(src1, gy*2+1 + (ki+1) * n_4);
|
| 104 |
+
dequantized_weights.s0 = ((bits4.s0 & 0x00F0) >> 4) * scale.s0 - mval.s0;
|
| 105 |
+
dequantized_weights.s1 = ((bits4.s1 & 0x00F0) >> 4) * scale.s1 - mval.s1;
|
| 106 |
+
dequantized_weights.s2 = ((bits4.s2 & 0x00F0) >> 4) * scale.s2 - mval.s2;
|
| 107 |
+
dequantized_weights.s3 = ((bits4.s3 & 0x00F0) >> 4) * scale.s3 - mval.s3;
|
| 108 |
+
c0 += B * dequantized_weights.s0;
|
| 109 |
+
c1 += B * dequantized_weights.s1;
|
| 110 |
+
c2 += B * dequantized_weights.s2;
|
| 111 |
+
c3 += B * dequantized_weights.s3;
|
| 112 |
+
|
| 113 |
+
// j=2
|
| 114 |
+
B.s0123 = read_imageh(src1, gy*2 + (ki+2) * n_4);
|
| 115 |
+
B.s4567 = read_imageh(src1, gy*2+1 + (ki+2) * n_4);
|
| 116 |
+
dequantized_weights.s0 = ((bits4.s0 & 0x0F00) >> 8) * scale.s0 - mval.s0;
|
| 117 |
+
dequantized_weights.s1 = ((bits4.s1 & 0x0F00) >> 8) * scale.s1 - mval.s1;
|
| 118 |
+
dequantized_weights.s2 = ((bits4.s2 & 0x0F00) >> 8) * scale.s2 - mval.s2;
|
| 119 |
+
dequantized_weights.s3 = ((bits4.s3 & 0x0F00) >> 8) * scale.s3 - mval.s3;
|
| 120 |
+
c0 += B * dequantized_weights.s0;
|
| 121 |
+
c1 += B * dequantized_weights.s1;
|
| 122 |
+
c2 += B * dequantized_weights.s2;
|
| 123 |
+
c3 += B * dequantized_weights.s3;
|
| 124 |
+
|
| 125 |
+
// j=3
|
| 126 |
+
B.s0123 = read_imageh(src1, gy*2 + (ki+3) * n_4);
|
| 127 |
+
B.s4567 = read_imageh(src1, gy*2+1 + (ki+3) * n_4);
|
| 128 |
+
dequantized_weights.s0 = ((bits4.s0 & 0xF000) >> 12) * scale.s0 - mval.s0;
|
| 129 |
+
dequantized_weights.s1 = ((bits4.s1 & 0xF000) >> 12) * scale.s1 - mval.s1;
|
| 130 |
+
dequantized_weights.s2 = ((bits4.s2 & 0xF000) >> 12) * scale.s2 - mval.s2;
|
| 131 |
+
dequantized_weights.s3 = ((bits4.s3 & 0xF000) >> 12) * scale.s3 - mval.s3;
|
| 132 |
+
c0 += B * dequantized_weights.s0;
|
| 133 |
+
c1 += B * dequantized_weights.s1;
|
| 134 |
+
c2 += B * dequantized_weights.s2;
|
| 135 |
+
c3 += B * dequantized_weights.s3;
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
int idx = (gy<<3)*m + (gx<<2);
|
| 140 |
+
|
| 141 |
+
if (idx+3 < m*n_no_padding) {
|
| 142 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 143 |
+
idx += m;
|
| 144 |
+
}
|
| 145 |
+
if (idx+3 < m*n_no_padding) {
|
| 146 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 147 |
+
idx += m;
|
| 148 |
+
}
|
| 149 |
+
if (idx+3 < m*n_no_padding) {
|
| 150 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 151 |
+
idx += m;
|
| 152 |
+
}
|
| 153 |
+
if (idx+3 < m*n_no_padding) {
|
| 154 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 155 |
+
idx += m;
|
| 156 |
+
}
|
| 157 |
+
if (idx+3 < m*n_no_padding) {
|
| 158 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 159 |
+
idx += m;
|
| 160 |
+
}
|
| 161 |
+
if (idx+3 < m*n_no_padding) {
|
| 162 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 163 |
+
idx += m;
|
| 164 |
+
}
|
| 165 |
+
if (idx+3 < m*n_no_padding) {
|
| 166 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 167 |
+
idx += m;
|
| 168 |
+
}
|
| 169 |
+
if (idx+3 < m*n_no_padding) {
|
| 170 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 171 |
+
}
|
| 172 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q4_k_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
#ifndef TILESIZE_N
|
| 8 |
+
#define TILESIZE_N 32
|
| 9 |
+
#endif
|
| 10 |
+
#define QK_K 256
|
| 11 |
+
#define K_SCALE_SIZE 12
|
| 12 |
+
|
| 13 |
+
inline void get_scale_min_k4(
|
| 14 |
+
int j,
|
| 15 |
+
global const uchar * q,
|
| 16 |
+
uchar * d,
|
| 17 |
+
uchar * m,
|
| 18 |
+
uchar mask_d6,
|
| 19 |
+
uchar mask_d4,
|
| 20 |
+
uchar mask_hi2
|
| 21 |
+
) {
|
| 22 |
+
if (j < 4) {
|
| 23 |
+
*d = q[j] & mask_d6;
|
| 24 |
+
*m = q[j+4] & mask_d6;
|
| 25 |
+
} else {
|
| 26 |
+
*d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
|
| 27 |
+
*m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
// Expand the 4 nibbles in the low 16 bits of `u` into 4 bytes (one nibble per
|
| 32 |
+
// byte, value 0..15), packed for the int8 dp4a.
|
| 33 |
+
#define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
|
| 34 |
+
(((uint)((u) & 0x00F0u)) << 4) | \
|
| 35 |
+
(((uint)((u) & 0x0F00u)) << 8) | \
|
| 36 |
+
(((uint)((u) & 0xF000u)) << 12) )
|
| 37 |
+
|
| 38 |
+
// 32-K dp4a dot of one token's int8 activations (8 packed uints in lm) against the
|
| 39 |
+
// row's 8 packed weight uints. qw passed by value as a uint8 (register), not an array.
|
| 40 |
+
inline int dot8_q8a(uint8 qw, __local const uint * a) {
|
| 41 |
+
int r = 0;
|
| 42 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
|
| 43 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
|
| 44 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
|
| 45 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
|
| 46 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
|
| 47 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
|
| 48 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
|
| 49 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
|
| 50 |
+
return r;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 54 |
+
kernel void kernel_gemm_noshuffle_q4_k_q8_1_dp4a(
|
| 55 |
+
__global const ushort * src0_q, // q4_K weights (noshuffle, packed nibbles)
|
| 56 |
+
__global const uchar * src0_s, // 6-bit scale/min codes
|
| 57 |
+
__global const half * src0_d, // per-superblock scale
|
| 58 |
+
__global const half * src0_dm, // per-superblock min
|
| 59 |
+
__global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
|
| 60 |
+
__global const half * src1_da, // q8_1 per-block scale [N, K/32]
|
| 61 |
+
__global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
|
| 62 |
+
__global float * dst,
|
| 63 |
+
ulong offsetd,
|
| 64 |
+
int m, // output features (rows)
|
| 65 |
+
int n_no_padding, // tokens (cols)
|
| 66 |
+
int k, // K (== ne00)
|
| 67 |
+
uchar mask_d6,
|
| 68 |
+
uchar mask_d4,
|
| 69 |
+
uchar mask_hi2
|
| 70 |
+
) {
|
| 71 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 72 |
+
|
| 73 |
+
const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
|
| 74 |
+
const uint block_id_m = get_global_id(1);
|
| 75 |
+
const uint block_id_n = get_global_id(2);
|
| 76 |
+
|
| 77 |
+
const uint row = block_id_m * 64 + lid;
|
| 78 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 79 |
+
const bool row_valid = row < (uint)m;
|
| 80 |
+
const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
|
| 81 |
+
|
| 82 |
+
const uint num_superblocks = (uint)k / QK_K;
|
| 83 |
+
const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
|
| 84 |
+
const uint k_b = (uint)k >> 5; // blocks-of-32 along K
|
| 85 |
+
|
| 86 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 87 |
+
__local half sh_d[TILESIZE_N];
|
| 88 |
+
__local half sh_s[TILESIZE_N];
|
| 89 |
+
|
| 90 |
+
// One float4 vector-register accumulator per group of 4 tokens (NGROUPS = TILESIZE_N/4).
|
| 91 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 92 |
+
float4 acc[NGROUPS];
|
| 93 |
+
#pragma unroll
|
| 94 |
+
for (int g = 0; g < NGROUPS; ++g) { acc[g] = (float4)(0.0f); }
|
| 95 |
+
|
| 96 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 97 |
+
const uint sub = step >> 5;
|
| 98 |
+
const uint sb_idx = step / QK_K;
|
| 99 |
+
const uint sub_idx = sub & 7;
|
| 100 |
+
|
| 101 |
+
// weight scale/min for this WI's row, this subblock
|
| 102 |
+
const float dd = (float)src0_d [rrow + sb_idx * m];
|
| 103 |
+
const float dmm = (float)src0_dm[rrow + sb_idx * m];
|
| 104 |
+
global const uchar * sc = src0_s + rrow * num_superblocks * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 105 |
+
uchar sv, mn;
|
| 106 |
+
get_scale_min_k4(sub_idx, sc, &sv, &mn, mask_d6, mask_d4, mask_hi2);
|
| 107 |
+
const float scale = dd * (float)sv;
|
| 108 |
+
const float minv = dmm * (float)mn;
|
| 109 |
+
|
| 110 |
+
// repack this row's 32 weight nibbles into 8 dp4a uints. The packed q4_K
|
| 111 |
+
// layout stores one ushort = 4 consecutive-K nibbles for a row at
|
| 112 |
+
// src0_q[row + (K_group)*m], K_group = step/4 + u.
|
| 113 |
+
const uint wbase = rrow + (step >> 2) * (uint)m;
|
| 114 |
+
uint8 qw;
|
| 115 |
+
qw.s0 = EXP4(src0_q[wbase + 0 * m]);
|
| 116 |
+
qw.s1 = EXP4(src0_q[wbase + 1 * m]);
|
| 117 |
+
qw.s2 = EXP4(src0_q[wbase + 2 * m]);
|
| 118 |
+
qw.s3 = EXP4(src0_q[wbase + 3 * m]);
|
| 119 |
+
qw.s4 = EXP4(src0_q[wbase + 4 * m]);
|
| 120 |
+
qw.s5 = EXP4(src0_q[wbase + 5 * m]);
|
| 121 |
+
qw.s6 = EXP4(src0_q[wbase + 6 * m]);
|
| 122 |
+
qw.s7 = EXP4(src0_q[wbase + 7 * m]);
|
| 123 |
+
|
| 124 |
+
// cooperatively stage the 32-token x 32-K int8 activations to lm
|
| 125 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 126 |
+
const uint t = idx >> 3;
|
| 127 |
+
const uint u = idx & 7;
|
| 128 |
+
const uint c = col_base + t;
|
| 129 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 130 |
+
}
|
| 131 |
+
if (lid < TILESIZE_N) {
|
| 132 |
+
const uint c = col_base + lid;
|
| 133 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 134 |
+
sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
|
| 135 |
+
}
|
| 136 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 137 |
+
|
| 138 |
+
#define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
|
| 139 |
+
#pragma unroll
|
| 140 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 141 |
+
const int b = g * 4;
|
| 142 |
+
float4 rf;
|
| 143 |
+
rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
|
| 144 |
+
rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
|
| 145 |
+
acc[g] += scale * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
|
| 146 |
+
}
|
| 147 |
+
#undef LD4
|
| 148 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
if (!row_valid) {
|
| 152 |
+
return;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
// dst is [token, feature] row-major (stride m): dst[col*m + row]. Scatter each
|
| 156 |
+
// lane with a per-token padding guard (dst is non-contiguous in token).
|
| 157 |
+
#pragma unroll
|
| 158 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 159 |
+
const uint b = (uint)(g * 4);
|
| 160 |
+
const float4 a = acc[g];
|
| 161 |
+
const uint c0 = col_base + b;
|
| 162 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 163 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 164 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 165 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 166 |
+
}
|
| 167 |
+
#undef NGROUPS
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 171 |
+
kernel void kernel_gemm_noshuffle_q4_k_q8_1_dp4a_wimg(
|
| 172 |
+
__read_only image1d_buffer_t src0_q_img, // q4_K weights as uint32 texels (2 ushorts/texel)
|
| 173 |
+
__global const uchar * src0_s, // 6-bit scale/min codes
|
| 174 |
+
__global const half * src0_d, // per-superblock scale
|
| 175 |
+
__global const half * src0_dm, // per-superblock min
|
| 176 |
+
__global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
|
| 177 |
+
__global const half * src1_da, // q8_1 per-block scale [N, K/32]
|
| 178 |
+
__global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
|
| 179 |
+
__global float * dst,
|
| 180 |
+
ulong offsetd,
|
| 181 |
+
int m, // output features (rows)
|
| 182 |
+
int n_no_padding, // tokens (cols)
|
| 183 |
+
int k, // K (== ne00)
|
| 184 |
+
uchar mask_d6,
|
| 185 |
+
uchar mask_d4,
|
| 186 |
+
uchar mask_hi2
|
| 187 |
+
) {
|
| 188 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 189 |
+
|
| 190 |
+
const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
|
| 191 |
+
const uint block_id_m = get_global_id(1);
|
| 192 |
+
const uint block_id_n = get_global_id(2);
|
| 193 |
+
|
| 194 |
+
const uint row = block_id_m * 64 + lid;
|
| 195 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 196 |
+
const bool row_valid = row < (uint)m;
|
| 197 |
+
const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
|
| 198 |
+
|
| 199 |
+
// Constant per WI: the ushort the row needs always sits in the same half of
|
| 200 |
+
// its uint32 texel (m even => index parity == rrow parity). Hoist the shift.
|
| 201 |
+
const uint sel = (rrow & 1u) * 16u;
|
| 202 |
+
|
| 203 |
+
const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
|
| 204 |
+
const uint k_b = (uint)k >> 5; // blocks-of-32 along K
|
| 205 |
+
const uint num_superblocks = (uint)k / QK_K;
|
| 206 |
+
|
| 207 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 208 |
+
__local half sh_d[TILESIZE_N];
|
| 209 |
+
__local half sh_s[TILESIZE_N];
|
| 210 |
+
|
| 211 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 212 |
+
float4 acc[NGROUPS];
|
| 213 |
+
#pragma unroll
|
| 214 |
+
for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
|
| 215 |
+
|
| 216 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 217 |
+
const uint sub = step >> 5;
|
| 218 |
+
const uint sb_idx = step / QK_K;
|
| 219 |
+
const uint sub_idx = sub & 7;
|
| 220 |
+
|
| 221 |
+
const float dd = (float)src0_d [rrow + sb_idx * m];
|
| 222 |
+
const float dmm = (float)src0_dm[rrow + sb_idx * m];
|
| 223 |
+
global const uchar * sc = src0_s + rrow * num_superblocks * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 224 |
+
uchar sv, mn;
|
| 225 |
+
get_scale_min_k4(sub_idx, sc, &sv, &mn, mask_d6, mask_d4, mask_hi2);
|
| 226 |
+
const float scale = dd * (float)sv;
|
| 227 |
+
const float minv = dmm * (float)mn;
|
| 228 |
+
|
| 229 |
+
const uint wbase = rrow + (step >> 2) * (uint)m;
|
| 230 |
+
uint8 qw;
|
| 231 |
+
qw.s0 = EXP4(read_imageui(src0_q_img, (int)((wbase + 0 * m) >> 1)).x >> sel);
|
| 232 |
+
qw.s1 = EXP4(read_imageui(src0_q_img, (int)((wbase + 1 * m) >> 1)).x >> sel);
|
| 233 |
+
qw.s2 = EXP4(read_imageui(src0_q_img, (int)((wbase + 2 * m) >> 1)).x >> sel);
|
| 234 |
+
qw.s3 = EXP4(read_imageui(src0_q_img, (int)((wbase + 3 * m) >> 1)).x >> sel);
|
| 235 |
+
qw.s4 = EXP4(read_imageui(src0_q_img, (int)((wbase + 4 * m) >> 1)).x >> sel);
|
| 236 |
+
qw.s5 = EXP4(read_imageui(src0_q_img, (int)((wbase + 5 * m) >> 1)).x >> sel);
|
| 237 |
+
qw.s6 = EXP4(read_imageui(src0_q_img, (int)((wbase + 6 * m) >> 1)).x >> sel);
|
| 238 |
+
qw.s7 = EXP4(read_imageui(src0_q_img, (int)((wbase + 7 * m) >> 1)).x >> sel);
|
| 239 |
+
|
| 240 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 241 |
+
const uint t = idx >> 3;
|
| 242 |
+
const uint u = idx & 7;
|
| 243 |
+
const uint c = col_base + t;
|
| 244 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 245 |
+
}
|
| 246 |
+
if (lid < TILESIZE_N) {
|
| 247 |
+
const uint c = col_base + lid;
|
| 248 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 249 |
+
sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
|
| 250 |
+
}
|
| 251 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 252 |
+
|
| 253 |
+
#define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
|
| 254 |
+
#pragma unroll
|
| 255 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 256 |
+
const int b = g * 4;
|
| 257 |
+
float4 rf;
|
| 258 |
+
rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
|
| 259 |
+
rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
|
| 260 |
+
acc[g] += scale * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
|
| 261 |
+
}
|
| 262 |
+
#undef LD4
|
| 263 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
if (!row_valid) {
|
| 267 |
+
return;
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
#pragma unroll
|
| 271 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 272 |
+
const uint b = (uint)(g * 4);
|
| 273 |
+
const float4 a = acc[g];
|
| 274 |
+
const uint c0 = col_base + b;
|
| 275 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 276 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 277 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 278 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 279 |
+
}
|
| 280 |
+
#undef NGROUPS
|
| 281 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_0_f32.cl
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
#ifdef ADRENO_GPU
|
| 11 |
+
REQD_SUBGROUP_SIZE_128
|
| 12 |
+
#endif
|
| 13 |
+
|
| 14 |
+
kernel void kernel_gemm_noshuffle_q5_0_f32(
|
| 15 |
+
global const ushort * src0_qs, // quantized A
|
| 16 |
+
global const uchar * src0_qh, // 5th bits
|
| 17 |
+
global const half * src0_d, // A scales
|
| 18 |
+
__read_only image1d_buffer_t src1, // B (1d image)
|
| 19 |
+
global float * dst, // C
|
| 20 |
+
int m, // M
|
| 21 |
+
int n, // N with padding
|
| 22 |
+
int k, // K
|
| 23 |
+
int n_no_padding // N without padding
|
| 24 |
+
) {
|
| 25 |
+
|
| 26 |
+
int n_4 = n >> 2;
|
| 27 |
+
|
| 28 |
+
int gy = get_global_id(0);
|
| 29 |
+
int gx = get_global_id(1);
|
| 30 |
+
int gx_2 = gx << 2;
|
| 31 |
+
|
| 32 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
| 33 |
+
half8 B;
|
| 34 |
+
half4 dequantized_weights;
|
| 35 |
+
|
| 36 |
+
global const ushort * weight_ptr = src0_qs + gx_2;
|
| 37 |
+
global const uchar * qh_ptr = src0_qh + gx_2;
|
| 38 |
+
global const half * scale_ptr = src0_d + gx_2;
|
| 39 |
+
|
| 40 |
+
for (int i = 0; i < k; i += 4) {
|
| 41 |
+
|
| 42 |
+
B.s0123 = read_imageh(src1, gy*2 + i*n_4);
|
| 43 |
+
B.s4567 = read_imageh(src1, gy*2 + i*n_4 + 1);
|
| 44 |
+
|
| 45 |
+
ushort4 bits4 = vload4(0, weight_ptr + (i >> 2)*m);
|
| 46 |
+
uchar4 bits1 = vload4(0, qh_ptr + (i >> 3)*m);
|
| 47 |
+
uchar4 qh = bits1 >> (uchar4)(i & 4);
|
| 48 |
+
|
| 49 |
+
half4 scale = vload4(0, scale_ptr + (i >> 5)*m);
|
| 50 |
+
|
| 51 |
+
// j=0
|
| 52 |
+
dequantized_weights.s0 = (convert_half((bits4.s0 & 0x000F) | ((qh.s0 & 0x01) << 4)) - 16.0h) * scale.s0;
|
| 53 |
+
dequantized_weights.s1 = (convert_half((bits4.s1 & 0x000F) | ((qh.s1 & 0x01) << 4)) - 16.0h) * scale.s1;
|
| 54 |
+
dequantized_weights.s2 = (convert_half((bits4.s2 & 0x000F) | ((qh.s2 & 0x01) << 4)) - 16.0h) * scale.s2;
|
| 55 |
+
dequantized_weights.s3 = (convert_half((bits4.s3 & 0x000F) | ((qh.s3 & 0x01) << 4)) - 16.0h) * scale.s3;
|
| 56 |
+
c0 += B * dequantized_weights.s0;
|
| 57 |
+
c1 += B * dequantized_weights.s1;
|
| 58 |
+
c2 += B * dequantized_weights.s2;
|
| 59 |
+
c3 += B * dequantized_weights.s3;
|
| 60 |
+
|
| 61 |
+
// j=1
|
| 62 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+1)*n_4);
|
| 63 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+1)*n_4 + 1);
|
| 64 |
+
dequantized_weights.s0 = (convert_half(((bits4.s0 & 0x00F0) >> 4) | ((qh.s0 & 0x02) << 3)) - 16.0h) * scale.s0;
|
| 65 |
+
dequantized_weights.s1 = (convert_half(((bits4.s1 & 0x00F0) >> 4) | ((qh.s1 & 0x02) << 3)) - 16.0h) * scale.s1;
|
| 66 |
+
dequantized_weights.s2 = (convert_half(((bits4.s2 & 0x00F0) >> 4) | ((qh.s2 & 0x02) << 3)) - 16.0h) * scale.s2;
|
| 67 |
+
dequantized_weights.s3 = (convert_half(((bits4.s3 & 0x00F0) >> 4) | ((qh.s3 & 0x02) << 3)) - 16.0h) * scale.s3;
|
| 68 |
+
c0 += B * dequantized_weights.s0;
|
| 69 |
+
c1 += B * dequantized_weights.s1;
|
| 70 |
+
c2 += B * dequantized_weights.s2;
|
| 71 |
+
c3 += B * dequantized_weights.s3;
|
| 72 |
+
|
| 73 |
+
// j=2
|
| 74 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+2)*n_4);
|
| 75 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+2)*n_4 + 1);
|
| 76 |
+
dequantized_weights.s0 = (convert_half(((bits4.s0 & 0x0F00) >> 8) | ((qh.s0 & 0x04) << 2)) - 16.0h) * scale.s0;
|
| 77 |
+
dequantized_weights.s1 = (convert_half(((bits4.s1 & 0x0F00) >> 8) | ((qh.s1 & 0x04) << 2)) - 16.0h) * scale.s1;
|
| 78 |
+
dequantized_weights.s2 = (convert_half(((bits4.s2 & 0x0F00) >> 8) | ((qh.s2 & 0x04) << 2)) - 16.0h) * scale.s2;
|
| 79 |
+
dequantized_weights.s3 = (convert_half(((bits4.s3 & 0x0F00) >> 8) | ((qh.s3 & 0x04) << 2)) - 16.0h) * scale.s3;
|
| 80 |
+
c0 += B * dequantized_weights.s0;
|
| 81 |
+
c1 += B * dequantized_weights.s1;
|
| 82 |
+
c2 += B * dequantized_weights.s2;
|
| 83 |
+
c3 += B * dequantized_weights.s3;
|
| 84 |
+
|
| 85 |
+
// j=3
|
| 86 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+3)*n_4);
|
| 87 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+3)*n_4 + 1);
|
| 88 |
+
dequantized_weights.s0 = (convert_half(((bits4.s0 & 0xF000) >> 12) | ((qh.s0 & 0x08) << 1)) - 16.0h) * scale.s0;
|
| 89 |
+
dequantized_weights.s1 = (convert_half(((bits4.s1 & 0xF000) >> 12) | ((qh.s1 & 0x08) << 1)) - 16.0h) * scale.s1;
|
| 90 |
+
dequantized_weights.s2 = (convert_half(((bits4.s2 & 0xF000) >> 12) | ((qh.s2 & 0x08) << 1)) - 16.0h) * scale.s2;
|
| 91 |
+
dequantized_weights.s3 = (convert_half(((bits4.s3 & 0xF000) >> 12) | ((qh.s3 & 0x08) << 1)) - 16.0h) * scale.s3;
|
| 92 |
+
c0 += B * dequantized_weights.s0;
|
| 93 |
+
c1 += B * dequantized_weights.s1;
|
| 94 |
+
c2 += B * dequantized_weights.s2;
|
| 95 |
+
c3 += B * dequantized_weights.s3;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
int idx = (gy<<3)*m + (gx<<2);
|
| 99 |
+
|
| 100 |
+
if(idx+3 < m*n_no_padding){
|
| 101 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 102 |
+
idx += m;
|
| 103 |
+
}
|
| 104 |
+
if(idx+3 < m*n_no_padding){
|
| 105 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 106 |
+
idx += m;
|
| 107 |
+
}
|
| 108 |
+
if(idx+3 < m*n_no_padding){
|
| 109 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 110 |
+
idx += m;
|
| 111 |
+
}
|
| 112 |
+
if(idx+3 < m*n_no_padding){
|
| 113 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 114 |
+
idx += m;
|
| 115 |
+
}
|
| 116 |
+
if(idx+3 < m*n_no_padding){
|
| 117 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 118 |
+
idx += m;
|
| 119 |
+
}
|
| 120 |
+
if(idx+3 < m*n_no_padding){
|
| 121 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 122 |
+
idx += m;
|
| 123 |
+
}
|
| 124 |
+
if(idx+3 < m*n_no_padding){
|
| 125 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 126 |
+
idx += m;
|
| 127 |
+
}
|
| 128 |
+
if(idx+3 < m*n_no_padding){
|
| 129 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 130 |
+
}
|
| 131 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_0_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
// Weight layout
|
| 8 |
+
// src0_qs[row + (k/4)*m] ushort = 4 low nibbles (K = 4*grp .. +3)
|
| 9 |
+
// src0_qh[row + (k/8)*m] uchar = 8 high bits (one per element)
|
| 10 |
+
// src0_d [row + (k/32)*m] half = per-32-block scale
|
| 11 |
+
|
| 12 |
+
#define TILESIZE_N 32
|
| 13 |
+
|
| 14 |
+
// 4 nibbles in low 16 bits of u -> 4 bytes (value 0..15)
|
| 15 |
+
#define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
|
| 16 |
+
(((uint)((u) & 0x00F0u)) << 4) | \
|
| 17 |
+
(((uint)((u) & 0x0F00u)) << 8) | \
|
| 18 |
+
(((uint)((u) & 0xF000u)) << 12) )
|
| 19 |
+
// 4 high bits (one per element, in bits 0..3 of h) -> bit4 of each of 4 bytes
|
| 20 |
+
#define EXP1(h) ( (((uint)((h) & 0x1u)) << 4) | \
|
| 21 |
+
(((uint)((h) & 0x2u)) << 11) | \
|
| 22 |
+
(((uint)((h) & 0x4u)) << 18) | \
|
| 23 |
+
(((uint)((h) & 0x8u)) << 25) )
|
| 24 |
+
|
| 25 |
+
inline int dot8_q8a(uint8 qw, __local const uint * a) {
|
| 26 |
+
int r = 0;
|
| 27 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
|
| 28 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
|
| 29 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
|
| 30 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
|
| 31 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
|
| 32 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
|
| 33 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
|
| 34 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
|
| 35 |
+
return r;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 39 |
+
kernel void kernel_gemm_noshuffle_q5_0_q8_1_dp4a(
|
| 40 |
+
__global const ushort * src0_qs, // q5_0 low nibbles (4/ushort, feature-major)
|
| 41 |
+
__global const uchar * src0_qh, // q5_0 high-bit plane (8/uchar, feature-major)
|
| 42 |
+
__global const half * src0_d, // per-32-block scale, feature-major
|
| 43 |
+
__global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
|
| 44 |
+
__global const half * src1_da, // q8_1 per-block scale [N, K/32]
|
| 45 |
+
__global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
|
| 46 |
+
__global float * dst,
|
| 47 |
+
ulong offsetd,
|
| 48 |
+
int m, // output features (rows)
|
| 49 |
+
int n_no_padding, // tokens (cols)
|
| 50 |
+
int k // K (== ne00)
|
| 51 |
+
) {
|
| 52 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 53 |
+
|
| 54 |
+
const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
|
| 55 |
+
const uint block_id_m = get_global_id(1);
|
| 56 |
+
const uint block_id_n = get_global_id(2);
|
| 57 |
+
|
| 58 |
+
const uint row = block_id_m * 64 + lid;
|
| 59 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 60 |
+
const bool row_valid = row < (uint)m;
|
| 61 |
+
const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
|
| 62 |
+
|
| 63 |
+
const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
|
| 64 |
+
const uint k_b = (uint)k >> 5; // blocks-of-32 along K
|
| 65 |
+
|
| 66 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 67 |
+
__local half sh_d[TILESIZE_N];
|
| 68 |
+
__local half sh_s[TILESIZE_N];
|
| 69 |
+
|
| 70 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 71 |
+
float4 acc[NGROUPS];
|
| 72 |
+
#pragma unroll
|
| 73 |
+
for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
|
| 74 |
+
|
| 75 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 76 |
+
const uint sub = step >> 5;
|
| 77 |
+
|
| 78 |
+
const float d_w = (float)src0_d[rrow + sub * (uint)m];
|
| 79 |
+
const float minv = d_w * 16.0f; // -16 centering -> subtract via q8_1 sum
|
| 80 |
+
|
| 81 |
+
// 8 weight uints (32 elements) for this row, this 32-block.
|
| 82 |
+
// nibbles: src0_qs[row + (step/4 + u)*m]; high bits: src0_qh[row + (step/8 + u/2)*m],
|
| 83 |
+
// 4-bit group selected by (u&1)*4.
|
| 84 |
+
const uint qsbase = rrow + (step >> 2) * (uint)m;
|
| 85 |
+
const uint qhbase = rrow + (step >> 3) * (uint)m;
|
| 86 |
+
uint8 qw;
|
| 87 |
+
#define QW(u) (EXP4(src0_qs[qsbase + (u) * m]) | \
|
| 88 |
+
EXP1((uint)(src0_qh[qhbase + ((u) >> 1) * m] >> (((u) & 1u) * 4u)) & 0xFu))
|
| 89 |
+
qw.s0 = QW(0); qw.s1 = QW(1); qw.s2 = QW(2); qw.s3 = QW(3);
|
| 90 |
+
qw.s4 = QW(4); qw.s5 = QW(5); qw.s6 = QW(6); qw.s7 = QW(7);
|
| 91 |
+
#undef QW
|
| 92 |
+
|
| 93 |
+
// cooperatively stage the 32-token x 32-K int8 activations to lm
|
| 94 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 95 |
+
const uint t = idx >> 3;
|
| 96 |
+
const uint u = idx & 7;
|
| 97 |
+
const uint c = col_base + t;
|
| 98 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 99 |
+
}
|
| 100 |
+
if (lid < TILESIZE_N) {
|
| 101 |
+
const uint c = col_base + lid;
|
| 102 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 103 |
+
sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
|
| 104 |
+
}
|
| 105 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 106 |
+
|
| 107 |
+
#define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
|
| 108 |
+
#pragma unroll
|
| 109 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 110 |
+
const int b = g * 4;
|
| 111 |
+
float4 rf;
|
| 112 |
+
rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
|
| 113 |
+
rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
|
| 114 |
+
acc[g] += d_w * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
|
| 115 |
+
}
|
| 116 |
+
#undef LD4
|
| 117 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
if (!row_valid) {
|
| 121 |
+
return;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
#pragma unroll
|
| 125 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 126 |
+
const uint b = (uint)(g * 4);
|
| 127 |
+
const float4 a = acc[g];
|
| 128 |
+
const uint c0 = col_base + b;
|
| 129 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 130 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 131 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 132 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 133 |
+
}
|
| 134 |
+
#undef NGROUPS
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 138 |
+
kernel void kernel_gemm_noshuffle_q5_0_q8_1_dp4a_wimg(
|
| 139 |
+
__read_only image1d_buffer_t src0_qs_img, // q5_0 low nibbles as uint32 texels (2 ushorts/texel)
|
| 140 |
+
__global const uchar * src0_qh,
|
| 141 |
+
__global const half * src0_d,
|
| 142 |
+
__global const uint * src1_qa,
|
| 143 |
+
__global const half * src1_da,
|
| 144 |
+
__global const half * src1_sa,
|
| 145 |
+
__global float * dst,
|
| 146 |
+
ulong offsetd,
|
| 147 |
+
int m,
|
| 148 |
+
int n_no_padding,
|
| 149 |
+
int k
|
| 150 |
+
) {
|
| 151 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 152 |
+
|
| 153 |
+
const uint lid = get_local_id(0);
|
| 154 |
+
const uint block_id_m = get_global_id(1);
|
| 155 |
+
const uint block_id_n = get_global_id(2);
|
| 156 |
+
|
| 157 |
+
const uint row = block_id_m * 64 + lid;
|
| 158 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 159 |
+
const bool row_valid = row < (uint)m;
|
| 160 |
+
const uint rrow = row_valid ? row : 0;
|
| 161 |
+
|
| 162 |
+
const uint sel = (rrow & 1u) * 16u; // constant per WI: qs ushort half in its uint32 texel
|
| 163 |
+
|
| 164 |
+
const uint k_u = (uint)k >> 2;
|
| 165 |
+
const uint k_b = (uint)k >> 5;
|
| 166 |
+
|
| 167 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 168 |
+
__local half sh_d[TILESIZE_N];
|
| 169 |
+
__local half sh_s[TILESIZE_N];
|
| 170 |
+
|
| 171 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 172 |
+
float4 acc[NGROUPS];
|
| 173 |
+
#pragma unroll
|
| 174 |
+
for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
|
| 175 |
+
|
| 176 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 177 |
+
const uint sub = step >> 5;
|
| 178 |
+
|
| 179 |
+
const float d_w = (float)src0_d[rrow + sub * (uint)m];
|
| 180 |
+
const float minv = d_w * 16.0f;
|
| 181 |
+
|
| 182 |
+
const uint qsbase = rrow + (step >> 2) * (uint)m; // ushort index
|
| 183 |
+
const uint qhbase = rrow + (step >> 3) * (uint)m;
|
| 184 |
+
uint8 qw;
|
| 185 |
+
// qs ushort via texture: uint32 texel = ushort_index>>1, half = sel.
|
| 186 |
+
#define QSU(u) ((read_imageui(src0_qs_img, (int)((qsbase + (u) * m) >> 1)).x >> sel) & 0xFFFFu)
|
| 187 |
+
#define QW(u) (EXP4(QSU(u)) | \
|
| 188 |
+
EXP1((uint)(src0_qh[qhbase + ((u) >> 1) * m] >> (((u) & 1u) * 4u)) & 0xFu))
|
| 189 |
+
qw.s0 = QW(0); qw.s1 = QW(1); qw.s2 = QW(2); qw.s3 = QW(3);
|
| 190 |
+
qw.s4 = QW(4); qw.s5 = QW(5); qw.s6 = QW(6); qw.s7 = QW(7);
|
| 191 |
+
#undef QW
|
| 192 |
+
#undef QSU
|
| 193 |
+
|
| 194 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 195 |
+
const uint t = idx >> 3;
|
| 196 |
+
const uint u = idx & 7;
|
| 197 |
+
const uint c = col_base + t;
|
| 198 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 199 |
+
}
|
| 200 |
+
if (lid < TILESIZE_N) {
|
| 201 |
+
const uint c = col_base + lid;
|
| 202 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 203 |
+
sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
|
| 204 |
+
}
|
| 205 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 206 |
+
|
| 207 |
+
#define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
|
| 208 |
+
#pragma unroll
|
| 209 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 210 |
+
const int b = g * 4;
|
| 211 |
+
float4 rf;
|
| 212 |
+
rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
|
| 213 |
+
rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
|
| 214 |
+
acc[g] += d_w * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
|
| 215 |
+
}
|
| 216 |
+
#undef LD4
|
| 217 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
if (!row_valid) {
|
| 221 |
+
return;
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
#pragma unroll
|
| 225 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 226 |
+
const uint b = (uint)(g * 4);
|
| 227 |
+
const float4 a = acc[g];
|
| 228 |
+
const uint c0 = col_base + b;
|
| 229 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 230 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 231 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 232 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 233 |
+
}
|
| 234 |
+
#undef NGROUPS
|
| 235 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_1_f32.cl
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
#ifdef ADRENO_GPU
|
| 11 |
+
REQD_SUBGROUP_SIZE_128
|
| 12 |
+
#endif
|
| 13 |
+
|
| 14 |
+
kernel void kernel_gemm_noshuffle_q5_1_f32(
|
| 15 |
+
global const ushort * src0_qs, // quantized A
|
| 16 |
+
global const uchar * src0_qh, // 5th bits
|
| 17 |
+
global const half * src0_d, // A scales
|
| 18 |
+
global const half * src0_m, // A mins
|
| 19 |
+
__read_only image1d_buffer_t src1, // B (1d image)
|
| 20 |
+
global float * dst, // C
|
| 21 |
+
int m, // M
|
| 22 |
+
int n, // N with padding
|
| 23 |
+
int k, // K
|
| 24 |
+
int n_no_padding // N without padding
|
| 25 |
+
) {
|
| 26 |
+
|
| 27 |
+
int n_4 = n >> 2;
|
| 28 |
+
|
| 29 |
+
int gy = get_global_id(0);
|
| 30 |
+
int gx = get_global_id(1);
|
| 31 |
+
int gx_2 = gx << 2;
|
| 32 |
+
|
| 33 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
| 34 |
+
half8 B;
|
| 35 |
+
half4 dequantized_weights;
|
| 36 |
+
|
| 37 |
+
global const ushort * weight_ptr = src0_qs + gx_2;
|
| 38 |
+
global const uchar * qh_ptr = src0_qh + gx_2;
|
| 39 |
+
global const half * scale_ptr = src0_d + gx_2;
|
| 40 |
+
global const half * min_ptr = src0_m + gx_2;
|
| 41 |
+
|
| 42 |
+
for (int i = 0; i < k; i += 4) {
|
| 43 |
+
|
| 44 |
+
B.s0123 = read_imageh(src1, gy*2 + i*n_4);
|
| 45 |
+
B.s4567 = read_imageh(src1, gy*2 + i*n_4 + 1);
|
| 46 |
+
|
| 47 |
+
ushort4 bits4 = vload4(0, weight_ptr + (i >> 2)*m);
|
| 48 |
+
uchar4 bits1 = vload4(0, qh_ptr + (i >> 3)*m);
|
| 49 |
+
uchar4 qh = bits1 >> (uchar4)(i & 4);
|
| 50 |
+
|
| 51 |
+
half4 scale = vload4(0, scale_ptr + (i >> 5)*m);
|
| 52 |
+
half4 minv = vload4(0, min_ptr + (i >> 5)*m);
|
| 53 |
+
|
| 54 |
+
// j=0
|
| 55 |
+
dequantized_weights.s0 = convert_half((bits4.s0 & 0x000F) | ((qh.s0 & 0x01) << 4)) * scale.s0 + minv.s0;
|
| 56 |
+
dequantized_weights.s1 = convert_half((bits4.s1 & 0x000F) | ((qh.s1 & 0x01) << 4)) * scale.s1 + minv.s1;
|
| 57 |
+
dequantized_weights.s2 = convert_half((bits4.s2 & 0x000F) | ((qh.s2 & 0x01) << 4)) * scale.s2 + minv.s2;
|
| 58 |
+
dequantized_weights.s3 = convert_half((bits4.s3 & 0x000F) | ((qh.s3 & 0x01) << 4)) * scale.s3 + minv.s3;
|
| 59 |
+
c0 += B * dequantized_weights.s0;
|
| 60 |
+
c1 += B * dequantized_weights.s1;
|
| 61 |
+
c2 += B * dequantized_weights.s2;
|
| 62 |
+
c3 += B * dequantized_weights.s3;
|
| 63 |
+
|
| 64 |
+
// j=1
|
| 65 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+1)*n_4);
|
| 66 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+1)*n_4 + 1);
|
| 67 |
+
dequantized_weights.s0 = convert_half(((bits4.s0 & 0x00F0) >> 4) | ((qh.s0 & 0x02) << 3)) * scale.s0 + minv.s0;
|
| 68 |
+
dequantized_weights.s1 = convert_half(((bits4.s1 & 0x00F0) >> 4) | ((qh.s1 & 0x02) << 3)) * scale.s1 + minv.s1;
|
| 69 |
+
dequantized_weights.s2 = convert_half(((bits4.s2 & 0x00F0) >> 4) | ((qh.s2 & 0x02) << 3)) * scale.s2 + minv.s2;
|
| 70 |
+
dequantized_weights.s3 = convert_half(((bits4.s3 & 0x00F0) >> 4) | ((qh.s3 & 0x02) << 3)) * scale.s3 + minv.s3;
|
| 71 |
+
c0 += B * dequantized_weights.s0;
|
| 72 |
+
c1 += B * dequantized_weights.s1;
|
| 73 |
+
c2 += B * dequantized_weights.s2;
|
| 74 |
+
c3 += B * dequantized_weights.s3;
|
| 75 |
+
|
| 76 |
+
// j=2
|
| 77 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+2)*n_4);
|
| 78 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+2)*n_4 + 1);
|
| 79 |
+
dequantized_weights.s0 = convert_half(((bits4.s0 & 0x0F00) >> 8) | ((qh.s0 & 0x04) << 2)) * scale.s0 + minv.s0;
|
| 80 |
+
dequantized_weights.s1 = convert_half(((bits4.s1 & 0x0F00) >> 8) | ((qh.s1 & 0x04) << 2)) * scale.s1 + minv.s1;
|
| 81 |
+
dequantized_weights.s2 = convert_half(((bits4.s2 & 0x0F00) >> 8) | ((qh.s2 & 0x04) << 2)) * scale.s2 + minv.s2;
|
| 82 |
+
dequantized_weights.s3 = convert_half(((bits4.s3 & 0x0F00) >> 8) | ((qh.s3 & 0x04) << 2)) * scale.s3 + minv.s3;
|
| 83 |
+
c0 += B * dequantized_weights.s0;
|
| 84 |
+
c1 += B * dequantized_weights.s1;
|
| 85 |
+
c2 += B * dequantized_weights.s2;
|
| 86 |
+
c3 += B * dequantized_weights.s3;
|
| 87 |
+
|
| 88 |
+
// j=3
|
| 89 |
+
B.s0123 = read_imageh(src1, gy*2 + (i+3)*n_4);
|
| 90 |
+
B.s4567 = read_imageh(src1, gy*2 + (i+3)*n_4 + 1);
|
| 91 |
+
dequantized_weights.s0 = convert_half(((bits4.s0 & 0xF000) >> 12) | ((qh.s0 & 0x08) << 1)) * scale.s0 + minv.s0;
|
| 92 |
+
dequantized_weights.s1 = convert_half(((bits4.s1 & 0xF000) >> 12) | ((qh.s1 & 0x08) << 1)) * scale.s1 + minv.s1;
|
| 93 |
+
dequantized_weights.s2 = convert_half(((bits4.s2 & 0xF000) >> 12) | ((qh.s2 & 0x08) << 1)) * scale.s2 + minv.s2;
|
| 94 |
+
dequantized_weights.s3 = convert_half(((bits4.s3 & 0xF000) >> 12) | ((qh.s3 & 0x08) << 1)) * scale.s3 + minv.s3;
|
| 95 |
+
c0 += B * dequantized_weights.s0;
|
| 96 |
+
c1 += B * dequantized_weights.s1;
|
| 97 |
+
c2 += B * dequantized_weights.s2;
|
| 98 |
+
c3 += B * dequantized_weights.s3;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
int idx = (gy<<3)*m + (gx<<2);
|
| 102 |
+
|
| 103 |
+
if(idx+3 < m*n_no_padding){
|
| 104 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 105 |
+
idx += m;
|
| 106 |
+
}
|
| 107 |
+
if(idx+3 < m*n_no_padding){
|
| 108 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 109 |
+
idx += m;
|
| 110 |
+
}
|
| 111 |
+
if(idx+3 < m*n_no_padding){
|
| 112 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 113 |
+
idx += m;
|
| 114 |
+
}
|
| 115 |
+
if(idx+3 < m*n_no_padding){
|
| 116 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 117 |
+
idx += m;
|
| 118 |
+
}
|
| 119 |
+
if(idx+3 < m*n_no_padding){
|
| 120 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 121 |
+
idx += m;
|
| 122 |
+
}
|
| 123 |
+
if(idx+3 < m*n_no_padding){
|
| 124 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 125 |
+
idx += m;
|
| 126 |
+
}
|
| 127 |
+
if(idx+3 < m*n_no_padding){
|
| 128 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 129 |
+
idx += m;
|
| 130 |
+
}
|
| 131 |
+
if(idx+3 < m*n_no_padding){
|
| 132 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 133 |
+
}
|
| 134 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_k_f32.cl
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
|
| 3 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 4 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 5 |
+
#define ADRENO_GPU 1
|
| 6 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 7 |
+
#endif
|
| 8 |
+
#define QK_K 256
|
| 9 |
+
#define K_SCALE_SIZE 12
|
| 10 |
+
|
| 11 |
+
inline void get_scale_min_k4(
|
| 12 |
+
int j,
|
| 13 |
+
global const uchar * q,
|
| 14 |
+
uchar * d,
|
| 15 |
+
uchar * m,
|
| 16 |
+
uchar mask_d6,
|
| 17 |
+
uchar mask_d4,
|
| 18 |
+
uchar mask_hi2
|
| 19 |
+
) {
|
| 20 |
+
if (j < 4) {
|
| 21 |
+
*d = q[j] & mask_d6;
|
| 22 |
+
*m = q[j+4] & mask_d6;
|
| 23 |
+
} else {
|
| 24 |
+
*d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
|
| 25 |
+
*m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
#ifdef ADRENO_GPU
|
| 30 |
+
REQD_SUBGROUP_SIZE_128
|
| 31 |
+
#endif
|
| 32 |
+
kernel void kernel_gemm_noshuffle_q5_k_f32(
|
| 33 |
+
global const ushort * src0_q,
|
| 34 |
+
global const uchar * src0_qh,
|
| 35 |
+
global const uchar * src0_s,
|
| 36 |
+
global const half * src0_d,
|
| 37 |
+
global const half * src0_dm,
|
| 38 |
+
read_only image1d_buffer_t src1,
|
| 39 |
+
global float * dst,
|
| 40 |
+
ulong offsetd,
|
| 41 |
+
int m,
|
| 42 |
+
int n,
|
| 43 |
+
int k,
|
| 44 |
+
int n_no_padding,
|
| 45 |
+
uchar mask_d6,
|
| 46 |
+
uchar mask_d4,
|
| 47 |
+
uchar mask_hi2
|
| 48 |
+
) {
|
| 49 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 50 |
+
int n_4 = n >> 2;
|
| 51 |
+
int gy = get_global_id(0);
|
| 52 |
+
int gx = get_global_id(1);
|
| 53 |
+
int gx_2 = gx << 2;
|
| 54 |
+
|
| 55 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
| 56 |
+
half8 B;
|
| 57 |
+
half4 dequantized_weights;
|
| 58 |
+
|
| 59 |
+
int num_blocks_K = k / QK_K;
|
| 60 |
+
|
| 61 |
+
global const ushort * weight_ptr = src0_q + gx_2;
|
| 62 |
+
global const uchar * qh_ptr = src0_qh + gx_2;
|
| 63 |
+
global const half * d_ptr = src0_d + gx_2;
|
| 64 |
+
global const half * dm_ptr = src0_dm + gx_2;
|
| 65 |
+
|
| 66 |
+
for (int i = 0; i < k; i += 32) {
|
| 67 |
+
int sb_idx = i / QK_K;
|
| 68 |
+
int sub_idx = (i / 32) % 8;
|
| 69 |
+
|
| 70 |
+
half4 d = vload4(0, d_ptr + sb_idx * m);
|
| 71 |
+
half4 dm = vload4(0, dm_ptr + sb_idx * m);
|
| 72 |
+
|
| 73 |
+
global const uchar * sc0 = src0_s + (gx_2+0) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 74 |
+
global const uchar * sc1 = src0_s + (gx_2+1) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 75 |
+
global const uchar * sc2 = src0_s + (gx_2+2) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 76 |
+
global const uchar * sc3 = src0_s + (gx_2+3) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 77 |
+
|
| 78 |
+
uchar sv0, mn0, sv1, mn1, sv2, mn2, sv3, mn3;
|
| 79 |
+
get_scale_min_k4(sub_idx, sc0, &sv0, &mn0, mask_d6, mask_d4, mask_hi2);
|
| 80 |
+
get_scale_min_k4(sub_idx, sc1, &sv1, &mn1, mask_d6, mask_d4, mask_hi2);
|
| 81 |
+
get_scale_min_k4(sub_idx, sc2, &sv2, &mn2, mask_d6, mask_d4, mask_hi2);
|
| 82 |
+
get_scale_min_k4(sub_idx, sc3, &sv3, &mn3, mask_d6, mask_d4, mask_hi2);
|
| 83 |
+
|
| 84 |
+
half4 scale = convert_half4(convert_float4(d) * convert_float4((uchar4)(sv0, sv1, sv2, sv3)));
|
| 85 |
+
half4 mval = convert_half4(convert_float4(dm) * convert_float4((uchar4)(mn0, mn1, mn2, mn3)));
|
| 86 |
+
|
| 87 |
+
for (int l = 0; l < 32; l += 4) {
|
| 88 |
+
int ki = i + l;
|
| 89 |
+
ushort4 bits4 = vload4(0, weight_ptr + (ki/4) * m);
|
| 90 |
+
uchar4 qh_bits = vload4(0, qh_ptr + (ki/8) * m);
|
| 91 |
+
int qh_shift = ki % 8;
|
| 92 |
+
|
| 93 |
+
// j=0
|
| 94 |
+
B.s0123 = read_imageh(src1, gy*2 + (ki+0) * n_4);
|
| 95 |
+
B.s4567 = read_imageh(src1, gy*2+1 + (ki+0) * n_4);
|
| 96 |
+
dequantized_weights.s0 = ((bits4.s0 & 0x000F) | (((qh_bits.s0 >> (qh_shift+0)) & 1) << 4)) * scale.s0 - mval.s0;
|
| 97 |
+
dequantized_weights.s1 = ((bits4.s1 & 0x000F) | (((qh_bits.s1 >> (qh_shift+0)) & 1) << 4)) * scale.s1 - mval.s1;
|
| 98 |
+
dequantized_weights.s2 = ((bits4.s2 & 0x000F) | (((qh_bits.s2 >> (qh_shift+0)) & 1) << 4)) * scale.s2 - mval.s2;
|
| 99 |
+
dequantized_weights.s3 = ((bits4.s3 & 0x000F) | (((qh_bits.s3 >> (qh_shift+0)) & 1) << 4)) * scale.s3 - mval.s3;
|
| 100 |
+
c0 += B * dequantized_weights.s0;
|
| 101 |
+
c1 += B * dequantized_weights.s1;
|
| 102 |
+
c2 += B * dequantized_weights.s2;
|
| 103 |
+
c3 += B * dequantized_weights.s3;
|
| 104 |
+
|
| 105 |
+
// j=1
|
| 106 |
+
B.s0123 = read_imageh(src1, gy*2 + (ki+1) * n_4);
|
| 107 |
+
B.s4567 = read_imageh(src1, gy*2+1 + (ki+1) * n_4);
|
| 108 |
+
dequantized_weights.s0 = (((bits4.s0 & 0x00F0) >> 4) | (((qh_bits.s0 >> (qh_shift+1)) & 1) << 4)) * scale.s0 - mval.s0;
|
| 109 |
+
dequantized_weights.s1 = (((bits4.s1 & 0x00F0) >> 4) | (((qh_bits.s1 >> (qh_shift+1)) & 1) << 4)) * scale.s1 - mval.s1;
|
| 110 |
+
dequantized_weights.s2 = (((bits4.s2 & 0x00F0) >> 4) | (((qh_bits.s2 >> (qh_shift+1)) & 1) << 4)) * scale.s2 - mval.s2;
|
| 111 |
+
dequantized_weights.s3 = (((bits4.s3 & 0x00F0) >> 4) | (((qh_bits.s3 >> (qh_shift+1)) & 1) << 4)) * scale.s3 - mval.s3;
|
| 112 |
+
c0 += B * dequantized_weights.s0;
|
| 113 |
+
c1 += B * dequantized_weights.s1;
|
| 114 |
+
c2 += B * dequantized_weights.s2;
|
| 115 |
+
c3 += B * dequantized_weights.s3;
|
| 116 |
+
|
| 117 |
+
// j=2
|
| 118 |
+
B.s0123 = read_imageh(src1, gy*2 + (ki+2) * n_4);
|
| 119 |
+
B.s4567 = read_imageh(src1, gy*2+1 + (ki+2) * n_4);
|
| 120 |
+
dequantized_weights.s0 = (((bits4.s0 & 0x0F00) >> 8) | (((qh_bits.s0 >> (qh_shift+2)) & 1) << 4)) * scale.s0 - mval.s0;
|
| 121 |
+
dequantized_weights.s1 = (((bits4.s1 & 0x0F00) >> 8) | (((qh_bits.s1 >> (qh_shift+2)) & 1) << 4)) * scale.s1 - mval.s1;
|
| 122 |
+
dequantized_weights.s2 = (((bits4.s2 & 0x0F00) >> 8) | (((qh_bits.s2 >> (qh_shift+2)) & 1) << 4)) * scale.s2 - mval.s2;
|
| 123 |
+
dequantized_weights.s3 = (((bits4.s3 & 0x0F00) >> 8) | (((qh_bits.s3 >> (qh_shift+2)) & 1) << 4)) * scale.s3 - mval.s3;
|
| 124 |
+
c0 += B * dequantized_weights.s0;
|
| 125 |
+
c1 += B * dequantized_weights.s1;
|
| 126 |
+
c2 += B * dequantized_weights.s2;
|
| 127 |
+
c3 += B * dequantized_weights.s3;
|
| 128 |
+
|
| 129 |
+
// j=3
|
| 130 |
+
B.s0123 = read_imageh(src1, gy*2 + (ki+3) * n_4);
|
| 131 |
+
B.s4567 = read_imageh(src1, gy*2+1 + (ki+3) * n_4);
|
| 132 |
+
dequantized_weights.s0 = (((bits4.s0 & 0xF000) >> 12) | (((qh_bits.s0 >> (qh_shift+3)) & 1) << 4)) * scale.s0 - mval.s0;
|
| 133 |
+
dequantized_weights.s1 = (((bits4.s1 & 0xF000) >> 12) | (((qh_bits.s1 >> (qh_shift+3)) & 1) << 4)) * scale.s1 - mval.s1;
|
| 134 |
+
dequantized_weights.s2 = (((bits4.s2 & 0xF000) >> 12) | (((qh_bits.s2 >> (qh_shift+3)) & 1) << 4)) * scale.s2 - mval.s2;
|
| 135 |
+
dequantized_weights.s3 = (((bits4.s3 & 0xF000) >> 12) | (((qh_bits.s3 >> (qh_shift+3)) & 1) << 4)) * scale.s3 - mval.s3;
|
| 136 |
+
c0 += B * dequantized_weights.s0;
|
| 137 |
+
c1 += B * dequantized_weights.s1;
|
| 138 |
+
c2 += B * dequantized_weights.s2;
|
| 139 |
+
c3 += B * dequantized_weights.s3;
|
| 140 |
+
}
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
int idx = (gy<<3)*m + (gx<<2);
|
| 144 |
+
|
| 145 |
+
if (idx+3 < m*n_no_padding) {
|
| 146 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 147 |
+
idx += m;
|
| 148 |
+
}
|
| 149 |
+
if (idx+3 < m*n_no_padding) {
|
| 150 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 151 |
+
idx += m;
|
| 152 |
+
}
|
| 153 |
+
if (idx+3 < m*n_no_padding) {
|
| 154 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 155 |
+
idx += m;
|
| 156 |
+
}
|
| 157 |
+
if (idx+3 < m*n_no_padding) {
|
| 158 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 159 |
+
idx += m;
|
| 160 |
+
}
|
| 161 |
+
if (idx+3 < m*n_no_padding) {
|
| 162 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 163 |
+
idx += m;
|
| 164 |
+
}
|
| 165 |
+
if (idx+3 < m*n_no_padding) {
|
| 166 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 167 |
+
idx += m;
|
| 168 |
+
}
|
| 169 |
+
if (idx+3 < m*n_no_padding) {
|
| 170 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 171 |
+
idx += m;
|
| 172 |
+
}
|
| 173 |
+
if (idx+3 < m*n_no_padding) {
|
| 174 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 175 |
+
}
|
| 176 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q5_k_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_N 32
|
| 8 |
+
#define QK_K 256
|
| 9 |
+
#define K_SCALE_SIZE 12
|
| 10 |
+
|
| 11 |
+
inline void get_scale_min_k4(
|
| 12 |
+
int j,
|
| 13 |
+
global const uchar * q,
|
| 14 |
+
uchar * d,
|
| 15 |
+
uchar * m,
|
| 16 |
+
uchar mask_d6,
|
| 17 |
+
uchar mask_d4,
|
| 18 |
+
uchar mask_hi2
|
| 19 |
+
) {
|
| 20 |
+
if (j < 4) {
|
| 21 |
+
*d = q[j] & mask_d6;
|
| 22 |
+
*m = q[j+4] & mask_d6;
|
| 23 |
+
} else {
|
| 24 |
+
*d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
|
| 25 |
+
*m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
// 4 nibbles in the low 16 bits of `u` -> 4 bytes (value 0..15, bits 0-3).
|
| 30 |
+
#define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
|
| 31 |
+
(((uint)((u) & 0x00F0u)) << 4) | \
|
| 32 |
+
(((uint)((u) & 0x0F00u)) << 8) | \
|
| 33 |
+
(((uint)((u) & 0xF000u)) << 12) )
|
| 34 |
+
|
| 35 |
+
// 4 high bits (one per element, in bits 0-3 of h) -> bit 4 of each of 4 bytes,
|
| 36 |
+
// so OR with EXP4 forms the 5-bit q5_K code 0..31.
|
| 37 |
+
#define EXP1(h) ( (((uint)((h) & 0x1u)) << 4) | \
|
| 38 |
+
(((uint)((h) & 0x2u)) << 11) | \
|
| 39 |
+
(((uint)((h) & 0x4u)) << 18) | \
|
| 40 |
+
(((uint)((h) & 0x8u)) << 25) )
|
| 41 |
+
|
| 42 |
+
inline int dot8_q8a(uint8 qw, __local const uint * a) {
|
| 43 |
+
int r = 0;
|
| 44 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
|
| 45 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
|
| 46 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
|
| 47 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
|
| 48 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
|
| 49 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
|
| 50 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
|
| 51 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
|
| 52 |
+
return r;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 56 |
+
kernel void kernel_gemm_noshuffle_q5_k_q8_1_dp4a(
|
| 57 |
+
__global const ushort * src0_q, // q5_K low nibbles (transposed, ushort = 4 nibbles)
|
| 58 |
+
__global const uchar * src0_qh, // q5_K high bits (transposed, uchar = 8 elems/byte)
|
| 59 |
+
__global const uchar * src0_s, // 6-bit scale/min codes [row][superblock][12]
|
| 60 |
+
__global const half * src0_d, // per-superblock scale (transposed)
|
| 61 |
+
__global const half * src0_dm, // per-superblock min (transposed)
|
| 62 |
+
__global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
|
| 63 |
+
__global const half * src1_da, // q8_1 per-block scale [N, K/32]
|
| 64 |
+
__global const half * src1_sa, // q8_1 per-block sum*d [N, K/32]
|
| 65 |
+
__global float * dst,
|
| 66 |
+
ulong offsetd,
|
| 67 |
+
int m, // output features (rows)
|
| 68 |
+
int n_no_padding, // tokens (cols)
|
| 69 |
+
int k, // K (== ne00)
|
| 70 |
+
uchar mask_d6,
|
| 71 |
+
uchar mask_d4,
|
| 72 |
+
uchar mask_hi2
|
| 73 |
+
) {
|
| 74 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 75 |
+
|
| 76 |
+
const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
|
| 77 |
+
const uint block_id_m = get_global_id(1);
|
| 78 |
+
const uint block_id_n = get_global_id(2);
|
| 79 |
+
|
| 80 |
+
const uint row = block_id_m * 64 + lid;
|
| 81 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 82 |
+
const bool row_valid = row < (uint)m;
|
| 83 |
+
const uint rrow = row_valid ? row : 0;
|
| 84 |
+
|
| 85 |
+
const uint num_superblocks = (uint)k / QK_K;
|
| 86 |
+
const uint k_u = (uint)k >> 2;
|
| 87 |
+
const uint k_b = (uint)k >> 5;
|
| 88 |
+
|
| 89 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 90 |
+
__local half sh_d[TILESIZE_N];
|
| 91 |
+
__local half sh_s[TILESIZE_N];
|
| 92 |
+
|
| 93 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 94 |
+
float4 acc[NGROUPS];
|
| 95 |
+
#pragma unroll
|
| 96 |
+
for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
|
| 97 |
+
|
| 98 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 99 |
+
const uint sub = step >> 5;
|
| 100 |
+
const uint sb_idx = step / QK_K;
|
| 101 |
+
const uint sub_idx = sub & 7;
|
| 102 |
+
|
| 103 |
+
const float dd = (float)src0_d [rrow + sb_idx * m];
|
| 104 |
+
const float dmm = (float)src0_dm[rrow + sb_idx * m];
|
| 105 |
+
global const uchar * sc = src0_s + rrow * num_superblocks * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
| 106 |
+
uchar sv, mn;
|
| 107 |
+
get_scale_min_k4(sub_idx, sc, &sv, &mn, mask_d6, mask_d4, mask_hi2);
|
| 108 |
+
const float scale = dd * (float)sv;
|
| 109 |
+
const float minv = dmm * (float)mn;
|
| 110 |
+
|
| 111 |
+
// repack this row's 32 weights (nibble | high-bit) into 8 dp4a uints.
|
| 112 |
+
// ushort u -> 4 elements at K = step + u*4; its 4 high bits are nibble
|
| 113 |
+
// (u&1) of qh byte (step/8 + u/2).
|
| 114 |
+
const uint wbase = rrow + (step >> 2) * (uint)m;
|
| 115 |
+
const uint qhbase = rrow + (step >> 3) * (uint)m;
|
| 116 |
+
uint8 qw;
|
| 117 |
+
#define QWU(u) ( EXP4((uint)src0_q[wbase + (uint)(u) * m]) \
|
| 118 |
+
| EXP1( (uint)((src0_qh[qhbase + (uint)((u) >> 1) * m] >> (((u) & 1) * 4)) & 0x0Fu) ) )
|
| 119 |
+
qw.s0 = QWU(0); qw.s1 = QWU(1); qw.s2 = QWU(2); qw.s3 = QWU(3);
|
| 120 |
+
qw.s4 = QWU(4); qw.s5 = QWU(5); qw.s6 = QWU(6); qw.s7 = QWU(7);
|
| 121 |
+
#undef QWU
|
| 122 |
+
|
| 123 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 124 |
+
const uint t = idx >> 3;
|
| 125 |
+
const uint u = idx & 7;
|
| 126 |
+
const uint c = col_base + t;
|
| 127 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 128 |
+
}
|
| 129 |
+
if (lid < TILESIZE_N) {
|
| 130 |
+
const uint c = col_base + lid;
|
| 131 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 132 |
+
sh_s[lid] = (c < (uint)n_no_padding) ? src1_sa[c * k_b + sub] : (half)0;
|
| 133 |
+
}
|
| 134 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 135 |
+
|
| 136 |
+
#define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
|
| 137 |
+
#pragma unroll
|
| 138 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 139 |
+
const int b = g * 4;
|
| 140 |
+
float4 rf;
|
| 141 |
+
rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
|
| 142 |
+
rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
|
| 143 |
+
acc[g] += scale * LD4(sh_d, b) * rf - minv * LD4(sh_s, b);
|
| 144 |
+
}
|
| 145 |
+
#undef LD4
|
| 146 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
if (!row_valid) {
|
| 150 |
+
return;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
#pragma unroll
|
| 154 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 155 |
+
const uint b = (uint)(g * 4);
|
| 156 |
+
const float4 a = acc[g];
|
| 157 |
+
const uint c0 = col_base + b;
|
| 158 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 159 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 160 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 161 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 162 |
+
}
|
| 163 |
+
#undef NGROUPS
|
| 164 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q6_k_f32.cl
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
#ifdef ADRENO_GPU
|
| 11 |
+
REQD_SUBGROUP_SIZE_128
|
| 12 |
+
#endif
|
| 13 |
+
kernel void kernel_gemm_noshuffle_q6_K_f32(
|
| 14 |
+
global const ushort * src0_ql,
|
| 15 |
+
global const uchar * src0_qh,
|
| 16 |
+
global const ushort * src0_s,
|
| 17 |
+
global const half * src0_d,
|
| 18 |
+
read_only image1d_buffer_t src1,
|
| 19 |
+
global float * dst,
|
| 20 |
+
ulong offsetd,
|
| 21 |
+
int m,
|
| 22 |
+
int n,
|
| 23 |
+
int k,
|
| 24 |
+
int n_no_padding,
|
| 25 |
+
ushort mask_f000,
|
| 26 |
+
uchar mask_c0
|
| 27 |
+
) {
|
| 28 |
+
dst = (global float *)( (global char *)dst + offsetd );
|
| 29 |
+
|
| 30 |
+
int m_4 = m >> 2;
|
| 31 |
+
int n_4 = n >> 2;
|
| 32 |
+
|
| 33 |
+
int gy = get_global_id(0); // n
|
| 34 |
+
int gx = get_global_id(1); // m
|
| 35 |
+
int gx_2 = gx << 2;
|
| 36 |
+
|
| 37 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
| 38 |
+
half8 B;
|
| 39 |
+
half4 dequantized_weights;
|
| 40 |
+
|
| 41 |
+
global const ushort * ptr_ql = src0_ql + gx_2;
|
| 42 |
+
global const uchar * ptr_qh = src0_qh + gx_2;
|
| 43 |
+
global const ushort * ptr_s = src0_s + gx_2;
|
| 44 |
+
global const half * ptr_d = src0_d + gx_2;
|
| 45 |
+
|
| 46 |
+
for (int i = 0; i < k; i += 4) {
|
| 47 |
+
// load 4x elements (ushort) of ql on M, each ushort contains 4 weights
|
| 48 |
+
// 4x ushort correspons to 4 rows on M
|
| 49 |
+
ushort4 bits4 = vload4(0, ptr_ql + (i/4)*m); // ql packed in 4s in ushort
|
| 50 |
+
uchar4 bits2 = vload4(0, ptr_qh + (i/4)*m); // qh packed in 4s in uchar
|
| 51 |
+
|
| 52 |
+
// load 4 consecutive scales
|
| 53 |
+
char8 scale_s_8 = as_char8(vload4(0, ptr_s + (i/16/2)*m)); // 1 char scale every 16 elements, packed in 2s
|
| 54 |
+
char4 scale_s = ((i/16) % 2) == 0 ? scale_s_8.s0246 : scale_s_8.s1357; // transposed as ushort, 2 blocks
|
| 55 |
+
half4 scale_d = vload4(0, ptr_d + (i/256)*m); // 1 half scale every 256 elements
|
| 56 |
+
|
| 57 |
+
// j=0
|
| 58 |
+
// load 2x 4 elements of activations on N, corresponding to 8 rows on N
|
| 59 |
+
B.s0123 = read_imageh(src1, gy*2 + (i + 0)*n_4 + 0);
|
| 60 |
+
B.s4567 = read_imageh(src1, gy*2 + (i + 0)*n_4 + 1);
|
| 61 |
+
dequantized_weights.s0 = (convert_half((bits4.s0 & 0x000F) | ((bits2.s0 & 0x03) << 4)) - 32.f) * scale_s.s0 * scale_d.s0;
|
| 62 |
+
dequantized_weights.s1 = (convert_half((bits4.s1 & 0x000F) | ((bits2.s1 & 0x03) << 4)) - 32.f) * scale_s.s1 * scale_d.s1;
|
| 63 |
+
dequantized_weights.s2 = (convert_half((bits4.s2 & 0x000F) | ((bits2.s2 & 0x03) << 4)) - 32.f) * scale_s.s2 * scale_d.s2;
|
| 64 |
+
dequantized_weights.s3 = (convert_half((bits4.s3 & 0x000F) | ((bits2.s3 & 0x03) << 4)) - 32.f) * scale_s.s3 * scale_d.s3;
|
| 65 |
+
c0 += B * dequantized_weights.s0;
|
| 66 |
+
c1 += B * dequantized_weights.s1;
|
| 67 |
+
c2 += B * dequantized_weights.s2;
|
| 68 |
+
c3 += B * dequantized_weights.s3;
|
| 69 |
+
|
| 70 |
+
// j=1
|
| 71 |
+
B.s0123 = read_imageh(src1, gy*2 + (i + 1)*n_4 + 0);
|
| 72 |
+
B.s4567 = read_imageh(src1, gy*2 + (i + 1)*n_4 + 1);
|
| 73 |
+
dequantized_weights.s0 = (convert_half((((bits4.s0 & 0x00F0) >> 4) | ((bits2.s0 & 0x0C) << 2))) - 32.f) * scale_s.s0 * scale_d.s0;
|
| 74 |
+
dequantized_weights.s1 = (convert_half((((bits4.s1 & 0x00F0) >> 4) | ((bits2.s1 & 0x0C) << 2))) - 32.f) * scale_s.s1 * scale_d.s1;
|
| 75 |
+
dequantized_weights.s2 = (convert_half((((bits4.s2 & 0x00F0) >> 4) | ((bits2.s2 & 0x0C) << 2))) - 32.f) * scale_s.s2 * scale_d.s2;
|
| 76 |
+
dequantized_weights.s3 = (convert_half((((bits4.s3 & 0x00F0) >> 4) | ((bits2.s3 & 0x0C) << 2))) - 32.f) * scale_s.s3 * scale_d.s3;
|
| 77 |
+
c0 += B * dequantized_weights.s0;
|
| 78 |
+
c1 += B * dequantized_weights.s1;
|
| 79 |
+
c2 += B * dequantized_weights.s2;
|
| 80 |
+
c3 += B * dequantized_weights.s3;
|
| 81 |
+
|
| 82 |
+
// j=2
|
| 83 |
+
B.s0123 = read_imageh(src1, gy*2 + (i + 2)*n_4 + 0);
|
| 84 |
+
B.s4567 = read_imageh(src1, gy*2 + (i + 2)*n_4 + 1);
|
| 85 |
+
dequantized_weights.s0 = (convert_half((((bits4.s0 & 0x0F00) >> 8) | (bits2.s0 & 0x30))) - 32.f) * scale_s.s0 * scale_d.s0;
|
| 86 |
+
dequantized_weights.s1 = (convert_half((((bits4.s1 & 0x0F00) >> 8) | (bits2.s1 & 0x30))) - 32.f) * scale_s.s1 * scale_d.s1;
|
| 87 |
+
dequantized_weights.s2 = (convert_half((((bits4.s2 & 0x0F00) >> 8) | (bits2.s2 & 0x30))) - 32.f) * scale_s.s2 * scale_d.s2;
|
| 88 |
+
dequantized_weights.s3 = (convert_half((((bits4.s3 & 0x0F00) >> 8) | (bits2.s3 & 0x30))) - 32.f) * scale_s.s3 * scale_d.s3;
|
| 89 |
+
c0 += B * dequantized_weights.s0;
|
| 90 |
+
c1 += B * dequantized_weights.s1;
|
| 91 |
+
c2 += B * dequantized_weights.s2;
|
| 92 |
+
c3 += B * dequantized_weights.s3;
|
| 93 |
+
|
| 94 |
+
// j=3
|
| 95 |
+
B.s0123 = read_imageh(src1, gy*2 + (i + 3)*n_4 + 0);
|
| 96 |
+
B.s4567 = read_imageh(src1, gy*2 + (i + 3)*n_4 + 1);
|
| 97 |
+
dequantized_weights.s0 = (convert_half((((bits4.s0 & mask_f000) >> 12) | ((bits2.s0 & mask_c0) >> 2))) - 32.f) * scale_s.s0 * scale_d.s0;
|
| 98 |
+
dequantized_weights.s1 = (convert_half((((bits4.s1 & mask_f000) >> 12) | ((bits2.s1 & mask_c0) >> 2))) - 32.f) * scale_s.s1 * scale_d.s1;
|
| 99 |
+
dequantized_weights.s2 = (convert_half((((bits4.s2 & mask_f000) >> 12) | ((bits2.s2 & mask_c0) >> 2))) - 32.f) * scale_s.s2 * scale_d.s2;
|
| 100 |
+
dequantized_weights.s3 = (convert_half((((bits4.s3 & mask_f000) >> 12) | ((bits2.s3 & mask_c0) >> 2))) - 32.f) * scale_s.s3 * scale_d.s3;
|
| 101 |
+
c0 += B * dequantized_weights.s0;
|
| 102 |
+
c1 += B * dequantized_weights.s1;
|
| 103 |
+
c2 += B * dequantized_weights.s2;
|
| 104 |
+
c3 += B * dequantized_weights.s3;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
int idx = (gy<<3)*m + (gx<<2);
|
| 108 |
+
|
| 109 |
+
if(idx+3 < m*n_no_padding){
|
| 110 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 111 |
+
idx += m;
|
| 112 |
+
}
|
| 113 |
+
if(idx+3 < m*n_no_padding){
|
| 114 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 115 |
+
idx += m;
|
| 116 |
+
}
|
| 117 |
+
if(idx+3 < m*n_no_padding){
|
| 118 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 119 |
+
idx += m;
|
| 120 |
+
}
|
| 121 |
+
if(idx+3 < m*n_no_padding){
|
| 122 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 123 |
+
idx += m;
|
| 124 |
+
}
|
| 125 |
+
if(idx+3 < m*n_no_padding){
|
| 126 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 127 |
+
idx += m;
|
| 128 |
+
}
|
| 129 |
+
if(idx+3 < m*n_no_padding){
|
| 130 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 131 |
+
idx += m;
|
| 132 |
+
}
|
| 133 |
+
if(idx+3 < m*n_no_padding){
|
| 134 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 135 |
+
idx += m;
|
| 136 |
+
}
|
| 137 |
+
if(idx+3 < m*n_no_padding){
|
| 138 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 139 |
+
}
|
| 140 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q6_k_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
#define TILESIZE_N 32
|
| 8 |
+
#define QK_K 256
|
| 9 |
+
|
| 10 |
+
// 4 nibbles in the low 16 bits of `u` -> 4 bytes (value 0..15, in bits 0-3).
|
| 11 |
+
#define EXP4(u) ( ((uint)((u) & 0x000Fu)) | \
|
| 12 |
+
(((uint)((u) & 0x00F0u)) << 4) | \
|
| 13 |
+
(((uint)((u) & 0x0F00u)) << 8) | \
|
| 14 |
+
(((uint)((u) & 0xF000u)) << 12) )
|
| 15 |
+
|
| 16 |
+
// 4 2-bit highs in byte `b` -> 4 bytes, value 0..3 in bits 4-5 (pre-multiplied
|
| 17 |
+
// by 16 so it ORs with the EXP4 nibble to form q6 in 0..63).
|
| 18 |
+
#define EXP2(b) ( (((uint)((b) & 0x03u)) << 4) | \
|
| 19 |
+
(((uint)((b) & 0x0Cu)) << 10) | \
|
| 20 |
+
(((uint)((b) & 0x30u)) << 16) | \
|
| 21 |
+
(((uint)((b) & 0xC0u)) << 22) )
|
| 22 |
+
|
| 23 |
+
// q6 (0..63, bits 0-5 of each byte) -> (q6-32) as a signed int8 per byte.
|
| 24 |
+
inline uint SIGN6(uint q6p) {
|
| 25 |
+
uint x = q6p ^ 0x20202020u;
|
| 26 |
+
uint s = x & 0x20202020u;
|
| 27 |
+
return x | (s << 1) | (s << 2);
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
// 16-K dp4a dot: 4 packed weight uints against 4 packed int8 activation uints.
|
| 31 |
+
inline int dot4_q8a(uint w0, uint w1, uint w2, uint w3,
|
| 32 |
+
uint a0, uint a1, uint a2, uint a3) {
|
| 33 |
+
int r = 0;
|
| 34 |
+
r = dot_acc_sat_4x8packed_ss_int(w0, a0, r);
|
| 35 |
+
r = dot_acc_sat_4x8packed_ss_int(w1, a1, r);
|
| 36 |
+
r = dot_acc_sat_4x8packed_ss_int(w2, a2, r);
|
| 37 |
+
r = dot_acc_sat_4x8packed_ss_int(w3, a3, r);
|
| 38 |
+
return r;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 42 |
+
kernel void kernel_gemm_noshuffle_q6_k_q8_1_dp4a(
|
| 43 |
+
__global const ushort * src0_ql, // q6_K low nibbles (noshuffle)
|
| 44 |
+
__global const uchar * src0_qh, // q6_K high 2-bit (uchar, 4 highs/elem)
|
| 45 |
+
__global const ushort * src0_s, // int8 scale codes (2 chars/ushort, per 16)
|
| 46 |
+
__global const half * src0_d, // per-superblock scale
|
| 47 |
+
__global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
|
| 48 |
+
__global const half * src1_da, // q8_1 per-block scale [N, K/32]
|
| 49 |
+
__global float * dst,
|
| 50 |
+
ulong offsetd,
|
| 51 |
+
int m, // output features (rows)
|
| 52 |
+
int n_no_padding, // tokens (cols)
|
| 53 |
+
int k // K (== ne00)
|
| 54 |
+
) {
|
| 55 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 56 |
+
|
| 57 |
+
const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
|
| 58 |
+
const uint block_id_m = get_global_id(1);
|
| 59 |
+
const uint block_id_n = get_global_id(2);
|
| 60 |
+
|
| 61 |
+
const uint row = block_id_m * 64 + lid;
|
| 62 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 63 |
+
const bool row_valid = row < (uint)m;
|
| 64 |
+
const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
|
| 65 |
+
|
| 66 |
+
const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
|
| 67 |
+
const uint k_b = (uint)k >> 5; // blocks-of-32 along K
|
| 68 |
+
|
| 69 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 70 |
+
__local half sh_d[TILESIZE_N];
|
| 71 |
+
|
| 72 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 73 |
+
float4 acc[NGROUPS];
|
| 74 |
+
#pragma unroll
|
| 75 |
+
for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
|
| 76 |
+
|
| 77 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 78 |
+
const uint sub = step >> 5; // 32-block index along K
|
| 79 |
+
const uint sb_idx = step / QK_K; // superblock index
|
| 80 |
+
|
| 81 |
+
// q6_K superblock scale + the two int8 sub-scales spanning this 32-block
|
| 82 |
+
const float dd = (float)src0_d[rrow + sb_idx * m];
|
| 83 |
+
const char2 sc = as_char2(src0_s[rrow + sub * m]);
|
| 84 |
+
const float scale0 = dd * (float)sc.s0; // K step..step+15
|
| 85 |
+
const float scale1 = dd * (float)sc.s1; // K step+16..step+31
|
| 86 |
+
|
| 87 |
+
// repack this row's 32 weights into 8 dp4a uints (4 K each). ql ushort +
|
| 88 |
+
// qh uchar are co-located at src0_*[row + (step/4 + u)*m].
|
| 89 |
+
const uint wbase = rrow + (step >> 2) * (uint)m;
|
| 90 |
+
uint qw[8];
|
| 91 |
+
#pragma unroll
|
| 92 |
+
for (int u = 0; u < 8; ++u) {
|
| 93 |
+
const uint o = wbase + (uint)u * (uint)m;
|
| 94 |
+
qw[u] = SIGN6(EXP4((uint)src0_ql[o]) | EXP2((uint)src0_qh[o]));
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
// cooperatively stage the 32-token x 32-K int8 activations + scale
|
| 98 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 99 |
+
const uint t = idx >> 3;
|
| 100 |
+
const uint u = idx & 7;
|
| 101 |
+
const uint c = col_base + t;
|
| 102 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 103 |
+
}
|
| 104 |
+
if (lid < TILESIZE_N) {
|
| 105 |
+
const uint c = col_base + lid;
|
| 106 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 107 |
+
}
|
| 108 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 109 |
+
|
| 110 |
+
#pragma unroll
|
| 111 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 112 |
+
const int b = g * 4;
|
| 113 |
+
float4 rf;
|
| 114 |
+
#define DOT_TOK(j) { \
|
| 115 |
+
__local const uint * a = sh_qa[b + (j)]; \
|
| 116 |
+
const int raw1 = dot4_q8a(qw[0], qw[1], qw[2], qw[3], a[0], a[1], a[2], a[3]); \
|
| 117 |
+
const int raw2 = dot4_q8a(qw[4], qw[5], qw[6], qw[7], a[4], a[5], a[6], a[7]); \
|
| 118 |
+
rf.s##j = scale0 * (float)raw1 + scale1 * (float)raw2; \
|
| 119 |
+
}
|
| 120 |
+
DOT_TOK(0); DOT_TOK(1); DOT_TOK(2); DOT_TOK(3);
|
| 121 |
+
#undef DOT_TOK
|
| 122 |
+
const float4 ad = (float4)((float)sh_d[b+0], (float)sh_d[b+1], (float)sh_d[b+2], (float)sh_d[b+3]);
|
| 123 |
+
acc[g] += ad * rf;
|
| 124 |
+
}
|
| 125 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
if (!row_valid) {
|
| 129 |
+
return;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
// dst is [token, feature] row-major (stride m): dst[col*m + row].
|
| 133 |
+
#pragma unroll
|
| 134 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 135 |
+
const uint b = (uint)(g * 4);
|
| 136 |
+
const float4 a = acc[g];
|
| 137 |
+
const uint c0 = col_base + b;
|
| 138 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 139 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 140 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 141 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 142 |
+
}
|
| 143 |
+
#undef NGROUPS
|
| 144 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q8_0_f32.cl
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
#ifdef ADRENO_GPU
|
| 11 |
+
REQD_SUBGROUP_SIZE_128
|
| 12 |
+
#endif
|
| 13 |
+
|
| 14 |
+
kernel void kernel_gemm_noshuffle_q8_0_f32(
|
| 15 |
+
global const uint * src0_q,
|
| 16 |
+
global const half * src0_d,
|
| 17 |
+
__read_only image1d_buffer_t src1,
|
| 18 |
+
global float * dst,
|
| 19 |
+
int k,
|
| 20 |
+
int m,
|
| 21 |
+
int n,
|
| 22 |
+
int n_no_padding,
|
| 23 |
+
ulong offsetd
|
| 24 |
+
) {
|
| 25 |
+
|
| 26 |
+
int m_4 = m >> 2;
|
| 27 |
+
int n_4 = n >> 2;
|
| 28 |
+
|
| 29 |
+
int gy = get_global_id(0);
|
| 30 |
+
int gx = get_global_id(1);
|
| 31 |
+
int gx_2 = gx << 2;
|
| 32 |
+
dst = (global float *)((global char*)dst + offsetd);
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
half8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
|
| 36 |
+
half8 B;
|
| 37 |
+
half4 deq;
|
| 38 |
+
|
| 39 |
+
__global const uint* wptr = src0_q + gx_2;
|
| 40 |
+
__global const half* sptr = src0_d + gx_2;
|
| 41 |
+
|
| 42 |
+
for (int i = 0; i < k; i += 4) {
|
| 43 |
+
uint4 pack4 = vload4(0, wptr + (i / 4) * m);
|
| 44 |
+
half4 scale = vload4(0, sptr + (i / 32) * m);
|
| 45 |
+
|
| 46 |
+
char4 p0 = as_char4(pack4.s0);
|
| 47 |
+
char4 p1 = as_char4(pack4.s1);
|
| 48 |
+
char4 p2 = as_char4(pack4.s2);
|
| 49 |
+
char4 p3 = as_char4(pack4.s3);
|
| 50 |
+
|
| 51 |
+
// ------------------- j = 0 (k = i+0) -------------------
|
| 52 |
+
B.s0123 = read_imageh(src1, gy * 2 + (i + 0) * n_4);
|
| 53 |
+
B.s4567 = read_imageh(src1, gy * 2 + (i + 0) * n_4 + 1);
|
| 54 |
+
|
| 55 |
+
half4 wj0 = convert_half4((char4)(p0.s0, p1.s0, p2.s0, p3.s0)) * scale;
|
| 56 |
+
|
| 57 |
+
c0 += B * wj0.s0;
|
| 58 |
+
c1 += B * wj0.s1;
|
| 59 |
+
c2 += B * wj0.s2;
|
| 60 |
+
c3 += B * wj0.s3;
|
| 61 |
+
|
| 62 |
+
// ------------------- j = 1 (k = i+1) -------------------
|
| 63 |
+
B.s0123 = read_imageh(src1, gy * 2 + (i + 1) * n_4);
|
| 64 |
+
B.s4567 = read_imageh(src1, gy * 2 + (i + 1) * n_4 + 1);
|
| 65 |
+
|
| 66 |
+
half4 wj1 = convert_half4((char4)(p0.s1, p1.s1, p2.s1, p3.s1)) * scale;
|
| 67 |
+
|
| 68 |
+
c0 += B * wj1.s0;
|
| 69 |
+
c1 += B * wj1.s1;
|
| 70 |
+
c2 += B * wj1.s2;
|
| 71 |
+
c3 += B * wj1.s3;
|
| 72 |
+
|
| 73 |
+
// ------------------- j = 2 (k = i+2) -------------------
|
| 74 |
+
B.s0123 = read_imageh(src1, gy * 2 + (i + 2) * n_4);
|
| 75 |
+
B.s4567 = read_imageh(src1, gy * 2 + (i + 2) * n_4 + 1);
|
| 76 |
+
|
| 77 |
+
half4 wj2 = convert_half4((char4)(p0.s2, p1.s2, p2.s2, p3.s2)) * scale;
|
| 78 |
+
|
| 79 |
+
c0 += B * wj2.s0;
|
| 80 |
+
c1 += B * wj2.s1;
|
| 81 |
+
c2 += B * wj2.s2;
|
| 82 |
+
c3 += B * wj2.s3;
|
| 83 |
+
|
| 84 |
+
// ------------------- j = 3 (k = i+3) -------------------
|
| 85 |
+
B.s0123 = read_imageh(src1, gy * 2 + (i + 3) * n_4);
|
| 86 |
+
B.s4567 = read_imageh(src1, gy * 2 + (i + 3) * n_4 + 1);
|
| 87 |
+
|
| 88 |
+
half4 wj3 = convert_half4((char4)(p0.s3, p1.s3, p2.s3, p3.s3)) * scale;
|
| 89 |
+
|
| 90 |
+
c0 += B * wj3.s0;
|
| 91 |
+
c1 += B * wj3.s1;
|
| 92 |
+
c2 += B * wj3.s2;
|
| 93 |
+
c3 += B * wj3.s3;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
int idx = (gy << 3) * m + (gx << 2);
|
| 97 |
+
|
| 98 |
+
if(idx+3 < m*n_no_padding){
|
| 99 |
+
vstore4((float4)(c0.s0, c1.s0, c2.s0, c3.s0), 0, dst + idx);
|
| 100 |
+
idx += m;
|
| 101 |
+
}
|
| 102 |
+
if(idx+3 < m*n_no_padding){
|
| 103 |
+
vstore4((float4)(c0.s1, c1.s1, c2.s1, c3.s1), 0, dst + idx);
|
| 104 |
+
idx += m;
|
| 105 |
+
}
|
| 106 |
+
if(idx+3 < m*n_no_padding){
|
| 107 |
+
vstore4((float4)(c0.s2, c1.s2, c2.s2, c3.s2), 0, dst + idx);
|
| 108 |
+
idx += m;
|
| 109 |
+
}
|
| 110 |
+
if(idx+3 < m*n_no_padding){
|
| 111 |
+
vstore4((float4)(c0.s3, c1.s3, c2.s3, c3.s3), 0, dst + idx);
|
| 112 |
+
idx += m;
|
| 113 |
+
}
|
| 114 |
+
if(idx+3 < m*n_no_padding){
|
| 115 |
+
vstore4((float4)(c0.s4, c1.s4, c2.s4, c3.s4), 0, dst + idx);
|
| 116 |
+
idx += m;
|
| 117 |
+
}
|
| 118 |
+
if(idx+3 < m*n_no_padding){
|
| 119 |
+
vstore4((float4)(c0.s5, c1.s5, c2.s5, c3.s5), 0, dst + idx);
|
| 120 |
+
idx += m;
|
| 121 |
+
}
|
| 122 |
+
if(idx+3 < m*n_no_padding){
|
| 123 |
+
vstore4((float4)(c0.s6, c1.s6, c2.s6, c3.s6), 0, dst + idx);
|
| 124 |
+
idx += m;
|
| 125 |
+
}
|
| 126 |
+
if(idx+3 < m*n_no_padding){
|
| 127 |
+
vstore4((float4)(c0.s7, c1.s7, c2.s7, c3.s7), 0, dst + idx);
|
| 128 |
+
}
|
| 129 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_noshuffle_q8_0_q8_1_dp4a.cl
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#ifdef cl_khr_integer_dot_product
|
| 4 |
+
#pragma OPENCL EXTENSION cl_khr_integer_dot_product : enable
|
| 5 |
+
#endif
|
| 6 |
+
|
| 7 |
+
// ne1<=8 keeps the f16 / bin small-batch path.
|
| 8 |
+
|
| 9 |
+
#define TILESIZE_N 32
|
| 10 |
+
|
| 11 |
+
// 32-K dp4a dot of one token's int8 activations (8 packed uints in lm) against
|
| 12 |
+
// 8 packed weight uints. q8_0 weights are already dp4a-format signed int8.
|
| 13 |
+
inline int dot8_q8a(uint8 qw, __local const uint * a) {
|
| 14 |
+
int r = 0;
|
| 15 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s0, a[0], r);
|
| 16 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s1, a[1], r);
|
| 17 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s2, a[2], r);
|
| 18 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s3, a[3], r);
|
| 19 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s4, a[4], r);
|
| 20 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s5, a[5], r);
|
| 21 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s6, a[6], r);
|
| 22 |
+
r = dot_acc_sat_4x8packed_ss_int(qw.s7, a[7], r);
|
| 23 |
+
return r;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 27 |
+
kernel void kernel_gemm_noshuffle_q8_0_q8_1_dp4a(
|
| 28 |
+
__global const uint * src0_q, // q8_0 weights: signed int8, 4/uint, feature-major
|
| 29 |
+
__global const half * src0_d, // per-32-block scale, feature-major [row + (k/32)*m]
|
| 30 |
+
__global const uint * src1_qa, // q8_1 activations int8 (as uint, 4/elem) [N, K]
|
| 31 |
+
__global const half * src1_da, // q8_1 per-block scale [N, K/32]
|
| 32 |
+
__global float * dst,
|
| 33 |
+
ulong offsetd,
|
| 34 |
+
int m, // output features (rows)
|
| 35 |
+
int n_no_padding, // tokens (cols)
|
| 36 |
+
int k // K (== ne00)
|
| 37 |
+
) {
|
| 38 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 39 |
+
|
| 40 |
+
const uint lid = get_local_id(0); // 0..63 -> row within the M-tile
|
| 41 |
+
const uint block_id_m = get_global_id(1);
|
| 42 |
+
const uint block_id_n = get_global_id(2);
|
| 43 |
+
|
| 44 |
+
const uint row = block_id_m * 64 + lid;
|
| 45 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 46 |
+
const bool row_valid = row < (uint)m;
|
| 47 |
+
const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
|
| 48 |
+
|
| 49 |
+
const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
|
| 50 |
+
const uint k_b = (uint)k >> 5; // blocks-of-32 along K
|
| 51 |
+
|
| 52 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 53 |
+
__local half sh_d[TILESIZE_N];
|
| 54 |
+
|
| 55 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 56 |
+
float4 acc[NGROUPS];
|
| 57 |
+
#pragma unroll
|
| 58 |
+
for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
|
| 59 |
+
|
| 60 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 61 |
+
const uint sub = step >> 5;
|
| 62 |
+
|
| 63 |
+
const float d_w = (float)src0_d[rrow + sub * (uint)m];
|
| 64 |
+
|
| 65 |
+
// 8 weight uints (32 int8) for this row, this 32-block. Feature-major:
|
| 66 |
+
// src0_q[row + (k/4 + u)*m], k/4 = step/4 (= step>>2).
|
| 67 |
+
const uint wbase = rrow + (step >> 2) * (uint)m;
|
| 68 |
+
uint8 qw;
|
| 69 |
+
qw.s0 = src0_q[wbase + 0 * m];
|
| 70 |
+
qw.s1 = src0_q[wbase + 1 * m];
|
| 71 |
+
qw.s2 = src0_q[wbase + 2 * m];
|
| 72 |
+
qw.s3 = src0_q[wbase + 3 * m];
|
| 73 |
+
qw.s4 = src0_q[wbase + 4 * m];
|
| 74 |
+
qw.s5 = src0_q[wbase + 5 * m];
|
| 75 |
+
qw.s6 = src0_q[wbase + 6 * m];
|
| 76 |
+
qw.s7 = src0_q[wbase + 7 * m];
|
| 77 |
+
|
| 78 |
+
// cooperatively stage the 32-token x 32-K int8 activations to LDS
|
| 79 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 80 |
+
const uint t = idx >> 3;
|
| 81 |
+
const uint u = idx & 7;
|
| 82 |
+
const uint c = col_base + t;
|
| 83 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 84 |
+
}
|
| 85 |
+
if (lid < TILESIZE_N) {
|
| 86 |
+
const uint c = col_base + lid;
|
| 87 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 88 |
+
}
|
| 89 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 90 |
+
|
| 91 |
+
#define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
|
| 92 |
+
#pragma unroll
|
| 93 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 94 |
+
const int b = g * 4;
|
| 95 |
+
float4 rf;
|
| 96 |
+
rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
|
| 97 |
+
rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
|
| 98 |
+
acc[g] += d_w * LD4(sh_d, b) * rf;
|
| 99 |
+
}
|
| 100 |
+
#undef LD4
|
| 101 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
if (!row_valid) {
|
| 105 |
+
return;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
// dst is [token, feature] row-major (stride m): dst[col*m + row].
|
| 109 |
+
#pragma unroll
|
| 110 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 111 |
+
const uint b = (uint)(g * 4);
|
| 112 |
+
const float4 a = acc[g];
|
| 113 |
+
const uint c0 = col_base + b;
|
| 114 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 115 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 116 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 117 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 118 |
+
}
|
| 119 |
+
#undef NGROUPS
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
__attribute__((qcom_wave_pair_mode(1)))
|
| 123 |
+
kernel void kernel_gemm_noshuffle_q8_0_q8_1_dp4a_wimg(
|
| 124 |
+
__read_only image1d_buffer_t src0_q_img, // q8_0 weights as uint32 texels (4 int8/texel)
|
| 125 |
+
__global const half * src0_d,
|
| 126 |
+
__global const uint * src1_qa,
|
| 127 |
+
__global const half * src1_da,
|
| 128 |
+
__global float * dst,
|
| 129 |
+
ulong offsetd,
|
| 130 |
+
int m,
|
| 131 |
+
int n_no_padding,
|
| 132 |
+
int k
|
| 133 |
+
) {
|
| 134 |
+
dst = (global float *)((global char *)dst + offsetd);
|
| 135 |
+
|
| 136 |
+
const uint lid = get_local_id(0);
|
| 137 |
+
const uint block_id_m = get_global_id(1);
|
| 138 |
+
const uint block_id_n = get_global_id(2);
|
| 139 |
+
|
| 140 |
+
const uint row = block_id_m * 64 + lid;
|
| 141 |
+
const uint col_base = block_id_n * TILESIZE_N;
|
| 142 |
+
const bool row_valid = row < (uint)m;
|
| 143 |
+
const uint rrow = row_valid ? row : 0;
|
| 144 |
+
|
| 145 |
+
const uint k_u = (uint)k >> 2;
|
| 146 |
+
const uint k_b = (uint)k >> 5;
|
| 147 |
+
|
| 148 |
+
__local uint sh_qa[TILESIZE_N][8];
|
| 149 |
+
__local half sh_d[TILESIZE_N];
|
| 150 |
+
|
| 151 |
+
#define NGROUPS (TILESIZE_N / 4)
|
| 152 |
+
float4 acc[NGROUPS];
|
| 153 |
+
#pragma unroll
|
| 154 |
+
for (int g = 0; g < NGROUPS; ++g) acc[g] = (float4)(0.0f);
|
| 155 |
+
|
| 156 |
+
for (uint step = 0; step < (uint)k; step += 32) {
|
| 157 |
+
const uint sub = step >> 5;
|
| 158 |
+
|
| 159 |
+
const float d_w = (float)src0_d[rrow + sub * (uint)m];
|
| 160 |
+
|
| 161 |
+
const uint wbase = rrow + (step >> 2) * (uint)m;
|
| 162 |
+
uint8 qw;
|
| 163 |
+
qw.s0 = read_imageui(src0_q_img, (int)(wbase + 0 * m)).x;
|
| 164 |
+
qw.s1 = read_imageui(src0_q_img, (int)(wbase + 1 * m)).x;
|
| 165 |
+
qw.s2 = read_imageui(src0_q_img, (int)(wbase + 2 * m)).x;
|
| 166 |
+
qw.s3 = read_imageui(src0_q_img, (int)(wbase + 3 * m)).x;
|
| 167 |
+
qw.s4 = read_imageui(src0_q_img, (int)(wbase + 4 * m)).x;
|
| 168 |
+
qw.s5 = read_imageui(src0_q_img, (int)(wbase + 5 * m)).x;
|
| 169 |
+
qw.s6 = read_imageui(src0_q_img, (int)(wbase + 6 * m)).x;
|
| 170 |
+
qw.s7 = read_imageui(src0_q_img, (int)(wbase + 7 * m)).x;
|
| 171 |
+
|
| 172 |
+
for (uint idx = lid; idx < TILESIZE_N * 8; idx += 64) {
|
| 173 |
+
const uint t = idx >> 3;
|
| 174 |
+
const uint u = idx & 7;
|
| 175 |
+
const uint c = col_base + t;
|
| 176 |
+
sh_qa[t][u] = (c < (uint)n_no_padding) ? src1_qa[c * k_u + (step >> 2) + u] : 0u;
|
| 177 |
+
}
|
| 178 |
+
if (lid < TILESIZE_N) {
|
| 179 |
+
const uint c = col_base + lid;
|
| 180 |
+
sh_d[lid] = (c < (uint)n_no_padding) ? src1_da[c * k_b + sub] : (half)0;
|
| 181 |
+
}
|
| 182 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 183 |
+
|
| 184 |
+
#define LD4(arr, b) ((float4)((float)arr[(b)+0], (float)arr[(b)+1], (float)arr[(b)+2], (float)arr[(b)+3]))
|
| 185 |
+
#pragma unroll
|
| 186 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 187 |
+
const int b = g * 4;
|
| 188 |
+
float4 rf;
|
| 189 |
+
rf.s0 = (float)dot8_q8a(qw, sh_qa[b+0]); rf.s1 = (float)dot8_q8a(qw, sh_qa[b+1]);
|
| 190 |
+
rf.s2 = (float)dot8_q8a(qw, sh_qa[b+2]); rf.s3 = (float)dot8_q8a(qw, sh_qa[b+3]);
|
| 191 |
+
acc[g] += d_w * LD4(sh_d, b) * rf;
|
| 192 |
+
}
|
| 193 |
+
#undef LD4
|
| 194 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
if (!row_valid) {
|
| 198 |
+
return;
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
#pragma unroll
|
| 202 |
+
for (int g = 0; g < NGROUPS; ++g) {
|
| 203 |
+
const uint b = (uint)(g * 4);
|
| 204 |
+
const float4 a = acc[g];
|
| 205 |
+
const uint c0 = col_base + b;
|
| 206 |
+
if (c0 + 0 < (uint)n_no_padding) dst[(c0 + 0) * (uint)m + row] = a.s0;
|
| 207 |
+
if (c0 + 1 < (uint)n_no_padding) dst[(c0 + 1) * (uint)m + row] = a.s1;
|
| 208 |
+
if (c0 + 2 < (uint)n_no_padding) dst[(c0 + 2) * (uint)m + row] = a.s2;
|
| 209 |
+
if (c0 + 3 < (uint)n_no_padding) dst[(c0 + 3) * (uint)m + row] = a.s3;
|
| 210 |
+
}
|
| 211 |
+
#undef NGROUPS
|
| 212 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemm_xmem_f16_f32_os8.cl
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_uniform_load : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_subgroup_constant_load : enable
|
| 4 |
+
|
| 5 |
+
__constant sampler_t smp_zero = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;
|
| 6 |
+
|
| 7 |
+
__kernel void adreno_xmem_pack_src_f32(
|
| 8 |
+
__global const void * src_void,
|
| 9 |
+
ulong offset,
|
| 10 |
+
__write_only image2d_t src_img,
|
| 11 |
+
int K,
|
| 12 |
+
int N) {
|
| 13 |
+
const int x = get_global_id(0);
|
| 14 |
+
const int y = get_global_id(1);
|
| 15 |
+
const int kpack = K / 4;
|
| 16 |
+
|
| 17 |
+
if (x >= N || y >= kpack) {
|
| 18 |
+
return;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
__global const float * src = (__global const float *)((__global const char *)src_void + offset);
|
| 22 |
+
const int base = x*K + y*4;
|
| 23 |
+
const half4 v = (half4)((half)src[base + 0], (half)src[base + 1], (half)src[base + 2], (half)src[base + 3]);
|
| 24 |
+
write_imageh(src_img, (int2)(x, y), v);
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
__kernel void adreno_xmem_prepack_weight_f16(
|
| 28 |
+
__global half4 * dst,
|
| 29 |
+
__global const void * src_void,
|
| 30 |
+
ulong offset,
|
| 31 |
+
int K,
|
| 32 |
+
int M,
|
| 33 |
+
int kpack,
|
| 34 |
+
int npack,
|
| 35 |
+
int os) {
|
| 36 |
+
const int linear = get_global_id(0);
|
| 37 |
+
const int total = kpack*npack;
|
| 38 |
+
if (linear >= total) {
|
| 39 |
+
return;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
__global const half * src = (__global const half *)((__global const char *)src_void + offset);
|
| 43 |
+
|
| 44 |
+
const int dst_ogroup = linear % os;
|
| 45 |
+
const int dst_o_sp_i = linear / os;
|
| 46 |
+
const int dst_i = dst_o_sp_i % kpack;
|
| 47 |
+
const int dst_o = dst_o_sp_i / kpack;
|
| 48 |
+
const int o_slice = dst_o*os + dst_ogroup;
|
| 49 |
+
const int k_base = dst_i*4;
|
| 50 |
+
|
| 51 |
+
half4 w0 = (half4)(0.0h);
|
| 52 |
+
half4 w1 = (half4)(0.0h);
|
| 53 |
+
half4 w2 = (half4)(0.0h);
|
| 54 |
+
half4 w3 = (half4)(0.0h);
|
| 55 |
+
|
| 56 |
+
const int o0 = o_slice*4 + 0;
|
| 57 |
+
const int o1 = o_slice*4 + 1;
|
| 58 |
+
const int o2 = o_slice*4 + 2;
|
| 59 |
+
const int o3 = o_slice*4 + 3;
|
| 60 |
+
|
| 61 |
+
if (k_base + 0 < K) {
|
| 62 |
+
if (o0 < M) w0.s0 = src[o0*K + k_base + 0];
|
| 63 |
+
if (o1 < M) w0.s1 = src[o1*K + k_base + 0];
|
| 64 |
+
if (o2 < M) w0.s2 = src[o2*K + k_base + 0];
|
| 65 |
+
if (o3 < M) w0.s3 = src[o3*K + k_base + 0];
|
| 66 |
+
}
|
| 67 |
+
if (k_base + 1 < K) {
|
| 68 |
+
if (o0 < M) w1.s0 = src[o0*K + k_base + 1];
|
| 69 |
+
if (o1 < M) w1.s1 = src[o1*K + k_base + 1];
|
| 70 |
+
if (o2 < M) w1.s2 = src[o2*K + k_base + 1];
|
| 71 |
+
if (o3 < M) w1.s3 = src[o3*K + k_base + 1];
|
| 72 |
+
}
|
| 73 |
+
if (k_base + 2 < K) {
|
| 74 |
+
if (o0 < M) w2.s0 = src[o0*K + k_base + 2];
|
| 75 |
+
if (o1 < M) w2.s1 = src[o1*K + k_base + 2];
|
| 76 |
+
if (o2 < M) w2.s2 = src[o2*K + k_base + 2];
|
| 77 |
+
if (o3 < M) w2.s3 = src[o3*K + k_base + 2];
|
| 78 |
+
}
|
| 79 |
+
if (k_base + 3 < K) {
|
| 80 |
+
if (o0 < M) w3.s0 = src[o0*K + k_base + 3];
|
| 81 |
+
if (o1 < M) w3.s1 = src[o1*K + k_base + 3];
|
| 82 |
+
if (o2 < M) w3.s2 = src[o2*K + k_base + 3];
|
| 83 |
+
if (o3 < M) w3.s3 = src[o3*K + k_base + 3];
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
dst[linear*4 + 0] = w0;
|
| 87 |
+
dst[linear*4 + 1] = w1;
|
| 88 |
+
dst[linear*4 + 2] = w2;
|
| 89 |
+
dst[linear*4 + 3] = w3;
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
__attribute__((qcom_max_concurrent_subgroups(12)))
|
| 93 |
+
__kernel void kernel_gemm_xmem_f16_f32_os8(
|
| 94 |
+
__constant half8 * weights_buffer __attribute__((sub_group_uniform)),
|
| 95 |
+
__constant half8 * xmem_buffer __attribute__((max_constant_size((6144)))),
|
| 96 |
+
__read_only image2d_t src_img,
|
| 97 |
+
__write_only image2d_t dst_img,
|
| 98 |
+
int N,
|
| 99 |
+
int npack,
|
| 100 |
+
int kpack) {
|
| 101 |
+
const int X = get_group_id(1)*get_local_size(0) + get_local_id(0);
|
| 102 |
+
const int Z = get_group_id(0)*get_local_size(2) + get_local_id(2);
|
| 103 |
+
|
| 104 |
+
if (X >= N || Z*8 >= npack) {
|
| 105 |
+
return;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
half4 r0 = (half4)(0.0h);
|
| 109 |
+
half4 r1 = (half4)(0.0h);
|
| 110 |
+
half4 r2 = (half4)(0.0h);
|
| 111 |
+
half4 r3 = (half4)(0.0h);
|
| 112 |
+
half4 r4 = (half4)(0.0h);
|
| 113 |
+
half4 r5 = (half4)(0.0h);
|
| 114 |
+
half4 r6 = (half4)(0.0h);
|
| 115 |
+
half4 r7 = (half4)(0.0h);
|
| 116 |
+
|
| 117 |
+
int f_offset = Z*kpack*32;
|
| 118 |
+
int subgroup_id = (int)(0x1F & qcom_get_physical_sub_group_id());
|
| 119 |
+
subgroup_id = subgroup_id % 12;
|
| 120 |
+
const int c_offset = subgroup_id*32;
|
| 121 |
+
__constant half16 * weights_cache = (__constant half16 *)&xmem_buffer[c_offset];
|
| 122 |
+
|
| 123 |
+
int coord_s = 0;
|
| 124 |
+
do {
|
| 125 |
+
const half4 src0 = read_imageh(src_img, smp_zero, (int2)(X, coord_s));
|
| 126 |
+
coord_s++;
|
| 127 |
+
const half4 src1 = read_imageh(src_img, smp_zero, (int2)(X, coord_s));
|
| 128 |
+
coord_s++;
|
| 129 |
+
|
| 130 |
+
qcom_sub_group_constant_load8(xmem_buffer, weights_buffer, c_offset, f_offset >> 1, 32);
|
| 131 |
+
f_offset += 64;
|
| 132 |
+
qcom_sub_group_sync(QCOM_CLK_CONST_LOAD_SYNC);
|
| 133 |
+
|
| 134 |
+
r0 += src0.x * weights_cache[0].s0123;
|
| 135 |
+
r0 += src0.y * weights_cache[0].s4567;
|
| 136 |
+
r0 += src0.z * weights_cache[0].s89ab;
|
| 137 |
+
r0 += src0.w * weights_cache[0].scdef;
|
| 138 |
+
r1 += src0.x * weights_cache[1].s0123;
|
| 139 |
+
r1 += src0.y * weights_cache[1].s4567;
|
| 140 |
+
r1 += src0.z * weights_cache[1].s89ab;
|
| 141 |
+
r1 += src0.w * weights_cache[1].scdef;
|
| 142 |
+
r2 += src0.x * weights_cache[2].s0123;
|
| 143 |
+
r2 += src0.y * weights_cache[2].s4567;
|
| 144 |
+
r2 += src0.z * weights_cache[2].s89ab;
|
| 145 |
+
r2 += src0.w * weights_cache[2].scdef;
|
| 146 |
+
r3 += src0.x * weights_cache[3].s0123;
|
| 147 |
+
r3 += src0.y * weights_cache[3].s4567;
|
| 148 |
+
r3 += src0.z * weights_cache[3].s89ab;
|
| 149 |
+
r3 += src0.w * weights_cache[3].scdef;
|
| 150 |
+
r4 += src0.x * weights_cache[4].s0123;
|
| 151 |
+
r4 += src0.y * weights_cache[4].s4567;
|
| 152 |
+
r4 += src0.z * weights_cache[4].s89ab;
|
| 153 |
+
r4 += src0.w * weights_cache[4].scdef;
|
| 154 |
+
r5 += src0.x * weights_cache[5].s0123;
|
| 155 |
+
r5 += src0.y * weights_cache[5].s4567;
|
| 156 |
+
r5 += src0.z * weights_cache[5].s89ab;
|
| 157 |
+
r5 += src0.w * weights_cache[5].scdef;
|
| 158 |
+
r6 += src0.x * weights_cache[6].s0123;
|
| 159 |
+
r6 += src0.y * weights_cache[6].s4567;
|
| 160 |
+
r6 += src0.z * weights_cache[6].s89ab;
|
| 161 |
+
r6 += src0.w * weights_cache[6].scdef;
|
| 162 |
+
r7 += src0.x * weights_cache[7].s0123;
|
| 163 |
+
r7 += src0.y * weights_cache[7].s4567;
|
| 164 |
+
r7 += src0.z * weights_cache[7].s89ab;
|
| 165 |
+
r7 += src0.w * weights_cache[7].scdef;
|
| 166 |
+
|
| 167 |
+
r0 += src1.x * weights_cache[8].s0123;
|
| 168 |
+
r0 += src1.y * weights_cache[8].s4567;
|
| 169 |
+
r0 += src1.z * weights_cache[8].s89ab;
|
| 170 |
+
r0 += src1.w * weights_cache[8].scdef;
|
| 171 |
+
r1 += src1.x * weights_cache[9].s0123;
|
| 172 |
+
r1 += src1.y * weights_cache[9].s4567;
|
| 173 |
+
r1 += src1.z * weights_cache[9].s89ab;
|
| 174 |
+
r1 += src1.w * weights_cache[9].scdef;
|
| 175 |
+
r2 += src1.x * weights_cache[10].s0123;
|
| 176 |
+
r2 += src1.y * weights_cache[10].s4567;
|
| 177 |
+
r2 += src1.z * weights_cache[10].s89ab;
|
| 178 |
+
r2 += src1.w * weights_cache[10].scdef;
|
| 179 |
+
r3 += src1.x * weights_cache[11].s0123;
|
| 180 |
+
r3 += src1.y * weights_cache[11].s4567;
|
| 181 |
+
r3 += src1.z * weights_cache[11].s89ab;
|
| 182 |
+
r3 += src1.w * weights_cache[11].scdef;
|
| 183 |
+
r4 += src1.x * weights_cache[12].s0123;
|
| 184 |
+
r4 += src1.y * weights_cache[12].s4567;
|
| 185 |
+
r4 += src1.z * weights_cache[12].s89ab;
|
| 186 |
+
r4 += src1.w * weights_cache[12].scdef;
|
| 187 |
+
r5 += src1.x * weights_cache[13].s0123;
|
| 188 |
+
r5 += src1.y * weights_cache[13].s4567;
|
| 189 |
+
r5 += src1.z * weights_cache[13].s89ab;
|
| 190 |
+
r5 += src1.w * weights_cache[13].scdef;
|
| 191 |
+
r6 += src1.x * weights_cache[14].s0123;
|
| 192 |
+
r6 += src1.y * weights_cache[14].s4567;
|
| 193 |
+
r6 += src1.z * weights_cache[14].s89ab;
|
| 194 |
+
r6 += src1.w * weights_cache[14].scdef;
|
| 195 |
+
r7 += src1.x * weights_cache[15].s0123;
|
| 196 |
+
r7 += src1.y * weights_cache[15].s4567;
|
| 197 |
+
r7 += src1.z * weights_cache[15].s89ab;
|
| 198 |
+
r7 += src1.w * weights_cache[15].scdef;
|
| 199 |
+
} while (coord_s < kpack);
|
| 200 |
+
|
| 201 |
+
int coord_s_out = Z*8;
|
| 202 |
+
if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r0); coord_s_out++; }
|
| 203 |
+
if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r1); coord_s_out++; }
|
| 204 |
+
if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r2); coord_s_out++; }
|
| 205 |
+
if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r3); coord_s_out++; }
|
| 206 |
+
if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r4); coord_s_out++; }
|
| 207 |
+
if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r5); coord_s_out++; }
|
| 208 |
+
if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r6); coord_s_out++; }
|
| 209 |
+
if (coord_s_out < npack) { write_imageh(dst_img, (int2)(X, coord_s_out), r7); }
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
__kernel void adreno_xmem_store_dst_f32(
|
| 213 |
+
__read_only image2d_t dst_img,
|
| 214 |
+
__global void * dst_void,
|
| 215 |
+
ulong offset,
|
| 216 |
+
int M,
|
| 217 |
+
int N) {
|
| 218 |
+
const int x = get_global_id(0);
|
| 219 |
+
const int y = get_global_id(1);
|
| 220 |
+
const int npack = (M + 3) / 4;
|
| 221 |
+
|
| 222 |
+
if (x >= N || y >= npack) {
|
| 223 |
+
return;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
__global float * dst = (__global float *)((__global char *)dst_void + offset);
|
| 227 |
+
const half4 hv = read_imageh(dst_img, smp_zero, (int2)(x, y));
|
| 228 |
+
const int m = y*4;
|
| 229 |
+
if (m + 0 < M) dst[x*M + m + 0] = (float)hv.s0;
|
| 230 |
+
if (m + 1 < M) dst[x*M + m + 1] = (float)hv.s1;
|
| 231 |
+
if (m + 2 < M) dst[x*M + m + 2] = (float)hv.s2;
|
| 232 |
+
if (m + 3 < M) dst[x*M + m + 3] = (float)hv.s3;
|
| 233 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_mxfp4_f32.cl
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_MXFP4 32
|
| 6 |
+
#define N_SIMDGROUP 4
|
| 7 |
+
#define SIMDGROUP_WIDTH 64
|
| 8 |
+
|
| 9 |
+
static inline half8 mxfp4_to_fp16_packed8(ushort2 fp4x8) { //, ushort 0x0E00, ushort 0x8000) {
|
| 10 |
+
ushort2 fp16_packed_a_0, fp16_packed_b_0, bias_a, bias_b, sign_a, sign_b;
|
| 11 |
+
fp16_packed_a_0.lo = (fp4x8.s0 << 9) & 0x0E00;
|
| 12 |
+
fp16_packed_a_0.hi = (fp4x8.s0 << 5) & 0x0E00;
|
| 13 |
+
fp16_packed_b_0.lo = (fp4x8.s0 << 1) & 0x0E00;
|
| 14 |
+
fp16_packed_b_0.hi = (fp4x8.s0 >> 3) & 0x0E00;
|
| 15 |
+
|
| 16 |
+
bias_a.lo = (fp16_packed_a_0.lo != 0) ? 0x3800 : 0x0;
|
| 17 |
+
bias_a.hi = (fp16_packed_a_0.hi != 0) ? 0x3800 : 0x0;
|
| 18 |
+
bias_b.lo = (fp16_packed_b_0.lo != 0) ? 0x3800 : 0x0;
|
| 19 |
+
bias_b.hi = (fp16_packed_b_0.hi != 0) ? 0x3800 : 0x0;
|
| 20 |
+
|
| 21 |
+
fp16_packed_a_0.lo = (fp16_packed_a_0.lo != 0x0200) ? fp16_packed_a_0.lo : 0x0;
|
| 22 |
+
fp16_packed_a_0.hi = (fp16_packed_a_0.hi != 0x0200) ? fp16_packed_a_0.hi : 0x0;
|
| 23 |
+
fp16_packed_b_0.lo = (fp16_packed_b_0.lo != 0x0200) ? fp16_packed_b_0.lo : 0x0;
|
| 24 |
+
fp16_packed_b_0.hi = (fp16_packed_b_0.hi != 0x0200) ? fp16_packed_b_0.hi : 0x0;
|
| 25 |
+
|
| 26 |
+
sign_a.lo = (fp4x8.s0 << 12) & 0x8000;
|
| 27 |
+
sign_a.hi = (fp4x8.s0 << 8) & 0x8000;
|
| 28 |
+
sign_b.lo = (fp4x8.s0 << 4) & 0x8000;
|
| 29 |
+
sign_b.hi = fp4x8.s0 & 0x8000;
|
| 30 |
+
|
| 31 |
+
fp16_packed_a_0 = sign_a + bias_a + fp16_packed_a_0;
|
| 32 |
+
fp16_packed_b_0 = sign_b + bias_b + fp16_packed_b_0;
|
| 33 |
+
|
| 34 |
+
ushort2 fp16_packed_a_1, fp16_packed_b_1;
|
| 35 |
+
fp16_packed_a_1.lo = (fp4x8.s1 << 9) & 0x0E00;
|
| 36 |
+
fp16_packed_a_1.hi = (fp4x8.s1 << 5) & 0x0E00;
|
| 37 |
+
fp16_packed_b_1.lo = (fp4x8.s1 << 1) & 0x0E00;
|
| 38 |
+
fp16_packed_b_1.hi = (fp4x8.s1 >> 3) & 0x0E00;
|
| 39 |
+
|
| 40 |
+
bias_a.lo = (fp16_packed_a_1.lo != 0) ? 0x3800 : 0x0;
|
| 41 |
+
bias_a.hi = (fp16_packed_a_1.hi != 0) ? 0x3800 : 0x0;
|
| 42 |
+
bias_b.lo = (fp16_packed_b_1.lo != 0) ? 0x3800 : 0x0;
|
| 43 |
+
bias_b.hi = (fp16_packed_b_1.hi != 0) ? 0x3800 : 0x0;
|
| 44 |
+
|
| 45 |
+
fp16_packed_a_1.lo = (fp16_packed_a_1.lo != 0x0200) ? fp16_packed_a_1.lo : 0x0;
|
| 46 |
+
fp16_packed_a_1.hi = (fp16_packed_a_1.hi != 0x0200) ? fp16_packed_a_1.hi : 0x0;
|
| 47 |
+
fp16_packed_b_1.lo = (fp16_packed_b_1.lo != 0x0200) ? fp16_packed_b_1.lo : 0x0;
|
| 48 |
+
fp16_packed_b_1.hi = (fp16_packed_b_1.hi != 0x0200) ? fp16_packed_b_1.hi : 0x0;
|
| 49 |
+
|
| 50 |
+
sign_a.lo = (fp4x8.s1 << 12) & 0x8000;
|
| 51 |
+
sign_a.hi = (fp4x8.s1 << 8) & 0x8000;
|
| 52 |
+
sign_b.lo = (fp4x8.s1 << 4) & 0x8000;
|
| 53 |
+
sign_b.hi = fp4x8.s1 & 0x8000;
|
| 54 |
+
|
| 55 |
+
fp16_packed_a_1 = sign_a + bias_a + fp16_packed_a_1;
|
| 56 |
+
fp16_packed_b_1 = sign_b + bias_b + fp16_packed_b_1;
|
| 57 |
+
|
| 58 |
+
return as_half8((ushort8)(fp16_packed_a_0, fp16_packed_b_0, fp16_packed_a_1, fp16_packed_b_1));
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
static inline float e8m0_to_fp32(uchar x) {
|
| 62 |
+
int bits;
|
| 63 |
+
bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
|
| 64 |
+
return as_float(bits);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 69 |
+
__kernel void kernel_gemv_moe_mxfp4_f32(
|
| 70 |
+
__global uint4 * src0_q,
|
| 71 |
+
__global uchar * src0_e,
|
| 72 |
+
__read_only image1d_buffer_t src1,
|
| 73 |
+
__global uint * src2,
|
| 74 |
+
__global float * dst,
|
| 75 |
+
ulong offsetd,
|
| 76 |
+
int ne00,
|
| 77 |
+
int ne01,
|
| 78 |
+
int ne11
|
| 79 |
+
) {
|
| 80 |
+
uint i01 = get_global_id(0);
|
| 81 |
+
uint i20 = get_global_id(2);
|
| 82 |
+
uint sgid = get_local_id(1);
|
| 83 |
+
uint slid = get_sub_group_local_id();
|
| 84 |
+
|
| 85 |
+
uint i11 = i20 % ne11;
|
| 86 |
+
|
| 87 |
+
uint expert_id = src2[i20];
|
| 88 |
+
uint expert_offset = expert_id * ne00 * ne01 / 32;
|
| 89 |
+
|
| 90 |
+
__private float sum = 0.0f; // each thread calculate partial sum of one output
|
| 91 |
+
|
| 92 |
+
// loop along ne00 in block granularity, skip 4 blocks every iter
|
| 93 |
+
for (uint ib00 = sgid; ib00 < (ne00 / QK_MXFP4); ib00 += N_SIMDGROUP) {
|
| 94 |
+
|
| 95 |
+
// load one block of q
|
| 96 |
+
uint4 regQ = src0_q[expert_offset + ib00 * ne01 + i01];
|
| 97 |
+
|
| 98 |
+
uint offset = i11 * ne00 / 4 + ib00 * 8;
|
| 99 |
+
|
| 100 |
+
half8 fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s0));
|
| 101 |
+
|
| 102 |
+
float4 shared_y4;
|
| 103 |
+
shared_y4 = read_imagef(src1, (offset + 0));
|
| 104 |
+
float4 acc = shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
|
| 105 |
+
|
| 106 |
+
shared_y4 = read_imagef(src1, (offset + 4));
|
| 107 |
+
acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s1));
|
| 111 |
+
|
| 112 |
+
shared_y4 = read_imagef(src1, (offset + 1));
|
| 113 |
+
acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
|
| 114 |
+
|
| 115 |
+
shared_y4 = read_imagef(src1, (offset + 5));
|
| 116 |
+
acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s2));
|
| 120 |
+
|
| 121 |
+
shared_y4 = read_imagef(src1, (offset + 2));
|
| 122 |
+
acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
|
| 123 |
+
|
| 124 |
+
shared_y4 = read_imagef(src1, (offset + 6));
|
| 125 |
+
acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s3));
|
| 129 |
+
|
| 130 |
+
shared_y4 = read_imagef(src1, (offset + 3));
|
| 131 |
+
acc += shared_y4 * (float4)(fp16x8.s0, fp16x8.s2, fp16x8.s4, fp16x8.s6);
|
| 132 |
+
|
| 133 |
+
shared_y4 = read_imagef(src1, (offset + 7));
|
| 134 |
+
acc += shared_y4 * (float4)(fp16x8.s1, fp16x8.s3, fp16x8.s5, fp16x8.s7);
|
| 135 |
+
|
| 136 |
+
uchar regE = src0_e[ib00 * ne01 + i01 + expert_offset];
|
| 137 |
+
sum += e8m0_to_fp32(regE) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
// reduction in local memory, assumes #subgroups=4
|
| 141 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 142 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 143 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 144 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 145 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 146 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 147 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 148 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 149 |
+
|
| 150 |
+
// 1 outputs per thread in subgroup 0
|
| 151 |
+
if (sgid == 0) {
|
| 152 |
+
dst = dst + (offsetd >> 2);
|
| 153 |
+
dst[i01 + i20 * ne01] = sum;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_mxfp4_f32_ns.cl
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_MXFP4 32
|
| 6 |
+
#define N_SIMDGROUP 4
|
| 7 |
+
#define SIMDGROUP_WIDTH 64
|
| 8 |
+
|
| 9 |
+
static inline half8 mxfp4_to_fp16_packed8(ushort2 fp4x8) {
|
| 10 |
+
ushort2 fp16_packed_a_0, fp16_packed_b_0, bias_a, bias_b, sign_a, sign_b;
|
| 11 |
+
fp16_packed_a_0.lo = (fp4x8.s0 << 9) & 0x0E00;
|
| 12 |
+
fp16_packed_a_0.hi = (fp4x8.s0 << 5) & 0x0E00;
|
| 13 |
+
fp16_packed_b_0.lo = (fp4x8.s0 << 1) & 0x0E00;
|
| 14 |
+
fp16_packed_b_0.hi = (fp4x8.s0 >> 3) & 0x0E00;
|
| 15 |
+
|
| 16 |
+
bias_a.lo = (fp16_packed_a_0.lo != 0) ? 0x3800 : 0x0;
|
| 17 |
+
bias_a.hi = (fp16_packed_a_0.hi != 0) ? 0x3800 : 0x0;
|
| 18 |
+
bias_b.lo = (fp16_packed_b_0.lo != 0) ? 0x3800 : 0x0;
|
| 19 |
+
bias_b.hi = (fp16_packed_b_0.hi != 0) ? 0x3800 : 0x0;
|
| 20 |
+
|
| 21 |
+
fp16_packed_a_0.lo = (fp16_packed_a_0.lo != 0x0200) ? fp16_packed_a_0.lo : 0x0;
|
| 22 |
+
fp16_packed_a_0.hi = (fp16_packed_a_0.hi != 0x0200) ? fp16_packed_a_0.hi : 0x0;
|
| 23 |
+
fp16_packed_b_0.lo = (fp16_packed_b_0.lo != 0x0200) ? fp16_packed_b_0.lo : 0x0;
|
| 24 |
+
fp16_packed_b_0.hi = (fp16_packed_b_0.hi != 0x0200) ? fp16_packed_b_0.hi : 0x0;
|
| 25 |
+
|
| 26 |
+
sign_a.lo = (fp4x8.s0 << 12) & 0x8000;
|
| 27 |
+
sign_a.hi = (fp4x8.s0 << 8) & 0x8000;
|
| 28 |
+
sign_b.lo = (fp4x8.s0 << 4) & 0x8000;
|
| 29 |
+
sign_b.hi = fp4x8.s0 & 0x8000;
|
| 30 |
+
|
| 31 |
+
fp16_packed_a_0 = sign_a + bias_a + fp16_packed_a_0;
|
| 32 |
+
fp16_packed_b_0 = sign_b + bias_b + fp16_packed_b_0;
|
| 33 |
+
|
| 34 |
+
ushort2 fp16_packed_a_1, fp16_packed_b_1;
|
| 35 |
+
fp16_packed_a_1.lo = (fp4x8.s1 << 9) & 0x0E00;
|
| 36 |
+
fp16_packed_a_1.hi = (fp4x8.s1 << 5) & 0x0E00;
|
| 37 |
+
fp16_packed_b_1.lo = (fp4x8.s1 << 1) & 0x0E00;
|
| 38 |
+
fp16_packed_b_1.hi = (fp4x8.s1 >> 3) & 0x0E00;
|
| 39 |
+
|
| 40 |
+
bias_a.lo = (fp16_packed_a_1.lo != 0) ? 0x3800 : 0x0;
|
| 41 |
+
bias_a.hi = (fp16_packed_a_1.hi != 0) ? 0x3800 : 0x0;
|
| 42 |
+
bias_b.lo = (fp16_packed_b_1.lo != 0) ? 0x3800 : 0x0;
|
| 43 |
+
bias_b.hi = (fp16_packed_b_1.hi != 0) ? 0x3800 : 0x0;
|
| 44 |
+
|
| 45 |
+
fp16_packed_a_1.lo = (fp16_packed_a_1.lo != 0x0200) ? fp16_packed_a_1.lo : 0x0;
|
| 46 |
+
fp16_packed_a_1.hi = (fp16_packed_a_1.hi != 0x0200) ? fp16_packed_a_1.hi : 0x0;
|
| 47 |
+
fp16_packed_b_1.lo = (fp16_packed_b_1.lo != 0x0200) ? fp16_packed_b_1.lo : 0x0;
|
| 48 |
+
fp16_packed_b_1.hi = (fp16_packed_b_1.hi != 0x0200) ? fp16_packed_b_1.hi : 0x0;
|
| 49 |
+
|
| 50 |
+
sign_a.lo = (fp4x8.s1 << 12) & 0x8000;
|
| 51 |
+
sign_a.hi = (fp4x8.s1 << 8) & 0x8000;
|
| 52 |
+
sign_b.lo = (fp4x8.s1 << 4) & 0x8000;
|
| 53 |
+
sign_b.hi = fp4x8.s1 & 0x8000;
|
| 54 |
+
|
| 55 |
+
fp16_packed_a_1 = sign_a + bias_a + fp16_packed_a_1;
|
| 56 |
+
fp16_packed_b_1 = sign_b + bias_b + fp16_packed_b_1;
|
| 57 |
+
|
| 58 |
+
return as_half8((ushort8)(fp16_packed_a_0, fp16_packed_b_0, fp16_packed_a_1, fp16_packed_b_1));
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
static inline float e8m0_to_fp32(uchar x) {
|
| 62 |
+
int bits;
|
| 63 |
+
bits = (x == 0) ? 0x00400000 : ((uint) x << 23);
|
| 64 |
+
return as_float(bits);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 69 |
+
__kernel void kernel_gemv_moe_mxfp4_f32_ns(
|
| 70 |
+
__global uint * src0_q,
|
| 71 |
+
__global uchar * src0_e,
|
| 72 |
+
__read_only image1d_buffer_t src1,
|
| 73 |
+
__global uint * src2,
|
| 74 |
+
__global float * dst,
|
| 75 |
+
ulong offsetd,
|
| 76 |
+
int ne00,
|
| 77 |
+
int ne01,
|
| 78 |
+
int ne11
|
| 79 |
+
) {
|
| 80 |
+
uint i01 = get_global_id(0);
|
| 81 |
+
uint i20 = get_global_id(2);
|
| 82 |
+
uint sgid = get_local_id(1);
|
| 83 |
+
uint slid = get_sub_group_local_id();
|
| 84 |
+
|
| 85 |
+
if (i01 >= ne01) {
|
| 86 |
+
return;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
uint i11 = i20 % ne11;
|
| 90 |
+
|
| 91 |
+
uint expert_id = src2[i20];
|
| 92 |
+
uint expert_offset = expert_id * ne00 * ne01 / 32;
|
| 93 |
+
|
| 94 |
+
__private float sum = 0.0f; // each thread calculate partial sum of one output
|
| 95 |
+
|
| 96 |
+
// loop along ne00 in block granularity, skip 4 blocks every iter
|
| 97 |
+
for (uint ib00 = sgid; ib00 < (ne00 / QK_MXFP4); ib00 += N_SIMDGROUP) {
|
| 98 |
+
|
| 99 |
+
// load one block of q
|
| 100 |
+
uint4 regQ;
|
| 101 |
+
uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
|
| 102 |
+
|
| 103 |
+
regQ.s0 = src0_q[block_offset];
|
| 104 |
+
regQ.s1 = src0_q[block_offset + ne01];
|
| 105 |
+
regQ.s2 = src0_q[block_offset + ne01 * 2];
|
| 106 |
+
regQ.s3 = src0_q[block_offset + ne01 * 3];
|
| 107 |
+
|
| 108 |
+
uint offset = i11 * ne00 / 4 + ib00 * 8;
|
| 109 |
+
|
| 110 |
+
half8 fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s0));
|
| 111 |
+
|
| 112 |
+
float4 shared_y4;
|
| 113 |
+
shared_y4 = read_imagef(src1, (offset + 0));
|
| 114 |
+
float4 acc = shared_y4 * convert_float4(fp16x8.lo);
|
| 115 |
+
|
| 116 |
+
shared_y4 = read_imagef(src1, (offset + 1));
|
| 117 |
+
acc += shared_y4 * convert_float4(fp16x8.hi);
|
| 118 |
+
|
| 119 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s1));
|
| 120 |
+
|
| 121 |
+
shared_y4 = read_imagef(src1, (offset + 2));
|
| 122 |
+
acc += shared_y4 * convert_float4(fp16x8.lo);
|
| 123 |
+
|
| 124 |
+
shared_y4 = read_imagef(src1, (offset + 3));
|
| 125 |
+
acc += shared_y4 * convert_float4(fp16x8.hi);
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s2));
|
| 129 |
+
|
| 130 |
+
shared_y4 = read_imagef(src1, (offset + 4));
|
| 131 |
+
acc += shared_y4 * convert_float4(fp16x8.lo);
|
| 132 |
+
|
| 133 |
+
shared_y4 = read_imagef(src1, (offset + 5));
|
| 134 |
+
acc += shared_y4 * convert_float4(fp16x8.hi);
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s3));
|
| 138 |
+
|
| 139 |
+
shared_y4 = read_imagef(src1, (offset + 6));
|
| 140 |
+
acc += shared_y4 * convert_float4(fp16x8.lo);
|
| 141 |
+
|
| 142 |
+
shared_y4 = read_imagef(src1, (offset + 7));
|
| 143 |
+
acc += shared_y4 * convert_float4(fp16x8.hi);
|
| 144 |
+
|
| 145 |
+
uchar regE = src0_e[ib00 * ne01 + i01 + expert_offset];
|
| 146 |
+
sum += e8m0_to_fp32(regE) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
// reduction in local memory, assumes #subgroups=4
|
| 150 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 151 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 152 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 153 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 154 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 155 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 156 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 157 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 158 |
+
|
| 159 |
+
// 1 outputs per thread in subgroup 0
|
| 160 |
+
if (sgid == 0) {
|
| 161 |
+
dst = dst + (offsetd >> 2);
|
| 162 |
+
dst[i01 + i20 * ne01] = sum;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 168 |
+
__kernel void kernel_gemv_moe_mxfp4_f32_ns_wimg(
|
| 169 |
+
__read_only image1d_buffer_t src0_q,
|
| 170 |
+
__global uchar * src0_e,
|
| 171 |
+
__read_only image1d_buffer_t src1,
|
| 172 |
+
__global uint * src2,
|
| 173 |
+
__global float * dst,
|
| 174 |
+
ulong offsetd,
|
| 175 |
+
int ne00,
|
| 176 |
+
int ne01,
|
| 177 |
+
int ne11
|
| 178 |
+
) {
|
| 179 |
+
uint i01 = get_global_id(0);
|
| 180 |
+
uint i20 = get_global_id(2);
|
| 181 |
+
uint sgid = get_local_id(1);
|
| 182 |
+
uint slid = get_sub_group_local_id();
|
| 183 |
+
|
| 184 |
+
if (i01 >= ne01) {
|
| 185 |
+
return;
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
uint i11 = i20 % ne11;
|
| 189 |
+
|
| 190 |
+
uint expert_id = src2[i20];
|
| 191 |
+
uint expert_offset = expert_id * ne00 * ne01 / 32;
|
| 192 |
+
|
| 193 |
+
__private float sum = 0.0f;
|
| 194 |
+
|
| 195 |
+
for (uint ib00 = sgid; ib00 < (ne00 / QK_MXFP4); ib00 += N_SIMDGROUP) {
|
| 196 |
+
|
| 197 |
+
uint4 regQ;
|
| 198 |
+
uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
|
| 199 |
+
|
| 200 |
+
regQ.s0 = read_imageui(src0_q, (int)(block_offset)).x;
|
| 201 |
+
regQ.s1 = read_imageui(src0_q, (int)(block_offset + ne01)).x;
|
| 202 |
+
regQ.s2 = read_imageui(src0_q, (int)(block_offset + ne01 * 2)).x;
|
| 203 |
+
regQ.s3 = read_imageui(src0_q, (int)(block_offset + ne01 * 3)).x;
|
| 204 |
+
|
| 205 |
+
uint offset = i11 * ne00 / 4 + ib00 * 8;
|
| 206 |
+
|
| 207 |
+
half8 fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s0));
|
| 208 |
+
|
| 209 |
+
float4 shared_y4;
|
| 210 |
+
shared_y4 = read_imagef(src1, (offset + 0));
|
| 211 |
+
float4 acc = shared_y4 * convert_float4(fp16x8.lo);
|
| 212 |
+
|
| 213 |
+
shared_y4 = read_imagef(src1, (offset + 1));
|
| 214 |
+
acc += shared_y4 * convert_float4(fp16x8.hi);
|
| 215 |
+
|
| 216 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s1));
|
| 217 |
+
|
| 218 |
+
shared_y4 = read_imagef(src1, (offset + 2));
|
| 219 |
+
acc += shared_y4 * convert_float4(fp16x8.lo);
|
| 220 |
+
|
| 221 |
+
shared_y4 = read_imagef(src1, (offset + 3));
|
| 222 |
+
acc += shared_y4 * convert_float4(fp16x8.hi);
|
| 223 |
+
|
| 224 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s2));
|
| 225 |
+
|
| 226 |
+
shared_y4 = read_imagef(src1, (offset + 4));
|
| 227 |
+
acc += shared_y4 * convert_float4(fp16x8.lo);
|
| 228 |
+
|
| 229 |
+
shared_y4 = read_imagef(src1, (offset + 5));
|
| 230 |
+
acc += shared_y4 * convert_float4(fp16x8.hi);
|
| 231 |
+
|
| 232 |
+
fp16x8 = mxfp4_to_fp16_packed8(as_ushort2(regQ.s3));
|
| 233 |
+
|
| 234 |
+
shared_y4 = read_imagef(src1, (offset + 6));
|
| 235 |
+
acc += shared_y4 * convert_float4(fp16x8.lo);
|
| 236 |
+
|
| 237 |
+
shared_y4 = read_imagef(src1, (offset + 7));
|
| 238 |
+
acc += shared_y4 * convert_float4(fp16x8.hi);
|
| 239 |
+
|
| 240 |
+
uchar regE = src0_e[ib00 * ne01 + i01 + expert_offset];
|
| 241 |
+
sum += e8m0_to_fp32(regE) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 245 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 246 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 247 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 248 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 249 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 250 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 251 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 252 |
+
|
| 253 |
+
if (sgid == 0) {
|
| 254 |
+
dst = dst + (offsetd >> 2);
|
| 255 |
+
dst[i01 + i20 * ne01] = sum;
|
| 256 |
+
}
|
| 257 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_0_f32_ns.cl
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_Q4_0 32
|
| 6 |
+
#define N_SIMDGROUP 4
|
| 7 |
+
#define SIMDGROUP_WIDTH 64
|
| 8 |
+
|
| 9 |
+
static inline float8 q4_0_to_fp32_packed8(ushort2 q4x8) {
|
| 10 |
+
float8 fp32x8;
|
| 11 |
+
fp32x8.s0 = (float)((q4x8.s0 & 0x000F) - 8);
|
| 12 |
+
fp32x8.s1 = (float)(((q4x8.s0 & 0x00F0) >> 4) - 8);
|
| 13 |
+
fp32x8.s2 = (float)(((q4x8.s0 & 0x0F00) >> 8) - 8);
|
| 14 |
+
fp32x8.s3 = (float)(((q4x8.s0 & 0xF000) >> 12) - 8);
|
| 15 |
+
fp32x8.s4 = (float)((q4x8.s1 & 0x000F) - 8);
|
| 16 |
+
fp32x8.s5 = (float)(((q4x8.s1 & 0x00F0) >> 4) - 8);
|
| 17 |
+
fp32x8.s6 = (float)(((q4x8.s1 & 0x0F00) >> 8) - 8);
|
| 18 |
+
fp32x8.s7 = (float)(((q4x8.s1 & 0xF000) >> 12) - 8);
|
| 19 |
+
return fp32x8;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 24 |
+
__kernel void kernel_gemv_moe_q4_0_f32_ns(
|
| 25 |
+
__global uint * src0_q,
|
| 26 |
+
__global half * src0_d,
|
| 27 |
+
__read_only image1d_buffer_t src1,
|
| 28 |
+
__global uint * src2,
|
| 29 |
+
__global float * dst,
|
| 30 |
+
ulong offsetd,
|
| 31 |
+
int ne00,
|
| 32 |
+
int ne01,
|
| 33 |
+
int ne11
|
| 34 |
+
) {
|
| 35 |
+
uint i01 = get_global_id(0);
|
| 36 |
+
uint i20 = get_global_id(2);
|
| 37 |
+
uint sgid = get_local_id(1);
|
| 38 |
+
uint slid = get_sub_group_local_id();
|
| 39 |
+
|
| 40 |
+
if (i01 >= ne01) {
|
| 41 |
+
return;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
uint i11 = i20 % ne11;
|
| 45 |
+
|
| 46 |
+
uint expert_id = src2[i20];
|
| 47 |
+
uint expert_offset = expert_id * ne00 * ne01 / 32;
|
| 48 |
+
|
| 49 |
+
__private float sum = 0.0f; // each thread calculate partial sum of one output
|
| 50 |
+
|
| 51 |
+
// loop along ne00 in block granularity, skip 4 blocks every iter
|
| 52 |
+
for (uint ib00 = sgid; ib00 < (ne00 / QK_Q4_0); ib00 += N_SIMDGROUP) {
|
| 53 |
+
|
| 54 |
+
// load one block of q
|
| 55 |
+
uint4 regQ;
|
| 56 |
+
uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
|
| 57 |
+
|
| 58 |
+
regQ.s0 = src0_q[block_offset];
|
| 59 |
+
regQ.s1 = src0_q[block_offset + ne01];
|
| 60 |
+
regQ.s2 = src0_q[block_offset + ne01 * 2];
|
| 61 |
+
regQ.s3 = src0_q[block_offset + ne01 * 3];
|
| 62 |
+
|
| 63 |
+
uint offset = i11 * ne00 / 4 + ib00 * 8;
|
| 64 |
+
|
| 65 |
+
float8 fp32x8 = q4_0_to_fp32_packed8(as_ushort2(regQ.s0));
|
| 66 |
+
|
| 67 |
+
float4 shared_y4;
|
| 68 |
+
shared_y4 = read_imagef(src1, (offset + 0));
|
| 69 |
+
float4 acc = shared_y4 * fp32x8.lo;
|
| 70 |
+
|
| 71 |
+
shared_y4 = read_imagef(src1, (offset + 1));
|
| 72 |
+
acc += shared_y4 * fp32x8.hi;
|
| 73 |
+
|
| 74 |
+
fp32x8 = q4_0_to_fp32_packed8(as_ushort2(regQ.s1));
|
| 75 |
+
|
| 76 |
+
shared_y4 = read_imagef(src1, (offset + 2));
|
| 77 |
+
acc += shared_y4 * fp32x8.lo;
|
| 78 |
+
|
| 79 |
+
shared_y4 = read_imagef(src1, (offset + 3));
|
| 80 |
+
acc += shared_y4 * fp32x8.hi;
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
fp32x8 = q4_0_to_fp32_packed8(as_ushort2(regQ.s2));
|
| 84 |
+
|
| 85 |
+
shared_y4 = read_imagef(src1, (offset + 4));
|
| 86 |
+
acc += shared_y4 * fp32x8.lo;
|
| 87 |
+
|
| 88 |
+
shared_y4 = read_imagef(src1, (offset + 5));
|
| 89 |
+
acc += shared_y4 * fp32x8.hi;
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
fp32x8 = q4_0_to_fp32_packed8(as_ushort2(regQ.s3));
|
| 93 |
+
|
| 94 |
+
shared_y4 = read_imagef(src1, (offset + 6));
|
| 95 |
+
acc += shared_y4 * fp32x8.lo;
|
| 96 |
+
|
| 97 |
+
shared_y4 = read_imagef(src1, (offset + 7));
|
| 98 |
+
acc += shared_y4 * fp32x8.hi;
|
| 99 |
+
|
| 100 |
+
half regS = src0_d[ib00 * ne01 + i01 + expert_offset];
|
| 101 |
+
sum += (float)(regS) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
// reduction in local memory, assumes #subgroups=4
|
| 105 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 106 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 107 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 108 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 109 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 110 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 111 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 112 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 113 |
+
|
| 114 |
+
// 1 outputs per thread in subgroup 0
|
| 115 |
+
if (sgid == 0) {
|
| 116 |
+
dst = dst + (offsetd >> 2);
|
| 117 |
+
dst[i01 + i20 * ne01] = sum;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_1_f32_ns.cl
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_Q4_1 32
|
| 6 |
+
#define N_SIMDGROUP 4
|
| 7 |
+
#define SIMDGROUP_WIDTH 64
|
| 8 |
+
|
| 9 |
+
static inline float8 q4_1_to_fp32_packed8(ushort2 q4x8, half s, half m) {
|
| 10 |
+
float8 fp32x8;
|
| 11 |
+
fp32x8.s0 = (float)((q4x8.s0 & 0x000F) * s + m);
|
| 12 |
+
fp32x8.s1 = (float)(((q4x8.s0 & 0x00F0) >> 4) * s + m);
|
| 13 |
+
fp32x8.s2 = (float)(((q4x8.s0 & 0x0F00) >> 8) * s + m);
|
| 14 |
+
fp32x8.s3 = (float)(((q4x8.s0 & 0xF000) >> 12) * s + m);
|
| 15 |
+
fp32x8.s4 = (float)((q4x8.s1 & 0x000F) * s + m);
|
| 16 |
+
fp32x8.s5 = (float)(((q4x8.s1 & 0x00F0) >> 4) * s + m);
|
| 17 |
+
fp32x8.s6 = (float)(((q4x8.s1 & 0x0F00) >> 8) * s + m);
|
| 18 |
+
fp32x8.s7 = (float)(((q4x8.s1 & 0xF000) >> 12) * s + m);
|
| 19 |
+
return fp32x8;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 24 |
+
__kernel void kernel_gemv_moe_q4_1_f32_ns(
|
| 25 |
+
__global uint * src0_q,
|
| 26 |
+
__global half * src0_d,
|
| 27 |
+
__global half * src0_m,
|
| 28 |
+
__read_only image1d_buffer_t src1,
|
| 29 |
+
__global uint * src2,
|
| 30 |
+
__global float * dst,
|
| 31 |
+
ulong offsetd,
|
| 32 |
+
int ne00,
|
| 33 |
+
int ne01,
|
| 34 |
+
int ne11
|
| 35 |
+
) {
|
| 36 |
+
uint i01 = get_global_id(0);
|
| 37 |
+
uint i20 = get_global_id(2);
|
| 38 |
+
uint sgid = get_local_id(1);
|
| 39 |
+
uint slid = get_sub_group_local_id();
|
| 40 |
+
|
| 41 |
+
if (i01 >= ne01) {
|
| 42 |
+
return;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
uint i11 = i20 % ne11;
|
| 46 |
+
|
| 47 |
+
uint expert_id = src2[i20];
|
| 48 |
+
uint expert_offset = expert_id * ne00 * ne01 / 32;
|
| 49 |
+
|
| 50 |
+
__private float sum = 0.0f; // each thread calculate partial sum of one output
|
| 51 |
+
|
| 52 |
+
// loop along ne00 in block granularity, skip 4 blocks every iter
|
| 53 |
+
for (uint ib00 = sgid; ib00 < (ne00 / QK_Q4_1); ib00 += N_SIMDGROUP) {
|
| 54 |
+
|
| 55 |
+
// load one block of q
|
| 56 |
+
uint4 regQ;
|
| 57 |
+
uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
|
| 58 |
+
|
| 59 |
+
regQ.s0 = src0_q[block_offset];
|
| 60 |
+
regQ.s1 = src0_q[block_offset + ne01];
|
| 61 |
+
regQ.s2 = src0_q[block_offset + ne01 * 2];
|
| 62 |
+
regQ.s3 = src0_q[block_offset + ne01 * 3];
|
| 63 |
+
|
| 64 |
+
uint offset = i11 * ne00 / 4 + ib00 * 8;
|
| 65 |
+
|
| 66 |
+
half regM = src0_m[ib00 * ne01 + i01 + expert_offset];
|
| 67 |
+
half regS = src0_d[ib00 * ne01 + i01 + expert_offset];
|
| 68 |
+
|
| 69 |
+
float8 fp32x8 = q4_1_to_fp32_packed8(as_ushort2(regQ.s0), regS, regM);
|
| 70 |
+
|
| 71 |
+
float4 shared_y4;
|
| 72 |
+
shared_y4 = read_imagef(src1, (offset + 0));
|
| 73 |
+
float4 acc = shared_y4 * fp32x8.lo;
|
| 74 |
+
|
| 75 |
+
shared_y4 = read_imagef(src1, (offset + 1));
|
| 76 |
+
acc += shared_y4 * fp32x8.hi;
|
| 77 |
+
|
| 78 |
+
fp32x8 = q4_1_to_fp32_packed8(as_ushort2(regQ.s1), regS, regM);
|
| 79 |
+
|
| 80 |
+
shared_y4 = read_imagef(src1, (offset + 2));
|
| 81 |
+
acc += shared_y4 * fp32x8.lo;
|
| 82 |
+
|
| 83 |
+
shared_y4 = read_imagef(src1, (offset + 3));
|
| 84 |
+
acc += shared_y4 * fp32x8.hi;
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
fp32x8 = q4_1_to_fp32_packed8(as_ushort2(regQ.s2), regS, regM);
|
| 88 |
+
|
| 89 |
+
shared_y4 = read_imagef(src1, (offset + 4));
|
| 90 |
+
acc += shared_y4 * fp32x8.lo;
|
| 91 |
+
|
| 92 |
+
shared_y4 = read_imagef(src1, (offset + 5));
|
| 93 |
+
acc += shared_y4 * fp32x8.hi;
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
fp32x8 = q4_1_to_fp32_packed8(as_ushort2(regQ.s3), regS, regM);
|
| 97 |
+
|
| 98 |
+
shared_y4 = read_imagef(src1, (offset + 6));
|
| 99 |
+
acc += shared_y4 * fp32x8.lo;
|
| 100 |
+
|
| 101 |
+
shared_y4 = read_imagef(src1, (offset + 7));
|
| 102 |
+
acc += shared_y4 * fp32x8.hi;
|
| 103 |
+
|
| 104 |
+
sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
// reduction in local memory, assumes #subgroups=4
|
| 108 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 109 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 110 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 111 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 112 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 113 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 114 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 115 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 116 |
+
|
| 117 |
+
// 1 outputs per thread in subgroup 0
|
| 118 |
+
if (sgid == 0) {
|
| 119 |
+
dst = dst + (offsetd >> 2);
|
| 120 |
+
dst[i01 + i20 * ne01] = sum;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q4_k_f32_ns.cl
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_K 256
|
| 6 |
+
#define K_SCALE_SIZE 12
|
| 7 |
+
#define N_SIMDGROUP 4
|
| 8 |
+
#define SIMDGROUP_WIDTH 64
|
| 9 |
+
|
| 10 |
+
inline void get_scale_min_k4(
|
| 11 |
+
int j,
|
| 12 |
+
global const uchar * q,
|
| 13 |
+
uchar * d,
|
| 14 |
+
uchar * m
|
| 15 |
+
) {
|
| 16 |
+
if (j < 4) {
|
| 17 |
+
*d = q[j] & 63;
|
| 18 |
+
*m = q[j+4] & 63;
|
| 19 |
+
} else {
|
| 20 |
+
*d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
|
| 21 |
+
*m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
static inline float8 q4_k_to_fp32_packed8(ushort2 q4x8, float scale, float minv) {
|
| 26 |
+
float8 fp32x8;
|
| 27 |
+
fp32x8.s0 = (q4x8.s0 & 0x000F) * scale - minv;
|
| 28 |
+
fp32x8.s1 = ((q4x8.s0 & 0x00F0) >> 4) * scale - minv;
|
| 29 |
+
fp32x8.s2 = ((q4x8.s0 & 0x0F00) >> 8) * scale - minv;
|
| 30 |
+
fp32x8.s3 = ((q4x8.s0 & 0xF000) >> 12) * scale - minv;
|
| 31 |
+
fp32x8.s4 = (q4x8.s1 & 0x000F) * scale - minv;
|
| 32 |
+
fp32x8.s5 = ((q4x8.s1 & 0x00F0) >> 4) * scale - minv;
|
| 33 |
+
fp32x8.s6 = ((q4x8.s1 & 0x0F00) >> 8) * scale - minv;
|
| 34 |
+
fp32x8.s7 = ((q4x8.s1 & 0xF000) >> 12) * scale - minv;
|
| 35 |
+
return fp32x8;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 39 |
+
__kernel void kernel_gemv_moe_q4_k_f32_ns(
|
| 40 |
+
__global uint * src0_q,
|
| 41 |
+
__global half * src0_d,
|
| 42 |
+
__global half * src0_dm,
|
| 43 |
+
__global uchar * src0_s,
|
| 44 |
+
__read_only image1d_buffer_t src1,
|
| 45 |
+
__global uint * src2,
|
| 46 |
+
__global float * dst,
|
| 47 |
+
ulong offsetd,
|
| 48 |
+
int ne00,
|
| 49 |
+
int ne01,
|
| 50 |
+
int ne11
|
| 51 |
+
) {
|
| 52 |
+
uint i01 = get_global_id(0);
|
| 53 |
+
uint i20 = get_global_id(2);
|
| 54 |
+
uint sgid = get_local_id(1);
|
| 55 |
+
uint slid = get_sub_group_local_id();
|
| 56 |
+
|
| 57 |
+
if (i01 >= ne01) {
|
| 58 |
+
return;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
uint i11 = i20 % ne11;
|
| 62 |
+
|
| 63 |
+
uint expert_id = src2[i20];
|
| 64 |
+
|
| 65 |
+
int num_superblocks = ne00 / QK_K;
|
| 66 |
+
int num_subblocks = ne00 / 32;
|
| 67 |
+
int scales_per_row = num_superblocks * K_SCALE_SIZE;
|
| 68 |
+
|
| 69 |
+
// Expert offsets in the transposed noshuffle layout
|
| 70 |
+
uint expert_q_offset = expert_id * (ne00 / 8) * ne01;
|
| 71 |
+
uint expert_d_offset = expert_id * num_superblocks * ne01;
|
| 72 |
+
|
| 73 |
+
__private float sum = 0.0f;
|
| 74 |
+
|
| 75 |
+
// Loop over sub-blocks of 32 elements, N_SIMDGROUP sub-blocks per iter
|
| 76 |
+
for (uint ib = sgid; ib < num_subblocks; ib += N_SIMDGROUP) {
|
| 77 |
+
uint sb = ib / 8;
|
| 78 |
+
uint j = ib % 8;
|
| 79 |
+
|
| 80 |
+
// Load d and dmin for this super-block
|
| 81 |
+
half d_val = src0_d[expert_d_offset + sb * ne01 + i01];
|
| 82 |
+
half dm_val = src0_dm[expert_d_offset + sb * ne01 + i01];
|
| 83 |
+
|
| 84 |
+
// Load sub-block scale and min
|
| 85 |
+
global const uchar * sc = src0_s + (expert_id * ne01 + i01) * scales_per_row + sb * K_SCALE_SIZE;
|
| 86 |
+
uchar sv, mn;
|
| 87 |
+
get_scale_min_k4(j, sc, &sv, &mn);
|
| 88 |
+
|
| 89 |
+
float scale = (float)d_val * (float)sv;
|
| 90 |
+
float minv = (float)dm_val * (float)mn;
|
| 91 |
+
|
| 92 |
+
// Load 4 uints of quants (32 nibbles = 32 elements)
|
| 93 |
+
uint q_base = expert_q_offset + ib * ne01 * 4 + i01;
|
| 94 |
+
|
| 95 |
+
uint4 regQ;
|
| 96 |
+
regQ.s0 = src0_q[q_base];
|
| 97 |
+
regQ.s1 = src0_q[q_base + ne01];
|
| 98 |
+
regQ.s2 = src0_q[q_base + ne01 * 2];
|
| 99 |
+
regQ.s3 = src0_q[q_base + ne01 * 3];
|
| 100 |
+
|
| 101 |
+
// Load activations: 32 floats = 8 float4s
|
| 102 |
+
uint y_offset = i11 * ne00 / 4 + ib * 8;
|
| 103 |
+
|
| 104 |
+
float8 fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s0), scale, minv);
|
| 105 |
+
|
| 106 |
+
float4 shared_y4;
|
| 107 |
+
shared_y4 = read_imagef(src1, (y_offset + 0));
|
| 108 |
+
float4 acc = shared_y4 * fp32x8.lo;
|
| 109 |
+
|
| 110 |
+
shared_y4 = read_imagef(src1, (y_offset + 1));
|
| 111 |
+
acc += shared_y4 * fp32x8.hi;
|
| 112 |
+
|
| 113 |
+
fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s1), scale, minv);
|
| 114 |
+
|
| 115 |
+
shared_y4 = read_imagef(src1, (y_offset + 2));
|
| 116 |
+
acc += shared_y4 * fp32x8.lo;
|
| 117 |
+
|
| 118 |
+
shared_y4 = read_imagef(src1, (y_offset + 3));
|
| 119 |
+
acc += shared_y4 * fp32x8.hi;
|
| 120 |
+
|
| 121 |
+
fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s2), scale, minv);
|
| 122 |
+
|
| 123 |
+
shared_y4 = read_imagef(src1, (y_offset + 4));
|
| 124 |
+
acc += shared_y4 * fp32x8.lo;
|
| 125 |
+
|
| 126 |
+
shared_y4 = read_imagef(src1, (y_offset + 5));
|
| 127 |
+
acc += shared_y4 * fp32x8.hi;
|
| 128 |
+
|
| 129 |
+
fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s3), scale, minv);
|
| 130 |
+
|
| 131 |
+
shared_y4 = read_imagef(src1, (y_offset + 6));
|
| 132 |
+
acc += shared_y4 * fp32x8.lo;
|
| 133 |
+
|
| 134 |
+
shared_y4 = read_imagef(src1, (y_offset + 7));
|
| 135 |
+
acc += shared_y4 * fp32x8.hi;
|
| 136 |
+
|
| 137 |
+
sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
// reduction in local memory, assumes #subgroups=4
|
| 141 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 142 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 143 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 144 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 145 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 146 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 147 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 148 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 149 |
+
|
| 150 |
+
// 1 output per thread in subgroup 0
|
| 151 |
+
if (sgid == 0) {
|
| 152 |
+
dst = dst + (offsetd >> 2);
|
| 153 |
+
dst[i01 + i20 * ne01] = sum;
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 158 |
+
__kernel void kernel_gemv_moe_q4_k_f32_ns_wimg(
|
| 159 |
+
__read_only image1d_buffer_t src0_q,
|
| 160 |
+
__global half * src0_d,
|
| 161 |
+
__global half * src0_dm,
|
| 162 |
+
__global uchar * src0_s,
|
| 163 |
+
__read_only image1d_buffer_t src1,
|
| 164 |
+
__global uint * src2,
|
| 165 |
+
__global float * dst,
|
| 166 |
+
ulong offsetd,
|
| 167 |
+
int ne00,
|
| 168 |
+
int ne01,
|
| 169 |
+
int ne11
|
| 170 |
+
) {
|
| 171 |
+
uint i01 = get_global_id(0);
|
| 172 |
+
uint i20 = get_global_id(2);
|
| 173 |
+
uint sgid = get_local_id(1);
|
| 174 |
+
uint slid = get_sub_group_local_id();
|
| 175 |
+
|
| 176 |
+
if (i01 >= ne01) {
|
| 177 |
+
return;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
uint i11 = i20 % ne11;
|
| 181 |
+
|
| 182 |
+
uint expert_id = src2[i20];
|
| 183 |
+
|
| 184 |
+
int num_superblocks = ne00 / QK_K;
|
| 185 |
+
int num_subblocks = ne00 / 32;
|
| 186 |
+
int scales_per_row = num_superblocks * K_SCALE_SIZE;
|
| 187 |
+
|
| 188 |
+
uint expert_q_offset = expert_id * (ne00 / 8) * ne01;
|
| 189 |
+
uint expert_d_offset = expert_id * num_superblocks * ne01;
|
| 190 |
+
|
| 191 |
+
__private float sum = 0.0f;
|
| 192 |
+
|
| 193 |
+
for (uint ib = sgid; ib < num_subblocks; ib += N_SIMDGROUP) {
|
| 194 |
+
uint sb = ib / 8;
|
| 195 |
+
uint j = ib % 8;
|
| 196 |
+
|
| 197 |
+
half d_val = src0_d[expert_d_offset + sb * ne01 + i01];
|
| 198 |
+
half dm_val = src0_dm[expert_d_offset + sb * ne01 + i01];
|
| 199 |
+
|
| 200 |
+
global const uchar * sc = src0_s + (expert_id * ne01 + i01) * scales_per_row + sb * K_SCALE_SIZE;
|
| 201 |
+
uchar sv, mn;
|
| 202 |
+
get_scale_min_k4(j, sc, &sv, &mn);
|
| 203 |
+
|
| 204 |
+
float scale = (float)d_val * (float)sv;
|
| 205 |
+
float minv = (float)dm_val * (float)mn;
|
| 206 |
+
|
| 207 |
+
uint q_base = expert_q_offset + ib * ne01 * 4 + i01;
|
| 208 |
+
|
| 209 |
+
uint4 regQ;
|
| 210 |
+
regQ.s0 = read_imageui(src0_q, (int)(q_base)).x;
|
| 211 |
+
regQ.s1 = read_imageui(src0_q, (int)(q_base + ne01)).x;
|
| 212 |
+
regQ.s2 = read_imageui(src0_q, (int)(q_base + ne01 * 2)).x;
|
| 213 |
+
regQ.s3 = read_imageui(src0_q, (int)(q_base + ne01 * 3)).x;
|
| 214 |
+
|
| 215 |
+
uint y_offset = i11 * ne00 / 4 + ib * 8;
|
| 216 |
+
|
| 217 |
+
float8 fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s0), scale, minv);
|
| 218 |
+
|
| 219 |
+
float4 shared_y4;
|
| 220 |
+
shared_y4 = read_imagef(src1, (y_offset + 0));
|
| 221 |
+
float4 acc = shared_y4 * fp32x8.lo;
|
| 222 |
+
|
| 223 |
+
shared_y4 = read_imagef(src1, (y_offset + 1));
|
| 224 |
+
acc += shared_y4 * fp32x8.hi;
|
| 225 |
+
|
| 226 |
+
fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s1), scale, minv);
|
| 227 |
+
|
| 228 |
+
shared_y4 = read_imagef(src1, (y_offset + 2));
|
| 229 |
+
acc += shared_y4 * fp32x8.lo;
|
| 230 |
+
|
| 231 |
+
shared_y4 = read_imagef(src1, (y_offset + 3));
|
| 232 |
+
acc += shared_y4 * fp32x8.hi;
|
| 233 |
+
|
| 234 |
+
fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s2), scale, minv);
|
| 235 |
+
|
| 236 |
+
shared_y4 = read_imagef(src1, (y_offset + 4));
|
| 237 |
+
acc += shared_y4 * fp32x8.lo;
|
| 238 |
+
|
| 239 |
+
shared_y4 = read_imagef(src1, (y_offset + 5));
|
| 240 |
+
acc += shared_y4 * fp32x8.hi;
|
| 241 |
+
|
| 242 |
+
fp32x8 = q4_k_to_fp32_packed8(as_ushort2(regQ.s3), scale, minv);
|
| 243 |
+
|
| 244 |
+
shared_y4 = read_imagef(src1, (y_offset + 6));
|
| 245 |
+
acc += shared_y4 * fp32x8.lo;
|
| 246 |
+
|
| 247 |
+
shared_y4 = read_imagef(src1, (y_offset + 7));
|
| 248 |
+
acc += shared_y4 * fp32x8.hi;
|
| 249 |
+
|
| 250 |
+
sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 254 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 255 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 256 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 257 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 258 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 259 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 260 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 261 |
+
|
| 262 |
+
if (sgid == 0) {
|
| 263 |
+
dst = dst + (offsetd >> 2);
|
| 264 |
+
dst[i01 + i20 * ne01] = sum;
|
| 265 |
+
}
|
| 266 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_0_f32_ns.cl
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_Q5_0 32
|
| 6 |
+
#define N_SIMDGROUP 4
|
| 7 |
+
#define SIMDGROUP_WIDTH 64
|
| 8 |
+
|
| 9 |
+
static inline float8 q5_0_to_fp32_packed8(ushort2 qs5x8, uchar qh5x8) {
|
| 10 |
+
float8 fp32x8;
|
| 11 |
+
fp32x8.s0 = (float)((( qs5x8.s0 & 0x000F) | (( qh5x8 & 0x01) << 4)) - 16);
|
| 12 |
+
fp32x8.s1 = (float)((((qs5x8.s0 & 0x00F0) >> 4 ) | (((qh5x8 >> 1) & 0x01) << 4)) - 16);
|
| 13 |
+
fp32x8.s2 = (float)((((qs5x8.s0 & 0x0F00) >> 8 ) | (((qh5x8 >> 2) & 0x01) << 4)) - 16);
|
| 14 |
+
fp32x8.s3 = (float)((((qs5x8.s0 & 0xF000) >> 12) | (((qh5x8 >> 3) & 0x01) << 4)) - 16);
|
| 15 |
+
fp32x8.s4 = (float)((( qs5x8.s1 & 0x000F) | (((qh5x8 >> 4) & 0x01) << 4)) - 16);
|
| 16 |
+
fp32x8.s5 = (float)((((qs5x8.s1 & 0x00F0) >> 4 ) | (((qh5x8 >> 5) & 0x01) << 4)) - 16);
|
| 17 |
+
fp32x8.s6 = (float)((((qs5x8.s1 & 0x0F00) >> 8 ) | (((qh5x8 >> 6) & 0x01) << 4)) - 16);
|
| 18 |
+
fp32x8.s7 = (float)((((qs5x8.s1 & 0xF000) >> 12) | (((qh5x8 >> 7) & 0x01) << 4)) - 16);
|
| 19 |
+
return fp32x8;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 24 |
+
__kernel void kernel_gemv_moe_q5_0_f32_ns(
|
| 25 |
+
__global uint * src0_qs,
|
| 26 |
+
__global uint * src0_qh,
|
| 27 |
+
__global half * src0_d,
|
| 28 |
+
__read_only image1d_buffer_t src1,
|
| 29 |
+
__global uint * src2,
|
| 30 |
+
__global float * dst,
|
| 31 |
+
ulong offsetd,
|
| 32 |
+
uint ne00,
|
| 33 |
+
uint ne01,
|
| 34 |
+
uint ne11
|
| 35 |
+
) {
|
| 36 |
+
uint i01 = get_global_id(0);
|
| 37 |
+
uint i20 = get_global_id(2);
|
| 38 |
+
uint sgid = get_local_id(1);
|
| 39 |
+
uint slid = get_sub_group_local_id();
|
| 40 |
+
|
| 41 |
+
if (i01 >= ne01) {
|
| 42 |
+
return;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
uint i11 = i20 % ne11;
|
| 46 |
+
|
| 47 |
+
uint expert_id = src2[i20];
|
| 48 |
+
uint expert_offset = expert_id * ne00 * ne01 / 32;
|
| 49 |
+
|
| 50 |
+
__private float sum = 0.0f; // each thread calculate partial sum of one output
|
| 51 |
+
|
| 52 |
+
// loop along ne00 in block granularity, skip 4 blocks every iter
|
| 53 |
+
for (uint ib00 = sgid; ib00 < (ne00 / QK_Q5_0); ib00 += N_SIMDGROUP) {
|
| 54 |
+
|
| 55 |
+
// load one block of q
|
| 56 |
+
uint4 regQ;
|
| 57 |
+
uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
|
| 58 |
+
|
| 59 |
+
regQ.s0 = src0_qs[block_offset];
|
| 60 |
+
regQ.s1 = src0_qs[block_offset + ne01];
|
| 61 |
+
regQ.s2 = src0_qs[block_offset + ne01 * 2];
|
| 62 |
+
regQ.s3 = src0_qs[block_offset + ne01 * 3];
|
| 63 |
+
|
| 64 |
+
uint offset = i11 * ne00 / 4 + ib00 * 8;
|
| 65 |
+
|
| 66 |
+
uchar4 regQh = as_uchar4(src0_qh[ib00 * ne01 + i01 + expert_offset]);
|
| 67 |
+
half regS = src0_d[ib00 * ne01 + i01 + expert_offset];
|
| 68 |
+
|
| 69 |
+
float8 fp32x8 = q5_0_to_fp32_packed8(as_ushort2(regQ.s0), regQh.s0);
|
| 70 |
+
|
| 71 |
+
float4 shared_y4;
|
| 72 |
+
shared_y4 = read_imagef(src1, (offset + 0));
|
| 73 |
+
float4 acc = shared_y4 * fp32x8.lo;
|
| 74 |
+
|
| 75 |
+
shared_y4 = read_imagef(src1, (offset + 1));
|
| 76 |
+
acc += shared_y4 * fp32x8.hi;
|
| 77 |
+
|
| 78 |
+
fp32x8 = q5_0_to_fp32_packed8(as_ushort2(regQ.s1), regQh.s1);
|
| 79 |
+
|
| 80 |
+
shared_y4 = read_imagef(src1, (offset + 2));
|
| 81 |
+
acc += shared_y4 * fp32x8.lo;
|
| 82 |
+
|
| 83 |
+
shared_y4 = read_imagef(src1, (offset + 3));
|
| 84 |
+
acc += shared_y4 * fp32x8.hi;
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
fp32x8 = q5_0_to_fp32_packed8(as_ushort2(regQ.s2), regQh.s2);
|
| 88 |
+
|
| 89 |
+
shared_y4 = read_imagef(src1, (offset + 4));
|
| 90 |
+
acc += shared_y4 * fp32x8.lo;
|
| 91 |
+
|
| 92 |
+
shared_y4 = read_imagef(src1, (offset + 5));
|
| 93 |
+
acc += shared_y4 * fp32x8.hi;
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
fp32x8 = q5_0_to_fp32_packed8(as_ushort2(regQ.s3), regQh.s3);
|
| 97 |
+
|
| 98 |
+
shared_y4 = read_imagef(src1, (offset + 6));
|
| 99 |
+
acc += shared_y4 * fp32x8.lo;
|
| 100 |
+
|
| 101 |
+
shared_y4 = read_imagef(src1, (offset + 7));
|
| 102 |
+
acc += shared_y4 * fp32x8.hi;
|
| 103 |
+
|
| 104 |
+
sum += (float)(regS) * ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
// reduction in local memory, assumes #subgroups=4
|
| 108 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 109 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 110 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 111 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 112 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 113 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 114 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 115 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 116 |
+
|
| 117 |
+
// 1 outputs per thread in subgroup 0
|
| 118 |
+
if (sgid == 0) {
|
| 119 |
+
dst = dst + (offsetd >> 2);
|
| 120 |
+
dst[i01 + i20 * ne01] = sum;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_1_f32_ns.cl
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_Q5_1 32
|
| 6 |
+
#define N_SIMDGROUP 4
|
| 7 |
+
#define SIMDGROUP_WIDTH 64
|
| 8 |
+
|
| 9 |
+
static inline float8 q5_1_to_fp32_packed8(ushort2 qs5x8, uchar qh5x8, half s, half m) {
|
| 10 |
+
float8 fp32x8;
|
| 11 |
+
fp32x8.s0 = (float)((( qs5x8.s0 & 0x000F) | (( qh5x8 & 0x01) << 4)) * s + m);
|
| 12 |
+
fp32x8.s1 = (float)((((qs5x8.s0 & 0x00F0) >> 4 ) | (((qh5x8 >> 1) & 0x01) << 4)) * s + m);
|
| 13 |
+
fp32x8.s2 = (float)((((qs5x8.s0 & 0x0F00) >> 8 ) | (((qh5x8 >> 2) & 0x01) << 4)) * s + m);
|
| 14 |
+
fp32x8.s3 = (float)((((qs5x8.s0 & 0xF000) >> 12) | (((qh5x8 >> 3) & 0x01) << 4)) * s + m);
|
| 15 |
+
fp32x8.s4 = (float)((( qs5x8.s1 & 0x000F) | (((qh5x8 >> 4) & 0x01) << 4)) * s + m);
|
| 16 |
+
fp32x8.s5 = (float)((((qs5x8.s1 & 0x00F0) >> 4 ) | (((qh5x8 >> 5) & 0x01) << 4)) * s + m);
|
| 17 |
+
fp32x8.s6 = (float)((((qs5x8.s1 & 0x0F00) >> 8 ) | (((qh5x8 >> 6) & 0x01) << 4)) * s + m);
|
| 18 |
+
fp32x8.s7 = (float)((((qs5x8.s1 & 0xF000) >> 12) | (((qh5x8 >> 7) & 0x01) << 4)) * s + m);
|
| 19 |
+
return fp32x8;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 24 |
+
__kernel void kernel_gemv_moe_q5_1_f32_ns(
|
| 25 |
+
__global uint * src0_qs,
|
| 26 |
+
__global uint * src0_qh,
|
| 27 |
+
__global half * src0_d,
|
| 28 |
+
__global half * src0_m,
|
| 29 |
+
__read_only image1d_buffer_t src1,
|
| 30 |
+
__global uint * src2,
|
| 31 |
+
__global float * dst,
|
| 32 |
+
ulong offsetd,
|
| 33 |
+
uint ne00,
|
| 34 |
+
uint ne01,
|
| 35 |
+
uint ne11
|
| 36 |
+
) {
|
| 37 |
+
uint i01 = get_global_id(0);
|
| 38 |
+
uint i20 = get_global_id(2);
|
| 39 |
+
uint sgid = get_local_id(1);
|
| 40 |
+
uint slid = get_sub_group_local_id();
|
| 41 |
+
|
| 42 |
+
if (i01 >= ne01) {
|
| 43 |
+
return;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
uint i11 = i20 % ne11;
|
| 47 |
+
|
| 48 |
+
uint expert_id = src2[i20];
|
| 49 |
+
uint expert_offset = expert_id * ne00 * ne01 / 32;
|
| 50 |
+
|
| 51 |
+
__private float sum = 0.0f; // each thread calculate partial sum of one output
|
| 52 |
+
|
| 53 |
+
// loop along ne00 in block granularity, skip 4 blocks every iter
|
| 54 |
+
for (uint ib00 = sgid; ib00 < (ne00 / QK_Q5_1); ib00 += N_SIMDGROUP) {
|
| 55 |
+
|
| 56 |
+
// load one block of q
|
| 57 |
+
uint4 regQ;
|
| 58 |
+
uint block_offset = expert_offset * 4 + ib00 * ne01 * 4 + i01;
|
| 59 |
+
|
| 60 |
+
regQ.s0 = src0_qs[block_offset];
|
| 61 |
+
regQ.s1 = src0_qs[block_offset + ne01];
|
| 62 |
+
regQ.s2 = src0_qs[block_offset + ne01 * 2];
|
| 63 |
+
regQ.s3 = src0_qs[block_offset + ne01 * 3];
|
| 64 |
+
|
| 65 |
+
uint offset = i11 * ne00 / 4 + ib00 * 8;
|
| 66 |
+
|
| 67 |
+
uchar4 regQh = as_uchar4(src0_qh[ib00 * ne01 + i01 + expert_offset]);
|
| 68 |
+
half regM = src0_m[ib00 * ne01 + i01 + expert_offset];
|
| 69 |
+
half regS = src0_d[ib00 * ne01 + i01 + expert_offset];
|
| 70 |
+
|
| 71 |
+
float8 fp32x8 = q5_1_to_fp32_packed8(as_ushort2(regQ.s0), regQh.s0, regS, regM);
|
| 72 |
+
|
| 73 |
+
float4 shared_y4;
|
| 74 |
+
shared_y4 = read_imagef(src1, (offset + 0));
|
| 75 |
+
float4 acc = shared_y4 * fp32x8.lo;
|
| 76 |
+
|
| 77 |
+
shared_y4 = read_imagef(src1, (offset + 1));
|
| 78 |
+
acc += shared_y4 * fp32x8.hi;
|
| 79 |
+
|
| 80 |
+
fp32x8 = q5_1_to_fp32_packed8(as_ushort2(regQ.s1), regQh.s1, regS, regM);
|
| 81 |
+
|
| 82 |
+
shared_y4 = read_imagef(src1, (offset + 2));
|
| 83 |
+
acc += shared_y4 * fp32x8.lo;
|
| 84 |
+
|
| 85 |
+
shared_y4 = read_imagef(src1, (offset + 3));
|
| 86 |
+
acc += shared_y4 * fp32x8.hi;
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
fp32x8 = q5_1_to_fp32_packed8(as_ushort2(regQ.s2), regQh.s2, regS, regM);
|
| 90 |
+
|
| 91 |
+
shared_y4 = read_imagef(src1, (offset + 4));
|
| 92 |
+
acc += shared_y4 * fp32x8.lo;
|
| 93 |
+
|
| 94 |
+
shared_y4 = read_imagef(src1, (offset + 5));
|
| 95 |
+
acc += shared_y4 * fp32x8.hi;
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
fp32x8 = q5_1_to_fp32_packed8(as_ushort2(regQ.s3), regQh.s3, regS, regM);
|
| 99 |
+
|
| 100 |
+
shared_y4 = read_imagef(src1, (offset + 6));
|
| 101 |
+
acc += shared_y4 * fp32x8.lo;
|
| 102 |
+
|
| 103 |
+
shared_y4 = read_imagef(src1, (offset + 7));
|
| 104 |
+
acc += shared_y4 * fp32x8.hi;
|
| 105 |
+
|
| 106 |
+
sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
// reduction in local memory, assumes #subgroups=4
|
| 110 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 111 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 112 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 113 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 114 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 115 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 116 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 117 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 118 |
+
|
| 119 |
+
// 1 outputs per thread in subgroup 0
|
| 120 |
+
if (sgid == 0) {
|
| 121 |
+
dst = dst + (offsetd >> 2);
|
| 122 |
+
dst[i01 + i20 * ne01] = sum;
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q5_k_f32_ns.cl
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_K 256
|
| 6 |
+
#define K_SCALE_SIZE 12
|
| 7 |
+
#define N_SIMDGROUP 4
|
| 8 |
+
#define SIMDGROUP_WIDTH 64
|
| 9 |
+
|
| 10 |
+
inline void get_scale_min_k4(
|
| 11 |
+
int j,
|
| 12 |
+
global const uchar * q,
|
| 13 |
+
uchar * d,
|
| 14 |
+
uchar * m
|
| 15 |
+
) {
|
| 16 |
+
if (j < 4) {
|
| 17 |
+
*d = q[j] & 63;
|
| 18 |
+
*m = q[j+4] & 63;
|
| 19 |
+
} else {
|
| 20 |
+
*d = (q[j+4] & 0x0F) | ((q[j-4] & 0xC0) >> 2);
|
| 21 |
+
*m = ((q[j+4] >> 4) & 0x0F) | ((q[j] & 0xC0) >> 2);
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
static inline float8 q5_k_to_fp32_packed8(ushort2 qs5x8, uchar qh5x8, half s, half m) {
|
| 26 |
+
float8 fp32x8;
|
| 27 |
+
fp32x8.s0 = (float)((( qs5x8.s0 & 0x000F) | (( qh5x8 & 0x01) << 4)) * s + m);
|
| 28 |
+
fp32x8.s1 = (float)((((qs5x8.s0 & 0x00F0) >> 4 ) | (((qh5x8 >> 1) & 0x01) << 4)) * s + m);
|
| 29 |
+
fp32x8.s2 = (float)((((qs5x8.s0 & 0x0F00) >> 8 ) | (((qh5x8 >> 2) & 0x01) << 4)) * s + m);
|
| 30 |
+
fp32x8.s3 = (float)((((qs5x8.s0 & 0xF000) >> 12) | (((qh5x8 >> 3) & 0x01) << 4)) * s + m);
|
| 31 |
+
fp32x8.s4 = (float)((( qs5x8.s1 & 0x000F) | (((qh5x8 >> 4) & 0x01) << 4)) * s + m);
|
| 32 |
+
fp32x8.s5 = (float)((((qs5x8.s1 & 0x00F0) >> 4 ) | (((qh5x8 >> 5) & 0x01) << 4)) * s + m);
|
| 33 |
+
fp32x8.s6 = (float)((((qs5x8.s1 & 0x0F00) >> 8 ) | (((qh5x8 >> 6) & 0x01) << 4)) * s + m);
|
| 34 |
+
fp32x8.s7 = (float)((((qs5x8.s1 & 0xF000) >> 12) | (((qh5x8 >> 7) & 0x01) << 4)) * s + m);
|
| 35 |
+
return fp32x8;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 39 |
+
__kernel void kernel_gemv_moe_q5_k_f32_ns(
|
| 40 |
+
__global uint * src0_q,
|
| 41 |
+
__global uint * src0_qh,
|
| 42 |
+
__global half * src0_d,
|
| 43 |
+
__global half * src0_dm,
|
| 44 |
+
__global uchar * src0_s,
|
| 45 |
+
__read_only image1d_buffer_t src1,
|
| 46 |
+
__global uint * src2,
|
| 47 |
+
__global float * dst,
|
| 48 |
+
ulong offsetd,
|
| 49 |
+
int ne00,
|
| 50 |
+
int ne01,
|
| 51 |
+
int ne11
|
| 52 |
+
) {
|
| 53 |
+
uint i01 = get_global_id(0);
|
| 54 |
+
uint i20 = get_global_id(2);
|
| 55 |
+
uint sgid = get_local_id(1);
|
| 56 |
+
uint slid = get_sub_group_local_id();
|
| 57 |
+
|
| 58 |
+
if (i01 >= ne01) {
|
| 59 |
+
return;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
uint i11 = i20 % ne11;
|
| 63 |
+
|
| 64 |
+
uint expert_id = src2[i20];
|
| 65 |
+
|
| 66 |
+
int num_superblocks = ne00 / QK_K;
|
| 67 |
+
int num_subblocks = ne00 / 32;
|
| 68 |
+
int scales_per_row = num_superblocks * K_SCALE_SIZE;
|
| 69 |
+
|
| 70 |
+
// Expert offsets in the transposed noshuffle layout
|
| 71 |
+
uint expert_q_offset = expert_id * (ne00 / 8) * ne01;
|
| 72 |
+
uint expert_d_offset = expert_id * num_superblocks * ne01;
|
| 73 |
+
|
| 74 |
+
__private float sum = 0.0f;
|
| 75 |
+
|
| 76 |
+
// Loop over sub-blocks of 32 elements, N_SIMDGROUP sub-blocks per iter
|
| 77 |
+
for (uint ib = sgid; ib < num_subblocks; ib += N_SIMDGROUP) {
|
| 78 |
+
uint sb = ib / 8;
|
| 79 |
+
uint j = ib % 8;
|
| 80 |
+
|
| 81 |
+
// Load d and dmin for this super-block
|
| 82 |
+
half d_val = src0_d[expert_d_offset + sb * ne01 + i01];
|
| 83 |
+
half dm_val = src0_dm[expert_d_offset + sb * ne01 + i01];
|
| 84 |
+
|
| 85 |
+
// sub_block index = sb * 8 + j
|
| 86 |
+
uint expert_qh_offset = expert_id * num_superblocks * 8 * ne01;
|
| 87 |
+
uchar4 regQh = as_uchar4(src0_qh[expert_qh_offset + (sb * 8 + j) * ne01 + i01]);
|
| 88 |
+
|
| 89 |
+
// Load sub-block scale and min
|
| 90 |
+
global const uchar * sc = src0_s + (expert_id * ne01 + i01) * scales_per_row + sb * K_SCALE_SIZE;
|
| 91 |
+
uchar sv, mn;
|
| 92 |
+
get_scale_min_k4(j, sc, &sv, &mn);
|
| 93 |
+
|
| 94 |
+
float scale = (float)d_val * (float)sv;
|
| 95 |
+
float minv = -(float)dm_val * (float)mn;
|
| 96 |
+
|
| 97 |
+
// Load 4 uints of quants (32 nibbles = 32 elements)
|
| 98 |
+
uint q_base = expert_q_offset + ib * ne01 * 4 + i01;
|
| 99 |
+
|
| 100 |
+
uint4 regQ;
|
| 101 |
+
regQ.s0 = src0_q[q_base];
|
| 102 |
+
regQ.s1 = src0_q[q_base + ne01];
|
| 103 |
+
regQ.s2 = src0_q[q_base + ne01 * 2];
|
| 104 |
+
regQ.s3 = src0_q[q_base + ne01 * 3];
|
| 105 |
+
|
| 106 |
+
// Load activations: 32 floats = 8 float4s
|
| 107 |
+
uint y_offset = i11 * ne00 / 4 + ib * 8;
|
| 108 |
+
|
| 109 |
+
float8 fp32x8 = q5_k_to_fp32_packed8(as_ushort2(regQ.s0), regQh.s0, scale, minv);
|
| 110 |
+
|
| 111 |
+
float4 shared_y4;
|
| 112 |
+
shared_y4 = read_imagef(src1, (y_offset + 0));
|
| 113 |
+
float4 acc = shared_y4 * fp32x8.lo;
|
| 114 |
+
|
| 115 |
+
shared_y4 = read_imagef(src1, (y_offset + 1));
|
| 116 |
+
acc += shared_y4 * fp32x8.hi;
|
| 117 |
+
|
| 118 |
+
fp32x8 = q5_k_to_fp32_packed8(as_ushort2(regQ.s1), regQh.s1, scale, minv);
|
| 119 |
+
|
| 120 |
+
shared_y4 = read_imagef(src1, (y_offset + 2));
|
| 121 |
+
acc += shared_y4 * fp32x8.lo;
|
| 122 |
+
|
| 123 |
+
shared_y4 = read_imagef(src1, (y_offset + 3));
|
| 124 |
+
acc += shared_y4 * fp32x8.hi;
|
| 125 |
+
|
| 126 |
+
fp32x8 = q5_k_to_fp32_packed8(as_ushort2(regQ.s2), regQh.s2, scale, minv);
|
| 127 |
+
|
| 128 |
+
shared_y4 = read_imagef(src1, (y_offset + 4));
|
| 129 |
+
acc += shared_y4 * fp32x8.lo;
|
| 130 |
+
|
| 131 |
+
shared_y4 = read_imagef(src1, (y_offset + 5));
|
| 132 |
+
acc += shared_y4 * fp32x8.hi;
|
| 133 |
+
|
| 134 |
+
fp32x8 = q5_k_to_fp32_packed8(as_ushort2(regQ.s3), regQh.s3, scale, minv);
|
| 135 |
+
|
| 136 |
+
shared_y4 = read_imagef(src1, (y_offset + 6));
|
| 137 |
+
acc += shared_y4 * fp32x8.lo;
|
| 138 |
+
|
| 139 |
+
shared_y4 = read_imagef(src1, (y_offset + 7));
|
| 140 |
+
acc += shared_y4 * fp32x8.hi;
|
| 141 |
+
|
| 142 |
+
sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
// reduction in local memory, assumes #subgroups=4
|
| 146 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 147 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 148 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 149 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 150 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 151 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 152 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 153 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 154 |
+
|
| 155 |
+
// 1 output per thread in subgroup 0
|
| 156 |
+
if (sgid == 0) {
|
| 157 |
+
dst = dst + (offsetd >> 2);
|
| 158 |
+
dst[i01 + i20 * ne01] = sum;
|
| 159 |
+
}
|
| 160 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_moe_q6_k_f32_ns.cl
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 4 |
+
|
| 5 |
+
#define QK_K 256
|
| 6 |
+
#define N_SIMDGROUP 4
|
| 7 |
+
#define SIMDGROUP_WIDTH 64
|
| 8 |
+
|
| 9 |
+
static inline float8 q6_k_to_fp32_packed8(ushort2 ql8, ushort qh8, float d_scale) {
|
| 10 |
+
float8 fp32x8;
|
| 11 |
+
fp32x8.s0 = ((float)(( ql8.s0 & 0x000F) | ((uint)((qh8 ) & 0x3) << 4)) - 32.f) * d_scale;
|
| 12 |
+
fp32x8.s1 = ((float)((( ql8.s0 >> 4) & 0x000F) | ((uint)((qh8 >> 2) & 0x3) << 4)) - 32.f) * d_scale;
|
| 13 |
+
fp32x8.s2 = ((float)((( ql8.s0 >> 8) & 0x000F) | ((uint)((qh8 >> 4) & 0x3) << 4)) - 32.f) * d_scale;
|
| 14 |
+
fp32x8.s3 = ((float)((( ql8.s0 >> 12)& 0x000F) | ((uint)((qh8 >> 6) & 0x3) << 4)) - 32.f) * d_scale;
|
| 15 |
+
fp32x8.s4 = ((float)(( ql8.s1 & 0x000F) | ((uint)((qh8 >> 8) & 0x3) << 4)) - 32.f) * d_scale;
|
| 16 |
+
fp32x8.s5 = ((float)((( ql8.s1 >> 4) & 0x000F) | ((uint)((qh8 >>10) & 0x3) << 4)) - 32.f) * d_scale;
|
| 17 |
+
fp32x8.s6 = ((float)((( ql8.s1 >> 8) & 0x000F) | ((uint)((qh8 >>12) & 0x3) << 4)) - 32.f) * d_scale;
|
| 18 |
+
fp32x8.s7 = ((float)((( ql8.s1 >> 12)& 0x000F) | ((uint)((qh8 >>14) & 0x3) << 4)) - 32.f) * d_scale;
|
| 19 |
+
return fp32x8;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
__attribute__((qcom_reqd_sub_group_size("half")))
|
| 23 |
+
__kernel void kernel_gemv_moe_q6_k_f32_ns(
|
| 24 |
+
__global uint * src0_ql,
|
| 25 |
+
__global uint * src0_qh,
|
| 26 |
+
__global char * src0_s,
|
| 27 |
+
__global half * src0_d,
|
| 28 |
+
__read_only image1d_buffer_t src1,
|
| 29 |
+
__global uint * src2,
|
| 30 |
+
__global float * dst,
|
| 31 |
+
ulong offsetd,
|
| 32 |
+
int ne00,
|
| 33 |
+
int ne01,
|
| 34 |
+
int ne11
|
| 35 |
+
) {
|
| 36 |
+
uint i01 = get_global_id(0);
|
| 37 |
+
uint i20 = get_global_id(2);
|
| 38 |
+
uint sgid = get_local_id(1);
|
| 39 |
+
uint slid = get_sub_group_local_id();
|
| 40 |
+
|
| 41 |
+
if (i01 >= ne01) {
|
| 42 |
+
return;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
uint i11 = i20 % ne11;
|
| 46 |
+
|
| 47 |
+
uint expert_id = src2[i20];
|
| 48 |
+
|
| 49 |
+
int num_superblocks = ne00 / QK_K;
|
| 50 |
+
int num_subblocks = ne00 / 32; // 8 sub-blocks of 32 per super-block
|
| 51 |
+
int scales_per_row = num_superblocks * 16;
|
| 52 |
+
|
| 53 |
+
// Expert offsets in the transposed noshuffle layout
|
| 54 |
+
uint expert_ql_offset = expert_id * (ne00 / 8) * ne01; // 32 uints per super-block
|
| 55 |
+
uint expert_qh_offset = expert_id * (ne00 / 16) * ne01; // 16 uints per super-block
|
| 56 |
+
uint expert_d_offset = expert_id * num_superblocks * ne01;
|
| 57 |
+
|
| 58 |
+
__private float sum = 0.0f;
|
| 59 |
+
|
| 60 |
+
// Loop over sub-blocks of 32 elements, N_SIMDGROUP sub-blocks per iter
|
| 61 |
+
for (uint ib = sgid; ib < num_subblocks; ib += N_SIMDGROUP) {
|
| 62 |
+
uint sb = ib / 8; // super-block index
|
| 63 |
+
uint j = ib % 8; // 32-element group within super-block
|
| 64 |
+
|
| 65 |
+
// Load d for this super-block
|
| 66 |
+
half d_val = src0_d[expert_d_offset + sb * ne01 + i01];
|
| 67 |
+
|
| 68 |
+
// Load 2 sub-block scales
|
| 69 |
+
global const char * sc = src0_s + (expert_id * ne01 + i01) * scales_per_row + sb * 16;
|
| 70 |
+
float scale0 = (float)d_val * (float)sc[j * 2];
|
| 71 |
+
float scale1 = (float)d_val * (float)sc[j * 2 + 1];
|
| 72 |
+
|
| 73 |
+
// Load 4 uints of ql
|
| 74 |
+
uint ql_base = expert_ql_offset + (ib * 4) * ne01 + i01;
|
| 75 |
+
uint4 regQL;
|
| 76 |
+
regQL.s0 = src0_ql[ql_base];
|
| 77 |
+
regQL.s1 = src0_ql[ql_base + ne01];
|
| 78 |
+
regQL.s2 = src0_ql[ql_base + ne01 * 2];
|
| 79 |
+
regQL.s3 = src0_ql[ql_base + ne01 * 3];
|
| 80 |
+
|
| 81 |
+
// Load 2 uints of qh
|
| 82 |
+
uint qh_base = expert_qh_offset + (ib * 2) * ne01 + i01;
|
| 83 |
+
uint2 regQH;
|
| 84 |
+
regQH.s0 = src0_qh[qh_base];
|
| 85 |
+
regQH.s1 = src0_qh[qh_base + ne01];
|
| 86 |
+
|
| 87 |
+
// Load activations: 32 floats = 8 float4s
|
| 88 |
+
uint y_offset = i11 * ne00 / 4 + ib * 8;
|
| 89 |
+
|
| 90 |
+
float8 fp32x8 = q6_k_to_fp32_packed8(as_ushort2(regQL.s0), (ushort)(regQH.s0 & 0xFFFF), scale0);
|
| 91 |
+
|
| 92 |
+
float4 shared_y4;
|
| 93 |
+
shared_y4 = read_imagef(src1, (y_offset + 0));
|
| 94 |
+
float4 acc = shared_y4 * fp32x8.lo;
|
| 95 |
+
|
| 96 |
+
shared_y4 = read_imagef(src1, (y_offset + 1));
|
| 97 |
+
acc += shared_y4 * fp32x8.hi;
|
| 98 |
+
|
| 99 |
+
fp32x8 = q6_k_to_fp32_packed8(as_ushort2(regQL.s1), (ushort)(regQH.s0 >> 16), scale0);
|
| 100 |
+
|
| 101 |
+
shared_y4 = read_imagef(src1, (y_offset + 2));
|
| 102 |
+
acc += shared_y4 * fp32x8.lo;
|
| 103 |
+
|
| 104 |
+
shared_y4 = read_imagef(src1, (y_offset + 3));
|
| 105 |
+
acc += shared_y4 * fp32x8.hi;
|
| 106 |
+
|
| 107 |
+
fp32x8 = q6_k_to_fp32_packed8(as_ushort2(regQL.s2), (ushort)(regQH.s1 & 0xFFFF), scale1);
|
| 108 |
+
|
| 109 |
+
shared_y4 = read_imagef(src1, (y_offset + 4));
|
| 110 |
+
acc += shared_y4 * fp32x8.lo;
|
| 111 |
+
|
| 112 |
+
shared_y4 = read_imagef(src1, (y_offset + 5));
|
| 113 |
+
acc += shared_y4 * fp32x8.hi;
|
| 114 |
+
|
| 115 |
+
fp32x8 = q6_k_to_fp32_packed8(as_ushort2(regQL.s3), (ushort)(regQH.s1 >> 16), scale1);
|
| 116 |
+
|
| 117 |
+
shared_y4 = read_imagef(src1, (y_offset + 6));
|
| 118 |
+
acc += shared_y4 * fp32x8.lo;
|
| 119 |
+
|
| 120 |
+
shared_y4 = read_imagef(src1, (y_offset + 7));
|
| 121 |
+
acc += shared_y4 * fp32x8.hi;
|
| 122 |
+
|
| 123 |
+
sum += ((acc.s0 + acc.s1) + (acc.s2 + acc.s3));
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
// reduction in local memory, assumes #subgroups=4
|
| 127 |
+
__local float reduceLM[SIMDGROUP_WIDTH * (N_SIMDGROUP - 1)];
|
| 128 |
+
if (sgid == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = sum;
|
| 129 |
+
if (sgid == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = sum;
|
| 130 |
+
if (sgid == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = sum;
|
| 131 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 132 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 133 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 134 |
+
if (sgid == 0) sum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 135 |
+
|
| 136 |
+
// 1 output per thread in subgroup 0
|
| 137 |
+
if (sgid == 0) {
|
| 138 |
+
dst = dst + (offsetd >> 2);
|
| 139 |
+
dst[i01 + i20 * ne01] = sum;
|
| 140 |
+
}
|
| 141 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_iq4_nl_f32.cl
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
#define QK4_NL 32
|
| 11 |
+
#define NSUBGROUPS 4
|
| 12 |
+
#define SUBGROUP_SIZE 64
|
| 13 |
+
|
| 14 |
+
constant half kvalues_iq4nl[16] = {
|
| 15 |
+
(half)-127.f, (half)-104.f, (half)-83.f, (half)-65.f,
|
| 16 |
+
(half) -49.f, (half) -35.f, (half)-22.f, (half)-10.f,
|
| 17 |
+
(half) 1.f, (half) 13.f, (half) 25.f, (half) 38.f,
|
| 18 |
+
(half) 53.f, (half) 69.f, (half) 89.f, (half)113.f
|
| 19 |
+
};
|
| 20 |
+
|
| 21 |
+
// Packed LUT: 2 FP16 values per uint, 8 unique constant loads instead of 16
|
| 22 |
+
constant uint iq4nl_packed[8] = {
|
| 23 |
+
0xD680D7F0u, // idx 0,1: -127, -104
|
| 24 |
+
0xD410D530u, // idx 2,3: -83, -65
|
| 25 |
+
0xD060D220u, // idx 4,5: -49, -35
|
| 26 |
+
0xC900CD80u, // idx 6,7: -22, -10
|
| 27 |
+
0x4A803C00u, // idx 8,9: 1, 13
|
| 28 |
+
0x50C04E40u, // idx 10,11: 25, 38
|
| 29 |
+
0x545052A0u, // idx 12,13: 53, 69
|
| 30 |
+
0x57105590u // idx 14,15: 89, 113
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
// Packed dequant: 1 uint constant load (8-way divergence) + shift + as_half
|
| 34 |
+
#define IQ4_NL_DEQUANT(nibble) as_half((ushort)(iq4nl_packed[(nibble) >> 1] >> (((nibble) & 1u) << 4)))
|
| 35 |
+
|
| 36 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_1_hi(total_sums, bits4, scale, y) \
|
| 37 |
+
float shared_y; \
|
| 38 |
+
shared_y = sub_group_broadcast(y.s0, 0); \
|
| 39 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s0 & 0x000F)) * scale.s0 * shared_y; \
|
| 40 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s1 & 0x000F)) * scale.s1 * shared_y; \
|
| 41 |
+
shared_y = sub_group_broadcast(y.s1, 0); \
|
| 42 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
|
| 43 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
|
| 44 |
+
shared_y = sub_group_broadcast(y.s2, 0); \
|
| 45 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
|
| 46 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
|
| 47 |
+
shared_y = sub_group_broadcast(y.s3, 0); \
|
| 48 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0xF000) >> 12)) * scale.s0 * shared_y; \
|
| 49 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0xF000) >> 12)) * scale.s1 * shared_y; \
|
| 50 |
+
shared_y = sub_group_broadcast(y.s4, 0); \
|
| 51 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s2 & 0x000F)) * scale.s0 * shared_y; \
|
| 52 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s3 & 0x000F)) * scale.s1 * shared_y; \
|
| 53 |
+
shared_y = sub_group_broadcast(y.s5, 0); \
|
| 54 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
|
| 55 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
|
| 56 |
+
shared_y = sub_group_broadcast(y.s6, 0); \
|
| 57 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
|
| 58 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
|
| 59 |
+
shared_y = sub_group_broadcast(y.s7, 0); \
|
| 60 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0xF000) >> 12)) * scale.s0 * shared_y; \
|
| 61 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0xF000) >> 12)) * scale.s1 * shared_y; \
|
| 62 |
+
shared_y = sub_group_broadcast(y.s0, 1); \
|
| 63 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s4 & 0x000F)) * scale.s0 * shared_y; \
|
| 64 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s5 & 0x000F)) * scale.s1 * shared_y; \
|
| 65 |
+
shared_y = sub_group_broadcast(y.s1, 1); \
|
| 66 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
|
| 67 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
|
| 68 |
+
shared_y = sub_group_broadcast(y.s2, 1); \
|
| 69 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
|
| 70 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
|
| 71 |
+
shared_y = sub_group_broadcast(y.s3, 1); \
|
| 72 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0xF000) >> 12)) * scale.s0 * shared_y; \
|
| 73 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0xF000) >> 12)) * scale.s1 * shared_y; \
|
| 74 |
+
shared_y = sub_group_broadcast(y.s4, 1); \
|
| 75 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s6 & 0x000F)) * scale.s0 * shared_y; \
|
| 76 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s7 & 0x000F)) * scale.s1 * shared_y; \
|
| 77 |
+
shared_y = sub_group_broadcast(y.s5, 1); \
|
| 78 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
|
| 79 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
|
| 80 |
+
shared_y = sub_group_broadcast(y.s6, 1); \
|
| 81 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
|
| 82 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
|
| 83 |
+
shared_y = sub_group_broadcast(y.s7, 1); \
|
| 84 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0xF000) >> 12)) * scale.s0 * shared_y; \
|
| 85 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0xF000) >> 12)) * scale.s1 * shared_y; \
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_1_lo(total_sums, bits4, scale, y) \
|
| 89 |
+
shared_y = sub_group_broadcast(y.s0, 2); \
|
| 90 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s0 & 0x000F)) * scale.s0 * shared_y; \
|
| 91 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s1 & 0x000F)) * scale.s1 * shared_y; \
|
| 92 |
+
shared_y = sub_group_broadcast(y.s1, 2); \
|
| 93 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
|
| 94 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
|
| 95 |
+
shared_y = sub_group_broadcast(y.s2, 2); \
|
| 96 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
|
| 97 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
|
| 98 |
+
shared_y = sub_group_broadcast(y.s3, 2); \
|
| 99 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0xF000) >> 12)) * scale.s0 * shared_y; \
|
| 100 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0xF000) >> 12)) * scale.s1 * shared_y; \
|
| 101 |
+
shared_y = sub_group_broadcast(y.s4, 2); \
|
| 102 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s2 & 0x000F)) * scale.s0 * shared_y; \
|
| 103 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s3 & 0x000F)) * scale.s1 * shared_y; \
|
| 104 |
+
shared_y = sub_group_broadcast(y.s5, 2); \
|
| 105 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
|
| 106 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
|
| 107 |
+
shared_y = sub_group_broadcast(y.s6, 2); \
|
| 108 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
|
| 109 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
|
| 110 |
+
shared_y = sub_group_broadcast(y.s7, 2); \
|
| 111 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0xF000) >> 12)) * scale.s0 * shared_y; \
|
| 112 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0xF000) >> 12)) * scale.s1 * shared_y; \
|
| 113 |
+
shared_y = sub_group_broadcast(y.s0, 3); \
|
| 114 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s4 & 0x000F)) * scale.s0 * shared_y; \
|
| 115 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s5 & 0x000F)) * scale.s1 * shared_y; \
|
| 116 |
+
shared_y = sub_group_broadcast(y.s1, 3); \
|
| 117 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
|
| 118 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
|
| 119 |
+
shared_y = sub_group_broadcast(y.s2, 3); \
|
| 120 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
|
| 121 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
|
| 122 |
+
shared_y = sub_group_broadcast(y.s3, 3); \
|
| 123 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0xF000) >> 12)) * scale.s0 * shared_y; \
|
| 124 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0xF000) >> 12)) * scale.s1 * shared_y; \
|
| 125 |
+
shared_y = sub_group_broadcast(y.s4, 3); \
|
| 126 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s6 & 0x000F)) * scale.s0 * shared_y; \
|
| 127 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s7 & 0x000F)) * scale.s1 * shared_y; \
|
| 128 |
+
shared_y = sub_group_broadcast(y.s5, 3); \
|
| 129 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x00F0) >> 4)) * scale.s0 * shared_y; \
|
| 130 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x00F0) >> 4)) * scale.s1 * shared_y; \
|
| 131 |
+
shared_y = sub_group_broadcast(y.s6, 3); \
|
| 132 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x0F00) >> 8)) * scale.s0 * shared_y; \
|
| 133 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x0F00) >> 8)) * scale.s1 * shared_y; \
|
| 134 |
+
shared_y = sub_group_broadcast(y.s7, 3); \
|
| 135 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0xF000) >> 12)) * scale.s0 * shared_y; \
|
| 136 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0xF000) >> 12)) * scale.s1 * shared_y; \
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_8_hi(total_sums, bits4, scale, y) \
|
| 140 |
+
float8 shared_y; \
|
| 141 |
+
shared_y = sub_group_broadcast(y, 0); \
|
| 142 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s0 & 0x000F)) * scale.s0 * shared_y.s0; \
|
| 143 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x00F0) >> 4)) * scale.s0 * shared_y.s1; \
|
| 144 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x0F00) >> 8)) * scale.s0 * shared_y.s2; \
|
| 145 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0xF000) >> 12)) * scale.s0 * shared_y.s3; \
|
| 146 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s2 & 0x000F)) * scale.s0 * shared_y.s4; \
|
| 147 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x00F0) >> 4)) * scale.s0 * shared_y.s5; \
|
| 148 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x0F00) >> 8)) * scale.s0 * shared_y.s6; \
|
| 149 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0xF000) >> 12)) * scale.s0 * shared_y.s7; \
|
| 150 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s1 & 0x000F)) * scale.s1 * shared_y.s0; \
|
| 151 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x00F0) >> 4)) * scale.s1 * shared_y.s1; \
|
| 152 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x0F00) >> 8)) * scale.s1 * shared_y.s2; \
|
| 153 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0xF000) >> 12)) * scale.s1 * shared_y.s3; \
|
| 154 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s3 & 0x000F)) * scale.s1 * shared_y.s4; \
|
| 155 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x00F0) >> 4)) * scale.s1 * shared_y.s5; \
|
| 156 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x0F00) >> 8)) * scale.s1 * shared_y.s6; \
|
| 157 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0xF000) >> 12)) * scale.s1 * shared_y.s7; \
|
| 158 |
+
shared_y = sub_group_broadcast(y, 1); \
|
| 159 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s4 & 0x000F)) * scale.s0 * shared_y.s0; \
|
| 160 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x00F0) >> 4)) * scale.s0 * shared_y.s1; \
|
| 161 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x0F00) >> 8)) * scale.s0 * shared_y.s2; \
|
| 162 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0xF000) >> 12)) * scale.s0 * shared_y.s3; \
|
| 163 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s6 & 0x000F)) * scale.s0 * shared_y.s4; \
|
| 164 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x00F0) >> 4)) * scale.s0 * shared_y.s5; \
|
| 165 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x0F00) >> 8)) * scale.s0 * shared_y.s6; \
|
| 166 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0xF000) >> 12)) * scale.s0 * shared_y.s7; \
|
| 167 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s5 & 0x000F)) * scale.s1 * shared_y.s0; \
|
| 168 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x00F0) >> 4)) * scale.s1 * shared_y.s1; \
|
| 169 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x0F00) >> 8)) * scale.s1 * shared_y.s2; \
|
| 170 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0xF000) >> 12)) * scale.s1 * shared_y.s3; \
|
| 171 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s7 & 0x000F)) * scale.s1 * shared_y.s4; \
|
| 172 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x00F0) >> 4)) * scale.s1 * shared_y.s5; \
|
| 173 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x0F00) >> 8)) * scale.s1 * shared_y.s6; \
|
| 174 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0xF000) >> 12)) * scale.s1 * shared_y.s7; \
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_8_lo(total_sums, bits4, scale, y) \
|
| 178 |
+
shared_y = sub_group_broadcast(y, 2); \
|
| 179 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s0 & 0x000F)) * scale.s0 * shared_y.s0; \
|
| 180 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x00F0) >> 4)) * scale.s0 * shared_y.s1; \
|
| 181 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0x0F00) >> 8)) * scale.s0 * shared_y.s2; \
|
| 182 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s0 & 0xF000) >> 12)) * scale.s0 * shared_y.s3; \
|
| 183 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s2 & 0x000F)) * scale.s0 * shared_y.s4; \
|
| 184 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x00F0) >> 4)) * scale.s0 * shared_y.s5; \
|
| 185 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0x0F00) >> 8)) * scale.s0 * shared_y.s6; \
|
| 186 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s2 & 0xF000) >> 12)) * scale.s0 * shared_y.s7; \
|
| 187 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s1 & 0x000F)) * scale.s1 * shared_y.s0; \
|
| 188 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x00F0) >> 4)) * scale.s1 * shared_y.s1; \
|
| 189 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0x0F00) >> 8)) * scale.s1 * shared_y.s2; \
|
| 190 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s1 & 0xF000) >> 12)) * scale.s1 * shared_y.s3; \
|
| 191 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s3 & 0x000F)) * scale.s1 * shared_y.s4; \
|
| 192 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x00F0) >> 4)) * scale.s1 * shared_y.s5; \
|
| 193 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0x0F00) >> 8)) * scale.s1 * shared_y.s6; \
|
| 194 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s3 & 0xF000) >> 12)) * scale.s1 * shared_y.s7; \
|
| 195 |
+
shared_y = sub_group_broadcast(y, 3); \
|
| 196 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s4 & 0x000F)) * scale.s0 * shared_y.s0; \
|
| 197 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x00F0) >> 4)) * scale.s0 * shared_y.s1; \
|
| 198 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0x0F00) >> 8)) * scale.s0 * shared_y.s2; \
|
| 199 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s4 & 0xF000) >> 12)) * scale.s0 * shared_y.s3; \
|
| 200 |
+
total_sums.s0 += IQ4_NL_DEQUANT((bits4.s6 & 0x000F)) * scale.s0 * shared_y.s4; \
|
| 201 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x00F0) >> 4)) * scale.s0 * shared_y.s5; \
|
| 202 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0x0F00) >> 8)) * scale.s0 * shared_y.s6; \
|
| 203 |
+
total_sums.s0 += IQ4_NL_DEQUANT(((bits4.s6 & 0xF000) >> 12)) * scale.s0 * shared_y.s7; \
|
| 204 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s5 & 0x000F)) * scale.s1 * shared_y.s0; \
|
| 205 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x00F0) >> 4)) * scale.s1 * shared_y.s1; \
|
| 206 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0x0F00) >> 8)) * scale.s1 * shared_y.s2; \
|
| 207 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s5 & 0xF000) >> 12)) * scale.s1 * shared_y.s3; \
|
| 208 |
+
total_sums.s1 += IQ4_NL_DEQUANT((bits4.s7 & 0x000F)) * scale.s1 * shared_y.s4; \
|
| 209 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x00F0) >> 4)) * scale.s1 * shared_y.s5; \
|
| 210 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0x0F00) >> 8)) * scale.s1 * shared_y.s6; \
|
| 211 |
+
total_sums.s1 += IQ4_NL_DEQUANT(((bits4.s7 & 0xF000) >> 12)) * scale.s1 * shared_y.s7; \
|
| 212 |
+
|
| 213 |
+
#ifdef ADRENO_GPU
|
| 214 |
+
REQD_SUBGROUP_SIZE_64
|
| 215 |
+
#endif
|
| 216 |
+
kernel void kernel_gemv_noshuffle_iq4_nl_f32(
|
| 217 |
+
read_only image1d_buffer_t src0_q,
|
| 218 |
+
global half2 * src0_d,
|
| 219 |
+
read_only image1d_buffer_t src1,
|
| 220 |
+
global float * dst,
|
| 221 |
+
ulong offsetd,
|
| 222 |
+
int ne00,
|
| 223 |
+
int ne01)
|
| 224 |
+
{
|
| 225 |
+
uint groupId = get_local_id(1);
|
| 226 |
+
uint gid = get_global_id(0);
|
| 227 |
+
ushort slid = get_sub_group_local_id();
|
| 228 |
+
|
| 229 |
+
uint K = ne00;
|
| 230 |
+
uint M = ne01;
|
| 231 |
+
|
| 232 |
+
uint LINE_STRIDE_A = M / 2;
|
| 233 |
+
uint BLOCK_STRIDE_A = NSUBGROUPS * M;
|
| 234 |
+
|
| 235 |
+
private uint4 regA;
|
| 236 |
+
private half2 regS;
|
| 237 |
+
private float8 regB;
|
| 238 |
+
|
| 239 |
+
private float2 totalSum = (float2)(0.0f);
|
| 240 |
+
|
| 241 |
+
// loop along K in block granularity, skip 4 blocks every iter
|
| 242 |
+
for (uint k = groupId; k < (K / QK4_NL); k += NSUBGROUPS) {
|
| 243 |
+
regS = src0_d[gid + k * LINE_STRIDE_A]; // each fiber loads scale of two rows
|
| 244 |
+
// first 4 fibers in each wave load 8 B values to its private scope
|
| 245 |
+
if (slid < 4) {
|
| 246 |
+
regB.s0123 = read_imagef(src1, (slid * 2 + k * 8));
|
| 247 |
+
regB.s4567 = read_imagef(src1, (1 + slid * 2 + k * 8));
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
// load half weights for two blocks in consecutive rows
|
| 251 |
+
regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 0)).x;
|
| 252 |
+
regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 1)).x;
|
| 253 |
+
regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 2)).x;
|
| 254 |
+
regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 3)).x;
|
| 255 |
+
#ifdef VECTOR_SUB_GROUP_BROADCAST
|
| 256 |
+
dequantizeBlockAccum_ns_sgbroadcast_8_hi(totalSum, as_ushort8(regA), regS, regB);
|
| 257 |
+
#else
|
| 258 |
+
dequantizeBlockAccum_ns_sgbroadcast_1_hi(totalSum, as_ushort8(regA), regS, regB);
|
| 259 |
+
#endif // VECTOR_SUB_GROUP_BROADCAST
|
| 260 |
+
|
| 261 |
+
regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 4)).x;
|
| 262 |
+
regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 5)).x;
|
| 263 |
+
regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 6)).x;
|
| 264 |
+
regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 7)).x;
|
| 265 |
+
#ifdef VECTOR_SUB_GROUP_BROADCAST
|
| 266 |
+
dequantizeBlockAccum_ns_sgbroadcast_8_lo(totalSum, as_ushort8(regA), regS, regB);
|
| 267 |
+
#else
|
| 268 |
+
dequantizeBlockAccum_ns_sgbroadcast_1_lo(totalSum, as_ushort8(regA), regS, regB);
|
| 269 |
+
#endif // VECTOR_SUB_GROUP_BROADCAST
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
// reduction in local memory, assumes #wave=4
|
| 273 |
+
local float2 reduceLM[SUBGROUP_SIZE * 3];
|
| 274 |
+
if (groupId == 1) {
|
| 275 |
+
reduceLM[SUBGROUP_SIZE * 0 + slid] = totalSum;
|
| 276 |
+
}
|
| 277 |
+
if (groupId == 2) {
|
| 278 |
+
reduceLM[SUBGROUP_SIZE * 1 + slid] = totalSum;
|
| 279 |
+
}
|
| 280 |
+
if (groupId == 3) {
|
| 281 |
+
reduceLM[SUBGROUP_SIZE * 2 + slid] = totalSum;
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 285 |
+
|
| 286 |
+
if (groupId == 0) {
|
| 287 |
+
totalSum += reduceLM[SUBGROUP_SIZE * 0 + slid];
|
| 288 |
+
}
|
| 289 |
+
if (groupId == 0) {
|
| 290 |
+
totalSum += reduceLM[SUBGROUP_SIZE * 1 + slid];
|
| 291 |
+
}
|
| 292 |
+
if (groupId == 0) {
|
| 293 |
+
totalSum += reduceLM[SUBGROUP_SIZE * 2 + slid];
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
// 2 outputs per fiber in wave 0
|
| 297 |
+
if (groupId == 0) {
|
| 298 |
+
dst = (global float*)((global char*)dst + offsetd);
|
| 299 |
+
vstore2(totalSum, 0, &(dst[gid * 2]));
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q1_0_f32.cl
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
#define QK1_0 128
|
| 11 |
+
#define N_SIMDGROUP 4
|
| 12 |
+
|
| 13 |
+
#define dequantizeBlockAccum_q1(total, bits, scale, regB, lb) \
|
| 14 |
+
total += (2.0f*(float)((bits >> 0) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s0, lb+0); \
|
| 15 |
+
total += (2.0f*(float)((bits >> 1) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s1, lb+0); \
|
| 16 |
+
total += (2.0f*(float)((bits >> 2) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s2, lb+0); \
|
| 17 |
+
total += (2.0f*(float)((bits >> 3) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s3, lb+0); \
|
| 18 |
+
total += (2.0f*(float)((bits >> 4) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s4, lb+0); \
|
| 19 |
+
total += (2.0f*(float)((bits >> 5) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s5, lb+0); \
|
| 20 |
+
total += (2.0f*(float)((bits >> 6) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s6, lb+0); \
|
| 21 |
+
total += (2.0f*(float)((bits >> 7) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s7, lb+0); \
|
| 22 |
+
total += (2.0f*(float)((bits >> 8) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s0, lb+1); \
|
| 23 |
+
total += (2.0f*(float)((bits >> 9) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s1, lb+1); \
|
| 24 |
+
total += (2.0f*(float)((bits >> 10) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s2, lb+1); \
|
| 25 |
+
total += (2.0f*(float)((bits >> 11) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s3, lb+1); \
|
| 26 |
+
total += (2.0f*(float)((bits >> 12) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s4, lb+1); \
|
| 27 |
+
total += (2.0f*(float)((bits >> 13) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s5, lb+1); \
|
| 28 |
+
total += (2.0f*(float)((bits >> 14) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s6, lb+1); \
|
| 29 |
+
total += (2.0f*(float)((bits >> 15) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s7, lb+1); \
|
| 30 |
+
total += (2.0f*(float)((bits >> 16) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s0, lb+2); \
|
| 31 |
+
total += (2.0f*(float)((bits >> 17) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s1, lb+2); \
|
| 32 |
+
total += (2.0f*(float)((bits >> 18) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s2, lb+2); \
|
| 33 |
+
total += (2.0f*(float)((bits >> 19) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s3, lb+2); \
|
| 34 |
+
total += (2.0f*(float)((bits >> 20) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s4, lb+2); \
|
| 35 |
+
total += (2.0f*(float)((bits >> 21) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s5, lb+2); \
|
| 36 |
+
total += (2.0f*(float)((bits >> 22) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s6, lb+2); \
|
| 37 |
+
total += (2.0f*(float)((bits >> 23) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s7, lb+2); \
|
| 38 |
+
total += (2.0f*(float)((bits >> 24) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s0, lb+3); \
|
| 39 |
+
total += (2.0f*(float)((bits >> 25) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s1, lb+3); \
|
| 40 |
+
total += (2.0f*(float)((bits >> 26) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s2, lb+3); \
|
| 41 |
+
total += (2.0f*(float)((bits >> 27) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s3, lb+3); \
|
| 42 |
+
total += (2.0f*(float)((bits >> 28) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s4, lb+3); \
|
| 43 |
+
total += (2.0f*(float)((bits >> 29) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s5, lb+3); \
|
| 44 |
+
total += (2.0f*(float)((bits >> 30) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s6, lb+3); \
|
| 45 |
+
total += (2.0f*(float)((bits >> 31) & 1u) - 1.0f) * scale * sub_group_broadcast(regB.s7, lb+3);
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
#ifdef ADRENO_GPU
|
| 49 |
+
REQD_SUBGROUP_SIZE_64
|
| 50 |
+
#endif
|
| 51 |
+
__kernel void kernel_gemv_noshuffle_q1_0_f32(
|
| 52 |
+
read_only image1d_buffer_t src0_q,
|
| 53 |
+
global half * src0_d,
|
| 54 |
+
read_only image1d_buffer_t src1,
|
| 55 |
+
ulong offset1,
|
| 56 |
+
global float * dst,
|
| 57 |
+
ulong offsetd,
|
| 58 |
+
int ne00,
|
| 59 |
+
int ne01,
|
| 60 |
+
int ne02,
|
| 61 |
+
int ne10,
|
| 62 |
+
int ne12,
|
| 63 |
+
int ne0,
|
| 64 |
+
int ne1,
|
| 65 |
+
int r2,
|
| 66 |
+
int r3)
|
| 67 |
+
{
|
| 68 |
+
uint groupId = get_local_id(1);
|
| 69 |
+
uint gid = get_global_id(0);
|
| 70 |
+
ushort slid = get_sub_group_local_id();
|
| 71 |
+
|
| 72 |
+
uint K = ne00;
|
| 73 |
+
uint M = ne01;
|
| 74 |
+
|
| 75 |
+
uint LINE_STRIDE_A = M;
|
| 76 |
+
uint BLOCK_STRIDE_A = 4 * M;
|
| 77 |
+
|
| 78 |
+
uint4 regA;
|
| 79 |
+
half regS;
|
| 80 |
+
float8 regB;
|
| 81 |
+
|
| 82 |
+
float totalSum = 0.0f;
|
| 83 |
+
|
| 84 |
+
#pragma unroll 1
|
| 85 |
+
for (uint kb = groupId; kb < (K / QK1_0); kb += N_SIMDGROUP) {
|
| 86 |
+
regS = src0_d[gid + kb * LINE_STRIDE_A]; // each fiber loads its row's scale
|
| 87 |
+
|
| 88 |
+
// first 16 fibers load 8 B values each -> 128 activations for this block
|
| 89 |
+
if (slid < 16) {
|
| 90 |
+
regB.s0123 = read_imagef(src1, (slid * 2 + kb * 32));
|
| 91 |
+
regB.s4567 = read_imagef(src1, (1 + slid * 2 + kb * 32));
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
// load this row's 4 uint32 (128 sign bits)
|
| 95 |
+
regA.s0 = read_imageui(src0_q, (gid + kb * BLOCK_STRIDE_A + LINE_STRIDE_A * 0)).x;
|
| 96 |
+
regA.s1 = read_imageui(src0_q, (gid + kb * BLOCK_STRIDE_A + LINE_STRIDE_A * 1)).x;
|
| 97 |
+
regA.s2 = read_imageui(src0_q, (gid + kb * BLOCK_STRIDE_A + LINE_STRIDE_A * 2)).x;
|
| 98 |
+
regA.s3 = read_imageui(src0_q, (gid + kb * BLOCK_STRIDE_A + LINE_STRIDE_A * 3)).x;
|
| 99 |
+
|
| 100 |
+
float scale = (float)regS;
|
| 101 |
+
dequantizeBlockAccum_q1(totalSum, regA.s0, scale, regB, 0);
|
| 102 |
+
dequantizeBlockAccum_q1(totalSum, regA.s1, scale, regB, 4);
|
| 103 |
+
dequantizeBlockAccum_q1(totalSum, regA.s2, scale, regB, 8);
|
| 104 |
+
dequantizeBlockAccum_q1(totalSum, regA.s3, scale, regB, 12);
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
// reduction in local memory, assumes #wave = N_SIMDGROUP = 4
|
| 108 |
+
local float reduceLM[SIMDGROUP_WIDTH * 3];
|
| 109 |
+
if (groupId == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = totalSum;
|
| 110 |
+
if (groupId == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = totalSum;
|
| 111 |
+
if (groupId == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = totalSum;
|
| 112 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 113 |
+
if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 114 |
+
if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 115 |
+
if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 116 |
+
|
| 117 |
+
if (groupId == 0) {
|
| 118 |
+
dst = (global float*)((global char*)dst + offsetd);
|
| 119 |
+
dst[gid] = totalSum;
|
| 120 |
+
}
|
| 121 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32.cl
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
// assume
|
| 11 |
+
#define QK4_0 32
|
| 12 |
+
#define N_SIMDGROUP 4
|
| 13 |
+
|
| 14 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_1_hi(total_sums, bits4, scale, y) \
|
| 15 |
+
float shared_y; \
|
| 16 |
+
shared_y = sub_group_broadcast(y.s0, 0); \
|
| 17 |
+
total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 18 |
+
total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 19 |
+
shared_y = sub_group_broadcast(y.s1, 0); \
|
| 20 |
+
total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 21 |
+
total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 22 |
+
shared_y = sub_group_broadcast(y.s2, 0); \
|
| 23 |
+
total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 24 |
+
total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 25 |
+
shared_y = sub_group_broadcast(y.s3, 0); \
|
| 26 |
+
total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 27 |
+
total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 28 |
+
shared_y = sub_group_broadcast(y.s4, 0); \
|
| 29 |
+
total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 30 |
+
total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 31 |
+
shared_y = sub_group_broadcast(y.s5, 0); \
|
| 32 |
+
total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 33 |
+
total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 34 |
+
shared_y = sub_group_broadcast(y.s6, 0); \
|
| 35 |
+
total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 36 |
+
total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 37 |
+
shared_y = sub_group_broadcast(y.s7, 0); \
|
| 38 |
+
total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 39 |
+
total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 40 |
+
shared_y = sub_group_broadcast(y.s0, 1); \
|
| 41 |
+
total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 42 |
+
total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 43 |
+
shared_y = sub_group_broadcast(y.s1, 1); \
|
| 44 |
+
total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 45 |
+
total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 46 |
+
shared_y = sub_group_broadcast(y.s2, 1); \
|
| 47 |
+
total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 48 |
+
total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 49 |
+
shared_y = sub_group_broadcast(y.s3, 1); \
|
| 50 |
+
total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 51 |
+
total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 52 |
+
shared_y = sub_group_broadcast(y.s4, 1); \
|
| 53 |
+
total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 54 |
+
total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 55 |
+
shared_y = sub_group_broadcast(y.s5, 1); \
|
| 56 |
+
total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 57 |
+
total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 58 |
+
shared_y = sub_group_broadcast(y.s6, 1); \
|
| 59 |
+
total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 60 |
+
total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 61 |
+
shared_y = sub_group_broadcast(y.s7, 1); \
|
| 62 |
+
total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 63 |
+
total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_1_lo(total_sums, bits4, scale, y) \
|
| 67 |
+
shared_y = sub_group_broadcast(y.s0, 2); \
|
| 68 |
+
total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 69 |
+
total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 70 |
+
shared_y = sub_group_broadcast(y.s1, 2); \
|
| 71 |
+
total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 72 |
+
total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 73 |
+
shared_y = sub_group_broadcast(y.s2, 2); \
|
| 74 |
+
total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 75 |
+
total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 76 |
+
shared_y = sub_group_broadcast(y.s3, 2); \
|
| 77 |
+
total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 78 |
+
total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 79 |
+
shared_y = sub_group_broadcast(y.s4, 2); \
|
| 80 |
+
total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 81 |
+
total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 82 |
+
shared_y = sub_group_broadcast(y.s5, 2); \
|
| 83 |
+
total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 84 |
+
total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 85 |
+
shared_y = sub_group_broadcast(y.s6, 2); \
|
| 86 |
+
total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 87 |
+
total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 88 |
+
shared_y = sub_group_broadcast(y.s7, 2); \
|
| 89 |
+
total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 90 |
+
total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 91 |
+
shared_y = sub_group_broadcast(y.s0, 3); \
|
| 92 |
+
total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 93 |
+
total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 94 |
+
shared_y = sub_group_broadcast(y.s1, 3); \
|
| 95 |
+
total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 96 |
+
total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 97 |
+
shared_y = sub_group_broadcast(y.s2, 3); \
|
| 98 |
+
total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 99 |
+
total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 100 |
+
shared_y = sub_group_broadcast(y.s3, 3); \
|
| 101 |
+
total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 102 |
+
total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 103 |
+
shared_y = sub_group_broadcast(y.s4, 3); \
|
| 104 |
+
total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 105 |
+
total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 106 |
+
shared_y = sub_group_broadcast(y.s5, 3); \
|
| 107 |
+
total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 108 |
+
total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 109 |
+
shared_y = sub_group_broadcast(y.s6, 3); \
|
| 110 |
+
total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 111 |
+
total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 112 |
+
shared_y = sub_group_broadcast(y.s7, 3); \
|
| 113 |
+
total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 114 |
+
total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_8_hi(total_sums, bits4, scale, y) \
|
| 118 |
+
float8 shared_y; \
|
| 119 |
+
shared_y = sub_group_broadcast(y, 0); \
|
| 120 |
+
total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
|
| 121 |
+
total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
|
| 122 |
+
total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
|
| 123 |
+
total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
|
| 124 |
+
total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
|
| 125 |
+
total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
|
| 126 |
+
total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
|
| 127 |
+
total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
|
| 128 |
+
total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
|
| 129 |
+
total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
|
| 130 |
+
total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
|
| 131 |
+
total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
|
| 132 |
+
total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
|
| 133 |
+
total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
|
| 134 |
+
total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
|
| 135 |
+
total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
|
| 136 |
+
shared_y = sub_group_broadcast(y, 1); \
|
| 137 |
+
total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
|
| 138 |
+
total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
|
| 139 |
+
total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
|
| 140 |
+
total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
|
| 141 |
+
total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
|
| 142 |
+
total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
|
| 143 |
+
total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
|
| 144 |
+
total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
|
| 145 |
+
total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
|
| 146 |
+
total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
|
| 147 |
+
total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
|
| 148 |
+
total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
|
| 149 |
+
total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
|
| 150 |
+
total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
|
| 151 |
+
total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
|
| 152 |
+
total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_8_lo(total_sums, bits4, scale, y) \
|
| 156 |
+
shared_y = sub_group_broadcast(y, 2); \
|
| 157 |
+
total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
|
| 158 |
+
total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
|
| 159 |
+
total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
|
| 160 |
+
total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
|
| 161 |
+
total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
|
| 162 |
+
total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
|
| 163 |
+
total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
|
| 164 |
+
total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
|
| 165 |
+
total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
|
| 166 |
+
total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
|
| 167 |
+
total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
|
| 168 |
+
total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
|
| 169 |
+
total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
|
| 170 |
+
total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
|
| 171 |
+
total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
|
| 172 |
+
total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
|
| 173 |
+
shared_y = sub_group_broadcast(y, 3); \
|
| 174 |
+
total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
|
| 175 |
+
total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
|
| 176 |
+
total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
|
| 177 |
+
total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
|
| 178 |
+
total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
|
| 179 |
+
total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
|
| 180 |
+
total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
|
| 181 |
+
total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
|
| 182 |
+
total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
|
| 183 |
+
total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
|
| 184 |
+
total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
|
| 185 |
+
total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
|
| 186 |
+
total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
|
| 187 |
+
total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
|
| 188 |
+
total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
|
| 189 |
+
total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
|
| 190 |
+
|
| 191 |
+
#ifdef ADRENO_GPU
|
| 192 |
+
REQD_SUBGROUP_SIZE_64
|
| 193 |
+
#endif
|
| 194 |
+
__kernel void kernel_gemv_noshuffle_q4_0_f32(
|
| 195 |
+
__read_only image1d_buffer_t src0_q, // quantized A
|
| 196 |
+
global half2 * src0_d, // A scales
|
| 197 |
+
__read_only image1d_buffer_t src1, // B
|
| 198 |
+
ulong offset1, // offset to B (0)
|
| 199 |
+
global float * dst, // C
|
| 200 |
+
ulong offsetd, // offset to C (0)
|
| 201 |
+
int ne00, // K
|
| 202 |
+
int ne01, // M
|
| 203 |
+
int ne02, // 1
|
| 204 |
+
int ne10, // K
|
| 205 |
+
int ne12, // 1
|
| 206 |
+
int ne0, // M
|
| 207 |
+
int ne1, // N
|
| 208 |
+
int r2, // 1
|
| 209 |
+
int r3)
|
| 210 |
+
{
|
| 211 |
+
uint groupId = get_local_id(1);
|
| 212 |
+
uint gid = get_global_id(0);
|
| 213 |
+
ushort slid = get_sub_group_local_id();
|
| 214 |
+
|
| 215 |
+
uint K = ne00;
|
| 216 |
+
uint M = ne01;
|
| 217 |
+
|
| 218 |
+
uint LINE_STRIDE_A = M / 2;
|
| 219 |
+
uint BLOCK_STRIDE_A = N_SIMDGROUP * M;
|
| 220 |
+
|
| 221 |
+
__private uint4 regA;
|
| 222 |
+
__private half2 regS;
|
| 223 |
+
__private float8 regB;
|
| 224 |
+
|
| 225 |
+
__private float2 totalSum = (float2)(0.0f);
|
| 226 |
+
|
| 227 |
+
// loop along K in block granularity, skip 4 blocks every iter
|
| 228 |
+
for (uint k = groupId; k < (K / QK4_0); k += N_SIMDGROUP) {
|
| 229 |
+
regS = src0_d[gid + k * LINE_STRIDE_A]; // each fiber loads scale of two rows
|
| 230 |
+
// first 4 fibers in each wave load 8 B values to its private scope
|
| 231 |
+
if (slid < 4) {
|
| 232 |
+
regB.s0123 = read_imagef(src1, (slid * 2 + k * 8));
|
| 233 |
+
regB.s4567 = read_imagef(src1, (1 + slid * 2 + k * 8));
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
// load half weights for two blocks in consecutive rows
|
| 237 |
+
regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 0)).x;
|
| 238 |
+
regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 1)).x;
|
| 239 |
+
regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 2)).x;
|
| 240 |
+
regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 3)).x;
|
| 241 |
+
#ifdef VECTOR_SUB_GROUP_BROADCAST
|
| 242 |
+
dequantizeBlockAccum_ns_sgbroadcast_8_hi(totalSum, as_ushort8(regA), regS, regB);
|
| 243 |
+
#else
|
| 244 |
+
dequantizeBlockAccum_ns_sgbroadcast_1_hi(totalSum, as_ushort8(regA), regS, regB);
|
| 245 |
+
#endif // VECTOR_SUB_GROUP_BROADCAST
|
| 246 |
+
|
| 247 |
+
regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 4)).x;
|
| 248 |
+
regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 5)).x;
|
| 249 |
+
regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 6)).x;
|
| 250 |
+
regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 7)).x;
|
| 251 |
+
#ifdef VECTOR_SUB_GROUP_BROADCAST
|
| 252 |
+
dequantizeBlockAccum_ns_sgbroadcast_8_lo(totalSum, as_ushort8(regA), regS, regB);
|
| 253 |
+
#else
|
| 254 |
+
dequantizeBlockAccum_ns_sgbroadcast_1_lo(totalSum, as_ushort8(regA), regS, regB);
|
| 255 |
+
#endif // VECTOR_SUB_GROUP_BROADCAST
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
// reduction in local memory, assumes #wave=4
|
| 259 |
+
__local float2 reduceLM[SIMDGROUP_WIDTH * 3];
|
| 260 |
+
if (groupId == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = totalSum;
|
| 261 |
+
if (groupId == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = totalSum;
|
| 262 |
+
if (groupId == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = totalSum;
|
| 263 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 264 |
+
if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 265 |
+
if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 266 |
+
if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 267 |
+
|
| 268 |
+
// 2 outputs per fiber in wave 0
|
| 269 |
+
if (groupId == 0) {
|
| 270 |
+
dst = (global float*)((global char*)dst + offsetd);
|
| 271 |
+
vstore2(totalSum, 0, &(dst[gid * 2]));
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
}
|
backend/llama.cpp/ggml/src/ggml-opencl/kernels/gemv_noshuffle_q4_0_f32_spec.cl
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
| 2 |
+
#pragma OPENCL EXTENSION cl_khr_subgroups : enable
|
| 3 |
+
|
| 4 |
+
#ifdef cl_qcom_reqd_sub_group_size
|
| 5 |
+
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
|
| 6 |
+
#define ADRENO_GPU 1
|
| 7 |
+
#define REQD_SUBGROUP_SIZE_64 __attribute__((qcom_reqd_sub_group_size("half")))
|
| 8 |
+
#endif
|
| 9 |
+
|
| 10 |
+
// assume
|
| 11 |
+
#define QK4_0 32
|
| 12 |
+
#define N_SIMDGROUP 4
|
| 13 |
+
|
| 14 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_1_hi(total_sums, bits4, scale, y) \
|
| 15 |
+
float shared_y; \
|
| 16 |
+
shared_y = sub_group_broadcast(y.s0, 0); \
|
| 17 |
+
total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 18 |
+
total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 19 |
+
shared_y = sub_group_broadcast(y.s1, 0); \
|
| 20 |
+
total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 21 |
+
total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 22 |
+
shared_y = sub_group_broadcast(y.s2, 0); \
|
| 23 |
+
total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 24 |
+
total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 25 |
+
shared_y = sub_group_broadcast(y.s3, 0); \
|
| 26 |
+
total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 27 |
+
total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 28 |
+
shared_y = sub_group_broadcast(y.s4, 0); \
|
| 29 |
+
total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 30 |
+
total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 31 |
+
shared_y = sub_group_broadcast(y.s5, 0); \
|
| 32 |
+
total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 33 |
+
total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 34 |
+
shared_y = sub_group_broadcast(y.s6, 0); \
|
| 35 |
+
total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 36 |
+
total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 37 |
+
shared_y = sub_group_broadcast(y.s7, 0); \
|
| 38 |
+
total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 39 |
+
total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 40 |
+
shared_y = sub_group_broadcast(y.s0, 1); \
|
| 41 |
+
total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 42 |
+
total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 43 |
+
shared_y = sub_group_broadcast(y.s1, 1); \
|
| 44 |
+
total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 45 |
+
total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 46 |
+
shared_y = sub_group_broadcast(y.s2, 1); \
|
| 47 |
+
total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 48 |
+
total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 49 |
+
shared_y = sub_group_broadcast(y.s3, 1); \
|
| 50 |
+
total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 51 |
+
total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 52 |
+
shared_y = sub_group_broadcast(y.s4, 1); \
|
| 53 |
+
total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 54 |
+
total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 55 |
+
shared_y = sub_group_broadcast(y.s5, 1); \
|
| 56 |
+
total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 57 |
+
total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 58 |
+
shared_y = sub_group_broadcast(y.s6, 1); \
|
| 59 |
+
total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 60 |
+
total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 61 |
+
shared_y = sub_group_broadcast(y.s7, 1); \
|
| 62 |
+
total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 63 |
+
total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_1_lo(total_sums, bits4, scale, y) \
|
| 67 |
+
shared_y = sub_group_broadcast(y.s0, 2); \
|
| 68 |
+
total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 69 |
+
total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 70 |
+
shared_y = sub_group_broadcast(y.s1, 2); \
|
| 71 |
+
total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 72 |
+
total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 73 |
+
shared_y = sub_group_broadcast(y.s2, 2); \
|
| 74 |
+
total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 75 |
+
total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 76 |
+
shared_y = sub_group_broadcast(y.s3, 2); \
|
| 77 |
+
total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 78 |
+
total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 79 |
+
shared_y = sub_group_broadcast(y.s4, 2); \
|
| 80 |
+
total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 81 |
+
total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 82 |
+
shared_y = sub_group_broadcast(y.s5, 2); \
|
| 83 |
+
total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 84 |
+
total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 85 |
+
shared_y = sub_group_broadcast(y.s6, 2); \
|
| 86 |
+
total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 87 |
+
total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 88 |
+
shared_y = sub_group_broadcast(y.s7, 2); \
|
| 89 |
+
total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 90 |
+
total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 91 |
+
shared_y = sub_group_broadcast(y.s0, 3); \
|
| 92 |
+
total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 93 |
+
total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 94 |
+
shared_y = sub_group_broadcast(y.s1, 3); \
|
| 95 |
+
total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 96 |
+
total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 97 |
+
shared_y = sub_group_broadcast(y.s2, 3); \
|
| 98 |
+
total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 99 |
+
total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 100 |
+
shared_y = sub_group_broadcast(y.s3, 3); \
|
| 101 |
+
total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 102 |
+
total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 103 |
+
shared_y = sub_group_broadcast(y.s4, 3); \
|
| 104 |
+
total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y; \
|
| 105 |
+
total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y; \
|
| 106 |
+
shared_y = sub_group_broadcast(y.s5, 3); \
|
| 107 |
+
total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y; \
|
| 108 |
+
total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y; \
|
| 109 |
+
shared_y = sub_group_broadcast(y.s6, 3); \
|
| 110 |
+
total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y; \
|
| 111 |
+
total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y; \
|
| 112 |
+
shared_y = sub_group_broadcast(y.s7, 3); \
|
| 113 |
+
total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y; \
|
| 114 |
+
total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y; \
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_8_hi(total_sums, bits4, scale, y) \
|
| 118 |
+
float8 shared_y; \
|
| 119 |
+
shared_y = sub_group_broadcast(y, 0); \
|
| 120 |
+
total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
|
| 121 |
+
total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
|
| 122 |
+
total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
|
| 123 |
+
total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
|
| 124 |
+
total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
|
| 125 |
+
total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
|
| 126 |
+
total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
|
| 127 |
+
total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
|
| 128 |
+
total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
|
| 129 |
+
total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
|
| 130 |
+
total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
|
| 131 |
+
total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
|
| 132 |
+
total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
|
| 133 |
+
total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
|
| 134 |
+
total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
|
| 135 |
+
total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
|
| 136 |
+
shared_y = sub_group_broadcast(y, 1); \
|
| 137 |
+
total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
|
| 138 |
+
total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
|
| 139 |
+
total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
|
| 140 |
+
total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
|
| 141 |
+
total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
|
| 142 |
+
total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
|
| 143 |
+
total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
|
| 144 |
+
total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
|
| 145 |
+
total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
|
| 146 |
+
total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
|
| 147 |
+
total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
|
| 148 |
+
total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
|
| 149 |
+
total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
|
| 150 |
+
total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
|
| 151 |
+
total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
|
| 152 |
+
total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
#define dequantizeBlockAccum_ns_sgbroadcast_8_lo(total_sums, bits4, scale, y) \
|
| 156 |
+
shared_y = sub_group_broadcast(y, 2); \
|
| 157 |
+
total_sums.s0 += ((bits4.s0 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
|
| 158 |
+
total_sums.s0 += (((bits4.s0 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
|
| 159 |
+
total_sums.s0 += (((bits4.s0 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
|
| 160 |
+
total_sums.s0 += (((bits4.s0 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
|
| 161 |
+
total_sums.s0 += ((bits4.s2 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
|
| 162 |
+
total_sums.s0 += (((bits4.s2 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
|
| 163 |
+
total_sums.s0 += (((bits4.s2 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
|
| 164 |
+
total_sums.s0 += (((bits4.s2 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
|
| 165 |
+
total_sums.s1 += ((bits4.s1 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
|
| 166 |
+
total_sums.s1 += (((bits4.s1 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
|
| 167 |
+
total_sums.s1 += (((bits4.s1 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
|
| 168 |
+
total_sums.s1 += (((bits4.s1 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
|
| 169 |
+
total_sums.s1 += ((bits4.s3 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
|
| 170 |
+
total_sums.s1 += (((bits4.s3 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
|
| 171 |
+
total_sums.s1 += (((bits4.s3 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
|
| 172 |
+
total_sums.s1 += (((bits4.s3 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
|
| 173 |
+
shared_y = sub_group_broadcast(y, 3); \
|
| 174 |
+
total_sums.s0 += ((bits4.s4 & 0x000F) - 8) * scale.s0 * shared_y.s0; \
|
| 175 |
+
total_sums.s0 += (((bits4.s4 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s1; \
|
| 176 |
+
total_sums.s0 += (((bits4.s4 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s2; \
|
| 177 |
+
total_sums.s0 += (((bits4.s4 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s3; \
|
| 178 |
+
total_sums.s0 += ((bits4.s6 & 0x000F) - 8) * scale.s0 * shared_y.s4; \
|
| 179 |
+
total_sums.s0 += (((bits4.s6 & 0x00F0) >> 4) - 8) * scale.s0 * shared_y.s5; \
|
| 180 |
+
total_sums.s0 += (((bits4.s6 & 0x0F00) >> 8) - 8) * scale.s0 * shared_y.s6; \
|
| 181 |
+
total_sums.s0 += (((bits4.s6 & 0xF000) >> 12) - 8) * scale.s0 * shared_y.s7; \
|
| 182 |
+
total_sums.s1 += ((bits4.s5 & 0x000F) - 8) * scale.s1 * shared_y.s0; \
|
| 183 |
+
total_sums.s1 += (((bits4.s5 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s1; \
|
| 184 |
+
total_sums.s1 += (((bits4.s5 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s2; \
|
| 185 |
+
total_sums.s1 += (((bits4.s5 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s3; \
|
| 186 |
+
total_sums.s1 += ((bits4.s7 & 0x000F) - 8) * scale.s1 * shared_y.s4; \
|
| 187 |
+
total_sums.s1 += (((bits4.s7 & 0x00F0) >> 4) - 8) * scale.s1 * shared_y.s5; \
|
| 188 |
+
total_sums.s1 += (((bits4.s7 & 0x0F00) >> 8) - 8) * scale.s1 * shared_y.s6; \
|
| 189 |
+
total_sums.s1 += (((bits4.s7 & 0xF000) >> 12) - 8) * scale.s1 * shared_y.s7; \
|
| 190 |
+
|
| 191 |
+
#ifdef ADRENO_GPU
|
| 192 |
+
REQD_SUBGROUP_SIZE_64
|
| 193 |
+
#endif
|
| 194 |
+
__kernel void kernel_gemv_noshuffle_q4_0_f32(
|
| 195 |
+
__read_only image1d_buffer_t src0_q, // quantized A
|
| 196 |
+
global half2 * src0_d, // A scales
|
| 197 |
+
__read_only image1d_buffer_t src1, // B
|
| 198 |
+
ulong offset1, // offset to B (0)
|
| 199 |
+
global float * dst, // C
|
| 200 |
+
ulong offsetd, // offset to C (0)
|
| 201 |
+
uint K, // K
|
| 202 |
+
int ne01, // M
|
| 203 |
+
int ne02, // 1
|
| 204 |
+
int ne10, // K
|
| 205 |
+
int ne12, // 1
|
| 206 |
+
int ne0, // M
|
| 207 |
+
int ne1, // N
|
| 208 |
+
int r2, // 1
|
| 209 |
+
int r3)
|
| 210 |
+
{
|
| 211 |
+
uint groupId = get_local_id(1);
|
| 212 |
+
uint gid = get_global_id(0);
|
| 213 |
+
ushort slid = get_sub_group_local_id();
|
| 214 |
+
|
| 215 |
+
__private uint4 regA;
|
| 216 |
+
__private half2 regS;
|
| 217 |
+
__private float8 regB;
|
| 218 |
+
|
| 219 |
+
__private float2 totalSum = (float2)(0.0f);
|
| 220 |
+
|
| 221 |
+
// loop along K in block granularity, skip 4 blocks every iter
|
| 222 |
+
for (uint k = groupId; k < (K / QK4_0); k += N_SIMDGROUP) {
|
| 223 |
+
regS = src0_d[gid + k * LINE_STRIDE_A]; // each fiber loads scale of two rows
|
| 224 |
+
// first 4 fibers in each wave load 8 B values to its private scope
|
| 225 |
+
if (slid < 4) {
|
| 226 |
+
regB.s0123 = read_imagef(src1, (slid * 2 + k * 8));
|
| 227 |
+
regB.s4567 = read_imagef(src1, (1 + slid * 2 + k * 8));
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
// load half weights for two blocks in consecutive rows
|
| 231 |
+
regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 0)).x;
|
| 232 |
+
regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 1)).x;
|
| 233 |
+
regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 2)).x;
|
| 234 |
+
regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 3)).x;
|
| 235 |
+
#ifdef VECTOR_SUB_GROUP_BROADCAST
|
| 236 |
+
dequantizeBlockAccum_ns_sgbroadcast_8_hi(totalSum, as_ushort8(regA), regS, regB);
|
| 237 |
+
#else
|
| 238 |
+
dequantizeBlockAccum_ns_sgbroadcast_1_hi(totalSum, as_ushort8(regA), regS, regB);
|
| 239 |
+
#endif // VECTOR_SUB_GROUP_BROADCAST
|
| 240 |
+
|
| 241 |
+
regA.s0 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 4)).x;
|
| 242 |
+
regA.s1 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 5)).x;
|
| 243 |
+
regA.s2 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 6)).x;
|
| 244 |
+
regA.s3 = read_imageui(src0_q, (gid + k * BLOCK_STRIDE_A + LINE_STRIDE_A * 7)).x;
|
| 245 |
+
#ifdef VECTOR_SUB_GROUP_BROADCAST
|
| 246 |
+
dequantizeBlockAccum_ns_sgbroadcast_8_lo(totalSum, as_ushort8(regA), regS, regB);
|
| 247 |
+
#else
|
| 248 |
+
dequantizeBlockAccum_ns_sgbroadcast_1_lo(totalSum, as_ushort8(regA), regS, regB);
|
| 249 |
+
#endif // VECTOR_SUB_GROUP_BROADCAST
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
// reduction in local memory, assumes #wave=4
|
| 253 |
+
__local float2 reduceLM[SIMDGROUP_WIDTH * 3];
|
| 254 |
+
if (groupId == 1) reduceLM[SIMDGROUP_WIDTH * 0 + slid] = totalSum;
|
| 255 |
+
if (groupId == 2) reduceLM[SIMDGROUP_WIDTH * 1 + slid] = totalSum;
|
| 256 |
+
if (groupId == 3) reduceLM[SIMDGROUP_WIDTH * 2 + slid] = totalSum;
|
| 257 |
+
barrier(CLK_LOCAL_MEM_FENCE);
|
| 258 |
+
if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 0 + slid];
|
| 259 |
+
if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 1 + slid];
|
| 260 |
+
if (groupId == 0) totalSum += reduceLM[SIMDGROUP_WIDTH * 2 + slid];
|
| 261 |
+
|
| 262 |
+
// 2 outputs per fiber in wave 0
|
| 263 |
+
if (groupId == 0) {
|
| 264 |
+
dst = (global float*)((global char*)dst + offsetd);
|
| 265 |
+
vstore2(totalSum, 0, &(dst[gid * 2]));
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
}
|