如何编写编译器可以针对 SIMD 比较优化的代码? [复制]
Posted
技术标签:
【中文标题】如何编写编译器可以针对 SIMD 比较优化的代码? [复制]【英文标题】:How to write code that compiler can optimize to SIMD compare? [duplicate] 【发布时间】:2018-03-03 09:32:21 【问题描述】:std::array<int, 4> a = 1, 1, 1, 1;
std::array<int, 4> b = 1, 2, 3, 4 ;
std::array<int, 4> c;
bool res = false;
for (int i = 0; i < a.size(); i++)
a[i] = rand() % 10;
for (int i = 0; i < 4; i++)
c[i] = a[i] + b[i];
智能编译器可以很好地编译成SIMD。 但是如何编写下面的比较代码也可以很好地编译为 SIMD;
res = a[0] <= b[0] && a[1] <= b[1] && a[2] <= b[2] && a[3] <= b[3]; // not compile to SIMD
【问题讨论】:
您使用什么编译器和编译器选项? 如果你使用 gcc 可能是__attribute__ ((vector_size (16)))
?
Visual Studio 2015,x64,完全优化 (/Ox),高级矢量扩展 2 (/arch:AVX2),@BasileStarynkevitch
我不抱太大希望,这需要movmskps
-ing 从向量中比较结果并对其进行标量比较,这不是我见过 MSVC 在其上做的事情拥有。
Auto-Vectorize comparison, Auto-vectorization of loop containing comparisons, how to auto vectorization array comparison function
【参考方案1】:
这样的事情怎么样:
int res = 0;
#pragma omp simd reduction(+:res)
for (int i = 0 ; i < 4 ; i++)
res += a[i] < b[i];
?
如果您可以正确对齐输入(并在 openmp 编译指示中添加对齐子句),那么它应该很快。特别是如果您的输入真的超过 4 个元素。
res
将是 0-4 而不是 0 或 1,但这可能不是问题。 SIMD 指令倾向于处理水平加法而不是水平位与。
【讨论】:
SIMD 指令倾向于处理水平添加 呃,不是 x86。存在hadd
指令,但它只执行水平对,而不是整体减少。更重要的是,它比单独的 shuffle + add 指令要慢。 ***.com/questions/6996764/…。无论如何,在 x86 上,OP 想要的最佳 asm 是 pcmpgtd xmm0, xmm1
(a,b) / pmovmskb eax, xmm0
/ cmp eax, 0xffff
/ je condition_true
(即检查 a
的每个元素比较大于b
,所以比较掩码是唯一的)
所以你真正想要的是一个知道如何使用 SIMD 比较自己的智能编译器,否则我不确定有没有办法让它发出汇编。顺便说一句,x86 上的水平与与水平相加一样简单,对于非布尔向量,您不能只将向量提取到整数位图。另外顺便说一句,NEON 没有 pmovmskb
的等价物,因此将布尔向量转换为整数位图需要更多的工作。
而不是res += a[i] < b[i];
我认为最好使用res &= a[i] < b[i];
来获得布尔结果而不是总和
彼得,我完全同意,但问题是关于编写编译器可以自动矢量化的代码。我写的是我能想到的最接近的,没有经过大量测试:(
Lưu Vĩnh Phúc,&=
将不起作用。也许你的意思是|=
?正如我在回答中提到的,我决定改用+=
是有原因的,但|=
会起作用……它可能会慢一点。以上是关于如何编写编译器可以针对 SIMD 比较优化的代码? [复制]的主要内容,如果未能解决你的问题,请参考以下文章