AVRGCC 3.3.2 (20040404) BUG: AVRGCC ignores "volatile" keyword for "register" variables when -o2 or -o3 optimization option is used. Code: ================================================== register volatile unsigned char flags asm("r16"); int main(void) { while(1) { if ( flags & 0x02 ) // Some event detected { flags &= (0xFF-0x02); // Clear flag } } return 0; } ================================================== Compiler generates: ================================================== while(1) 64: 80 2f mov r24, r16 66: 99 27 eor r25, r25 { if ( flags & 0x02 ) // Some event detected 68: 81 ff sbrs r24, 1 6a: fe cf rjmp .-4 ; 0x68 { flags &= (0xFF-0x02); // Clear flag 6c: 80 2f mov r24, r16 6e: 8d 7f andi r24, 0xFD ; 253 70: 08 2f mov r16, r24 72: 99 27 eor r25, r25 74: f9 cf rjmp .-14 ; 0x68
I suggest you to ask on the gcc@ list what it is the effect of "volatile" on a global register variable. I know I read before that this is not obvious, but I don't recall the details offhand.
Subject: Re: New: AVRGCC ignores "volatile" keyword for "register" variables m_klokov at mail dot ru wrote: > AVRGCC ignores "volatile" keyword for "register" variables > when -o2 or -o3 optimization option is used. You didn't say what was wrong with the code. Maybe you were expecting all references to the volatile register to be atomic? They aren't. That isn't what volatile means. There is also a more general problem here in that gcc knows what a volatile memory location is, but does not know what a volatile register is. As a result, volatile register variables won't work the way you expect. By the way, current gcc sources emit a warning for this testcase: tmp.c:1: warning: volatile register variables don't work as you might wish
> You didn't say what was wrong with the code. Yes. It's my mistake. The compiler moves the access to volatile variable from the loop (i.e. optimizes it). in fact the compiler optimizes the code: while(1) { if(flag) do_something(); } to code: register char temp=flag; while(1) { if(temp) do_something(); } where flag global declared as: volatile register char flag; (By the way such "optimization" is neither shorter nor faster for AVR MCU) > Maybe you were expecting all references to the volatile register > to be atomic? They aren't. That isn't what volatile means. I didn't expect it should be uninterrupted (if you mean this...) I just expected that compiler will know that this variables may be changed by external process (hardware, interrupt handler, another thread). So if I write to check this variable 1000 times in loop, compiler should not always use the result from first check outside the loop. It should produce REAL checking every time as the value can be altered. > There is also a more general problem here in that gcc knows what a > volatile memory location is, but does not know what a volatile register > is. As a result, volatile register variables won't work the way you expect. > By the way, current gcc sources emit a warning for this testcase: > tmp.c:1: warning: volatile register variables don't work as you might wish Do you mean that volatile keyword can not be used (will not work) with register variables? So I cannot use the register variables that can be changed from outside the code?
Not a bug, volatile on global registers means nothing.
(In reply to comment #4) > Not a bug, volatile on global registers means nothing. Why do you think so? Volatile means volatile, it shouldn't depend of "register" or not, global or local. Anyway compiler should assume that this variable can be altered by external process (thread, interrupt handler or hardware). So it souldn't copy this value to another temporary place and use this copy when I want to read this value, as the real value CAN BE CHANGED. Please refere to samples I provided before.
(In reply to comment #4) > Not a bug, volatile on global registers means nothing. Volatile means volatile... Let me explain more... There are 32 registers in AVR-core. GCC uses only 16. So other registers I can use in asm-code. As you know asm-routines are usually high-speed low-level drivers, interrupt handlers, often with some "tricks" (like fixed execution time or something like this - something you can't do with C). OK. Lets say asm-code is the interrupt handler and it use free register to notify the main C-program about some event. It uses register because it's much faster then RAM, and much more comfortable. So how can i define such register to allow C-code to access it ??? I should use the "register" keyword obviously... AND I should use the "volatile" keyword to say compiler that value can be changed by interrupt handler... (not by C-sentence) and the code MUST reread the value in a manner I wrote in my C-code (i.e. don't optimize it). It's THE STANDARD MEANINGS of theese keywords... You must be assuming that C-compiler must use all the available registers? Or hardware always has small number of registers? If so, you make GCC-compiler HARDWARE-DEPENDENT... My english is not so good, Sorry. Please ask if you have any questions.
I did a simple test on my avr-gcc 4.2.2 and it seems that this bug (i dont think it should be Resolution: INVALID but...) is fixed in 4.2.2 atleast. I changed the register used in the example to r2 to see if the AVR's incapability to do andi (AND immediate) on r0-r15 would cause any problems, but even this didnt cause the bug. Here's the objdump output: while(1) { if ( flags & 0x02 ) // Some event detected 8: 21 fe sbrs r2, 1 a: fe cf rjmp .-4 ; 0x8 <main+0x8> { flags &= (0xFF-0x02); // Clear flag c: 8d ef ldi r24, 0xFD ; 253 e: 28 22 and r2, r24 10: 21 fe sbrs r2, 1 12: fa cf rjmp .-12 ; 0x8 <main+0x8> 14: fb cf rjmp .-10 ; 0xc <main+0xc>