2014-03-19 72 views
5

我編譯這個C函數:爲什麼這個IA32彙編代碼有三條leal指令?

int calc(int x, int y, int z) { 
    return x + 3*y + 19*z; 
} 

而且我在calc.s得到這個,而我註釋發生了什麼事:

 .file "calc.c" 
     .text 
.globl calc 
     .type calc, @function 
calc: 
     pushl %ebp     //Save paramaters 
     movl %esp, %ebp    //Move stack pointer into %ebp 
     movl 12(%ebp), %eax   //Move y into %eax 
     movl 16(%ebp), %ecx   //Move z into %ecx 
     leal (%eax,%eax,2), %eax  //%eax = 3*y 
     addl 8(%ebp), %eax   //%eax = x+3y 
     leal (%ecx,%ecx,8), %edx  // ? 
     leal (%ecx,%edx,2), %edx  // ? 
     addl %edx, %eax    //%eax = (x+3*y)+(19*z) 
     popl %ebp     //Pop the previous pointer 
     ret 
     .size calc, .-calc 
     .ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3" 
     .section  .note.GNU-stack,"",@progbits 

我明白了一切到最後兩個萊亞爾指令。爲什麼你需要兩個19 * z的leal指令,而3 * y是在一個指令中完成的。

+0

見謝爾蓋的答案 - lea只能乘以2,4或8. –

+0

一般的答案是,LEA指令的作用類似於來自小常量1,2,4,8的乘加指令。通過使用它們,可以在幾條機器指令中乘以不同的值,這比使用真正的乘法指令更快。 –

回答

7

leal是一種通過廉價的小常數來執行乘法的方法,如果常數是2加1的乘方。這個想法是沒有抵消的萊爾相當於「Reg1 = Reg2 + Reg3 * Scale」。如果Reg2中和REG3正好匹配,這意味着「Reg1中= Reg2中*(比例+ 1)。

leal只支持比例因子最多8個,所以19乘,你需要兩個。

的影響的

leal (%eax,%eax,2), %eax 

是:

eax = eax + eax*2 

它是由三說,乘法

。 10

後兩個lealš在一起19執行乘法:

leal (%ecx,%ecx,8), %edx  // edx = ecx+ecx*8 
leal (%ecx,%edx,2), %edx  // edx = ecx+edx*2 (but edx is already z*9) 
+0

現在有了完美的感覺,謝謝 – MeesterMarcus

4
leal (%ecx,%ecx,8), %edx # edx = ecx + 8*ecx = 9*ecx = 9 * z 
leal (%ecx,%edx,2), %edx 
# edx = ecx + 2*edx = ecx + 2 * (ecx + 8*ecx) = z + 2 * 9 * z = 19 * z 

lea指令使用添加和bitshifts和更快然後使用mul整數乘法這樣做的原因。 Lea受限於1,2,4和8倍增因子 - 因此有兩條指令。

+1

這回答了另一個問題:「什麼是LEA」用於?這不回答OP的問題「爲什麼你需要兩條指令?」 – anatolyg

2

lea有雙重目的,一個是計算地址,但它也可以用於與一些約束算法,爲你和你的代碼中觀察到。需要兩個電話,因爲lea標量乘數是limited to 1, 2, 4 or 8這意味着通過19,讓您的乘法需要兩次調用lea

[...]標量乘數被限制爲固定值1,2,4 ,或8個字節,字,雙字或四字偏移分別。這本身允許通過的恆定值2,3,4,5,8和9通用寄存器的乘法,[...]

所以你的情況有:

leal (%ecx,%ecx,8), %edx  // edx = ecx + ecx*8 which is z*8 + z = z*9 
leal (%ecx,%edx,2), %edx  // edx = ecx + edx*2 which gives us (z*9)*2 + z 
           // for a total of 19z