compiler, runtime: Fix complex division of NaN / 0.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 9 Oct 2013 22:31:15 +0000 (22:31 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 9 Oct 2013 22:31:15 +0000 (22:31 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@203331 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/runtime.cc
gcc/go/gofrontend/runtime.def
libgo/Makefile.am
libgo/Makefile.in
libgo/runtime/go-cdiv.c [new file with mode: 0644]

index d5e3a67..9d59349 100644 (file)
@@ -5967,6 +5967,43 @@ Binary_expression::do_get_tree(Translate_context* context)
                                right);
     }
 
+  // For complex division Go wants slightly different results than the
+  // GCC library provides, so we have our own runtime routine.
+  if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL)
+    {
+      const char *name;
+      tree *pdecl;
+      Type* ctype;
+      static tree complex64_div_decl;
+      static tree complex128_div_decl;
+      switch (this->left_->type()->complex_type()->bits())
+       {
+       case 64:
+         name = "__go_complex64_div";
+         pdecl = &complex64_div_decl;
+         ctype = Type::lookup_complex_type("complex64");
+         break;
+       case 128:
+         name = "__go_complex128_div";
+         pdecl = &complex128_div_decl;
+         ctype = Type::lookup_complex_type("complex128");
+         break;
+       default:
+         go_unreachable();
+       }
+      Btype* cbtype = ctype->get_backend(gogo);
+      tree ctype_tree = type_to_tree(cbtype);
+      return Gogo::call_builtin(pdecl,
+                               this->location(),
+                               name,
+                               2,
+                               ctype_tree,
+                               ctype_tree,
+                               fold_convert_loc(gccloc, ctype_tree, left),
+                               type,
+                               fold_convert_loc(gccloc, ctype_tree, right));
+    }
+
   tree compute_type = excess_precision_type(type);
   if (compute_type != NULL_TREE)
     {
index ecc508d..3b0f188 100644 (file)
@@ -42,6 +42,8 @@ enum Runtime_function_type
   RFT_RUNE,
   // Go type float64, C type double.
   RFT_FLOAT64,
+  // Go type complex64, C type __complex float.
+  RFT_COMPLEX64,
   // Go type complex128, C type __complex double.
   RFT_COMPLEX128,
   // Go type string, C type struct __go_string.
@@ -126,6 +128,10 @@ runtime_function_type(Runtime_function_type bft)
          t = Type::lookup_float_type("float64");
          break;
 
+       case RFT_COMPLEX64:
+         t = Type::lookup_complex_type("complex64");
+         break;
+
        case RFT_COMPLEX128:
          t = Type::lookup_complex_type("complex128");
          break;
@@ -216,6 +222,7 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
     case RFT_UINTPTR:
     case RFT_RUNE:
     case RFT_FLOAT64:
+    case RFT_COMPLEX64:
     case RFT_COMPLEX128:
     case RFT_STRING:
     case RFT_POINTER:
index 0d3fd3c..a303a50 100644 (file)
@@ -68,6 +68,12 @@ DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__go_string_to_int_array",
               P1(STRING), R1(SLICE))
 
 
