Skip to content

Commit e2bc170

Browse files
committed
Publish int2 quant kernel
1 parent 179609b commit e2bc170

2 files changed

Lines changed: 79 additions & 1 deletion

File tree

src/kernels/kernels_specialized.inl

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,6 @@ static auto PIQUANT_HOT quant_bf16_to_uint4_nearest(
640640
auto qb {std::clamp(static_cast<std::int32_t>(std::round(static_cast<fp32_t>(b) * scale)) + zp, 0, 15)};
641641
return qa & 15 | (qb & 15)<<4;
642642
}};
643-
644643
for (; i+1 < numel; i += 2) {
645644
auto a {x[i]};
646645
auto b {x[i+1]};
@@ -652,6 +651,81 @@ static auto PIQUANT_HOT quant_bf16_to_uint4_nearest(
652651
}
653652
}
654653

654+
static auto PIQUANT_HOT quant_bf16_to_uint2_nearest(
655+
const bfp16_t* PIQUANT_RESTRICT x,
656+
uint2_t* PIQUANT_RESTRICT o,
657+
std::int64_t numel,
658+
fp32_t scale,
659+
std::int32_t zp
660+
) noexcept -> void {
661+
scale = 1.0f / scale;
662+
std::int64_t i {};
663+
#if defined(__AVX512F__) && defined(__AVX512BW__)
664+
__m512 vinv_scale {_mm512_set1_ps(scale)};
665+
__m512 vhalf {_mm512_set1_ps(0.5f)};
666+
__m512 vneg_half {_mm512_set1_ps(-0.5f)};
667+
__m512 vzero_ps {_mm512_setzero_ps()};
668+
__m512i vzp {_mm512_set1_epi32(zp)};
669+
__m512i vmin {_mm512_setzero_si512()};
670+
__m512i vmax {_mm512_set1_epi32(3)};
671+
__m128i mask03 {_mm_set1_epi8(0x03)};
672+
__m128i w0146 {_mm_setr_epi8(
673+
1,4, 16,64, 1,4, 16,64,
674+
1,4, 16,64, 1,4, 16,64
675+
)};
676+
for (; i+15 < numel; i += 16) {
677+
#if defined(__AVX512BF16__)
678+
__m256i raw {_mm256_loadu_si256(reinterpret_cast<const __m256i*>(x+i))};
679+
__m512 xf {_mm512_cvtpbh_ps(std::bit_cast<__m256bh>(raw))};
680+
#else
681+
__m256i raw {_mm256_loadu_si256(reinterpret_cast<const __m256i*>(x + i))};
682+
__m512i u32s {_mm512_cvtepu16_epi32(raw)};
683+
__m512i shl {_mm512_slli_epi32(u32s, 16)};
684+
__m512 xf {_mm512_castsi512_ps(shl)};
685+
#endif
686+
__m512 scaled {_mm512_mul_ps(xf, vinv_scale)};
687+
__m512 rnd {_mm512_mask_blend_ps(_mm512_cmp_ps_mask(scaled, vzero_ps, _CMP_GE_OQ), vneg_half, vhalf)};
688+
__m512i qi32 {_mm512_min_epi32(
689+
_mm512_max_epi32(
690+
_mm512_add_epi32(
691+
_mm512_cvttps_epi32(_mm512_add_ps(scaled, rnd)),
692+
vzp),
693+
vmin),
694+
vmax)};
695+
__m128i u8 {_mm512_cvtusepi32_epi8(qi32)};
696+
u8 = _mm_and_si128(u8, mask03);
697+
__m128i pair_sums {_mm_maddubs_epi16(u8, w0146)};
698+
__m128i bytes16 {_mm_hadd_epi16(pair_sums, _mm_setzero_si128())};
699+
__m128i packed4 {_mm_packus_epi16(bytes16, _mm_setzero_si128())};
700+
_mm_storeu_si32(o + (i>>2), packed4);
701+
}
702+
#endif
703+
704+
const auto quant_step_packed {[=](bfp16_t a, bfp16_t b, bfp16_t c, bfp16_t d) noexcept -> std::uint8_t {
705+
auto qa {std::clamp(static_cast<std::int32_t>(std::round(static_cast<fp32_t>(a) * scale)) + zp, 0, 3)};
706+
auto qb {std::clamp(static_cast<std::int32_t>(std::round(static_cast<fp32_t>(b) * scale)) + zp, 0, 3)};
707+
auto qc {std::clamp(static_cast<std::int32_t>(std::round(static_cast<fp32_t>(c) * scale)) + zp, 0, 3)};
708+
auto qd {std::clamp(static_cast<std::int32_t>(std::round(static_cast<fp32_t>(d) * scale)) + zp, 0, 3)};
709+
return (qa & 3) | ((qb & 3)<<2) | ((qc & 3)<<4) | ((qd & 3)<<6);
710+
}};
711+
for (; i+3 < numel; i += 4) {
712+
auto a {x[i]};
713+
auto b {x[i+1]};
714+
auto c {x[i+2]};
715+
auto d {x[i+3]};
716+
o[i>>2] = quant_step_packed(a, b, c, d);
717+
}
718+
if (numel & 3) { /* Handle 1-, 2- or 3-value tail */
719+
std::uint8_t p {};
720+
switch (numel & 3) {
721+
case 3: p |= (quant_step_packed(x[i+2], 0, 0, 0)&3) << 4;
722+
case 2: p |= (quant_step_packed(x[i+1], 0, 0, 0)&3) << 2;
723+
case 1: p |= (quant_step_packed(x[i], 0, 0, 0)&3);
724+
}
725+
o[i>>2] = p;
726+
}
727+
}
728+
655729
template <const reduce_op ReduceOp>
656730
static auto PIQUANT_HOT dequant_uint8_to_f32(
657731
const std::uint8_t* PIQUANT_RESTRICT x,

src/kernels/quantize.inl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ static auto PIQUANT_HOT quant_generic(
124124
quant_bf16_to_uint4_nearest(static_cast<const bfp16_t*>(in), static_cast<uint4_t*>(out), numel, scale, zp);
125125
return;
126126
}
127+
if constexpr (std::is_same_v<In, bfp16_t> && std::is_same_v<Out, uint2_t> && RoundMode == round_mode::nearest) {
128+
quant_bf16_to_uint2_nearest(static_cast<const bfp16_t*>(in), static_cast<uint2_t*>(out), numel, scale, zp);
129+
return;
130+
}
127131

128132
const auto* PIQUANT_RESTRICT x {static_cast<const In*>(in)};
129133
auto* PIQUANT_RESTRICT o {static_cast<Out*>(out)};

0 commit comments

Comments
 (0)