sse 指令访问冲突
sse instruction access violation
我是 SSE 指令的新手,正在尝试学习它。我写了一个小程序如下,但是给了我访问冲突错误。可能是内存错位的原因,但我很难找出到底是哪里出了问题。
void add_sse(uint16_t *a, uint16_t *b {
__m128i *av = (__m128i*)a; //16-byte aligned (128 bits)
__m128i *bv = (__m128i*)b;
__m128i cv = _mm_setzero_si128();
for (int i = 0; i < 2; i++)
{
cv = _mm_adds_epu16(av[i], bv[i]);
_mm_store_si128(av + i, cv);
}
}
int main(){
uint16_t a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
uint16_t b[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
add_sse(a, b);
int size = sizeof(a) / sizeof(uint16_t);
for (int i = 0; i < size; i++)
std::cout << a[i] << std::endl;
getchar();
return 0;
}
我还尝试了另一种方法 add_sse()
,发现它在一段时间内有效,但大部分时间都无效。这是代码:
void add_sse(uint16_t *a, uint16_t *b) {
*(__m128i*) &a[0] = _mm_add_epi16(*(__m128i*)&a[0], *(__m128i*)&b[0]);
*(__m128i*) &a[8] = _mm_add_epi16(*(__m128i*)&a[8], *(__m128i*)&b[8]);
}
编辑:感谢彼得的评论。我现在开始工作了。只是 post 它以确保任何有类似问题的人都能得到答案。这是我得到的:
void add_sse(uint16_t *a, uint16_t *b) {
__m256i av = _mm256_loadu_si256((__m256i*)a);
__m256i bv = _mm256_loadu_si256((__m256i*)b);
__m256i sum = _mm256_add_epi32(av, bv);
_mm256_storeu_si256((__m256i*)a, sum);
}
如果您不需要对齐输入,您有两个主要选择:
执行标量运算直到地址对齐,然后执行对齐向量循环。
使用 loadu 和 storeu 内部函数。它们的主要目的是将对齐信息传达给编译器,因此它可以使用适当的加载指令(适用于未对齐的指令,或在未对齐时出错的指令)。 (对于 float,在 float* 和 __m128
之间转换,但 int load / store 内在函数甚至不为你转换。)
我是 SSE 指令的新手,正在尝试学习它。我写了一个小程序如下,但是给了我访问冲突错误。可能是内存错位的原因,但我很难找出到底是哪里出了问题。
void add_sse(uint16_t *a, uint16_t *b {
__m128i *av = (__m128i*)a; //16-byte aligned (128 bits)
__m128i *bv = (__m128i*)b;
__m128i cv = _mm_setzero_si128();
for (int i = 0; i < 2; i++)
{
cv = _mm_adds_epu16(av[i], bv[i]);
_mm_store_si128(av + i, cv);
}
}
int main(){
uint16_t a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
uint16_t b[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
add_sse(a, b);
int size = sizeof(a) / sizeof(uint16_t);
for (int i = 0; i < size; i++)
std::cout << a[i] << std::endl;
getchar();
return 0;
}
我还尝试了另一种方法 add_sse()
,发现它在一段时间内有效,但大部分时间都无效。这是代码:
void add_sse(uint16_t *a, uint16_t *b) {
*(__m128i*) &a[0] = _mm_add_epi16(*(__m128i*)&a[0], *(__m128i*)&b[0]);
*(__m128i*) &a[8] = _mm_add_epi16(*(__m128i*)&a[8], *(__m128i*)&b[8]);
}
编辑:感谢彼得的评论。我现在开始工作了。只是 post 它以确保任何有类似问题的人都能得到答案。这是我得到的:
void add_sse(uint16_t *a, uint16_t *b) {
__m256i av = _mm256_loadu_si256((__m256i*)a);
__m256i bv = _mm256_loadu_si256((__m256i*)b);
__m256i sum = _mm256_add_epi32(av, bv);
_mm256_storeu_si256((__m256i*)a, sum);
}
如果您不需要对齐输入,您有两个主要选择:
执行标量运算直到地址对齐,然后执行对齐向量循环。
使用 loadu 和 storeu 内部函数。它们的主要目的是将对齐信息传达给编译器,因此它可以使用适当的加载指令(适用于未对齐的指令,或在未对齐时出错的指令)。 (对于 float,在 float* 和
__m128
之间转换,但 int load / store 内在函数甚至不为你转换。)