4ad/go

test/64bit.go fails for sparc64 SSA backend

binarycrusader opened this issue · 6 comments

When SSA-built run via 'go run run.go -v 64bit.go', this test fails as follows (some output elided for brevity):

# go run run.go -- 64bit.go
exit status 1
int64 1 * 9223372036854765808 = 9223372036854765808 should be 274877896944
int64 1 * 9223372036854775807 = 9223372036854775807 should be 274877906943
int64 1 * 8690466096661279830 = 8690466096661279830 should be 132876743766
int64 1 * -1 = -1 should be 274877906943
int64 1 * -2 = -2 should be 274877906942
int64 1 * -3 = -3 should be 274877906941
int64 1 * -100 = -100 should be 274877906844
int64 1 * -10001 = -10001 should be 274877896943
int64 1 * -2147483647 = -2147483647 should be 272730423297
int64 1 * -2147483648 = -2147483648 should be 272730423296
int64 1 * -2147483649 = -2147483649 should be 272730423295
int64 1 * -3221225472 = -3221225472 should be 271656681472
int64 1 * -4294967296 = -4294967296 should be 270582939648
int64 1 * -4294967295 = -4294967295 should be 270582939649
int64 1 * -8589934592 = -8589934592 should be 266287972352
int64 1 * -9223372036854765808 = -9223372036854765808 should be 10000
int64 1 * -9223372036854775807 = -9223372036854775807 should be 1 
int64 1 * -9223372036854775808 = -9223372036854775808 should be 0 
int64 1 * -8690466088605830058 = -8690466088605830058 should be 150056612950
int64 1 << uint64 61 = 2305843009213693952 should be 0 
int64 1 << uint 61 = 2305843009213693952 should be 0 
int64 1 << uint32 61 = 2305843009213693952 should be 0 
int64 1 << uint16 61 = 2305843009213693952 should be 0 
int64 1 << uint8 61 = 2305843009213693952 should be 0 
int64 1 << uint64 62 = 4611686018427387904 should be 0 
int64 1 << uint 62 = 4611686018427387904 should be 0 
int64 1 << uint32 62 = 4611686018427387904 should be 0 
int64 1 << uint16 62 = 4611686018427387904 should be 0 
int64 1 << uint8 62 = 4611686018427387904 should be 0 
int64 1 << uint64 63 = -9223372036854775808 should be 0 
int64 1 << uint 63 = -9223372036854775808 should be 0 
int64 1 << uint32 63 = -9223372036854775808 should be 0 
int64 1 << uint16 63 = -9223372036854775808 should be 0 
int64 1 << uint8 63 = -9223372036854775808 should be 0 
int64 2 * 9223372036854765808 = -20000 should be 274877886944
...
exit status 1

FAIL    64bit.go        16.767s

It's likely that MULXHI/UMULXHI is still not correct.

Here's a reduced, minimal test case just for the first few failing multiplications:

package main

import "os"

var ok = true

func testInt64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot int64, dodiv bool) {
	if n, op, want := a*b, `*`, mul; n != want {
		ok = false
		println(`int64`, a, op, b, `=`, n, `should be`, want)
	}
}

func test1() {
	testInt64Binary(0x000000001, 0x7fffffffffffd8f0, 0x7fffffffffffd8f1, -0x7fffffffffffd8ef, 0x3fffffd8f0, 0x000000000, 0x000000001, 0x000000000, 0x7fffffffffffd8f1, 0x7fffffffffffd8f1, 0x000000001, true)
	testInt64Binary(0x000000001, 0x7fffffffffffffff, -0x8000000000000000, -0x7ffffffffffffffe, 0x3fffffffff, 0x000000000, 0x000000001, 0x000000001, 0x7fffffffffffffff, 0x7ffffffffffffffe, 0x000000000, true)
	testInt64Binary(0x000000001, 0x789abcdef0123456, 0x789abcdef0123457, -0x789abcdef0123455, 0x1ef0123456, 0x000000000, 0x000000001, 0x000000000, 0x789abcdef0123457, 0x789abcdef0123457, 0x000000001, true)
}
func main() {
	test1()
	if !ok {
		os.Exit(1)
	}
}

This can be cross-compiled and cross-linked on and amd64 system using:

SSATEST=1 GOSSAHASH="" GOOS=solaris GOARCH=sparc64 go tool compile test.go
GOOS=solaris GOARCH=sparc64 go tool link test.o

The binary can then be copied to (or accessed via NFS for convenience) a sparc64 system where the following output will be seen when executed:

int64 1 * 9223372036854765808 = 9223372036854765808 should be 274877896944
int64 1 * 9223372036854775807 = 9223372036854775807 should be 274877906943
int64 1 * 8690466096661279830 = 8690466096661279830 should be 132876743766

I just ran that example on https://play.golang.org and it also failed there... this test seems wrong to me; 1 * 9223372036854765808 is 9223372036854765808 which definitely can be represented as an int64.

My guess is that the program generating the test is failing.

The program generation being wrong seems right because many of the error messages didn't make any sense to me. I've filed all of these issues to track status, but thanks for taking a quick look.

Confirmed; the code generation is the issue. The differences between a known, good version and the bad one are (the numbers that are different here are for the 'mul' parameter to testInt64Binary, which is supposed to be the result of multiplying a*b):

--- good.go  2017-07-21 12:40:08.445035367 +0000
+++ bad.go   2017-07-21 12:40:08.447732819 +0000
@@ -16,7 +16,7 @@
         0x7fffffffffffd8f0,
         0x7fffffffffffd8f1,
         -0x7fffffffffffd8ef,
-        0x7fffffffffffd8f0,
+        0x3fffffd8f0,
         0x000000000,
         0x000000001,
         0x000000000,
@@ -28,7 +28,7 @@
         0x7fffffffffffffff,
         -0x8000000000000000,
         -0x7ffffffffffffffe,
-        0x7fffffffffffffff,
+        0x3fffffffff,
         0x000000000,
         0x000000001,
         0x000000001,
@@ -40,7 +40,7 @@
         0x789abcdef0123456,
         0x789abcdef0123457,
         -0x789abcdef0123455,
-        0x789abcdef0123456,
+        0x1ef0123456,
         0x000000000,
         0x000000001,
         0x000000000,

This turned out to be a register allocation / scheduling bug for SLLmax/SRLmax:

We can't safely write to the output register(s) until we're done referencing the input register(s) as they may be the same due to register allocation scheduling by the SSA backend.

As such, stash the second argument in a temporary register so that we can safely refer to it even after writing to the output register.

Fixed.