将代码转换为 Neon 程序集

Posted

技术标签:

【中文标题】将代码转换为 Neon 程序集【英文标题】:Convert code to Neon assembly 【发布时间】:2012-07-05 07:34:00 【问题描述】:

我正在将下面的代码翻译成 Neon Assembly。任何帮助将不胜感激。

void sum(int length, int *a, int *b, int *c, int *d, char *result)

   int i;

   for (i = 0; i < length; i++)
      
          int sum = (a[i] + b[i] + c[i] + d[i])/4;
          if (sum > threshold)
             result[i] = 1;
          else
             result[i] = 0;
      

实际代码是一个图像二值化算法。上面的代码只是为了演示这个想法,而不是让简单的事情变得更复杂。

【问题讨论】:

你不能只通过编译器运行它吗? 只需打开编译器上的开关即可生成程序集,然后将该输出转换为 Neon 程序集 【参考方案1】:

这是一个相当简单的实现。请注意,我们将划分和阈值测试转换为仅针对threshold * 4 的测试(以消除划分):

void sum(const int n, const int32_t *a, const int32_t *b, const int32_t *c, const int32_t *d, int32_t *result)

   const int32_t threshold4 = threshold * 4;
   const int32x4_t vthreshold4 =  threshold4, threshold4, threshold4, threshold4 ;
   const uint32x4_t vk1 =  1, 1, 1, 1 ;
   int i;

   for (i = 0; i < n; i += 4)
   
      int32x4_t va = vld1q_s32(&a[i]);    // load values from a, b, c, d
      int32x4_t vb = vld1q_s32(&b[i]);
      int32x4_t vc = vld1q_s32(&c[i]);
      int32x4_t vd = vld1q_s32(&d[i]);

      int32x4_t vsum = vaddq_s32(va, vb); // sum values form a, b, c, d
      vsum = vaddq_s32(vsum, vc);
      vsum = vaddq_s32(vsum, vd);

      uint32x4_t vcmp = vcgtq_s32(vsum, vthreshold4);
                                          // compare with threshold * 4
      int32x4_t vresult = (int32x4_t)vandq_u32(vcmp, vk1);
                                          // convert result to 0/1
      vst1q_s32(&result[i], vresult);     // store result
   

注意事项:

完全未经测试的代码 - 可能需要进一步的工作 result 已更改为 int32_t * - 打包到 uint8_t 并不难,但它为这个初始示例增加了很多复杂性,所以我想我现在应该保持简单 abcdresult都需要16字节对齐 n 需要是 4 的倍数 abcd 的总和需要适合 32 位有符号整数 threshold * 4 需要适应 32 位有符号整数

【讨论】:

谢谢你,保罗。因为源是灰度图像,所以我需要将 uchar 加载到 int32x4_t 值中。我正在考虑使用 int32x4_t input = vshrn_n_u32(source, 24) // source 是 uint8_t。你能告诉我你是怎么收拾行李的吗? 要压缩到 8 位,您需要使用 4 x 4 x 32 位向量并使用 vmovn_xxx 或 vpadd_xxx 指令先压缩到 2 x 8 x 16 位向量,然后再压缩到单个 16 x 8 位向量。 谢谢@paul-r。实际上,我们是从 q(128 位)寄存器打包到 d(64 位)寄存器,所以我认为它应该是 2x32x4 -> 2x16x4 -> 8x8 向量。我仍在努力实现这一点(我对 Neon 完全陌生,所以花了我很多时间) @PaulR - 有什么办法可以加快这些初始化:int32x4_t vthreshold4 = threshold4, threshold4, threshold4, threshold4 uint32x4_t vk1 = 1, 1, 1, 1 。由于算法规范(BLAKE2 加密哈希),我在关键代码路径上有一个函数必须多次执行。 @jww:编译器应该足够聪明,可以将诸如此类的常量从任何封闭循环中提升出来,即使它来自内联函数 - 你检查过生成的代码吗?如果做不到这一点,您可以将初始化的常量作为参数传递给函数。

以上是关于将代码转换为 Neon 程序集的主要内容,如果未能解决你的问题,请参考以下文章

Android 将 C++ 转换/编译为 Neon

Armv8a NEON 内联汇编代码:如何将 16x8 位向量转换为四个 4x32 位(整数)向量?

将 C 代码转换为 Web 程序集时出错

从 SSE 到 ARM Neon 的指令转换

使用 ARM neon 内部函数进行深度转换

将 C 代码转换为 x86-64 位程序集?