[4.2] MIPS: missed optimization

Richard Sandiford rdsandiford@googlemail.com
Tue Nov 25 09:24:00 GMT 2008


Manuel Lauss <mano@roarinelk.homelinux.net> writes:
> On Sun, Nov 23, 2008 at 05:14:27PM +0000, Richard Sandiford wrote:
>> Richard Sandiford <rdsandiford@googlemail.com> writes:
>> > Manuel Lauss <mano@roarinelk.homelinux.net> writes:
>> >> Admittedly my understanding of mips assembly is not yet very advanced, am I
>> >> missing something or is this a bug?
>> >
>> > Well, it's a missed optimisation, certainly.  Fortunately,
>> > it's conceptually fairly easy to fix.
>> 
>> FWIW, I've attached a patch against GCC 4.4 below.  Tested on
>> mipsisa64-elfoabi.
>> 
>> I don't think it's appropriate to apply the patch at this stage
>> in the development cycle, so I'll hold it back for GCC 4.5.
>> I'll add some testcases then too.
>
> I tested this with 4.3.2 and it works very well.

Great!  Thanks for testing it.

> One minor thing though if you don't mind.  Consider this C snippet:
>
> -------------- 8< ------------------------- >8 ----------------
>
> #define SYS_CNTRL_M21   (1 << 19)
> #define SYS_COUNTER_CNTRL 0xb1900014
> #define SYS_RTCMATCH2   0xb1900054
> #define SYS_RTCREAD     0xb1900058
>
> int au1x_rtcmatch2_set_next_event(unsigned long delta, void *x)
> {
>   unsigned long next;
>
>   next = *(unsigned long *)(SYS_RTCREAD) + delta;
>
>   /* wait for register access */
>   while (*(unsigned long *)(SYS_COUNTER_CNTRL) & SYS_CNTRL_M21)
>     ;
>   *(unsigned long *)(SYS_RTCMATCH2) = next;
>   asm volatile ("sync");
> }
>
> -------------- 8< ------------------------- >8 -------------
>
> My patched gcc generates this with -O2 (-Os is actually worse):
>
> 0x00000028 <au1x_rtcmatch2_set_next_event+0>:   lui     v0,0xb190
> 0x0000002c <au1x_rtcmatch2_set_next_event+4>:   lw      v1,88(v0)
> 0x00000030 <au1x_rtcmatch2_set_next_event+8>:   lui     a2,0xb190
> 0x00000034 <au1x_rtcmatch2_set_next_event+12>:  lui     a1,0x8
> 0x00000038 <au1x_rtcmatch2_set_next_event+16>:  lw      v0,20(a2)
> 0x0000003c <au1x_rtcmatch2_set_next_event+20>:  and     v0,v0,a1
> 0x00000040 <au1x_rtcmatch2_set_next_event+24>:  bnez    v0,0x38 <au1x_rtcmatch2_set_next_event+16>
> 0x00000044 <au1x_rtcmatch2_set_next_event+28>:  lui     v0,0xb190
> 0x00000048 <au1x_rtcmatch2_set_next_event+32>:  addu    v1,a0,v1
> 0x0000004c <au1x_rtcmatch2_set_next_event+36>:  sw      v1,84(v0)
> 0x00000050 <au1x_rtcmatch2_set_next_event+40>:  sync
> 0x00000054 <au1x_rtcmatch2_set_next_event+44>:  jr      ra
> 0x00000058 <au1x_rtcmatch2_set_next_event+48>:  nop
>
> IMO gcc's register usage is a bit odd;  when the 'addu' at 0x48
> is moved to 0x30 (as 'addu a0,a0,v1'), v1 could be reused and the
> two additional 'lui v0,0xb190' become unecessary, saving 2 insns.
> (This code is called fairly often, so I do care about performance ;-))

Hmm, GCC 4.4 suffers from the same problem.  Before CSE1 we have:

     R1 := 0xb1900000
     load R1+88
     ...
loop:
     ...
     R2 := 0xb1900000
     load R2+20
     ...
     R3 := 0xb1900000
     store R3+84

After CSE we have:

     R1 := 0xb1900000
     load R1+88
     ...
loop:
     ...
     R2 := 0xb1900000
     load R2+20
     ...
     store R2+84           <--- A

where the important thing is that A uses R2 instead of R1.
Loop hoisting converts this to:

     R1 := 0xb1900000
     load R1+88
     ...
     R4 := 0xb1900000
loop:
     ...
     R2 := R4
     load R4+20
     ...
     store R2+84

where the loop still has an assigment to R2, even though it is
now only used after the loop.  Then the GCSE "bypass" pass comes
along and replaces this with:

     R1 := 0xb1900000
     load R1+88
     ...
     R4 := 0xb1900000
loop:
     ...
     R2 := 0xb1900000
     load R4+20
     ...
     store R2+84           <--- A

As a workaround, -fno-gcse produces good code for this testcase with 4.4.
Maybe it will for 4.3 too.  It might well make other functions worse though.

Richard



More information about the Gcc mailing list