Bug #7187

using signbit with optimisation > -O1 gives dereferencing type-punned pointer will break strict-aliasing rules

Added by Richard PALO over 2 years ago. Updated over 2 years ago.

Status:NewStart date:2016-07-17
Priority:NormalDue date:
Assignee:-% Done:

0%

Category:-
Target version:-
Difficulty:Medium Tags:needs-triage

Description

simple test program picked from libgo in gcc5.4:

richard@omnis:/home/richard/src/tsignbit$ cat tsignbit.c
#include <stdio.h>
#include <math.h>

void
runtime_printfloat(double v)
{
    if(isinf(v)) {
        if(signbit(v)) {
            printf("-Inf\n");
        } else {
            printf("+Inf\n");
        }
    }
    return;
}

problem demonstrated with gcc4.8 from omnios, but is similar with all gcc tested:

richard@omnis:/home/richard/src/tsignbit$ /opt/gcc-4.8.1/bin/gcc -std=gnu99  -Wall -c tsignbit.c 
richard@omnis:/home/richard/src/tsignbit$ /opt/gcc-4.8.1/bin/gcc -std=gnu99  -Wall -c tsignbit.c -O1
richard@omnis:/home/richard/src/tsignbit$ /opt/gcc-4.8.1/bin/gcc -std=gnu99  -Wall -c tsignbit.c -O2
tsignbit.c: In function ‘runtime_printfloat’:
tsignbit.c:8:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   if(signbit(v)) {
   ^

there must be a better way than the resulting code (extracted from -save-temps):

void
runtime_printfloat(double v)
{
 if(__builtin_isinf(v)) {
  if(__extension__( { __typeof(v) __x_s = (v); (sizeof (__x_s) == sizeof (float) ? (int) (*(unsigned *) &__x_s >> 31) : sizeof (__x_s) == sizeof (double) ? (int) (((unsigned *) &__x_s)[1] >> 31) : (int) (((unsigned short *) &__x_s)[4] >> 15)); })) {
   printf("-Inf\n");
  } else {
   printf("+Inf\n");
  }
 }
 return;
}

History

#1 Updated by Rich Lowe over 2 years ago

Pretty sure GCC has a builtin (or two), and we also have inlines in libm as well. Are you sure you should even be hitting a (presumably) macro version?

#2 Updated by Igor Kozhukhov over 2 years ago

Rich Lowe wrote:

Pretty sure GCC has a builtin (or two), and we also have inlines in libm as well. Are you sure you should even be hitting a (presumably) macro version?

i can confirm it on dilos env where i'm using gcc48 64bit:

gor@infra-99-018:/myshare/ssd02/builds/dilos-illumos.lx/12$ gcc-4.8 -std=gnu99 -Wall -c tsignbit.c 
igor@infra-99-018:/myshare/ssd02/builds/dilos-illumos.lx/12$ gcc-4.8 -std=gnu99 -Wall -c tsignbit.c -O1
igor@infra-99-018:/myshare/ssd02/builds/dilos-illumos.lx/12$ gcc-4.8 -std=gnu99 -Wall -c tsignbit.c -O2
tsignbit.c: In function ‘runtime_printfloat’:
tsignbit.c:8:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   if(signbit(v)) {
   ^
igor@infra-99-018:/myshare/ssd02/builds/dilos-illumos.lx/12$ gcc-4.8 -std=gnu99 -Wall -c tsignbit.c -O3
tsignbit.c: In function ‘runtime_printfloat’:
tsignbit.c:8:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   if(signbit(v)) {
   ^

#3 Updated by Richard PALO over 2 years ago

it looks as if iso/math_c99.h doesn't map onto the gate's libm implementation
(which itself seems to be missing _signbitf(float) and _signbitl(long double),
although _signbit(double) is there)

gcc fixincludes, even if not disabled, won't fixup math_c99.h as the selection sentinel
will fail.... the latest (v5) does:

#if defined( SOLARIS_MATH_11_CHECK )
 /* @(#)math_c99.h    1.14    13/03/27 */
 #undef    signbit
 #define    signbit(x)    (sizeof(x) == sizeof(float) \
                ? __builtin_signbitf(x) \
                : sizeof(x) == sizeof(long double) \
                  ? __builtin_signbitl(x) \
                  : __builtin_signbit(x))
#endif  /* SOLARIS_MATH_11_CHECK */

Also available in: Atom