为什么这个IA32汇编代码有三个leal指令?

Mee*_*cus 5 c x86 assembly intel

我编译了这个C函数:

int calc(int x, int y, int z) {
   return x + 3*y + 19*z;
}
Run Code Online (Sandbox Code Playgroud)

我在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
Run Code Online (Sandbox Code Playgroud)

我理解最后两个leal指令的一切.为什么你需要两个19*z的leal指令,而3*y是在一个指令中完成的.

Sev*_*yev 7

leal如果常数是2加1的幂,则是以便宜的方式执行乘以小常数的方法.这个想法是没有偏移的leal相当于"Reg1 = Reg2 + Reg3*Scale".如果Reg2和Reg3恰好匹配,则表示"Reg1 = Reg2*(Scale + 1).

leal 只支持最多8的比例因子,所以要乘以19,你需要两个.

的效果

leal   (%eax,%eax,2), %eax
Run Code Online (Sandbox Code Playgroud)

是:

eax = eax + eax*2
Run Code Online (Sandbox Code Playgroud)

也就是说,乘以三.

第二个两个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)
Run Code Online (Sandbox Code Playgroud)