How can I prevent GCC from optimizing out a busy wait loop?
avr-gcc, c, gcc, optimization
Solution
I developed this answer after following a link from dmckee's answer, but it takes a different approach than his/her answer.
Function Attributes documentation from GCC mentions:
`noinline` This function attribute prevents a function from being considered for inlining. If the function does not have side-effects, there are optimizations other than inlining that causes function calls to be optimized away, although the function call is live. To keep such calls from being optimized away, put `asm ("");`
This gave me an interesting idea... Instead of adding a `nop` instruction at the inner loop, I tried adding an empty assembly code in there, like this:
unsigned char i, j;
j = 0;
while(--j) {
i = 0;
while(--i)
asm("");
}
And it worked! That loop has not been optimized-out, and no extra `nop` instructions were inserted.
What's more, if you use `volatile`, gcc will store those variables in RAM and add a bunch of `ldd` and `std` to copy them to temporary registers. This approach, on the other hand, doesn't use `volatile` and generates no such overhead.
Update: If you are compiling code using `-ansi` or `-std`, you must replace the `asm` keyword with `__asm__`, as described in GCC documentation.
In addition, you can also use `__asm__ __volatile__("")` if your assembly statement must execute where we put it, (i.e. must not be moved out of a loop as an optimization).
Problem
I want to write a C code firmware for Atmel AVR microcontrollers. I will compile it using GCC. Also, I want to enable compiler optimizations (`-Os` or `-O2`), as I see no reason to not enable them, and they will probably generate a better assembly way faster than writing assembly manually. But I want a small piece of code not optimized. I want to delay the execution of a function by some time, and thus I wanted to write a do-nothing loop just to waste some time. No need to be precise, just wait some time. ``` /* How can it NOT optimize this, while optimizing other code? */ unsigned char i, j; j = 0; while(--j) { i = 0; while(--i); } ``` Since memory access in AVR is a lot slower, I want `i` and `j` to be kept in CPU registers. I found util/delay.h and util/delay_basic.h from AVR Libc. Although most times it might be a better idea to use those functions, this question remains valid and interesting. Related questions: - How can I prevent GCC optimizing some statements in C? - Is there a way to tell GCC not to optimise a particular piece of code? - How not to optimize away - mechanics of a folly function
Related problems
- Is there a way to tell GCC not to optimise a particular piece of code?
- Endless loop in C/C++
- How can I prevent GCC optimizing some statements in C?
- The difference between asm, asm volatile and clobbering memory
- Enforcing statement order in C++
- How not to optimize away - mechanics of a folly function
- Best way to implement busy loop?