2014-03-19 46 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