M0 : bad C11 atomics

Bug #1764595 reported by fenugrec
10
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain
Confirmed
Undecided
Unassigned

Bug Description

Hi,
this is mostly a rehash of https://answers.launchpad.net/gcc-arm-embedded/+question/265649 . Freshly tested against 7-2017-q4 release, issue present since forever (at least 4.9)

Here's the essential:

Compiling the following code with "arm-none-eabi-gcc -save-temps -mcpu=cortex-m0 -mthumb -fverbose-asm at.c"
**** at.c ****
#include <stdatomic.h>

atomic_flag aflag = ATOMIC_FLAG_INIT;

int main(void) {
 while (1) {
  while (atomic_flag_test_and_set( &aflag));
  atomic_flag_clear( &aflag);
 }
 return 0;
}
*********

 gives the following intermediate assembly :

********* at.s (excerpt) ****
main:
 push {r7, lr} @
 add r7, sp, #0 @,,
.L3:
@ t1.c:16: while (atomic_flag_test_and_set( &aflag));
 nop
.L2:
@ t1.c:16: while (atomic_flag_test_and_set( &aflag));
 ldr r3, .L4 @ tmp114,
 ldrb r2, [r3] @ tmp115,
 movs r1, #1 @ tmp116,
 strb r1, [r3] @ tmp117,
 uxtb r3, r2 @ _1, tmp115
@ t1.c:16: while (atomic_flag_test_and_set( &aflag));
 cmp r3, #0 @ _1,
 bne .L2 @,
 ........
**********

The problem is the "ldrb ...strb" sequence which is not atomic. M0 cores do not have strex/ldrex , they require an interrupt disable around the protected operation (mrs + cpsid + msr).

I believe gcc shouldn't silently generate a non-atomic sequence like this !

Tags: atomic c11 m0
fenugrec (fenugrec)
description: updated
Changed in gcc-arm-embedded:
status: New → Confirmed
Revision history for this message
Przemyslaw Wirkus (wirkus) wrote :

I can still reproduce with GCC 9.2.1 (9-2019-q4-major):

main:
 @ args = 0, pretend = 0, frame = 0
 @ frame_needed = 1, uses_anonymous_args = 0
 push {r7, lr} @
 add r7, sp, #0 @,,
.L3:
@ at.c:7: while (atomic_flag_test_and_set( &aflag));
 nop
.L2:
@ at.c:7: while (atomic_flag_test_and_set( &aflag));
 ldr r3, .L4 @ tmp112,
 ldrb r2, [r3] @ tmp113,
 movs r1, #1 @ tmp114,
 strb r1, [r3] @ tmp115,
 uxtb r3, r2 @ _1, tmp113
@ at.c:7: while (atomic_flag_test_and_set( &aflag));
 cmp r3, #0 @ _1,
 bne .L2 @,
@ at.c:8: atomic_flag_clear( &aflag);
 ldr r3, .L4 @ tmp116,
 dmb ish
 movs r2, #0 @ tmp117,
 strb r2, [r3] @ tmp118,
 dmb ish
@ at.c:7: while (atomic_flag_test_and_set( &aflag));
 b .L3 @
.L5:
 .align 2
.L4:
 .word aflag
 .size main, .-main
 .ident "GCC: (GNU Tools for Arm Embedded Processors 9-2019-q4-major) 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599]"

Revision history for this message
fenugrec (fenugrec) wrote :

Just checking in for the yearly test. Still present in 10.2.0 ;

main:
 @ args = 0, pretend = 0, frame = 0
 @ frame_needed = 1, uses_anonymous_args = 0
 push {r7, lr} @
 add r7, sp, #0 @,,
.L3:
@ at.c:7: while (atomic_flag_test_and_set( &aflag));
 nop
.L2:
@ at.c:7: while (atomic_flag_test_and_set( &aflag));
 ldr r3, .L4 @ tmp115,
 ldrb r2, [r3] @ tmp116,
 movs r1, #1 @ tmp117,
 strb r1, [r3] @ tmp118,
 uxtb r3, r2 @ _1, tmp116
@ at.c:7: while (atomic_flag_test_and_set( &aflag));
 cmp r3, #0 @ _1,
 bne .L2 @,
@ at.c:8: atomic_flag_clear( &aflag);
 ldr r3, .L4 @ tmp119,
 dmb ish
 movs r2, #0 @ tmp120,
 strb r2, [r3] @ tmp121,
 dmb ish
@ at.c:7: while (atomic_flag_test_and_set( &aflag));
 b .L3 @
.L5:
 .align 2
.L4:
 .word aflag
 .size main, .-main
 .ident "GCC: (Arch Repository) 10.2.0"

Revision history for this message
David Brown (davidbrown) wrote :

The C11/C++11 atomic support on gcc for embedded ARM is almost completely broken - it is worse than useless because it silently gives incorrect code. For simple read or write access to 32-bit or smaller atomics, the code is correct but inefficient (you don't need DSB and similar barriers on single-core Cortex-M devices). For anything bigger or more complex, you get non-atomic sequences or calls to library functions that have spin locks that cannot work on a single core device.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.