#include #include #include #include "ggml-bitnet.h" #include "ggml-quants.h" #include "gemm-config.h" #include "ggml-cpu-impl.h" #include #include #if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) #define QK_I2_S 128 #elif defined(__ARM_NEON) #define QK_I2_S 64 #endif #if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) #include // horizontally add 8 int32_t static inline int hsum_i32_8(const __m256i a) { const __m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(a), _mm256_extractf128_si256(a, 1)); const __m128i hi64 = _mm_unpackhi_epi64(sum128, sum128); const __m128i sum64 = _mm_add_epi32(hi64, sum128); const __m128i hi32 = _mm_shuffle_epi32(sum64, _MM_SHUFFLE(2, 3, 0, 1)); return _mm_cvtsi128_si32(_mm_add_epi32(sum64, hi32)); } #elif defined(__loongarch_asx) // horizontally add 8 int32_t static inline int hsum_i32_8(const __m256i a) { __m256i tmp1 = __lasx_xvpermi_q(a, a, 0x11); __m256i tmp2 = __lasx_xvpermi_q(a, a, 0x00); __m128i tmp1_128 = lasx_extracti128_lo(tmp1); __m128i tmp2_128 = lasx_extracti128_lo(tmp2); __m128i sum128 = __lsx_vadd_w(tmp1_128, tmp2_128); __m128i ev = __lsx_vpickev_w(sum128, sum128); __m128i od = __lsx_vpickod_w(sum128, sum128); __m128i sum64 = __lsx_vadd_w(ev, od); int sum64_1, sum64_2; sum64_1 = __lsx_vpickve2gr_w(sum64, 0); sum64_2 = __lsx_vpickve2gr_w(sum64, 1); return sum64_1 + sum64_2; } #endif size_t quantize_i2_s(const float * src, void * dst, int64_t nrow, int64_t n_per_row, const float * quant_weights) { #if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) #if defined(ACT_PARALLEL) size_t row_size = ggml_row_size(GGML_TYPE_I2_S, n_per_row); int n = nrow * n_per_row; // f32 -> q8 double max = 0; for (int i = 0; i < n; ++i) { max = fmax(max, (double)fabs((double)src[i])); } double i2_scale = max; uint8_t* q8 = (uint8_t*)malloc(n * sizeof(uint8_t)); for (int i=0; i 0 ? 2 : 0; } memset(dst, 0, n * sizeof(uint8_t) / 4); // q8 -> 0, 1, 2 // | | | // -1, 0, 1 uint8_t* i2_weight = (uint8_t*)dst; for (int i = 0; i < n / QK_I2_S; i++) { for (int j = 0; j < QK_I2_S; j++) { int group_idx = j / 32; int group_pos = j % 32; uint8_t temp = (q8[i * QK_I2_S + j] << (6 - 2 * group_idx)); i2_weight[i * 32 + group_pos] |= temp; } } float* scale_ptr = (float*)((char*)i2_weight + n / 4); scale_ptr[0] = i2_scale; free(q8); // 32B for alignment return nrow * row_size / 4 + 32; #else assert((nrow % 4) == 0 && "quantize_i2_s_1x4 requires nrow % 4 == 0"); size_t row_size = ggml_row_size(GGML_TYPE_I2_S, n_per_row); int64_t n = nrow * n_per_row; double max = 0; for (int64_t i = 0; i < n; ++i) { max = fmax(max, (double)fabs((double)src[i])); } double i2_scale = max; uint8_t* q8 = (uint8_t*)malloc(n * sizeof(uint8_t)); for (int64_t i=0; i 0 ? 2 : 0; } uint8_t* out = (uint8_t*)dst; memset(out, 0, (size_t)(n / 4)); // for each group of 4 rows, for each column, write one byte int64_t nrow4 = nrow / 4; for (int64_t rg = 0; rg < nrow4; rg++) { int64_t r0 = rg * 4 + 0; int64_t r1 = rg * 4 + 1; int64_t r2 = rg * 4 + 2; int64_t r3 = rg * 4 + 3; int64_t base = rg * n_per_row; for (int64_t col = 0; col < n_per_row; col++) { uint8_t q0 = q8[r0 * n_per_row + col]; uint8_t q1 = q8[r1 * n_per_row + col]; uint8_t q2 = q8[r2 * n_per_row + col]; uint8_t q3 = q8[r3 * n_per_row + col]; uint8_t packed = (uint8_t)((q0 << 6) | (q1 << 4) | (q2 << 2) | (q3 << 0)); out[base + col] = packed; } } // store scale at the end of quantized data (same location pattern as quantize_i2_s) float* scale_ptr = (float*)((char*)out + n / 4); scale_ptr[0] = (float)i2_scale; free(q8); // return size (keep same formula as quantize_i2_s) return nrow * row_size / 4 + 32; #endif #elif defined(__ARM_NEON) size_t row_size = ggml_row_size(GGML_TYPE_I2_S, n_per_row); int n = nrow * n_per_row; // f32 -> q8 double max = 0; for (int i = 0; i < n; ++i) { max = fmax(max, (double)fabs((double)src[i])); } double i2_scale = max; uint8_t* q8 = (uint8_t*)malloc(n * sizeof(uint8_t)); for (int i=0; i 0 ? 2 : 0; } memset(dst, 0, n * sizeof(uint8_t) / 4); // q8 -> 0, 1, 2 // | | | // -1, 0, 1 uint8_t* i2_weight = (uint8_t*)dst; for (int i = 0; i < n / QK_I2_S; i++) { for (int j = 0; j < QK_I2_S; j++) { int group_idx = j / 16; int group_pos = j % 16; uint8_t temp = (q8[i * QK_I2_S + j] << (6 - 2 * group_idx)); i2_weight[i * 16 + group_pos] |= temp; } } float* scale_ptr = (float*)((char*)i2_weight + n / 4); scale_ptr[0] = i2_scale; free(q8); // 32B for alignment return nrow * row_size / 4 + 32; #endif } void ggml_vec_dot_i2_i8_s_1x1(int n, float * s, size_t bs, const void * vx, size_t bx, const void * vy, size_t by, int nrc) { #if defined(__AVX2__) const uint8_t * x = (uint8_t *)vx; const int8_t * y = (int8_t *)vy; const int nb = n / QK_I2_S; const int group32_num = nb / 32; const int la_num = nb % 32; const int groupla_num = nb % 32 != 0 ? 1 : 0; __m256i mask = _mm256_set1_epi8(0x03); __m256i one16 = _mm256_set1_epi16(1); // 处理多行,nrc表示要处理的行数 for (int row = 0; row < nrc; row++) { __m256i accu = _mm256_setzero_si256(); // 计算当前行的x指针偏移 const uint8_t * x_row = x + row * bx / 4; for (int i = 0; i < group32_num; i++) { const uint8_t *px = x_row + i * 1024; // 32 * 32 const int8_t *py = y + i * 4096; // 32 * 128 __m256i accu32 = _mm256_setzero_si256(); for (int j = 0; j < 32; j++) { // 128 index __m256i xq8_3 = _mm256_loadu_si256((const __m256i*)(px)); __m256i xq8_2 = _mm256_srli_epi16(xq8_3, 2); __m256i xq8_1 = _mm256_srli_epi16(xq8_3, 4); __m256i xq8_0 = _mm256_srli_epi16(xq8_3, 6); // each 32 index xq8_3 = _mm256_and_si256(xq8_3, mask); xq8_2 = _mm256_and_si256(xq8_2, mask); xq8_1 = _mm256_and_si256(xq8_1, mask); xq8_0 = _mm256_and_si256(xq8_0, mask); // each 32 index __m256i yq8_0 = _mm256_loadu_si256((const __m256i*)(py)); __m256i yq8_1 = _mm256_loadu_si256((const __m256i*)(py + 32)); __m256i yq8_2 = _mm256_loadu_si256((const __m256i*)(py + 64)); __m256i yq8_3 = _mm256_loadu_si256((const __m256i*)(py + 96)); xq8_0 = _mm256_maddubs_epi16(xq8_0, yq8_0); xq8_1 = _mm256_maddubs_epi16(xq8_1, yq8_1); xq8_2 = _mm256_maddubs_epi16(xq8_2, yq8_2); xq8_3 = _mm256_maddubs_epi16(xq8_3, yq8_3); accu32 = _mm256_add_epi16(accu32, _mm256_add_epi16(xq8_0, xq8_1)); accu32 = _mm256_add_epi16(accu32, _mm256_add_epi16(xq8_2, xq8_3)); px += 32; py += 128; } accu = _mm256_add_epi32(_mm256_madd_epi16(accu32, one16), accu); } for (int i = 0; i < groupla_num; i++) { __m256i accula = _mm256_setzero_si256(); const uint8_t *px = x_row + group32_num * 1024; // 32 * 32 const int8_t *py = y + group32_num * 4096; // 32 * 128 for (int j = 0; j < la_num; j++) { // 128 index __m256i xq8_3 = _mm256_loadu_si256((const __m256i*)(px)); __m256i xq8_2 = _mm256_srli_epi16(xq8_3, 2); __m256i xq8_1 = _mm256_srli_epi16(xq8_3, 4); __m256i xq8_0 = _mm256_srli_epi16(xq8_3, 6); // each 32 index xq8_3 = _mm256_and_si256(xq8_3, mask); xq8_2 = _mm256_and_si256(xq8_2, mask); xq8_1 = _mm256_and_si256(xq8_1, mask); xq8_0 = _mm256_and_si256(xq8_0, mask); // each 32 index __m256i yq8_0 = _mm256_loadu_si256((const __m256i*)(py)); __m256i yq8_1 = _mm256_loadu_si256((const __m256i*)(py + 32)); __m256i yq8_2 = _mm256_loadu_si256((const __m256i*)(py + 64)); __m256i yq8_3 = _mm256_loadu_si256((const __m256i*)(py + 96)); xq8_0 = _mm256_maddubs_epi16(xq8_0, yq8_0); xq8_1 = _mm256_maddubs_epi16(xq8_1, yq8_1); xq8_2 = _mm256_maddubs_epi16(xq8_2, yq8_2); xq8_3 = _mm256_maddubs_epi16(xq8_3, yq8_3); accula = _mm256_add_epi16(accula, _mm256_add_epi16(xq8_0, xq8_1)); accula = _mm256_add_epi16(accula, _mm256_add_epi16(xq8_2, xq8_3)); px += 32; py += 128; } accu = _mm256_add_epi32(accu, _mm256_madd_epi16(accula, one16)); } int sumi = hsum_i32_8(accu); s[row] = (float)sumi; } #elif defined(__ARM_NEON) const uint8_t * x = (uint8_t *)vx; const int8_t * y = (int8_t *)vy; const int nb = n / QK_I2_S; const int group32_num = nb / 32; const int la_num = nb % 32; const int groupla_num = nb % 32 != 0 ? 1 : 0; const uint8x16_t mask = vdupq_n_u8(3); // 处理多列,nrc表示要处理的列数 for (int row = 0; row < nrc; row++) { int32x4_t accu = vdupq_n_s32(0); // 计算当前行的x指针偏移 const uint8_t * x_row = x + row * bx / 4; for (int i=0; i < group32_num; i++) { #if defined(__ARM_FEATURE_DOTPROD) #else int16x8_t accu32 = vdupq_n_s16(0); #endif for (int j=0; j < 32; j++) { uint8x16_t xq8_3 = vld1q_u8(x_row + i * 32 * 16 + j * 16); uint8x16_t xq8_2 = vshrq_n_u8(xq8_3, 2); uint8x16_t xq8_1 = vshrq_n_u8(xq8_3, 4); uint8x16_t xq8_0 = vshrq_n_u8(xq8_3, 6); int8x16_t q8_0 = vreinterpretq_s8_u8(vandq_u8(xq8_0, mask)); int8x16_t q8_1 = vreinterpretq_s8_u8(vandq_u8(xq8_1, mask)); int8x16_t q8_2 = vreinterpretq_s8_u8(vandq_u8(xq8_2, mask)); int8x16_t q8_3 = vreinterpretq_s8_u8(vandq_u8(xq8_3, mask)); const int8x16_t yq8_0 = vld1q_s8(y + i * 32 * 64 + j * 64 + 0); const int8x16_t yq8_1 = vld1q_s8(y + i * 32 * 64 + j * 64 + 16); const int8x16_t yq8_2 = vld1q_s8(y + i * 32 * 64 + j * 64 + 32); const int8x16_t yq8_3 = vld1q_s8(y + i * 32 * 64 + j * 64 + 48); #if defined(__ARM_FEATURE_DOTPROD) accu = vdotq_s32(accu, q8_0, yq8_0); accu = vdotq_s32(accu, q8_1, yq8_1); accu = vdotq_s32(accu, q8_2, yq8_2); accu = vdotq_s32(accu, q8_3, yq8_3); #else accu32 = vmlal_s8(accu32, vget_low_s8(q8_0), vget_low_s8(yq8_0)); accu32 = vmlal_s8(accu32, vget_high_s8(q8_0), vget_high_s8(yq8_0)); accu32 = vmlal_s8(accu32, vget_low_s8(q8_1), vget_low_s8(yq8_1)); accu32 = vmlal_s8(accu32, vget_high_s8(q8_1), vget_high_s8(yq8_1)); accu32 = vmlal_s8(accu32, vget_low_s8(q8_2), vget_low_s8(yq8_2)); accu32 = vmlal_s8(accu32, vget_high_s8(q8_2), vget_high_s8(yq8_2)); accu32 = vmlal_s8(accu32, vget_low_s8(q8_3), vget_low_s8(yq8_3)); accu32 = vmlal_s8(accu32, vget_high_s8(q8_3), vget_high_s8(yq8_3)); #endif } #if defined(__ARM_FEATURE_DOTPROD) #else accu = vaddq_s32(accu, vmovl_s16(vget_low_s16(accu32))); accu = vaddq_s32(accu, vmovl_high_s16(accu32)); #endif } for (int i = 0; i < groupla_num; i++){ #if defined(__ARM_FEATURE_DOTPROD) #else int16x8_t accula = vdupq_n_s16(0); #endif for (int j = 0; j < la_num; j++) { uint8x16_t xq8_3 = vld1q_u8(x_row + group32_num * 32 * 16 + j * 16); uint8x16_t xq8_2 = vshrq_n_u8(xq8_3, 2); uint8x16_t xq8_1 = vshrq_n_u8(xq8_3, 4); uint8x16_t xq8_0 = vshrq_n_u8(xq8_3, 6); int8x16_t q8_0 = vreinterpretq_s8_u8(vandq_u8(xq8_0, mask)); int8x16_t q8_1 = vreinterpretq_s8_u8(vandq_u8(xq8_1, mask)); int8x16_t q8_2 = vreinterpretq_s8_u8(vandq_u8(xq8_2, mask)); int8x16_t q8_3 = vreinterpretq_s8_u8(vandq_u8(xq8_3, mask)); const int8x16_t yq8_0 = vld1q_s8(y + group32_num * 32 * 64 + j * 64 + 0); const int8x16_t yq8_1 = vld1q_s8(y + group32_num * 32 * 64 + j * 64 + 16); const int8x16_t yq8_2 = vld1q_s8(y + group32_num * 32 * 64 + j * 64 + 32); const int8x16_t yq8_3 = vld1q_s8(y + group32_num * 32 * 64 + j * 64 + 48); #if defined(__ARM_FEATURE_DOTPROD) accu = vdotq_s32(accu, q8_0, yq8_0); accu = vdotq_s32(accu, q8_1, yq8_1); accu = vdotq_s32(accu, q8_2, yq8_2); accu = vdotq_s32(accu, q8_3, yq8_3); #else accula = vmlal_s8(accula, vget_low_s8(q8_0), vget_low_s8(yq8_0)); accula = vmlal_s8(accula, vget_high_s8(q8_0), vget_high_s8(yq8_0)); accula = vmlal_s8(accula, vget_low_s8(q8_1), vget_low_s8(yq8_1)); accula = vmlal_s8(accula, vget_high_s8(q8_1), vget_high_s8(yq8_1)); accula = vmlal_s8(accula, vget_low_s8(q8_2), vget_low_s8(yq8_2)); accula = vmlal_s8(accula, vget_high_s8(q8_2), vget_high_s8(yq8_2)); accula = vmlal_s8(accula, vget_low_s8(q8_3), vget_low_s8(yq8_3)); accula = vmlal_s8(accula, vget_high_s8(q8_3), vget_high_s8(yq8_3)); #endif } #if defined(__ARM_FEATURE_DOTPROD) #else accu = vaddq_s32(accu, vmovl_s16(vget_low_s16(accula))); accu = vaddq_s32(accu, vmovl_high_s16(accula)); #endif } int sumi = vaddlvq_s32(accu); s[row] = (float)sumi; } #endif } void ggml_vec_dot_i2_i8_s_1x4_32W(int n, float * s, size_t bs, const void * vx, size_t bx, const void * vy, size_t by, int nrc) { #if defined(__AVX2__) const uint8_t * x = (uint8_t *)vx; const int8_t * y = (int8_t *)vy; const int nb = n / QK_I2_S; const int group32_num = nb / 32; const int la_num = nb % 32; const int groupla_num = nb % 32 != 0 ? 1 : 0; const __m256i mask = _mm256_set1_epi8(0x03); const __m256i one16 = _mm256_set1_epi16(1); // 处理多行,nrc表示要处理的行数 for (int row = 0; row < nrc; row+=4) { __m256i accu[4]; for(int rb = 0; rb < 4; rb++) { accu[rb] = _mm256_setzero_si256(); } const uint8_t * x_row = x + (row) * bx / 4; // 计算当前行的x指针偏移 for (int i = 0; i < group32_num; i++) { const uint8_t * px = x_row + i * 1024 * 4; __m256i accu32[4]; for(int rb = 0; rb < 4; rb++) { accu32[rb] = _mm256_setzero_si256(); } const int8_t *py = y + i * 4096; for (int j = 0; j < 32 * 4; j++) { // each 32 index __m256i yq8_0 = _mm256_loadu_si256((const __m256i*)(py)); __m256i xq8[4]; xq8[3] = _mm256_loadu_si256((const __m256i*)(px)); xq8[2] = _mm256_srli_epi16(xq8[3], 2); xq8[1] = _mm256_srli_epi16(xq8[3], 4); xq8[0] = _mm256_srli_epi16(xq8[3], 6); xq8[3] = _mm256_and_si256(xq8[3], mask); xq8[2] = _mm256_and_si256(xq8[2], mask); xq8[1] = _mm256_and_si256(xq8[1], mask); xq8[0] = _mm256_and_si256(xq8[0], mask); for (int rb = 0; rb < 4; rb++) { xq8[rb] = _mm256_maddubs_epi16(xq8[rb], yq8_0); accu32[rb] = _mm256_add_epi16(accu32[rb], xq8[rb]); } px += 32; py += 32; } for(int rb = 0; rb < 4; rb++) { accu[rb] = _mm256_add_epi32(_mm256_madd_epi16(accu32[rb], one16), accu[rb]); } } for (int i = 0; i < groupla_num; i++) { const int8_t *py = y + group32_num * 4096; // 32 * 128 __m256i accula[4]; for(int rb = 0; rb < 4; rb++) { accula[rb] = _mm256_setzero_si256(); } const uint8_t * px = x_row + group32_num * 1024 * 4; for (int j = 0; j < la_num * 4; j++) { // each 32 index __m256i yq8_0 = _mm256_loadu_si256((const __m256i*)(py)); __m256i xq8[4]; xq8[3] = _mm256_loadu_si256((const __m256i*)(px)); xq8[2] = _mm256_srli_epi16(xq8[3], 2); xq8[1] = _mm256_srli_epi16(xq8[3], 4); xq8[0] = _mm256_srli_epi16(xq8[3], 6); xq8[3] = _mm256_and_si256(xq8[3], mask); xq8[2] = _mm256_and_si256(xq8[2], mask); xq8[1] = _mm256_and_si256(xq8[1], mask); xq8[0] = _mm256_and_si256(xq8[0], mask); for (int rb = 0; rb < 4; rb++) { xq8[rb] = _mm256_maddubs_epi16(xq8[rb], yq8_0); accula[rb] = _mm256_add_epi16(accula[rb], xq8[rb]); } px += 32; py += 32; } for(int rb = 0; rb < 4; rb++) { accu[rb] = _mm256_add_epi32(accu[rb], _mm256_madd_epi16(accula[rb], one16)); } } for(int rb = 0; rb < 4; rb++) { int sumi = hsum_i32_8(accu[rb]); s[row + rb] = (float)sumi; } } #elif defined(__ARM_NEON) #endif } void ggml_vec_dot_i2_i8_s_1xN(int n, float * s, size_t bs, const void * vx, size_t bx, const void * vy, size_t by, int nrc) { #if defined(__AVX2__) const uint8_t * x = (uint8_t *)vx; const int8_t * y = (int8_t *)vy; const int nb = n / QK_I2_S; const int group32_num = nb / 32; const int la_num = nb % 32; const int groupla_num = nb % 32 != 0 ? 1 : 0; const __m256i mask = _mm256_set1_epi8(0x03); const __m256i one16 = _mm256_set1_epi16(1); // 处理多行,nrc表示要处理的行数 for (int row = 0; row < nrc; row+=PARALLEL_SIZE) { //__m256i accu = _mm256_setzero_si256(); __m256i accu[PARALLEL_SIZE]; const uint8_t * x_row[PARALLEL_SIZE]; for(int rb = 0; rb < PARALLEL_SIZE; rb++) { accu[rb] = _mm256_setzero_si256(); x_row[rb] = x + (row + rb) * bx / 4; } // 计算当前行的x指针偏移 for (int i = 0; i < group32_num; i++) { const uint8_t * px[PARALLEL_SIZE]; __m256i accu32[PARALLEL_SIZE]; for(int rb = 0; rb < PARALLEL_SIZE; rb++) { px[rb] = x_row[rb] + i * 1024; // 32 * 32 accu32[rb] = _mm256_setzero_si256(); } const int8_t *py = y + i * 4096; // 32 * 128 for (int j = 0; j < 32; j++) { // each 32 index __m256i yq8_0 = _mm256_loadu_si256((const __m256i*)(py)); __m256i yq8_1 = _mm256_loadu_si256((const __m256i*)(py + 32)); __m256i yq8_2 = _mm256_loadu_si256((const __m256i*)(py + 64)); __m256i yq8_3 = _mm256_loadu_si256((const __m256i*)(py + 96)); for (int rb = 0; rb < PARALLEL_SIZE; rb++) { __m256i xq8_3 = _mm256_loadu_si256((const __m256i*)(px[rb])); __m256i xq8_2 = _mm256_srli_epi16(xq8_3, 2); __m256i xq8_1 = _mm256_srli_epi16(xq8_3, 4); __m256i xq8_0 = _mm256_srli_epi16(xq8_3, 6); // each 32 index xq8_3 = _mm256_and_si256(xq8_3, mask); xq8_2 = _mm256_and_si256(xq8_2, mask); xq8_1 = _mm256_and_si256(xq8_1, mask); xq8_0 = _mm256_and_si256(xq8_0, mask); xq8_0 = _mm256_maddubs_epi16(xq8_0, yq8_0); xq8_1 = _mm256_maddubs_epi16(xq8_1, yq8_1); xq8_2 = _mm256_maddubs_epi16(xq8_2, yq8_2); xq8_3 = _mm256_maddubs_epi16(xq8_3, yq8_3); accu32[rb] = _mm256_add_epi16(accu32[rb], _mm256_add_epi16(xq8_0, xq8_1)); accu32[rb] = _mm256_add_epi16(accu32[rb], _mm256_add_epi16(xq8_2, xq8_3)); px[rb] += 32; } py += 128; } for(int rb = 0; rb < PARALLEL_SIZE; rb++) { accu[rb] = _mm256_add_epi32(_mm256_madd_epi16(accu32[rb], one16), accu[rb]); } } for (int i = 0; i < groupla_num; i++) { const int8_t *py = y + group32_num * 4096; // 32 * 128 const uint8_t * px[PARALLEL_SIZE]; __m256i accula[PARALLEL_SIZE]; for(int rb = 0; rb < PARALLEL_SIZE; rb++) { px[rb] = x_row[rb] + group32_num * 1024; // 32 * 32 accula[rb] = _mm256_setzero_si256(); } for (int j = 0; j < la_num; j++) { // each 32 index __m256i yq8_0 = _mm256_loadu_si256((const __m256i*)(py)); __m256i yq8_1 = _mm256_loadu_si256((const __m256i*)(py + 32)); __m256i yq8_2 = _mm256_loadu_si256((const __m256i*)(py + 64)); __m256i yq8_3 = _mm256_loadu_si256((const __m256i*)(py + 96)); for (int rb = 0; rb < PARALLEL_SIZE; rb++) { // 128 index __m256i xq8_3 = _mm256_loadu_si256((const __m256i*)(px[rb])); __m256i xq8_2 = _mm256_srli_epi16(xq8_3, 2); __m256i xq8_1 = _mm256_srli_epi16(xq8_3, 4); __m256i xq8_0 = _mm256_srli_epi16(xq8_3, 6); // each 32 index xq8_3 = _mm256_and_si256(xq8_3, mask); xq8_2 = _mm256_and_si256(xq8_2, mask); xq8_1 = _mm256_and_si256(xq8_1, mask); xq8_0 = _mm256_and_si256(xq8_0, mask); xq8_0 = _mm256_maddubs_epi16(xq8_0, yq8_0); xq8_1 = _mm256_maddubs_epi16(xq8_1, yq8_1); xq8_2 = _mm256_maddubs_epi16(xq8_2, yq8_2); xq8_3 = _mm256_maddubs_epi16(xq8_3, yq8_3); accula[rb] = _mm256_add_epi16(accula[rb], _mm256_add_epi16(xq8_0, xq8_1)); accula[rb] = _mm256_add_epi16(accula[rb], _mm256_add_epi16(xq8_2, xq8_3)); px[rb] += 32; } py += 128; } for(int rb = 0; rb < PARALLEL_SIZE; rb++) { accu[rb] = _mm256_add_epi32(accu[rb], _mm256_madd_epi16(accula[rb], one16)); } } for(int rb = 0; rb < PARALLEL_SIZE; rb++) { int sumi = hsum_i32_8(accu[rb]); s[row + rb] = (float)sumi; } } #elif defined(__ARM_NEON) const uint8_t * x = (uint8_t *)vx; const int8_t * y = (int8_t *)vy; const int nb = n / QK_I2_S; const int group32_num = nb / 32; const int la_num = nb % 32; const int groupla_num = nb % 32 != 0 ? 1 : 0; const uint8x16_t mask = vdupq_n_u8(3); // 处理多行,nrc表示要处理的行数 for (int row = 0; row < nrc; row += PARALLEL_SIZE) { int32x4_t accu[PARALLEL_SIZE]; const uint8_t * x_row[PARALLEL_SIZE]; for (int rb = 0; rb < PARALLEL_SIZE; rb++) { accu[rb] = vdupq_n_s32(0); x_row[rb] = x + (row + rb) * bx / 4; } for (int i = 0; i < group32_num; i++) { #if defined(__ARM_FEATURE_DOTPROD) #else int16x8_t accu32[PARALLEL_SIZE]; for (int rb = 0; rb < PARALLEL_SIZE; rb++) { accu32[rb] = vdupq_n_s16(0); } #endif const uint8_t * px[PARALLEL_SIZE]; for (int rb = 0; rb < PARALLEL_SIZE; rb++) { px[rb] = x_row[rb] + i * 32 * 16; } for (int j = 0; j < 32; j++) { // 加载 y 数据(对所有行共享) const int8x16_t yq8_0 = vld1q_s8(y + i * 32 * 64 + j * 64 + 0); const int8x16_t yq8_1 = vld1q_s8(y + i * 32 * 64 + j * 64 + 16); const int8x16_t yq8_2 = vld1q_s8(y + i * 32 * 64 + j * 64 + 32); const int8x16_t yq8_3 = vld1q_s8(y + i * 32 * 64 + j * 64 + 48); // 处理每一行 for (int rb = 0; rb < PARALLEL_SIZE; rb++) { uint8x16_t xq8_3 = vld1q_u8(px[rb] + 0); uint8x16_t xq8_2 = vshrq_n_u8(xq8_3, 2); uint8x16_t xq8_1 = vshrq_n_u8(xq8_3, 4); uint8x16_t xq8_0 = vshrq_n_u8(xq8_3, 6); int8x16_t q8_3 = vreinterpretq_s8_u8(vandq_u8(xq8_3, mask)); int8x16_t q8_2 = vreinterpretq_s8_u8(vandq_u8(xq8_2, mask)); int8x16_t q8_1 = vreinterpretq_s8_u8(vandq_u8(xq8_1, mask)); int8x16_t q8_0 = vreinterpretq_s8_u8(vandq_u8(xq8_0, mask)); #if defined(__ARM_FEATURE_DOTPROD) accu[rb] = vdotq_s32(accu[rb], q8_0, yq8_0); accu[rb] = vdotq_s32(accu[rb], q8_1, yq8_1); accu[rb] = vdotq_s32(accu[rb], q8_2, yq8_2); accu[rb] = vdotq_s32(accu[rb], q8_3, yq8_3); #else accu32[rb] = vmlal_s8(accu32[rb], vget_low_s8(q8_3), vget_low_s8(yq8_3)); accu32[rb] = vmlal_s8(accu32[rb], vget_high_s8(q8_3), vget_high_s8(yq8_3)); accu32[rb] = vmlal_s8(accu32[rb], vget_low_s8(q8_2), vget_low_s8(yq8_2)); accu32[rb] = vmlal_s8(accu32[rb], vget_high_s8(q8_2), vget_high_s8(yq8_2)); accu32[rb] = vmlal_s8(accu32[rb], vget_low_s8(q8_1), vget_low_s8(yq8_1)); accu32[rb] = vmlal_s8(accu32[rb], vget_high_s8(q8_1), vget_high_s8(yq8_1)); accu32[rb] = vmlal_s8(accu32[rb], vget_low_s8(q8_0), vget_low_s8(yq8_0)); accu32[rb] = vmlal_s8(accu32[rb], vget_high_s8(q8_0), vget_high_s8(yq8_0)); #endif px[rb] += 16; } } #if defined(__ARM_FEATURE_DOTPROD) #else for (int rb = 0; rb < PARALLEL_SIZE; rb++) { accu[rb] = vaddq_s32(accu[rb], vmovl_s16(vget_low_s16(accu32[rb]))); accu[rb] = vaddq_s32(accu[rb], vmovl_high_s16(accu32[rb])); } #endif } for (int i = 0; i < groupla_num; i++) { #if defined(__ARM_FEATURE_DOTPROD) #else int16x8_t accula[PARALLEL_SIZE]; for (int rb = 0; rb < PARALLEL_SIZE; rb++) { accula[rb] = vdupq_n_s16(0); } #endif const uint8_t * px[PARALLEL_SIZE]; for (int rb = 0; rb < PARALLEL_SIZE; rb++) { px[rb] = x_row[rb] + group32_num * 32 * 16; } for (int j = 0; j < la_num; j++) { // 加载 y 数据(对所有行共享) const int8x16_t yq8_0 = vld1q_s8(y + group32_num * 32 * 64 + j * 64 + 0); const int8x16_t yq8_1 = vld1q_s8(y + group32_num * 32 * 64 + j * 64 + 16); const int8x16_t yq8_2 = vld1q_s8(y + group32_num * 32 * 64 + j * 64 + 32); const int8x16_t yq8_3 = vld1q_s8(y + group32_num * 32 * 64 + j * 64 + 48); // 处理每一行 for (int rb = 0; rb < PARALLEL_SIZE; rb++) { uint8x16_t xq8_3 = vld1q_u8(px[rb] + 0); uint8x16_t xq8_2 = vshrq_n_u8(xq8_3, 2); uint8x16_t xq8_1 = vshrq_n_u8(xq8_3, 4); uint8x16_t xq8_0 = vshrq_n_u8(xq8_3, 6); int8x16_t q8_3 = vreinterpretq_s8_u8(vandq_u8(xq8_3, mask)); int8x16_t q8_2 = vreinterpretq_s8_u8(vandq_u8(xq8_2, mask)); int8x16_t q8_1 = vreinterpretq_s8_u8(vandq_u8(xq8_1, mask)); int8x16_t q8_0 = vreinterpretq_s8_u8(vandq_u8(xq8_0, mask)); #if defined(__ARM_FEATURE_DOTPROD) accu[rb] = vdotq_s32(accu[rb], q8_0, yq8_0); accu[rb] = vdotq_s32(accu[rb], q8_1, yq8_1); accu[rb] = vdotq_s32(accu[rb], q8_2, yq8_2); accu[rb] = vdotq_s32(accu[rb], q8_3, yq8_3); #else accula[rb] = vmlal_s8(accula[rb], vget_low_s8(q8_3), vget_low_s8(yq8_3)); accula[rb] = vmlal_s8(accula[rb], vget_high_s8(q8_3), vget_high_s8(yq8_3)); accula[rb] = vmlal_s8(accula[rb], vget_low_s8(q8_2), vget_low_s8(yq8_2)); accula[rb] = vmlal_s8(accula[rb], vget_high_s8(q8_2), vget_high_s8(yq8_2)); accula[rb] = vmlal_s8(accula[rb], vget_low_s8(q8_1), vget_low_s8(yq8_1)); accula[rb] = vmlal_s8(accula[rb], vget_high_s8(q8_1), vget_high_s8(yq8_1)); accula[rb] = vmlal_s8(accula[rb], vget_low_s8(q8_0), vget_low_s8(yq8_0)); accula[rb] = vmlal_s8(accula[rb], vget_high_s8(q8_0), vget_high_s8(yq8_0)); #endif px[rb] += 16; } } #if defined(__ARM_FEATURE_DOTPROD) #else for (int rb = 0; rb < PARALLEL_SIZE; rb++) { accu[rb] = vaddq_s32(accu[rb], vmovl_s16(vget_low_s16(accula[rb]))); accu[rb] = vaddq_s32(accu[rb], vmovl_high_s16(accula[rb])); } #endif } // 合并结果并写回 for (int rb = 0; rb < PARALLEL_SIZE; rb++) { int sumi = vaddlvq_s32(accu[rb]); s[row + rb] = (float)sumi; } } #endif } void ggml_vec_dot_i2_i8_s_Nx1(int n, float * s, size_t bs, const void * vx, size_t bx, const void * vy, size_t by, int nrc) { #if defined(__AVX2__) const uint8_t * x = (uint8_t *)vx; const int8_t * y = (int8_t *)vy; const int nb = n / QK_I2_S; const int group32_num = nb / 32; const int la_num = nb % 32; const int groupla_num = nb % 32 != 0 ? 1 : 0; __m256i mask = _mm256_set1_epi8(0x03); __m256i one16 = _mm256_set1_epi16(1); for (int col = 0; col < nrc; col += PARALLEL_SIZE) { __m256i accu[PARALLEL_SIZE]; for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accu[iy] = _mm256_setzero_si256(); } int8_t * y_col = y + col * by; for (int i = 0; i < group32_num; i++) { const uint8_t *px = x + i * 1024; const int8_t *py = y_col + i * 4096; __m256i accu32[PARALLEL_SIZE]; for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accu32[iy] = _mm256_setzero_si256(); } for (int j = 0; j < 32; j++) { __m256i xq8 = _mm256_loadu_si256((const __m256i*)(px)); __m256i xq8_3 = _mm256_and_si256(xq8, mask); __m256i xq8_2 = _mm256_and_si256(_mm256_srli_epi16(xq8, 2), mask); __m256i xq8_1 = _mm256_and_si256(_mm256_srli_epi16(xq8, 4), mask); __m256i xq8_0 = _mm256_and_si256(_mm256_srli_epi16(xq8, 6), mask); for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accu32[iy] = _mm256_add_epi16(accu32[iy], _mm256_add_epi16( _mm256_add_epi16(_mm256_maddubs_epi16(xq8_0, _mm256_loadu_si256((const __m256i*)(py + 0 * 32 + iy * by))), _mm256_maddubs_epi16(xq8_1, _mm256_loadu_si256((const __m256i*)(py + 1 * 32 + iy * by)))), _mm256_add_epi16(_mm256_maddubs_epi16(xq8_2, _mm256_loadu_si256((const __m256i*)(py + 2 * 32 + iy * by))), _mm256_maddubs_epi16(xq8_3, _mm256_loadu_si256((const __m256i*)(py + 3 * 32 + iy * by)))))); } px += 32; py += 128; } for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accu[iy] = _mm256_add_epi32(_mm256_madd_epi16(accu32[iy], one16), accu[iy]); } } for (int i = 0; i < groupla_num; i++) { const uint8_t *px = x + group32_num * 1024; const int8_t *py = y_col + group32_num * 4096; __m256i accula[PARALLEL_SIZE]; for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accula[iy] = _mm256_setzero_si256(); } for (int j = 0; j < la_num; j++) { __m256i xq8 = _mm256_loadu_si256((const __m256i*)(px)); __m256i xq8_3 = _mm256_and_si256(xq8, mask); __m256i xq8_2 = _mm256_and_si256(_mm256_srli_epi16(xq8, 2), mask); __m256i xq8_1 = _mm256_and_si256(_mm256_srli_epi16(xq8, 4), mask); __m256i xq8_0 = _mm256_and_si256(_mm256_srli_epi16(xq8, 6), mask); for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accula[iy] = _mm256_add_epi16(accula[iy], _mm256_add_epi16( _mm256_add_epi16(_mm256_maddubs_epi16(xq8_0, _mm256_loadu_si256((const __m256i*)(py + 0 * 32 + iy * by))), _mm256_maddubs_epi16(xq8_1, _mm256_loadu_si256((const __m256i*)(py + 1 * 32 + iy * by)))), _mm256_add_epi16(_mm256_maddubs_epi16(xq8_2, _mm256_loadu_si256((const __m256i*)(py + 2 * 32 + iy * by))), _mm256_maddubs_epi16(xq8_3, _mm256_loadu_si256((const __m256i*)(py + 3 * 32 + iy * by)))))); } px += 32; py += 128; } for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accu[iy] = _mm256_add_epi32(_mm256_madd_epi16(accula[iy], one16), accu[iy]); } } for (int iy = 0; iy < PARALLEL_SIZE; iy++) { int sumi = hsum_i32_8(accu[iy]); s[(col + iy) * bs] = (float)sumi; } } #elif defined(__ARM_NEON) const uint8_t * x = (uint8_t *)vx; const int8_t * y = (int8_t *)vy; const int nb = n / QK_I2_S; const int group32_num = nb / 32; const int la_num = nb % 32; const int groupla_num = nb % 32 != 0 ? 1 : 0; const uint8x16_t mask = vdupq_n_u8(3); for (int col = 0; col < nrc; col += PARALLEL_SIZE) { int32x4_t accu[PARALLEL_SIZE]; for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accu[iy] = vdupq_n_s32(0); } const int8_t * y_col = y + col * by; for (int i = 0; i < group32_num; i++) { const uint8_t *px = x + i * 512; // i * 32 * 16 const int8_t *py = y_col + i * 2048; // i * 32 * 64 #if defined(__ARM_FEATURE_DOTPROD) #else int16x8_t accu32[PARALLEL_SIZE]; for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accu32[iy] = vdupq_n_s16(0); } #endif for (int j = 0; j < 32; j++) { // 加载并解包 x 数据(对所有列共享) uint8x16_t xq8_3 = vld1q_u8(px + 0); uint8x16_t xq8_2 = vshrq_n_u8(xq8_3, 2); uint8x16_t xq8_1 = vshrq_n_u8(xq8_3, 4); uint8x16_t xq8_0 = vshrq_n_u8(xq8_3, 6); int8x16_t q8_0 = vreinterpretq_s8_u8(vandq_u8(xq8_0, mask)); int8x16_t q8_1 = vreinterpretq_s8_u8(vandq_u8(xq8_1, mask)); int8x16_t q8_2 = vreinterpretq_s8_u8(vandq_u8(xq8_2, mask)); int8x16_t q8_3 = vreinterpretq_s8_u8(vandq_u8(xq8_3, mask)); // 处理每一列 for (int iy = 0; iy < PARALLEL_SIZE; iy++) { const int8x16_t yq8_0 = vld1q_s8(py + 0 * 16 + iy * by); const int8x16_t yq8_1 = vld1q_s8(py + 1 * 16 + iy * by); const int8x16_t yq8_2 = vld1q_s8(py + 2 * 16 + iy * by); const int8x16_t yq8_3 = vld1q_s8(py + 3 * 16 + iy * by); #if defined(__ARM_FEATURE_DOTPROD) accu[iy] = vdotq_s32(accu[iy], q8_0, yq8_0); accu[iy] = vdotq_s32(accu[iy], q8_1, yq8_1); accu[iy] = vdotq_s32(accu[iy], q8_2, yq8_2); accu[iy] = vdotq_s32(accu[iy], q8_3, yq8_3); #else accu32[iy] = vmlal_s8(accu32[iy], vget_low_s8(q8_0), vget_low_s8(yq8_0)); accu32[iy] = vmlal_s8(accu32[iy], vget_high_s8(q8_0), vget_high_s8(yq8_0)); accu32[iy] = vmlal_s8(accu32[iy], vget_low_s8(q8_1), vget_low_s8(yq8_1)); accu32[iy] = vmlal_s8(accu32[iy], vget_high_s8(q8_1), vget_high_s8(yq8_1)); accu32[iy] = vmlal_s8(accu32[iy], vget_low_s8(q8_2), vget_low_s8(yq8_2)); accu32[iy] = vmlal_s8(accu32[iy], vget_high_s8(q8_2), vget_high_s8(yq8_2)); accu32[iy] = vmlal_s8(accu32[iy], vget_low_s8(q8_3), vget_low_s8(yq8_3)); accu32[iy] = vmlal_s8(accu32[iy], vget_high_s8(q8_3), vget_high_s8(yq8_3)); #endif } px += 16; py += 64; } #if defined(__ARM_FEATURE_DOTPROD) #else for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accu[iy] = vaddq_s32(accu[iy], vaddq_s32(vmovl_high_s16(accu32[iy]), vmovl_s16(vget_low_s16(accu32[iy])))); } #endif } for (int i = 0; i < groupla_num; i++) { const uint8_t *px = x + group32_num * 512; const int8_t *py = y_col + group32_num * 2048; #if defined(__ARM_FEATURE_DOTPROD) #else int16x8_t accula[PARALLEL_SIZE]; for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accula[iy] = vdupq_n_s16(0); } #endif for (int j = 0; j < la_num; j++) { // 加载并解包 x 数据(对所有列共享) uint8x16_t xq8_3 = vld1q_u8(px + 0); uint8x16_t xq8_2 = vshrq_n_u8(xq8_3, 2); uint8x16_t xq8_1 = vshrq_n_u8(xq8_3, 4); uint8x16_t xq8_0 = vshrq_n_u8(xq8_3, 6); int8x16_t q8_0 = vreinterpretq_s8_u8(vandq_u8(xq8_0, mask)); int8x16_t q8_1 = vreinterpretq_s8_u8(vandq_u8(xq8_1, mask)); int8x16_t q8_2 = vreinterpretq_s8_u8(vandq_u8(xq8_2, mask)); int8x16_t q8_3 = vreinterpretq_s8_u8(vandq_u8(xq8_3, mask)); // 处理每一列 for (int iy = 0; iy < PARALLEL_SIZE; iy++) { const int8x16_t yq8_0 = vld1q_s8(py + 0 * 16 + iy * by); const int8x16_t yq8_1 = vld1q_s8(py + 1 * 16 + iy * by); const int8x16_t yq8_2 = vld1q_s8(py + 2 * 16 + iy * by); const int8x16_t yq8_3 = vld1q_s8(py + 3 * 16 + iy * by); #if defined(__ARM_FEATURE_DOTPROD) accu[iy] = vdotq_s32(accu[iy], q8_0, yq8_0); accu[iy] = vdotq_s32(accu[iy], q8_1, yq8_1); accu[iy] = vdotq_s32(accu[iy], q8_2, yq8_2); accu[iy] = vdotq_s32(accu[iy], q8_3, yq8_3); #else accula[iy] = vmlal_s8(accula[iy], vget_low_s8(q8_0), vget_low_s8(yq8_0)); accula[iy] = vmlal_s8(accula[iy], vget_high_s8(q8_0), vget_high_s8(yq8_0)); accula[iy] = vmlal_s8(accula[iy], vget_low_s8(q8_1), vget_low_s8(yq8_1)); accula[iy] = vmlal_s8(accula[iy], vget_high_s8(q8_1), vget_high_s8(yq8_1)); accula[iy] = vmlal_s8(accula[iy], vget_low_s8(q8_2), vget_low_s8(yq8_2)); accula[iy] = vmlal_s8(accula[iy], vget_high_s8(q8_2), vget_high_s8(yq8_2)); accula[iy] = vmlal_s8(accula[iy], vget_low_s8(q8_3), vget_low_s8(yq8_3)); accula[iy] = vmlal_s8(accula[iy], vget_high_s8(q8_3), vget_high_s8(yq8_3)); #endif } px += 16; py += 64; } #if defined(__ARM_FEATURE_DOTPROD) #else for (int iy = 0; iy < PARALLEL_SIZE; iy++) { accu[iy] = vaddq_s32(accu[iy], vaddq_s32(vmovl_high_s16(accula[iy]), vmovl_s16(vget_low_s16(accula[iy])))); } #endif } // 合并结果并写回 for (int iy = 0; iy < PARALLEL_SIZE; iy++) { int sumi = vaddlvq_s32(accu[iy]); s[(col + iy) * bs] = (float)sumi; } } #endif } void ggml_vec_dot_i2_i8_s(int n, float * s, size_t bs, const void * vx, size_t bx, const void * vy, size_t by, int nrc) { if (nrc % PARALLEL_SIZE == 0) { #if defined(ACT_PARALLEL) ggml_vec_dot_i2_i8_s_Nx1(n, s, bs, vx, bx, vy, by, nrc); #else ggml_vec_dot_i2_i8_s_1xN(n, s, bs, vx, bx, vy, by, nrc); #endif } else { ggml_vec_dot_i2_i8_s_1x1(n, s, bs, vx, bx, vy, by, nrc); } }