#include "packed_matmul_cpu.h" #if (defined(__x86_64__) || defined(_M_X64)) && !defined(_MSC_VER) #include #include #include #include #include #include #include #include #define ORBITQUANT_TARGET_AVX512 \ __attribute__((target("avx512f,avx512dq,avx512bw,avx512vl,fma,f16c"))) #define ORBITQUANT_TARGET_AVX512_BF16 \ __attribute__((target( \ "avx512f,avx512dq,avx512bw,avx512vl,avx512bf16,fma,f16c"))) #define ORBITQUANT_HAS_AVX512_BF16_INTRINSICS 1 #define ORBITQUANT_NOINLINE __attribute__((noinline)) #define ORBITQUANT_ALWAYS_INLINE __attribute__((always_inline)) namespace orbitquant::cpu { namespace { ORBITQUANT_TARGET_AVX512 inline float horizontal_sum(__m512 value) { return _mm512_reduce_add_ps(value); } ORBITQUANT_TARGET_AVX512 inline __m512 load_float16( void const *data, std::int64_t offset) { return _mm512_loadu_ps(static_cast(data) + offset); } ORBITQUANT_TARGET_AVX512 inline __m512 load_half16( void const *data, std::int64_t offset) { const auto *source = static_cast(data) + offset; const __m256i packed = _mm256_loadu_si256(reinterpret_cast<__m256i const *>(source)); return _mm512_cvtph_ps(packed); } ORBITQUANT_TARGET_AVX512 inline __m512 load_bfloat16( void const *data, std::int64_t offset) { const auto *source = static_cast(data) + offset; const __m256i packed = _mm256_loadu_si256(reinterpret_cast<__m256i const *>(source)); const __m512i widened = _mm512_cvtepu16_epi32(packed); return _mm512_castsi512_ps(_mm512_slli_epi32(widened, 16)); } template inline void store_value(void *data, std::int64_t offset, float value) { static_cast(data)[offset] = scalar_t(value); } template <> inline void store_value(void *data, std::int64_t offset, float value) { static_cast(data)[offset] = value; } template < typename scalar_t, __m512 (*load16)(void const *, std::int64_t), int row_tile> ORBITQUANT_TARGET_AVX512 inline void packed_matmul_avx512_w4_rows( PackedMatmulArgs const &args, std::uint8_t const *packed_row, std::int64_t out_col, std::int64_t row_start) { __m512 accumulators[row_tile]; #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { accumulators[row] = _mm512_setzero_ps(); } const __m512 centroid_lut = _mm512_loadu_ps(args.centroids); const __m128i nibble_mask = _mm_set1_epi8(15); std::int64_t k = 0; for (; k + 16 <= args.in_features; k += 16) { const std::int64_t byte_offset = k / 2; std::int64_t packed; std::memcpy(&packed, packed_row + byte_offset, sizeof(packed)); const __m128i bytes = _mm_cvtsi64_si128(packed); const __m128i low = _mm_and_si128(bytes, nibble_mask); const __m128i high = _mm_and_si128( _mm_srli_epi16(bytes, 4), nibble_mask); const __m512i indices = _mm512_cvtepu8_epi32(_mm_unpacklo_epi8(low, high)); const __m512 weight = _mm512_permutexvar_ps(indices, centroid_lut); #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { const std::int64_t input_offset = (row_start + row) * args.in_features + k; accumulators[row] = _mm512_fmadd_ps( load16(args.x, input_offset), weight, accumulators[row]); } } const float row_norm = args.row_norms[out_col]; #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { const std::int64_t input_row_offset = (row_start + row) * args.in_features; float accumulator = horizontal_sum(accumulators[row]); for (std::int64_t tail = k; tail < args.in_features; ++tail) { const std::uint8_t packed = packed_row[tail / 2]; const std::uint8_t index = (tail & 1) == 0 ? packed & 15u : (packed >> 4) & 15u; if constexpr (std::is_same_v) { accumulator += static_cast(args.x)[input_row_offset + tail] * args.centroids[index]; } else { accumulator += static_cast( static_cast( args.x)[input_row_offset + tail]) * args.centroids[index]; } } accumulator *= row_norm; if (args.has_bias) { accumulator += args.bias[out_col]; } store_value( args.out, (row_start + row) * args.out_features + out_col, accumulator); } } template ORBITQUANT_TARGET_AVX512 ORBITQUANT_NOINLINE void packed_matmul_avx512_w4_typed( PackedMatmulArgs const &args, std::int64_t out_start, std::int64_t out_end) { constexpr int kPrimaryRowTile = 8; const std::int64_t packed_row_bytes = args.in_features / 2; for (std::int64_t out_col = out_start; out_col < out_end; ++out_col) { const auto *packed_row = args.packed_weight_indices + out_col * packed_row_bytes; std::int64_t row = 0; for (; row + kPrimaryRowTile <= args.rows; row += kPrimaryRowTile) { packed_matmul_avx512_w4_rows( args, packed_row, out_col, row); } if (row + 8 <= args.rows) { packed_matmul_avx512_w4_rows( args, packed_row, out_col, row); row += 8; } if (row + 4 <= args.rows) { packed_matmul_avx512_w4_rows( args, packed_row, out_col, row); row += 4; } switch (args.rows - row) { case 3: packed_matmul_avx512_w4_rows( args, packed_row, out_col, row); break; case 2: packed_matmul_avx512_w4_rows( args, packed_row, out_col, row); break; case 1: packed_matmul_avx512_w4_rows( args, packed_row, out_col, row); break; default: break; } } } template inline std::uint32_t unpack_index_generic( std::uint8_t const *packed_row, std::int64_t value_index) { const std::int64_t bit_start = value_index * Bits; const std::int64_t byte_index = bit_start >> 3; const unsigned bit_offset = static_cast(bit_start & 7); std::uint32_t raw = packed_row[byte_index]; if (bit_offset + static_cast(Bits) > 8) { raw |= static_cast(packed_row[byte_index + 1]) << 8; } return (raw >> bit_offset) & ((1u << Bits) - 1u); } // Each decoder turns 16 consecutive packed indices into 16 fp32 centroid // values. Rows are byte-aligned because dispatch requires in_features // divisibility (W2/W6: in % 4 == 0, W3: in % 8 == 0). struct W2Avx512Decoder { static constexpr int kBits = 2; struct Tables { __m512 lut; }; ORBITQUANT_TARGET_AVX512 static inline Tables load_tables( float const *centroids) { return Tables{_mm512_broadcast_f32x4(_mm_loadu_ps(centroids))}; } ORBITQUANT_TARGET_AVX512 static inline __m512 decode( std::uint8_t const *packed_row, std::int64_t k, Tables const &tables) { std::uint32_t packed_bits; std::memcpy(&packed_bits, packed_row + (k >> 2), sizeof(packed_bits)); const __m128i bytes = _mm_cvtsi32_si128(static_cast(packed_bits)); const __m128i replicated = _mm_shuffle_epi8( bytes, _mm_setr_epi8(0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3)); const __m512i widened = _mm512_cvtepu8_epi32(replicated); const __m512i shifts = _mm512_set_epi32( 6, 4, 2, 0, 6, 4, 2, 0, 6, 4, 2, 0, 6, 4, 2, 0); const __m512i indices = _mm512_and_si512( _mm512_srlv_epi32(widened, shifts), _mm512_set1_epi32(3)); return _mm512_permutexvar_ps(indices, tables.lut); } }; struct W3Avx512Decoder { static constexpr int kBits = 3; struct Tables { __m512 lut; }; ORBITQUANT_TARGET_AVX512 static inline Tables load_tables( float const *centroids) { return Tables{_mm512_broadcast_f32x8(_mm256_loadu_ps(centroids))}; } ORBITQUANT_TARGET_AVX512 static inline __m512 decode( std::uint8_t const *packed_row, std::int64_t k, Tables const &tables) { std::uint64_t raw_bits = 0; std::memcpy(&raw_bits, packed_row + (k * 3 >> 3), 6); const __m128i raw = _mm_cvtsi64_si128(static_cast(raw_bits)); const __m128i window_low = _mm_shuffle_epi8( raw, _mm_setr_epi8(0, 1, 0, 1, 0, 1, 1, 2, 1, 2, 1, 2, 2, 3, 2, 3)); const __m128i window_high = _mm_shuffle_epi8( raw, _mm_setr_epi8(3, 4, 3, 4, 3, 4, 4, 5, 4, 5, 4, 5, 5, 6, 5, 6)); const __m512i widened = _mm512_cvtepu16_epi32( _mm256_set_m128i(window_high, window_low)); const __m512i shifts = _mm512_set_epi32( 5, 2, 7, 4, 1, 6, 3, 0, 5, 2, 7, 4, 1, 6, 3, 0); const __m512i indices = _mm512_and_si512( _mm512_srlv_epi32(widened, shifts), _mm512_set1_epi32(7)); return _mm512_permutexvar_ps(indices, tables.lut); } }; struct W6Avx512Decoder { static constexpr int kBits = 6; struct Tables { __m512 lut0; __m512 lut1; __m512 lut2; __m512 lut3; }; ORBITQUANT_TARGET_AVX512 static inline Tables load_tables( float const *centroids) { return Tables{ _mm512_loadu_ps(centroids), _mm512_loadu_ps(centroids + 16), _mm512_loadu_ps(centroids + 32), _mm512_loadu_ps(centroids + 48)}; } ORBITQUANT_TARGET_AVX512 static inline __m512 decode( std::uint8_t const *packed_row, std::int64_t k, Tables const &tables) { std::uint64_t low_bytes; std::uint32_t high_bytes; std::uint8_t const *source = packed_row + (k * 6 >> 3); std::memcpy(&low_bytes, source, sizeof(low_bytes)); std::memcpy(&high_bytes, source + 8, sizeof(high_bytes)); const __m128i raw = _mm_set_epi64x( static_cast(high_bytes), static_cast(low_bytes)); const __m128i window_low = _mm_shuffle_epi8( raw, _mm_setr_epi8(0, 1, 0, 1, 1, 2, 2, 3, 3, 4, 3, 4, 4, 5, 5, 6)); const __m128i window_high = _mm_shuffle_epi8( raw, _mm_setr_epi8(6, 7, 6, 7, 7, 8, 8, 9, 9, 10, 9, 10, 10, 11, 11, 12)); const __m512i widened = _mm512_cvtepu16_epi32( _mm256_set_m128i(window_high, window_low)); const __m512i shifts = _mm512_set_epi32( 2, 4, 6, 0, 2, 4, 6, 0, 2, 4, 6, 0, 2, 4, 6, 0); const __m512i indices = _mm512_and_si512( _mm512_srlv_epi32(widened, shifts), _mm512_set1_epi32(63)); const __m512 low_pair = _mm512_permutex2var_ps(tables.lut0, indices, tables.lut1); const __m512 high_pair = _mm512_permutex2var_ps(tables.lut2, indices, tables.lut3); const __mmask16 use_high = _mm512_test_epi32_mask(indices, _mm512_set1_epi32(32)); return _mm512_mask_blend_ps(use_high, low_pair, high_pair); } }; template < typename scalar_t, __m512 (*load16)(void const *, std::int64_t), typename decoder_t, int row_tile> ORBITQUANT_TARGET_AVX512 inline void packed_matmul_avx512_lowbit_rows( PackedMatmulArgs const &args, std::uint8_t const *packed_row, std::int64_t out_col, std::int64_t row_start) { __m512 accumulators[row_tile]; #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { accumulators[row] = _mm512_setzero_ps(); } const typename decoder_t::Tables tables = decoder_t::load_tables(args.centroids); std::int64_t k = 0; for (; k + 16 <= args.in_features; k += 16) { const __m512 weight = decoder_t::decode(packed_row, k, tables); #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { const std::int64_t input_offset = (row_start + row) * args.in_features + k; accumulators[row] = _mm512_fmadd_ps( load16(args.x, input_offset), weight, accumulators[row]); } } const float row_norm = args.row_norms[out_col]; #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { const std::int64_t input_row_offset = (row_start + row) * args.in_features; float accumulator = horizontal_sum(accumulators[row]); for (std::int64_t tail = k; tail < args.in_features; ++tail) { const std::uint32_t index = unpack_index_generic(packed_row, tail); if constexpr (std::is_same_v) { accumulator += static_cast(args.x)[input_row_offset + tail] * args.centroids[index]; } else { accumulator += static_cast( static_cast( args.x)[input_row_offset + tail]) * args.centroids[index]; } } accumulator *= row_norm; if (args.has_bias) { accumulator += args.bias[out_col]; } store_value( args.out, (row_start + row) * args.out_features + out_col, accumulator); } } template ORBITQUANT_TARGET_AVX512 inline void packed_matmul_avx512_buffered_rows( PackedMatmulArgs const &args, float const *decoded_row, std::int64_t out_col, std::int64_t row_start) { __m512 accumulators[row_tile]; #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { accumulators[row] = _mm512_setzero_ps(); } std::int64_t k = 0; for (; k + 16 <= args.in_features; k += 16) { const __m512 weight = _mm512_loadu_ps(decoded_row + k); #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { const std::int64_t input_offset = (row_start + row) * args.in_features + k; accumulators[row] = _mm512_fmadd_ps( load16(args.x, input_offset), weight, accumulators[row]); } } const float row_norm = args.row_norms[out_col]; #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { const std::int64_t input_row_offset = (row_start + row) * args.in_features; float accumulator = horizontal_sum(accumulators[row]); for (std::int64_t tail = k; tail < args.in_features; ++tail) { if constexpr (std::is_same_v) { accumulator += static_cast(args.x)[input_row_offset + tail] * decoded_row[tail]; } else { accumulator += static_cast( static_cast( args.x)[input_row_offset + tail]) * decoded_row[tail]; } } accumulator *= row_norm; if (args.has_bias) { accumulator += args.bias[out_col]; } store_value( args.out, (row_start + row) * args.out_features + out_col, accumulator); } } template < typename scalar_t, __m512 (*load16)(void const *, std::int64_t), typename decoder_t> ORBITQUANT_TARGET_AVX512 ORBITQUANT_NOINLINE void packed_matmul_avx512_lowbit_typed( PackedMatmulArgs const &args, std::int64_t out_start, std::int64_t out_end) { constexpr int kPrimaryRowTile = 8; const std::int64_t packed_row_bytes = args.in_features * decoder_t::kBits / 8; // Two or more row tiles amortize the packed decode: expand the column once // into a per-thread scratch row and stream plain FMA tiles from it. const bool use_decoded_buffer = args.rows >= 16; thread_local std::vector decoded_row_storage; if (use_decoded_buffer && decoded_row_storage.size() < static_cast(args.in_features)) { decoded_row_storage.resize(static_cast(args.in_features)); } for (std::int64_t out_col = out_start; out_col < out_end; ++out_col) { const auto *packed_row = args.packed_weight_indices + out_col * packed_row_bytes; if (use_decoded_buffer) { float *decoded_row = decoded_row_storage.data(); const typename decoder_t::Tables tables = decoder_t::load_tables(args.centroids); std::int64_t k = 0; for (; k + 16 <= args.in_features; k += 16) { _mm512_storeu_ps(decoded_row + k, decoder_t::decode(packed_row, k, tables)); } for (; k < args.in_features; ++k) { decoded_row[k] = args.centroids[unpack_index_generic(packed_row, k)]; } std::int64_t row = 0; for (; row + kPrimaryRowTile <= args.rows; row += kPrimaryRowTile) { packed_matmul_avx512_buffered_rows( args, decoded_row, out_col, row); } if (row + 4 <= args.rows) { packed_matmul_avx512_buffered_rows( args, decoded_row, out_col, row); row += 4; } switch (args.rows - row) { case 3: packed_matmul_avx512_buffered_rows( args, decoded_row, out_col, row); break; case 2: packed_matmul_avx512_buffered_rows( args, decoded_row, out_col, row); break; case 1: packed_matmul_avx512_buffered_rows( args, decoded_row, out_col, row); break; default: break; } continue; } std::int64_t row = 0; for (; row + kPrimaryRowTile <= args.rows; row += kPrimaryRowTile) { packed_matmul_avx512_lowbit_rows( args, packed_row, out_col, row); } if (row + 4 <= args.rows) { packed_matmul_avx512_lowbit_rows( args, packed_row, out_col, row); row += 4; } switch (args.rows - row) { case 3: packed_matmul_avx512_lowbit_rows( args, packed_row, out_col, row); break; case 2: packed_matmul_avx512_lowbit_rows( args, packed_row, out_col, row); break; case 1: packed_matmul_avx512_lowbit_rows( args, packed_row, out_col, row); break; default: break; } } } template ORBITQUANT_TARGET_AVX512 void packed_matmul_avx512_lowbit_dispatch( PackedMatmulArgs const &args, std::int64_t out_start, std::int64_t out_end) { switch (args.scalar_kind) { case ScalarKind::Float32: packed_matmul_avx512_lowbit_typed( args, out_start, out_end); return; case ScalarKind::Float16: packed_matmul_avx512_lowbit_typed( args, out_start, out_end); return; case ScalarKind::BFloat16: packed_matmul_avx512_lowbit_typed( args, out_start, out_end); return; } } #if defined(ORBITQUANT_HAS_AVX512_BF16_INTRINSICS) template ORBITQUANT_TARGET_AVX512_BF16 ORBITQUANT_ALWAYS_INLINE inline void accumulate_bf16_w4_chunk( PackedMatmulArgs const &args, std::uint8_t const *packed_row, std::int64_t row_start, std::int64_t k, __m512i centroid_lut_words, __m128i nibble_mask, __m512 (&accumulators)[row_tile]) { const std::int64_t byte_offset = k / 2; const __m128i bytes = _mm_loadu_si128( reinterpret_cast<__m128i const *>(packed_row + byte_offset)); const __m128i low = _mm_and_si128(bytes, nibble_mask); const __m128i high = _mm_and_si128( _mm_srli_epi16(bytes, 4), nibble_mask); const __m256i packed_indices = _mm256_set_m128i( _mm_unpackhi_epi8(low, high), _mm_unpacklo_epi8(low, high)); const __m512i indices = _mm512_cvtepu8_epi16(packed_indices); const __m512bh weights = (__m512bh)_mm512_permutexvar_epi16( indices, centroid_lut_words); #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { const std::int64_t input_offset = (row_start + row) * args.in_features + k; const __m512bh activations = (__m512bh)_mm512_loadu_si512( static_cast(args.x) + input_offset); accumulators[row] = _mm512_dpbf16_ps(accumulators[row], activations, weights); } } template ORBITQUANT_TARGET_AVX512_BF16 inline void packed_matmul_avx512_bf16_w4_rows( PackedMatmulArgs const &args, std::uint8_t const *packed_row, std::int64_t out_col, std::int64_t row_start) { __m512 accumulators[row_tile]; #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { accumulators[row] = _mm512_setzero_ps(); } const float row_norm = args.row_norms[out_col]; const __m512 centroid_lut = _mm512_mul_ps( _mm512_loadu_ps(args.centroids), _mm512_set1_ps(row_norm)); const __m512i centroid_lut_words = (__m512i)_mm512_cvtne2ps_pbh( centroid_lut, centroid_lut); const __m128i nibble_mask = _mm_set1_epi8(15); std::int64_t k = 0; if constexpr (unroll_k) { #if defined(__clang__) #pragma clang loop unroll_count(2) #elif defined(__GNUC__) #pragma GCC unroll 2 #endif for (; k + 32 <= args.in_features; k += 32) { accumulate_bf16_w4_chunk( args, packed_row, row_start, k, centroid_lut_words, nibble_mask, accumulators); } } else { for (; k + 32 <= args.in_features; k += 32) { accumulate_bf16_w4_chunk( args, packed_row, row_start, k, centroid_lut_words, nibble_mask, accumulators); } } #pragma clang loop unroll(full) for (int row = 0; row < row_tile; ++row) { const std::int64_t input_row_offset = (row_start + row) * args.in_features; float accumulator = horizontal_sum(accumulators[row]); if constexpr (!aligned_k) { for (std::int64_t tail = k; tail < args.in_features; ++tail) { const std::uint8_t packed = packed_row[tail / 2]; const std::uint8_t index = (tail & 1) == 0 ? packed & 15u : (packed >> 4) & 15u; const float activation = static_cast( static_cast(args.x)[input_row_offset + tail]); const float weight = static_cast( c10::BFloat16(args.centroids[index] * row_norm)); accumulator += activation * weight; } } if (args.has_bias) { accumulator += args.bias[out_col]; } store_value( args.out, (row_start + row) * args.out_features + out_col, accumulator); } } template ORBITQUANT_TARGET_AVX512_BF16 ORBITQUANT_NOINLINE void packed_matmul_avx512_bf16_w4_typed( PackedMatmulArgs const &args, std::int64_t out_start, std::int64_t out_end) { static_assert(primary_row_tile == 4 || primary_row_tile == 8); const std::int64_t packed_row_bytes = args.in_features / 2; for (std::int64_t out_col = out_start; out_col < out_end; ++out_col) { const auto *packed_row = args.packed_weight_indices + out_col * packed_row_bytes; std::int64_t row = 0; for (; row + primary_row_tile <= args.rows; row += primary_row_tile) { packed_matmul_avx512_bf16_w4_rows( args, packed_row, out_col, row); } if (row + 4 <= args.rows) { packed_matmul_avx512_bf16_w4_rows<4, aligned_k, unroll_k>( args, packed_row, out_col, row); row += 4; } switch (args.rows - row) { case 3: packed_matmul_avx512_bf16_w4_rows<3, aligned_k, unroll_k>( args, packed_row, out_col, row); break; case 2: packed_matmul_avx512_bf16_w4_rows<2, aligned_k, unroll_k>( args, packed_row, out_col, row); break; case 1: packed_matmul_avx512_bf16_w4_rows<1, aligned_k, unroll_k>( args, packed_row, out_col, row); break; default: break; } } } #endif bool runtime_has_avx512() { #if defined(_MSC_VER) int registers[4]{}; __cpuid(registers, 1); const bool osxsave = (registers[2] & (1 << 27)) != 0; const bool avx = (registers[2] & (1 << 28)) != 0; const bool fma = (registers[2] & (1 << 12)) != 0; const bool f16c = (registers[2] & (1 << 29)) != 0; if (!osxsave || !avx || !fma || !f16c || (_xgetbv(0) & 0xE6) != 0xE6) { return false; } __cpuidex(registers, 7, 0); constexpr unsigned required_ebx = (1u << 16) | (1u << 17) | (1u << 30) | (1u << 31); return (static_cast(registers[1]) & required_ebx) == required_ebx; #else __builtin_cpu_init(); return __builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512dq") && __builtin_cpu_supports("avx512bw") && __builtin_cpu_supports("avx512vl") && __builtin_cpu_supports("fma") && __builtin_cpu_supports("f16c"); #endif } bool runtime_has_avx512_bf16() { #if defined(ORBITQUANT_HAS_AVX512_BF16_INTRINSICS) __builtin_cpu_init(); return runtime_has_avx512() && __builtin_cpu_supports("avx512bf16"); #else return false; #endif } bool runtime_has_verified_amd_bf16_tuning() { static const bool available = [] { unsigned int eax = 0; unsigned int ebx = 0; unsigned int ecx = 0; unsigned int edx = 0; // CPUID vendor registers spell "AuthenticAMD" in EBX, EDX, ECX order. if (!__get_cpuid(0, &eax, &ebx, &ecx, &edx) || ebx != 0x68747541u || edx != 0x69746e65u || ecx != 0x444d4163u || !__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { return false; } const unsigned int base_family = (eax >> 8) & 0xfu; const unsigned int family = base_family == 0xfu ? base_family + ((eax >> 20) & 0xffu) : base_family; // The four-row unrolled tile was measured on Zen 4 (EPYC 4564P); apply it // to the AMD families that ship AVX-512 BF16 (Zen 4 = 19h, Zen 5 = 1Ah) // instead of pinning the one benchmarked model. return (family == 0x19u || family == 0x1au) && runtime_has_avx512_bf16(); }(); return available; } } // namespace bool packed_matmul_x86_avx512_available() { static const bool available = runtime_has_avx512(); return available; } void packed_matmul_x86_avx512_range( PackedMatmulArgs const &args, std::int64_t out_start, std::int64_t out_end) { if (!packed_matmul_x86_avx512_available()) { packed_matmul_scalar_range(args, out_start, out_end); return; } if (args.bits == 2 && args.in_features % 4 == 0) { packed_matmul_avx512_lowbit_dispatch( args, out_start, out_end); return; } if (args.bits == 3 && args.in_features % 8 == 0) { packed_matmul_avx512_lowbit_dispatch( args, out_start, out_end); return; } if (args.bits == 6 && args.in_features % 4 == 0) { packed_matmul_avx512_lowbit_dispatch( args, out_start, out_end); return; } if (args.bits != 4 || args.in_features % 2 != 0) { packed_matmul_scalar_range(args, out_start, out_end); return; } switch (args.scalar_kind) { case ScalarKind::Float32: packed_matmul_avx512_w4_typed( args, out_start, out_end); return; case ScalarKind::Float16: packed_matmul_avx512_w4_typed( args, out_start, out_end); return; case ScalarKind::BFloat16: #if defined(ORBITQUANT_HAS_AVX512_BF16_INTRINSICS) if (runtime_has_avx512_bf16()) { const bool tuned_dimension = args.in_features == 1536 || args.in_features == 1920 || args.in_features == 3072; const bool use_tuned_shape = runtime_has_verified_amd_bf16_tuning() && args.rows >= 16 && tuned_dimension; if (args.in_features % 32 == 0) { if (use_tuned_shape) { packed_matmul_avx512_bf16_w4_typed<4, true, true>( args, out_start, out_end); } else { packed_matmul_avx512_bf16_w4_typed<8, true, false>( args, out_start, out_end); } } else { packed_matmul_avx512_bf16_w4_typed<8, false, false>( args, out_start, out_end); } return; } #endif packed_matmul_avx512_w4_typed( args, out_start, out_end); return; } } } // namespace orbitquant::cpu #else namespace orbitquant::cpu { bool packed_matmul_x86_avx512_available() { return false; } void packed_matmul_x86_avx512_range( PackedMatmulArgs const &args, std::int64_t out_start, std::int64_t out_end) { packed_matmul_scalar_range(args, out_start, out_end); } } // namespace orbitquant::cpu #endif