将 q 寄存器中的 128 位数据转换(求和)为 16 位数据的高效算法

Posted

技术标签:

【中文标题】将 q 寄存器中的 128 位数据转换(求和)为 16 位数据的高效算法【英文标题】:Efficient algorithm to convert(sum) 128-bit data in q-register to 16-bit data 【发布时间】:2012-08-04 10:33:20 【问题描述】:

我在 q-register 中有 128 位数据。我想对这个 q 寄存器中的单个 16 位块求和,最终得到一个 16 位的最终总和(任何超过 16 位的进位都应该被添加到这个 16 位数字的 LSB 中)。

我想要实现的是:

VADD.U16(一些 16 位变量)q0[0] q0[1] q0[2] ......... q0[7]

但使用内在函数,

如果有人能给我一个算法,将不胜感激。

我尝试使用成对加法,但我最终得到了一个相当笨拙的解决方案..

下面是它的外观:

int convert128to16(uint16x8_t data128)

    uint16_t data16 = 0;
    uint16x4_t ddata;
    print16(data128);

    uint32x4_t data = vpaddlq_u16(data128);
    print32(data);

    uint16x4_t data_hi = vget_high_u16(data);
    print16x4(data_hi);

    uint16x4_t data_low = vget_low_u16(data);
    print16x4(data_low);

    ddata = vpadd_u16( data_hi, data_low);
    print16x4(ddata);

它仍然不完整且有点笨拙。任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

可以使用横向添加指令:

这是一个片段:

  uint16x8_t input = /* load your data128 here */

  uint64x2_t temp   = vpaddlq_u32 (vpaddlq_u16 (input)); 

  uint64x1_t result = vadd_u64 (vget_high_u64 (temp), 
                                vget_low_u64  (temp));


  // result now contains the sum of all 16 bit unsigned words
  // stored in data128. 

  // to add the values that overflow from 16 bit just do another 16 bit
  // horizontal addition and return the lowest 16 bit as the final result:

 uint16x4_t w = vpadd_u16 (
     vreinterpret_u16_u64 (result),                              
     vreinterpret_u16_u64 (result));

 uint16_t wrappedResult = vget_lane_u16 (w, 0);

【讨论】:

谢谢 Nils,那额外的步骤是什么?如果我必须将此结果收集到某个变量中,以便从函数返回,我将如何做到这一点?你能扩展到同一段代码吗? 非常感谢,这可以作为我许多其他任务的参考。再次感谢..【参考方案2】:

如果您的目标是对 16 位块(模 16 位)求和,则可以使用以下片段:

uin16_t convert128to16(uint16x8_t data128)

  data128 += (data128 >> 64);

  data128 += (data128 >> 32);

  data128 += (data128 >> 16);

  return data128 & 0xffff;


【讨论】:

感谢您的帮助@wildplasser,但我正在寻找使用内在函数在霓虹灯上工作的代码。你的解决方案看起来很一般。如果我错了,请纠正我 是的,它是通用的。但是,如果你有一个 C 编译器,也许它足够聪明,可以找到(高度具体的)指令。但是,如果我理解正确,架构/编译器已经有一种机制将宽寄存器视为较小寄存器的“数组”。聪明的编译器会知道这一点。 同意,但我目前需要的是内在函数,我想从内在函数生成程序集并优化是一个更好的选择。比直接从 C 源代码生成/优化霓虹灯代码?这不是真的吗?

以上是关于将 q 寄存器中的 128 位数据转换(求和)为 16 位数据的高效算法的主要内容,如果未能解决你的问题,请参考以下文章

NEON:如何将 128 位 ARGB 转换为具有饱和度的 32 位 ARGB?

如何将一个 XMM 128 位寄存器拆分为两个 64 位整数寄存器?

存储介于-64(十六进制)和128(十六进制)之间的值所需的最小寄存器长度?

NEON:将 uint8_t 数组加载到 128 位寄存器中

用 YMM 向量寄存器求和 vec4[idx[i]] * scalar[i]

如何将两个打包的 64 位四字加载到 128 位 xmm 寄存器中