This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Failing assignment operator

Hi,

we have encountered a problem with the operator '+='. This is a problem that we have seen 4 times in different places in our code. Each time the problem is the same. The expression is calculated but the addition to the destination parm never takes place. There are two code examples pasted below including the compiled code. The first show a failing version and the second a working solution.

We using the TM4C129DNCPDT with the compiler version 'TI v5.0.4'. If needed I can post additional information about installed modules.
All affected files are C files, so perhaps this bug is related to the C compiler only.

I have tried to search for assignment operater bugs, but have not found any match. But this being such a frequently occurring bug (for us at least) I seriously doubt that no one has encountered it before.

Has anyone run into this bug before?
Has it been solved a newer compiler release?

As we are getting close to finalizing our project we only want to change compiler if there is a good reason to do so. But this being a rather serious issue we need to collect sufficient information to evaluate whether we should upgrade or not.

Kind regards,
Christian


/************************************************************************** Failing: -------- The function below fails in the way that the variable 'uSecCnt' does not get updated. The returned value is always the same. The expressions are calculated correctly but the result is never added to 'uSecCnt'. **************************************************************************/ uint32_t HalTimerUsGet() { // Set the timer to wrap after 1 min. to facilitate check of code) static uint32_t uSecCnt = (uint32_t)(~0 - (60 * 1000 * 1000)); static uint32_t lastTicks = ~0; uint32_t ticks; HalIrqStat_t iState; iState = HalIrqDisable(); ticks = TimerValueGet(TIMER4_BASE, TIMER_A); if (ticks > lastTicks) { // timer wrap, 35.8 more sec passed uSecCnt += (lastTicks - (int32_t)ticks) * CPU_MHZ_INV; } else { uSecCnt += (lastTicks - ticks) * CPU_MHZ_INV; } lastTicks = ticks; HalIrqRestore(iState); return uSecCnt; }
114       {
          HalTimerUsGet:
000596d6:   B50E     PUSH            {R1, R2, R3, LR}
121           iState = HalIrqDisable();
000596d8:   F00CFB8D BL              HalIrqDisable
000596dc:   F88D0004 STRB.W          R0, [R13, #4]
123           ticks = TimerValueGet(TIMER4_BASE, TIMER_A);
000596e0:   4866     LDR             R0, $C$CON4
000596e2:   21FF     MOV             R1, #0xFF
000596e4:   F014F816 BL              TimerValueGet
000596e8:   9000     STR             R0, [SP]
125           if (ticks > lastTicks)
000596ea:   4865     LDR             R0, $C$CON9
000596ec:   9900     LDR             R1, [SP]
000596ee:   6800     LDR             R0, [R0]
000596f0:   4288     CMP             R0, R1
000596f2:   D217     BCS             $C$L2
128               uSecCnt += (lastTicks - (int32_t)ticks) * CPU_MHZ_INV;
000596f4:   4862     LDR             R0, $C$CON9
000596f6:   4963     LDR             R1, $C$CON10
000596f8:   9A00     LDR             R2, [SP]
000596fa:   6800     LDR             R0, [R0]
000596fc:   EDD10A00 FLDS            S1, [R1, #0]
00059700:   1A80     SUB             R0, R0, R2
00059702:   EE000A10 FMSR            S0, R0
00059706:   4860     LDR             R0, $C$CON11
00059708:   ED901A00 FLDS            S2, [R0, #0]
0005970c:   EEB80A40 FUITOS          S0, S0
00059710:   EEF80A60 FUITOS          S1, S1
00059714:   EE410A00 FMACS           S1, S2, S0
00059718:   EEBC0AE0 FTOUIZS         S0, S1
0005971c:   EE100A10 FMRS            R0, S0
00059720:   6008     STR             R0, [R1]
129           }
00059722:   E016     B               $C$L3
132               uSecCnt += (lastTicks - ticks) * CPU_MHZ_INV;
          $C$L2:
00059724:   4856     LDR             R0, $C$CON9
00059726:   4957     LDR             R1, $C$CON10
00059728:   9A00     LDR             R2, [SP]
0005972a:   6800     LDR             R0, [R0]
0005972c:   EDD10A00 FLDS            S1, [R1, #0]
00059730:   1A80     SUB             R0, R0, R2
00059732:   EE000A10 FMSR            S0, R0
00059736:   4854     LDR             R0, $C$CON11
00059738:   ED901A00 FLDS            S2, [R0, #0]
0005973c:   EEB80A40 FUITOS          S0, S0
00059740:   EEF80A60 FUITOS          S1, S1
00059744:   EE410A00 FMACS           S1, S2, S0
00059748:   EEBC0AE0 FTOUIZS         S0, S1
0005974c:   EE100A10 FMRS            R0, S0
00059750:   6008     STR             R0, [R1]
134           lastTicks = ticks;
          $C$L3:
00059752:   9800     LDR             R0, [SP]
00059754:   494A     LDR             R1, $C$CON9
00059756:   6008     STR             R0, [R1]
136           HalIrqRestore(iState);
00059758:   F89D0004 LDRB.W          R0, [R13, #4]
0005975c:   F00CFB60 BL              HalIrqRestore
138           return uSecCnt;
00059760:   4848     LDR             R0, $C$CON10
00059762:   6800     LDR             R0, [R0]
139       }
00059764:   BD0E     POP             {R1, R2, R3, PC}

/**************************************************************************
Working solution:

By changing the assignment operator and storing the result in a temporary
variable first, the function now works correctly and the parameter 'uSecCnt'
gets updated correctly.
**************************************************************************/
uint32_t HalTimerUsGet()
{
    // Set the timer to wrap after 1 min. to facilitate check of code)
    static uint32_t uSecCnt = (uint32_t)(~0 - (60 * 1000 * 1000));
    static uint32_t lastTicks = ~0;
    uint32_t ticks;
    uint32_t elapsed;
    HalIrqStat_t iState;

    iState = HalIrqDisable();

    ticks = TimerValueGet(TIMER4_BASE, TIMER_A);

    if (ticks > lastTicks)
    {
        // timer wrap, 35.8 more sec passed
        elapsed = (lastTicks - (int32_t)ticks) * CPU_MHZ_INV;
    }
    else
    {
        elapsed = (lastTicks - ticks) * CPU_MHZ_INV;
    }
    uSecCnt += elapsed;
    lastTicks = ticks;

    HalIrqRestore(iState);

    return uSecCnt;
}
114       {
          HalTimerUsGet:
0005a51a:   B50E     PUSH            {R1, R2, R3, LR}
122           iState = HalIrqDisable();
0005a51c:   F00CF84B BL              HalIrqDisable
0005a520:   F88D0008 STRB.W          R0, [R13, #8]
124           ticks = TimerValueGet(TIMER4_BASE, TIMER_A);
0005a524:   4864     LDR             R0, $C$CON4
0005a526:   21FF     MOV             R1, #0xFF
0005a528:   F013FD5C BL              TimerValueGet
0005a52c:   9000     STR             R0, [SP]
126           if (ticks > lastTicks)
0005a52e:   4863     LDR             R0, $C$CON9
0005a530:   9900     LDR             R1, [SP]
0005a532:   6800     LDR             R0, [R0]
0005a534:   4288     CMP             R0, R1
0005a536:   D212     BCS             $C$L2
129               elapsed = (lastTicks - (int32_t)ticks) * CPU_MHZ_INV;
0005a538:   4860     LDR             R0, $C$CON9
0005a53a:   9900     LDR             R1, [SP]
0005a53c:   6800     LDR             R0, [R0]
0005a53e:   1A40     SUB             R0, R0, R1
0005a540:   EE000A10 FMSR            S0, R0
0005a544:   485E     LDR             R0, $C$CON10
0005a546:   EDD00A00 FLDS            S1, [R0, #0]
0005a54a:   EEB80A40 FUITOS          S0, S0
0005a54e:   EE200A80 FMULS           S0, S1, S0
0005a552:   EEBC0AC0 FTOUIZS         S0, S0
0005a556:   EE100A10 FMRS            R0, S0
0005a55a:   9001     STR             R0, [SP, #0x4]
130           }
0005a55c:   E011     B               $C$L3
133               elapsed = (lastTicks - ticks) * CPU_MHZ_INV;
          $C$L2:
0005a55e:   4857     LDR             R0, $C$CON9
0005a560:   9900     LDR             R1, [SP]
0005a562:   6800     LDR             R0, [R0]
0005a564:   1A40     SUB             R0, R0, R1
0005a566:   EE000A10 FMSR            S0, R0
0005a56a:   4855     LDR             R0, $C$CON10
0005a56c:   EDD00A00 FLDS            S1, [R0, #0]
0005a570:   EEB80A40 FUITOS          S0, S0
0005a574:   EE200A80 FMULS           S0, S1, S0
0005a578:   EEBC0AC0 FTOUIZS         S0, S0
0005a57c:   EE100A10 FMRS            R0, S0
0005a580:   9001     STR             R0, [SP, #0x4]
135           uSecCnt += elapsed;
          $C$L3:
0005a582:   4950     LDR             R1, $C$CON11
0005a584:   9801     LDR             R0, [SP, #0x4]
0005a586:   680A     LDR             R2, [R1]
0005a588:   1880     ADD             R0, R0, R2
0005a58a:   6008     STR             R0, [R1]
136           lastTicks = ticks;
0005a58c:   9800     LDR             R0, [SP]
0005a58e:   494B     LDR             R1, $C$CON9
0005a590:   6008     STR             R0, [R1]
138           HalIrqRestore(iState);
0005a592:   F89D0008 LDRB.W          R0, [R13, #8]
0005a596:   F00CF823 BL              HalIrqRestore
140           return uSecCnt;
0005a59a:   484A     LDR             R0, $C$CON11
0005a59c:   6800     LDR             R0, [R0]
141       }
0005a59e:   BD0E     POP             {R1, R2, R3, PC}

  • Expressions "E1 += E2" are defined to be equivalent to "E1 = E1 + E2" except that E1 is only evaluated once. As the constant CPU_MHZ_INV seems to be a single precision floating point constant, the new value of uSecCnt is computed as single precision float, which cannot represent all 32 bit integer values. You can fix this by either introducing temporaries as you did, or by explicitly casting the right hand side of the += expression to int32_t.

  • Hi Markus,

    Yes, you are right. I ask myself why I didn't think of that. Seems so obvious now.

    Thanks for you input :-)