[Top][All Lists]
[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.