除了上一节提到的循环结构外,if...else...之类的条件选择语句也需要进行优化,因为if...else...语句生成的汇编指令中的jle之类的条件跳转指令,会让处理器的指令预取缓存措施大打折扣...
if: <condition to evaluate> jxx else ; jump to the else part if the condition is false <code to implement the "then" statements> jmp end ;jump to the end else: < code to implement the "else" statements> end: |
if (eax < ebx) || (eax == ecx) then < then logic code> else < else logic code > |
if: cmpl %eax, %ebx jg then cmpl %eax, %ecx jne else then: < then logic code> jmp end else: < else logic code > end: |
/* condtest.c - An example of optimizing if-then code */
#include <stdio.h>
int conditiontest(int test1, int test2)
{
int result;
if (test1 > test2)
{
result = test1;
}
else if (test1 < test2)
{
result = test2;
}
else
{
result = 0;
}
return result;
}
int main()
{
int data1 = 10;
int data2 = 30;
printf("The result is %d\n", conditiontest(data1, data2));
return 0;
}
|
$ gcc -S condtest.c $ cat condtest.s .file "condtest.c" .text .globl conditiontest .type conditiontest, @function conditiontest: pushl %ebp movl %esp, %ebp subl $16, %esp movl 8(%ebp), %eax cmpl 12(%ebp), %eax jle .L2 movl 8(%ebp), %eax movl %eax, -4(%ebp) jmp .L3 .L2: movl 8(%ebp), %eax cmpl 12(%ebp), %eax jge .L4 movl 12(%ebp), %eax movl %eax, -4(%ebp) jmp .L3 .L4: movl $0, -4(%ebp) .L3: movl -4(%ebp), %eax leave ret .size conditiontest, .-conditiontest .section .rodata .LC0: .string "The result is %d\n" .text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $32, %esp movl $10, 28(%esp) movl $30, 24(%esp) movl 24(%esp), %eax movl %eax, 4(%esp) movl 28(%esp), %eax movl %eax, (%esp) call conditiontest movl $.LC0, %edx movl %eax, 4(%esp) movl %edx, (%esp) call printf movl $0, %eax leave ret .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.5.3-12ubuntu2) 4.5.3" .section .note.GNU-stack,"",@progbits $ |
movl 8(%ebp), %eax cmpl 12(%ebp), %eax jle .L2 movl 8(%ebp), %eax movl %eax, -4(%ebp) jmp .L3 .L2: movl 8(%ebp), %eax cmpl 12(%ebp), %eax jge .L4 movl 12(%ebp), %eax movl %eax, -4(%ebp) jmp .L3 .L4: movl $0, -4(%ebp) .L3: movl -4(%ebp), %eax |
$ gcc -O3 -S -o condtest2.s condtest.c $ cat condtest2.s .file "condtest.c" .text .p2align 4,,15 .globl conditiontest .type conditiontest, @function conditiontest: pushl %ebp movl %esp, %ebp movl 12(%ebp), %edx movl 8(%ebp), %eax cmpl %edx, %eax jg .L2 movl $0, %eax cmovl %edx, %eax .L2: popl %ebp ret .size conditiontest, .-conditiontest .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "The result is %d\n" .text .p2align 4,,15 .globl main .type main, @function main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $16, %esp movl $30, 8(%esp) movl $.LC0, 4(%esp) movl $1, (%esp) call __printf_chk xorl %eax, %eax leave ret .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.5.3-12ubuntu2) 4.5.3" .section .note.GNU-stack,"",@progbits $ |
movl 12(%ebp), %edx movl 8(%ebp), %eax cmpl %edx, %eax jg .L2 movl $0, %eax cmovl %edx, %eax .L2: popl %ebp ret |
/* csetest.c - An example of implementing cse optimization */ #include <stdio.h> void funct1(int a, int b) { int c = a * b; int d = (a * b) / 5; int e = 500 / (a * b); printf("The results are c=%d d=%d e=%d\n", c, d, e); } int main() { int a = 10; int b = 25; funct1(a, b); funct1(20, 10); return 0; } |
$ gcc -S csetest.c $ cat csetest.s ................................. ................................. funct1: pushl %ebp movl %esp, %ebp subl $56, %esp movl 8(%ebp), %eax imull 12(%ebp), %eax movl %eax, -12(%ebp) movl 8(%ebp), %eax movl %eax, %ecx imull 12(%ebp), %ecx movl $1717986919, %edx movl %ecx, %eax imull %edx sarl %edx movl %ecx, %eax sarl $31, %eax movl %edx, %ecx subl %eax, %ecx movl %ecx, %eax movl %eax, -16(%ebp) movl 8(%ebp), %eax movl %eax, %edx imull 12(%ebp), %edx movl %edx, -28(%ebp) movl $500, %eax movl %eax, %edx sarl $31, %edx idivl -28(%ebp) movl %eax, -20(%ebp) movl $.LC0, %eax movl -20(%ebp), %edx movl %edx, 12(%esp) movl -16(%ebp), %edx movl %edx, 8(%esp) movl -12(%ebp), %edx movl %edx, 4(%esp) movl %eax, (%esp) call printf leave ret ................................. ................................. $ |
$ gcc -O3 -S -o csetest2.s csetest.c $ cat csetest2.s ................................ ................................ funct1: pushl %ebp movl $500, %eax movl %esp, %ebp subl $40, %esp movl 12(%ebp), %ecx movl %eax, %edx imull 8(%ebp), %ecx sarl $31, %edx movl $.LC0, 4(%esp) movl $1, (%esp) idivl %ecx movl $1717986919, %edx movl %ecx, 8(%esp) movl %eax, 16(%esp) movl %ecx, %eax imull %edx movl %ecx, %eax sarl $31, %eax sarl %edx subl %eax, %edx movl %edx, 12(%esp) call __printf_chk leave ret ................................ ................................ $ |