> >> On Mon, May 11, 2009 at 4:45 PM, Jamie Prescott wrote: > >> > >>> Hi! > >>> I wanted to add finer (one per) register subclasses, so that I can more > finely > >> control > >>> the register placement inside the inline assembly. > >> > >> You don't need that. > >> You can just use asm("registername") on variables. > >> like so: > >> > >> int f(int a) > >> { > >> register int r0 __asm__("r0"); > >> asm("use %0": "+r"(r0) ); > >> } > >> > >> Thanks, > >> Andrew Pinski > > That works with gcc 3.x but causes trouble and won't work smooth with gcc 4.x. > > Here are just two examples that will crash for target AVR: > > // ice.c //////////////////////////////////////////////// > typedef union > { > unsigned char asByte[2]; > unsigned short asWord; > } data16_t; > > data16_t mac10 (data16_t); > > void put_sfrac16 (data16_t q) > { > unsigned char i; > for (i=0; i < 2; i++) > { > register data16_t digit asm ("r24"); > digit.asByte[1] = 0; > > digit.asByte[0] = q.asByte[0]; > digit = mac10 (digit); > q.asByte[0] = digit.asByte[0]; > } > } > ////////////////////////////////////////////////// > > compiling this with > > avr-gcc ice.c -Os -S > rund into ICE in fwprop: > > ice.c: In function 'put_sfrac16': > ice.c:21: internal compiler error: in propagate_rtx, at fwprop.c:469 > > > GNU C (WinAVR 20090313) version 4.3.2 (avr) compiled by GNU C > > version 3.4.5 (mingw-vista special r3), GMP version 4.2.3, > > MPFR version 2.4.0. > > > The second example shows that global register variables are pretty much > useless > in gcc 4.x. I am using global registers in gcc 3.4.6 and it work smooth. > Without > global regs I would have to pay considerable performance penalties, so I am > still using avr-gcc 3.4.6 (which produces code that is both faster and > smaller > than code from any avr-gcc 4.x I tested so far: from 4.1 up to 4.5). Here it > is: > > // bug.c /////////////////////////////////////////////// > // avr-gcc bug.c -Os -S -ffixed-2 -ffixed-3 > > register unsigned int currData asm ("r2"); > > // from > typedef unsigned int uint8_t __attribute__((__mode__(__QI__))); > > // from > #define PINB (*(volatile uint8_t *)(0x16 + 0x20)) > #define PORTB (*(volatile uint8_t *)(0x18 + 0x20)) > > // from > void __vector_1 (void) __attribute__ ((signal,used,externally_visible)); > void __vector_1 (void) > { > // Nothing special, just an ISR that depends on currData > if (currData & 0x4000) > PORTB |= 2; > else > PORTB &= ~2; > > currData = currData << 1; > } > > void foo (void) > { > for (;;) > { > while (PINB & 1); > currData = 0x2123; > while (!(PINB & 1)); > } > } > ////////////////////////////////////////////////////// > > CSE decides that currData in foo is dead. As everyone can see, the produced > assembler does not touch the global register R3:R2. Making global reg vars > volatile is iseless (gcc goesn' even warn about that and gcc doesn't even > have a > flag to tag a global reg volatile). > > There are just (conditional) branches left that jump around and poll SFRs: > > foo: > /* prologue: function */ > /* frame size = 0 */ > .L13: > sbic 54-32,0 ; 12 *sbix_branch [length = 2] > rjmp .L13 > .L10: > sbis 54-32,0 ; 22 *sbix_branch [length = 2] > rjmp .L10 > rjmp .L13 ; 50 jump [length = 1] > .size foo, .-foo > > Global register variables can boost performance in embedded applications. > It's a > pitty that this is pretty much useless in "modern" gcc 4.x.
Oh, this is bad news :/ Is the problem only with global register allocations, or even with local ones? Wouldn't the approach of having register subclasses and handling them with ad-hoc contraints (like the road I took before) be a more universally working solution? - Jamie