avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-gcc-list] Re: Suspect optimizer missed code in avr-gcc 4.4.3..


From: David Brown
Subject: [avr-gcc-list] Re: Suspect optimizer missed code in avr-gcc 4.4.3..
Date: Tue, 16 Feb 2010 11:46:58 +0100
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20100111 Lightning/1.0b1 Thunderbird/3.0.1

On 16/02/2010 06:10, Weddington, Eric wrote:


-----Original Message-----
From:
address@hidden
[mailto:address@hidden
org] On Behalf Of uhmgawa
Sent: Tuesday, February 16, 2010 6:38 AM
To: address@hidden
Subject: [avr-gcc-list] Suspect optimizer missed code in
avr-gcc 4.4.3..

I've seen some similar bug reports but not specifically
related to a bitwise-and operation where more than one
set bit exists in the constant operand.  Note if the
constant '3' is replaced with an 'unsigned char'
variable of the same value, the expected minimal
code sequence results (sans the fetch of the added
variable from memory).

Here is a list of known AVR GCC bug reports:
<http://www.nongnu.org/avr-libc/bugs.html>
Please note the ones marked as "missed optimization". See if your bug fits one 
of those. If not, then please submit a bug report to the GCC project.

I've had a quick check on this one - I can confirm the O/P's results using a number of different WinAVR releases, including the latest.

It is a similar case to
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34791>

I've added the OP's example code, and some more comments (copied below for convenience).

mvh.,

David




There are many other cases where 8-bit optimisation is missing - C's integer promotion gets in the way. This is particularly common when dealing with a compile-time constant - there is no way in C to say that "0x3f" is 8-bit rather than a 16-bit int.

Another example of code with this problem is:

void foo(void) {
    static unsigned char count;

    if (++count & 0x3f) {
        PORTC &= ~0x01;
    } else {
        PORTC |= 0x01;
    }
}

Both the "&" and the comparison with zero are done as 16-bit.


One work-around is to use this macro:

#define const_byte(x) ({ static const __attribute__((__progmem__)) \
                         unsigned char v = x; v; })

Then we can write:

#define const_byte(x) ({ static const __attribute__((__progmem__)) \
                         unsigned char v = x; v; })

uint8_t bar3(uint8_t x, uint8_t y) {
        return data[y ^ (x & const_byte(0x0f))];
}

147                     bar3:
 148                    /* prologue: function */
 149                    /* frame size = 0 */
 150 008c 8F70                  andi r24,lo8(15)         ;  tmp45,
 151 008e 8627                  eor r24,r22      ;  tmp45, y
 152 0090 E0E0                  ldi r30,lo8(data)        ;  tmp48,
 153 0092 F0E0                  ldi r31,hi8(data)        ;  tmp48,
 154 0094 E80F                  add r30,r24      ;  tmp48, tmp45
 155 0096 F11D                  adc r31,__zero_reg__     ;  tmp48
 156 0098 8081                  ld r24,Z         ; , data
 157                    /* epilogue start */
 158 009a 0895                  ret
 160


As far as I can see, this generated code is optimal.

The macro works because it forces the value to be 8-bit, rather than a 16-bit compile-time constant. However, the compiler is still smart enough to see that since it's a "const" with known value, it's value can be used directly. As a side effect, the static "variable" must be created somewhere - by using __progmen__, we create it in flash rather than wasting ram. Even that waste could be spared by garbage-collection linking, or by using a dedicated segment rather than .progmem.data.






reply via email to

[Prev in Thread] Current Thread [Next in Thread]