1
2
3
4
5 package ssacompile_test
6
7 import (
8 "encoding/binary"
9 "testing"
10 "unsafe"
11 )
12
13 type point struct {
14 x, y int
15 }
16
17
18 func simpleStructAddr(c bool) int {
19 p := point{10, 20}
20 ptr := &p
21 if c {
22 ptr.x += 1
23 } else {
24 ptr.y += 1
25 }
26 return ptr.x + ptr.y
27 }
28
29
30 func simpleStructReg(c bool) int {
31 x, y := 10, 20
32 if c {
33 x += 1
34 } else {
35 y += 1
36 }
37 return x + y
38 }
39
40 type inner struct {
41 a, b int
42 }
43
44 type outer struct {
45 in inner
46 c int
47 }
48
49
50 func nestedStructAddr(c bool) int {
51 o := outer{inner{1, 2}, 3}
52 ptr := &o
53 if c {
54 ptr.in.a += 10
55 } else {
56 ptr.in.b += 20
57 }
58 return ptr.in.a + ptr.in.b + ptr.c
59 }
60
61
62 func nestedStructReg(c bool) int {
63 a, b, c_val := 1, 2, 3
64 if c {
65 a += 10
66 } else {
67 b += 20
68 }
69 return a + b + c_val
70 }
71
72 type mixed struct {
73 a int32
74 b float64
75 }
76
77
78 func mixedStructAddr(c bool) float64 {
79 m := mixed{1, 2.0}
80 ptr := &m
81 if c {
82 ptr.a = 10
83 } else {
84 ptr.b = 20.0
85 }
86 return float64(ptr.a) + ptr.b
87 }
88
89
90 func mixedStructReg(c bool) float64 {
91 a := int32(1)
92 b := 2.0
93 if c {
94 a = 10
95 } else {
96 b = 20.0
97 }
98 return float64(a) + b
99 }
100
101
102 func arrayAddr(c bool) int {
103 var a [3]int
104 a[0] = 10
105 a[1] = 20
106 a[2] = 30
107 if c {
108 a[1] += 5
109 }
110 return a[0] + a[1] + a[2]
111 }
112
113
114 func arrayReg(c bool) int {
115 a0, a1, a2 := 10, 20, 30
116 if c {
117 a1 += 5
118 }
119 return a0 + a1 + a2
120 }
121
122
123 func zeroStructAddr(c bool) int {
124 var p point
125 ptr := &p
126 if c {
127 ptr.x = 10
128 } else {
129 ptr.y = 20
130 }
131 return ptr.x + ptr.y
132 }
133
134
135 func zeroStructReg(c bool) int {
136 var x, y int
137 if c {
138 x = 10
139 } else {
140 y = 20
141 }
142 return x + y
143 }
144
145
146 func moveStructAddr(c bool) int {
147 p1 := point{10, 20}
148 var p2 point
149 if c {
150 p2 = p1
151 } else {
152 p2 = point{30, 40}
153 }
154 return p2.x + p2.y
155 }
156
157
158 func moveStructReg(c bool) int {
159 p1x, p1y := 10, 20
160 var p2x, p2y int
161 if c {
162 p2x, p2y = p1x, p1y
163 } else {
164 p2x, p2y = 30, 40
165 }
166 return p2x + p2y
167 }
168
169
170 func shadowedStructAddr(c bool) int {
171 p := point{10, 20}
172 if c {
173 p := point{30, 40}
174 return p.x + p.y
175 }
176 return p.x + p.y
177 }
178
179
180 func shadowedStructReg(c bool) int {
181 px, py := 10, 20
182 if c {
183 px2, py2 := 30, 40
184 return px2 + py2
185 }
186 return px + py
187 }
188
189 type big struct {
190 a [100]int
191 }
192
193
194 func tooBigStructAddr() int {
195 var b big
196 b.a[0] = 10
197 return b.a[0]
198 }
199
200
201 func tooBigStructReg() int {
202 var a0 int = 10
203 return a0
204 }
205
206 type arrayStruct struct {
207 a [2]int
208 b int
209 }
210
211
212 func arrayStructAddr(c bool) int {
213 s := arrayStruct{[2]int{1, 2}, 3}
214 if c {
215 s.a[0] += 10
216 } else {
217 s.b += 20
218 }
219 return s.a[0] + s.a[1] + s.b
220 }
221
222
223 func arrayStructReg(c bool) int {
224 a0, a1, b := 1, 2, 3
225 if c {
226 a0 += 10
227 } else {
228 b += 20
229 }
230 return a0 + a1 + b
231 }
232
233 type stringStruct struct {
234 s string
235 i int
236 }
237
238
239 func stringStructAddr(c bool) int {
240
241
242 ss := stringStruct{"hello", 10}
243 if c {
244 ss.i += 5
245 }
246 return len(ss.s) + ss.i
247 }
248
249
250 func sliceStructAddr(c bool) int {
251 type sliceStruct struct {
252 sl []int
253 i int
254 }
255 ss := sliceStruct{[]int{1, 2, 3}, 10}
256 p := &ss
257 if c {
258 p.i += 5
259 }
260 return len(p.sl) + cap(p.sl) + p.sl[0] + p.i
261 }
262
263
264 func sliceStructReg(c bool) int {
265 sl, i := []int{1, 2, 3}, 10
266 if c {
267 i += 5
268 }
269 return len(sl) + cap(sl) + sl[0] + i
270 }
271
272
273 func ifaceStructAddr(c bool) int {
274 type ifaceStruct struct {
275 e any
276 i int
277 }
278 is := ifaceStruct{e: 42, i: 10}
279 p := &is
280 if c {
281 p.i += 5
282 }
283 return p.e.(int) + p.i
284 }
285
286
287 func ifaceStructReg(c bool) int {
288 var e any = 42
289 i := 10
290 if c {
291 i += 5
292 }
293 return e.(int) + i
294 }
295
296
297 func complexStructAddr(c bool) int {
298 type complexStruct struct {
299 z complex128
300 i int
301 }
302 cs := complexStruct{z: complex(3, 4), i: 10}
303 p := &cs
304 if c {
305 p.i += 5
306 }
307 return int(real(p.z)) + int(imag(p.z)) + p.i
308 }
309
310
311 func complexStructReg(c bool) int {
312 z, i := complex(3.0, 4.0), 10
313 if c {
314 i += 5
315 }
316 return int(real(z)) + int(imag(z)) + i
317 }
318
319
320 func stringStructReg(c bool) int {
321 s, i := "hello", 10
322 if c {
323 i += 5
324 }
325 return len(s) + i
326 }
327
328
329 func partialZeroAddr(bool) int {
330 type T struct {
331 a int
332 b [2]int
333 c int
334 }
335
336 t := T{a: 9, c: 9}
337 p := &t.b
338 *p = [2]int{}
339 return t.a * t.c
340 }
341
342
343 func partialMoveAddr(bool) int {
344 type T struct {
345 a int
346 b [2]int
347 c int
348 }
349
350 b2 := [2]int{1, 2}
351
352 t := T{a: 9, c: 9}
353 p := &t.b
354 *p = b2
355 return t.a * t.c
356 }
357
358
359 func unsafeSelfMoveAddr(c bool) int {
360 var s struct {
361 a [2]uint16
362 b uint32
363 }
364 s.a[0], s.a[1] = 1, 2
365 *(*[4]byte)(unsafe.Pointer(&s.b)) = *(*[4]byte)(unsafe.Pointer(&s.a))
366 if c {
367 s.b++
368 }
369 return int(s.b)
370 }
371
372 func unsafeAliasMoveAddr(c bool) int {
373
374
375
376
377
378 var x [4]byte
379 x[0], x[1], x[2], x[3] = 1, 2, 3, 4
380 var y [2]uint16
381 y = *(*[2]uint16)(unsafe.Pointer(&x))
382 if c {
383 y[0]++
384 }
385 return int(y[0]) + int(y[1])
386 }
387
388
389 func unsafeAliasMoveReg(c bool) int {
390
391 v0 := binary.NativeEndian.Uint16([]byte{1, 2})
392 v1 := binary.NativeEndian.Uint16([]byte{3, 4})
393 if c {
394 v0++
395 }
396 return int(v0) + int(v1)
397 }
398
399
400 func bareComplexAddr(c bool) int {
401
402
403 x := complex(3.0, 4.0)
404 q := &x
405 if c {
406 q = &x
407 }
408 return int(real(*q)) + int(imag(*q))
409 }
410
411
412 func bareComplexReg(c bool) int {
413 re, im := 3.0, 4.0
414 _ = c
415 return int(re) + int(im)
416 }
417
418
419 func bareStringAddr(c bool) int {
420 s := "hello"
421 p := &s
422 if c {
423 p = &s
424 }
425 return len(*p)
426 }
427
428
429 func bareStringReg(c bool) int {
430 _ = c
431 return 5
432 }
433
434 func TestDecomposeAddr(t *testing.T) {
435 tests := []struct {
436 name string
437 f1 func(bool) int
438 f2 func(bool) int
439 }{
440 {"simpleStruct", simpleStructAddr, simpleStructReg},
441 {"nestedStruct", nestedStructAddr, nestedStructReg},
442 {"array", arrayAddr, arrayReg},
443 {"zeroStruct", zeroStructAddr, zeroStructReg},
444 {"moveStruct", moveStructAddr, moveStructReg},
445 {"shadowedStruct", shadowedStructAddr, shadowedStructReg},
446 {"arrayStruct", arrayStructAddr, arrayStructReg},
447 {"stringStruct", stringStructAddr, stringStructReg},
448 {"unsafeAliasMove", unsafeAliasMoveAddr, unsafeAliasMoveReg},
449 {"unsafeSelfMove", unsafeSelfMoveAddr, func(c bool) int {
450
451 b := binary.NativeEndian.Uint32(binary.NativeEndian.AppendUint16(binary.NativeEndian.AppendUint16(nil, 1), 2))
452 if c {
453 return int(b + 1)
454 }
455 return int(b)
456 }},
457 {"bareComplex", bareComplexAddr, bareComplexReg},
458 {"bareString", bareStringAddr, bareStringReg},
459 {"sliceStruct", sliceStructAddr, sliceStructReg},
460 {"ifaceStruct", ifaceStructAddr, ifaceStructReg},
461 {"complexStruct", complexStructAddr, complexStructReg},
462 {"partialZero", partialZeroAddr, func(bool) int { return 81 }},
463 {"partialMove", partialMoveAddr, func(bool) int { return 81 }},
464 }
465
466 for _, tc := range tests {
467 for _, c := range []bool{true, false} {
468 if got, want := tc.f1(c), tc.f2(c); got != want {
469 t.Errorf("%s(%v): got %d, want %d", tc.name, c, got, want)
470 }
471 }
472 }
473
474 if got, want := mixedStructAddr(true), mixedStructReg(true); got != want {
475 t.Errorf("mixedStruct(true): got %f, want %f", got, want)
476 }
477 if got, want := mixedStructAddr(false), mixedStructReg(false); got != want {
478 t.Errorf("mixedStruct(false): got %f, want %f", got, want)
479 }
480
481 if got, want := tooBigStructAddr(), tooBigStructReg(); got != want {
482 t.Errorf("tooBigStruct: got %d, want %d", got, want)
483 }
484 }
485
View as plain text