Menu

#184 QS_END() leaves all interrupts disabled w/ GNU ARM

QPCPP
closed
None
1
2024-08-01
2017-10-06
Anonymous
No

Using v5.9.6 of QP/C++ and g++ arm compiler, the following snippet of code is compiled into assembly in such a way that all interrupts are left disabled after QS_END() is called.

The snippet of code in C++ is show below.

The equivalent assembly is shown in the attached image. Note the Red lines. Instead of caching the value of primask, disabling interrupts, then finally restoring primask, the compiler generates assembly that disables interrupts, caches primask, then immediately restores primask leaving all interrupts disabled.

void MemPoolManager::PrintPoolStats(uint32_t print_tag) {
uint32_t i;
for(i = 0; i < 10; i++) {
QS_BEGIN(SNS_BGLOG_ID_HEAP_VERBOSE, 0);
QS_U32(8, 0);
QS_END();
}
}

Compiler command line for above snippet below:
arm-none-eabi-g++ -o build\win-h9791-bg2xilinx-gnu-nodoc-wear-cm0-dbg\lib\common\mem_pool_manager.cpo -c -fno-rtti -fno-exceptions -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -fno-rtti -fno-exceptions -std=c++11 -Wall -Os -gdwarf-2 -Wall -ffunction-sections -fno-strict-aliasing -O1 -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -fmessage-length=0 -fno-common -DOFFTARGET_UNIT_TESTING -DARM_MATH_CM0 -DARM_MATH_MATRIX_CHECK -DARM_MATH_ROUNDING -DUNALIGNED_SUPPORT_DISABLE -DARM_MATH_CM0 -DARM_MATH_MATRIX_CHECK -DARM_MATH_ROUNDING -DUNALIGNED_SUPPORT_DISABLE -DQ_SPY -DBG_DEBUG -IC:\uh\5.9.6\QP\SHIP-win-gnu-nodoc-cm0-dbg\include

1 Attachments

