From: Shenghou Ma Date: Thu, 30 Apr 2015 23:03:31 +0000 (-0400) Subject: runtime: fix software FP regs corruption when emulating SQRT on ARM X-Git-Tag: go1.5beta1~753 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=102436e800d161dfd8b884278d1ddc5101f562dd;p=gostls13.git runtime: fix software FP regs corruption when emulating SQRT on ARM When emulating ARM FSQRT instruction, the sqrt function itself should not use any floating point arithmetics, otherwise it will clobber the user software FP registers. Fortunately, the sqrt function only uses floating point instructions to test for corner cases, so it's easy to make that function does all it job using pure integer arithmetic only. I've verified that after this change, runtime.stepflt and runtime.sqrt doesn't contain any call to _sfloat. (Perhaps we should add //go:nosfloat to make the compiler enforce this?) Fixes #10641. Change-Id: Ida4742c49000fae4fea4649f28afde630ce4c576 Signed-off-by: Shenghou Ma Reviewed-on: https://go-review.googlesource.com/9570 Reviewed-by: Dave Cheney Reviewed-by: Keith Randall --- diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 1b5f267b8b..e0c8b17bd3 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -17,6 +17,7 @@ var F32to64 = f32to64 var Fcmp64 = fcmp64 var Fintto64 = fintto64 var F64toint = f64toint +var Sqrt = sqrt var Entersyscall = entersyscall var Exitsyscall = exitsyscall diff --git a/src/runtime/softfloat_arm.go b/src/runtime/softfloat_arm.go index 8f184ccf3b..4e97e13f1a 100644 --- a/src/runtime/softfloat_arm.go +++ b/src/runtime/softfloat_arm.go @@ -437,8 +437,7 @@ stage3: // regd, regm are 4bit variables break case 0xeeb10bc0: // D[regd] = sqrt D[regm] - uval = float64bits(sqrt(float64frombits(fgetd(regm)))) - fputd(regd, uval) + fputd(regd, sqrt(fgetd(regm))) if fptrace > 0 { print("*** D[", regd, "] = sqrt D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n") diff --git a/src/runtime/sqrt.go b/src/runtime/sqrt.go index d483f8a01f..7452a61f3c 100644 --- a/src/runtime/sqrt.go +++ b/src/runtime/sqrt.go @@ -3,11 +3,12 @@ // license that can be found in the LICENSE file. // Copy of math/sqrt.go, here for use by ARM softfloat. +// Modified to not use any floating point arithmetic so +// that we don't clobber any floating-point registers +// while emulating the sqrt instruction. package runtime -import "unsafe" - // The original C code and the long comment below are // from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and // came with this notice. The go code is a simplified @@ -89,21 +90,30 @@ const ( float64Mask = 0x7FF float64Shift = 64 - 11 - 1 float64Bias = 1023 + float64NaN = 0x7FF8000000000001 + float64Inf = 0x7FF0000000000000 maxFloat64 = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52 ) -func float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) } -func float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) } +// isnanu returns whether ix represents a NaN floating point number. +func isnanu(ix uint64) bool { + exp := (ix >> float64Shift) & float64Mask + sig := ix << (64 - float64Shift) >> (64 - float64Shift) + return exp == float64Mask && sig != 0 +} -func sqrt(x float64) float64 { +func sqrt(ix uint64) uint64 { // special cases switch { - case x == 0 || x != x || x > maxFloat64: - return x - case x < 0: - return nan() + case ix == 0 || ix == 1<<63: // x == 0 + return ix + case isnanu(ix): // x != x + return ix + case ix&(1<<63) != 0: // x < 0 + return float64NaN + case ix == float64Inf: // x > MaxFloat + return ix } - ix := float64bits(x) // normalize x exp := int((ix >> float64Shift) & float64Mask) if exp == 0 { // subnormal x @@ -139,5 +149,5 @@ func sqrt(x float64) float64 { q += q & 1 // round according to extra bit } ix = q>>1 + uint64(exp-1+float64Bias)<