霓虹灯等效于 mm_madd_epi16 和 mm_maddubs_epi16
Posted
技术标签:
【中文标题】霓虹灯等效于 mm_madd_epi16 和 mm_maddubs_epi16【英文标题】:Neon equivalent of mm_madd_epi16 and mm_maddubs_epi16 【发布时间】:2021-10-21 09:48:19 【问题描述】:我正在尝试将 SSE 中的代码移植到 Neon。
我找不到 mm_maddubs_epi16 和 mm_madd_epi16 的等效内在函数。
关于 Neon 的这些内在函数的任何见解。
【问题讨论】:
您将它们用于什么样的用例?作为扩大水平总和的一部分?或者两个输入都不是常数的东西,你实际上需要扩大产品以及水平添加对的一个步骤? 我的输入是非恒定的,我需要扩大产品以及水平添加对的一个步骤。 【参考方案1】:您可能想查看_mm_madd_epi16
和 _mm_maddubs_epi16
的 SIMDe 实现(请注意未来的读者:您可能需要检查这些文件的最新版本,因为 SIMDe 中的实现有时会得到改进,而且我不太可能会记得更新这个答案)。这些实现只是从那里复制过来的。
如果您在 AArch64 上,对于 _mm_madd_epi16
,您可能希望使用 vmull_s16
+vget_low_s16
作为低半部分,vmull_high_s16
作为高半部分,然后使用 vpaddq_s32
将它们加在一起成 128 位结果。如果没有 AArch64,您将需要两个 vmull_s16
调用(一个带有 vget_low_s16
,一个带有 vget_high_s16
),但由于不支持 vpaddq_s32
,您需要两个带有 vcombine_s32
的 vpadd_s32
调用:
#if defined(SIMDE_ARM_NEON_A64V8_NATIVE)
int32x4_t pl = vmull_s16(vget_low_s16(a_.neon_i16), vget_low_s16(b_.neon_i16));
int32x4_t ph = vmull_high_s16(a_.neon_i16, b_.neon_i16);
r_.neon_s32 = vpaddq_s32(pl, ph);
#elif defined(SIMDE_ARM_NEON_A32V7_NATIVE)
int32x4_t pl = vmull_s16(vget_low_s16(a_.neon_i16), vget_low_s16(b_.neon_i16));
int32x4_t ph = vmull_s16(vget_high_s16(a_.neon_i16), vget_high_s16(b_.neon_i16));
int32x2_t rl = vpadd_s32(vget_low_s32(pl), vget_high_s32(pl));
int32x2_t rh = vpadd_s32(vget_low_s32(ph), vget_high_s32(ph));
r_.neon_i32 = vcombine_s32(rl, rh);
#endif
对于_mm_maddubs_epi16
,它有点复杂,但我不认为特定于 AArch64 的版本会有多大用处:
/* Zero extend a */
int16x8_t a_odd = vreinterpretq_s16_u16(vshrq_n_u16(a_.neon_u16, 8));
int16x8_t a_even = vreinterpretq_s16_u16(vbicq_u16(a_.neon_u16, vdupq_n_u16(0xff00)));
/* Sign extend by shifting left then shifting right. */
int16x8_t b_even = vshrq_n_s16(vshlq_n_s16(b_.neon_i16, 8), 8);
int16x8_t b_odd = vshrq_n_s16(b_.neon_i16, 8);
/* multiply */
int16x8_t prod1 = vmulq_s16(a_even, b_even);
int16x8_t prod2 = vmulq_s16(a_odd, b_odd);
/* saturated add */
r_.neon_i16 = vqaddq_s16(prod1, prod2);
【讨论】:
以上是关于霓虹灯等效于 mm_madd_epi16 和 mm_maddubs_epi16的主要内容,如果未能解决你的问题,请参考以下文章