This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Go patch committed: Fix complex division of NaN / 0
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org, gofrontend-dev at googlegroups dot com
- Date: Wed, 09 Oct 2013 15:31:46 -0700
- Subject: Go patch committed: Fix complex division of NaN / 0
- Authentication-results: sourceware.org; auth=none
This patch to the Go frontend and libgo fixes complex division of NaN /
0. Go expects that to produce NaN. When using libgcc it could produce
Inf. Specifically NaN+1i / 0+0i produced NaN+Infi, which by the rules
of C99 Annex G is Inf. This may be correct for C, but it's not correct
for Go. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline. Will commit to 4.8 branch when it reopens.
Ian
diff -r c54f26ba8279 go/expressions.cc
--- a/go/expressions.cc Tue Oct 08 16:55:52 2013 -0700
+++ b/go/expressions.cc Wed Oct 09 15:17:14 2013 -0700
@@ -5967,6 +5967,43 @@
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)
{
diff -r c54f26ba8279 go/runtime.cc
--- a/go/runtime.cc Tue Oct 08 16:55:52 2013 -0700
+++ b/go/runtime.cc Wed Oct 09 15:17:14 2013 -0700
@@ -42,6 +42,8 @@
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 @@
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 @@
case RFT_UINTPTR:
case RFT_RUNE:
case RFT_FLOAT64:
+ case RFT_COMPLEX64:
case RFT_COMPLEX128:
case RFT_STRING:
case RFT_POINTER:
diff -r c54f26ba8279 go/runtime.def
--- a/go/runtime.def Tue Oct 08 16:55:52 2013 -0700
+++ b/go/runtime.def Wed Oct 09 15:17:14 2013 -0700
@@ -68,6 +68,12 @@
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),
diff -r c54f26ba8279 libgo/Makefile.am
--- a/libgo/Makefile.am Tue Oct 08 16:55:52 2013 -0700
+++ b/libgo/Makefile.am Wed Oct 09 15:17:14 2013 -0700
@@ -424,6 +424,7 @@
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 \
diff -r c54f26ba8279 libgo/runtime/go-cdiv.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-cdiv.c Wed Oct 09 15:17:14 2013 -0700
@@ -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;
+}