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; +}