diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
commit | 43a123c1ae6613b3efeed291fa552ecd909d3acf (patch) | |
tree | fd92518b7024bc74031f78a1cf9e454b65e73665 /test/abi | |
parent | Initial commit. (diff) | |
download | golang-1.20-upstream.tar.xz golang-1.20-upstream.zip |
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test/abi')
55 files changed, 2014 insertions, 0 deletions
diff --git a/test/abi/bad_internal_offsets.go b/test/abi/bad_internal_offsets.go new file mode 100644 index 0000000..d396c1a --- /dev/null +++ b/test/abi/bad_internal_offsets.go @@ -0,0 +1,74 @@ +// compile + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +package genChecker0 + +var FailCount int + +//go:noinline +func NoteFailure(fidx int, pkg string, pref string, parmNo int, _ uint64) { + FailCount += 1 + if FailCount > 10 { + panic("bad") + } +} + +//go:noinline +func NoteFailureElem(fidx int, pkg string, pref string, parmNo int, elem int, _ uint64) { + FailCount += 1 + if FailCount > 10 { + panic("bad") + } +} + +type StructF0S0 struct { + F0 int16 + F1 string + F2 StructF0S1 +} + +type StructF0S1 struct { + _ uint16 +} + +// 0 returns 3 params +//go:registerparams +//go:noinline +func Test0(p0 uint32, p1 StructF0S0, p2 int32) { + // consume some stack space, so as to trigger morestack + var pad [256]uint64 + pad[FailCount]++ + if p0 == 0 { + return + } + p1f0c := int16(-3096) + if p1.F0 != p1f0c { + NoteFailureElem(0, "genChecker0", "parm", 1, 0, pad[0]) + return + } + p1f1c := "f6ꂅ8ˋ<" + if p1.F1 != p1f1c { + NoteFailureElem(0, "genChecker0", "parm", 1, 1, pad[0]) + return + } + p1f2c := StructF0S1{} + if p1.F2 != p1f2c { + NoteFailureElem(0, "genChecker0", "parm", 1, 2, pad[0]) + return + } + p2f0c := int32(496713155) + if p2 != p2f0c { + NoteFailureElem(0, "genChecker0", "parm", 2, 0, pad[0]) + return + } + // recursive call + Test0(p0-1, p1, p2) + return + // 0 addr-taken params, 0 addr-taken returns +} diff --git a/test/abi/bad_select_crash.go b/test/abi/bad_select_crash.go new file mode 100644 index 0000000..58ca463 --- /dev/null +++ b/test/abi/bad_select_crash.go @@ -0,0 +1,272 @@ +// build -goexperiment regabi,regabiargs + +// Copyright 2021 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. + +package main + +import ( + "fmt" + "os" + "reflect" +) + +func main() { + // Only print if there is a problem + Caller2() + if FailCount != 0 { + fmt.Fprintf(os.Stderr, "FAILURES: %d\n", FailCount) + os.Exit(2) + } +} + +var ParamFailCount int + +var ReturnFailCount int + +var FailCount int + +var Mode string + +type UtilsType int + +//go:noinline +func NoteFailure(cm int, pidx int, fidx int, pkg string, pref string, parmNo int, isret bool, _ uint64) { + if isret { + if ParamFailCount != 0 { + return + } + ReturnFailCount++ + } else { + ParamFailCount++ + } + fmt.Fprintf(os.Stderr, "Error: fail %s |%d|%d|%d| =%s.Test%d= %s %d\n", Mode, cm, pidx, fidx, pkg, fidx, pref, parmNo) + + if ParamFailCount+FailCount+ReturnFailCount > 9999 { + os.Exit(1) + } +} + +//go:noinline +func NoteFailureElem(cm int, pidx int, fidx int, pkg string, pref string, parmNo int, elem int, isret bool, _ uint64) { + + if isret { + if ParamFailCount != 0 { + return + } + ReturnFailCount++ + } else { + ParamFailCount++ + } + fmt.Fprintf(os.Stderr, "Error: fail %s |%d|%d|%d| =%s.Test%d= %s %d elem %d\n", Mode, cm, pidx, fidx, pkg, fidx, pref, parmNo, elem) + + if ParamFailCount+FailCount+ReturnFailCount > 9999 { + os.Exit(1) + } +} + +func BeginFcn() { + ParamFailCount = 0 + ReturnFailCount = 0 +} + +func EndFcn() { + FailCount += ParamFailCount + FailCount += ReturnFailCount +} + +func Caller2() { + BeginFcn() + c0 := StructF2S0{F0: ArrayF2S1E1{New_3(float64(-0.4418990509835844))}} + c1 := ArrayF2S2E1{StructF2S1{ /* _: "(z̽|" */ F1: ""}} + c2 := int16(4162) + c3 := float32(-7.667096e+37) + c4 := int64(3202175648847048679) + var p0 ArrayF2S0E0 + p0 = ArrayF2S0E0{} + var p1 uint8 + p1 = uint8(57) + var p2 uint16 + p2 = uint16(10920) + var p3 float64 + p3 = float64(-1.597256501942112) + Mode = "" + // 5 returns 4 params + r0, r1, r2, r3, r4 := Test2(p0, p1, p2, p3) + if !EqualStructF2S0(r0, c0) { + NoteFailure(9, 42, 2, "genChecker42", "return", 0, true, uint64(0)) + } + if r1 != c1 { + NoteFailure(9, 42, 2, "genChecker42", "return", 1, true, uint64(0)) + } + if r2 != c2 { + NoteFailure(9, 42, 2, "genChecker42", "return", 2, true, uint64(0)) + } + if r3 != c3 { + NoteFailure(9, 42, 2, "genChecker42", "return", 3, true, uint64(0)) + } + if r4 != c4 { + NoteFailure(9, 42, 2, "genChecker42", "return", 4, true, uint64(0)) + } + // same call via reflection + Mode = "reflect" + rc := reflect.ValueOf(Test2) + rvslice := rc.Call([]reflect.Value{reflect.ValueOf(p0), reflect.ValueOf(p1), reflect.ValueOf(p2), reflect.ValueOf(p3)}) + rr0i := rvslice[0].Interface() + rr0v := rr0i.(StructF2S0) + if !EqualStructF2S0(rr0v, c0) { + NoteFailure(9, 42, 2, "genChecker42", "return", 0, true, uint64(0)) + } + rr1i := rvslice[1].Interface() + rr1v := rr1i.(ArrayF2S2E1) + if rr1v != c1 { + NoteFailure(9, 42, 2, "genChecker42", "return", 1, true, uint64(0)) + } + rr2i := rvslice[2].Interface() + rr2v := rr2i.(int16) + if rr2v != c2 { + NoteFailure(9, 42, 2, "genChecker42", "return", 2, true, uint64(0)) + } + rr3i := rvslice[3].Interface() + rr3v := rr3i.(float32) + if rr3v != c3 { + NoteFailure(9, 42, 2, "genChecker42", "return", 3, true, uint64(0)) + } + rr4i := rvslice[4].Interface() + rr4v := rr4i.(int64) + if rr4v != c4 { + NoteFailure(9, 42, 2, "genChecker42", "return", 4, true, uint64(0)) + } + EndFcn() +} + +type StructF0S0 struct { +} + +type ArrayF0S0E2 [2]int16 + +type ArrayF0S1E1 [1]StructF0S0 + +type StructF1S0 struct { + F0 StructF1S1 + _ ArrayF1S0E4 +} + +type StructF1S1 struct { +} + +type StructF1S2 struct { + F0 uint32 + F1 uint8 + F2 string + F3 string + F4 ArrayF1S1E1 +} + +type StructF1S3 struct { + F0 float64 +} + +type StructF1S4 struct { + _ int32 + F1 float32 +} + +type StructF1S5 struct { + F0 uint16 +} + +type StructF1S6 struct { + F0 uint8 + F1 uint32 +} + +type ArrayF1S0E4 [4]float64 + +type ArrayF1S1E1 [1]StructF1S3 + +type ArrayF1S2E2 [2]StructF1S4 + +type ArrayF1S3E2 [2]StructF1S5 + +type ArrayF1S4E4 [4]ArrayF1S5E3 + +type ArrayF1S5E3 [3]string + +type ArrayF1S6E1 [1]float64 + +type StructF2S0 struct { + F0 ArrayF2S1E1 +} + +// equal func for StructF2S0 +//go:noinline +func EqualStructF2S0(left StructF2S0, right StructF2S0) bool { + return EqualArrayF2S1E1(left.F0, right.F0) +} + +type StructF2S1 struct { + _ string + F1 string +} + +type ArrayF2S0E0 [0]int8 + +type ArrayF2S1E1 [1]*float64 + +// equal func for ArrayF2S1E1 +//go:noinline +func EqualArrayF2S1E1(left ArrayF2S1E1, right ArrayF2S1E1) bool { + return *left[0] == *right[0] +} + +type ArrayF2S2E1 [1]StructF2S1 + +// 5 returns 4 params +//go:registerparams +//go:noinline +func Test2(p0 ArrayF2S0E0, p1 uint8, _ uint16, p3 float64) (r0 StructF2S0, r1 ArrayF2S2E1, r2 int16, r3 float32, r4 int64) { + // consume some stack space, so as to trigger morestack + var pad [16]uint64 + pad[FailCount&0x1]++ + rc0 := StructF2S0{F0: ArrayF2S1E1{New_3(float64(-0.4418990509835844))}} + rc1 := ArrayF2S2E1{StructF2S1{ /* _: "(z̽|" */ F1: ""}} + rc2 := int16(4162) + rc3 := float32(-7.667096e+37) + rc4 := int64(3202175648847048679) + p1f0c := uint8(57) + if p1 != p1f0c { + NoteFailureElem(9, 42, 2, "genChecker42", "parm", 1, 0, false, pad[0]) + return + } + _ = uint16(10920) + p3f0c := float64(-1.597256501942112) + if p3 != p3f0c { + NoteFailureElem(9, 42, 2, "genChecker42", "parm", 3, 0, false, pad[0]) + return + } + defer func(p0 ArrayF2S0E0, p1 uint8) { + // check parm passed + // check parm passed + if p1 != p1f0c { + NoteFailureElem(9, 42, 2, "genChecker42", "parm", 1, 0, false, pad[0]) + return + } + // check parm captured + if p3 != p3f0c { + NoteFailureElem(9, 42, 2, "genChecker42", "parm", 3, 0, false, pad[0]) + return + } + }(p0, p1) + + return rc0, rc1, rc2, rc3, rc4 + // 0 addr-taken params, 0 addr-taken returns +} + +//go:noinline +func New_3(i float64) *float64 { + x := new(float64) + *x = i + return x +} diff --git a/test/abi/convF_criteria.go b/test/abi/convF_criteria.go new file mode 100644 index 0000000..77ed56d --- /dev/null +++ b/test/abi/convF_criteria.go @@ -0,0 +1,27 @@ +// run + +// Copyright 2021 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. + +package main + +import "fmt" + +type myStruct struct { + F0 [0]struct{} + F1 float32 +} + +type myStruct2 struct { + F0 [0]struct{} + F1 float32 + F2 [0]struct{} +} + +func main() { + x := myStruct{F1: -1.25} + fmt.Println(x) + x2 := myStruct2{F1: -7.97} + fmt.Println(x2) +} diff --git a/test/abi/convF_criteria.out b/test/abi/convF_criteria.out new file mode 100644 index 0000000..457f0de --- /dev/null +++ b/test/abi/convF_criteria.out @@ -0,0 +1,2 @@ +{[] -1.25} +{[] -7.97 []} diff --git a/test/abi/convT64_criteria.go b/test/abi/convT64_criteria.go new file mode 100644 index 0000000..165bdfa --- /dev/null +++ b/test/abi/convT64_criteria.go @@ -0,0 +1,25 @@ +// run + +// Copyright 2021 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. + +package main + +import ( + "fmt" +) + +type MyStruct struct { + F0 [0]float64 + F1 byte + F2 int16 + _ struct { + F0 uint32 + } +} + +func main() { + p0 := MyStruct{F0: [0]float64{}, F1: byte(27), F2: int16(9887)} + fmt.Println(p0) +} diff --git a/test/abi/convT64_criteria.out b/test/abi/convT64_criteria.out new file mode 100644 index 0000000..8ac8571 --- /dev/null +++ b/test/abi/convT64_criteria.out @@ -0,0 +1 @@ +{[] 27 9887 {0}} diff --git a/test/abi/defer_aggregate.go b/test/abi/defer_aggregate.go new file mode 100644 index 0000000..6dd8282 --- /dev/null +++ b/test/abi/defer_aggregate.go @@ -0,0 +1,48 @@ +// run + +// Copyright 2021 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. + +package main + +const p0exp = "foo" +const p1exp = 10101 +const p2exp = 3030303 +const p3exp = 505050505 +const p4exp = 70707070707 + +//go:noinline +//go:registerparams +func callee(p0 string, p1 uint64, p2 uint64, p3 uint64, p4 uint64) { + if p0 != p0exp { + panic("bad p0") + } + if p1 != p1exp { + panic("bad p1") + } + if p2 != p2exp { + panic("bad p2") + } + if p3 != p3exp { + panic("bad p3") + } + if p4 != p4exp { + panic("bad p4") + } + defer func(p0 string, p2 uint64) { + if p0 != p0exp { + panic("defer bad p0") + } + if p1 != p1exp { + panic("defer bad p1") + } + if p2 != p2exp { + panic("defer bad p2") + } + }(p0, p2) +} + +func main() { + callee(p0exp, p1exp, p2exp, p3exp, p4exp) +} diff --git a/test/abi/defer_recover_results.go b/test/abi/defer_recover_results.go new file mode 100644 index 0000000..7787f26 --- /dev/null +++ b/test/abi/defer_recover_results.go @@ -0,0 +1,36 @@ +// run + +// Copyright 2021 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. + +// Test that when a function recovers from a panic, it +// returns the correct results to the caller (in particular, +// setting the result registers correctly). + +package main + +type S struct { + x uint8 + y uint16 + z uint32 + w float64 +} + +var a0, b0, c0, d0 = 10, "hello", S{1, 2, 3, 4}, [2]int{111, 222} + +//go:noinline +//go:registerparams +func F() (a int, b string, _ int, c S, d [2]int) { + a, b, c, d = a0, b0, c0, d0 + defer func() { recover() }() + panic("XXX") + return +} + +func main() { + a1, b1, zero, c1, d1 := F() + if a1 != a0 || b1 != b0 || c1 != c0 || d1 != d0 || zero != 0 { // unnamed result gets zero value + panic("FAIL") + } +} diff --git a/test/abi/double_nested_addressed_struct.go b/test/abi/double_nested_addressed_struct.go new file mode 100644 index 0000000..be7c88a --- /dev/null +++ b/test/abi/double_nested_addressed_struct.go @@ -0,0 +1,62 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink *string + +type stringPair struct { + a, b string +} + +type stringPairPair struct { + x, y stringPair +} + +// The goal of this test is to be sure that the call arg/result expander works correctly +// for a corner case of passing a 2-nested struct that fits in registers to/from calls. +// AND, the struct has its address taken. + +//go:registerparams +//go:noinline +func H(spp stringPairPair) string { + F(&spp) + return spp.x.a + " " + spp.x.b + " " + spp.y.a + " " + spp.y.b +} + +//go:registerparams +//go:noinline +func G(d, c, b, a string) stringPairPair { + return stringPairPair{stringPair{a, b}, stringPair{c, d}} +} + +//go:registerparams +//go:noinline +func F(spp *stringPairPair) { + spp.x.a, spp.x.b, spp.y.a, spp.y.b = spp.y.b, spp.y.a, spp.x.b, spp.x.a +} + +func main() { + spp := G("this", "is", "a", "test") + s := H(spp) + gotVsWant(s, "this is a test") +} + +func gotVsWant(got, want string) { + if got != want { + fmt.Printf("FAIL, got %s, wanted %s\n", got, want) + } +} diff --git a/test/abi/double_nested_struct.go b/test/abi/double_nested_struct.go new file mode 100644 index 0000000..814341e --- /dev/null +++ b/test/abi/double_nested_struct.go @@ -0,0 +1,54 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink *string + +type stringPair struct { + a, b string +} + +type stringPairPair struct { + x, y stringPair +} + +// The goal of this test is to be sure that the call arg/result expander works correctly +// for a corner case of passing a 2-nested struct that fits in registers to/from calls. + +//go:registerparams +//go:noinline +func H(spp stringPairPair) string { + return spp.x.a + " " + spp.x.b + " " + spp.y.a + " " + spp.y.b +} + +//go:registerparams +//go:noinline +func G(a, b, c, d string) stringPairPair { + return stringPairPair{stringPair{a, b}, stringPair{c, d}} +} + +func main() { + spp := G("this", "is", "a", "test") + s := H(spp) + gotVsWant(s, "this is a test") +} + +func gotVsWant(got, want string) { + if got != want { + fmt.Printf("FAIL, got %s, wanted %s\n", got, want) + } +} diff --git a/test/abi/f_ret_z_not.go b/test/abi/f_ret_z_not.go new file mode 100644 index 0000000..63d6c79 --- /dev/null +++ b/test/abi/f_ret_z_not.go @@ -0,0 +1,39 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import "fmt" + +type Z struct { +} + +type NZ struct { + x, y int +} + +//go:noinline +func f(x, y int) (Z, NZ, Z) { + var z Z + return z, NZ{x, y}, z +} + +//go:noinline +func g() (Z, NZ, Z) { + a, b, c := f(3, 4) + return c, b, a +} + +func main() { + _, b, _ := g() + fmt.Println(b.x + b.y) +} diff --git a/test/abi/f_ret_z_not.out b/test/abi/f_ret_z_not.out new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/test/abi/f_ret_z_not.out @@ -0,0 +1 @@ +7 diff --git a/test/abi/fibish.go b/test/abi/fibish.go new file mode 100644 index 0000000..b72f132 --- /dev/null +++ b/test/abi/fibish.go @@ -0,0 +1,33 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +package main + +import "fmt" + +// Test that register results are correctly returned (and passed) + +//go:registerparams +//go:noinline +func f(x int) (int, int) { + + if x < 3 { + return 0, x + } + + a, b := f(x - 2) + c, d := f(x - 1) + return a + d, b + c +} + +func main() { + x := 40 + a, b := f(x) + fmt.Printf("f(%d)=%d,%d\n", x, a, b) +} diff --git a/test/abi/fibish.out b/test/abi/fibish.out new file mode 100644 index 0000000..9bd80c3 --- /dev/null +++ b/test/abi/fibish.out @@ -0,0 +1 @@ +f(40)=39088169,126491972 diff --git a/test/abi/fibish_closure.go b/test/abi/fibish_closure.go new file mode 100644 index 0000000..988001e --- /dev/null +++ b/test/abi/fibish_closure.go @@ -0,0 +1,34 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +package main + +import "fmt" + +// Test that register results are correctly returned (and passed) + +type MagicLastTypeNameForTestingRegisterABI func(int, MagicLastTypeNameForTestingRegisterABI) (int, int) + +//go:noinline +func f(x int, unused MagicLastTypeNameForTestingRegisterABI) (int, int) { + + if x < 3 { + return 0, x + } + + a, b := f(x-2, unused) + c, d := f(x-1, unused) + return a + d, b + c +} + +func main() { + x := 40 + a, b := f(x, f) + fmt.Printf("f(%d)=%d,%d\n", x, a, b) +} diff --git a/test/abi/fibish_closure.out b/test/abi/fibish_closure.out new file mode 100644 index 0000000..9bd80c3 --- /dev/null +++ b/test/abi/fibish_closure.out @@ -0,0 +1 @@ +f(40)=39088169,126491972 diff --git a/test/abi/fuzz_trailing_zero_field.go b/test/abi/fuzz_trailing_zero_field.go new file mode 100644 index 0000000..ae7ad32 --- /dev/null +++ b/test/abi/fuzz_trailing_zero_field.go @@ -0,0 +1,39 @@ +// run + +// Copyright 2021 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. + +package main + +var p0exp = S1{ + F1: complex(float64(2.3640607624715027), float64(-0.2717825524109192)), + F2: S2{F1: 9}, + F3: 103050709, +} + +type S1 struct { + F1 complex128 + F2 S2 + F3 uint64 +} + +type S2 struct { + F1 uint64 + F2 empty +} + +type empty struct { +} + +//go:noinline +//go:registerparams +func callee(p0 S1) { + if p0 != p0exp { + panic("bad p0") + } +} + +func main() { + callee(p0exp) +} diff --git a/test/abi/idata.go b/test/abi/idata.go new file mode 100644 index 0000000..af2b87b --- /dev/null +++ b/test/abi/idata.go @@ -0,0 +1,97 @@ +// run + +// Copyright 2021 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. + +// Excerpted from go/constant/value.go to capture a bug from there. + +package main + +import ( + "fmt" + "math" + "math/big" +) + +type ( + unknownVal struct{} + intVal struct{ val *big.Int } // Int values not representable as an int64 + ratVal struct{ val *big.Rat } // Float values representable as a fraction + floatVal struct{ val *big.Float } // Float values not representable as a fraction + complexVal struct{ re, im Value } +) + +const prec = 512 + +func (unknownVal) String() string { return "unknown" } + +func (x intVal) String() string { return x.val.String() } +func (x ratVal) String() string { return rtof(x).String() } + +func (x floatVal) String() string { + f := x.val + + // Use exact fmt formatting if in float64 range (common case): + // proceed if f doesn't underflow to 0 or overflow to inf. + if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) { + return fmt.Sprintf("%.6g", x) + } + + return "OOPS" +} + +func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) } + +func newFloat() *big.Float { return new(big.Float).SetPrec(prec) } + +//go:noinline +//go:registerparams +func itor(x intVal) ratVal { return ratVal{nil} } + +//go:noinline +//go:registerparams +func itof(x intVal) floatVal { return floatVal{nil} } +func rtof(x ratVal) floatVal { return floatVal{newFloat().SetRat(x.val)} } + +type Value interface { + String() string +} + +//go:noinline +//go:registerparams +func ToFloat(x Value) Value { + switch x := x.(type) { + case intVal: + if smallInt(x.val) { + return itor(x) + } + return itof(x) + case ratVal, floatVal: + return x + case complexVal: + if Sign(x.im) == 0 { + return ToFloat(x.re) + } + } + return unknownVal{} +} + +//go:noinline +//go:registerparams +func smallInt(x *big.Int) bool { + return false +} + +//go:noinline +//go:registerparams +func Sign(x Value) int { + return 0 +} + + +func main() { + v := ratVal{big.NewRat(22,7)} + s := ToFloat(v).String() + fmt.Printf("s=%s\n", s) +} diff --git a/test/abi/idata.out b/test/abi/idata.out new file mode 100644 index 0000000..98190c2 --- /dev/null +++ b/test/abi/idata.out @@ -0,0 +1 @@ +s=3.14286 diff --git a/test/abi/leaf.go b/test/abi/leaf.go new file mode 100644 index 0000000..f893f5d --- /dev/null +++ b/test/abi/leaf.go @@ -0,0 +1,36 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import "fmt" + +type i5f5 struct { + a, b int16 + c, d, e int32 + r, s, t, u, v float32 +} + +//go:registerparams +//go:noinline +func F(x i5f5) i5f5 { + return x +} + +func main() { + x := i5f5{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + y := x + z := F(x) + if y != z { + fmt.Printf("y=%v, z=%v\n", y, z) + } +} diff --git a/test/abi/leaf2.go b/test/abi/leaf2.go new file mode 100644 index 0000000..d2018d5 --- /dev/null +++ b/test/abi/leaf2.go @@ -0,0 +1,43 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import "fmt" + +type i4 struct { + a, b, c, d int +} + +//go:registerparams +//go:noinline +func F(x i4) i4 { + ab := x.a + x.b + bc := x.b + x.c + cd := x.c + x.d + ad := x.a + x.d + ba := x.a - x.b + cb := x.b - x.c + dc := x.c - x.d + da := x.a - x.d + + return i4{ab*bc + da, cd*ad + cb, ba*cb + ad, dc*da + bc} +} + +func main() { + x := i4{1, 2, 3, 4} + y := x + z := F(x) + if (i4{12, 34, 6, 8}) != z { + fmt.Printf("y=%v, z=%v\n", y, z) + } +} diff --git a/test/abi/many_int_input.go b/test/abi/many_int_input.go new file mode 100644 index 0000000..8fda937 --- /dev/null +++ b/test/abi/many_int_input.go @@ -0,0 +1,33 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +//go:registerparams +//go:noinline +func F(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int64) { + G(z, y, x, w, v, u, t, s, r, q, p, o, n, m, l, k, j, i, h, g, f, e, d, c, b, a) +} + +//go:registerparams +//go:noinline +func G(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int64) { + fmt.Println(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) +} + +func main() { + F(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26) +} diff --git a/test/abi/many_int_input.out b/test/abi/many_int_input.out new file mode 100644 index 0000000..fecfa82 --- /dev/null +++ b/test/abi/many_int_input.out @@ -0,0 +1 @@ +26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 diff --git a/test/abi/many_intstar_input.go b/test/abi/many_intstar_input.go new file mode 100644 index 0000000..b209c80 --- /dev/null +++ b/test/abi/many_intstar_input.go @@ -0,0 +1,45 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink int = 3 + +//go:registerparams +//go:noinline +func F(a, b, c, d, e, f *int) { + G(f, e, d, c, b, a) + sink += *a // *a == 6 after swapping in G +} + +//go:registerparams +//go:noinline +func G(a, b, c, d, e, f *int) { + var scratch [1000 * 100]int + scratch[*a] = *f // scratch[6] = 1 + fmt.Println(*a, *b, *c, *d, *e, *f) // Forces it to spill b + sink = scratch[*b+1] // scratch[5+1] == 1 + *f, *a = *a, *f + *e, *b = *b, *e + *d, *c = *c, *d +} + +func main() { + a, b, c, d, e, f := 1, 2, 3, 4, 5, 6 + F(&a, &b, &c, &d, &e, &f) + fmt.Println(a, b, c, d, e, f) + fmt.Println(sink) +} diff --git a/test/abi/many_intstar_input.out b/test/abi/many_intstar_input.out new file mode 100644 index 0000000..0a37ccb --- /dev/null +++ b/test/abi/many_intstar_input.out @@ -0,0 +1,3 @@ +6 5 4 3 2 1 +6 5 4 3 2 1 +7 diff --git a/test/abi/map.go b/test/abi/map.go new file mode 100644 index 0000000..236655a --- /dev/null +++ b/test/abi/map.go @@ -0,0 +1,34 @@ +// run + +// Copyright 2021 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. + +package main + +import "runtime" + +type T [10]int + +var m map[*T]int + +//go:noinline +func F() { + m = map[*T]int{ + K(): V(), // the key temp should be live across call to V + } +} + +//go:noinline +func V() int { runtime.GC(); runtime.GC(); runtime.GC(); return 123 } + +//go:noinline +func K() *T { + p := new(T) + runtime.SetFinalizer(p, func(*T) { println("FAIL") }) + return p +} + +func main() { + F() +} diff --git a/test/abi/method_wrapper.go b/test/abi/method_wrapper.go new file mode 100644 index 0000000..7aa262f --- /dev/null +++ b/test/abi/method_wrapper.go @@ -0,0 +1,35 @@ +// run + +// Copyright 2021 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. + +package main + +type S int + +type T struct { + a int + S +} + +//go:noinline +func (s *S) M(a int, x [2]int, b float64, y [2]float64) (S, int, [2]int, float64, [2]float64) { + return *s, a, x, b, y +} + +var s S = 42 +var t = &T{S: s} + +var fn = (*T).M // force a method wrapper + +func main() { + a := 123 + x := [2]int{456, 789} + b := 1.2 + y := [2]float64{3.4, 5.6} + s1, a1, x1, b1, y1 := fn(t, a, x, b, y) + if a1 != a || x1 != x || b1 != b || y1 != y || s1 != s { + panic("FAIL") + } +} diff --git a/test/abi/more_intstar_input.go b/test/abi/more_intstar_input.go new file mode 100644 index 0000000..f0a48fb --- /dev/null +++ b/test/abi/more_intstar_input.go @@ -0,0 +1,44 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink int + +//go:registerparams +//go:noinline +func F(a, b, c, d, e, f, g, h, i, j, k, l, m *int) { + G(m, l, k, j, i, h, g, f, e, d, c, b, a) + // did the pointers get properly updated? + sink = *a + *m +} + +//go:registerparams +//go:noinline +func G(a, b, c, d, e, f, g, h, i, j, k, l, m *int) { + // Do not reference the parameters + var scratch [1000 * 100]int + I := *c - *e - *l // zero. + scratch[I] = *d + fmt.Println("Got this far!") + sink += scratch[0] +} + +func main() { + a, b, c, d, e, f, g, h, i, j, k, l, m := 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 + F(&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m) + fmt.Printf("Sink = %d\n", sink-7) +} diff --git a/test/abi/more_intstar_input.out b/test/abi/more_intstar_input.out new file mode 100644 index 0000000..2ab84bf --- /dev/null +++ b/test/abi/more_intstar_input.out @@ -0,0 +1,2 @@ +Got this far! +Sink = 7 diff --git a/test/abi/named_results.go b/test/abi/named_results.go new file mode 100644 index 0000000..eaaadb1 --- /dev/null +++ b/test/abi/named_results.go @@ -0,0 +1,91 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +package main + +import ( + "fmt" +) + +var sink *string + +var y int + +//go:registerparams +//go:noinline +func F(a, b, c *int) (x int) { + x = *a + G(&x) + x += *b + G(&x) + x += *c + G(&x) + return +} + +//go:registerparams +//go:noinline +func G(x *int) { + y += *x + fmt.Println("y = ", y) +} + +//go:registerparams +//go:noinline +func X() { + *sink += " !!!!!!!!!!!!!!!" +} + +//go:registerparams +//go:noinline +func H(s, t string) (result string) { // result leaks to heap + result = "Aloha! " + s + " " + t + sink = &result + r := "" + if len(s) <= len(t) { + r = "OKAY! " + X() + } + return r + result +} + +//go:registerparams +//go:noinline +func K(s, t string) (result string) { // result spills + result = "Aloha! " + s + " " + t + r := "" + if len(s) <= len(t) { + r = "OKAY! " + X() + } + return r + result +} + +func main() { + a, b, c := 1, 4, 16 + x := F(&a, &b, &c) + fmt.Printf("x = %d\n", x) + + y := H("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) + z := H("Hello", "Pal!") + fmt.Println("len(z) =", len(z)) + fmt.Println("z =", z) + + fmt.Println() + + y = K("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) + z = K("Hello", "Pal!") + fmt.Println("len(z) =", len(z)) + fmt.Println("z =", z) + +} diff --git a/test/abi/named_results.out b/test/abi/named_results.out new file mode 100644 index 0000000..02f12e8 --- /dev/null +++ b/test/abi/named_results.out @@ -0,0 +1,13 @@ +y = 1 +y = 6 +y = 27 +x = 21 +len(y) = 41 +y = OKAY! Aloha! Hello World! !!!!!!!!!!!!!!! +len(z) = 17 +z = Aloha! Hello Pal! + +len(y) = 25 +y = OKAY! Aloha! Hello World! +len(z) = 17 +z = Aloha! Hello Pal! diff --git a/test/abi/named_return_stuff.go b/test/abi/named_return_stuff.go new file mode 100644 index 0000000..faa0221 --- /dev/null +++ b/test/abi/named_return_stuff.go @@ -0,0 +1,94 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink *string + +var y int + +//go:registerparams +//go:noinline +func F(a, b, c *int) (x int) { + x = *a + G(&x) + x += *b + G(&x) + x += *c + G(&x) + return +} + +//go:registerparams +//go:noinline +func G(x *int) { + y += *x + fmt.Println("y = ", y) +} + +//go:registerparams +//go:noinline +func X() { + *sink += " !!!!!!!!!!!!!!!" +} + +//go:registerparams +//go:noinline +func H(s, t string) (result string) { // result leaks to heap + result = "Aloha! " + s + " " + t + sink = &result + r := "" + if len(s) <= len(t) { + r = "OKAY! " + X() + } + return r + result +} + +//go:registerparams +//go:noinline +func K(s, t string) (result string) { // result spills + result = "Aloha! " + s + " " + t + r := "" + if len(s) <= len(t) { + r = "OKAY! " + X() + } + return r + result +} + +func main() { + a, b, c := 1, 4, 16 + x := F(&a, &b, &c) + fmt.Printf("x = %d\n", x) + + y := H("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) + z := H("Hello", "Pal!") + fmt.Println("len(z) =", len(z)) + fmt.Println("z =", z) + + fmt.Println() + + y = K("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) + z = K("Hello", "Pal!") + fmt.Println("len(z) =", len(z)) + fmt.Println("z =", z) + +} diff --git a/test/abi/named_return_stuff.out b/test/abi/named_return_stuff.out new file mode 100644 index 0000000..02f12e8 --- /dev/null +++ b/test/abi/named_return_stuff.out @@ -0,0 +1,13 @@ +y = 1 +y = 6 +y = 27 +x = 21 +len(y) = 41 +y = OKAY! Aloha! Hello World! !!!!!!!!!!!!!!! +len(z) = 17 +z = Aloha! Hello Pal! + +len(y) = 25 +y = OKAY! Aloha! Hello World! +len(z) = 17 +z = Aloha! Hello Pal! diff --git a/test/abi/open_defer_1.go b/test/abi/open_defer_1.go new file mode 100644 index 0000000..0a0ace3 --- /dev/null +++ b/test/abi/open_defer_1.go @@ -0,0 +1,36 @@ +// run + +// Copyright 2021 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. + +// For #45062, miscompilation of open defer of method invocation + +package main + +func main() { + var x, y, z int = -1, -2, -3 + F(x, y, z) +} + +//go:noinline +func F(x, y, z int) { + defer i.M(x, y, z) + defer func() { recover() }() + panic("XXX") +} + +type T int + +func (t *T) M(x, y, z int) { + if x == -1 && y == -2 && z == -3 { + return + } + println("FAIL: Expected -1, -2, -3, but x, y, z =", x, y, z) +} + +var t T = 42 + +type I interface{ M(x, y, z int) } + +var i I = &t diff --git a/test/abi/part_live.go b/test/abi/part_live.go new file mode 100644 index 0000000..592b6b3 --- /dev/null +++ b/test/abi/part_live.go @@ -0,0 +1,48 @@ +// run + +// Copyright 2021 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. + +// A test for partial liveness / partial spilling / compiler-induced GC failure + +package main + +import "runtime" +import "unsafe" + +//go:registerparams +func F(s []int) { + for i, x := range s { + G(i, x) + } + GC() + G(len(s), cap(s)) + GC() +} + +//go:noinline +//go:registerparams +func G(int, int) {} + +//go:registerparams +func GC() { runtime.GC(); runtime.GC() } + +func main() { + s := make([]int, 3) + escape(s) + p := int(uintptr(unsafe.Pointer(&s[2])) + 42) // likely point to unallocated memory + poison([3]int{p, p, p}) + F(s) +} + +//go:noinline +//go:registerparams +func poison([3]int) {} + +//go:noinline +//go:registerparams +func escape(s []int) { + g = s +} +var g []int diff --git a/test/abi/part_live_2.go b/test/abi/part_live_2.go new file mode 100644 index 0000000..f9d7b01 --- /dev/null +++ b/test/abi/part_live_2.go @@ -0,0 +1,53 @@ +// run + +// Copyright 2021 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. + +// A test for partial liveness / partial spilling / compiler-induced GC failure + +package main + +import "runtime" +import "unsafe" + +//go:registerparams +func F(s []int) { + for i, x := range s { + G(i, x) + } + GC() + H(&s[0]) // It's possible that this will make the spill redundant, but there's a bug in spill slot allocation. + G(len(s), cap(s)) + GC() +} + +//go:noinline +//go:registerparams +func G(int, int) {} + +//go:noinline +//go:registerparams +func H(*int) {} + +//go:registerparams +func GC() { runtime.GC(); runtime.GC() } + +func main() { + s := make([]int, 3) + escape(s) + p := int(uintptr(unsafe.Pointer(&s[2])) + 42) // likely point to unallocated memory + poison([3]int{p, p, p}) + F(s) +} + +//go:noinline +//go:registerparams +func poison([3]int) {} + +//go:noinline +//go:registerparams +func escape(s []int) { + g = s +} +var g []int diff --git a/test/abi/result_live.go b/test/abi/result_live.go new file mode 100644 index 0000000..2be54e3 --- /dev/null +++ b/test/abi/result_live.go @@ -0,0 +1,20 @@ +// errorcheck -0 -live + +// Copyright 2021 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. + +package p + +type T struct { a, b, c, d string } // pass in registers, not SSA-able + +//go:registerparams +func F() (r T) { + r.a = g(1) // ERROR "live at call to g: r" + r.b = g(2) // ERROR "live at call to g: r" + r.c = g(3) // ERROR "live at call to g: r" + r.d = g(4) // ERROR "live at call to g: r" + return +} + +func g(int) string diff --git a/test/abi/result_regalloc.go b/test/abi/result_regalloc.go new file mode 100644 index 0000000..58aecad --- /dev/null +++ b/test/abi/result_regalloc.go @@ -0,0 +1,46 @@ +// run + +// Copyright 2021 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. + +// Bug: in (*bb).d, the value to be returned was not allocated to +// a register that satisfies its register mask. + +package main + +type bb struct { + r float64 + x []float64 +} + +//go:noinline +func B(r float64, x []float64) I { + return bb{r, x} +} + +func (b bb) d() (int, int) { + if b.r == 0 { + return 0, len(b.x) + } + return len(b.x), len(b.x) +} + +type I interface { d() (int, int) } + +func D(r I) (int, int) { return r.d() } + +//go:noinline +func F() (int, int) { + r := float64(1) + x := []float64{0, 1, 2} + b := B(r, x) + return D(b) +} + +func main() { + x, y := F() + if x != 3 || y != 3 { + panic("FAIL") + } +} diff --git a/test/abi/return_stuff.go b/test/abi/return_stuff.go new file mode 100644 index 0000000..130d8be --- /dev/null +++ b/test/abi/return_stuff.go @@ -0,0 +1,38 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +//go:registerparams +//go:noinline +func F(a, b, c *int) int { + return *a + *b + *c +} + +//go:registerparams +//go:noinline +func H(s, t string) string { + return s + " " + t +} + +func main() { + a, b, c := 1, 4, 16 + x := F(&a, &b, &c) + fmt.Printf("x = %d\n", x) + y := H("Hello", "World!") + fmt.Println("len(y) =", len(y)) + fmt.Println("y =", y) +} diff --git a/test/abi/return_stuff.out b/test/abi/return_stuff.out new file mode 100644 index 0000000..5f519d7 --- /dev/null +++ b/test/abi/return_stuff.out @@ -0,0 +1,3 @@ +x = 21 +len(y) = 12 +y = Hello World! diff --git a/test/abi/s_sif_sif.go b/test/abi/s_sif_sif.go new file mode 100644 index 0000000..f05f26f --- /dev/null +++ b/test/abi/s_sif_sif.go @@ -0,0 +1,37 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +package main + +// Test ensures that abi information producer and consumer agree about the +// order of registers for inputs. T's registers should be I0, F0, I1, F1. + +import "fmt" + +type P struct { + a int8 + x float64 +} + +type T struct { + d, e P +} + +//go:registerparams +//go:noinline +func G(t T) float64 { + return float64(t.d.a+t.e.a) + t.d.x + t.e.x +} + +func main() { + x := G(T{P{10, 20}, P{30, 40}}) + if x != 100.0 { + fmt.Printf("FAIL, Expected 100, got %f\n", x) + } +} diff --git a/test/abi/spills3.go b/test/abi/spills3.go new file mode 100644 index 0000000..2478284 --- /dev/null +++ b/test/abi/spills3.go @@ -0,0 +1,48 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import "fmt" + +type i4 struct { + a, b, c, d int +} + +//go:noinline +func spills(px *i4) { +} + +//go:registerparams +//go:noinline +func F(x i4) i4 { + ab := x.a + x.b + bc := x.b + x.c + cd := x.c + x.d + ad := x.a + x.d + ba := x.a - x.b + cb := x.b - x.c + dc := x.c - x.d + da := x.a - x.d + i := i4{ab*bc + da, cd*ad + cb, ba*cb + ad, dc*da + bc} + spills(&i) + return i +} + +func main() { + x := i4{1, 2, 3, 4} + y := x + z := F(x) + if z != (i4{12, 34, 6, 8}) { + fmt.Printf("y=%v, z=%v\n", y, z) + } +} diff --git a/test/abi/spills4.go b/test/abi/spills4.go new file mode 100644 index 0000000..205f5a6 --- /dev/null +++ b/test/abi/spills4.go @@ -0,0 +1,44 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import "fmt" + +type i5f5 struct { + a, b int16 + c, d, e int32 + r, s, t, u, v float32 +} + +//go:noinline +func spills(_ *float32) { + +} + +//go:registerparams +//go:noinline +func F(x i5f5) i5f5 { + y := x.v + spills(&y) + x.r = y + return x +} + +func main() { + x := i5f5{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + y := x + z := F(x) + if (i5f5{1, 2, 3, 4, 5, 10, 7, 8, 9, 10}) != z { + fmt.Printf("y=%v, z=%v\n", y, z) + } +} diff --git a/test/abi/store_reg_args.go b/test/abi/store_reg_args.go new file mode 100644 index 0000000..df5e4e1 --- /dev/null +++ b/test/abi/store_reg_args.go @@ -0,0 +1,29 @@ +// run + +// Copyright 2021 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. + +// When the function Store an Arg and also use it in another place, +// be sure not to generate duplicated OpArgXXXReg values, which confuses +// the register allocator. + +package main + +//go:noinline +//go:registerparams +func F(x, y float32) { + if x < 0 { + panic("FAIL") + } + g = [4]float32{x, y, x, y} +} + +var g [4]float32 + +func main() { + F(1, 2) + if g[0] != 1 || g[1] != 2 || g[2] != 1 || g[3] != 2 { + panic("FAIL") + } +} diff --git a/test/abi/struct_3_string_input.go b/test/abi/struct_3_string_input.go new file mode 100644 index 0000000..54a8b38 --- /dev/null +++ b/test/abi/struct_3_string_input.go @@ -0,0 +1,40 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import ( + "fmt" +) + +var sink *string + +type toobig struct { + a, b, c string +} + +//go:registerparams +//go:noinline +func H(x toobig) string { + return x.a + " " + x.b + " " + x.c +} + +func main() { + s := H(toobig{"Hello", "there,", "World"}) + gotVsWant(s, "Hello there, World") +} + +func gotVsWant(got, want string) { + if got != want { + fmt.Printf("FAIL, got %s, wanted %s\n", got, want) + } +} diff --git a/test/abi/struct_3_string_input.out b/test/abi/struct_3_string_input.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/abi/struct_3_string_input.out diff --git a/test/abi/struct_lower_1.go b/test/abi/struct_lower_1.go new file mode 100644 index 0000000..b20de9b --- /dev/null +++ b/test/abi/struct_lower_1.go @@ -0,0 +1,30 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +package main + +import "fmt" + +//go:registerparams +//go:noinline +func passStruct6(a Struct6) Struct6 { + return a +} + +type Struct6 struct { + Struct1 +} + +type Struct1 struct { + A, B, C uint +} + +func main() { + fmt.Println(passStruct6(Struct6{Struct1{1, 2, 3}})) +} diff --git a/test/abi/struct_lower_1.out b/test/abi/struct_lower_1.out new file mode 100644 index 0000000..d326cb6 --- /dev/null +++ b/test/abi/struct_lower_1.out @@ -0,0 +1 @@ +{{1 2 3}} diff --git a/test/abi/too_big_to_ssa.go b/test/abi/too_big_to_ssa.go new file mode 100644 index 0000000..6c55d31 --- /dev/null +++ b/test/abi/too_big_to_ssa.go @@ -0,0 +1,48 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +package main + +import ( + "fmt" +) + +var sink *string + +type toobig struct { + // 6 words will not SSA but will fit in registers + a, b, c string +} + +//go:registerparams +//go:noinline +func H(x toobig) string { + return x.a + " " + x.b + " " + x.c +} + +//go:registerparams +//go:noinline +func I(a, b, c string) toobig { + return toobig{a, b, c} +} + +func main() { + s := H(toobig{"Hello", "there,", "World"}) + gotVsWant(s, "Hello there, World") + fmt.Println(s) + t := H(I("Ahoy", "there,", "Matey")) + gotVsWant(t, "Ahoy there, Matey") + fmt.Println(t) +} + +func gotVsWant(got, want string) { + if got != want { + fmt.Printf("FAIL, got %s, wanted %s\n", got, want) + } +} diff --git a/test/abi/too_big_to_ssa.out b/test/abi/too_big_to_ssa.out new file mode 100644 index 0000000..eeece34 --- /dev/null +++ b/test/abi/too_big_to_ssa.out @@ -0,0 +1,2 @@ +Hello there, World +Ahoy there, Matey diff --git a/test/abi/uglyfib.go b/test/abi/uglyfib.go new file mode 100644 index 0000000..b8e8739 --- /dev/null +++ b/test/abi/uglyfib.go @@ -0,0 +1,82 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +// wasm is excluded because the compiler chatter about register abi pragma ends up +// on stdout, and causes the expected output to not match. + +package main + +import "fmt" + +// This test is designed to provoke a stack growth +// in a way that very likely leaves junk in the +// parameter save area if they aren't saved or spilled +// there, as appropriate. + +//go:registerparams +//go:noinline +func f(x int, xm1, xm2, p *int) { + var y = [2]int{x - 4, 0} + if x < 2 { + *p += x + return + } + x -= 3 + g(*xm1, xm2, &x, p) // xm1 is no longer live. + h(*xm2, &x, &y[0], p) // xm2 is no longer live, but was spilled. +} + +//go:registerparams +//go:noinline +func g(x int, xm1, xm2, p *int) { + var y = [3]int{x - 4, 0, 0} + if x < 2 { + *p += x + return + } + x -= 3 + k(*xm2, &x, &y[0], p) + h(*xm1, xm2, &x, p) +} + +//go:registerparams +//go:noinline +func h(x int, xm1, xm2, p *int) { + var y = [4]int{x - 4, 0, 0, 0} + if x < 2 { + *p += x + return + } + x -= 3 + k(*xm1, xm2, &x, p) + f(*xm2, &x, &y[0], p) +} + +//go:registerparams +//go:noinline +func k(x int, xm1, xm2, p *int) { + var y = [5]int{x - 4, 0, 0, 0, 0} + if x < 2 { + *p += x + return + } + x -= 3 + f(*xm2, &x, &y[0], p) + g(*xm1, xm2, &x, p) +} + +func main() { + x := 40 + var y int + xm1 := x - 1 + xm2 := x - 2 + f(x, &xm1, &xm2, &y) + + fmt.Printf("Fib(%d)=%d\n", x, y) +} diff --git a/test/abi/uglyfib.out b/test/abi/uglyfib.out new file mode 100644 index 0000000..d892270 --- /dev/null +++ b/test/abi/uglyfib.out @@ -0,0 +1 @@ +Fib(40)=102334155 diff --git a/test/abi/wrapdefer_largetmp.go b/test/abi/wrapdefer_largetmp.go new file mode 100644 index 0000000..fb6eeba --- /dev/null +++ b/test/abi/wrapdefer_largetmp.go @@ -0,0 +1,37 @@ +// run + +//go:build !wasm +// +build !wasm + +// Copyright 2021 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. + +package main + +//go:noinline +func F() { + b := g() + defer g2(b) + n := g()[20] + println(n) +} + +type T [45]int + +var x = 0 + +//go:noinline +func g() T { + x++ + return T{20: x} +} + +//go:noinline +func g2(t T) { + if t[20] != 1 { + println("FAIL", t[20]) + } +} + +func main() { F() } diff --git a/test/abi/wrapdefer_largetmp.out b/test/abi/wrapdefer_largetmp.out new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/test/abi/wrapdefer_largetmp.out @@ -0,0 +1 @@ +2 diff --git a/test/abi/zombie_struct_select.go b/test/abi/zombie_struct_select.go new file mode 100644 index 0000000..d0cab98 --- /dev/null +++ b/test/abi/zombie_struct_select.go @@ -0,0 +1,36 @@ +// run + +// Copyright 2021 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. + +package main + +type patchlist struct { + head, tail uint32 +} + +type frag struct { + i uint32 + out patchlist +} + +//go:noinline +//go:registerparams +func patch(l patchlist, i uint32) { +} + +//go:noinline +//go:registerparams +func badbad(f1, f2 frag) frag { + // concat of failure is failure + if f1.i == 0 || f2.i == 0 { // internal compiler error: 'badbad': incompatible OpArgIntReg [4]: v42 and v26 + return frag{} + } + patch(f1.out, f2.i) + return frag{f1.i, f2.out} +} + +func main() { + badbad(frag{i: 2}, frag{i: 3}) +} |