Skip to content

Commit b75db30

Browse files
committed
[SYCL] Fix Q8_0 reorder: add missing dequantize path for GEMM
The Q8_0 reorder optimization (ggml-org#21527) was missing a reorder-aware dequantizer for the GEMM code path used during prompt processing. After token generation reordered Q8_0 weights (via DMMV/MMVQ), the next prompt processing pass would read them with the standard dequantizer, producing garbage output. Add dequantize_block_q8_0_reorder() and wire it into both ggml_get_to_fp16_sycl() and ggml_get_to_fp32_sycl(), matching the pattern already used by Q4_0, Q4_K, and Q6_K. Fixes ggml-org#21589 AI (Claude) was used to assist with root cause investigation and writing the kernel code. All code was human-reviewed and tested on real hardware.
1 parent 6606000 commit b75db30

2 files changed

Lines changed: 59 additions & 2 deletions

File tree

ggml/src/ggml-sycl/convert.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,25 @@ static void dequantize_row_q4_0_sycl_reorder(const void *vx, dst_t *y, const int
151151

152152
}
153153

154+
template <typename dst_t>
155+
static void dequantize_row_q8_0_sycl_reorder(const void *vx, dst_t *y, const int64_t k,
156+
dpct::queue_ptr stream) {
157+
158+
dpct::has_capability_or_fail(stream->get_device(),
159+
{sycl::aspect::fp16});
160+
161+
int constexpr WARP_K = WARP_SIZE * QK8_0;
162+
const int n_warp = (k + WARP_K - 1) / WARP_K;
163+
GGML_ASSERT(k % QK8_0 == 0);
164+
stream->parallel_for(sycl::nd_range<3>(sycl::range<3>(1, 1, n_warp) *
165+
sycl::range<3>(1, 1, WARP_SIZE),
166+
sycl::range<3>(1, 1, WARP_SIZE)),
167+
[=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]]{
168+
dequantize_block_q8_0_reorder(vx, y, k, item_ct1);
169+
});
170+
171+
}
172+
154173
template <typename dst_t>
155174
static void dequantize_row_q4_1_sycl(const void *vx, dst_t *y, const int64_t k,
156175
dpct::queue_ptr stream) {
@@ -614,7 +633,12 @@ to_fp16_sycl_t ggml_get_to_fp16_sycl(ggml_type type, ggml_tensor * dst) {
614633
case GGML_TYPE_Q5_1:
615634
return dequantize_block_sycl<QK5_1, QR5_1, dequantize_q5_1>;
616635
case GGML_TYPE_Q8_0:
617-
return dequantize_block_sycl<QK8_0, QR8_0, dequantize_q8_0>;
636+
if (dst->src[0]->extra &&
637+
((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
638+
return dequantize_row_q8_0_sycl_reorder;
639+
} else {
640+
return dequantize_block_sycl<QK8_0, QR8_0, dequantize_q8_0>;
641+
}
618642
case GGML_TYPE_Q2_K:
619643
return dequantize_row_q2_K_sycl;
620644
case GGML_TYPE_Q3_K:
@@ -683,7 +707,12 @@ to_fp32_sycl_t ggml_get_to_fp32_sycl(ggml_type type, ggml_tensor *dst) {
683707
case GGML_TYPE_Q5_1:
684708
return dequantize_block_sycl<QK5_1, QR5_1, dequantize_q5_1>;
685709
case GGML_TYPE_Q8_0:
686-
return dequantize_block_sycl<QK8_0, QR8_0, dequantize_q8_0>;
710+
if (dst->src[0]->extra &&
711+
((ggml_tensor_extra_gpu*)dst->src[0]->extra)->optimized_feature.reorder) {
712+
return dequantize_row_q8_0_sycl_reorder;
713+
} else {
714+
return dequantize_block_sycl<QK8_0, QR8_0, dequantize_q8_0>;
715+
}
687716
case GGML_TYPE_Q2_K:
688717
return dequantize_row_q2_K_sycl;
689718
case GGML_TYPE_Q3_K:

ggml/src/ggml-sycl/dequantize.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,34 @@ static void dequantize_block_q4_0_reorder(const void * __restrict__ vx, dst_t *
238238

239239
}
240240

241+
// Dequantize Q8_0 from reorder layout: [all qs (k bytes)][all d values]
242+
// Each thread handles one block of QK8_0 elements.
243+
template<typename dst_t>
244+
static void dequantize_block_q8_0_reorder(const void * __restrict__ vx, dst_t * __restrict__ yy, int64_t k,
245+
const sycl::nd_item<3> &item_ct1) {
246+
247+
const int64_t i = item_ct1.get_group(2);
248+
const int64_t tid = item_ct1.get_local_id(2);
249+
const int lane_ib = i * WARP_SIZE + tid;
250+
251+
if (lane_ib >= k / QK8_0) {
252+
return;
253+
}
254+
255+
dst_t * y_ptr = yy + lane_ib * QK8_0;
256+
257+
auto qs = (const int8_t*)vx + lane_ib * QK8_0;
258+
auto s_ptr = (const sycl::half*)((const uint8_t*)vx + k) + lane_ib;
259+
260+
const float d = float(*s_ptr);
261+
262+
#pragma unroll
263+
for (int l = 0; l < QK8_0; ++l) {
264+
y_ptr[l] = d * qs[l];
265+
}
266+
267+
}
268+
241269
template<typename dst_t>
242270
static void dequantize_block_q4_1(const void * __restrict__ vx, dst_t * __restrict__ yy, int64_t nb32,
243271
const sycl::nd_item<3> &item_ct1) {

0 commit comments

Comments
 (0)