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