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  

View as plain text