Bug 32397 - wrong instruction order generated
Summary: wrong instruction order generated
Status: RESOLVED DUPLICATE of bug 21920
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.2.0
: P3 major
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-06-19 00:30 UTC by Hans Rosenfeld
Modified: 2007-06-19 11:27 UTC (History)
13 users (show)

See Also:
Host: i386-unknown-netbsdelf4.0.
Target: arm-elf
Build: i386-unknown-netbsdelf4.0.
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Hans Rosenfeld 2007-06-19 00:30:57 UTC
this C code line 
{(((Cyg_libm_ieee_double_shape_type *)&x)->parts.msw) = (hx&0x800fffff)|(k<<20); return x;}
causes this assembler code to be generated:

bic     r3, ip, #2130706432
bic     r3, r3, #15728640
ldmia   sp, {r0-r1}
orr     r3, r3, r2, asl #20
str     r3, [r5, #0]
b       .L6

The ldmia instruction loads the value to be returned from memory before the calculation is finished and the result is stored there. Rearranging the instructions by hand in the resulting binary makes the program work.

gcc output:
Using built-in specs.
Target: arm-elf
Configured with: /usr/local/src/gcc-4.2.0/configure --target=arm-elf --prefix=/usr/local --with-gnu-as --with-gnu-ld --disable-hosted-libstdcxx --disable-__cxa_atexit --enable-languages=c,c++
Thread model: single
gcc version 4.2.0
 /usr/local/libexec/gcc/arm-elf/4.2.0/cc1 -E -quiet -v -I/tmp/ecos/whz2292_install/include -I/usr/local/share/ecos/packages/language/c/libm/current -I/usr/local/share/ecos/packages/language/c/libm/current/src -I/usr/local/share/ecos/packages/language/c/libm/current/tests -I. -I/usr/local/share/ecos/packages/language/c/libm/current/src/double/portable-api/ -D__USES_INITFINI__ -MD src/double/portable-api/s_scalbn.tmp /usr/local/share/ecos/packages/language/c/libm/current/src/double/portable-api/s_scalbn.c -mcpu=arm7tdmi -Wall -Wpointer-arith -Wstrict-prototypes -Winline -Wundef -finline-limit=7000 -ffunction-sections -fdata-sections -fno-exceptions -fworking-directory -O2 -fpch-preprocess -o s_scalbn.i
ignoring nonexistent directory "/usr/local/lib/gcc/arm-elf/4.2.0/../../../../arm-elf/sys-include"
#include "..." search starts here:
#include <...> search starts here:
 /tmp/ecos/whz2292_install/include
 /usr/local/share/ecos/packages/language/c/libm/current
 /usr/local/share/ecos/packages/language/c/libm/current/src
 /usr/local/share/ecos/packages/language/c/libm/current/tests
 .
 /usr/local/share/ecos/packages/language/c/libm/current/src/double/portable-api/
 /usr/local/lib/gcc/arm-elf/4.2.0/include
 /usr/local/lib/gcc/arm-elf/4.2.0/../../../../arm-elf/include
End of search list.
 /usr/local/libexec/gcc/arm-elf/4.2.0/cc1 -fpreprocessed s_scalbn.i -quiet -dumpbase s_scalbn.c -mcpu=arm7tdmi -auxbase-strip src/double/portable-api/language_c_libm_s_scalbn.o -g -O2 -Wall -Wpointer-arith -Wstrict-prototypes -Winline -Wundef -version -finline-limit=7000 -ffunction-sections -fdata-sections -fno-exceptions -o s_scalbn.s
GNU C version 4.2.0 (arm-elf)
	compiled by GNU C version 4.1.2 20061021 prerelease (NetBSD nb3 20061125).
GGC heuristics: --param ggc-min-expand=64 --param ggc-min-heapsize=65415
Compiler executable checksum: f21aa8a15d6feeb6af69912bd33e6003
 /usr/local/lib/gcc/arm-elf/4.2.0/../../../../arm-elf/bin/as -mcpu=arm7tdmi -o src/double/portable-api/language_c_libm_s_scalbn.o s_scalbn.s

source file:
# 1 "/usr/local/share/ecos/packages/language/c/libm/current/src/double/portable-api/s_scalbn.c"
# 1 "/tmp/ecos/whz2292_build/language/c/libm/current//"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/local/share/ecos/packages/language/c/libm/current/src/double/portable-api/s_scalbn.c"
# 56 "/usr/local/share/ecos/packages/language/c/libm/current/src/double/portable-api/s_scalbn.c"
# 1 "/tmp/ecos/whz2292_install/include/pkgconf/libm.h" 1
# 12 "/tmp/ecos/whz2292_install/include/pkgconf/libm.h"
# 1 "/tmp/ecos/whz2292_install/include/pkgconf/system.h" 1
# 13 "/tmp/ecos/whz2292_install/include/pkgconf/libm.h" 2
typedef enum {
    CYGNUM_LIBM_COMPAT_UNINIT= 0,
    CYGNUM_LIBM_COMPAT_POSIX = 1,
    CYGNUM_LIBM_COMPAT_IEEE = 2,
    CYGNUM_LIBM_COMPAT_XOPEN = 3,

    CYGNUM_LIBM_COMPAT_SVID = 4

} Cyg_libm_compat_t;
# 57 "/usr/local/share/ecos/packages/language/c/libm/current/src/double/portable-api/s_scalbn.c" 2
# 83 "/usr/local/share/ecos/packages/language/c/libm/current/src/double/portable-api/s_scalbn.c"
# 1 "/usr/local/share/ecos/packages/language/c/libm/current/src/mathincl/fdlibm.h" 1
# 66 "/usr/local/share/ecos/packages/language/c/libm/current/src/mathincl/fdlibm.h"
# 1 "/tmp/ecos/whz2292_install/include/cyg/infra/cyg_type.h" 1
# 58 "/tmp/ecos/whz2292_install/include/cyg/infra/cyg_type.h"
# 1 "/tmp/ecos/whz2292_install/include/stddef.h" 1
# 64 "/tmp/ecos/whz2292_install/include/stddef.h"
# 1 "/usr/local/lib/gcc/arm-elf/4.2.0/include/stddef.h" 1 3 4
# 152 "/usr/local/lib/gcc/arm-elf/4.2.0/include/stddef.h" 3 4
typedef long int ptrdiff_t;
# 214 "/usr/local/lib/gcc/arm-elf/4.2.0/include/stddef.h" 3 4
typedef long unsigned int size_t;
# 326 "/usr/local/lib/gcc/arm-elf/4.2.0/include/stddef.h" 3 4
typedef int wchar_t;
# 65 "/tmp/ecos/whz2292_install/include/stddef.h" 2
# 59 "/tmp/ecos/whz2292_install/include/cyg/infra/cyg_type.h" 2
# 83 "/tmp/ecos/whz2292_install/include/cyg/infra/cyg_type.h"
# 1 "/tmp/ecos/whz2292_install/include/cyg/hal/basetype.h" 1
# 84 "/tmp/ecos/whz2292_install/include/cyg/infra/cyg_type.h" 2
# 160 "/tmp/ecos/whz2292_install/include/cyg/infra/cyg_type.h"
typedef int bool;
# 202 "/tmp/ecos/whz2292_install/include/cyg/infra/cyg_type.h"
typedef unsigned char cyg_uint8 ;
typedef signed char cyg_int8 ;

typedef unsigned short cyg_uint16 ;
typedef signed short cyg_int16 ;

typedef unsigned int cyg_uint32 ;
typedef signed int cyg_int32 ;

typedef unsigned long long cyg_uint64 ;
typedef signed long long cyg_int64 ;

typedef int cyg_bool ;






typedef unsigned int cyg_ucount8 ;
typedef signed int cyg_count8 ;

typedef unsigned int cyg_ucount16 ;
typedef signed int cyg_count16 ;

typedef unsigned int cyg_ucount32 ;
typedef signed int cyg_count32 ;

typedef unsigned long long cyg_ucount64 ;
typedef signed long long cyg_count64 ;






typedef volatile unsigned char cyg_atomic;
typedef volatile unsigned char CYG_ATOMIC;




typedef cyg_uint32 CYG_WORD;
typedef cyg_uint8 CYG_BYTE;
typedef cyg_uint16 CYG_WORD16;
typedef cyg_uint32 CYG_WORD32;
typedef cyg_uint64 CYG_WORD64;

typedef cyg_uint32 CYG_ADDRESS;
typedef cyg_uint32 CYG_ADDRWORD;
# 67 "/usr/local/share/ecos/packages/language/c/libm/current/src/mathincl/fdlibm.h" 2
# 1 "/tmp/ecos/whz2292_install/include/math.h" 1
# 69 "/tmp/ecos/whz2292_install/include/math.h"
# 1 "/tmp/ecos/whz2292_install/include/float.h" 1
# 65 "/tmp/ecos/whz2292_install/include/float.h"
# 1 "/usr/local/lib/gcc/arm-elf/4.2.0/include/float.h" 1 3 4
# 66 "/tmp/ecos/whz2292_install/include/float.h" 2
# 70 "/tmp/ecos/whz2292_install/include/math.h" 2

# 1 "/tmp/ecos/whz2292_install/include/sys/ieeefp.h" 1
# 141 "/tmp/ecos/whz2292_install/include/sys/ieeefp.h"
typedef union
{
    cyg_int32 asi32[2];

    cyg_int64 asi64;

    double value;

    struct
    {

        unsigned int fraction1:16;
        unsigned int fraction0: 4;
        unsigned int exponent :11;
        unsigned int sign : 1;
        unsigned int fraction3:16;
        unsigned int fraction2:16;
# 166 "/tmp/ecos/whz2292_install/include/sys/ieeefp.h"
    } number;

    struct
    {

        unsigned int function1:16;
        unsigned int function0:3;
        unsigned int quiet:1;
        unsigned int exponent: 11;
        unsigned int sign : 1;
        unsigned int function3:16;
        unsigned int function2:16;
# 187 "/tmp/ecos/whz2292_install/include/sys/ieeefp.h"
    } nan;

    struct
    {

        cyg_uint32 msw;
        cyg_uint32 lsw;




    } parts;

} Cyg_libm_ieee_double_shape_type;


typedef union
{
    cyg_int32 asi32;

    float value;

    struct
    {
        unsigned int fraction0: 7;
        unsigned int fraction1: 16;
        unsigned int exponent: 8;
        unsigned int sign : 1;
    } number;

    struct
    {
        unsigned int function1:16;
        unsigned int function0:6;
        unsigned int quiet:1;
        unsigned int exponent:8;
        unsigned int sign:1;
    } nan;

} Cyg_libm_ieee_float_shape_type;
# 72 "/tmp/ecos/whz2292_install/include/math.h" 2
# 102 "/tmp/ecos/whz2292_install/include/math.h"
struct exception {
    int type;
    char *name;
    double arg1;
    double arg2;
    double retval;
};






extern const Cyg_libm_ieee_double_shape_type cyg_libm_infinity;
# 135 "/tmp/ecos/whz2292_install/include/math.h"
extern Cyg_libm_compat_t cygvar_libm_compat_mode;






static inline Cyg_libm_compat_t
cyg_libm_get_compat_mode( void )
{
    return cygvar_libm_compat_mode;
}


static inline Cyg_libm_compat_t
cyg_libm_set_compat_mode( Cyg_libm_compat_t math_compat_mode)
{
    Cyg_libm_compat_t oldmode;

    oldmode = cygvar_libm_compat_mode;
    cygvar_libm_compat_mode = math_compat_mode;
    return oldmode;
}
# 173 "/tmp/ecos/whz2292_install/include/math.h"
extern int signgam;
# 182 "/tmp/ecos/whz2292_install/include/math.h"
extern double
acos( double );

extern double
asin( double );

extern double
atan( double );

extern double
atan2( double, double );


extern double
cos( double );

extern double
sin( double );

extern double
tan( double );



extern double
cosh( double );

extern double
sinh( double );

extern double
tanh( double );



extern double
exp( double );

extern double
frexp( double, int * );


extern double
ldexp( double, int );

extern double
log( double );

extern double
log10( double );

extern double
modf( double, double * );






extern double
pow( double, double );

extern double
sqrt( double );



extern double
ceil( double );

extern double
fabs( double );

extern double
floor( double );

extern double
fmod( double, double );





extern int
matherr( struct exception * );





extern double
acosh( double );

extern double
asinh( double );

extern double
atanh( double );



extern double
erf( double );


extern double
erfc( double );



extern double
lgamma( double );



extern double
lgamma_r( double, int * );



extern double
gamma( double );
# 312 "/tmp/ecos/whz2292_install/include/math.h"
extern double
gamma_r( double, int * );




extern double
j0( double );

extern double
j1( double );

extern double
jn( int, double );


extern double
y0( double );


extern double
y1( double );


extern double
yn( int, double );




extern double
scalbn( double, int );



extern double
scalb( double, double );
# 358 "/tmp/ecos/whz2292_install/include/math.h"
extern double
cbrt( double );

extern double
hypot( double, double );

extern int
isnan( double );

extern int
finite( double );

extern double
logb( double );



extern int
ilogb( double );


extern double
nextafter( double, double );




extern double
remainder( double, double );

extern double
significand( double );





extern double
copysign ( double, double );

extern double
rint( double );




extern double
expm1( double );


extern double
log1p( double );
# 68 "/usr/local/share/ecos/packages/language/c/libm/current/src/mathincl/fdlibm.h" 2
# 1 "/tmp/ecos/whz2292_install/include/float.h" 1
# 69 "/usr/local/share/ecos/packages/language/c/libm/current/src/mathincl/fdlibm.h" 2
# 85 "/usr/local/share/ecos/packages/language/c/libm/current/src/mathincl/fdlibm.h"
typedef cyg_int32 __int32_t;
typedef cyg_uint32 __uint32_t;
typedef Cyg_libm_ieee_double_shape_type ieee_double_shape_type;
# 190 "/usr/local/share/ecos/packages/language/c/libm/current/src/mathincl/fdlibm.h"
extern double
__ieee754_sqrt( double );

extern double
__ieee754_acos( double );

extern double
__ieee754_acosh( double );

extern double
__ieee754_log( double );

extern double
__ieee754_atanh( double );

extern double
__ieee754_asin( double );

extern double
__ieee754_atan2( double, double );

extern double
__ieee754_exp( double );

extern double
__ieee754_cosh( double );

extern double
__ieee754_fmod( double, double );

extern double
__ieee754_pow( double, double );

extern double
__ieee754_lgamma_r( double, int * );

extern double
__ieee754_gamma_r( double, int * );

extern double
__ieee754_lgamma( double );

extern double
__ieee754_gamma( double );

extern double
__ieee754_log10( double );

extern double
__ieee754_sinh( double );

extern double
__ieee754_hypot( double, double );

extern double
__ieee754_j0( double );

extern double
__ieee754_j1( double );

extern double
__ieee754_y0( double );

extern double
__ieee754_y1( double );

extern double
__ieee754_jn( int, double );

extern double
__ieee754_yn( int, double );

extern double
__ieee754_remainder( double, double );

extern int
__ieee754_rem_pio2( double, double * );


extern double
__ieee754_scalb( double, double );







extern double
__kernel_standard( double, double, int );

extern double
__kernel_sin( double, double, int );

extern double
__kernel_cos( double, double );

extern double
__kernel_tan( double, double, int );

extern int
__kernel_rem_pio2( double *, double *, int, int, int, const int * );
# 84 "/usr/local/share/ecos/packages/language/c/libm/current/src/double/portable-api/s_scalbn.c" 2

static const double
two54 = 1.80143985094819840000e+16,
twom54 = 5.55111512312578270212e-17,
huge = 1.0e+300,
tiny = 1.0e-300;

        double scalbn (double x, int n)
{
        int k,hx,lx;
        hx = (((Cyg_libm_ieee_double_shape_type *)&x)->parts.msw);
        lx = (((Cyg_libm_ieee_double_shape_type *)&x)->parts.lsw);
        k = (hx&0x7ff00000)>>20;
        if (k==0) {
            if ((lx|(hx&0x7fffffff))==0) return x;
            x *= two54;
            hx = (((Cyg_libm_ieee_double_shape_type *)&x)->parts.msw);
            k = ((hx&0x7ff00000)>>20) - 54;
            if (n< -50000) return tiny*x;
            }
        if (k==0x7ff) return x+x;
        k = k+n;
        if (k > 0x7fe) return huge*copysign(huge,x);
        if (k > 0)
            {(((Cyg_libm_ieee_double_shape_type *)&x)->parts.msw) = (hx&0x800fffff)|(k<<20); return x;}
        if (k <= -54) {
            if (n > 50000)
                return huge*copysign(huge,x);
            else return tiny*copysign(tiny,x);
        }
        k += 54;
        (((Cyg_libm_ieee_double_shape_type *)&x)->parts.msw) = (hx&0x800fffff)|(k<<20);
        return x*twom54;
}
Comment 1 Andrew Pinski 2007-06-19 07:56:00 UTC
((Cyg_libm_ieee_double_shape_type *)&x)->part is ovbiously an aliasing violation.

*** This bug has been marked as a duplicate of 21920 ***
Comment 2 Hans Rosenfeld 2007-06-19 10:52:51 UTC
Subject: Re:  wrong instruction order generated

On Tue, Jun 19, 2007 at 07:56:01AM -0000, pinskia at gcc dot gnu dot org wrote:
> ------- Comment #1 from pinskia at gcc dot gnu dot org  2007-06-19 07:56 -------
> ((Cyg_libm_ieee_double_shape_type *)&x)->part is ovbiously an aliasing
> violation.

I doubt that. As you can see in the source file, x is a double and
Cyg_libm_ieee_double_shape_type is a union containing a double. 

To quote the standard,
 7 An object shall have its stored value accessed only by an lvalue
   expression that has one of the following types:
    a type compatible with the effective type of the object,
	[...]
    an aggregate or union type that includes one of the aforementioned
     types among its members (including, recursively, a member of a
     subaggregate or contained union) [...]

So as far as I understand this should be perfectly legal by the ISO C
standard.

Maybe I'm missing somthing here, I read everywhere that using a union
for this kind of thing is a gcc extension. I wonder, if there is no
standard way to manipulate doubles by treating them as ints or bitfields
or something like that, how is one supposed to write a floating point
emulator in ISO C?


Comment 3 Rask Ingemann Lambertsen 2007-06-19 11:27:14 UTC
You can use memcpy (&int, &float, min (sizeof (int), sizeof (float))) and vice versa. I suppose you can also memcpy() into or out of a char array of the right size.
If you were to use the GCC extension of using a union, it would look something like this:

double x;
cyg_uint32 hx, lx;
Cyg_libm_ieee_double_shape_type tmp;

tmp.value = x;
hx = tmp.parts.msw
lx = tmp.parts.lsw