1// asmcheck
2
3// Copyright 2018 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7package codegen
8
9import "runtime"
10
11// This file contains code generation tests related to the use of the
12// stack.
13
14// Check that stack stores are optimized away.
15
16// 386:"TEXT\t.*, [$]0-"
17// amd64:"TEXT\t.*, [$]0-"
18// arm:"TEXT\t.*, [$]-4-"
19// arm64:"TEXT\t.*, [$]0-"
20// mips:"TEXT\t.*, [$]-4-"
21// ppc64x:"TEXT\t.*, [$]0-"
22// s390x:"TEXT\t.*, [$]0-"
23func StackStore() int {
24	var x int
25	return *(&x)
26}
27
28type T struct {
29	A, B, C, D int // keep exported fields
30	x, y, z    int // reset unexported fields
31}
32
33// Check that large structs are cleared directly (issue #24416).
34
35// 386:"TEXT\t.*, [$]0-"
36// amd64:"TEXT\t.*, [$]0-"
37// arm:"TEXT\t.*, [$]0-" (spills return address)
38// arm64:"TEXT\t.*, [$]0-"
39// mips:"TEXT\t.*, [$]-4-"
40// ppc64x:"TEXT\t.*, [$]0-"
41// s390x:"TEXT\t.*, [$]0-"
42func ZeroLargeStruct(x *T) {
43	t := T{}
44	*x = t
45}
46
47// Check that structs are partially initialised directly (issue #24386).
48
49// Notes:
50// - 386 fails due to spilling a register
51// amd64:"TEXT\t.*, [$]0-"
52// arm:"TEXT\t.*, [$]0-" (spills return address)
53// arm64:"TEXT\t.*, [$]0-"
54// ppc64x:"TEXT\t.*, [$]0-"
55// s390x:"TEXT\t.*, [$]0-"
56// Note: that 386 currently has to spill a register.
57func KeepWanted(t *T) {
58	*t = T{A: t.A, B: t.B, C: t.C, D: t.D}
59}
60
61// Check that small array operations avoid using the stack (issue #15925).
62
63// Notes:
64// - 386 fails due to spilling a register
65// - arm & mips fail due to softfloat calls
66// amd64:"TEXT\t.*, [$]0-"
67// arm64:"TEXT\t.*, [$]0-"
68// ppc64x:"TEXT\t.*, [$]0-"
69// s390x:"TEXT\t.*, [$]0-"
70func ArrayAdd64(a, b [4]float64) [4]float64 {
71	return [4]float64{a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]}
72}
73
74// Check that small array initialization avoids using the stack.
75
76// 386:"TEXT\t.*, [$]0-"
77// amd64:"TEXT\t.*, [$]0-"
78// arm:"TEXT\t.*, [$]0-" (spills return address)
79// arm64:"TEXT\t.*, [$]0-"
80// mips:"TEXT\t.*, [$]-4-"
81// ppc64x:"TEXT\t.*, [$]0-"
82// s390x:"TEXT\t.*, [$]0-"
83func ArrayInit(i, j int) [4]int {
84	return [4]int{i, 0, j, 0}
85}
86
87// Check that assembly output has matching offset and base register
88// (issue #21064).
89
90func check_asmout(b [2]int) int {
91	runtime.GC() // use some frame
92	// amd64:`.*b\+24\(SP\)`
93	// arm:`.*b\+4\(FP\)`
94	return b[1]
95}
96
97// Check that simple functions get promoted to nosplit, even when
98// they might panic in various ways. See issue 31219.
99// amd64:"TEXT\t.*NOSPLIT.*"
100func MightPanic(a []int, i, j, k, s int) {
101	_ = a[i]     // panicIndex
102	_ = a[i:j]   // panicSlice
103	_ = a[i:j:k] // also panicSlice
104	_ = i << s   // panicShift
105	_ = i / j    // panicDivide
106}
107
108// Put a defer in a loop, so second defer is not open-coded
109func Defer() {
110	for i := 0; i < 2; i++ {
111		defer func() {}()
112	}
113	// amd64:`CALL\truntime\.deferprocStack`
114	defer func() {}()
115}
116
117// Check that stack slots are shared among values of the same
118// type, but not pointer-identical types. See issue 65783.
119
120func spillSlotReuse() {
121	// The return values of getp1 and getp2 need to be
122	// spilled around the calls to nopInt. Make sure that
123	// spill slot gets reused.
124
125	//arm64:`.*autotmp_2-8\(SP\)`
126	getp1()[nopInt()] = 0
127	//arm64:`.*autotmp_2-8\(SP\)`
128	getp2()[nopInt()] = 0
129}
130
131//go:noinline
132func nopInt() int {
133	return 0
134}
135
136//go:noinline
137func getp1() *[4]int {
138	return nil
139}
140
141//go:noinline
142func getp2() *[4]int {
143	return nil
144}
145