diff mbox

libgo patch committed: Make libgo C code more portable

Message ID mcr7g557b43.fsf@iant-glaptop.roam.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor May 28, 2014, 11:10 p.m. UTC
This patch to libgo, from Peter Collingbourne, changes some of the C
code to make it easier to compile libgo with a compiler other than GCC.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian

Comments

Rainer Orth June 3, 2014, 10:49 a.m. UTC | #1
Ian Lance Taylor <iant@google.com> writes:

> This patch to libgo, from Peter Collingbourne, changes some of the C
> code to make it easier to compile libgo with a compiler other than GCC.
> Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
> Committed to mainline.
[...]
> diff -r d73f07d002ef libgo/runtime/print.c
> --- a/libgo/runtime/print.c	Tue May 27 15:00:31 2014 -0700
> +++ b/libgo/runtime/print.c	Wed May 28 16:09:25 2014 -0700
> @@ -2,6 +2,8 @@
>  // Use of this source code is governed by a BSD-style
>  // license that can be found in the LICENSE file.
>  
> +#include <complex.h>
> +#include <math.h>
>  #include <stdarg.h>
>  #include "runtime.h"
>  #include "array.h"
> @@ -174,13 +176,12 @@
>  		gwrite("NaN", 3);
>  		return;
>  	}
> -	i = __builtin_isinf_sign(v);
> -	if(i > 0) {
> -		gwrite("+Inf", 4);
> -		return;
> -	}
> -	if(i < 0) {
> -		gwrite("-Inf", 4);
> +	if(isinf(v)) {
> +		if(signbit(v)) {
> +			gwrite("-Inf", 4);
> +		} else {
> +			gwrite("+Inf", 4);
> +		}
>  		return;
>  	}
>  

This change broke Solaris Go bootstrap:

/vol/gcc/src/hg/trunk/local/libgo/runtime/print.c: In function '__go_print_double':
/vol/gcc/src/hg/trunk/local/libgo/runtime/print.c:200:3: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
   if(signbit(v)) {
   ^
cc1: all warnings being treated as errors
make: *** [print.lo] Error 1

It's an issue in the gcc version of signbit in <iso/math_c99.h>,
ultimately:

#undef	signbit
#if defined(__sparc)
#define	signbit(x)	__extension__( \
			{ __typeof(x) __x_s = (x); \
			(int) (*(unsigned *) &__x_s >> 31); })
#elif defined(__i386) || defined(__amd64)
#define	signbit(x)	__extension__( \
			{ __typeof(x) __x_s = (x); \
			(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)); })
#endif

Solaris lacks __signbit{f,,l} in libm, like some other Unices do, and
cannot use __builtin_signbit since that is missing in gcc 3.4 still
bundled with Solaris 10 and 11.  I'll probably go for handling this in
fixincludes on mainline, though, where the gcc 3 issue is irrelevant.

	Rainer
diff mbox

Patch

diff -r d73f07d002ef libgo/runtime/go-cdiv.c
--- a/libgo/runtime/go-cdiv.c	Tue May 27 15:00:31 2014 -0700
+++ b/libgo/runtime/go-cdiv.c	Wed May 28 16:09:25 2014 -0700
@@ -4,6 +4,9 @@ 
    Use of this source code is governed by a BSD-style
    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
    division of complex64 or complex128.  We use these because Go's
    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
    to result in NaN, not Inf.  */
 
