Electronic – XC32 optimizes vaiable used for register reading

ccompileroptimizationpicxc32

I am facing a problem with XC32 compiler's optimization. Whenever I write a function to read something from register, XC32 optimizes (read: Removes) the variable which holds the return value.

I have a wrapper function which reads a perticular pin of perticular port:

uint8_t u8INT_DIO_ReadRangeSelect(void)
{
    uint8_t u8pinstatus = 0;

    // Read pin assigned to Range Select input
    u8pinstatus = (uint8_t) SYS_PORTS_PinRead(PORTS_ID_0, 
            RANGE_SELECT_PORT, RANGE_SELECT_PIN);

    return u8pinstatus;
}

Here SYS_PORTS_PinRead is a harmony (PIC's code generating tool) generated code and it just reads the port pin.
Code for that is:

return( _SFR_BIT_READ( _PORTS_READ_B_VREG(index) + ((channel-1) * 0x40), bitPos ) );

Note that, it's an inline function.

Now, when I set Optimization level to 1, XC32 removes u8pinstatus variable and always returns 0.

But if I declare u8pinstatus as volatile, everything works fine (which was expected).

But then I need to declare all the variables volatile because all my wrapper functions are always returning 0. That's not a good way.

Is it that XC32 gone bonks or am I doing something wrong?

Additional Info:

Assembly code with optimization:

!uint8_t u8INT_DIO_ReadRangeSelect(void)
!{
0x9D00AA8C: ADDIU SP, SP, -24
0x9D00AA90: SW RA, 20(SP)
!    uint8_t u8pinstatus = 0;
!    
!    // Read pin assigned to Range Select input
!    u8pinstatus = (uint8_t) SYS_PORTS_PinRead(PORTS_ID_0, 
0x9D00AA94: ADDU A0, ZERO, ZERO
0x9D00AA98: ADDIU A1, ZERO, 3
0x9D00AA9C: JAL SYS_PORTS_PinRead
0x9D00AAA0: ADDIU A2, ZERO, 8
!            RANGE_SELECT_PORT, RANGE_SELECT_PIN);
!    return u8pinstatus;
!}
0x9D00AAA4: LW RA, 20(SP)
0x9D00AAA8: JR RA
0x9D00AAAC: ADDIU SP, SP, 24

Assembly code without optimization:

!uint8_t u8INT_DIO_ReadRangeSelect(void)
!{
0x9D00F998: ADDIU SP, SP, -32
0x9D00F99C: SW RA, 28(SP)
0x9D00F9A0: SW S8, 24(SP)
0x9D00F9A4: ADDU S8, SP, ZERO
!    uint8_t u8pinstatus = 0;
0x9D00F9A8: SB ZERO, 16(S8)
!    
!    // Read pin assigned to Range Select input
!    u8pinstatus = (uint8_t) SYS_PORTS_PinRead(PORTS_ID_0, 
0x9D00F9AC: ADDU A0, ZERO, ZERO
0x9D00F9B0: ADDIU A1, ZERO, 3
0x9D00F9B4: ADDIU A2, ZERO, 8
0x9D00F9B8: JAL SYS_PORTS_PinRead
0x9D00F9BC: NOP
0x9D00F9C0: SB V0, 16(S8)
!            RANGE_SELECT_PORT, RANGE_SELECT_PIN);
!    return u8pinstatus;
0x9D00F9C4: LBU V0, 16(S8)
!}
0x9D00F9C8: ADDU SP, S8, ZERO
0x9D00F9CC: LW RA, 28(SP)
0x9D00F9D0: LW S8, 24(SP)
0x9D00F9D4: ADDIU SP, SP, 32
0x9D00F9D8: JR RA
0x9D00F9DC: NOP

Best Answer

Compiler optimizations typically assume that nothing but the program itself can alter the contents of memory. With that assumption, repeated reads from the same register on a microcontroller are often optimized out, because the compiler doesn't see anything in the code that can possibly give a different result with repeated execution. Why execute the same instructions over and over if the result will always be the same?

Volatile is the workaround. It tells the compiler that something else in the universe might alter that particular address in memory, and that its assumptions about future values aren't necessarily true. "Don't optimize me, bro".

In short, I think things are behaving exactly as intended.