For setting individual bits of a register, the construct
unsigned char BitLocation = Whatever;
REG |= (1<<BitLocation);
is commonly used. avr-gcc fails to realize that the target register
is only 8 bits wide and performs an unnecessary 16-Bit shift of 1.
Even if this code snippet is replaced by the following:
unsigned char BitLocation = Whatever;
const unsigned char one = 1;
REG |= (one << BitLocation);
The inefficient code will be generated, even with the -Os flag.
I suppose this is because the << operator is not defined for 8-bit
wide data types.
Environment:
System: Darwin variable.local 7.9.0 Darwin Kernel Version 7.9.0: Wed Mar 30
20:11:17 PST 2005; root:xnu/xnu-517.12.7.obj~1/RELEASE_PPC Power Macintosh
powerpc
host: powerpc-apple-darwin7.9.0
build: powerpc-apple-darwin7.9.0
target: avr-unknown-none
configured with: ../configure --target=avr --prefix=/usr/local/atmel
--enable-languages=c --disable-libssp --enable-__cxa_atexit
--enable-clocale=gnu --disable-nls : (reconfigured) ../configure --target=avr
--prefix=/usr/local/avr --enable-languages=c --disable-libssp
--enable-__cxa_atexit --enable-clocale=gnu --disable-nls
How-To-Repeat:
Use the following test program, compile with -Os -S to see assembler
code generated by avr-gcc:
#include <avr/io.h>
void setpin(unsigned char pin, unsigned char val) {
if (val == 1) PORTC |= (1<<pin);
else PORTC &= ~(1<<pin);
}
void setpin1(unsigned char pin, unsigned char val) {
const unsigned char one = 1;
if (val == 1) PORTC |= (one<<pin);
else PORTC &= ~(one<<pin);
}
int main(void) {
setpin(3, 1);
setpin1(3, 1);
return 0;
}
------- Comment #1 from r dot leitgeb at x-pin dot com 2006-10-23 11:39 -------
Fix:
Define shift operators for 8 bit wide data types, use if possible.
I'm not a compiler expert but I know that the multiply operator
detects the data types involved, so it should be doable with the
shift operators as well.
--
Summary: Poor optimization for character shifts on Atmel AVR
Product: gcc
Version: 4.1.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: r dot leitgeb at x-pin dot com
GCC build triplet: powerpc-apple-darwin7.9.0
GCC host triplet: powerpc-apple-darwin7.9.0
GCC target triplet: avr-unknown-none
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29560