2011-05-24 15 views
5

Estoy tratando de utilizar una macro montaje (ARM) para el punto fijo de la multiplicación:conjunto del brazo de GCC preprocesador de las macros

#define MULT(a,b) __asm__ __volatile__ (\ 
     "SMULL r2, r3, %0, %1\n\t" \ 
     "ADD r2, r2, #0x8000\n\t" \ 
     "ADC r3, r3, #0\n\t" \ 
     "MOV %0, r2, ASR#16\n\t" \ 
     "ORR %0, %0, r3, ASL#16" \ 
     : "=r" (a) : "0"(a), "1"(b) : "r2", "r3"); 

pero al intentar compilar me sale error (s): espera expresión antes 'asm '

(puede ignorar todo por debajo de esto si usted valora su tiempo, pero que sería bueno si se toma una mirada en ella, la cuestión principal aquí es cómo hacer el trabajo más arriba)

he intentado esto :

static inline GLfixed MULT(GLfixed a, GLfixed b){ 
     asm volatile(
     "SMULL r2, r3, %[a], %[b]\n" 
     "ADD r2, r2, #0x8000\n" 
     "ADC r3, r3, #0\n" 
     "MOV %[a], r2, ASR#16\n" 
     "ORR %[a], %[a], r3, ASL#16\n" 
     : "=r" (a) 
     : [a] "r" (a), [b] "r" (b) 
     : "r2", "r3"); 
    return a; } 

Esto compila pero no parece ser un problema porque cuando uso constantes ex: MULT (65536,65536) funciona, pero cuando utilizo las variables parece f ** k arriba:

GLfixed m[16]; 
m[0]=costab[player_ry];//1(65536 integer representation) 
m[5]=costab[player_rx];//1(65536 integer representation) 
m[6]=-sintab[player_rx];//0 
m[8]=-sintab[player_ry];//0 
LOG("%i,%i,%i",m[6],m[8],MULT(m[6],m[8])); 
m[1]=MULT(m[6],m[8]); 
m[2]=MULT(m[5],-m[8]); 
m[9]=MULT(-m[6],m[0]); 
m[10]=MULT(m[5],m[0]); 
m[12]=MULT(m[0],0)+MULT(m[8],0); 
m[13]=MULT(m[1],0)+MULT(m[5],0)+MULT(m[9],0); 
m[14]=MULT(m[2],0)+MULT(m[6],0)+MULT(m[10],0); 
m[15]=0x00010000;//1(65536 integer representation) 

int i=0; 
while(i<16) 
{ 
    LOG("%i,%i,%i,%i",m[i],m[i+1],m[i+2],m[i+3]); 
    i+=4; 
} 

el código anterior imprimir (LOG es como printf aquí):

0,0,-1411346156 
65536,65536,65536,440 
-2134820096,65536,0,-1345274311 
0,65536,22,220 
65536,196608,131072,65536 

Cuando el resultado correcto sería (obviamente un montón de basura en el anterior):

0,0,0 
65536,0,0,0 
0,65536,0,0 
0,0,65536,0 
0,0,0,65536 

Respuesta

3

¿Has probado el código C simple en lugar del montaje? En mi sistema con GCC 4.5.3 el compilador genera código que es al menos tan buena como la mano ensamblador escrito:

int mul (int a, int b) 
{ 
    long long x = ((long long)a * b + 0x8000); 
    return x>>16; 
} 

compila a la siguiente asm-código:

# input: r0, r1 
mov r3, #32768 
mov r4, #0 
smlal r3, r4, r0, r1 
mov r0, r3, lsr #16 
orr r0, r0, r4, asl #16 
# result in r0 

(función de llamada de epílogo y prólogo eliminado)

El código se vuelve aún mejor si tiene múltiples multiplicaciones en una sola función porque el compilador eliminará las instrucciones mov r3, # 32768 redundantes.

5

La primera parte es bastante fácil: el problema es que un bloque __asm__ es una declaración, no una expresión.

Puede utilizar la extensión de GCC statement expressions para lograr lo que quiere - algo como esto:

#define MULT(a,b) \ 
    ({ \ 
    __asm__ __volatile__ (\ 
     /* ... asm stuff here ... */ 
    ); \ 
    a; \ 
    }) 

La segunda parte es debido a problemas en las especificaciones de entrada y de salida de operando. Aquí tienes dos versiones diferentes, y ambas están equivocadas. En la versión macro, que ha dicho:

: "=r" (a) : "0"(a), "1"(b) : "r2", "r3" 

que las obliga

  • la salida a a un registro (esto es el operando 0);
  • la entrada a es lo mismo que el operando 0, es decir, el mismo registro (este es el operando 1);
  • la entrada b es lo mismo que el operando 1, es decir, el mismo nuevamente (este es el operando 2).

Necesita "r"(b) aquí, y puede referirse a él como %2.

En la versión en línea, usted ha dicho:

: "=r" (a) : [a] "r" (a), [b] "r" (b) : "r2", "r3" 

que limita la salida y la entrada aa y b a los registros, pero

  • no declara ninguna relación entre ellos ;
  • el asm nunca se refiere explícitamente al operando de salida (no le ha dado un nombre al operando de salida, y el código asm no se refiere a %0).

Usted debe ser capaz de solucionar la versión original con:

: "=r" (a) : "0" (a), "r" (b) : "r2", "r3" 

y se refieren a la a ya sea como %0 o %1 y b como %2.

La versión en línea se puede fijar de esta manera:

: [a] "=r" (a) : "[a]" (a), [b] "r" (b) : "r2", "r3" 

y se refieren los operandos como %[a] y %[b].

Si desea utilizar nombres en la versión macro, necesitará algo en la línea de

: [arg_a] "=r" (a) : "[arg_a]" (a), [arg_b] "r" (b) : "r2", "r3" 

(y se refieren a %[arg_a] y %[arg_b]) porque de lo contrario el preprocesador se ampliará el a y b interior [a] y [b].

Observe la sutileza en los casos de argumentos nombrados: cuando se asigna un nombre a un argumento (como en el resultado a) escriba [a] - sin comillas - pero cuando se refiere al nombre de otro operando ya nombrado (como en la entrada a) necesita ponerlo dentro de las cotizaciones: "[a]".

Cuestiones relacionadas