c++ ARM neon Intrisics:使用vmaxvq_s16()是在int16x8向量中找到max值的最快方法吗?

enyaitl3  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(194)

我想知道是否有人找到了一种比使用vmaxvq_s16() ARM neon Intrisic更有效(更快)的方法来查找int16x8向量中的最大值。
例如,我试图从做一些矢量化比较中受益,但无法通过使用上面的intrisic更快地找到解决方案。

cyvaqqii

cyvaqqii1#

正如评论中所指出的,vmaxvq的实现有相当多的延迟,甚至没有双重问题,但典型的替代方案甚至更糟。

a = vmaxq_s16(a, vextq_s16(a,a,1));
   a = vmaxq_s16(a, vextq_s16(a,a,2));
   a = vmaxq_s16(a, vextq_s16(a,a,4));

然而,ARM64通常更有效地实现成对最大值,允许

a = vpmaxq_s16(a, a);
   a = vpmaxq_s16(a, a);
   a = vpmaxq_s16(a, a);

如果原来的问题不允许重组纯垂直操作,仍然有可能摊销并行的最大操作。

// the two first elements here will be garbage
   int16_t buffer[N + 2];
   auto A = vdupq_n_s16(0);
   for (int i = 0; i < N; i++) {
       int16x8_t x = my_algorithm();
       A = vpmaxq_s16(A, x);  // <- just a single fast vpmax per iteration
       vst1q_lane_s16(buffer + i, A, 1);
   }
   // you need two more iterations to finish the pairwise horizontal
   // maximums that are partially stored in A
   for (int i = N; i < N + 2; i++) {
      A = vpmaxq_s16(A, A);
      vst1q_lane_s16(buffer + i, A, 1);
   }

两次迭代的示例运行

A = 0   0   0   0   0   0   0   0,   v_0 = 1 2 3 1 2 3 1 2
   A = 0   0   0   0   3   4   5   3,   v_1 = 0 1 0 2 3 2 0 0
   A = 0   0  3+4 5+3 0+1 0+2 3+2 0+0,  v_2 = ? ? ? ? ? ? ? ?
   -----------------
   A = 0  [15] 3   5.  ?   ?   ?   ?    [15 = 1+2+3+1+2+3+1+2]
   A = 15 [ 8] ?   ?   ?   ?   ?   ?    [8  = 0+1+0+2+3+2+0+0]

第一个元素A[0]将btw累加所有元素的总最大值。

相关问题