Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get GCC to preserve an SSE register throughout a function that uses inline asm

I'm writing a program in C that needs to do some fast math calculations. I'm using inline SSE assembly instructions to get some SIMD action (using packed double precision floating point numbers). I'm compiling using GCC on Linux.

I'm in a situation where I need to loop over some data, and I use a constant factor in my calculations. I'd like to keep that factor tucked away in a safe register during the loop, so I don't have to re-load it every time.

To clarify with some code:

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;"
        );
    }
}

I've tried doing something with the "register" keyword. But if I'm not mistaken, it looks as though I can only preserve a pointer to that structure (in a general register). This would need to be deferenced every iteration, wasting precious time.

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 */

I don't just like to assume that GCC won't change the xmm1 register, it's too much of a "demons flying out of one's nose" kind of thing :-). So I'm hoping there is a proper way to do this.

like image 665
RoaldFre Avatar asked Aug 08 '09 22:08

RoaldFre


People also ask

Does GCC support inline assembly?

GCC provides two forms of inline asm statements. A basic asm statement is one with no operands (see Basic Asm), while an extended asm statement (see Extended Asm) includes one or more operands.

What is __ asm __ in C?

The __asm keyword invokes the inline assembler and can appear wherever a C or C++ statement is legal. It cannot appear by itself. It must be followed by an assembly instruction, a group of instructions enclosed in braces, or, at the very least, an empty pair of braces.

What is inline assembly with example?

In computer programming, an inline assembler is a feature of some compilers that allows low-level code written in assembly language to be embedded within a program, among code that otherwise has been compiled from a higher-level language such as C or Ada.


1 Answers

I think the solution here is to make gcc aware that your vec2_t type is actually a vector; then you can just calculate the loop-invariant value and treat it as a normal variable (except the compiler knows it is a vector type) :

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
       );
   }
}

I just compiled this up with a simple calculation inside the loop, and with at least optimisation level 1 the value of invariant is kept in a XMM register during the loop.

(This all assumes you don't need your loop invariant in an explicit XMM register; and that you can use GCC's normal register allocation).

like image 142
DaveR Avatar answered Sep 28 '22 00:09

DaveR