Forwarding this message to the linaro toolchain list instead. I am not the person who should be supporting the Linaro ODP project with GCC questiosn; the toolchain team inside Linaro should be instead.
Thanks, Andrew Pinski
________________________________________ From: Ola Liljedahl ola.liljedahl@linaro.org Sent: Monday, November 24, 2014 2:31 PM To: lng-odp@lists.linaro.org; Pinski, Andrew Subject: strange behavior in GCC for use of uninitialized variables
Consider the following code fragment (from real life):
#include <stdint.h>
typedef volatile uint32_t odp_atomic_u32_t;
static inline uint32_t odp_atomic_fetch_inc_u32(odp_atomic_u32_t *ptr) { return __sync_fetch_and_add(ptr, 1); }
static inline void odp_spin(void) { #ifdef __SSE2__ __asm__ __volatile__ ("pause"); #else __asm__ __volatile__ ("rep; nop"); #endif }
typedef struct { int count; odp_atomic_u32_t bar; } odp_barrier_t;
void odp_barrier_wait(odp_barrier_t *barrier) { uint32_t count; int wasless;
// wasless = barrier->bar < barrier->count; <<<lost on git add -p __atomic_thread_fence(__ATOMIC_SEQ_CST); count = odp_atomic_fetch_inc_u32(&barrier->bar);
if (count == 2*barrier->count-1) { barrier->bar = 0; } else { while ((barrier->bar < barrier->count) == wasless) odp_spin(); }
__atomic_thread_fence(__ATOMIC_SEQ_CST); }
While fixing and cleaning up this code, the indicated line that initializes 'wasless' was dropped (because it reappears in a later patch in the patch set after the odp_atomic_fetch_inc call). To my surprise, GCC did not complain when compiling this file (using -O2 -Wall). But it does complain when compiling with -O0 -Wall. With some investigation, it seems like GCC understands that if a statement does not have any side effects so it can optimize away everything, including the usage of the uninitialized variable and thus also the corresponding warning.
olli@macmini:~/hacking/gcc-wunit$ gcc -O2 -Wall -c odp_barrier.c olli@macmini:~/hacking/gcc-wunit$ gcc -O0 -Wall -c odp_barrier.c odp_barrier.c: In function ‘odp_barrier_wait’: odp_barrier.c:42:9: warning: ‘wasless’ may be used uninitialized in this function [-Wmaybe-uninitialized] while ((barrier->bar < barrier->count) == wasless) ^
However the proper code seems to be generated in both cases (there is a "pause" instruction inlined or a call to odp_spin). So odp_spin() is not without side effects and is not optimized away. This contradicts my hypothesis.
Consider this minimalistic example: olli@macmini:~/hacking/gcc-wunit$ cat wunit.c #include <stdlib.h>
void test(void) { int wasless; int wasmore;
if (wasless) (void)0; if (wasmore) abort(); }
olli@macmini:~/hacking/gcc-wunit$ gcc -O0 -Wall -c wunit.c wunit.c: In function ‘test’: wunit.c:9:5: warning: ‘wasmore’ is used uninitialized in this function [-Wuninitialized] if (wasmore) abort(); ^ olli@macmini:~/hacking/gcc-wunit$ gcc -O2 -Wall -c wunit.c wunit.c: In function ‘test’: wunit.c:9:5: warning: ‘wasmore’ is used uninitialized in this function [-Wuninitialized] if (wasmore) abort(); ^
Here GCC warns when used with both -O0 and -O2 but only for the usage where there is a side effect. The use of 'wasless' that does not lead to any side-effects is ignored (and possibly rightly so, I can imagine this is undefined behavior, fortunately I did not attempt to run this program or my computer could have melted).
It is a bit worrying to me that instances of use of initialized variables is sometimes missed by GCC. Both because of lack of diagnostics for what is most likely a bug but also because I don't understand why GCC does this and the implications of that (at least it is a known unknown now).
-- Ola
Hi Ola,
I can confirm this problem with latest linaro-4.9-branch build. However, this is target-independent problem (reproducible on, at least, x86 and aarch64), so it is best to be tracked and addressed via upstream bugzilla.
Would you submit a PR on http://gcc.gnu.org/bugzilla ?
Thank you,
-- Maxim Kuvyrkov www.linaro.org
On Nov 25, 2014, at 1:34 AM, Pinski, Andrew Andrew.Pinski@caviumnetworks.com wrote:
Forwarding this message to the linaro toolchain list instead. I am not the person who should be supporting the Linaro ODP project with GCC questiosn; the toolchain team inside Linaro should be instead.
Thanks, Andrew Pinski
From: Ola Liljedahl ola.liljedahl@linaro.org Sent: Monday, November 24, 2014 2:31 PM To: lng-odp@lists.linaro.org; Pinski, Andrew Subject: strange behavior in GCC for use of uninitialized variables
Consider the following code fragment (from real life):
#include <stdint.h>
typedef volatile uint32_t odp_atomic_u32_t;
static inline uint32_t odp_atomic_fetch_inc_u32(odp_atomic_u32_t *ptr) { return __sync_fetch_and_add(ptr, 1); }
static inline void odp_spin(void) { #ifdef __SSE2__ __asm__ __volatile__ ("pause"); #else __asm__ __volatile__ ("rep; nop"); #endif }
typedef struct { int count; odp_atomic_u32_t bar; } odp_barrier_t;
void odp_barrier_wait(odp_barrier_t *barrier) { uint32_t count; int wasless;
// wasless = barrier->bar < barrier->count; <<<lost on git add -p __atomic_thread_fence(__ATOMIC_SEQ_CST); count = odp_atomic_fetch_inc_u32(&barrier->bar);
if (count == 2*barrier->count-1) { barrier->bar = 0; } else { while ((barrier->bar < barrier->count) == wasless) odp_spin(); } __atomic_thread_fence(__ATOMIC_SEQ_CST);
}
While fixing and cleaning up this code, the indicated line that initializes 'wasless' was dropped (because it reappears in a later patch in the patch set after the odp_atomic_fetch_inc call). To my surprise, GCC did not complain when compiling this file (using -O2 -Wall). But it does complain when compiling with -O0 -Wall. With some investigation, it seems like GCC understands that if a statement does not have any side effects so it can optimize away everything, including the usage of the uninitialized variable and thus also the corresponding warning.
olli@macmini:~/hacking/gcc-wunit$ gcc -O2 -Wall -c odp_barrier.c olli@macmini:~/hacking/gcc-wunit$ gcc -O0 -Wall -c odp_barrier.c odp_barrier.c: In function ‘odp_barrier_wait’: odp_barrier.c:42:9: warning: ‘wasless’ may be used uninitialized in this function [-Wmaybe-uninitialized] while ((barrier->bar < barrier->count) == was less)
Thanks Maxim,
Yes I should do that. I also intend to make the code used to reproduce the problem smaller.
One of my worries was that GCC considered the loop without side effects (ignoring the inline assembler in odp_spin()) and thus removed the loop (including the usage of the uninitialized variable). But that does not seem to be the case.
-- Ola
On 27 November 2014 at 08:58, Maxim Kuvyrkov maxim.kuvyrkov@linaro.org wrote:
Hi Ola,
I can confirm this problem with latest linaro-4.9-branch build. However, this is target-independent problem (reproducible on, at least, x86 and aarch64), so it is best to be tracked and addressed via upstream bugzilla.
Would you submit a PR on http://gcc.gnu.org/bugzilla ?
Thank you,
-- Maxim Kuvyrkov www.linaro.org
On Nov 25, 2014, at 1:34 AM, Pinski, Andrew Andrew.Pinski@caviumnetworks.com wrote:
Forwarding this message to the linaro toolchain list instead. I am not the person who should be supporting the Linaro ODP project with GCC questiosn; the toolchain team inside Linaro should be instead.
Thanks, Andrew Pinski
From: Ola Liljedahl ola.liljedahl@linaro.org Sent: Monday, November 24, 2014 2:31 PM To: lng-odp@lists.linaro.org; Pinski, Andrew Subject: strange behavior in GCC for use of uninitialized variables
Consider the following code fragment (from real life):
#include <stdint.h>
typedef volatile uint32_t odp_atomic_u32_t;
static inline uint32_t odp_atomic_fetch_inc_u32(odp_atomic_u32_t *ptr) { return __sync_fetch_and_add(ptr, 1); }
static inline void odp_spin(void) { #ifdef __SSE2__ __asm__ __volatile__ ("pause"); #else __asm__ __volatile__ ("rep; nop"); #endif }
typedef struct { int count; odp_atomic_u32_t bar; } odp_barrier_t;
void odp_barrier_wait(odp_barrier_t *barrier) { uint32_t count; int wasless;
// wasless = barrier->bar < barrier->count; <<<lost on git add -p __atomic_thread_fence(__ATOMIC_SEQ_CST); count = odp_atomic_fetch_inc_u32(&barrier->bar);
if (count == 2*barrier->count-1) { barrier->bar = 0; } else { while ((barrier->bar < barrier->count) == wasless) odp_spin(); } __atomic_thread_fence(__ATOMIC_SEQ_CST);
}
While fixing and cleaning up this code, the indicated line that initializes 'wasless' was dropped (because it reappears in a later patch in the patch set after the odp_atomic_fetch_inc call). To my surprise, GCC did not complain when compiling this file (using -O2 -Wall). But it does complain when compiling with -O0 -Wall. With some investigation, it seems like GCC understands that if a statement does not have any side effects so it can optimize away everything, including the usage of the uninitialized variable and thus also the corresponding warning.
olli@macmini:~/hacking/gcc-wunit$ gcc -O2 -Wall -c odp_barrier.c olli@macmini:~/hacking/gcc-wunit$ gcc -O0 -Wall -c odp_barrier.c odp_barrier.c: In function ‘odp_barrier_wait’: odp_barrier.c:42:9: warning: ‘wasless’ may be used uninitialized in this function [-Wmaybe-uninitialized] while ((barrier->bar < barrier->count) == was less)
On 27 November 2014 at 12:16, Ola Liljedahl ola.liljedahl@linaro.org wrote:
Thanks Maxim,
Yes I should do that. I also intend to make the code used to reproduce the problem smaller.
One of my worries was that GCC considered the loop without side effects (ignoring the inline assembler in odp_spin()) and thus removed the loop (including the usage of the uninitialized variable). But that does not seem to be the case.
-- Ola
Shouldn't preprocessor (cpp) show what really happens?
Maxim.
On 27 November 2014 at 08:58, Maxim Kuvyrkov maxim.kuvyrkov@linaro.org wrote:
Hi Ola,
I can confirm this problem with latest linaro-4.9-branch build.
However, this is target-independent problem (reproducible on, at least, x86 and aarch64), so it is best to be tracked and addressed via upstream bugzilla.
Would you submit a PR on http://gcc.gnu.org/bugzilla ?
Thank you,
-- Maxim Kuvyrkov www.linaro.org
On Nov 25, 2014, at 1:34 AM, Pinski, Andrew <
Andrew.Pinski@caviumnetworks.com> wrote:
Forwarding this message to the linaro toolchain list instead. I am not
the person who should be supporting the Linaro ODP project with GCC questiosn; the toolchain team inside Linaro should be instead.
Thanks, Andrew Pinski
From: Ola Liljedahl ola.liljedahl@linaro.org Sent: Monday, November 24, 2014 2:31 PM To: lng-odp@lists.linaro.org; Pinski, Andrew Subject: strange behavior in GCC for use of uninitialized variables
Consider the following code fragment (from real life):
#include <stdint.h>
typedef volatile uint32_t odp_atomic_u32_t;
static inline uint32_t odp_atomic_fetch_inc_u32(odp_atomic_u32_t *ptr) { return __sync_fetch_and_add(ptr, 1); }
static inline void odp_spin(void) { #ifdef __SSE2__ __asm__ __volatile__ ("pause"); #else __asm__ __volatile__ ("rep; nop"); #endif }
typedef struct { int count; odp_atomic_u32_t bar; } odp_barrier_t;
void odp_barrier_wait(odp_barrier_t *barrier) { uint32_t count; int wasless;
// wasless = barrier->bar < barrier->count; <<<lost on git add -p __atomic_thread_fence(__ATOMIC_SEQ_CST); count = odp_atomic_fetch_inc_u32(&barrier->bar);
if (count == 2*barrier->count-1) { barrier->bar = 0; } else { while ((barrier->bar < barrier->count) == wasless) odp_spin(); } __atomic_thread_fence(__ATOMIC_SEQ_CST);
}
While fixing and cleaning up this code, the indicated line that initializes 'wasless' was dropped (because it reappears in a later patch in the patch set after the odp_atomic_fetch_inc call). To my surprise, GCC did not complain when compiling this file (using -O2 -Wall). But it does complain when compiling with -O0 -Wall. With some investigation, it seems like GCC understands that if a statement does not have any side effects so it can optimize away everything, including the usage of the uninitialized variable and thus also the corresponding warning.
olli@macmini:~/hacking/gcc-wunit$ gcc -O2 -Wall -c odp_barrier.c olli@macmini:~/hacking/gcc-wunit$ gcc -O0 -Wall -c odp_barrier.c odp_barrier.c: In function ‘odp_barrier_wait’: odp_barrier.c:42:9: warning: ‘wasless’ may be used uninitialized in this function [-Wmaybe-uninitialized] while ((barrier->bar < barrier->count) == was less)
lng-odp mailing list lng-odp@lists.linaro.org http://lists.linaro.org/mailman/listinfo/lng-odp
Maxim U.,
There are no macros here for preprocessor to complain.
Ola,
The uninitialized warnings are generated by a pass that is separate from code generation. The deficiencies of this pass should not affect correctness of the code.
-- Maxim Kuvyrkov www.linaro.org
On Nov 27, 2014, at 1:31 PM, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On 27 November 2014 at 12:16, Ola Liljedahl ola.liljedahl@linaro.org wrote: Thanks Maxim,
Yes I should do that. I also intend to make the code used to reproduce the problem smaller.
One of my worries was that GCC considered the loop without side effects (ignoring the inline assembler in odp_spin()) and thus removed the loop (including the usage of the uninitialized variable). But that does not seem to be the case.
-- Ola
Shouldn't preprocessor (cpp) show what really happens?
Maxim.
On 27 November 2014 at 08:58, Maxim Kuvyrkov maxim.kuvyrkov@linaro.org wrote:
Hi Ola,
I can confirm this problem with latest linaro-4.9-branch build. However, this is target-independent problem (reproducible on, at least, x86 and aarch64), so it is best to be tracked and addressed via upstream bugzilla.
Would you submit a PR on http://gcc.gnu.org/bugzilla ?
Thank you,
-- Maxim Kuvyrkov www.linaro.org
On Nov 25, 2014, at 1:34 AM, Pinski, Andrew Andrew.Pinski@caviumnetworks.com wrote:
Forwarding this message to the linaro toolchain list instead. I am not the person who should be supporting the Linaro ODP project with GCC questiosn; the toolchain team inside Linaro should be instead.
Thanks, Andrew Pinski
From: Ola Liljedahl ola.liljedahl@linaro.org Sent: Monday, November 24, 2014 2:31 PM To: lng-odp@lists.linaro.org; Pinski, Andrew Subject: strange behavior in GCC for use of uninitialized variables
Consider the following code fragment (from real life):
#include <stdint.h>
typedef volatile uint32_t odp_atomic_u32_t;
static inline uint32_t odp_atomic_fetch_inc_u32(odp_atomic_u32_t *ptr) { return __sync_fetch_and_add(ptr, 1); }
static inline void odp_spin(void) { #ifdef __SSE2__ __asm__ __volatile__ ("pause"); #else __asm__ __volatile__ ("rep; nop"); #endif }
typedef struct { int count; odp_atomic_u32_t bar; } odp_barrier_t;
void odp_barrier_wait(odp_barrier_t *barrier) { uint32_t count; int wasless;
// wasless = barrier->bar < barrier->count; <<<lost on git add -p __atomic_thread_fence(__ATOMIC_SEQ_CST); count = odp_atomic_fetch_inc_u32(&barrier->bar);
if (count == 2*barrier->count-1) { barrier->bar = 0; } else { while ((barrier->bar < barrier->count) == wasless) odp_spin(); } __atomic_thread_fence(__ATOMIC_SEQ_CST);
}
While fixing and cleaning up this code, the indicated line that initializes 'wasless' was dropped (because it reappears in a later patch in the patch set after the odp_atomic_fetch_inc call). To my surprise, GCC did not complain when compiling this file (using -O2 -Wall). But it does complain when compiling with -O0 -Wall. With some investigation, it seems like GCC understands that if a statement does not have any side effects so it can optimize away everything, including the usage of the uninitialized variable and thus also the corresponding warning.
olli@macmini:~/hacking/gcc-wunit$ gcc -O2 -Wall -c odp_barrier.c olli@macmini:~/hacking/gcc-wunit$ gcc -O0 -Wall -c odp_barrier.c odp_barrier.c: In function ‘odp_barrier_wait’: odp_barrier.c:42:9: warning: ‘wasless’ may be used uninitialized in this function [-Wmaybe-uninitialized] while ((barrier->bar < barrier->count) == was less)
lng-odp mailing list lng-odp@lists.linaro.org http://lists.linaro.org/mailman/listinfo/lng-odp
linaro-toolchain@lists.linaro.org