summaryrefslogtreecommitdiffstats
path: root/test/abi
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
commit43a123c1ae6613b3efeed291fa552ecd909d3acf (patch)
treefd92518b7024bc74031f78a1cf9e454b65e73665 /test/abi
parentInitial commit. (diff)
downloadgolang-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')
-rw-r--r--test/abi/bad_internal_offsets.go74
-rw-r--r--test/abi/bad_select_crash.go272
-rw-r--r--test/abi/convF_criteria.go27
-rw-r--r--test/abi/convF_criteria.out2
-rw-r--r--test/abi/convT64_criteria.go25
-rw-r--r--test/abi/convT64_criteria.out1
-rw-r--r--test/abi/defer_aggregate.go48
-rw-r--r--test/abi/defer_recover_results.go36
-rw-r--r--test/abi/double_nested_addressed_struct.go62
-rw-r--r--test/abi/double_nested_struct.go54
-rw-r--r--test/abi/f_ret_z_not.go39
-rw-r--r--test/abi/f_ret_z_not.out1
-rw-r--r--test/abi/fibish.go33
-rw-r--r--test/abi/fibish.out1
-rw-r--r--test/abi/fibish_closure.go34
-rw-r--r--test/abi/fibish_closure.out1
-rw-r--r--test/abi/fuzz_trailing_zero_field.go39
-rw-r--r--test/abi/idata.go97
-rw-r--r--test/abi/idata.out1
-rw-r--r--test/abi/leaf.go36
-rw-r--r--test/abi/leaf2.go43
-rw-r--r--test/abi/many_int_input.go33
-rw-r--r--test/abi/many_int_input.out1
-rw-r--r--test/abi/many_intstar_input.go45
-rw-r--r--test/abi/many_intstar_input.out3
-rw-r--r--test/abi/map.go34
-rw-r--r--test/abi/method_wrapper.go35
-rw-r--r--test/abi/more_intstar_input.go44
-rw-r--r--test/abi/more_intstar_input.out2
-rw-r--r--test/abi/named_results.go91
-rw-r--r--test/abi/named_results.out13
-rw-r--r--test/abi/named_return_stuff.go94
-rw-r--r--test/abi/named_return_stuff.out13
-rw-r--r--test/abi/open_defer_1.go36
-rw-r--r--test/abi/part_live.go48
-rw-r--r--test/abi/part_live_2.go53
-rw-r--r--test/abi/result_live.go20
-rw-r--r--test/abi/result_regalloc.go46
-rw-r--r--test/abi/return_stuff.go38
-rw-r--r--test/abi/return_stuff.out3
-rw-r--r--test/abi/s_sif_sif.go37
-rw-r--r--test/abi/spills3.go48
-rw-r--r--test/abi/spills4.go44
-rw-r--r--test/abi/store_reg_args.go29
-rw-r--r--test/abi/struct_3_string_input.go40
-rw-r--r--test/abi/struct_3_string_input.out0
-rw-r--r--test/abi/struct_lower_1.go30
-rw-r--r--test/abi/struct_lower_1.out1
-rw-r--r--test/abi/too_big_to_ssa.go48
-rw-r--r--test/abi/too_big_to_ssa.out2
-rw-r--r--test/abi/uglyfib.go82
-rw-r--r--test/abi/uglyfib.out1
-rw-r--r--test/abi/wrapdefer_largetmp.go37
-rw-r--r--test/abi/wrapdefer_largetmp.out1
-rw-r--r--test/abi/zombie_struct_select.go36
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})
+}