-__complex float
-__go_complex64_div (__complex float a, __complex float b)
+complex float
+__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)
-	  && !__builtin_isinff (__imag__ a)
-	  && (__builtin_isnanf (__real__ a) || __builtin_isnanf (__imag__ a)))
+      if (!isinf (crealf (a))
+	  && !isinf (cimagf (a))
+	  && (isnan (crealf (a)) || isnan (cimagf (a))))
 	{
 	  /* 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;
 }
 
-__complex double
-__go_complex128_div (__complex double a, __complex double b)
+complex double
+__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)
-	  && !__builtin_isinf (__imag__ a)
-	  && (__builtin_isnan (__real__ a) || __builtin_isnan (__imag__ a)))
+      if (!isinf (creal (a))
+	  && !isinf (cimag (a))
+	  && (isnan (creal (a)) || isnan (cimag (a))))
 	{
 	  /* 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;
diff -r d73f07d002ef libgo/runtime/go-type-complex.c
--- a/libgo/runtime/go-type-complex.c	Tue May 27 15:00:31 2014 -0700
+++ b/libgo/runtime/go-type-complex.c	Wed May 28 16:09:25 2014 -0700
@@ -4,13 +4,13 @@ 
    Use of this source code is governed by a BSD-style
    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 "go-type.h"
 
-/* The 64-bit type.  */
-
-typedef unsigned int DItype __attribute__ ((mode (DI)));
-
 /* Hash function for float types.  */
 
 uintptr_t
@@ -18,69 +18,67 @@ 
 {
   if (key_size == 8)
     {
-      union
-      {
-	unsigned char a[8];
-	__complex float cf;
-	DItype di;
-      } ucf;
-      __complex float cf;
+      const complex float *cfp;
+      complex float cf;
       float cfr;
       float cfi;
+      uint64_t fi;
 
-      __builtin_memcpy (ucf.a, vkey, 8);
-      cf = ucf.cf;
-      cfr = __builtin_crealf (cf);
-      cfi = __builtin_cimagf (cf);
-      if (__builtin_isinff (cfr) || __builtin_isinff (cfi))
+      cfp = (const complex float *) vkey;
+      cf = *cfp;
+
+      cfr = crealf (cf);
+      cfi = cimagf (cf);
+
+      if (isinf (cfr) || isinf (cfi))
 	return 0;
 
       /* 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.  */
-      if (__builtin_isnanf (cfr) || __builtin_isnanf (cfi))
+      if (isnan (cfr) || isnan (cfi))
 	return runtime_fastrand1 ();
 
       /* Avoid negative zero.  */
       if (cfr == 0 && cfi == 0)
 	return 0;
       else if (cfr == 0)
-	ucf.cf = cfi * 1.0iF;
+	cf = cfi * I;
       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)
     {
-      union
-      {
-	unsigned char a[16];
-	__complex double cd;
-	DItype adi[2];
-      } ucd;
-      __complex double cd;
+      const complex double *cdp;
+      complex double cd;
       double cdr;
       double cdi;
+      uint64_t di[2];
 
-      __builtin_memcpy (ucd.a, vkey, 16);
-      cd = ucd.cd;
-      cdr = __builtin_crealf (cd);
-      cdi = __builtin_cimagf (cd);
-      if (__builtin_isinf (cdr) || __builtin_isinf (cdi))
+      cdp = (const complex double *) vkey;
+      cd = *cdp;
+
+      cdr = creal (cd);
+      cdi = cimag (cd);
+
+      if (isinf (cdr) || isinf (cdi))
 	return 0;
 
-      if (__builtin_isnan (cdr) || __builtin_isnan (cdi))
+      if (isnan (cdr) || isnan (cdi))
 	return runtime_fastrand1 ();
 
       /* Avoid negative zero.  */
       if (cdr == 0 && cdi == 0)
 	return 0;
       else if (cdr == 0)
-	ucd.cd = cdi * 1.0i;
+	cd = cdi * I;
       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
     runtime_throw ("__go_type_hash_complex: invalid complex size");
@@ -93,35 +91,23 @@ 
 {
   if (key_size == 8)
     {
-      union
-      {
-	unsigned char a[8];
-	__complex float cf;
-      } ucf;
-      __complex float cf1;
-      __complex float cf2;
+      const complex float *cfp1;
+      const complex float *cfp2;
+      
+      cfp1 = (const complex float *) vk1;
+      cfp2 = (const complex float *) vk2;
 
-      __builtin_memcpy (ucf.a, vk1, 8);
-      cf1 = ucf.cf;
-      __builtin_memcpy (ucf.a, vk2, 8);
-      cf2 = ucf.cf;
-      return cf1 == cf2;
+      return *cfp1 == *cfp2;
     }
   else if (key_size == 16)
     {
-      union
-      {
-	unsigned char a[16];
-	__complex double cd;
-      } ucd;
-      __complex double cd1;
-      __complex double cd2;
+      const complex double *cdp1;
+      const complex double *cdp2;
+      
+      cdp1 = (const complex double *) vk1;
+      cdp2 = (const complex double *) vk2;
 
-      __builtin_memcpy (ucd.a, vk1, 16);
-      cd1 = ucd.cd;
-      __builtin_memcpy (ucd.a, vk2, 16);
-      cd2 = ucd.cd;
-      return cd1 == cd2;
+      return *cdp1 == *cdp2;
     }
   else
     runtime_throw ("__go_type_equal_complex: invalid complex size");
diff -r d73f07d002ef libgo/runtime/go-type-float.c
--- a/libgo/runtime/go-type-float.c	Tue May 27 15:00:31 2014 -0700
+++ b/libgo/runtime/go-type-float.c	Wed May 28 16:09:25 2014 -0700
@@ -4,14 +4,11 @@ 
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
+#include <math.h>
+#include <stdint.h>
 #include "runtime.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.  */
 
 uintptr_t
@@ -19,45 +16,41 @@ 
 {
   if (key_size == 4)
     {
-      union
-      {
-	unsigned char a[4];
-	float f;
-	SItype si;
-      } uf;
+      const float *fp;
       float f;
+      uint32_t si;
 
-      __builtin_memcpy (uf.a, vkey, 4);
-      f = uf.f;
-      if (__builtin_isinff (f) || f == 0)
+      fp = (const float *) vkey;
+      f = *fp;
+
+      if (isinf (f) || f == 0)
 	return 0;
 
       /* 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.  */
-      if (__builtin_isnanf (f))
+      if (isnan (f))
 	return runtime_fastrand1 ();
 
-      return (uintptr_t) uf.si;
+      memcpy (&si, vkey, 4);
+      return (uintptr_t) si;
     }
   else if (key_size == 8)
     {
-      union
-      {
-	unsigned char a[8];
-	double d;
-	DItype di;
-      } ud;
+      const double *dp;
       double d;
+      uint64_t di;
 
-      __builtin_memcpy (ud.a, vkey, 8);
-      d = ud.d;
-      if (__builtin_isinf (d) || d == 0)
+      dp = (const double *) vkey;
+      d = *dp;
+
+      if (isinf (d) || d == 0)
 	return 0;
 
-      if (__builtin_isnan (d))
+      if (isnan (d))
 	return runtime_fastrand1 ();
 
-      return (uintptr_t) ud.di;
+      memcpy (&di, vkey, 8);
+      return (uintptr_t) di;
     }
   else
     runtime_throw ("__go_type_hash_float: invalid float size");
@@ -70,36 +63,23 @@ 
 {
   if (key_size == 4)
     {
-      union
-      {
-	unsigned char a[4];
-	float f;
-      } uf;
-      float f1;
-      float f2;
+      const float *fp1;
+      const float *fp2;
 
-      __builtin_memcpy (uf.a, vk1, 4);
-      f1 = uf.f;
-      __builtin_memcpy (uf.a, vk2, 4);
-      f2 = uf.f;
-      return f1 == f2;
+      fp1 = (const float *) vk1;
+      fp2 = (const float *) vk2;
+
+      return *fp1 == *fp2;
     }
   else if (key_size == 8)
     {
-      union
-      {
-	unsigned char a[8];
-	double d;
-	DItype di;
-      } ud;
-      double d1;
-      double d2;
+      const double *dp1;
+      const double *dp2;
 
-      __builtin_memcpy (ud.a, vk1, 8);
-      d1 = ud.d;
-      __builtin_memcpy (ud.a, vk2, 8);
-      d2 = ud.d;
-      return d1 == d2;
+      dp1 = (const double *) vk1;
+      dp2 = (const double *) vk2;
+
+      return *dp1 == *dp2;
     }
   else
     runtime_throw ("__go_type_equal_float: invalid float size");
diff -r d73f07d002ef libgo/runtime/print.c
--- a/libgo/runtime/print.c	Tue May 27 15:00:31 2014 -0700
+++ b/libgo/runtime/print.c	Wed May 28 16:09:25 2014 -0700
@@ -2,6 +2,8 @@ 
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+#include <complex.h>
+#include <math.h>
 #include <stdarg.h>
 #include "runtime.h"
 #include "array.h"
@@ -105,7 +107,7 @@ 
 			runtime_printfloat(va_arg(va, float64));
 			break;
 		case 'C':
-			runtime_printcomplex(va_arg(va, __complex double));
+			runtime_printcomplex(va_arg(va, complex double));
 			break;
 		case 'i':
 			runtime_printiface(va_arg(va, Iface));
@@ -174,13 +176,12 @@ 
 		gwrite("NaN", 3);
 		return;
 	}
-	i = __builtin_isinf_sign(v);
-	if(i > 0) {
-		gwrite("+Inf", 4);
-		return;
-	}
-	if(i < 0) {
-		gwrite("-Inf", 4);
+	if(isinf(v)) {
+		if(signbit(v)) {
+			gwrite("-Inf", 4);
+		} else {
+			gwrite("+Inf", 4);
+		}
 		return;
 	}
 
@@ -243,11 +244,11 @@ 
 }
 
 void
-runtime_printcomplex(__complex double v)
+runtime_printcomplex(complex double v)
 {
 	gwrite("(", 1);
-	runtime_printfloat(__builtin_creal(v));
-	runtime_printfloat(__builtin_cimag(v));
+	runtime_printfloat(creal(v));
+	runtime_printfloat(cimag(v));
 	gwrite("i)", 2);
 }
 
diff -r d73f07d002ef libgo/runtime/runtime.h
--- a/libgo/runtime/runtime.h	Tue May 27 15:00:31 2014 -0700
+++ b/libgo/runtime/runtime.h	Wed May 28 16:09:25 2014 -0700
@@ -5,6 +5,7 @@ 
 #include "config.h"
 
 #include "go-assert.h"
+#include <complex.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -710,7 +711,7 @@ 
 void	runtime_printuint(uint64);
 void	runtime_printhex(uint64);
 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 **, void **)
   __asm__ (GOSYM_PREFIX "reflect.call");