NEON:将 int8x16_t 拆包成一对 int16x8 并将一对 int16x8_t 打包成 int8x16_t

Posted

技术标签:

【中文标题】NEON:将 int8x16_t 拆包成一对 int16x8 并将一对 int16x8_t 打包成 int8x16_t【英文标题】:NEON: Unpacking int8x16_t into a pair of int16x8 & packing a pair of int16x8_t into a int8x16_t 【发布时间】:2019-08-05 17:39:23 【问题描述】:

我正在为我制作的算法的 arm64 实现 NEON 版本。

我面临的问题是:

- 如何将 int8x16 解压缩为两个 int16x8_t,这意味着字节有点“投射”到短裤?- 如何将这两个 @987654326 打包@回到int8x16_t

我尝试这样做的原因是对几个矢量化短裤应用操作,不会溢出,最后将结果打包回int8x16_t

这是我针对这个问题的 SSE2 实现:

SSE2 开箱:

__m128i a1 = _mm_srai_epi16(_mm_unpacklo_epi8(input, input), 8);
__m128i a2 = _mm_srai_epi16(_mm_unpackhi_epi8(input, input), 8);

SSE2 包装:

__m128i output = _mm_packs_epi16(a1, a2);

【问题讨论】:

您可能已经知道这一点,但对于 x86 SSE4.1,您将使用 pmovsx (cvtepi8_epi16(input)) 作为下半部分。您正在实施的操作是“符号扩展”,因此为将来的搜索者提及这一点很有帮助。 @PeterCordes 是的,我知道,但感谢您的精确,它总能提供帮助! 相关:Loading 8-bit values using NEON/ARM 表明 ARM SIMD 具有扩展的 add/sub,如果它可以满足您的要求,它可能比首先进行符号扩展更有效。 【参考方案1】:

你可以做到,例如像这样的内在函数:

#include <stdint.h>
#include <arm_neon.h>

void func(int8_t *buf) 
    int8x16_t vec = vld1q_s8(buf); // load 16x int8_t
    int16x8_t short1 = vmovl_s8(vget_low_s8(vec)); // cast the first 8x int8_t to int16_t
    int16x8_t short2 = vmovl_s8(vget_high_s8(vec)); // cast the last 8x int8_t to int16_t
    short1 = vaddq_s16(short1, short1); // Do operation on int16
    short2 = vaddq_s16(short2, short2);
    vec = vcombine_s8(vmovn_s16(short1), vmovn_s16(short2)); // Cast back to int8_t and combine the two vectors
    vst1q_s8(buf, vec); // Store

【讨论】:

感谢您的回答!真的很有帮助

以上是关于NEON:将 int8x16_t 拆包成一对 int16x8 并将一对 int16x8_t 打包成 int8x16_t的主要内容,如果未能解决你的问题,请参考以下文章

arm_neon.h 是不是缺少所有 float16_t 类型?

如何在 Neon 中将 uint32x4_t 转换为 uint8x16_t?

如何使用 arm neon 8bit 乘加和到 32 位向量?

在 arm neon 中有效地累积符号位

我收到有关某些 Neon 代码的错误消息

Q寄存器的两个子部分之和的NEON固有