2011-05-24 123 views
5

我試圖使用定點乘法的組件(ARM)宏:GCC ARM彙編預處理宏

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

但是當試圖編譯我得到錯誤(S):之前預期的表達「ASM'

(您可以忽略下面這一切,如果你珍惜你的時間,但如果你看了看它這將是很好,這裏的主要問題是如何使上述工作)

我想這:

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

這將編譯但似乎是一個問題,因爲當我使用常量例如:MULT(65536,65536),它的工作原理,但是當我使用變量似乎他媽的起來:

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

上面的代碼將打印(LOG是如printf這裏):

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

當正確的結果將是(很明顯,很多垃圾在上面):

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

回答

3

您是否試過簡單的C代碼而不是程序集?我與GCC 4.5.3系統的編譯器生成的代碼,至少是一樣好你的手寫彙編:

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

編譯下面的ASM-代碼:

# 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 

(函數調用收尾和序言刪除)

如果您在單個函數中有多個乘法,代碼變得更好,因爲編譯器將刪除多餘的mov r3,#32768指令。

5

第一部分很簡單:問題在於__asm__塊是一個語句,而不是一個表達式。

您可以使用GCC的statement expressions擴展達到你想要的東西 - 是這樣的:

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

第二部分是由於輸入和輸出操作規範的問題。你在這裏有兩個不同的版本,都是錯誤的。在宏版本,你說:

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

從而限制了

  • 輸出a到寄存器(這是操作數0);
  • 輸入a與操作數0相同,即相同的寄存器(這是操作數1);
  • 輸入b與操作數1相同,即再次相同(這是操作數2)。

這裏您需要"r"(b),可以參考它%2

在在線版本,你說:

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

這限制了輸出a和輸入ab到寄存器,但

  • 不聲明它們之間的任何關係;
  • asm從不明確指向輸出操作數(您沒有給出輸出操作數一個名稱,並且asm代碼不涉及%0)。

你應該能夠與修復原始版本:

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

,並參考a爲任何%0%1,並b%2

的共線版本可以固定這樣的:

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

,並且是指操作數爲%[a]%[b]

如果你想在宏版本中使用的名稱,你需要沿着

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

東西線(並參考%[arg_a]%[arg_b]),否則預處理器將擴大ab[a][b]

請注意指定參數情況下的細微之處:當給參數指定名稱時(如輸出a),您編寫[a] - 不含引號 - 但是當您引用另一個已命名操作數的名稱時(如在輸入a),你需要把它放在引號:"[a]"