Extending constraints using register subclasses

Georg-Johann Lay avr@gjlay.de
Wed May 13 20:58:00 GMT 2009


Jamie Prescott schrieb:
> Thank you Andrew, I wasn't aware of that. Will be going that way.
> Just out of curiosity, was there something flawed in the way I took before?
> Meaning, could have been done that way, but my code was wrong somewhere?
> 
>  - Jamie
> 
> ----- Original Message ----
> 
>>From: Andrew Pinski <pinskia@gmail.com>
>>To: Jamie Prescott <jpresss@yahoo.com>
>>Cc: gcc@gcc.gnu.org
>>Sent: Monday, May 11, 2009 4:47:57 PM
>>Subject: Re: Extending constraints using register subclasses
>>
>>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 <inttypes.h>
typedef unsigned int uint8_t __attribute__((__mode__(__QI__)));

// from <avr/io.h>
#define PINB (*(volatile uint8_t *)(0x16 + 0x20))
#define PORTB (*(volatile uint8_t *)(0x18 + 0x20))

// from <avr/interrupt.h>
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.

Georg-Johann



More information about the Gcc mailing list