c - pinsrd/_mm_insert_epi32 与字节指针对齐?

标签 c bit-manipulation sse intrinsics

类似于this question ,我想将几​​个 24 位值收集到 SSE/AVX 寄存器的 32 位双字中。进一步:

  • 每个值都位于距基指针不连续的偏移处
  • 每个值的偏移量只有 1 字节对齐
  • 我可以确保读取超出(或之前)每个值的 vector 是安全的

AVX2(高性能?)收集解决方案可以,但我还需要 AVX 之前的支持。看起来带有指示 1 字节对齐的 SIB 字节的pinsrd 正是我想要的,但我不知道如何让编译器发出此指令编码...

使用标准内在函数:

uint32_t *p = &base[offset];
vec = _mm_insert_epi32(vec, *p, 1);  // for each dword...

假设偏移量对齐,产生合理的编码:

660f3a2244_b5_0001 pinsrd   $0x1, (%rbp,%rsi,4), %xmm0

但是,我想实际发出:

660f3a2244_35_0001 pinsrd   $0x1, (%rbp,%rsi), %xmm0

并手动预乘偏移 3。

这种编码(通过十六进制编辑链接的二进制文件进行测试)似乎工作得很好。但是……我怎样才能发出它呢?没有大量的类型转换或属性 __align__ 似乎有效。显而易见的方法:

uint8_t *p = &base[offset*3];
vec = _mm_insert_epi32(vec, *p, 1);

当然,在插入之前会通过零扩展将一个字节取消引用为双字。

我的内联汇编尝试:

static inline __m128i __attribute__((always_inline))
_mm_insertu_epi32(__m128i a, void *b, long o, const int8_t imm8)
{
    __asm__("pinsrd %3, (%1, %2), %0" : "+x"(a) : "r"(b), "r"(o), "i"(imm8));
    return a;
}

产量:

660f3a22041601      pinsrd  $0x1, (%rsi,%rdx), %xmm0

这是有希望的,但似乎完全混淆了优化器;所有周围的代码都被扰乱得无法识别。

有没有办法在不使用纯汇编的情况下做到这一点? (我想使用内在...)

另请参阅:Dereference pointers in XMM register

最佳答案

@harold,谢谢。

我已经在执行 movd 和几个pinsrd(例如 clang)。但是我在 godbolt 上看到 clang/gcc/icc 使用各种解包模式,所以我将对它们进行分析。

不幸的是,“避免聚集”并不是解决方案。但你是对的,内在确实可以与任意对齐一起工作。简单的指针转换最终会做正确的事情(即产生可能未对齐的地址):

__m128i gather32_scale4(int *b, long o0, long o1, long o2, long o3)
{
    return _mm_set_epi32(b[o0], b[o1], b[o2], b[o3]);
    //  movd    xmm0, dword ptr [rdi + 4*r8]
    //  pinsrd  xmm0, dword ptr [rdi + 4*rcx], 1
    //  pinsrd  xmm0, dword ptr [rdi + 4*rdx], 2
    //  pinsrd  xmm0, dword ptr [rdi + 4*rsi], 3
}

__m128i gather32_scale1(int *b, long o0, long o1, long o2, long o3)
{
    return _mm_set_epi32(
        *(int *)&((char *)b)[o0],
        *(int *)&((char *)b)[o1],
        *(int *)&((char *)b)[o2],
        *(int *)&((char *)b)[o3]);
    //  movd    xmm0, dword ptr [rdi + r8]
    //  pinsrd  xmm0, dword ptr [rdi + rcx], 1
    //  pinsrd  xmm0, dword ptr [rdi + rdx], 2
    //  pinsrd  xmm0, dword ptr [rdi + rsi], 3
}

(与手动编写的_mm_insert_epi32类似)

关于c - pinsrd/_mm_insert_epi32 与字节指针对齐?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43694221/

相关文章:

c++ - C 程序执行

c - 无需在地址后写端口即可访问服务器

c - 从队列打印的程序改为打印一个数字

c++ - 为什么我无法删除 _mm_empty()?

c - 是否可以将 C 文件编译为 .app 而不是 .exe 文件?

c# - 计算 X 位掩码的最快方法?

c - 为什么 AND 一个带有 0xFFFFFFFF 的 uint32 值?

python - 按位运算一元 ~(反转)

simd - 如何使用avx(但没有avx-512)将int 64转换为int 32

c - AVX 标量运算要快得多