用于 C++/SSE 代码的高效 NEON 内在函数

Efficient NEON intrinsics for C++/SSE code

如何高效地将以下代码片段转换为 NEON 内在函数?

C++

int diff_scale, c0, c1;
cost = (short)(cost + std::min(c0, c1) >> diff_scale));

上交所

__m128i ds = _mm_cvtsi32_si128(diff_scale);
__m128i c0 = _mm_load_si128((__m128i*)(cost));
__m128i c1 = _mm_load_si128((__m128i*)(cost + 8));
__m128i z = _mm_setzero_si128();    
_mm_store_si128((__m128i*)(cost), _mm_adds_epi16(c0, _mm_srl_epi16(_mm_unpacklo_epi8(diff, z), ds)));
_mm_store_si128((__m128i*)(cost + 8), _mm_adds_epi16(c1, _mm_srl_epi16(_mm_unpackhi_epi8(diff, z), ds)));

SSE 看起来应该是这样的:

int8x16_t ds = vdupq_n_s8(-diff_scale);
int16x8_t c0 = vld1q_s16(cost);
int16x8_t c1 = vld1q_s16(cost + 8);
uint8x16_t diff_ds = vshlq_u8(diff, ds);
#if defined(MAY_SATURATE)
vst1q_s16(cost,     vqaddq_s16(c0, vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(diff_ds)))));
vst1q_s16(cost + 8, vqaddq_s16(c1, vreinterpretq_s16_u16(vmovl_u8(vget_high_s8(diff_ds)))));
#else
vst1q_s16(cost,     vreinterpretq_s16_u16(vaddw_u16(vreinterpretq_u16_s16(c0), vget_low_u8(diff_ds))));
vst1q_s16(cost + 8, vreinterpretq_s16_u16(vaddw_u16(vreinterpretq_u16_s16(c1), vget_high_s8(diff_ds))));
#endif

C++ 需要对向量进行某种外推...可能是这样的?:

int diff_scale, c0[8], c1[8];
int32x4_t ds = vdupq_n_s32(-diff_scale);
int32x4_t c0lo = vld1q_s32(c0);
int32x4_t c0hi = vld1q_s32(c0 + 4);
int32x4_t c1lo = vld1q_s32(c1);
int32x4_t c1hi = vld1q_s32(c1 + 4);
int16x8_t c = vld1q_s16(cost);
c0lo = vshlq_s32(vaddw_s32(vminq_s32(c0lo, c1lo), vget_low_s16(c), ds);
c0hi = vshlq_s32(vaddw_s32(vminq_s32(c0hi, c1hi), vget_high_s16(c), ds);
vst1q_s16(cost, vcombine_s16(vmovn_s16(c0lo), vmovn_s16(c0hi)));

如果 diff_scale 是一个常量,则改为:

const int diff_scale = 1;
int c0[8], c1[8];
int32x4_t c0lo = vld1q_s32(c0);
int32x4_t c0hi = vld1q_s32(c0 + 4);
int32x4_t c1lo = vld1q_s32(c1);
int32x4_t c1hi = vld1q_s32(c1 + 4);
int16x8_t c = vld1q_s16(cost);
c = vcombine_s16(vshrn_n_s32(vaddw_s32(vminq_s32(c0lo, c1lo), vget_low_s16(c), diff_scale),
                 vshrn_n_s32(vaddw_s32(vminq_s32(c0hi, c1hi), vget_high_s16(c), diff_scale));
vst1q_s16(cost, c);

虽然这些看起来都可以通过更多上下文变得更简单。