获取GCC以在使用内联asm的函数中保留SSE寄存器

时间:2009-08-08 22:54:43

标签: c gcc assembly sse inline-assembly

我正在用C语言编写一个需要进行快速数学计算的程序。我正在使用内联SSE汇编指令来获取一些SIMD操作(使用打包的双精度浮点数)。我正在Linux上使用GCC进行编译。

我处在需要循环某些数据的情况下,我在计算中使用了一个常数因子。我希望在循环期间将该因素隐藏在安全寄存器中,因此我不必每次都重新加载它。

用一些代码澄清:

struct vect2 {
    fltpt x;
    fltpt y;
}__attribute__((aligned(16))); /* Align on 16B boundary for SSE2 instructions */
typedef struct vect2 vect2_t;


void function()
{
    /* get a specific value set up in xmm1, and keep it there for the 
     * rest of the loop. */
    for( int i = 0, i<N; i++ ){
        asm(
            "Some calculations;"
            "on an element of;"
            "a data set.;"
            "The value in xmm1;"
            "is needed;"
        );
    }
}

我尝试过使用“register”关键字做一些事情。但是如果我没有弄错的话,看起来我只能将指针保存到该结构中(在通用寄存器中)。这需要每次迭代都要尊重,浪费宝贵的时间。

register vect2_t hVect asm("xmm1") = {h, h};
/* Gives error: data type of 'hVect' isn't suitable for a register */

register vect2_t *hVect2 asm("rax");
*hVect2 = (vect2_t){h,h};
/* Seems to work, but not what I'm looking for */

我不只是假设GCC不会改变xmm1寄存器,而是太多的“恶魔飞出一个人的鼻子”这样的事情:-)。所以我希望有一个正确的方法来做到这一点。

3 个答案:

答案 0 :(得分:8)

我认为这里的解决方案是让gcc意识到你的vec2_t类型实际上是一个向量;然后你可以计算循环不变量值并将其视为普通变量(除了编译器知道它是矢量类型):

typedef double vec2_t __attribute__ ((vector_size (16)));

void function()
{
  /* get a specific value set up, e.g. */
  vec2_t invariant;
  asm( "some calculations, soring result in invariant."
       : "=x" (invariant) );

  for( int i = 0; i<N; i++ ){
    asm(
            "Some calculations;"
            "on an element of;"
            "a data set.;"
            "The value in xmm1;"
            "is needed;"
            : "x" (invariant) // and other SSE arguments
       );
   }
}

我刚刚在循环内部进行了简单的计算,并且至少在优化级别1,invariant的值在循环期间保存在XMM寄存器中。

(这都假设你不需要需要你的循环不变量在显式XMM寄存器中;并且你可以使用GCC的正常寄存器分配。)

答案 1 :(得分:3)

我认为最好将寄存器赋值留给编译器。它可能比你更好地跟踪它。 GCC已经使用了SSE扩展,但如果你确定你知道的更好,请使用GCC __builtin函数。 说实话,我有点怀疑你会用它来加快速度。

祝你好运!

这些网站可能很有趣。

GCC X86 Built-in functions

Working with SIMD with GCC

答案 2 :(得分:3)

我习惯使用汇编和C,我在这里要做的是我会在汇编中编写整个函数。 如果您有一个灵活的make系统,我建议单独组装ASM功能并将其链接到您的应用程序中。唯一的问题是编译器无法内联函数。

void function(void); // C

extern“C”函数(void); // C ++