【发布时间】:2020-09-10 03:04:00
【问题描述】:
我想以尽可能少的时钟周期数将 2 个 AVX-512 向量的元素合并到另外两个向量中。
具体问题如下:
// inputs
__m512i a = {a0, a1, ..., a31}; // 32x 16-bit int16_t integers
__m512i b = {b0, b1, ..., b31}; // 32x 16-bit int16_t integers
// desired output
__m512i A = {a0 , b0 , a1 , b1 , ..., a15, b15};
__m512i B = {a16, b16, a17, b17, ..., a31, b31};
天真的方法是将向量(a和b)复制到内存并通过直接索引创建向量(A和B),如下所示:
union U512i {
__m512i vec;
alignas(64) int16_t vals[32];
};
U512i ta = { a };
U512i tb = { b }
U512i A = _mm512_set_epi16( tb.vals[15], ta.vals[15], ... tb.vals[0], ta.vals[0] );
U512i B = _mm512_set_epi16( tb.vals[31], ta.vals[31], ... tb.vals[16], ta.vals[16] );
我还需要进行类似的合并,但步幅不同,例如:
// inputs
__m512i a = {a0, a1, ..., a31}; // 32x 16-bit int16_t integers
__m512i b = {b0, b1, ..., b31}; // 32x 16-bit int16_t integers
// desired output
__m512i A = {a0 , a1 , b0 , b1 , ..., a14, a15, b14, b15};
__m512i B = {a16, a17, b16, b17, ..., a30, a31, b30, b31};
最适合解决此问题的 AVX-512 内在函数是什么?一些解释将不胜感激,因为我是 AVX-512 内在函数的新手。
感谢您的帮助!
【问题讨论】:
-
你看过
_mm512_mask_blend_epi16和一些洗牌吗? -
vpermt2w可以在每个输出的一条指令中执行此操作。或者在一些成本为 3 uop 的 CPU 上,vpunpcklwd+vpunpckhwd然后用 2x 单 uopvpermt2d修复该通道内交错,这些结果应该总共可以工作 4 个 shuffle uop 而不是 6 个。 -
保持pairs相邻的版本相当于32位元素粒度,所以可以只使用单uop
vpermt2d。 -
@PeterCordes,感谢您的建议。我的 CPU (Skylake) 支持 vpermt2w。虽然 _mm512_mask_permutex2var_epi16 解决了我的问题,但它有点慢(7 个周期)。事实上,与幼稚的方式(通过转移到内存)相比,性能几乎保持不变。
-
vpermt2w是 3 uop,在 SKX 上的 吞吐量 为每 2 个周期 1 个。是的,这并不理想,但是产生 A 和 B 的两个独立 shuffle 的延迟可能会重叠。 uops.info/…你确定像clang这样的编译器还没有把你正在做的事情编译成这样的洗牌吗?除非您的基准测试设计不佳,或者您的实际用例瓶颈在其他地方,或者您的编译器已经很好地优化了您的幼稚方式,否则这里应该有空间。
标签: c hpc intrinsics avx avx512