Почему return 139? С
Пытаемся векторизовать сложение
https://godbolt.org/z/KaYPn51jK
код
#include <immintrin.h>
#include <stdio.h>
double inner2(double* x, double* y, int n){
__m256d *xx, *yy;
__m256d p, s,u;
xx = (__m256d*)x;
yy = (__m256d*)y;
s = _mm256_setzero_pd();
for(int i=0; i<(n/4); ++i){
p = _mm256_mul_pd(xx[i],yy[i]);
s = _mm256_add_pd(s,p);
}
u = _mm256_permute2f128_pd(s , s , 1);
s = _mm256_add_pd(s, u);
s = _mm256_hadd_pd(s, s);
s = _mm256_hadd_pd(s, s);
double sum;
_mm256_store_pd(&sum,s);
return sum;
}
int main()
{
double a[4], b[4];
a[0]=a[1]=a[2]=a[3]=1.0;
b[0]=b[1]=b[2]=b[3]=1.0;
double * c = &(a[0]);
double * d = &(b[0]);
double e = inner2(c,d,4);
printf("%f" ,e);
return 0;
}
Почему здесь return 139? Подозреваю, что-то не так с адресами, но не могу понять, что. Что-то видимо крайне простое и в функции main, но как я не пытался методом тыка поменять, не получалось.
А в то же время такое:
https://godbolt.org/z/dnz1Gne5b
то есть то же самое, но для float и m128, работает корректно
Ответы (1 шт):
Автор решения: maestro
→ Ссылка
У вас две ошибки.
- Инструкции AVX требуют выравнивания по границе 32 байт. У вас это требование не выполнено. Для создания выровненных массивов можно использовать функцию
aligned_alloc. - Функция
_mm256_store_pdсохраняет всё содержимое регистра (4 числа double) по переданному указателю. А у вас передаётся указатель на одно число double. Это приводит к разрушению стека. Предлагаю сначала извлечь из типа__m256dдва числа в регистр__m128d, а затем уже из него извлечь одно нужное нам число.
Про массив типа __m256d* написал в комментариях. Не уверен, что так можно. Но сделал так, как считаю правильным.
#include <immintrin.h>
#include <stdio.h>
double inner2(double* x, double* y, int n){
__m256d p, s,u;
s = _mm256_setzero_pd();
for(int i=0; i<n; i += 4) {
//Здесь загрузка 4 чисел из массива в регистр
__m256d vx = _mm256_load_pd(x + i);
__m256d vy = _mm256_load_pd(y + i);
p = _mm256_mul_pd(vx, vy);
s = _mm256_add_pd(s, p);
}
u = _mm256_permute2f128_pd(s, s, 1);
s = _mm256_add_pd(s, u);
s = _mm256_hadd_pd(s, s);
s = _mm256_hadd_pd(s, s);
//Это непереносимая конструкция, работает для GCC
double sum __attribute__ ((aligned (32)));
__m128d a = _mm256_extractf128_pd(s, 0);
_mm_storel_pd(&sum, a);
return sum;
}
int main()
{
//Создаём указатели на выровненную память с помощью стандартной функции языка C11
double *a = aligned_alloc(32, 4 * sizeof(double));
double *b = aligned_alloc(32, 4 * sizeof(double));
a[0]=a[1]=a[2]=a[3]=1.0;
b[0]=b[1]=b[2]=b[3]=1.0;
double e = inner2(a,b,4);
printf("%f" ,e);
free(a);
free(b);
return 0;
}