diff --git a/src/simd/dispatch.cpp b/src/simd/dispatch.cpp index eab3eb6..38331c6 100644 --- a/src/simd/dispatch.cpp +++ b/src/simd/dispatch.cpp @@ -20,10 +20,19 @@ namespace rabitqlib::simd { ); } +// With zero extra bits there is no extra code to contribute to the inner +// product, so the ex_bits == 0 slot must be a constant-zero stub rather than +// a duplicate of the 1-bit implementation. +static float ip_fxu0( + const float* /*query*/, const uint8_t* /*compact_code*/, size_t /*dim*/ +) { + return 0.0F; +} + ExcodeIpTable resolve_excode_ip_table() { if (cpu::has_avx512_core()) { return { - excode_ipimpl::ip16_fxu1_avx512, + ip_fxu0, excode_ipimpl::ip16_fxu1_avx512, excode_ipimpl::ip64_fxu2_avx512, excode_ipimpl::ip64_fxu3_avx512, @@ -35,7 +44,7 @@ ExcodeIpTable resolve_excode_ip_table() { }; } else if (cpu::has_avx2()) { return { - excode_ipimpl::ip16_fxu1_avx2, + ip_fxu0, excode_ipimpl::ip16_fxu1_avx2, excode_ipimpl::ip64_fxu2_avx2, excode_ipimpl::ip64_fxu3_avx2, diff --git a/tests/unit/rabitqlib/utils/space_test.cpp b/tests/unit/rabitqlib/utils/space_test.cpp index 8ef9206..fcbc4c8 100644 --- a/tests/unit/rabitqlib/utils/space_test.cpp +++ b/tests/unit/rabitqlib/utils/space_test.cpp @@ -55,6 +55,23 @@ TEST(Select_IP_Func, returns_stable_function_pointer) { } } +TEST(Select_IP_Func, zero_ex_bits_contributes_nothing) { + constexpr size_t dim = 64; + std::vector query(dim); + std::vector codes(dim / 8); + + for (size_t i = 0; i < dim; ++i) { + query[i] = static_cast(i) + 1.0F; + } + for (size_t i = 0; i < codes.size(); ++i) { + codes[i] = 0xFF; + } + + ex_ipfunc ip_func = select_excode_ipfunc(0); + ASSERT_NE(ip_func, nullptr); + ASSERT_EQ(ip_func(query.data(), codes.data(), dim), 0.0F); +} + TEST(ScalarQuantize, Uint8MatchesRoundedScalar) { constexpr size_t dim = 37; constexpr float lo = -3.0F;