gcc — C ++ SSE2 встроенные функции

Я только что узнал, что есть способ добиться некоторого распараллеливания с помощью встроенных функций. Я нашел следующий код и хотел пройти через него, но я мог многое понять. Я пытался сделать операции с одинарной точностью, но как я могу это сделать?

#include <stdio.h>
#include <stdlib.h>
#include <xmmintrin.h>

inline double pi_4 (int n){
int i;
__m128d mypart2,x2, b, c, one;
double *x = (double *)malloc(n*sizeof(double));
double *mypart = (double *)malloc(n*sizeof(double));
double sum = 0.0;
double dx = 1.0/n;
double x1[2] __attribute__((aligned(16)));
one = _mm_set_pd1(1.0); // set one to (1,1)
for (i = 0; i < n; i++){
x[i] = dx/2 + dx*i;
}
for (i = 0; i < n; i+=2){
x1[0]=x[i]; x1[1]=x[i+1];
x2 = _mm_load_pd(x1);
b = _mm_mul_pd(x2,x2);
c = _mm_add_pd(b,one);
mypart2 = _mm_div_pd(one,c);
_mm_store_pd(&mypart[i], mypart2);
}
for (i = 0; i < n; i++)
sum += mypart[i];
return sum*dx;
}

int main(){
double res;
res=pi_4(128);
printf("pi = %lf\n", 4*res);
return 0;
}

Я думал о том, чтобы изменить все с двойного на плавающее и вызвать правильные встроенные функции, например, вместо _mm_set_pd1 -> _mm_set_ps1. Я не знаю, сделает ли это программу с двойной точностью до одинарной.

ОБНОВИТЬ

Я пытался, как следует, но я получаю ошибку сегментации

#include <stdio.h>
#include <stdlib.h>
#include <xmmintrin.h>

inline float pi_4 (int n){
int i;
__m128 mypart2,x2, b, c, one;
float *x = (float *)malloc(n*sizeof(float));
float *mypart = (float*)malloc(n*sizeof(float));
float sum = 0.0;
float dx = 1.0/n;
float x1[2] __attribute__((aligned(16)));
one = _mm_set_ps1(1.0); // set one to (1,1)
for (i = 0; i < n; i++){
x[i] = dx/2 + dx*i;
}
for (i = 0; i < n; i+=2){
x1[0]=x[i]; x1[1]=x[i+1];
x2 = _mm_load_ps(x1);
b = _mm_mul_ps(x2,x2);
c = _mm_add_ps(b,one);
mypart2 = _mm_div_ps(one,c);
_mm_store_ps(&mypart[i], mypart2);
}
for (i = 0; i < n; i++)
sum += mypart[i];
return sum*dx;
}
int main(){
float res;
res=pi_4(128);
printf("pi = %lf\n", 4*res);
return 0;
}

1

Решение

Требуется еще несколько исправлений:

  • x1 должен быть объявлен с 4 элементами.
  • Второй цикл for должен увеличиваться на 4 (именно это вызвало ошибку segfault).
  • Там должно быть 4 назначения на x1 массив.

Все эти изменения связаны с тем, что одинарная точность упаковывает 4 значения в 16-байтовый векторный регистр, а двойная точность — только 2 значения. Я думаю, что это было так:

#include <stdio.h>
#include <stdlib.h>
#include <xmmintrin.h>

inline float pi_4 (int n){
int i;
__m128 mypart2,x2, b, c, one;
float *x = (float *)malloc(n*sizeof(float));
float *mypart = (float*)malloc(n*sizeof(float));
float sum = 0.0;
float dx = 1.0/n;
float x1[4] __attribute__((aligned(16)));
one = _mm_set_ps1(1.0); // set one to (1,1,1,1)
for (i = 0; i < n; i++){
x[i] = dx/2 + dx*i;
}
for (i = 0; i < n; i+=4){
x1[0]=x[i]; x1[1]=x[i+1];
x1[2]=x[i+2]; x1[3]=x[i+3];
x2 = _mm_load_ps(x1);
b = _mm_mul_ps(x2,x2);
c = _mm_add_ps(b,one);
mypart2 = _mm_div_ps(one,c);
_mm_store_ps(&mypart[i], mypart2);
}
for (i = 0; i < n; i++)
sum += mypart[i];
return sum*dx;
}
int main(){
float res;
res=pi_4(128);
printf("pi = %lf\n", 4*res);
return 0;
}

Барабанная дробь…

$ ./foo
pi = 3.141597

Слово об использовании malloc(), Я думаю, что большинство реализаций будет возвращать память, выровненную по 16-байтовой границе, как требуется для загрузки и хранения SSE, но это не может быть гарантировано, поскольку __m128 не является типом C / C ++ (он гарантированно будет выровнен для «обычных» типов) , Было бы безопаснее использовать memalign() или же posix_memalign(),

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]