Gen*_*nís 14 c optimization hpc sse compiler-optimization
这篇文章与我几天前发布的另一篇文章密切相关.这一次,我编写了一个简单的代码,它只添加了一对元素数组,将结果乘以另一个数组中的值并将其存储在第四个数组中,所有变量浮点数都是双精度类型.
我制作了两个版本的代码:一个是SSE指令,使用调用而另一个没有它我然后使用gcc和-O0优化级别编译它们.我在下面写下:
// SSE VERSION
#define N 10000
#define NTIMES 100000
#include <time.h>
#include <stdio.h>
#include <xmmintrin.h>
#include <pmmintrin.h>
double a[N] __attribute__((aligned(16)));
double b[N] __attribute__((aligned(16)));
double c[N] __attribute__((aligned(16)));
double r[N] __attribute__((aligned(16)));
int main(void){
int i, times;
for( times = 0; times < NTIMES; times++ ){
for( i = 0; i <N; i+= 2){
__m128d mm_a = _mm_load_pd( &a[i] );
_mm_prefetch( &a[i+4], _MM_HINT_T0 );
__m128d mm_b = _mm_load_pd( &b[i] );
_mm_prefetch( &b[i+4] , _MM_HINT_T0 );
__m128d mm_c = _mm_load_pd( &c[i] );
_mm_prefetch( &c[i+4] , _MM_HINT_T0 );
__m128d mm_r;
mm_r = _mm_add_pd( mm_a, mm_b );
mm_a = _mm_mul_pd( mm_r , mm_c );
_mm_store_pd( &r[i], mm_a );
}
}
}
//NO SSE VERSION
//same definitions as before
int main(void){
int i, times;
for( times = 0; times < NTIMES; times++ ){
for( i = 0; i < N; i++ ){
r[i] = (a[i]+b[i])*c[i];
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用-O0编译它们时,如果没有特别给出-mno-sse(和其他)选项,gcc将使用XMM/MMX寄存器和SSE intstructions.我检查了为第二个代码生成的汇编代码,我注意到它使用了movsd,addsd和mulsd指令.所以它使用SSE指令,但只使用那些使用寄存器最低部分的指令,如果我没有错的话.正如预期的那样,为第一个C代码生成的汇编代码使用了addp和mulpd指令,尽管生成了相当大的汇编代码.
无论如何,据我所知,第一个代码应该获得更好的SIMD范例,因为每次迭代都会计算两个结果值.尽管如此,第二个代码执行的操作比第一个代码快25%.我还用单精度值进行了测试,得到了类似的结果.这是什么原因?
chi*_*ill 15
GCC中的矢量化已启用-O3
.这就是为什么在-O0
,你看到的只是普通的标量SSE2指令集(movsd
,addsd
,等).使用GCC 4.6.1和你的第二个例子:
#define N 10000
#define NTIMES 100000
double a[N] __attribute__ ((aligned (16)));
double b[N] __attribute__ ((aligned (16)));
double c[N] __attribute__ ((aligned (16)));
double r[N] __attribute__ ((aligned (16)));
int
main (void)
{
int i, times;
for (times = 0; times < NTIMES; times++)
{
for (i = 0; i < N; ++i)
r[i] = (a[i] + b[i]) * c[i];
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
并使用gcc -S -O3 -msse2 sse.c
以下指令编译内部循环的产生,这非常好:
.L3:
movapd a(%eax), %xmm0
addpd b(%eax), %xmm0
mulpd c(%eax), %xmm0
movapd %xmm0, r(%eax)
addl $16, %eax
cmpl $80000, %eax
jne .L3
Run Code Online (Sandbox Code Playgroud)
如您所见,通过启用矢量化,GCC会发出代码以并行执行两个循环迭代.但是它可以改进 - 这段代码使用SSE寄存器的低128位,但它可以使用完整的256位YMM寄存器,通过启用SSX指令的AVX编码(如果在机器上可用).因此,编译相同的程序与gcc -S -O3 -msse2 -mavx sse.c
内循环:
.L3:
vmovapd a(%eax), %ymm0
vaddpd b(%eax), %ymm0, %ymm0
vmulpd c(%eax), %ymm0, %ymm0
vmovapd %ymm0, r(%eax)
addl $32, %eax
cmpl $80000, %eax
jne .L3
Run Code Online (Sandbox Code Playgroud)
请注意,v
在每条指令前面,该指令使用256位YMM寄存器,原始循环的四次迭代是并行执行的.
归档时间: |
|
查看次数: |
26705 次 |
最近记录: |