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.