runtime: fix misc gcc-isms and undefined behavior

This includes the use of __complex and __builtin_ functions where
unprefixed entities would suffice, and the use of a union for
bit-casting between types.

From-SVN: r211036
This commit is contained in:
Ian Lance Taylor 2014-05-28 23:10:47 +00:00
parent bc2eed9a8e
commit 93c521ea9c
5 changed files with 109 additions and 138 deletions

View File

@ -4,6 +4,9 @@
Use of this source code is governed by a BSD-style Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */ license that can be found in the LICENSE file. */
#include <complex.h>
#include <math.h>
/* Calls to these functions are generated by the Go frontend for /* Calls to these functions are generated by the Go frontend for
division of complex64 or complex128. We use these because Go's division of complex64 or complex128. We use these because Go's
complex division expects slightly different results from the GCC complex division expects slightly different results from the GCC
@ -13,33 +16,33 @@
the the whole number is Inf, but an operation involving NaN ought the the whole number is Inf, but an operation involving NaN ought
to result in NaN, not Inf. */ to result in NaN, not Inf. */
__complex float complex float
__go_complex64_div (__complex float a, __complex float b) __go_complex64_div (complex float a, complex float b)
{ {
if (__builtin_expect (b == 0+0i, 0)) if (__builtin_expect (b == 0, 0))
{ {
if (!__builtin_isinff (__real__ a) if (!isinf (crealf (a))
&& !__builtin_isinff (__imag__ a) && !isinf (cimagf (a))
&& (__builtin_isnanf (__real__ a) || __builtin_isnanf (__imag__ a))) && (isnan (crealf (a)) || isnan (cimagf (a))))
{ {
/* Pass "1" to nanf to match math/bits.go. */ /* Pass "1" to nanf to match math/bits.go. */
return __builtin_nanf("1") + __builtin_nanf("1")*1i; return nanf("1") + nanf("1")*I;
} }
} }
return a / b; return a / b;
} }
__complex double complex double
__go_complex128_div (__complex double a, __complex double b) __go_complex128_div (complex double a, complex double b)
{ {
if (__builtin_expect (b == 0+0i, 0)) if (__builtin_expect (b == 0, 0))
{ {
if (!__builtin_isinf (__real__ a) if (!isinf (creal (a))
&& !__builtin_isinf (__imag__ a) && !isinf (cimag (a))
&& (__builtin_isnan (__real__ a) || __builtin_isnan (__imag__ a))) && (isnan (creal (a)) || isnan (cimag (a))))
{ {
/* Pass "1" to nan to match math/bits.go. */ /* Pass "1" to nan to match math/bits.go. */
return __builtin_nan("1") + __builtin_nan("1")*1i; return nan("1") + nan("1")*I;
} }
} }
return a / b; return a / b;

View File

@ -4,13 +4,13 @@
Use of this source code is governed by a BSD-style Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */ license that can be found in the LICENSE file. */
#include <complex.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include "runtime.h" #include "runtime.h"
#include "go-type.h" #include "go-type.h"
/* The 64-bit type. */
typedef unsigned int DItype __attribute__ ((mode (DI)));
/* Hash function for float types. */ /* Hash function for float types. */
uintptr_t uintptr_t
@ -18,69 +18,67 @@ __go_type_hash_complex (const void *vkey, uintptr_t key_size)
{ {
if (key_size == 8) if (key_size == 8)
{ {
union const complex float *cfp;
{ complex float cf;
unsigned char a[8];
__complex float cf;
DItype di;
} ucf;
__complex float cf;
float cfr; float cfr;
float cfi; float cfi;
uint64_t fi;
__builtin_memcpy (ucf.a, vkey, 8); cfp = (const complex float *) vkey;
cf = ucf.cf; cf = *cfp;
cfr = __builtin_crealf (cf);
cfi = __builtin_cimagf (cf); cfr = crealf (cf);
if (__builtin_isinff (cfr) || __builtin_isinff (cfi)) cfi = cimagf (cf);
if (isinf (cfr) || isinf (cfi))
return 0; return 0;
/* NaN != NaN, so the hash code of a NaN is irrelevant. Make it /* NaN != NaN, so the hash code of a NaN is irrelevant. Make it
random so that not all NaNs wind up in the same place. */ random so that not all NaNs wind up in the same place. */
if (__builtin_isnanf (cfr) || __builtin_isnanf (cfi)) if (isnan (cfr) || isnan (cfi))
return runtime_fastrand1 (); return runtime_fastrand1 ();
/* Avoid negative zero. */ /* Avoid negative zero. */
if (cfr == 0 && cfi == 0) if (cfr == 0 && cfi == 0)
return 0; return 0;
else if (cfr == 0) else if (cfr == 0)
ucf.cf = cfi * 1.0iF; cf = cfi * I;
else if (cfi == 0) else if (cfi == 0)
ucf.cf = cfr; cf = cfr;
return ucf.di; memcpy (&fi, &cf, 8);
return (uintptr_t) cfi;
} }
else if (key_size == 16) else if (key_size == 16)
{ {
union const complex double *cdp;
{ complex double cd;
unsigned char a[16];
__complex double cd;
DItype adi[2];
} ucd;
__complex double cd;
double cdr; double cdr;
double cdi; double cdi;
uint64_t di[2];
__builtin_memcpy (ucd.a, vkey, 16); cdp = (const complex double *) vkey;
cd = ucd.cd; cd = *cdp;
cdr = __builtin_crealf (cd);
cdi = __builtin_cimagf (cd); cdr = creal (cd);
if (__builtin_isinf (cdr) || __builtin_isinf (cdi)) cdi = cimag (cd);
if (isinf (cdr) || isinf (cdi))
return 0; return 0;
if (__builtin_isnan (cdr) || __builtin_isnan (cdi)) if (isnan (cdr) || isnan (cdi))
return runtime_fastrand1 (); return runtime_fastrand1 ();
/* Avoid negative zero. */ /* Avoid negative zero. */
if (cdr == 0 && cdi == 0) if (cdr == 0 && cdi == 0)
return 0; return 0;
else if (cdr == 0) else if (cdr == 0)
ucd.cd = cdi * 1.0i; cd = cdi * I;
else if (cdi == 0) else if (cdi == 0)
ucd.cd = cdr; cd = cdr;
return ucd.adi[0] ^ ucd.adi[1]; memcpy (&di, &cd, 16);
return di[0] ^ di[1];
} }
else else
runtime_throw ("__go_type_hash_complex: invalid complex size"); runtime_throw ("__go_type_hash_complex: invalid complex size");
@ -93,35 +91,23 @@ __go_type_equal_complex (const void *vk1, const void *vk2, uintptr_t key_size)
{ {
if (key_size == 8) if (key_size == 8)
{ {
union const complex float *cfp1;
{ const complex float *cfp2;
unsigned char a[8];
__complex float cf; cfp1 = (const complex float *) vk1;
} ucf; cfp2 = (const complex float *) vk2;
__complex float cf1;
__complex float cf2;
__builtin_memcpy (ucf.a, vk1, 8); return *cfp1 == *cfp2;
cf1 = ucf.cf;
__builtin_memcpy (ucf.a, vk2, 8);
cf2 = ucf.cf;
return cf1 == cf2;
} }
else if (key_size == 16) else if (key_size == 16)
{ {
union const complex double *cdp1;
{ const complex double *cdp2;
unsigned char a[16];
__complex double cd; cdp1 = (const complex double *) vk1;
} ucd; cdp2 = (const complex double *) vk2;
__complex double cd1;
__complex double cd2;
__builtin_memcpy (ucd.a, vk1, 16); return *cdp1 == *cdp2;
cd1 = ucd.cd;
__builtin_memcpy (ucd.a, vk2, 16);
cd2 = ucd.cd;
return cd1 == cd2;
} }
else else
runtime_throw ("__go_type_equal_complex: invalid complex size"); runtime_throw ("__go_type_equal_complex: invalid complex size");

View File

@ -4,14 +4,11 @@
Use of this source code is governed by a BSD-style Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */ license that can be found in the LICENSE file. */
#include <math.h>
#include <stdint.h>
#include "runtime.h" #include "runtime.h"
#include "go-type.h" #include "go-type.h"
/* The 32-bit and 64-bit types. */
typedef unsigned int SItype __attribute__ ((mode (SI)));
typedef unsigned int DItype __attribute__ ((mode (DI)));
/* Hash function for float types. */ /* Hash function for float types. */
uintptr_t uintptr_t
@ -19,45 +16,41 @@ __go_type_hash_float (const void *vkey, uintptr_t key_size)
{ {
if (key_size == 4) if (key_size == 4)
{ {
union const float *fp;
{
unsigned char a[4];
float f;
SItype si;
} uf;
float f; float f;
uint32_t si;
__builtin_memcpy (uf.a, vkey, 4); fp = (const float *) vkey;
f = uf.f; f = *fp;
if (__builtin_isinff (f) || f == 0)
if (isinf (f) || f == 0)
return 0; return 0;
/* NaN != NaN, so the hash code of a NaN is irrelevant. Make it /* NaN != NaN, so the hash code of a NaN is irrelevant. Make it
random so that not all NaNs wind up in the same place. */ random so that not all NaNs wind up in the same place. */
if (__builtin_isnanf (f)) if (isnan (f))
return runtime_fastrand1 (); return runtime_fastrand1 ();
return (uintptr_t) uf.si; memcpy (&si, vkey, 4);
return (uintptr_t) si;
} }
else if (key_size == 8) else if (key_size == 8)
{ {
union const double *dp;
{
unsigned char a[8];
double d;
DItype di;
} ud;
double d; double d;
uint64_t di;
__builtin_memcpy (ud.a, vkey, 8); dp = (const double *) vkey;
d = ud.d; d = *dp;
if (__builtin_isinf (d) || d == 0)
if (isinf (d) || d == 0)
return 0; return 0;
if (__builtin_isnan (d)) if (isnan (d))
return runtime_fastrand1 (); return runtime_fastrand1 ();
return (uintptr_t) ud.di; memcpy (&di, vkey, 8);
return (uintptr_t) di;
} }
else else
runtime_throw ("__go_type_hash_float: invalid float size"); runtime_throw ("__go_type_hash_float: invalid float size");
@ -70,36 +63,23 @@ __go_type_equal_float (const void *vk1, const void *vk2, uintptr_t key_size)
{ {
if (key_size == 4) if (key_size == 4)
{ {
union const float *fp1;
{ const float *fp2;
unsigned char a[4];
float f;
} uf;
float f1;
float f2;
__builtin_memcpy (uf.a, vk1, 4); fp1 = (const float *) vk1;
f1 = uf.f; fp2 = (const float *) vk2;
__builtin_memcpy (uf.a, vk2, 4);
f2 = uf.f; return *fp1 == *fp2;
return f1 == f2;
} }
else if (key_size == 8) else if (key_size == 8)
{ {
union const double *dp1;
{ const double *dp2;
unsigned char a[8];
double d;
DItype di;
} ud;
double d1;
double d2;
__builtin_memcpy (ud.a, vk1, 8); dp1 = (const double *) vk1;
d1 = ud.d; dp2 = (const double *) vk2;
__builtin_memcpy (ud.a, vk2, 8);
d2 = ud.d; return *dp1 == *dp2;
return d1 == d2;
} }
else else
runtime_throw ("__go_type_equal_float: invalid float size"); runtime_throw ("__go_type_equal_float: invalid float size");

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include <complex.h>
#include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include "runtime.h" #include "runtime.h"
#include "array.h" #include "array.h"
@ -105,7 +107,7 @@ go_vprintf(const char *s, va_list va)
runtime_printfloat(va_arg(va, float64)); runtime_printfloat(va_arg(va, float64));
break; break;
case 'C': case 'C':
runtime_printcomplex(va_arg(va, __complex double)); runtime_printcomplex(va_arg(va, complex double));
break; break;
case 'i': case 'i':
runtime_printiface(va_arg(va, Iface)); runtime_printiface(va_arg(va, Iface));
@ -174,13 +176,12 @@ runtime_printfloat(double v)
gwrite("NaN", 3); gwrite("NaN", 3);
return; return;
} }
i = __builtin_isinf_sign(v); if(isinf(v)) {
if(i > 0) { if(signbit(v)) {
gwrite("+Inf", 4); gwrite("-Inf", 4);
return; } else {
} gwrite("+Inf", 4);
if(i < 0) { }
gwrite("-Inf", 4);
return; return;
} }
@ -243,11 +244,11 @@ runtime_printfloat(double v)
} }
void void
runtime_printcomplex(__complex double v) runtime_printcomplex(complex double v)
{ {
gwrite("(", 1); gwrite("(", 1);
runtime_printfloat(__builtin_creal(v)); runtime_printfloat(creal(v));
runtime_printfloat(__builtin_cimag(v)); runtime_printfloat(cimag(v));
gwrite("i)", 2); gwrite("i)", 2);
} }

View File

@ -5,6 +5,7 @@
#include "config.h" #include "config.h"
#include "go-assert.h" #include "go-assert.h"
#include <complex.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -710,7 +711,7 @@ void runtime_printpointer(void*);
void runtime_printuint(uint64); void runtime_printuint(uint64);
void runtime_printhex(uint64); void runtime_printhex(uint64);
void runtime_printslice(Slice); void runtime_printslice(Slice);
void runtime_printcomplex(__complex double); void runtime_printcomplex(complex double);
void reflect_call(const struct __go_func_type *, FuncVal *, _Bool, _Bool, void reflect_call(const struct __go_func_type *, FuncVal *, _Bool, _Bool,
void **, void **) void **, void **)
__asm__ (GOSYM_PREFIX "reflect.call"); __asm__ (GOSYM_PREFIX "reflect.call");