http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58259

            Bug ID: 58259
           Summary: PowerPC: Atomic flag test and set generates NULL
                    pointer read and write
           Product: gcc
           Version: 4.7.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: sebastian.hu...@embedded-brains.de

The GCC C compiler generates a NULL pointer read and write for the atomic flag
test and set method in GCC 4.7, 4.8 and 4.9.  The GCC C++ compiler doesn't have
this problem.

C test case:

#include <stdatomic.h>

_Bool test_and_set(atomic_flag *flag)
{
  return atomic_flag_test_and_set_explicit(flag, memory_order_acquire);
}

C++ test case:

#include <atomic>

bool test_and_set(std::atomic_flag &flag)
{
  return flag.test_and_set(std::memory_order_acquire);
}

GCC assembler output:

powerpc-eabi-gcc-4.7.0 -std=c11 -Wall -Wextra -O2 -S test.c && cat test.s
        .file   "test.c"
        .section        ".text"
        .align 2
        .globl test_and_set
        .type   test_and_set, @function
test_and_set:
        li 10,0
        rlwinm 9,3,3,27,28
        lbz 5,0(10) <--- HERE IS THE NULL POINTER READ
        xori 9,9,24
        li 7,255
        li 6,1
        rlwinm 3,3,0,0,29
        slw 7,7,9
        slw 5,5,9
        slw 6,6,9
.L2:
        lwarx 10,0,3
        and 8,10,7
        cmpw 0,8,5
        andc 8,10,7
        or 8,8,6
        bne- 0,.L3
        stwcx. 8,0,3
        bne- 0,.L2
.L3:
        isync
        srw 10,10,9
        li 9,0
        mfcr 3
        rlwinm 3,3,3,1
        stb 10,0(9) <--- HERE IS THE NULL POINTER WRITE
        blr
        .size   test_and_set, .-test_and_set
        .ident  "GCC: (GNU) 4.7.0 20120202 (experimental) [master revision
022fc2d:bffd767:fd457cef14f3bc6673e90a2de80005feea743ab7]"

powerpc-eabi-gcc -std=c11 -Wall -Wextra -O2 -S test.c && cat test.s
        .file   "test.c"
        .section        ".text"
        .align 2
        .globl test_and_set
        .type   test_and_set, @function
test_and_set:
        li 9,0
        li 7,255
        lbz 5,0(9)
        rlwinm 9,3,3,27,28
        xori 9,9,24
        li 6,1
        rlwinm 3,3,0,0,29
        slw 7,7,9
        slw 5,5,9
        slw 6,6,9
.L2:
        lwarx 10,0,3
        and 4,10,7
        andc 8,10,7
        cmpw 0,4,5
        or 8,8,6
        bne- 0,.L3
        stwcx. 8,0,3
        bne- 0,.L2
.L3:
        isync
        srw 10,10,9
        li 9,0
        stb 10,0(9)
        mfcr 3
        rlwinm 3,3,3,1
        blr
        .size   test_and_set, .-test_and_set
        .ident  "GCC: (GNU) 4.9.0 20130828 (experimental) [master revision
022fc2d:bffd767:fd457cef14f3bc6673e90a2de80005feea743ab7]"

powerpc-eabi-g++ -std=c++11 -Wall -Wextra -O2 -S test.cc && cat test.s
        .file   "test.cc"
        .section        ".text"
        .align 2
        .globl _Z12test_and_setRSt11atomic_flag
        .type   _Z12test_and_setRSt11atomic_flag, @function
_Z12test_and_setRSt11atomic_flag:
.LFB326:
        .cfi_startproc
        rlwinm 9,3,3,27,28
        li 6,255
        xori 9,9,24
        li 7,1
        rlwinm 8,3,0,0,29
        slw 6,6,9
        slw 7,7,9
.L2:
        lwarx 3,0,8
        andc 10,3,6
        or 10,10,7
        stwcx. 10,0,8
        bne- 0,.L2
        isync
        srw 3,3,9
        rlwinm 3,3,0,0xff
        blr
        .cfi_endproc
.LFE326:
        .size   _Z12test_and_setRSt11atomic_flag,
.-_Z12test_and_setRSt11atomic_flag
        .ident  "GCC: (GNU) 4.9.0 20130828 (experimental) [master revision
022fc2d:bffd767:fd457cef14f3bc6673e90a2de80005feea743ab7]"

The ARMv7 architecture has a very similar atomic model and GCC generates valid
code:

arm-eabi-gcc -march=armv7-a -std=c11 -Wall -Wextra -O2 -S test.c && cat test.s
        .arch armv7-a
        .fpu softvfp
        .eabi_attribute 20, 1
        .eabi_attribute 21, 1
        .eabi_attribute 23, 3
        .eabi_attribute 24, 1
        .eabi_attribute 25, 1
        .eabi_attribute 26, 1
        .eabi_attribute 30, 2
        .eabi_attribute 34, 1
        .eabi_attribute 18, 4
        .file   "test.c"
        .text
        .align  2
        .global test_and_set
        .type   test_and_set, %function
test_and_set:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        @ link register save eliminated.
        mov     r3, #0
        mov     r1, #1
        ldrb    r2, [r3]        @ zero_extendqisi2
.L2:
        ldrexb  r3, [r0]
        cmp     r3, r2
        bne     .L3
        strexb  ip, r1, [r0]
        cmp     ip, #0
        bne     .L2
.L3:
        mov     r2, #0
        dmb     sy
        movne   r0, #0
        moveq   r0, #1
        strb    r3, [r2]
        bx      lr
        .size   test_and_set, .-test_and_set
        .ident  "GCC: (GNU) 4.8.2 20130807 (prerelease) [master revision
022fc2d:bffd767:fd457cef14f3bc6673e90a2de80005feea743ab7]"

Interestingly the code generated by the C++ compiler is much better for both
ARM and PowerPC.

arm-eabi-g++ -march=armv7-a -std=c++11 -Wall -Wextra -O2 -S test.cc && cat
test.s
        .arch armv7-a
        .fpu softvfp
        .eabi_attribute 20, 1
        .eabi_attribute 21, 1
        .eabi_attribute 23, 3
        .eabi_attribute 24, 1
        .eabi_attribute 25, 1
        .eabi_attribute 26, 1
        .eabi_attribute 30, 2
        .eabi_attribute 34, 1
        .eabi_attribute 18, 4
        .file   "test.cc"
        .text
        .align  2
        .global _Z12test_and_setRSt11atomic_flag
        .type   _Z12test_and_setRSt11atomic_flag, %function
_Z12test_and_setRSt11atomic_flag:
        .fnstart
.LFB326:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        @ link register save eliminated.
        mov     r2, #1
.L2:
        ldrexb  r3, [r0]
        strexb  r1, r2, [r0]
        cmp     r1, #0
        bne     .L2
        dmb     sy
        uxtb    r0, r3
        bx      lr
        .cantunwind
        .fnend
        .size   _Z12test_and_setRSt11atomic_flag,
.-_Z12test_and_setRSt11atomic_flag
        .ident  "GCC: (GNU) 4.8.2 20130807 (prerelease) [master revision
022fc2d:bffd767:fd457cef14f3bc6673e90a2de80005feea743ab7]"

Reply via email to