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

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

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

cyvaqqii

cyvaqqii1#

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

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

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

  1. a = vpmaxq_s16(a, a);
  2. a = vpmaxq_s16(a, a);
  3. a = vpmaxq_s16(a, a);

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

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

两次迭代的示例运行

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

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

展开查看全部

相关问题