将 SSE2 迁移到 Arm NEON 内部函数

Posted

技术标签:

【中文标题】将 SSE2 迁移到 Arm NEON 内部函数【英文标题】:Migrate SSE2 to Arm NEON intrinsincs 【发布时间】:2011-09-26 12:42:00 【问题描述】:

我在 SSE2 intrinsincs 中有以下代码。它处理来自 Kinect 的输入。

__m128i md = _mm_setr_epi16((r0<<3)  | (r1>>5), ((r1<<6)  | (r2>>2) ), ((r2<<9)  | (r3<<1) | (r4>>7) ), ((r4<<4)  | (r5>>4) ), ((r5<<7)  | (r6>>1) ),((r6<<10) | (r7<<2) | (r8>>6) ), ((r8<<5)  | (r9>>3) ), ((r9<<8)  | (r10)   ));
md = _mm_and_si128(md, mmask);
__m128i mz = _mm_load_si128((__m128i *) &depth_ref_z[i]);
__m128i mZ = _mm_load_si128((__m128i *) &depth_ref_Z[i]);
mz = _mm_cmpgt_epi16(md, mz);
mZ = _mm_cmpgt_epi16(mZ, md);
mz = _mm_and_si128(mz, mZ);
md = _mm_and_si128(mz, md);
_mm_store_si128((__m128i *) frame,md)
if(_mm_movemask_epi8(mz)) ... 

这基本上将 11 uint8_t (r0-r10​​) 解压缩到 SSE 寄存器中的 8 uint16_t (mmask 是常量并且之前创建的)。然后,它从两个用作边界的数组中加载两个具有相应元素的寄存器。它检查它们并创建一个寄存器,其中将不符合标准的元素清零。然后它存储它们并进一步处理每个元素。当没有元素通过时,移动掩码可以作为一个很好的优化,在这种情况下可以跳过处理。

这很好用,现在我也想将它移植到 NEON。除了两部分外,大部分内容都很简单。查看 SSE2 代码中的汇编器输出(gcc),我发现不是在 _mm_setr_epi16 中进行 8 次 uint16_t 移动,而是将它们移动并 ors 到 uint32_t 中,最后进行 4 次移动。这似乎很有效,因为编译器会处理它,所以我没有更改代码。我应该在 NEON 案例中手动应用它吗?而不是 8 个 vsetq_lane_u16 进行移位并执行 4 个 vsetq_lane_u32?我会遇到字节序问题吗?是否值得?

最后一部分是移动蒙版,因为我找不到对应的。任何人都可以提出一些建议吗?

【问题讨论】:

【参考方案1】:

我更喜欢从纯 C 代码而不是 SSE2 开始;在这个低级别可能不容易看到优化机会

【讨论】:

以上是关于将 SSE2 迁移到 Arm NEON 内部函数的主要内容,如果未能解决你的问题,请参考以下文章

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

ARM NEON指令集总结

ARM NEON 内部函数将 D(64 位)寄存器转换为 Q(128 位)寄存器的低半部分,而上半部分未定义

使用 ARM NEON 执行比 C 代码需要更长的时间

SAD 16*4 的 Arm-neon 优化版本未提供预期增益

将 SSE2 和 AVX 内部函数与不同的编译器混合