runtime: fix uint64->float32 conversion for softfloat

The fix for #48807 in CL 354429 forgot that we also need to fix
the softfloat implementation.

Update #48807

Change-Id: I596fb4e14e78145d1ad43c130b2cc5122b73655c
Reviewed-on: https://go-review.googlesource.com/c/go/+/354613
Trust: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
diff --git a/src/cmd/compile/internal/test/ssa_test.go b/src/cmd/compile/internal/test/ssa_test.go
index 2f3e24c..af7d962 100644
--- a/src/cmd/compile/internal/test/ssa_test.go
+++ b/src/cmd/compile/internal/test/ssa_test.go
@@ -162,7 +162,7 @@
 	}
 
 	flags := []string{""}
-	if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" {
+	if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" || runtime.GOARCH == "386" {
 		flags = append(flags, ",softfloat")
 	}
 	for _, flag := range flags {
diff --git a/src/runtime/softfloat64.go b/src/runtime/softfloat64.go
index 084aa13..42ef009 100644
--- a/src/runtime/softfloat64.go
+++ b/src/runtime/softfloat64.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Software IEEE754 64-bit floating point.
-// Only referred to (and thus linked in) by arm port
+// Only referred to (and thus linked in) by softfloat targets
 // and by tests in this directory.
 
 package runtime
@@ -414,6 +414,25 @@
 	}
 	return fpack64(fs, mant, int(mantbits64), 0)
 }
+func fintto32(val int64) (f uint32) {
+	fs := uint64(val) & (1 << 63)
+	mant := uint64(val)
+	if fs != 0 {
+		mant = -mant
+	}
+	// Reduce mantissa size until it fits into a uint32.
+	// Keep track of the bits we throw away, and if any are
+	// nonzero or them into the lowest bit.
+	exp := int(mantbits32)
+	var trunc uint32
+	for mant >= 1<<32 {
+		trunc |= uint32(mant) & 1
+		mant >>= 1
+		exp++
+	}
+
+	return fpack32(uint32(fs>>32), uint32(mant), exp, trunc)
+}
 
 // 64x64 -> 128 multiply.
 // adapted from hacker's delight.
@@ -493,6 +512,7 @@
 }
 
 func fdiv32(x, y uint32) uint32 {
+	// TODO: are there double-rounding problems here? See issue 48807.
 	return f64to32(fdiv64(f32to64(x), f32to64(y)))
 }
 
@@ -527,7 +547,7 @@
 }
 
 func fint32to32(x int32) uint32 {
-	return f64to32(fintto64(int64(x)))
+	return fintto32(int64(x))
 }
 
 func fint32to64(x int32) uint64 {
@@ -535,7 +555,7 @@
 }
 
 func fint64to32(x int64) uint32 {
-	return f64to32(fintto64(x))
+	return fintto32(x)
 }
 
 func fint64to64(x int64) uint64 {
@@ -595,5 +615,13 @@
 }
 
 func fuint64to32(x uint64) uint32 {
-	return f64to32(fuint64to64(x))
+	if int64(x) >= 0 {
+		return fint64to32(int64(x))
+	}
+	// See ../cmd/compile/internal/ssagen/ssa.go:uint64Tofloat
+	y := x & 1
+	z := x >> 1
+	z = z | y
+	r := fint64to32(int64(z))
+	return fadd32(r, r)
 }