Inner-loop optimization regression from 3.3 to 3.4

Jan Hubicka jh@suse.cz
Mon Oct 13 17:01:00 GMT 2003


> 
> I wanted a break from machine modes so I thought I'd squeeze some
> cycles out of _cpp_skip_block_comment.  In the process I discovered
> a serious optimization regression in 3.4, relative to 3.3.
> 
> Consider code like the following.
> 
> void
> _cpp_skip_block_comment (struct cpp_buffer *buf)
> {
>   unsigned char c, *cur = buf->cur;
> 
>   for (;;)
>     {
>       do
>         c = *cur++;
>       while (c != '/' && c != '\n');
> 
>       if (c == '/')
>         {
>           if (cur[-2] == '*'
>             break;
>         
>           foo();
>         }
>       else if (c == '\n')
>         bar();
>    }
>   buf->cur = cur;
> }
> 
> 3.3 generates code like this (I'm only showing the inner loop):
> 
> .L93:
>         incl    %ebx
>         cmpb    $47, %al
>         je      .L92
>         cmpb    $10, %al
>         je      .L94
> .L88:
>         movzbl  (%ebx), %eax
>         jmp     .L93
> 
> whereas 3.4 generates code like this:
> 
> .L93:
>         incl    %ebx
>         cmpb    $47, %cl
>         setne   %al
>         xorl    %edx, %edx
>         cmpb    $10, %cl
>         setne   %dl
>         testl   %eax, %edx
>         jne     .L88

This sequence is produced by fold-const that now is able to fold x && y
into (x!=0) & (y!=0).  This commonly lose on i386 because setcc is quite
expensive.  The two duplicated tests are consequence of fact that RTL
optimizers never see the original comparsions.

On hammer branch we do have patch to use the conversion only for |,
where !=0 can be ommited so the sequence is shorter and usually a win
(depending on the cost of evaulation of second operand and branch
probabilities).  We can use same way on mainline, but this may or may
not be win for some other architectures, depending on the cost of setcc
equivalent, so perhaps this can be conditionalized by BRANCH_COST.

Overall I do believe that such things are very target specific and
require knowledge of branch probabilities and costs to be done properly,
so it belongs to backend.  I wrote ifcvt imporvement to deal with such a
testcases at:
http://gcc.gnu.org/ml/gcc-patches/2002-06/msg00026.html
It is able to combine || and && style tests (sequence of branches
targetting the same destination)

It is used on hammer branch for a while and does not appear to cause any
problems now when RTL sharing issues are sorted out.  It causes small
but measurable SPEC imrovement (about 2points if I recall correctly).
I can update the patch easilly for current tree if it would be
considered for mainline.  There is small conflict with related IA-64
specific work for multiway branches.  ALso I was told that for IA-64 we
may extend the patch to deal with sequence of multiple branches, not
only combining two at a time.

Honza
>         cmpb    $47, %cl
>         je      .L92
>         cmpb    $10, %cl
>         je      .L94
> .L88:
>         movzbl  (%ebx), %ecx
>         jmp     .L93
> 
> It seems obvious that 3.4 is significantly worse.  Jan, I'm cc:ing you
> because you know the i386 back end and the RTL optimizers quite well.
> But if anyone has any idea what has happened here and how we can fix
> it, that would be cool.
> 
> My patch is a significant win for other reasons, so I'll be checking
> it in after it completes testing - if you want to see the code before
> it shows up in CVS, let me know.
> 
> zw



More information about the Gcc mailing list