1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package main
6
7import (
8	"fmt"
9	"testing"
10)
11
12var output string
13
14func mypanic(t *testing.T, s string) {
15	t.Fatalf(s + "\n" + output)
16
17}
18
19func assertEqual(t *testing.T, x, y int) {
20	if x != y {
21		mypanic(t, fmt.Sprintf("assertEqual failed got %d, want %d", x, y))
22	}
23}
24
25func TestAddressed(t *testing.T) {
26	x := f1_ssa(2, 3)
27	output += fmt.Sprintln("*x is", *x)
28	output += fmt.Sprintln("Gratuitously use some stack")
29	output += fmt.Sprintln("*x is", *x)
30	assertEqual(t, *x, 9)
31
32	w := f3a_ssa(6)
33	output += fmt.Sprintln("*w is", *w)
34	output += fmt.Sprintln("Gratuitously use some stack")
35	output += fmt.Sprintln("*w is", *w)
36	assertEqual(t, *w, 6)
37
38	y := f3b_ssa(12)
39	output += fmt.Sprintln("*y.(*int) is", *y.(*int))
40	output += fmt.Sprintln("Gratuitously use some stack")
41	output += fmt.Sprintln("*y.(*int) is", *y.(*int))
42	assertEqual(t, *y.(*int), 12)
43
44	z := f3c_ssa(8)
45	output += fmt.Sprintln("*z.(*int) is", *z.(*int))
46	output += fmt.Sprintln("Gratuitously use some stack")
47	output += fmt.Sprintln("*z.(*int) is", *z.(*int))
48	assertEqual(t, *z.(*int), 8)
49
50	args(t)
51	test_autos(t)
52}
53
54//go:noinline
55func f1_ssa(x, y int) *int {
56	x = x*y + y
57	return &x
58}
59
60//go:noinline
61func f3a_ssa(x int) *int {
62	return &x
63}
64
65//go:noinline
66func f3b_ssa(x int) interface{} { // ./foo.go:15: internal error: f3b_ssa ~r1 (type interface {}) recorded as live on entry
67	return &x
68}
69
70//go:noinline
71func f3c_ssa(y int) interface{} {
72	x := y
73	return &x
74}
75
76type V struct {
77	p    *V
78	w, x int64
79}
80
81func args(t *testing.T) {
82	v := V{p: nil, w: 1, x: 1}
83	a := V{p: &v, w: 2, x: 2}
84	b := V{p: &v, w: 0, x: 0}
85	i := v.args_ssa(a, b)
86	output += fmt.Sprintln("i=", i)
87	assertEqual(t, int(i), 2)
88}
89
90//go:noinline
91func (v V) args_ssa(a, b V) int64 {
92	if v.w == 0 {
93		return v.x
94	}
95	if v.w == 1 {
96		return a.x
97	}
98	if v.w == 2 {
99		return b.x
100	}
101	b.p.p = &a // v.p in caller = &a
102
103	return -1
104}
105
106func test_autos(t *testing.T) {
107	test(t, 11)
108	test(t, 12)
109	test(t, 13)
110	test(t, 21)
111	test(t, 22)
112	test(t, 23)
113	test(t, 31)
114	test(t, 32)
115}
116
117func test(t *testing.T, which int64) {
118	output += fmt.Sprintln("test", which)
119	v1 := V{w: 30, x: 3, p: nil}
120	v2, v3 := v1.autos_ssa(which, 10, 1, 20, 2)
121	if which != v2.val() {
122		output += fmt.Sprintln("Expected which=", which, "got v2.val()=", v2.val())
123		mypanic(t, "Failure of expected V value")
124	}
125	if v2.p.val() != v3.val() {
126		output += fmt.Sprintln("Expected v2.p.val()=", v2.p.val(), "got v3.val()=", v3.val())
127		mypanic(t, "Failure of expected V.p value")
128	}
129	if which != v3.p.p.p.p.p.p.p.val() {
130		output += fmt.Sprintln("Expected which=", which, "got v3.p.p.p.p.p.p.p.val()=", v3.p.p.p.p.p.p.p.val())
131		mypanic(t, "Failure of expected V.p value")
132	}
133}
134
135func (v V) val() int64 {
136	return v.w + v.x
137}
138
139// autos_ssa uses contents of v and parameters w1, w2, x1, x2
140// to initialize a bunch of locals, all of which have their
141// address taken to force heap allocation, and then based on
142// the value of which a pair of those locals are copied in
143// various ways to the two results y, and z, which are also
144// addressed. Which is expected to be one of 11-13, 21-23, 31, 32,
145// and y.val() should be equal to which and y.p.val() should
146// be equal to z.val().  Also, x(.p)**8 == x; that is, the
147// autos are all linked into a ring.
148//
149//go:noinline
150func (v V) autos_ssa(which, w1, x1, w2, x2 int64) (y, z V) {
151	fill_ssa(v.w, v.x, &v, v.p) // gratuitous no-op to force addressing
152	var a, b, c, d, e, f, g, h V
153	fill_ssa(w1, x1, &a, &b)
154	fill_ssa(w1, x2, &b, &c)
155	fill_ssa(w1, v.x, &c, &d)
156	fill_ssa(w2, x1, &d, &e)
157	fill_ssa(w2, x2, &e, &f)
158	fill_ssa(w2, v.x, &f, &g)
159	fill_ssa(v.w, x1, &g, &h)
160	fill_ssa(v.w, x2, &h, &a)
161	switch which {
162	case 11:
163		y = a
164		z.getsI(&b)
165	case 12:
166		y.gets(&b)
167		z = c
168	case 13:
169		y.gets(&c)
170		z = d
171	case 21:
172		y.getsI(&d)
173		z.gets(&e)
174	case 22:
175		y = e
176		z = f
177	case 23:
178		y.gets(&f)
179		z.getsI(&g)
180	case 31:
181		y = g
182		z.gets(&h)
183	case 32:
184		y.getsI(&h)
185		z = a
186	default:
187
188		panic("")
189	}
190	return
191}
192
193// gets is an address-mentioning way of implementing
194// structure assignment.
195//
196//go:noinline
197func (to *V) gets(from *V) {
198	*to = *from
199}
200
201// gets is an address-and-interface-mentioning way of
202// implementing structure assignment.
203//
204//go:noinline
205func (to *V) getsI(from interface{}) {
206	*to = *from.(*V)
207}
208
209// fill_ssa initializes r with V{w:w, x:x, p:p}
210//
211//go:noinline
212func fill_ssa(w, x int64, r, p *V) {
213	*r = V{w: w, x: x, p: p}
214}
215