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