aboutsummaryrefslogtreecommitdiff
path: root/test/codegen/stack.go
blob: 65c9868d67086d950efc7a97175ddcd684525f2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// asmcheck

// Copyright 2018 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 codegen

import "runtime"

// This file contains code generation tests related to the use of the
// stack.

// Check that stack stores are optimized away.

// 386:"TEXT\t.*, [$]0-"
// amd64:"TEXT\t.*, [$]0-"
// arm:"TEXT\t.*, [$]-4-"
// arm64:"TEXT\t.*, [$]0-"
// mips:"TEXT\t.*, [$]-4-"
// ppc64x:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
func StackStore() int {
	var x int
	return *(&x)
}

type T struct {
	A, B, C, D int // keep exported fields
	x, y, z    int // reset unexported fields
}

// Check that large structs are cleared directly (issue #24416).

// 386:"TEXT\t.*, [$]0-"
// amd64:"TEXT\t.*, [$]0-"
// arm:"TEXT\t.*, [$]0-" (spills return address)
// arm64:"TEXT\t.*, [$]0-"
// mips:"TEXT\t.*, [$]-4-"
// ppc64x:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
func ZeroLargeStruct(x *T) {
	t := T{}
	*x = t
}

// Check that structs are partially initialised directly (issue #24386).

// Notes:
// - 386 fails due to spilling a register
// amd64:"TEXT\t.*, [$]0-"
// arm:"TEXT\t.*, [$]0-" (spills return address)
// arm64:"TEXT\t.*, [$]0-"
// ppc64x:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
// Note: that 386 currently has to spill a register.
func KeepWanted(t *T) {
	*t = T{A: t.A, B: t.B, C: t.C, D: t.D}
}

// Check that small array operations avoid using the stack (issue #15925).

// Notes:
// - 386 fails due to spilling a register
// - arm & mips fail due to softfloat calls
// amd64:"TEXT\t.*, [$]0-"
// arm64:"TEXT\t.*, [$]0-"
// ppc64x:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
func ArrayAdd64(a, b [4]float64) [4]float64 {
	return [4]float64{a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]}
}

// Check that small array initialization avoids using the stack.

// 386:"TEXT\t.*, [$]0-"
// amd64:"TEXT\t.*, [$]0-"
// arm:"TEXT\t.*, [$]0-" (spills return address)
// arm64:"TEXT\t.*, [$]0-"
// mips:"TEXT\t.*, [$]-4-"
// ppc64x:"TEXT\t.*, [$]0-"
// s390x:"TEXT\t.*, [$]0-"
func ArrayInit(i, j int) [4]int {
	return [4]int{i, 0, j, 0}
}

// Check that assembly output has matching offset and base register
// (issue #21064).

func check_asmout(b [2]int) int {
	runtime.GC() // use some frame
	// amd64:`.*b\+24\(SP\)`
	// arm:`.*b\+4\(FP\)`
	return b[1]
}

// Check that simple functions get promoted to nosplit, even when
// they might panic in various ways. See issue 31219.
// amd64:"TEXT\t.*NOSPLIT.*"
func MightPanic(a []int, i, j, k, s int) {
	_ = a[i]     // panicIndex
	_ = a[i:j]   // panicSlice
	_ = a[i:j:k] // also panicSlice
	_ = i << s   // panicShift
	_ = i / j    // panicDivide
}

// Put a defer in a loop, so second defer is not open-coded
func Defer() {
	for i := 0; i < 2; i++ {
		defer func() {}()
	}
	// amd64:`CALL\truntime\.deferprocStack`
	defer func() {}()
}

// Check that stack slots are shared among values of the same
// type, but not pointer-identical types. See issue 65783.

func spillSlotReuse() {
	// The return values of getp1 and getp2 need to be
	// spilled around the calls to nopInt. Make sure that
	// spill slot gets reused.

	//arm64:`.*autotmp_2-8\(SP\)`
	getp1()[nopInt()] = 0
	//arm64:`.*autotmp_2-8\(SP\)`
	getp2()[nopInt()] = 0
}

//go:noinline
func nopInt() int {
	return 0
}

//go:noinline
func getp1() *[4]int {
	return nil
}

//go:noinline
func getp2() *[4]int {
	return nil
}