Source file test/codegen/stack.go
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 7 package codegen 8 9 import "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-" 23 func StackStore() int { 24 var x int 25 return *(&x) 26 } 27 28 type 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-" 42 func 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. 57 func 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-" 70 func 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-" 83 func 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 90 func 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.*" 100 func 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 109 func 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 120 func 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 132 func nopInt() int { 133 return 0 134 } 135 136 //go:noinline 137 func getp1() *[4]int { 138 return nil 139 } 140 141 //go:noinline 142 func getp2() *[4]int { 143 return nil 144 } 145