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  

View as plain text