+// Complex division.
+DEF_GO_RUNTIME(COMPLEX64_DIV, "__go_complex64_div",
+              P2(COMPLEX64, COMPLEX64), R1(COMPLEX64))
+DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div",
+              P2(COMPLEX128, COMPLEX128), R1(COMPLEX128))
+
 // Make a slice.
 DEF_GO_RUNTIME(MAKESLICE1, "__go_make_slice1", P2(TYPE, UINTPTR), R1(SLICE))
 DEF_GO_RUNTIME(MAKESLICE2, "__go_make_slice2", P3(TYPE, UINTPTR, UINTPTR),
index c81c66c..957f23c 100644 (file)
@@ -424,6 +424,7 @@ runtime_files = \
        runtime/go-caller.c \
        runtime/go-callers.c \
        runtime/go-can-convert-interface.c \
+       runtime/go-cdiv.c \
        runtime/go-cgo.c \
        runtime/go-check-interface.c \
        runtime/go-construct-map.c \
index 9e31e8c..706a72e 100644 (file)
@@ -195,7 +195,7 @@ libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
 @LIBGO_IS_LINUX_TRUE@am__objects_5 = getncpu-linux.lo
 am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
        go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \
-       go-callers.lo go-can-convert-interface.lo go-cgo.lo \
+       go-callers.lo go-can-convert-interface.lo go-cdiv.lo go-cgo.lo \
        go-check-interface.lo go-construct-map.lo \
        go-convert-interface.lo go-copy.lo go-defer.lo \
        go-deferred-recover.lo go-eface-compare.lo \
@@ -757,6 +757,7 @@ runtime_files = \
        runtime/go-caller.c \
        runtime/go-callers.c \
        runtime/go-can-convert-interface.c \
+       runtime/go-cdiv.c \
        runtime/go-cgo.c \
        runtime/go-check-interface.c \
        runtime/go-construct-map.c \
@@ -2368,6 +2369,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-caller.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-callers.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-can-convert-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cdiv.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cgo.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-check-interface.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@
@@ -2554,6 +2556,13 @@ go-can-convert-interface.lo: runtime/go-can-convert-interface.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-can-convert-interface.lo `test -f 'runtime/go-can-convert-interface.c' || echo '$(srcdir)/'`runtime/go-can-convert-interface.c
 
+go-cdiv.lo: runtime/go-cdiv.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-cdiv.lo -MD -MP -MF $(DEPDIR)/go-cdiv.Tpo -c -o go-cdiv.lo `test -f 'runtime/go-cdiv.c' || echo '$(srcdir)/'`runtime/go-cdiv.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-cdiv.Tpo $(DEPDIR)/go-cdiv.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-cdiv.c' object='go-cdiv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-cdiv.lo `test -f 'runtime/go-cdiv.c' || echo '$(srcdir)/'`runtime/go-cdiv.c
+
 go-cgo.lo: runtime/go-cgo.c
 @am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-cgo.lo -MD -MP -MF $(DEPDIR)/go-cgo.Tpo -c -o go-cgo.lo `test -f 'runtime/go-cgo.c' || echo '$(srcdir)/'`runtime/go-cgo.c
 @am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-cgo.Tpo $(DEPDIR)/go-cgo.Plo
diff --git a/libgo/runtime/go-cdiv.c b/libgo/runtime/go-cdiv.c
new file mode 100644 (file)
index 0000000..0a81e45
--- /dev/null
@@ -0,0 +1,46 @@
+/* go-cdiv.c -- complex division routines
+
+   Copyright 2013 The Go Authors. All rights reserved.
+   Use of this source code is governed by a BSD-style
+   license that can be found in the LICENSE file.  */
+
+/* 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
+   default.  When dividing NaN+1.0i / 0+0i, Go expects NaN+NaNi but
+   GCC generates NaN+Infi.  NaN+Infi seems wrong seems the rules of
+   C99 Annex G specify that if either side of a complex number is Inf,
+   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)
+{
+  if (__builtin_expect (b == 0+0i, 0))
+    {
+      if (!__builtin_isinff (__real__ a)
+         && !__builtin_isinff (__imag__ a)
+         && (__builtin_isnanf (__real__ a) || __builtin_isnanf (__imag__ a)))
+       {
+         /* Pass "1" to nanf to match math/bits.go.  */
+         return __builtin_nanf("1") + __builtin_nanf("1")*1i;
+       }
+    }
+  return a / b;
+}
+
+__complex double
+__go_complex128_div (__complex double a, __complex double b)
+{
+  if (__builtin_expect (b == 0+0i, 0))
+    {
+      if (!__builtin_isinf (__real__ a)
+         && !__builtin_isinf (__imag__ a)
+         && (__builtin_isnan (__real__ a) || __builtin_isnan (__imag__ a)))
+       {
+         /* Pass "1" to nan to match math/bits.go.  */
+         return __builtin_nan("1") + __builtin_nan("1")*1i;
+       }
+    }
+  return a / b;
+}