c++ SSE2的内在特性
C++ SSE2 intrinsics
我刚刚了解到有一种方法可以使用intrinsic实现一些并行化。我发现下面的代码,并想通过它,但我可以理解很多。我试图使运算达到单精度,但我怎么能做到呢?
#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 = %lfn", 4*res);
return 0;
}
我正在考虑将一切从double改为float,并调用正确的内在函数,例如,而不是_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 = %lfn", 4*res);
return 0;
}
需要更多的修复:
-
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 = %lfn", 4*res);
return 0;
}
滚筒滚……
$ ./foo
pi = 3.141597
关于malloc()
的使用。我认为大多数实现将返回在SSE加载和存储所需的16字节边界上对齐的内存,但这可能无法保证,因为__m128不是C/c++类型(它保证为"正常"类型对齐)。使用memalign()
或posix_memalign()
会更安全。
相关文章:
- 使用 SSE2 和 AVX2 编译库
- 是否启用了 SSE2 指令?
- SSE2 函数如何从它应该所在的标头中丢失?
- SSE2优化用于从RGB565转换为RGB888(无alpha通道)
- SSE2包装的8位整数签名乘数(高半):将M128i(16x8位)分解为两个M128i(每个8x16),然后重新包装
- 最佳无分支有条件选择两个SSE2填充双打
- 如何仅使用 SSE2 在双精度中地板/整数
- 如何将VDT的Pade Exp fast_ex()的双重版本的标量代码转换为SSE2?
- SSE2 矢量化和虚拟机
- SSE2 内部函数 - 找到两个无符号短向量的最大值
- 这个SSE2换位有什么问题?
- 将 % 与 SSE2 一起使用?
- i5-2500k 上的 cpuid 指令:未设置 MMX、SSE、SSE2 位
- 是否有SSE2 _MM_UNPACKHI/LO_EPI32/64和_MM_SHUFFLE_EPI8/32的霓虹灯等效物
- GDB 在操作 SSE2 寄存器时报告EXC_BAD_ACCESS
- VS2013中SSE2代码的运行错误
- uint64 数组到 uint128 用于 SSE2
- 使用SSE2优化RGB565到RGB888的转换
- SSE2、Visual Studio 2010和调试版本
- 使用快速英特尔随机生成器(SSE2)会因堆栈问题而失败..已损坏