2009-08-04 135 views
2

目前,我有以下代码:使用SSE将4个浮点数乘以4个浮点数的最有效方法是什么?

float a[4] = { 10, 20, 30, 40 }; 
float b[4] = { 0.1, 0.1, 0.1, 0.1 }; 
asm volatile("movups (%0), %%xmm0\n\t" 
      "mulps (%1), %%xmm0\n\t"    
      "movups %%xmm0, (%1)"    
      :: "r" (a), "r" (b)); 

我首先是几个问题:

(1)如果我要对齐16字节边界的数组,将它甚至工作?由于数组是分配在堆栈上的,因此调整它们几乎是不可能的。

看到所选答案的这篇文章:Are stack variables aligned by the GCC __attribute__((aligned(x)))?

(2)可以将代码在所有被重构,使之更有效率?如果我将两个浮点数组都放入寄存器而不只是一个,会怎么样?

感谢

回答

1

如果我是对齐16字节边界的数组,将它甚至工作?由于数组是分配在堆栈上的,因此调整它们几乎是不可能的。

要求堆叠上的对齐工作。否则内部函数将无法工作。我想你所引用的帖子必须与他选择的高价值对齐。

以2:

不,不应该有性能差异。有关几个处理器的指令时序,请参见此site


如何堆栈变量的对齐工作:

push ebp 
mov ebp, esp 
and esp, -16    ; fffffff0H 
sub esp, 200    ; 000000c8H 

对齐堆栈的开始16字节。

1

是否GCC提供了__m128数据类型的支持?如果是这样,那么这是您保证16字节对齐数据类型的最佳方案。尽管如此,还有__attribute__((aligned(16)))用于对齐事物。定义你的数组如下

float a[4] __attribute__((aligned(16))) = { 10, 20, 30, 40 }; 
float b[4] __attribute__((aligned(16))) = { 0.1, 0.1, 0.1, 0.1 }; 

然后用MOVAPS代替:)

+0

感谢;但正如本文所述http://stackoverflow.com/questions/841433/gcc-attributealignedx-explanation似乎不可能对齐在堆栈上分配的数组? (而不是全局数组分配在.data中) – horseyguy 2009-08-04 12:44:11

+0

感谢修复Bastien :) Banister ...你能试试看看会发生什么吗?如果与解释相关的是正确的,那么就不可能像正确地对齐double这样的东西,然而它们会对齐。 – Goz 2009-08-04 12:55:10

+0

是的,我很快就会......我有一种感觉,相关的解释是错误的,因为这个问题中的每个人都似乎暗示。感谢大家! :) – horseyguy 2009-08-04 12:58:16

1

(1)如果我需要对齐16个字节边界上的数组,它会工作吗?由于数组是分配在堆栈上的,因此调整它们几乎是不可能的。

没有,这是很简单的排列使用and堆栈指针:

and esp, 0xFFFFFFF0 ; aligned on a 16-byte boundary 

但是,你应该使用什么GCC提供,如一个16个字节的类型,或者__attribute__定制校准。

+0

感谢您的回答,您能否向我解释如何使用'和'进行对齐?我不太''得到它:) – horseyguy 2009-08-05 16:33:48

7

写在C,使用

gcc -S -mssse3 

,如果你有一个相当新的gcc版本。

0

关于重构。你可以使用内在的。 实施例:

#include <emmintrin.h> 

int main(void) 
{ 
    __m128 a1,b1; 

    a1=_mm_set_ps(10, 20,30,40); 
    b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1); 

    a1=_mm_mul_ps(a1,b1); 

    return 0; 
} 

随着优化GCC(-O2-O3)它可以是工作更快然后ASM。

1

使用内在性尤其是在优化方面要快得多。 我写了简单的测试和比较两种版本(ASM和内在)

unsigned long long time1; 
__m128 a1,b1; 


a1=_mm_set_ps(10, 20,30,40); 
b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1); 
float a[4] = { 10, 20, 30, 40 }; 
float b[4] = { 0.1, 0.1, 0.1, 0.1 }; 

time1=__rdtsc(); 
a1=_mm_mul_ps(a1,b1); 
time1=__rdtsc() - time1 ; 
printf("Time: %llu\n",time1); 


time1=__rdtsc(); 
asm volatile("movups (%0), %%xmm0\n\t" 
       "mulps (%1), %%xmm0\n\t" 
       "movups %%xmm0, (%1)" 
       :: "r" (a), "r" (b)); 
time1=__rdtsc() - time1 ; 
printf("Time: %llu\n",time1); 

内在版本50-60处理器时间戳 ASM版本〜1000 PROC时间戳

你可以测试你的机器上