Skip to content

Commit 3b50bab

Browse files
ihb2032meta-codesync[bot]
authored andcommitted
Optimize RVV batch-4 distance kernels (#5469)
Summary: Summary This PR refactors the RVV distance implementation and adds native vectorized batch-4 kernels for inner product and squared L2 distance. Pull Request resolved: #5469 Reviewed By: alibeklfc Differential Revision: D114382677 Pulled By: mnorris11 fbshipit-source-id: c55354c296c1c9c96a8e6cec9388fb3514773218
1 parent b3942ab commit 3b50bab

1 file changed

Lines changed: 93 additions & 55 deletions

File tree

faiss/utils/simd_impl/distances_rvv.cpp

Lines changed: 93 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,42 @@
1616

1717
namespace faiss {
1818

19+
template <typename Vec, typename Reduce>
20+
static inline float rvv_reduce(
21+
Vec value,
22+
size_t vl,
23+
float identity,
24+
Reduce reduce) {
25+
vfloat32m1_t init = __riscv_vfmv_s_f_f32m1(identity, 1);
26+
vfloat32m1_t result = reduce(value, init, vl);
27+
return __riscv_vfmv_f_s_f32m1_f32(result);
28+
}
29+
30+
static inline size_t rvv_argmin(const float* values, size_t n) {
31+
size_t vlmax = __riscv_vsetvlmax_e32m8();
32+
vfloat32m8_t vmin = __riscv_vfmv_v_f_f32m8(__builtin_inff(), vlmax);
33+
size_t i = 0;
34+
while (i < n) {
35+
size_t vl = __riscv_vsetvl_e32m8(n - i);
36+
vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
37+
vmin = __riscv_vfmin_vv_f32m8_tu(vmin, vmin, vd, vl);
38+
i += vl;
39+
}
40+
float min_val = rvv_reduce(
41+
vmin, vlmax, __builtin_inff(), __riscv_vfredmin_vs_f32m8_f32m1);
42+
i = 0;
43+
while (i < n) {
44+
size_t vl = __riscv_vsetvl_e32m8(n - i);
45+
vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
46+
long j = __riscv_vfirst_m_b4(
47+
__riscv_vmfeq_vf_f32m8_b4(vd, min_val, vl), vl);
48+
if (j >= 0)
49+
return i + static_cast<size_t>(j);
50+
i += vl;
51+
}
52+
return n;
53+
}
54+
1955
template <>
2056
float fvec_norm_L2sqr<SIMDLevel::RISCV_RVV>(const float* x, size_t d) {
2157
size_t vlmax = __riscv_vsetvlmax_e32m8();
@@ -27,9 +63,7 @@ float fvec_norm_L2sqr<SIMDLevel::RISCV_RVV>(const float* x, size_t d) {
2763
acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vx, vl);
2864
i += vl;
2965
}
30-
vfloat32m1_t sum = __riscv_vfmv_s_f_f32m1(0.0f, 1);
31-
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
32-
return __riscv_vfmv_f_s_f32m1_f32(sum);
66+
return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
3367
}
3468

3569
template <>
@@ -48,9 +82,7 @@ float fvec_L2sqr<SIMDLevel::RISCV_RVV>(
4882
acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vx, vl);
4983
i += vl;
5084
}
51-
vfloat32m1_t sum = __riscv_vfmv_s_f_f32m1(0.0f, 1);
52-
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
53-
return __riscv_vfmv_f_s_f32m1_f32(sum);
85+
return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
5486
}
5587

5688
template <>
@@ -68,9 +100,7 @@ float fvec_inner_product<SIMDLevel::RISCV_RVV>(
68100
acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vy, vl);
69101
i += vl;
70102
}
71-
vfloat32m1_t sum = __riscv_vfmv_s_f_f32m1(0.0f, 1);
72-
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
73-
return __riscv_vfmv_f_s_f32m1_f32(sum);
103+
return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
74104
}
75105

