与this question类似,我想将几个24位值收集到SSE / AVX寄存器的32位双字中。进一步:
AVX2(高性能?)收集解决方案没问题,但我还需要预先支持AVX。它看起来像带有SIB字节的pinrd指示1字节对齐完全符合我的要求,但我无法弄清楚如何让编译器发出这种指令编码......
使用标准内在:
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);
当然,在插入之前,将一个带零扩展的字节解引用到dword。
我的内联asm尝试:
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
哪个很有前景,但似乎完全混淆了优化器;所有周围的代码都被忽视了。
如果没有纯粹的asm,有没有办法做到这一点? (我想使用内在的...)
答案 0 :(得分:0)
@harold,谢谢。
我已经在做了一些movd,然后是几个pinrd(比如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)