faiss 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +3 -1
- data/vendor/faiss/faiss/Clustering.cpp +9 -1
- data/vendor/faiss/faiss/Clustering.h +8 -0
- data/vendor/faiss/faiss/IVFlib.cpp +14 -3
- data/vendor/faiss/faiss/Index.h +2 -2
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +24 -4
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +16 -145
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +8 -18
- data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
- data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
- data/vendor/faiss/faiss/IndexEDEN.h +57 -0
- data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
- data/vendor/faiss/faiss/IndexFlat.cpp +21 -54
- data/vendor/faiss/faiss/IndexFlat.h +2 -2
- data/vendor/faiss/faiss/IndexHNSW.cpp +311 -102
- data/vendor/faiss/faiss/IndexHNSW.h +31 -7
- data/vendor/faiss/faiss/IndexIDMap.cpp +26 -8
- data/vendor/faiss/faiss/IndexIDMap.h +2 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +36 -10
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
- data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
- data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
- data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +49 -23
- data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
- data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
- data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
- data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
- data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
- data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
- data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
- data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
- data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
- data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
- data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
- data/vendor/faiss/faiss/IndexShards.cpp +5 -5
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +6 -5
- data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
- data/vendor/faiss/faiss/SuperKMeans.cpp +286 -247
- data/vendor/faiss/faiss/SuperKMeans.h +33 -2
- data/vendor/faiss/faiss/VectorTransform.cpp +71 -2
- data/vendor/faiss/faiss/VectorTransform.h +3 -0
- data/vendor/faiss/faiss/clone_index.cpp +8 -0
- data/vendor/faiss/faiss/factory_tools.cpp +47 -4
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +1 -5
- data/vendor/faiss/faiss/gpu/GpuDistance.h +2 -5
- data/vendor/faiss/faiss/gpu/GpuIndex.h +38 -16
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +71 -1
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
- data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
- data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
- data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +7 -4
- data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
- data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
- data/vendor/faiss/faiss/impl/HNSW.cpp +528 -267
- data/vendor/faiss/faiss/impl/HNSW.h +46 -7
- data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
- data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
- data/vendor/faiss/faiss/impl/Panorama.h +20 -9
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +38 -26
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +239 -72
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +66 -4
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +4 -13
- data/vendor/faiss/faiss/impl/ResultHandler.h +34 -34
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +287 -84
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +26 -10
- data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
- data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
- data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +90 -14
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/expanded_scanners.h +5 -1
- data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +1 -0
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
- data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
- data/vendor/faiss/faiss/impl/index_read.cpp +491 -50
- data/vendor/faiss/faiss/impl/index_write.cpp +86 -30
- data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
- data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
- data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
- data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +73 -39
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
- data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
- data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
- data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
- data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
- data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +887 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +90 -24
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +169 -13
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +125 -26
- data/vendor/faiss/faiss/impl/simd_dispatch.h +70 -31
- data/vendor/faiss/faiss/index_factory.cpp +40 -7
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +9 -6
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +29 -8
- data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
- data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
- data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
- data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +47 -5
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +23 -3
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +4 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +10 -4
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
- data/vendor/faiss/faiss/utils/distances.cpp +30 -11
- data/vendor/faiss/faiss/utils/distances_dispatch.h +30 -24
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +1 -1
- data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
- data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
- data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
- data/vendor/faiss/faiss/utils/hamming.cpp +16 -10
- data/vendor/faiss/faiss/utils/hamming.h +10 -1
- data/vendor/faiss/faiss/utils/hamming_distance/common.h +14 -3
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +24 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +1 -1
- data/vendor/faiss/faiss/utils/hamming_distance/{hamming_computer-avx512_spr.h → hamming_computer-avx512_vpopcnt.h} +85 -24
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +141 -0
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
- data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +194 -30
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +198 -18
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +330 -40
- data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +112 -23
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_dispatch.h +2 -7
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +6 -1
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +34 -0
- data/vendor/faiss/faiss/utils/simd_levels.cpp +196 -47
- data/vendor/faiss/faiss/utils/simd_levels.h +33 -8
- data/vendor/faiss/faiss/utils/utils.cpp +9 -27
- metadata +21 -5
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +0 -15
|
@@ -5,19 +5,107 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// -*- c++ -*-
|
|
9
|
+
|
|
8
10
|
#include <faiss/utils/rabitq_simd.h>
|
|
9
11
|
|
|
10
12
|
#ifdef COMPILE_SIMD_RISCV_RVV
|
|
11
13
|
|
|
14
|
+
#include <riscv_vector.h>
|
|
15
|
+
|
|
12
16
|
namespace faiss::rabitq {
|
|
13
17
|
|
|
18
|
+
// SWAR per-byte popcount over a u8m4 group: each output byte holds the
|
|
19
|
+
// population count (0..8) of the corresponding input byte.
|
|
20
|
+
static inline vuint8m4_t popcount_u8m4(vuint8m4_t v, size_t vl) {
|
|
21
|
+
vuint8m4_t t = __riscv_vsrl_vx_u8m4(v, 1, vl);
|
|
22
|
+
t = __riscv_vand_vx_u8m4(t, 0x55, vl);
|
|
23
|
+
v = __riscv_vsub_vv_u8m4(v, t, vl);
|
|
24
|
+
t = __riscv_vsrl_vx_u8m4(v, 2, vl);
|
|
25
|
+
t = __riscv_vand_vx_u8m4(t, 0x33, vl);
|
|
26
|
+
v = __riscv_vand_vx_u8m4(v, 0x33, vl);
|
|
27
|
+
v = __riscv_vadd_vv_u8m4(v, t, vl);
|
|
28
|
+
t = __riscv_vsrl_vx_u8m4(v, 4, vl);
|
|
29
|
+
v = __riscv_vadd_vv_u8m4(v, t, vl);
|
|
30
|
+
return __riscv_vand_vx_u8m4(v, 0x0F, vl);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Shared body for bitwise_{and,xor}_dot_product. @p combine applies the
|
|
34
|
+
// per-element bit op (AND or XOR) between the data and query bit-planes; the
|
|
35
|
+
// popcount of the result for query bit-plane j is weighted by 2^j.
|
|
36
|
+
template <typename Op>
|
|
37
|
+
static inline uint64_t bitwise_dot_product_rvv(
|
|
38
|
+
const uint8_t* query,
|
|
39
|
+
const uint8_t* data,
|
|
40
|
+
size_t size,
|
|
41
|
+
size_t qb,
|
|
42
|
+
Op combine) {
|
|
43
|
+
size_t vlmax = __riscv_vsetvlmax_e16m8();
|
|
44
|
+
vuint16m8_t acc = __riscv_vmv_v_x_u16m8(0, vlmax);
|
|
45
|
+
size_t i = 0;
|
|
46
|
+
while (i < size) {
|
|
47
|
+
size_t vl = __riscv_vsetvl_e8m4(size - i);
|
|
48
|
+
vuint8m4_t vx = __riscv_vle8_v_u8m4(data + i, vl);
|
|
49
|
+
for (size_t j = 0; j < qb; j++) {
|
|
50
|
+
vuint8m4_t vq = __riscv_vle8_v_u8m4(query + j * size + i, vl);
|
|
51
|
+
vuint8m4_t vp = popcount_u8m4(combine(vx, vq, vl), vl);
|
|
52
|
+
vuint16m8_t vw = __riscv_vzext_vf2_u16m8(vp, vl);
|
|
53
|
+
vw = __riscv_vsll_vx_u16m8(vw, j, vl);
|
|
54
|
+
acc = __riscv_vadd_vv_u16m8_tu(acc, acc, vw, vl);
|
|
55
|
+
}
|
|
56
|
+
i += vl;
|
|
57
|
+
}
|
|
58
|
+
vuint32m1_t red = __riscv_vmv_v_x_u32m1(0, 1);
|
|
59
|
+
red = __riscv_vwredsumu_vs_u16m8_u32m1(acc, red, vlmax);
|
|
60
|
+
return __riscv_vmv_x_s_u32m1_u32(red);
|
|
61
|
+
}
|
|
62
|
+
|
|
14
63
|
template <>
|
|
15
64
|
uint64_t bitwise_and_dot_product<SIMDLevel::RISCV_RVV>(
|
|
16
65
|
const uint8_t* query,
|
|
17
66
|
const uint8_t* data,
|
|
18
67
|
size_t size,
|
|
19
68
|
size_t qb) {
|
|
20
|
-
return
|
|
69
|
+
return bitwise_dot_product_rvv(
|
|
70
|
+
query, data, size, qb, [](vuint8m4_t a, vuint8m4_t b, size_t vl) {
|
|
71
|
+
return __riscv_vand_vv_u8m4(a, b, vl);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
template <>
|
|
76
|
+
BitwiseAndDotProductResult bitwise_and_dot_product_with_popcount<
|
|
77
|
+
SIMDLevel::RISCV_RVV>(
|
|
78
|
+
const uint8_t* query,
|
|
79
|
+
const uint8_t* data,
|
|
80
|
+
size_t size,
|
|
81
|
+
size_t qb) {
|
|
82
|
+
// Fused single pass over @p data: reuse each loaded data group for both the
|
|
83
|
+
// doc-side popcount and the qb AND-dot bit-planes, mirroring the separate
|
|
84
|
+
// popcount<RVV> and bitwise_and_dot_product<RVV> kernels above.
|
|
85
|
+
size_t vlmax = __riscv_vsetvlmax_e16m8();
|
|
86
|
+
vuint16m8_t dot_acc = __riscv_vmv_v_x_u16m8(0, vlmax);
|
|
87
|
+
vuint16m8_t pop_acc = __riscv_vmv_v_x_u16m8(0, vlmax);
|
|
88
|
+
size_t i = 0;
|
|
89
|
+
while (i < size) {
|
|
90
|
+
size_t vl = __riscv_vsetvl_e8m4(size - i);
|
|
91
|
+
vuint8m4_t vx = __riscv_vle8_v_u8m4(data + i, vl);
|
|
92
|
+
vuint16m8_t vxp = __riscv_vzext_vf2_u16m8(popcount_u8m4(vx, vl), vl);
|
|
93
|
+
pop_acc = __riscv_vadd_vv_u16m8_tu(pop_acc, pop_acc, vxp, vl);
|
|
94
|
+
for (size_t j = 0; j < qb; j++) {
|
|
95
|
+
vuint8m4_t vq = __riscv_vle8_v_u8m4(query + j * size + i, vl);
|
|
96
|
+
vuint8m4_t vp = popcount_u8m4(__riscv_vand_vv_u8m4(vx, vq, vl), vl);
|
|
97
|
+
vuint16m8_t vw = __riscv_vzext_vf2_u16m8(vp, vl);
|
|
98
|
+
vw = __riscv_vsll_vx_u16m8(vw, j, vl);
|
|
99
|
+
dot_acc = __riscv_vadd_vv_u16m8_tu(dot_acc, dot_acc, vw, vl);
|
|
100
|
+
}
|
|
101
|
+
i += vl;
|
|
102
|
+
}
|
|
103
|
+
vuint32m1_t dot_red = __riscv_vmv_v_x_u32m1(0, 1);
|
|
104
|
+
dot_red = __riscv_vwredsumu_vs_u16m8_u32m1(dot_acc, dot_red, vlmax);
|
|
105
|
+
vuint32m1_t pop_red = __riscv_vmv_v_x_u32m1(0, 1);
|
|
106
|
+
pop_red = __riscv_vwredsumu_vs_u16m8_u32m1(pop_acc, pop_red, vlmax);
|
|
107
|
+
return {__riscv_vmv_x_s_u32m1_u32(dot_red),
|
|
108
|
+
__riscv_vmv_x_s_u32m1_u32(pop_red)};
|
|
21
109
|
}
|
|
22
110
|
|
|
23
111
|
template <>
|
|
@@ -26,28 +114,77 @@ uint64_t bitwise_xor_dot_product<SIMDLevel::RISCV_RVV>(
|
|
|
26
114
|
const uint8_t* data,
|
|
27
115
|
size_t size,
|
|
28
116
|
size_t qb) {
|
|
29
|
-
return
|
|
117
|
+
return bitwise_dot_product_rvv(
|
|
118
|
+
query, data, size, qb, [](vuint8m4_t a, vuint8m4_t b, size_t vl) {
|
|
119
|
+
return __riscv_vxor_vv_u8m4(a, b, vl);
|
|
120
|
+
});
|
|
30
121
|
}
|
|
31
122
|
|
|
32
123
|
template <>
|
|
33
124
|
uint64_t popcount<SIMDLevel::RISCV_RVV>(const uint8_t* data, size_t size) {
|
|
34
|
-
|
|
125
|
+
size_t vlmax = __riscv_vsetvlmax_e16m8();
|
|
126
|
+
vuint16m8_t acc = __riscv_vmv_v_x_u16m8(0, vlmax);
|
|
127
|
+
size_t i = 0;
|
|
128
|
+
while (i < size) {
|
|
129
|
+
size_t vl = __riscv_vsetvl_e8m4(size - i);
|
|
130
|
+
vuint8m4_t v = popcount_u8m4(__riscv_vle8_v_u8m4(data + i, vl), vl);
|
|
131
|
+
vuint16m8_t vw = __riscv_vzext_vf2_u16m8(v, vl);
|
|
132
|
+
acc = __riscv_vadd_vv_u16m8_tu(acc, acc, vw, vl);
|
|
133
|
+
i += vl;
|
|
134
|
+
}
|
|
135
|
+
vuint32m1_t red = __riscv_vmv_v_x_u32m1(0, 1);
|
|
136
|
+
red = __riscv_vwredsumu_vs_u16m8_u32m1(acc, red, vlmax);
|
|
137
|
+
return __riscv_vmv_x_s_u32m1_u32(red);
|
|
35
138
|
}
|
|
36
139
|
|
|
37
140
|
} // namespace faiss::rabitq
|
|
38
141
|
|
|
39
142
|
namespace faiss::rabitq::multibit {
|
|
40
143
|
|
|
144
|
+
static float ip_1exbit_rvv(
|
|
145
|
+
const uint8_t* __restrict sign_bits,
|
|
146
|
+
const uint8_t* __restrict ex_code,
|
|
147
|
+
const float* __restrict rotated_q,
|
|
148
|
+
size_t d,
|
|
149
|
+
float cb) {
|
|
150
|
+
size_t vlmax = __riscv_vsetvlmax_e32m8();
|
|
151
|
+
vfloat32m8_t acc = __riscv_vfmv_v_f_f32m8(0.0f, vlmax);
|
|
152
|
+
size_t i = 0;
|
|
153
|
+
while (i < d) {
|
|
154
|
+
size_t vl = __riscv_vsetvl_e32m8(d - i);
|
|
155
|
+
vbool4_t sb = __riscv_vlm_v_b4(sign_bits + i / 8, vl);
|
|
156
|
+
vbool4_t eb = __riscv_vlm_v_b4(ex_code + i / 8, vl);
|
|
157
|
+
vfloat32m8_t recon = __riscv_vfmv_v_f_f32m8(cb, vl);
|
|
158
|
+
recon = __riscv_vfadd_vf_f32m8_mu(sb, recon, recon, 2.0f, vl);
|
|
159
|
+
recon = __riscv_vfadd_vf_f32m8_mu(eb, recon, recon, 1.0f, vl);
|
|
160
|
+
vfloat32m8_t rq = __riscv_vle32_v_f32m8(rotated_q + i, vl);
|
|
161
|
+
acc = __riscv_vfmacc_vv_f32m8_tu(acc, rq, recon, vl);
|
|
162
|
+
i += vl;
|
|
163
|
+
}
|
|
164
|
+
vfloat32m1_t sum = __riscv_vfmv_s_f_f32m1(0.0f, 1);
|
|
165
|
+
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
|
|
166
|
+
return __riscv_vfmv_f_s_f32m1_f32(sum);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// no-tree-vectorize keeps the ex_bits >= 2 tail on the existing scalar
|
|
170
|
+
// ip_scalar without GCC turning its 64-bit memcpy window into a vluxei64 gather
|
|
171
|
+
// at unaligned addresses, which SIGBUSes on strict-align RVV cores (SpacemiT
|
|
172
|
+
// X60).
|
|
41
173
|
template <>
|
|
42
|
-
float
|
|
174
|
+
__attribute__((optimize("no-tree-vectorize", "no-tree-slp-vectorize"))) float
|
|
175
|
+
compute_inner_product<SIMDLevel::RISCV_RVV>(
|
|
43
176
|
const uint8_t* __restrict sign_bits,
|
|
44
177
|
const uint8_t* __restrict ex_code,
|
|
45
178
|
const float* __restrict rotated_q,
|
|
46
179
|
size_t d,
|
|
47
180
|
size_t ex_bits,
|
|
48
181
|
float cb) {
|
|
49
|
-
|
|
50
|
-
|
|
182
|
+
if (ex_bits == 1) {
|
|
183
|
+
return ip_1exbit_rvv(sign_bits, ex_code, rotated_q, d, cb);
|
|
184
|
+
}
|
|
185
|
+
// ex_bits >= 2 needs strided bit-plane extraction (PEXT on x86); RVV has no
|
|
186
|
+
// cheap equivalent without Zvbb, so reuse the scalar kernel.
|
|
187
|
+
return ip_scalar(sign_bits, ex_code, rotated_q, 0, d, ex_bits, cb);
|
|
51
188
|
}
|
|
52
189
|
|
|
53
190
|
} // namespace faiss::rabitq::multibit
|
|
@@ -9,13 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
// Private dispatch wrapper for SuperKMeans's block_l2. Routes to the
|
|
11
11
|
// highest available SIMD specialization at runtime (DD mode) or the
|
|
12
|
-
// compiled-in level (static mode).
|
|
13
|
-
// scalar primary template; adding NEON/SVE means just adding a new
|
|
14
|
-
// specialization file alongside the AVX ones.
|
|
12
|
+
// compiled-in level (static mode).
|
|
15
13
|
//
|
|
16
|
-
// Known perf gap: aarch64 (NEON/SVE) specializations are not implemented yet.
|
|
17
|
-
// aarch64 falls through to the scalar primary template. Validating SVE requires
|
|
18
|
-
// a Graviton-class host; deferred to a focused follow-up.
|
|
19
14
|
|
|
20
15
|
#include <faiss/impl/simd_dispatch.h>
|
|
21
16
|
#include <faiss/utils/simd_impl/super_kmeans_kernels.h>
|
|
@@ -24,7 +19,7 @@ namespace faiss {
|
|
|
24
19
|
namespace detail {
|
|
25
20
|
|
|
26
21
|
inline float block_l2_dispatch(const float* x, const float* y, int n) {
|
|
27
|
-
return
|
|
22
|
+
return with_simd_level_with_sve(
|
|
28
23
|
[&]<SIMDLevel SL>() { return block_l2<SL>(x, y, n); });
|
|
29
24
|
}
|
|
30
25
|
|
|
@@ -16,7 +16,7 @@ namespace detail {
|
|
|
16
16
|
|
|
17
17
|
// Squared L2 over `n` dimensions; n in [1, pdx_block_size].
|
|
18
18
|
// Primary template is the scalar fallback; SIMDLevels without a dedicated
|
|
19
|
-
// specialization (ARM_NEON,
|
|
19
|
+
// specialization (ARM_NEON, NONE, ...) use it directly.
|
|
20
20
|
template <SIMDLevel Level>
|
|
21
21
|
inline float block_l2(const float* x, const float* y, int n) {
|
|
22
22
|
float s = 0.0f;
|
|
@@ -39,5 +39,10 @@ template <>
|
|
|
39
39
|
float block_l2<SIMDLevel::AVX512>(const float* x, const float* y, int n);
|
|
40
40
|
#endif
|
|
41
41
|
|
|
42
|
+
#ifdef COMPILE_SIMD_ARM_SVE
|
|
43
|
+
template <>
|
|
44
|
+
float block_l2<SIMDLevel::ARM_SVE>(const float* x, const float* y, int n);
|
|
45
|
+
#endif
|
|
46
|
+
|
|
42
47
|
} // namespace detail
|
|
43
48
|
} // namespace faiss
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#ifdef COMPILE_SIMD_ARM_SVE
|
|
9
|
+
|
|
10
|
+
#include <faiss/utils/simd_impl/super_kmeans_kernels.h>
|
|
11
|
+
|
|
12
|
+
#include <arm_sve.h>
|
|
13
|
+
|
|
14
|
+
namespace faiss {
|
|
15
|
+
namespace detail {
|
|
16
|
+
|
|
17
|
+
template <>
|
|
18
|
+
float block_l2<SIMDLevel::ARM_SVE>(const float* x, const float* y, int n) {
|
|
19
|
+
svfloat32_t acc = svdup_n_f32(0.0f);
|
|
20
|
+
const int lanes = static_cast<int>(svcntw());
|
|
21
|
+
for (int m = 0; m < n; m += lanes) {
|
|
22
|
+
const svbool_t pg = svwhilelt_b32(m, n);
|
|
23
|
+
const svfloat32_t xv = svld1_f32(pg, x + m);
|
|
24
|
+
const svfloat32_t yv = svld1_f32(pg, y + m);
|
|
25
|
+
const svfloat32_t diff = svsub_f32_x(pg, xv, yv);
|
|
26
|
+
acc = svmla_f32_m(pg, acc, diff, diff);
|
|
27
|
+
}
|
|
28
|
+
return svaddv_f32(svptrue_b32(), acc);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
} // namespace detail
|
|
32
|
+
} // namespace faiss
|
|
33
|
+
|
|
34
|
+
#endif // COMPILE_SIMD_ARM_SVE
|
|
@@ -7,8 +7,15 @@
|
|
|
7
7
|
|
|
8
8
|
#include <faiss/utils/simd_levels.h>
|
|
9
9
|
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <cstdio>
|
|
10
12
|
#include <cstdlib>
|
|
11
13
|
|
|
14
|
+
#if defined(_MSC_VER)
|
|
15
|
+
// __cpuidex, _xgetbv
|
|
16
|
+
#include <intrin.h>
|
|
17
|
+
#endif
|
|
18
|
+
|
|
12
19
|
#include <faiss/impl/FaissAssert.h>
|
|
13
20
|
#include <faiss/impl/simd_dispatch.h>
|
|
14
21
|
|
|
@@ -20,6 +27,20 @@ SIMDLevel SIMDConfig::level = SIMDLevel::NONE;
|
|
|
20
27
|
// Bitmask of supported SIMD levels (1 << SIMDLevel)
|
|
21
28
|
uint64_t SIMDConfig::supported_simd_levels = 0;
|
|
22
29
|
|
|
30
|
+
// Microarchitecture flags (x86). Default false; set by
|
|
31
|
+
// detect_x86_uarch_flags() at load time.
|
|
32
|
+
bool SIMDConfig::avx512_split = false;
|
|
33
|
+
|
|
34
|
+
// Resolved here rather than in the header so that dependents, which never see
|
|
35
|
+
// FAISS_ENABLE_DD, still get the answer for the faiss they link against.
|
|
36
|
+
bool SIMDConfig::has_dynamic_dispatch() {
|
|
37
|
+
#ifdef FAISS_ENABLE_DD
|
|
38
|
+
return true;
|
|
39
|
+
#else
|
|
40
|
+
return false;
|
|
41
|
+
#endif
|
|
42
|
+
}
|
|
43
|
+
|
|
23
44
|
// ARM SVE runtime detection
|
|
24
45
|
#if defined(__aarch64__) || defined(_M_ARM64)
|
|
25
46
|
|
|
@@ -53,11 +74,110 @@ static bool has_sve() {
|
|
|
53
74
|
}
|
|
54
75
|
#endif
|
|
55
76
|
|
|
56
|
-
|
|
77
|
+
namespace {
|
|
57
78
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
//
|
|
79
|
+
#if defined(__x86_64__) || defined(_M_X64)
|
|
80
|
+
|
|
81
|
+
// MSVC and clang-cl do not support GNU-style
|
|
82
|
+
// 64-bit inline assembly, MSVC defines _M_X64 instead of __x86_64__
|
|
83
|
+
|
|
84
|
+
#if defined(_MSC_VER)
|
|
85
|
+
|
|
86
|
+
[[maybe_unused]] void cpuid_count(
|
|
87
|
+
unsigned int leaf,
|
|
88
|
+
unsigned int subleaf,
|
|
89
|
+
unsigned int regs[4]) {
|
|
90
|
+
int r[4];
|
|
91
|
+
__cpuidex(r, static_cast<int>(leaf), static_cast<int>(subleaf));
|
|
92
|
+
for (int i = 0; i < 4; i++) {
|
|
93
|
+
regs[i] = static_cast<unsigned int>(r[i]);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
[[maybe_unused]] uint64_t xgetbv0() {
|
|
98
|
+
return static_cast<uint64_t>(_xgetbv(0));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
#else // GCC / Clang
|
|
102
|
+
|
|
103
|
+
[[maybe_unused]] void cpuid_count(
|
|
104
|
+
unsigned int leaf,
|
|
105
|
+
unsigned int subleaf,
|
|
106
|
+
unsigned int regs[4]) {
|
|
107
|
+
asm volatile("cpuid"
|
|
108
|
+
: "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3])
|
|
109
|
+
: "a"(leaf), "c"(subleaf));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
[[maybe_unused]] uint64_t xgetbv0() {
|
|
113
|
+
unsigned int eax, edx;
|
|
114
|
+
asm volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
|
|
115
|
+
return eax | (static_cast<uint64_t>(edx) << 32);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#endif // _MSC_VER
|
|
119
|
+
|
|
120
|
+
// Detect x86 microarchitecture flags used for kernel routing. Uses raw
|
|
121
|
+
// cpuid so it is safe to run on any CPU regardless of compiled SIMD level.
|
|
122
|
+
void detect_x86_uarch_flags() {
|
|
123
|
+
unsigned int regs[4];
|
|
124
|
+
|
|
125
|
+
// Vendor string (CPUID.0): "AuthenticAMD" is EBX="Auth", EDX="enti",
|
|
126
|
+
// ECX="cAMD".
|
|
127
|
+
cpuid_count(0, 0, regs);
|
|
128
|
+
const bool is_amd = regs[1] == 0x68747541u && regs[3] == 0x69746e65u &&
|
|
129
|
+
regs[2] == 0x444d4163u;
|
|
130
|
+
|
|
131
|
+
// Family/model (CPUID.1 EAX).
|
|
132
|
+
cpuid_count(1, 0, regs);
|
|
133
|
+
const unsigned int eax1 = regs[0];
|
|
134
|
+
const unsigned int base_family = (eax1 >> 8) & 0xfu;
|
|
135
|
+
const unsigned int display_family =
|
|
136
|
+
base_family + (base_family == 0xfu ? ((eax1 >> 20) & 0xffu) : 0u);
|
|
137
|
+
// AMD Zen 4 / Zen 4c (Bergamo) is family 0x19 and splits AVX-512.
|
|
138
|
+
// (Zen 5, family 0x1A, has a native 512-bit datapath and is excluded.)
|
|
139
|
+
SIMDConfig::avx512_split = is_amd && display_family == 0x19u;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#else // Not x86-64
|
|
143
|
+
|
|
144
|
+
void detect_x86_uarch_flags() {}
|
|
145
|
+
|
|
146
|
+
#endif // defined(__x86_64__) || defined(_M_X64)
|
|
147
|
+
|
|
148
|
+
} // namespace
|
|
149
|
+
|
|
150
|
+
/// Must mirror the case labels in with_selected_simd_levels. A static build
|
|
151
|
+
/// defines a COMPILE_SIMD_* macro for every level whose sources it compiles,
|
|
152
|
+
/// not only for SINGLE_SIMD_LEVEL, so this reports a correct set in both
|
|
153
|
+
/// modes and the result is not a single level.
|
|
154
|
+
uint64_t compiled_simd_levels() {
|
|
155
|
+
uint64_t mask = uint64_t(1) << static_cast<int>(SIMDLevel::NONE);
|
|
156
|
+
#ifdef COMPILE_SIMD_AVX2
|
|
157
|
+
mask |= uint64_t(1) << static_cast<int>(SIMDLevel::AVX2);
|
|
158
|
+
#endif
|
|
159
|
+
#ifdef COMPILE_SIMD_AVX512
|
|
160
|
+
mask |= uint64_t(1) << static_cast<int>(SIMDLevel::AVX512);
|
|
161
|
+
#endif
|
|
162
|
+
#ifdef COMPILE_SIMD_AVX512_VPOPCNT
|
|
163
|
+
mask |= uint64_t(1) << static_cast<int>(SIMDLevel::AVX512_VPOPCNT);
|
|
164
|
+
#endif
|
|
165
|
+
#ifdef COMPILE_SIMD_AVX512_SPR
|
|
166
|
+
mask |= uint64_t(1) << static_cast<int>(SIMDLevel::AVX512_SPR);
|
|
167
|
+
#endif
|
|
168
|
+
#ifdef COMPILE_SIMD_ARM_NEON
|
|
169
|
+
mask |= uint64_t(1) << static_cast<int>(SIMDLevel::ARM_NEON);
|
|
170
|
+
#endif
|
|
171
|
+
#ifdef COMPILE_SIMD_ARM_SVE
|
|
172
|
+
mask |= uint64_t(1) << static_cast<int>(SIMDLevel::ARM_SVE);
|
|
173
|
+
#endif
|
|
174
|
+
#ifdef COMPILE_SIMD_RISCV_RVV
|
|
175
|
+
mask |= uint64_t(1) << static_cast<int>(SIMDLevel::RISCV_RVV);
|
|
176
|
+
#endif
|
|
177
|
+
return mask;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
#ifdef FAISS_ENABLE_DD
|
|
61
181
|
|
|
62
182
|
// Static initializer to run constructor at load time
|
|
63
183
|
// NOLINTNEXTLINE(facebook-avoid-non-const-global-variables)
|
|
@@ -71,7 +191,22 @@ SIMDConfig::SIMDConfig(const char** faiss_simd_level_env) {
|
|
|
71
191
|
if (!env_var) {
|
|
72
192
|
level = auto_detect_simd_level();
|
|
73
193
|
} else {
|
|
74
|
-
level
|
|
194
|
+
// Forcing a level the CPU lacks is allowed. Forcing one the binary
|
|
195
|
+
// does not hold is not: dispatch would fall to NONE and skip every
|
|
196
|
+
// level between. Walk down to the nearest compiled level instead.
|
|
197
|
+
const uint64_t compiled = compiled_simd_levels();
|
|
198
|
+
const SIMDLevel requested = to_simd_level(env_var);
|
|
199
|
+
level = requested;
|
|
200
|
+
while (((compiled >> static_cast<int>(level)) & 1) == 0) {
|
|
201
|
+
level = get_simd_fallback(level);
|
|
202
|
+
}
|
|
203
|
+
if (level != requested) {
|
|
204
|
+
fprintf(stderr,
|
|
205
|
+
"faiss: FAISS_SIMD_LEVEL=%s is not compiled into this "
|
|
206
|
+
"build, using %s instead\n",
|
|
207
|
+
to_string(requested).c_str(),
|
|
208
|
+
to_string(level).c_str());
|
|
209
|
+
}
|
|
75
210
|
supported_simd_levels = (1 << static_cast<int>(level));
|
|
76
211
|
}
|
|
77
212
|
supported_simd_levels |= (1 << static_cast<int>(SIMDLevel::NONE));
|
|
@@ -101,80 +236,86 @@ bool SIMDConfig::is_simd_level_available(SIMDLevel l) {
|
|
|
101
236
|
SIMDLevel SIMDConfig::auto_detect_simd_level() {
|
|
102
237
|
SIMDLevel detected_level = SIMDLevel::NONE;
|
|
103
238
|
|
|
104
|
-
|
|
239
|
+
detect_x86_uarch_flags();
|
|
240
|
+
|
|
241
|
+
#if (defined(__x86_64__) || defined(_M_X64)) && \
|
|
105
242
|
(defined(COMPILE_SIMD_AVX2) || defined(COMPILE_SIMD_AVX512))
|
|
106
|
-
unsigned int
|
|
243
|
+
unsigned int regs[4];
|
|
107
244
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
asm volatile("cpuid"
|
|
111
|
-
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
|
|
112
|
-
: "a"(eax), "c"(ecx));
|
|
245
|
+
cpuid_count(1, 0, regs);
|
|
246
|
+
unsigned int ecx1 = regs[2];
|
|
113
247
|
|
|
114
|
-
bool has_avx = (
|
|
248
|
+
bool has_avx = (ecx1 & (1 << 28)) != 0;
|
|
115
249
|
|
|
116
250
|
bool has_xsave_osxsave =
|
|
117
|
-
(
|
|
251
|
+
(ecx1 & ((1 << 26) | (1 << 27))) == ((1 << 26) | (1 << 27));
|
|
118
252
|
|
|
119
253
|
bool avx_supported = false;
|
|
120
254
|
if (has_avx && has_xsave_osxsave) {
|
|
121
|
-
|
|
122
|
-
asm volatile("xgetbv" : "=a"(xcr0), "=d"(edx) : "c"(0));
|
|
123
|
-
avx_supported = (xcr0 & 6) == 6;
|
|
255
|
+
avx_supported = (xgetbv0() & 6) == 6;
|
|
124
256
|
}
|
|
125
257
|
|
|
126
258
|
if (avx_supported) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
259
|
+
cpuid_count(7, 0, regs);
|
|
260
|
+
unsigned int ebx7 = regs[1];
|
|
261
|
+
// EDX of CPUID leaf 7 subleaf 0 carries AVX512_FP16 (bit 23),
|
|
262
|
+
// needed for the SPR detection below. Kept in a local so a later
|
|
263
|
+
// xgetbv cannot clobber it.
|
|
264
|
+
unsigned int cpuid7_edx = regs[3];
|
|
265
|
+
// Leaf 7 subleaf 0, not leaf 1: leaf 1 ECX holds unrelated bits at
|
|
266
|
+
// these positions.
|
|
267
|
+
unsigned int ecx7 = regs[2];
|
|
268
|
+
[[maybe_unused]] bool has_avx512_vnni = (ecx7 & (1 << 11)) != 0;
|
|
269
|
+
[[maybe_unused]] bool has_avx512_vpopcntdq = (ecx7 & (1 << 14)) != 0;
|
|
270
|
+
// Bit 12 = AVX512_BITALG, needed for the byte-wise popcount kernels.
|
|
271
|
+
[[maybe_unused]] bool has_avx512_bitalg = (ecx7 & (1 << 12)) != 0;
|
|
272
|
+
|
|
273
|
+
uint64_t xcr0 = xgetbv0();
|
|
138
274
|
|
|
139
275
|
#if defined(COMPILE_SIMD_AVX2) || defined(COMPILE_SIMD_AVX512)
|
|
140
|
-
bool has_avx2 = (
|
|
276
|
+
bool has_avx2 = (ebx7 & (1 << 5)) != 0;
|
|
141
277
|
if (has_avx2) {
|
|
142
278
|
supported_simd_levels |= (1 << static_cast<int>(SIMDLevel::AVX2));
|
|
143
279
|
detected_level = SIMDLevel::AVX2;
|
|
144
280
|
}
|
|
145
281
|
|
|
146
282
|
#if defined(COMPILE_SIMD_AVX512)
|
|
147
|
-
bool cpu_has_avx512f = (
|
|
283
|
+
bool cpu_has_avx512f = (ebx7 & (1 << 16)) != 0;
|
|
148
284
|
bool os_supports_avx512 = (xcr0 & 0xE0) == 0xE0;
|
|
149
285
|
bool has_avx512f = cpu_has_avx512f && os_supports_avx512;
|
|
150
286
|
if (has_avx512f) {
|
|
151
|
-
bool has_avx512cd = (
|
|
152
|
-
bool has_avx512vl = (
|
|
153
|
-
bool has_avx512dq = (
|
|
154
|
-
bool has_avx512bw = (
|
|
287
|
+
bool has_avx512cd = (ebx7 & (1 << 28)) != 0;
|
|
288
|
+
bool has_avx512vl = (ebx7 & (1 << 31)) != 0;
|
|
289
|
+
bool has_avx512dq = (ebx7 & (1 << 17)) != 0;
|
|
290
|
+
bool has_avx512bw = (ebx7 & (1 << 30)) != 0;
|
|
155
291
|
if (has_avx512bw && has_avx512cd && has_avx512vl && has_avx512dq) {
|
|
156
292
|
detected_level = SIMDLevel::AVX512;
|
|
157
293
|
supported_simd_levels |=
|
|
158
294
|
(1 << static_cast<int>(SIMDLevel::AVX512));
|
|
159
295
|
|
|
296
|
+
#if defined(COMPILE_SIMD_AVX512_VPOPCNT)
|
|
297
|
+
if (has_avx512_vpopcntdq && has_avx512_bitalg) {
|
|
298
|
+
detected_level = SIMDLevel::AVX512_VPOPCNT;
|
|
299
|
+
supported_simd_levels |=
|
|
300
|
+
(1 << static_cast<int>(SIMDLevel::AVX512_VPOPCNT));
|
|
301
|
+
}
|
|
302
|
+
#endif
|
|
303
|
+
|
|
160
304
|
#if defined(COMPILE_SIMD_AVX512_SPR)
|
|
161
305
|
// Check for Sapphire Rapids features.
|
|
162
|
-
// The SPR code path is compiled with
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
306
|
+
// The SPR code path is compiled with AVX512_VNNI, BF16,
|
|
307
|
+
// FP16 and VPOPCNTDQ, and falls back to the VPOPCNT kernels,
|
|
308
|
+
// which need BITALG. All five features are required.
|
|
309
|
+
// AMD Zen 4 has VPOPCNTDQ and BF16 but not FP16, and must
|
|
310
|
+
// remain on the AVX512_VPOPCNT level.
|
|
166
311
|
// CPUID EAX=7, ECX=1: EAX bit 5 = AVX512_BF16
|
|
167
312
|
// CPUID EAX=7, ECX=0: EDX bit 23 = AVX512_FP16
|
|
168
313
|
// (Linux: X86_FEATURE_AVX512_FP16 = 18*32+23)
|
|
169
314
|
bool has_avx512_fp16 = (cpuid7_edx & (1 << 23)) != 0;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
: "=a"(eax1), "=b"(ebx1), "=c"(ecx1), "=d"(edx1)
|
|
175
|
-
: "a"(eax1), "c"(ecx1));
|
|
176
|
-
bool has_avx512_bf16 = (eax1 & (1 << 5)) != 0;
|
|
177
|
-
if (has_avx512_bf16 && has_avx512_fp16) {
|
|
315
|
+
cpuid_count(7, 1, regs);
|
|
316
|
+
const bool has_avx512_bf16 = (regs[0] & (1 << 5)) != 0;
|
|
317
|
+
if (has_avx512_vnni && has_avx512_vpopcntdq &&
|
|
318
|
+
has_avx512_bitalg && has_avx512_bf16 && has_avx512_fp16) {
|
|
178
319
|
detected_level = SIMDLevel::AVX512_SPR;
|
|
179
320
|
supported_simd_levels |=
|
|
180
321
|
(1 << static_cast<int>(SIMDLevel::AVX512_SPR));
|
|
@@ -185,7 +326,7 @@ SIMDLevel SIMDConfig::auto_detect_simd_level() {
|
|
|
185
326
|
#endif // defined(COMPILE_SIMD_AVX512)
|
|
186
327
|
#endif // defined(COMPILE_SIMD_AVX2) || defined(COMPILE_SIMD_AVX512)
|
|
187
328
|
}
|
|
188
|
-
#endif // defined(__x86_64__)
|
|
329
|
+
#endif // defined(__x86_64__) || defined(_M_X64)
|
|
189
330
|
|
|
190
331
|
#ifdef COMPILE_SIMD_ARM_NEON
|
|
191
332
|
// ARM NEON is standard on aarch64
|
|
@@ -264,9 +405,12 @@ bool SIMDConfig::is_simd_level_available(SIMDLevel l) {
|
|
|
264
405
|
}
|
|
265
406
|
|
|
266
407
|
SIMDLevel SIMDConfig::auto_detect_simd_level() {
|
|
408
|
+
detect_x86_uarch_flags();
|
|
267
409
|
// In static mode, return the compiled-in level
|
|
268
410
|
#if defined(COMPILE_SIMD_AVX512_SPR)
|
|
269
411
|
return SIMDLevel::AVX512_SPR;
|
|
412
|
+
#elif defined(COMPILE_SIMD_AVX512_VPOPCNT)
|
|
413
|
+
return SIMDLevel::AVX512_VPOPCNT;
|
|
270
414
|
#elif defined(COMPILE_SIMD_AVX512)
|
|
271
415
|
return SIMDLevel::AVX512;
|
|
272
416
|
#elif defined(COMPILE_SIMD_AVX2)
|
|
@@ -301,6 +445,8 @@ std::string to_string(SIMDLevel level) {
|
|
|
301
445
|
return "AVX2";
|
|
302
446
|
case SIMDLevel::AVX512:
|
|
303
447
|
return "AVX512";
|
|
448
|
+
case SIMDLevel::AVX512_VPOPCNT:
|
|
449
|
+
return "AVX512_VPOPCNT";
|
|
304
450
|
case SIMDLevel::AVX512_SPR:
|
|
305
451
|
return "AVX512_SPR";
|
|
306
452
|
case SIMDLevel::ARM_NEON:
|
|
@@ -325,6 +471,9 @@ SIMDLevel to_simd_level(const std::string& level_str) {
|
|
|
325
471
|
if (level_str == "AVX512") {
|
|
326
472
|
return SIMDLevel::AVX512;
|
|
327
473
|
}
|
|
474
|
+
if (level_str == "AVX512_VPOPCNT") {
|
|
475
|
+
return SIMDLevel::AVX512_VPOPCNT;
|
|
476
|
+
}
|
|
328
477
|
if (level_str == "AVX512_SPR") {
|
|
329
478
|
return SIMDLevel::AVX512_SPR;
|
|
330
479
|
}
|