1

我需要做以下两个操作:

float x[4];
float y[16];

// 1-to-4 broadcast
for ( int i = 0; i < 16; ++i )
    y[i] = x[i / 4];

// 4-to-1 reduce-add
for ( int i = 0; i < 16; ++i )
    x[i / 4] += y[i];

什么是高效的 AVX-512 实施?

4

1 回答 1

2

对于reduce-add,只需进行in-lane shuffles并添加(vmovshdup/ vaddps/ vpermilps imm8/ vaddps),就像在x86上做水平浮点向量求和的最快方式一样,以获得每个128位通道中的水平和,然后vpermps对所需元素进行洗牌至底部。或者vcompressps使用常量掩码来做同样的事情,可选地使用内存目标。

一旦打包成单个向量,您就有了一个普通的 SIMD 128 位相加。

如果您的数组实际上大于 16,则vpermps您可以vpermt2ps从两个源向量中的每一个中获取每个第 4 个元素,而不是让您准备好将+=部分放入x[]256 位向量中。(或者再次与另一个 shuffle 组合成 512 位向量,但这可能会成为 SKX 上的 shuffle 吞吐量的瓶颈)。

在 SKX 上,vpermt2ps只有一个 uop,吞吐量为 1c / 延迟为 3c,因此它的强大效率非常高。在 KNL 上,它的吞吐量为 2c,比 差vpermps,但也许仍然值得。(KNL 没有 AVX512VL,但如果需要添加x[]256 位向量,您(或编译器)可以使用 AVX1 vaddps ymm。)

有关说明表,请参见https://agner.org/optimize/


对于负载:

这是在循环内完成的,还是重复的?(即你可以在寄存器中保留一个随机控制向量吗?如果是这样,你可以

  • VBROADCASTF32X4使用(单个 uop 用于加载端口)进行 128->512 广播。
  • vpermilps zmm,zmm,zmm在每个 128 位通道内进行通道内随机播放以广播不同的元素。(必须与广播负载分开,因为内存源vpermilps可以有一个m512m32bcst源。(指令通常有它们的内存广播粒度=它们的元素大小,不幸的是在某些情况下它根本没有用。而且vpermilps将控制向量作为内存操作数,而不是源数据。)

这比因为 shuffle 有 1 个周期延迟而不是 3 个(在 Skylake-avx512 上)略好。vpermps zmm,zmm,zmm

即使在循环之外,加载一个随机控制向量可能仍然是你最好的选择。

于 2018-10-13T01:30:53.343 回答