From e80f6a4de1a35cab03e7e4d29e26015895ffe04f Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Thu, 23 Aug 2012 14:35:26 +0800 Subject: [PATCH] cmd/6g: fix float32/64->uint64 conversion CVTSS2SQ's rounding mode is controlled by the RC field of MXCSR; as we specifically need truncate semantic, we should use CVTTSS2SQ. Fixes #3804. R=rsc, r CC=golang-dev https://golang.org/cl/6352079 --- src/cmd/6g/gsubr.c | 4 +- test/fixedbugs/bug447.go | 105 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 test/fixedbugs/bug447.go diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index 2758304427a..0f75bd8a2b7 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -796,9 +796,9 @@ gmove(Node *f, Node *t) // algorithm is: // if small enough, use native float64 -> int64 conversion. // otherwise, subtract 2^63, convert, and add it back. - a = ACVTSS2SQ; + a = ACVTTSS2SQ; if(ft == TFLOAT64) - a = ACVTSD2SQ; + a = ACVTTSD2SQ; bignodes(); regalloc(&r1, types[ft], N); regalloc(&r2, types[tt], t); diff --git a/test/fixedbugs/bug447.go b/test/fixedbugs/bug447.go new file mode 100644 index 00000000000..a4c871bdbf6 --- /dev/null +++ b/test/fixedbugs/bug447.go @@ -0,0 +1,105 @@ +// runoutput + +// Copyright 2012 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. + +// Issue 3804 +// test all possible float -> integer conversions + +package main + +import ( + "bytes" + "fmt" + "strings" +) + +var ( + intWidths = []int{8, 16, 32, 64} // int%d and uint%d + floatWidths = []int{32, 64} // float%d +) + +func main() { + + var names, funcs bytes.Buffer + + for _, iWidth := range intWidths { + for _, typ := range []string{"int", "uint"} { + var segs bytes.Buffer + itype := fmt.Sprintf("%s%d", typ, iWidth) + names.WriteString("\ttest" + itype + ",\n") + for _, fWidth := range floatWidths { + ftype := fmt.Sprintf("float%d", fWidth) + seg := strings.Replace(testSegment, "$F", ftype, -1) + seg = strings.Replace(seg, "$I", itype, -1) + segs.WriteString(seg) + } + body := strings.Replace(testFunc, "$I", itype, -1) + if typ[0] == 'u' { + body = strings.Replace(body, "$TEST", " || i < 0", 1) + } else { + body = strings.Replace(body, "$TEST", "", 1) + } + body = strings.Replace(body, "$TESTSEGMENTS", segs.String(), 1) + funcs.WriteString(body) + } + } + + program = strings.Replace(program, "$NAMES", names.String(), 1) + program = strings.Replace(program, "$FUNCS", funcs.String(), 1) + fmt.Print(program) +} + +const testSegment = ` + f$F := $F(f) + if math.Abs(float64(f$F) - f) < 0.05 { + if v := $I(f$F); v != $I(i) { + fmt.Printf("$I($F(%f)) = %v, expected %v\n", f, v, i) + } + }` + +const testFunc = +`func test$I(f float64, i int64) { + if i != int64($I(i))$TEST { + return + } +$TESTSEGMENTS +} +` + +var program = +`package main + +import ( + "fmt" + "math" +) + +var tests = []struct { + f float64 + i int64 +}{ + {39.7, 39}, + {-39.7, -39}, + {258.6, 258}, + {-258.6, -258}, + {65538.9, 65538}, + {-65538.9, -65538}, + {4294967298.8, 4294967298}, + {-4294967298.8, -4294967298}, +} + +var funcs = []func(float64, int64){ +$NAMES +} + +$FUNCS +func main() { + for _, t := range tests { + for _, f := range funcs { + f(t.f, t.i) + } + } +} +`