compiler: defer to middle-end for complex division
Go used to use slightly different semantics than C99 for complex division, so we used runtime routines to handle the different. The gc compiler has changes its behavior to match C99, so changes ours as well. For golang/go#14644 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/274213
This commit is contained in:
parent
65af6bc9f8
commit
cd34d5f2c4
|
@ -1,4 +1,4 @@
|
|||
6b01f8cdc11d86bd98165c91d6ae101bcf6b9e1a
|
||||
5364d15082de77d2759a01f254208d4cb4f579e3
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -6979,27 +6979,6 @@ Binary_expression::do_get_backend(Translate_context* context)
|
|||
// been converted to a String_concat_expression in do_lower.
|
||||
go_assert(!left_type->is_string_type());
|
||||
|
||||
// For complex division Go might want slightly different results than the
|
||||
// backend implementation provides, so we have our own runtime routine.
|
||||
if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL)
|
||||
{
|
||||
Runtime::Function complex_code;
|
||||
switch (this->left_->type()->complex_type()->bits())
|
||||
{
|
||||
case 64:
|
||||
complex_code = Runtime::COMPLEX64_DIV;
|
||||
break;
|
||||
case 128:
|
||||
complex_code = Runtime::COMPLEX128_DIV;
|
||||
break;
|
||||
default:
|
||||
go_unreachable();
|
||||
}
|
||||
Expression* complex_div =
|
||||
Runtime::make_call(complex_code, loc, 2, this->left_, this->right_);
|
||||
return complex_div->get_backend(context);
|
||||
}
|
||||
|
||||
Bexpression* left = this->left_->get_backend(context);
|
||||
Bexpression* right = this->right_->get_backend(context);
|
||||
|
||||
|
|
|
@ -62,12 +62,6 @@ DEF_GO_RUNTIME(STRINGTOSLICERUNE, "runtime.stringtoslicerune",
|
|||
P2(POINTER, 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(MAKESLICE, "runtime.makeslice", P3(TYPE, INT, INT),
|
||||
R1(POINTER))
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Copyright 2010 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.
|
||||
|
||||
// gcc '-std=c99' cmplxdivide.c && a.out >cmplxdivide1.go
|
||||
// This C program generates the file cmplxdivide1.go. It uses the
|
||||
// output of the operations by C99 as the reference to check
|
||||
// the implementation of complex numbers in Go.
|
||||
// The generated file, cmplxdivide1.go, is compiled along
|
||||
// with the driver cmplxdivide.go (the names are confusing
|
||||
// and unimaginative) to run the actual test. This is done by
|
||||
// the usual test runner.
|
||||
//
|
||||
// The file cmplxdivide1.go is checked in to the repository, but
|
||||
// if it needs to be regenerated, compile and run this C program
|
||||
// like this:
|
||||
// gcc '-std=c99' cmplxdivide.c && a.out >cmplxdivide1.go
|
||||
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
|
@ -12,50 +23,63 @@
|
|||
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
double f[] = {
|
||||
0,
|
||||
1,
|
||||
-1,
|
||||
2,
|
||||
0.0,
|
||||
-0.0,
|
||||
1.0,
|
||||
-1.0,
|
||||
2.0,
|
||||
NAN,
|
||||
INFINITY,
|
||||
-INFINITY,
|
||||
};
|
||||
|
||||
char*
|
||||
fmt(double g)
|
||||
{
|
||||
char* fmt(double g) {
|
||||
static char buf[10][30];
|
||||
static int n;
|
||||
char *p;
|
||||
|
||||
|
||||
p = buf[n++];
|
||||
if(n == 10)
|
||||
if(n == 10) {
|
||||
n = 0;
|
||||
}
|
||||
|
||||
sprintf(p, "%g", g);
|
||||
if(strcmp(p, "-0") == 0)
|
||||
strcpy(p, "negzero");
|
||||
|
||||
if(strcmp(p, "0") == 0) {
|
||||
strcpy(p, "zero");
|
||||
return p;
|
||||
}
|
||||
|
||||
if(strcmp(p, "-0") == 0) {
|
||||
strcpy(p, "-zero");
|
||||
return p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
iscnan(double complex d)
|
||||
{
|
||||
return !isinf(creal(d)) && !isinf(cimag(d)) && (isnan(creal(d)) || isnan(cimag(d)));
|
||||
}
|
||||
|
||||
double complex zero; // attempt to hide zero division from gcc
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int main(void) {
|
||||
int i, j, k, l;
|
||||
double complex n, d, q;
|
||||
|
||||
|
||||
printf("// skip\n");
|
||||
printf("// # generated by cmplxdivide.c\n");
|
||||
printf("\n");
|
||||
printf("package main\n");
|
||||
printf("var tests = []Test{\n");
|
||||
printf("\n");
|
||||
printf("import \"math\"\n");
|
||||
printf("\n");
|
||||
printf("var (\n");
|
||||
printf("\tnan = math.NaN()\n");
|
||||
printf("\tinf = math.Inf(1)\n");
|
||||
printf("\tzero = 0.0\n");
|
||||
printf(")\n");
|
||||
printf("\n");
|
||||
printf("var tests = []struct {\n");
|
||||
printf("\tf, g complex128\n");
|
||||
printf("\tout complex128\n");
|
||||
printf("}{\n");
|
||||
|
||||
for(i=0; i<nelem(f); i++)
|
||||
for(j=0; j<nelem(f); j++)
|
||||
for(k=0; k<nelem(f); k++)
|
||||
|
@ -63,17 +87,8 @@ main(void)
|
|||
n = f[i] + f[j]*I;
|
||||
d = f[k] + f[l]*I;
|
||||
q = n/d;
|
||||
|
||||
// BUG FIX.
|
||||
// Gcc gets the wrong answer for NaN/0 unless both sides are NaN.
|
||||
// That is, it treats (NaN+NaN*I)/0 = NaN+NaN*I (a complex NaN)
|
||||
// but it then computes (1+NaN*I)/0 = Inf+NaN*I (a complex infinity).
|
||||
// Since both numerators are complex NaNs, it seems that the
|
||||
// results should agree in kind. Override the gcc computation in this case.
|
||||
if(iscnan(n) && d == 0)
|
||||
q = (NAN+NAN*I) / zero;
|
||||
|
||||
printf("\tTest{complex(%s, %s), complex(%s, %s), complex(%s, %s)},\n",
|
||||
printf("\t{complex(%s, %s), complex(%s, %s), complex(%s, %s)},\n",
|
||||
fmt(creal(n)), fmt(cimag(n)),
|
||||
fmt(creal(d)), fmt(cimag(d)),
|
||||
fmt(creal(q)), fmt(cimag(q)));
|
||||
|
|
|
@ -1,36 +1,29 @@
|
|||
// run cmplxdivide1.go
|
||||
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Copyright 2010 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.
|
||||
|
||||
// Driver for complex division table defined in cmplxdivide1.go
|
||||
// For details, see the comment at the top of cmplxdivide.c.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/cmplx"
|
||||
)
|
||||
|
||||
type Test struct {
|
||||
f, g complex128
|
||||
out complex128
|
||||
}
|
||||
|
||||
var nan = math.NaN()
|
||||
var inf = math.Inf(1)
|
||||
var negzero = math.Copysign(0, -1)
|
||||
|
||||
func calike(a, b complex128) bool {
|
||||
switch {
|
||||
case cmplx.IsInf(a) && cmplx.IsInf(b):
|
||||
return true
|
||||
case cmplx.IsNaN(a) && cmplx.IsNaN(b):
|
||||
return true
|
||||
if imag(a) != imag(b) && !(math.IsNaN(imag(a)) && math.IsNaN(imag(b))) {
|
||||
return false
|
||||
}
|
||||
return a == b
|
||||
|
||||
if real(a) != real(b) && !(math.IsNaN(real(a)) && math.IsNaN(real(b))) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -439,7 +439,6 @@ runtime_files = \
|
|||
runtime/go-assert.c \
|
||||
runtime/go-caller.c \
|
||||
runtime/go-callers.c \
|
||||
runtime/go-cdiv.c \
|
||||
runtime/go-cgo.c \
|
||||
runtime/go-construct-map.c \
|
||||
runtime/go-ffi.c \
|
||||
|
|
|
@ -240,12 +240,11 @@ am__objects_2 = $(am__objects_1)
|
|||
@LIBGO_IS_RTEMS_TRUE@am__objects_3 = \
|
||||
@LIBGO_IS_RTEMS_TRUE@ runtime/rtems-task-variable-add.lo
|
||||
am__objects_4 = runtime/aeshash.lo runtime/go-assert.lo \
|
||||
runtime/go-caller.lo runtime/go-callers.lo runtime/go-cdiv.lo \
|
||||
runtime/go-cgo.lo runtime/go-construct-map.lo \
|
||||
runtime/go-ffi.lo runtime/go-fieldtrack.lo \
|
||||
runtime/go-matherr.lo runtime/go-memclr.lo \
|
||||
runtime/go-memequal.lo runtime/go-nanotime.lo \
|
||||
runtime/go-now.lo runtime/go-nosys.lo \
|
||||
runtime/go-caller.lo runtime/go-callers.lo runtime/go-cgo.lo \
|
||||
runtime/go-construct-map.lo runtime/go-ffi.lo \
|
||||
runtime/go-fieldtrack.lo runtime/go-matherr.lo \
|
||||
runtime/go-memclr.lo runtime/go-memequal.lo \
|
||||
runtime/go-nanotime.lo runtime/go-now.lo runtime/go-nosys.lo \
|
||||
runtime/go-reflect-call.lo runtime/go-setenv.lo \
|
||||
runtime/go-signal.lo runtime/go-unsafe-pointer.lo \
|
||||
runtime/go-unsetenv.lo runtime/go-unwind.lo \
|
||||
|
@ -892,7 +891,6 @@ runtime_files = \
|
|||
runtime/go-assert.c \
|
||||
runtime/go-caller.c \
|
||||
runtime/go-callers.c \
|
||||
runtime/go-cdiv.c \
|
||||
runtime/go-cgo.c \
|
||||
runtime/go-construct-map.c \
|
||||
runtime/go-ffi.c \
|
||||
|
@ -1343,8 +1341,6 @@ runtime/go-caller.lo: runtime/$(am__dirstamp) \
|
|||
runtime/$(DEPDIR)/$(am__dirstamp)
|
||||
runtime/go-callers.lo: runtime/$(am__dirstamp) \
|
||||
runtime/$(DEPDIR)/$(am__dirstamp)
|
||||
runtime/go-cdiv.lo: runtime/$(am__dirstamp) \
|
||||
runtime/$(DEPDIR)/$(am__dirstamp)
|
||||
runtime/go-cgo.lo: runtime/$(am__dirstamp) \
|
||||
runtime/$(DEPDIR)/$(am__dirstamp)
|
||||
runtime/go-construct-map.lo: runtime/$(am__dirstamp) \
|
||||
|
@ -1417,7 +1413,6 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-assert.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-caller.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-callers.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-cdiv.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-cgo.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-construct-map.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-context.Plo@am__quote@
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/* 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. */
|
||||
|
||||
#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
|
||||
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, 0))
|
||||
{
|
||||
if (!isinf (crealf (a))
|
||||
&& !isinf (cimagf (a))
|
||||
&& (isnan (crealf (a)) || isnan (cimagf (a))))
|
||||
{
|
||||
/* Pass "1" to nanf to match math/bits.go. */
|
||||
return nanf("1") + nanf("1")*I;
|
||||
}
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
||||
complex double
|
||||
__go_complex128_div (complex double a, complex double b)
|
||||
{
|
||||
if (__builtin_expect (b == 0, 0))
|
||||
{
|
||||
if (!isinf (creal (a))
|
||||
&& !isinf (cimag (a))
|
||||
&& (isnan (creal (a)) || isnan (cimag (a))))
|
||||
{
|
||||
/* Pass "1" to nan to match math/bits.go. */
|
||||
return nan("1") + nan("1")*I;
|
||||
}
|
||||
}
|
||||
return a / b;
|
||||
}
|
Loading…
Reference in New Issue