Canonicalization helps detect CommonSubExpressions, for example:
#include <stdio.h> int main(void) { unsigned u, pos; char buff[40]; for (u=pos=0; u < 10; u++) { buff[pos++] = (u <5) ? 'A' + u : 'a' + u; buff[pos++] = (u <=4) ? '0' + u : 'A' + u; } buff[pos++] = 0; printf("=%s=\n", buff); return 0; }
GCC -O1 compiles this into:
... movl $1, %edx movl $65, %ecx .L4: cmpl $4, %eax ja .L2 movb %cl, (%rsi) leal 48(%rax), %r8d jmp .L3 .L2: leal 97(%rax), %edi movb %dil, (%rsi) movl %ecx, %r8d .L3: mov %edx, %edi movb %r8b, (%rsp,%rdi) addl $1, %eax addl $1, %ecx addl $2, %edx addq $2, %rsi cmpl $10, %eax jne .L4 movb $0, 20(%rsp) movq %rsp, %rdx movl $.LC0, %esi movl $1, %edi movl $0, %eax call __printf_chk ...
GCC -O2 will actually delete the entire cycle and replace it with the destination stream.
source share