blob: cdabf978f086b096f4f37777fd7e2d1d429a98c7 [file] [log] [blame]
// Copyright 2015 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"
"testing"
)
var output string
func mypanic(t *testing.T, s string) {
t.Fatalf(s + "\n" + output)
}
func assertEqual(t *testing.T, x, y int) {
if x != y {
mypanic(t, fmt.Sprintf("assertEqual failed got %d, want %d", x, y))
}
}
func TestAddressed(t *testing.T) {
x := f1_ssa(2, 3)
output += fmt.Sprintln("*x is", *x)
output += fmt.Sprintln("Gratuitously use some stack")
output += fmt.Sprintln("*x is", *x)
assertEqual(t, *x, 9)
w := f3a_ssa(6)
output += fmt.Sprintln("*w is", *w)
output += fmt.Sprintln("Gratuitously use some stack")
output += fmt.Sprintln("*w is", *w)
assertEqual(t, *w, 6)
y := f3b_ssa(12)
output += fmt.Sprintln("*y.(*int) is", *y.(*int))
output += fmt.Sprintln("Gratuitously use some stack")
output += fmt.Sprintln("*y.(*int) is", *y.(*int))
assertEqual(t, *y.(*int), 12)
z := f3c_ssa(8)
output += fmt.Sprintln("*z.(*int) is", *z.(*int))
output += fmt.Sprintln("Gratuitously use some stack")
output += fmt.Sprintln("*z.(*int) is", *z.(*int))
assertEqual(t, *z.(*int), 8)
args(t)
test_autos(t)
}
//go:noinline
func f1_ssa(x, y int) *int {
x = x*y + y
return &x
}
//go:noinline
func f3a_ssa(x int) *int {
return &x
}
//go:noinline
func f3b_ssa(x int) interface{} { // ./foo.go:15: internal error: f3b_ssa ~r1 (type interface {}) recorded as live on entry
return &x
}
//go:noinline
func f3c_ssa(y int) interface{} {
x := y
return &x
}
type V struct {
p *V
w, x int64
}
func args(t *testing.T) {
v := V{p: nil, w: 1, x: 1}
a := V{p: &v, w: 2, x: 2}
b := V{p: &v, w: 0, x: 0}
i := v.args_ssa(a, b)
output += fmt.Sprintln("i=", i)
assertEqual(t, int(i), 2)
}
//go:noinline
func (v V) args_ssa(a, b V) int64 {
if v.w == 0 {
return v.x
}
if v.w == 1 {
return a.x
}
if v.w == 2 {
return b.x
}
b.p.p = &a // v.p in caller = &a
return -1
}
func test_autos(t *testing.T) {
test(t, 11)
test(t, 12)
test(t, 13)
test(t, 21)
test(t, 22)
test(t, 23)
test(t, 31)
test(t, 32)
}
func test(t *testing.T, which int64) {
output += fmt.Sprintln("test", which)
v1 := V{w: 30, x: 3, p: nil}
v2, v3 := v1.autos_ssa(which, 10, 1, 20, 2)
if which != v2.val() {
output += fmt.Sprintln("Expected which=", which, "got v2.val()=", v2.val())
mypanic(t, "Failure of expected V value")
}
if v2.p.val() != v3.val() {
output += fmt.Sprintln("Expected v2.p.val()=", v2.p.val(), "got v3.val()=", v3.val())
mypanic(t, "Failure of expected V.p value")
}
if which != v3.p.p.p.p.p.p.p.val() {
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())
mypanic(t, "Failure of expected V.p value")
}
}
func (v V) val() int64 {
return v.w + v.x
}
// autos_ssa uses contents of v and parameters w1, w2, x1, x2
// to initialize a bunch of locals, all of which have their
// address taken to force heap allocation, and then based on
// the value of which a pair of those locals are copied in
// various ways to the two results y, and z, which are also
// addressed. Which is expected to be one of 11-13, 21-23, 31, 32,
// and y.val() should be equal to which and y.p.val() should
// be equal to z.val(). Also, x(.p)**8 == x; that is, the
// autos are all linked into a ring.
//go:noinline
func (v V) autos_ssa(which, w1, x1, w2, x2 int64) (y, z V) {
fill_ssa(v.w, v.x, &v, v.p) // gratuitous no-op to force addressing
var a, b, c, d, e, f, g, h V
fill_ssa(w1, x1, &a, &b)
fill_ssa(w1, x2, &b, &c)
fill_ssa(w1, v.x, &c, &d)
fill_ssa(w2, x1, &d, &e)
fill_ssa(w2, x2, &e, &f)
fill_ssa(w2, v.x, &f, &g)
fill_ssa(v.w, x1, &g, &h)
fill_ssa(v.w, x2, &h, &a)
switch which {
case 11:
y = a
z.getsI(&b)
case 12:
y.gets(&b)
z = c
case 13:
y.gets(&c)
z = d
case 21:
y.getsI(&d)
z.gets(&e)
case 22:
y = e
z = f
case 23:
y.gets(&f)
z.getsI(&g)
case 31:
y = g
z.gets(&h)
case 32:
y.getsI(&h)
z = a
default:
panic("")
}
return
}
// gets is an address-mentioning way of implementing
// structure assignment.
//go:noinline
func (to *V) gets(from *V) {
*to = *from
}
// gets is an address-and-interface-mentioning way of
// implementing structure assignment.
//go:noinline
func (to *V) getsI(from interface{}) {
*to = *from.(*V)
}
// fill_ssa initializes r with V{w:w, x:x, p:p}
//go:noinline
func fill_ssa(w, x int64, r, p *V) {
*r = V{w: w, x: x, p: p}
}