This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

local class variable volatile bug (with O1,O2,O3)

Hello, I have a problem with the compiler optimizing away a volatile variable, and as a result generating an endless loop. My program is too big to show here, but I created an example main.cpp file which compiles the same way (with the same issue). It is quit possible the issue is not in the compiler, so I'm asking for help. Here:

uVision V5.10.0.2
Armcc.exe V5.04.0.49

cmdline (options) =
-c --cpu Cortex-M4.fp -g -O1 -Otime --apcs=interwork --asm --interleave --asm_dir ".\\"
-I C:\Keil_v5\ARM\RV31\INC
-I C:\Keil_v5\ARM\PACK\ARM\CMSIS\3.20.4\CMSIS\Include
-I C:\Keil_v5\ARM\PACK\Keil\ARMCortex_DFP\0.0.1\Device\Include
-o "*.o" --list_dir ".\\" --list --omf_browse "*.crf" --depend "*.d"

code (file=main.cpp):

#include "stdio.h"
typedef int BOOL;
class Event
{
  volatile BOOL w;
public:
  Event() { w=0;}
  void SetEvent() { w=1;}
  void SetEventFromInterrupt() { w=1;}
  void ResetEvent() { w=0;}
  BOOL CheckEvent() { return w;}
};

void SetupIrqEvent(Event *event);

void TestEvent()
{
  Event event;
  SetupIrqEvent(&event);

// problematic area - code (when -O1 or higher) will not r ead from memory (stack)
// wait for the event

   while(!event.CheckEvent()) ; 

  SetupIrqEvent(NULL);
}

Event *irqEvent=NULL;

void SetupIrqEvent(Event *event)
{
        irqEvent=event;
}

extern "C" void MyIrqHandler()
{
  if(irqEvent!=NULL)
  {
    irqEvent->SetEventFromInterrupt();
  }
}

Here is the listing I'm getting for TestEvent function:

                  _Z9TestEventv PROC ; TestEvent()
;;;15
;;;16     void TestEvent()
000006  b508              PUSH     {r3,lr}
000008  2000              MOVS     r0,#0
00000a  9000              STR      r0,[sp,#0]
;;;17     {
;;;18        Event event;
;;;19        SetupIrqEvent(&event);
00000c  4668              MOV      r0,sp
00000e  f7fffffe          BL       _Z13SetupIrqEventP5Event ; SetupIrqEvent(Event*)
000012  9800              LDR      r0,[sp,#0]
                  |L1.20|
000014  2800              CMP      r0,#0
;;;20          while(!event.CheckEvent()) ; 
000016  d0fd              BEQ      |L1.20|  ;  jump back to comparison, skip reloading
;;;21         SetupIrqEvent(NULL);
000018  2000              MOVS     r0,#0
00001a  f7fffffe          BL       _Z13SetupIrqEventP5Event ; SetupIrqEvent(Event*)
;;;22     }
00001e  bd08              POP      {r3,pc}
;;;23
                          ENDP

As you can see event.CheckEvent() gets inlined to a comparison, without reading the word each time from the memory (even though w is declared volatile).

Any ideas how can I fix this ? This is part of a lot of legacy code I have to deal with, and "just be careful and don't use volatile in local variables or classes which might have local instances" is not really an option.