76106
template <>
@@ -87,9 +117,7 @@ float fvec_L1<SIMDLevel::RISCV_RVV>(const float* x, const float* y, size_t d) {
87117
acc = __riscv_vfadd_vv_f32m8_tu(acc, acc, vx, vl);
88118
i += vl;
89119
}
90-
vfloat32m1_t sum = __riscv_vfmv_s_f_f32m1(0.0f, 1);
91-
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
92-
return __riscv_vfmv_f_s_f32m1_f32(sum);
120+
return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
93121
}
94122

95123
template <>
@@ -109,9 +137,7 @@ float fvec_Linf<SIMDLevel::RISCV_RVV>(
109137
vmax = __riscv_vfmax_vv_f32m8_tu(vmax, vmax, vx, vl);
110138
i += vl;
111139
}
112-
vfloat32m1_t max = __riscv_vfmv_s_f_f32m1(0.0f, 1);
113-
max = __riscv_vfredmax_vs_f32m8_f32m1(vmax, max, vlmax);
114-
return __riscv_vfmv_f_s_f32m1_f32(max);
140+
return rvv_reduce(vmax, vlmax, 0.0f, __riscv_vfredmax_vs_f32m8_f32m1);
115141
}
116142

117143
template <>
@@ -126,10 +152,29 @@ void fvec_inner_product_batch_4<SIMDLevel::RISCV_RVV>(
126152
float& dis1,
127153
float& dis2,
128154
float& dis3) {
129-
dis0 = fvec_inner_product<SIMDLevel::RISCV_RVV>(x, y0, d);
130-
dis1 = fvec_inner_product<SIMDLevel::RISCV_RVV>(x, y1, d);
131-
dis2 = fvec_inner_product<SIMDLevel::RISCV_RVV>(x, y2, d);
132-
dis3 = fvec_inner_product<SIMDLevel::RISCV_RVV>(x, y3, d);
155+
size_t vlmax = __riscv_vsetvlmax_e32m4();
156+
vfloat32m4_t vacc0 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
157+
vfloat32m4_t vacc1 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
158+
vfloat32m4_t vacc2 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
159+
vfloat32m4_t vacc3 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
160+
size_t i = 0;
161+
while (i < d) {
162+
size_t vl = __riscv_vsetvl_e32m4(d - i);
163+
vfloat32m4_t vx = __riscv_vle32_v_f32m4(x + i, vl);
164+
vfloat32m4_t vy = __riscv_vle32_v_f32m4(y0 + i, vl);
165+
vacc0 = __riscv_vfmacc_vv_f32m4_tu(vacc0, vx, vy, vl);
166+
vy = __riscv_vle32_v_f32m4(y1 + i, vl);
167+
vacc1 = __riscv_vfmacc_vv_f32m4_tu(vacc1, vx, vy, vl);
168+
vy = __riscv_vle32_v_f32m4(y2 + i, vl);
169+
vacc2 = __riscv_vfmacc_vv_f32m4_tu(vacc2, vx, vy, vl);
170+
vy = __riscv_vle32_v_f32m4(y3 + i, vl);
171+
vacc3 = __riscv_vfmacc_vv_f32m4_tu(vacc3, vx, vy, vl);
172+
i += vl;
173+
}
174+
dis0 = rvv_reduce(vacc0, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
175+
dis1 = rvv_reduce(vacc1, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
176+
dis2 = rvv_reduce(vacc2, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
177+
dis3 = rvv_reduce(vacc3, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
133178
}
134179

135180
template <>
@@ -144,10 +189,33 @@ void fvec_L2sqr_batch_4<SIMDLevel::RISCV_RVV>(
144189
float& dis1,
145190
float& dis2,
146191
float& dis3) {
147-
dis0 = fvec_L2sqr<SIMDLevel::RISCV_RVV>(x, y0, d);
148-
dis1 = fvec_L2sqr<SIMDLevel::RISCV_RVV>(x, y1, d);
149-
dis2 = fvec_L2sqr<SIMDLevel::RISCV_RVV>(x, y2, d);
150-
dis3 = fvec_L2sqr<SIMDLevel::RISCV_RVV>(x, y3, d);
192+
size_t vlmax = __riscv_vsetvlmax_e32m4();
193+
vfloat32m4_t vacc0 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
194+
vfloat32m4_t vacc1 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
195+
vfloat32m4_t vacc2 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
196+
vfloat32m4_t vacc3 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
197+
size_t i = 0;
198+
while (i < d) {
199+
size_t vl = __riscv_vsetvl_e32m4(d - i);
200+
vfloat32m4_t vx = __riscv_vle32_v_f32m4(x + i, vl);
201+
vfloat32m4_t vy = __riscv_vle32_v_f32m4(y0 + i, vl);
202+
vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
203+
vacc0 = __riscv_vfmacc_vv_f32m4_tu(vacc0, vy, vy, vl);
204+
vy = __riscv_vle32_v_f32m4(y1 + i, vl);
205+
vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
206+
vacc1 = __riscv_vfmacc_vv_f32m4_tu(vacc1, vy, vy, vl);
207+
vy = __riscv_vle32_v_f32m4(y2 + i, vl);
208+
vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
209+
vacc2 = __riscv_vfmacc_vv_f32m4_tu(vacc2, vy, vy, vl);
210+
vy = __riscv_vle32_v_f32m4(y3 + i, vl);
211+
vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
212+
vacc3 = __riscv_vfmacc_vv_f32m4_tu(vacc3, vy, vy, vl);
213+
i += vl;
214+
}
215+
dis0 = rvv_reduce(vacc0, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
216+
dis1 = rvv_reduce(vacc1, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
217+
dis2 = rvv_reduce(vacc2, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
218+
dis3 = rvv_reduce(vacc3, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
151219
}
152220

153221
template <>
@@ -168,9 +236,8 @@ void fvec_L2sqr_ny_transposed<SIMDLevel::RISCV_RVV>(
168236
acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vx, vl);
169237
i += vl;
170238
}
171-
vfloat32m1_t sum = __riscv_vfmv_s_f_f32m1(0.0f, 1);
172-
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
173-
float x_sqlen = __riscv_vfmv_f_s_f32m1_f32(sum);
239+
float x_sqlen =
240+
rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
174241
i = 0;
175242
while (i < ny) {
176243
size_t vl = __riscv_vsetvl_e32m8(ny - i);
@@ -214,35 +281,6 @@ void fvec_L2sqr_ny<SIMDLevel::RISCV_RVV>(
214281
}
215282
}
216283

217-
// Index of the first element equal to the minimum of values[0..n), or n when
218-
// there is none (e.g. n == 0). Shared by the *_nearest and madd_and_argmin
219-
// kernels so the vfmin/vfredmin/vfirst sequence lives in one place.
220-
static size_t rvv_argmin(const float* values, size_t n) {
221-
size_t vlmax = __riscv_vsetvlmax_e32m8();
222-
vfloat32m8_t vmin = __riscv_vfmv_v_f_f32m8(__builtin_inff(), vlmax);
223-
size_t i = 0;
224-
while (i < n) {
225-
size_t vl = __riscv_vsetvl_e32m8(n - i);
226-
vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
227-
vmin = __riscv_vfmin_vv_f32m8_tu(vmin, vmin, vd, vl);
228-
i += vl;
229-
}
230-
vfloat32m1_t rmin = __riscv_vfmv_s_f_f32m1(__builtin_inff(), 1);
231-
rmin = __riscv_vfredmin_vs_f32m8_f32m1(vmin, rmin, vlmax);
232-
float min_val = __riscv_vfmv_f_s_f32m1_f32(rmin);
233-
i = 0;
234-
while (i < n) {
235-
size_t vl = __riscv_vsetvl_e32m8(n - i);
236-
vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
237-
long j = __riscv_vfirst_m_b4(
238-
__riscv_vmfeq_vf_f32m8_b4(vd, min_val, vl), vl);
239-
if (j >= 0)
240-
return i + static_cast<size_t>(j);
241-
i += vl;
242-
}
243-
return n;
244-
}
245-
246284
template <>
247285
size_t fvec_L2sqr_ny_nearest<SIMDLevel::RISCV_RVV>(
248286
float* distances_tmp_buffer,

0 commit comments

Comments
 (0)