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
Anonymous
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):
The following command line has been used (see the -O optimization):
Generated disassebly:
The problem is apparent at address 1e (
cpsid i) and addresses 3a-3e (mrs r3,PRIMASKfollowed bymsr 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):
Generated disassebly:
This code seems to be correct. Specifically, the QF critical section is entered as:
and exited as:
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
View and moderate all "bugs Discussion" comments posted by this user
Mark all as spam, and block user from posting to "Bugs"
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]
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
This bug has been fixed in QP/C/C++ 6.0.0.
--MMS