0

In the following example the variable v is not accessible from outside this TU. So the compiler can optimize the loop in main() to an empty loop. This is done with -O3, but with -Os it remains a loop with the load of v outside the loop, so that it is effectively an endless loop without effect.

The function isr() could be optimized away, but is not since it should resemble an ISR and therefore hast the used attribute.

If one changes v to an external visible global, the assemble code remains the same!

How can the compiler reason, that v remains unmodified in this case?

Inserting a memory-barrier sure fixes that in both cases. But why isn't it suffcient to make v external visible?

#include <avr/cpufunc.h>

//int v; 
namespace {
    int v; 
    void isr() 
        __asm__("__vector_5") 
        __attribute__ ((__signal__, 
        __used__
        )); 
    void isr() { 
        v += 1; 
    }
}

int main() {
    while(true) {
//        _MemoryBarrier();
        if (v == 42) { 
            v += 1; 
        }
    }    
}

https://godbolt.org/z/4j7En41sE

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
wimalopaan
  • 4,838
  • 1
  • 21
  • 39
  • 2
    Infinite loop without side-effects - is UB, data race - is UB. Access to variable from different threads without synchronization - is data race. So, if you don't have `volatile` specifier or synchronization, then you have UB and everything can be optimized out. – sklott Jan 05 '23 at 12:18
  • If one inserts a different volatile access into the loop (no UB anymore), the access to `v` is still optimized away. There are no concurrent actions here, so no UB due to data race. – wimalopaan Jan 05 '23 at 12:23
  • 1
    An interrupt handler interrupting the loop could be seen as happening during `main`'s accesses to `v`. Optimizations preserve the behaviour of single-threaded code, but not of signals / interrupts unless you use `volatile sig_atomic_t v`. See also [MCU programming - C++ O2 optimization breaks while loop](https://electronics.stackexchange.com/a/387478) – Peter Cordes Jan 05 '23 at 12:36
  • As stated above, making `v` external visible is not sufficient to let the compiler reason, `v` might be modified. One must insert a call to a non-inline function, to achieve that. If the function is inline / defined in the same TU and does not access `v`, the compiler again can do the optimization. – wimalopaan Jan 05 '23 at 15:16
  • The strange thing is that although `isr()` is inline, modifying `v` and marked as `used`, this is handeld different than a call to a non-inline `foo()`. – wimalopaan Jan 05 '23 at 15:19
  • This looks like the attribute `used` is online to prevent the compiler from removing the function `isr()` at all. The attribute `used` does not mean that it takes place in the flow-analysis as somehow called. – wimalopaan Jan 05 '23 at 16:11

0 Answers0