Discussion

  • Quantum Leaps

    Quantum Leaps - 2017-10-10

    This is determined to be the GNU-ARM compiler issue, which apparently generates wrong code for the Cortex-M0/M0+ (ARMv6M architecture). The problem exists in many GNU-ARM versions, including the latest GCC 6.3.1 (GNU Tools for ARM Embedded Processors 6-2017-q2-update, 6.3.1 20170620 release).

    Specifically, the presence or absence of this bug depends on the optimization level used, as illustrated below:

    The following test code has been used (essentially identical to the OP):

    void crit_section_test(void) {
        uint32_t i;
        for(i = 0; i < 10; i++) {
            QS_BEGIN(123, 0);
                QS_U32(8, 0);
            QS_END();
        }
    }
    

    The following command line has been used (see the -O optimization):

    arm-none-eabi-gcc -c -O -mcpu=cortex-m0plus  -mthumb -Wall -ffunction-sections -fdata-sections -DQ_SPY ...
    

    Generated disassebly:

    00000000 <crit_section_test>:
       0:   b5f8        push    {r3, r4, r5, r6, r7, lr}
       2:   240a        movs    r4, #10
       4:   4e10        ldr r6, [pc, #64]   ; (48 <crit_section_test+0x48>)
       6:   2508        movs    r5, #8
       8:   0037        movs    r7, r6
       a:   e002        b.n 12 <crit_section_test+0x12>
       c:   3c01        subs    r4, #1
       e:   2c00        cmp r4, #0
      10:   d018        beq.n   44 <crit_section_test+0x44>
      12:   7bf3        ldrb    r3, [r6, #15]
      14:   421d        tst r5, r3
      16:   d0f9        beq.n   c <crit_section_test+0xc>
      18:   6a7b        ldr r3, [r7, #36]   ; 0x24
      1a:   2b00        cmp r3, #0
      1c:   d1f6        bne.n   c <crit_section_test+0xc>
      1e:   b672        cpsid   i
      20:   207b        movs    r0, #123    ; 0x7b
      22:   f7ff fffe   bl  0 <QS_beginRec>
      26:   f7ff fffe   bl  0 <crit_section_test>
      2a:   f7ff fffe   bl  0 <QS_u32_>
      2e:   2100        movs    r1, #0
      30:   2085        movs    r0, #133    ; 0x85
      32:   f7ff fffe   bl  0 <QS_u32>
      36:   f7ff fffe   bl  0 <QS_endRec>
      3a:   f3ef 8310   mrs r3, PRIMASK
      3e:   f383 8810   msr PRIMASK, r3
      42:   e7e3        b.n c <crit_section_test+0xc>
      44:   bdf8        pop {r3, r4, r5, r6, r7, pc}
      46:   46c0        nop         ; (mov r8, r8)
      48:   00000000    .word   0x00000000
    

    The problem is apparent at address 1e (cpsid i) and addresses 3a-3e (mrs r3,PRIMASK followed by msr PRIMASK, r3). These last two instructions leave the interrupts disabled, which is wrong.

    On the other hand, the same exact code compiled with the following command line (-O2 optimization):

    arm-none-eabi-gcc -c -O2 -mcpu=cortex-m0plus  -mthumb -Wall -ffunction-sections -fdata-sections -DQ_SPY ...
    

    Generated disassebly:

    00000000 <crit_section_test>:
       0:   b5f8        push    {r3, r4, r5, r6, r7, lr}
       2:   240a        movs    r4, #10
       4:   2608        movs    r6, #8
       6:   4d0f        ldr r5, [pc, #60]   ; (44 <crit_section_test+0x44>)
       8:   7beb        ldrb    r3, [r5, #15]
       a:   421e        tst r6, r3
       c:   d002        beq.n   14 <crit_section_test+0x14>
       e:   6a6b        ldr r3, [r5, #36]   ; 0x24
      10:   2b00        cmp r3, #0
      12:   d003        beq.n   1c <crit_section_test+0x1c>
      14:   3c01        subs    r4, #1
      16:   2c00        cmp r4, #0
      18:   d1f6        bne.n   8 <crit_section_test+0x8>
      1a:   bdf8        pop {r3, r4, r5, r6, r7, pc}
      1c:   f3ef 8710   mrs r7, PRIMASK
      20:   b672        cpsid   i
      22:   207b        movs    r0, #123    ; 0x7b
      24:   f7ff fffe   bl  0 <QS_beginRec>
      28:   f7ff fffe   bl  0 <crit_section_test>
      2c:   f7ff fffe   bl  0 <QS_u32_>
      30:   2100        movs    r1, #0
      32:   2085        movs    r0, #133    ; 0x85
      34:   f7ff fffe   bl  0 <QS_u32>
      38:   f7ff fffe   bl  0 <QS_endRec>
      3c:   f387 8810   msr PRIMASK, r7
      40:   e7e8        b.n 14 <crit_section_test+0x14>
      42:   46c0        nop         ; (mov r8, r8)
      44:   00000000    .word   0x00000000
    

    This code seems to be correct. Specifically, the QF critical section is entered as:

      1c:   f3ef 8710   mrs r7, PRIMASK
      20:   b672        cpsid   i
    

    and exited as:

      3c:   f387 8810   msr PRIMASK, r7
    

    Conclusion:
    The GNU-ARM compiler creates wrong code for ARM Cortex-M0/M0+ at certain optimization levels (-O and perhaps others). This compiler is NOT RECOMMENDED for these CPUs.

    Additionall, see also "Cortex M0/M0+/M1/M23 BAD Optimisation in GCC".

    --MMS

     

    Last edit: Quantum Leaps 2017-10-10
  • Anonymous

    Anonymous - 2017-10-11

    Hi,

    Could you compile your testcase with -save-temps and post the resulting .i to GNU ARM Embedded Toolchain's launchpad [1]? Given how frequent is this kind of code I rather suspect something is missing in the source code but be assured that if it is a bug in the toolchain we'll take due consideration.

    [1] https://bugs.launchpad.net/gcc-arm-embedded

    Best regards,

    Thomas [on behalf of the GNU Arm Embedded Toolchain team]

     
    • Quantum Leaps

      Quantum Leaps - 2017-10-11

      I was was able to distill the problem to a relatively small snippet of code without any external dependencies or macros. I filed this information as an official bug report at GCC-ARM-Embedded, please see:

      https://bugs.launchpad.net/gcc-arm-embedded/+bug/1722849

      As I experimented with this code, the excessive type casting in the condition for the if statement seems to be implicated (the bug goes away if I remove some of this type casting). The type casting has been added in the first place to satisfy static analysis with PC-Lint for MISRA-C compliance.

      --MMS

       
  • Quantum Leaps

    Quantum Leaps - 2017-11-12
    • status: open --> closed
     
  • Quantum Leaps

    Quantum Leaps - 2017-11-12

    This bug has been fixed in QP/C/C++ 6.0.0.
    --MMS

     

Anonymous
Anonymous

Add attachments
Cancel





MongoDB Logo MongoDB