problems with register variable (inline ASM)

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was reading how to force the compiler to use register var.

Why is this program not working !

void main(void){
volatile register char i asm("r2");

int x;

asm volatile("clr r2");

i=100;
for (x=1;x<1000;x++){
i+=x;
}
}

no errors (warning that main don't return an int)
the asm part make the code
but there is no code for i=100 and i+=x
i should be an int when I get it to work but the code here is as close I can get to the manual code

Jens

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok if I add a volatile variable that get i (test=i) after the loop, the code for i is made.
So now ny question is why is volatile for i not working?
And next are there any way to get the compiler to use movw and not two mov ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you have to declare i outside of main. The register allocation is only possible for static variables, and if you declare i within main it is an auto variable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
So now ny question is why is volatile for i not working?
volatile is working. If you take the volatile out the compiler optimizes everything away (with -Os).

It says in the documentation

Quote:
This makes sense only for external or static variables, because local variables do not have symbolic names in the assembler code. However, local variables may be held in registers.

Yet the last part seems not to be true anymore (tried with 4.1.0, 4.1.1, 4.2.2). I'm not quite sure if the documentation or gcc is at fault.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks

MegaTorr

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Why is this program not working !

That program (like so many of these short "test programs" presented here) doesn't actually DO anything does it? The optimiser can see this and therefore doesn't generate any code.

Was the intention that this for() loop be a delay of some sort (in which case the well engineered util/delay.h already provides much better options) or was the intention that the value 'i' actually be used (output to a PORT or the SPI or the UART or soemthing)? If the latter then when you add in that part of the code, because those destinations are "volatile", the optimiser will see somethinhg useful being done and won't discard the code.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One thing to be careful of when using register variables, is if you use a 'call-used' register, and make a function call, the optimizer may decide to optimize out further instructions for that variable (gcc 3.4.6, don't know about gcc 4.x.x).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
That program (like so many of these short "test programs" presented here) doesn't actually DO anything does it? The optimiser can see this and therefore doesn't generate any code.

Actually he DOES something. He declared i as volatile, which tells the compiler to not optimize it. And the compiler complies. What it doesn't do is the register assignment. It allocates i in r24 (at least that's how I interpret the assembler output).

One could argue that i isn't visible from outside main and the compiler is therefore free to use any register it wants.

On the other hand "r2" IS visible from anywhere in the program and could be changed from an ISR (located in another compilation unit). But the compiler has no knowledge about that (the linker would but he isn't part of the equation yet).

I therefore think the test program is valid and either the compiled assembler or the avr-libc documentation is not quite correct.

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
It allocates i in r24 (at least that's how I interpret the assembler output).
mine shows r24,r25 used by the for loop (x), but there is no 'i/r2' stuff happening in that loop at all. Just a 'for' loop.

gcc 3.4.6
if you declare i/r2 as global, it doesn't optimize away (#1), if i/r2 is local to main, it optimizes away, if i is used (no r2) as a local and declared volatile, it doesn't optimize away (#3)

Don't ask me what it all means, though. I would think #2 and #3 would act the same, but they don't. I guess you have to adapt to the compiler's thinking, because it will never adapt to yours.

//test #1
register volatile char i asm("r2");
int main(){
int x;
asm volatile("clr r2");
//r2 (i) is used below    
i=100;
for (x=1;x<1000;x++){
i+=x;
}
return 0;
}

//test #2
int main(){
register volatile char i asm("r2");
int x;
asm volatile("clr r2");
//r2 (i) is NOT used below
//the loop still occurs    
i=100;
for (x=1;x<1000;x++){
i+=x;
}
return 0;
}

//test #3
int main(){
volatile char i;
int x;
asm volatile("clr r2");
//i IS used below    
i=100;
for (x=1;x<1000;x++){
i+=x;
}
return 0;
}

I also get

Quote:
warning: volatile register variables don't work as you might wish
on the build output.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> I also get
> Quote:
> warning: volatile register variables don't work as you might wish
> on the build output.

Alas, they dropped this warning recently. :-(

I remember a discussion about the issue (and a reason why the warning was
removed), yet I see people are get bitten by it, so I opened a bug report:

http://gcc.gnu.org/bugzilla/show...

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok I did what Markus told me to do so here is the code:

volatile register int i asm("r2");
int main(void){
int x;
asm volatile("clr r2");
i=100;
for (x=1;x<1000;x++){
i+=x;
}
return(0);
}
And because i are volatile and global the compiler make the code.
If i is local there are no code generated. But this code

int main(void){
volatile register int i asm("r2");
volatile int test;
int x;

asm volatile("clr r2");
i=100;
for (x=1;x<1000;x++){
i+=x;
}
test=i;
return(0);
}

Where both test and i are local the code is made so there are a differens between normal var and register var.
And for info the code with local use of i will push and pop r2 and r3.

And to cliff the code was just a small test to see if it's time to start using C and not ASM for the AVR.
It was to see if the AVR emulator can be written in C with some inline ASM, but as always C is way to slow !!! (about half speed of ASM for this kind of things)

Jens

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jens,

I agree for something as time critical as an emulator the majority of it is going to have to be hand optimised Asm.

To try and optimise bootloader code into tight spaces I've tried doing the "force the C compiler to output the exact Asm I want" thing and, in the end, concluded that it'd just be easier to do it in Asm anyway.