#include "set_rows.hpp" #include "cpy.hpp" #include "ggml-quants.h" #include namespace utils { template static constexpr bool is_arithmetic_v() { return std::is_arithmetic_v || std::is_same_v #ifdef GGML_SYCL_HAS_BF16 || std::is_same_v #endif ; } } template static inline std::enable_if_t() && utils::is_arithmetic_v(), void> convert (const char* src, char* dst) { auto src_val = *reinterpret_cast(src); auto dst_val = sycl::vec(src_val).template convert()[0]; *reinterpret_cast(dst) = dst_val; } #ifdef GGML_SYCL_HAS_BF16 // sycl::vec::convert does not provide a half -> bfloat16 path, so route through float. template<> inline void convert(const char* src, char* dst) { const float tmp = sycl::vec(*reinterpret_cast(src)) .template convert()[0]; *reinterpret_cast(dst) = sycl::ext::oneapi::bfloat16(tmp); } #endif template static void set_rows_sycl_q(const char * __restrict__ src0_d, const TIdx * __restrict__ src1_d, blockType * __restrict__ dst_d, // tensor dimensions src0 and src1 const int64_t ne00, const int64_t ne01, const int64_t ne02, const int64_t ne03, const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t ne13, // strides for src0 const size_t nb00, const size_t nb01, const size_t nb02, const size_t nb03, // strides for src1 const size_t nb10, const size_t nb11, const size_t nb12, const size_t nb13, // strides for dst const size_t nb1, const size_t nb2, const size_t nb3, queue_ptr stream) { const int64_t total_blocks = (ne00 * ne01 * ne02 * ne03) / qk; constexpr int block_size = 256; const int64_t grid_size = ceil_div(total_blocks, block_size); stream->parallel_for(sycl::nd_range<1>(grid_size * block_size, block_size), [=](sycl::nd_item<1> item_ct1) { const int64_t i = item_ct1.get_global_linear_id(); if (i >= total_blocks) { return; } const int64_t i_base = i * qk; const int64_t i03 = i_base / (ne00 * ne01 * ne02); const int64_t rem1 = i_base - i03 * (ne00 * ne01 * ne02); const int64_t i02 = rem1 / (ne00 * ne01); const int64_t rem2 = rem1 - i02 * ne00 * ne01; const int64_t i01 = rem2 / ne00; const int64_t i00 = rem2 - i01 * ne00; const int64_t i12 = i03 % ne12; const int64_t i11 = i02 % ne11; const int64_t i10 = i01; const size_t src_offset = calculate_offset<3>({ nb01, nb02, nb03 }, { i01, i02, i03 }); const char * src_block = src0_d + src_offset + i00 * sizeof(TIn); const size_t src1_offset = calculate_offset<3>({ nb10, nb11, nb12 }, { i10, i11, i12 }); const int64_t dst_row = src1_d[src1_offset / sizeof(TIdx)]; const size_t dst_offset = calculate_offset<3>({ nb1, nb2, nb3 }, { dst_row, i02, i03 }) + (i00 / qk) * sizeof(blockType); char * dst_block = reinterpret_cast(reinterpret_cast(dst_d) + dst_offset); if constexpr (std::is_same_v) { cpyblck(src_block, dst_block); } else { float src_block_f32[qk]; const TIn * src_block_t = reinterpret_cast(src_block); for (int j = 0; j < qk; ++j) { src_block_f32[j] = (float) src_block_t[j]; } cpyblck(reinterpret_cast(src_block_f32), dst_block); } }); GGML_UNUSED(ne10); GGML_UNUSED(ne13); GGML_UNUSED(nb00); GGML_UNUSED(nb13); } template using quantize_row_qk_t = void (*)(const float *, blockType *, int64_t); using quantize_rows_f_t = size_t (*)(const float *, void *, int64_t, int64_t, const float *); template quantize_row> static void set_rows_sycl_qk_host( const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const int64_t ne00, const int64_t ne01, const int64_t ne02, const int64_t ne03, const int64_t ne11, const int64_t ne12, const size_t nb01, const size_t nb02, const size_t nb03, const size_t nb10, const size_t nb11, const size_t nb12, const size_t nb1, const size_t nb2, const size_t nb3, queue_ptr stream) { GGML_ASSERT(ne00 % qk == 0); const size_t src0_bytes = ggml_nbytes(src0); const size_t src1_bytes = ggml_nbytes(src1); std::vector src0_host(src0_bytes); std::vector src1_host(src1_bytes); stream->memcpy(src0_host.data(), src0->data, src0_bytes); stream->memcpy(src1_host.data(), src1->data, src1_bytes); stream->wait(); std::vector src_row_f32(ne00); const int64_t nblocks = ne00 / qk; std::vector dst_row_q(nblocks); for (int64_t i03 = 0; i03 < ne03; ++i03) { for (int64_t i02 = 0; i02 < ne02; ++i02) { for (int64_t i01 = 0; i01 < ne01; ++i01) { const int64_t i12 = i03 % ne12; const int64_t i11 = i02 % ne11; const int64_t i10 = i01; const size_t src1_offset = calculate_offset<3>({ nb10, nb11, nb12 }, { i10, i11, i12 }); const int64_t dst_row = *(const TIdx *) (src1_host.data() + src1_offset); const size_t src0_row_offset = calculate_offset<3>({ nb01, nb02, nb03 }, { i01, i02, i03 }); const TIn * src_row = reinterpret_cast(src0_host.data() + src0_row_offset); for (int64_t i00 = 0; i00 < ne00; ++i00) { src_row_f32[i00] = (float) src_row[i00]; } quantize_row(src_row_f32.data(), dst_row_q.data(), ne00); const size_t dst_offset = calculate_offset<3>({ nb1, nb2, nb3 }, { dst_row, i02, i03 }); stream->memcpy((char *) dst->data + dst_offset, dst_row_q.data(), nblocks * sizeof(blockType)); stream->wait(); } } } } template static void set_rows_sycl_iq_host( const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const int64_t ne00, const int64_t ne01, const int64_t ne02, const int64_t ne03, const int64_t ne11, const int64_t ne12, const size_t nb01, const size_t nb02, const size_t nb03, const size_t nb10, const size_t nb11, const size_t nb12, const size_t nb1, const size_t nb2, const size_t nb3, queue_ptr stream) { GGML_ASSERT(ne00 % qk == 0); const size_t src0_bytes = ggml_nbytes(src0); const size_t src1_bytes = ggml_nbytes(src1); std::vector src0_host(src0_bytes); std::vector src1_host(src1_bytes); stream->memcpy(src0_host.data(), src0->data, src0_bytes); stream->memcpy(src1_host.data(), src1->data, src1_bytes); stream->wait(); std::vector src_row_f32(ne00); const int64_t nblocks = ne00 / qk; std::vector dst_row_q(nblocks); for (int64_t i03 = 0; i03 < ne03; ++i03) { for (int64_t i02 = 0; i02 < ne02; ++i02) { for (int64_t i01 = 0; i01 < ne01; ++i01) { const int64_t i12 = i03 % ne12; const int64_t i11 = i02 % ne11; const int64_t i10 = i01; const size_t src1_offset = calculate_offset<3>({ nb10, nb11, nb12 }, { i10, i11, i12 }); const int64_t dst_row = *(const TIdx *) (src1_host.data() + src1_offset); const size_t src0_row_offset = calculate_offset<3>({ nb01, nb02, nb03 }, { i01, i02, i03 }); const TIn * src_row = reinterpret_cast(src0_host.data() + src0_row_offset); for (int64_t i00 = 0; i00 < ne00; ++i00) { src_row_f32[i00] = (float) src_row[i00]; } quantize_rows(src_row_f32.data(), dst_row_q.data(), 1, ne00, nullptr); const size_t dst_offset = calculate_offset<3>({ nb1, nb2, nb3 }, { dst_row, i02, i03 }); stream->memcpy((char *) dst->data + dst_offset, dst_row_q.data(), nblocks * sizeof(blockType)); stream->wait(); } } } } template static void k_set_rows( const char * __restrict__ src0, const TIdx * __restrict__ src1, char * __restrict__ dst, const int64_t ne00, const int64_t ne01, const int64_t ne02, const int64_t ne11, const int64_t ne12, const size_t nb01, const size_t nb02, const size_t nb03, const size_t nb10, const size_t nb11, const size_t nb12, const size_t nb1, const size_t nb2, const size_t nb3, const size_t src_type_size, const size_t dst_type_size, const int64_t total_elements, const sycl::nd_item<1> & item_ct1) { const int64_t i = item_ct1.get_global_linear_id(); if (i >= total_elements) { return; } const int64_t i03 = i / (ne00 * ne01 * ne02); const int64_t i02 = (i - i03 * ne00 * ne01 * ne02) / (ne00 * ne01); const int64_t i01 = (i - i03 * ne00 * ne01 * ne02 - i02 * ne00 * ne01) / ne00; const int64_t i00 = i - i03 * ne00 * ne01 * ne02 - i02 * ne00 * ne01 - i01 * ne00; const int64_t i12 = i03 % ne12; const int64_t i11 = i02 % ne11; const int64_t i10 = i01; const int64_t dst_row = *(const TIdx *)((const char *)src1 + calculate_offset<3>({nb10, nb11, nb12}, {i10, i11, i12})); const char * src0_row = src0 + calculate_offset<3>({nb01, nb02, nb03}, {i01, i02, i03}); const char * src_elem = src0_row + i00 * src_type_size; char * dst_row_ptr = dst + dst_row*nb1 + i02*nb2 + i03*nb3; char * dst_elem = dst_row_ptr + i00 * dst_type_size; convert(src_elem, dst_elem); } template static void set_rows_sycl( const char * src0_d, const TIdx * src1_d, char * dst_d, const int64_t ne00, const int64_t ne01, const int64_t ne02, const int64_t ne03, const int64_t ne11, const int64_t ne12, const size_t nb01, const size_t nb02, const size_t nb03, const size_t nb10, const size_t nb11, const size_t nb12, const size_t nb1, const size_t nb2, const size_t nb3, const size_t src_type_size, const size_t dst_type_size, queue_ptr stream) { const int64_t total_elements = ne00 * ne01 * ne02 * ne03; constexpr int block_size = 64; const int64_t grid_size = ceil_div(total_elements, block_size); stream->parallel_for( sycl::nd_range<1>(grid_size * block_size, block_size), [=](sycl::nd_item<1> item_ct1) [[intel::reqd_sub_group_size(WARP_SIZE)]] { k_set_rows( src0_d, src1_d, dst_d, ne00, ne01, ne02, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, src_type_size, dst_type_size, total_elements, item_ct1 ); } ); } template static void set_rows_sycl(ggml_backend_sycl_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) { const char * src0_d = (const char *)src0->data; const TIdx * src1_d = (const TIdx *)src1->data; GGML_TENSOR_BINARY_OP_LOCALS dpct::queue_ptr stream = ctx.stream(); switch (dst->type) { case GGML_TYPE_F32: set_rows_sycl( src0_d, src1_d, (char *)dst->data, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, sizeof(TIn), sizeof(float), stream ); break; case GGML_TYPE_F16: dpct::has_capability_or_fail(stream->get_device(), { sycl::aspect::fp16 }); set_rows_sycl( src0_d, src1_d, (char *)dst->data, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, sizeof(TIn), sizeof(sycl::half), stream ); break; #ifdef GGML_SYCL_HAS_BF16 case GGML_TYPE_BF16: set_rows_sycl( src0_d, src1_d, (char *)dst->data, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, sizeof(TIn), sizeof(sycl::ext::oneapi::bfloat16), stream ); break; #endif case GGML_TYPE_Q8_0: set_rows_sycl_q( src0_d, src1_d, (block_q8_0 *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q1_0: set_rows_sycl_q( src0_d, src1_d, (block_q1_0 *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q2_0: set_rows_sycl_q( src0_d, src1_d, (block_q2_0 *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q5_1: set_rows_sycl_q( src0_d, src1_d, (block_q5_1 *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q5_0: set_rows_sycl_q( src0_d, src1_d, (block_q5_0 *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q4_1: set_rows_sycl_q( src0_d, src1_d, (block_q4_1 *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q4_0: set_rows_sycl_q( src0_d, src1_d, (block_q4_0 *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_IQ4_NL: set_rows_sycl_q( src0_d, src1_d, (block_iq4_nl *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_MXFP4: set_rows_sycl_q( src0_d, src1_d, (block_mxfp4 *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_NVFP4: set_rows_sycl_q( src0_d, src1_d, (block_nvfp4 *) dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q2_K: set_rows_sycl_qk_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q3_K: set_rows_sycl_qk_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q4_K: set_rows_sycl_qk_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q5_K: set_rows_sycl_qk_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_Q6_K: set_rows_sycl_qk_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_IQ2_XXS: set_rows_sycl_iq_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_IQ2_XS: set_rows_sycl_iq_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_IQ2_S: set_rows_sycl_iq_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_IQ3_XXS: set_rows_sycl_qk_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_IQ3_S: set_rows_sycl_qk_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_IQ1_S: set_rows_sycl_iq_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_IQ1_M: set_rows_sycl_iq_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; case GGML_TYPE_IQ4_XS: set_rows_sycl_qk_host( src0, src1, dst, ne00, ne01, ne02, ne03, ne11, ne12, nb01, nb02, nb03, nb10, nb11, nb12, nb1, nb2, nb3, stream); break; default: GGML_ABORT("Unsupported tensor type!"); break; } } void ggml_sycl_op_set_rows(ggml_backend_sycl_context & ctx, ggml_tensor * dst) { scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/2); const ggml_tensor * src0 = dst->src[0]; const ggml_tensor * src1 = dst->src[1]; GGML_ASSERT(dst->src[0]->type == GGML_TYPE_F32 || dst->src[0]->type == GGML_TYPE_F16); GGML_ASSERT(dst->src[1]->type == GGML_TYPE_I64 || dst->src[1]->type == GGML_TYPE_I32); // dispatch on the index type (src1) and the source value type (src0) if (src0->type == GGML_TYPE_F16) { if (src1->type == GGML_TYPE_I64) { set_rows_sycl(ctx, src0, src1, dst); } else { set_rows_sycl(ctx, src0, src1, dst); } } else { if (src1->type == GGML_TYPE_I64) { set_rows_sycl(ctx, src0, src1, dst); } else { set_rows_sycl(ctx, src0, src1, dst); } } }