【发布时间】:2020-01-05 00:32:01
【问题描述】:
我想对一个相等性测试进行矢量化,其中将矢量中的所有元素与相同的值进行比较,并将结果写入一个 8 位字数组。结果数组中的每个 8 位字应为零或一。 (这有点浪费,但是在这个问题中,对布尔值进行打包并不是一个导入细节)。这个函数可以写成:
#include <stdint.h>
void vecEq (uint8_t* numbers, uint8_t* results, int len, uint8_t target) {
for(int i = 0; i < len; i++) {
results[i] = numbers[i] == target;
}
}
如果我们知道两个向量都是 256 位对齐的,我们可以首先将 target 广播到 AVX 寄存器,然后使用 SIMD 的 _mm256_cmpeq_epi8 一次执行 32 次相等测试。但是,在我正在使用的设置中,numbers 和results 都已由运行时分配(GHC 运行时,但这无关紧要)。它们都保证是 64 位对齐的。有没有办法向量化这个操作,最好不使用 AVX 寄存器?
我考虑过的方法是将 8 位字预先广播到 64 位字,然后一次与 8 个元素进行异或运算。这不起作用,因为我找不到矢量化方法将 XOR 的结果(零表示相等,其他任何表示不相等)转换为我需要的相等测试结果(0 表示不相等,1 表示相等,不应该存在其他任何东西)。粗略地说,我的草图是:
void vecEq (uint64_t* numbers, uint64_t* results, int len, uint_8 target) {
uint64_t targetA = (uint64_t)target;
uint64_t targetB = targetA<<56 | targetA<<48 | targetA<<40 | targetA<<32 | targetA<<24 | targetA<<16 | targetA<<8 | targetA;
for(int i = 0; i < len; i++) {
uint64_t tmp = numbers[i] ^ targetB;
results[i] = ... something with tmp ...;
}
}
【问题讨论】:
-
AVX 不像 SSE 那样支持未对齐的负载?
-
您使用的是什么编译器,您的目标平台是什么?所有三个主要编译器的当前版本已经按原样矢量化您的代码:godbolt.org/z/-p_MxP...
-
您可以将
uint64_t*s 转换为uint8_t*s 并执行原始循环,但是当我尝试它时,这并不会改变生成的(已经矢量化,如 Michael Kenzel 所说的)代码。如果适用于您的情况,请确保指定restrict(即,如果numbers和results不能重叠)。
标签: c x86 vectorization memory-alignment avx