C++ 连续迭代器上的SIMD指令

C++ 连续迭代器上的SIMD指令,c++,iterator,sse,simd,intrinsics,C++,Iterator,Sse,Simd,Intrinsics,我有两个类型为T的向量v1和v2,希望创建一个函数,使用SIMD指令执行v1&v2,并将输出存储在向量out中 理想情况下,我们会有 first1 = v1.begin(); last1 = v1.end(); first2 = v2.begin(); d_first = out.begin(); while(distance(first1, last1) >= 64 / sizeof(T)) { *d_first = _mm512_and_epi32(first1, f

我有两个类型为
T
的向量
v1
v2
,希望创建一个函数,使用SIMD指令执行
v1&v2
,并将输出存储在向量
out

理想情况下,我们会有

first1  = v1.begin();
last1   = v1.end();
first2  = v2.begin();
d_first = out.begin();
while(distance(first1, last1) >= 64 / sizeof(T)) {
     *d_first = _mm512_and_epi32(first1, first2);
     first1   += 64 / sizeof(T)
     first2   += 64 / sizeof(T)
     d_first1 += 64 / sizeof(T)
}
auto and_op = [](T a, T b) {return a & b;};
std::transform(first1, last1, first2, d_first, and_op);
上面代码的第一个问题是它使用32位整数。我不确定它是否希望这些字符对齐,如果它对齐,那么如果
t
类似于
char
short int
,代码将无法工作

第二个问题是我无法正确地转换向量迭代器<代码>\u mm512\u和\u epi32需要两个
\u m512i
变量作为输入。每当我传递一个连续迭代器或一个地址时,编译器总是抱怨说没有从我传递的内容转换到“uuum512i”(向量为8) “长”值)

我可以通过这样做使它工作

__m512i _a = _mm512_load_epi64(&*first1.base());
__m512i _b = _mm512_load_epi64(&*first2.base());'
__m512i _res = _mm512_and_epi64(_a, _b);
_mm512_store_epi64(&*d_first.base(), _res);
但我不确定加载/存储操作的成本有多高,或者我是否可以跳过它们


在大型连续阵列上运行SIMD指令的正确方法是什么?有没有一种方法可以使它适用于所有类型的连续数组,而不管它们是否对齐?

通常,您只需从容器上的
.data()
获取一个指针,然后手动在数组上循环,就像C型数组一样。或者增加索引并执行
\u mm512\u loadu\u si512(&vec[i])
。(除非对
std::vector
使用自定义对齐分配器,否则不应假定数据已对齐。但当前硬件上的512位向量可从确保数据对齐中获益匪浅,比如20%对256位向量的两个百分比。)

如果可以保证解引用迭代器方法是对底层数组元素的引用,而不是标量临时元素,那么它可能是安全的

加载/存储内部函数并不比通过解引用从内存中隐式加载成本更高;您需要从asm的角度来理解成本。编译器必须发出向量加载指令(或ALU指令的内存源操作数)并存储指令,以使asm对内存中的数据进行操作
\u mm\u load\u si128
\u mm\u loadu\u si128
基本上只是为了将对齐信息传递给编译器和强制转换而存在的。并表示对其他C类型(如memcpy)的严格别名和对齐安全访问