cmd/compile: fix pointer maps for morestack

Verified with test and with single step watching changes to register
values across morestack calls, after reload.

Also added stack-growth test with pointer parameters of varying lifetime.

For #40724.

Change-Id: Idb5fe27786ac5c6665a734d41e68d3d39de2f4da
Reviewed-on: https://go-review.googlesource.com/c/go/+/294429
Trust: David Chase <drchase@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
This commit is contained in:
David Chase 2021-02-19 18:00:48 -05:00
parent a2d92b5143
commit 3778f8e07d
4 changed files with 104 additions and 4 deletions

View File

@ -297,6 +297,22 @@ func affectedVar(v *ssa.Value) (*ir.Name, ssa.SymEffect) {
n, _ := ssa.AutoVar(v)
return n, ssa.SymWrite
case ssa.OpArgIntReg:
// This forces the spill slot for the register to be live at function entry.
// one of the following holds for a function F with pointer-valued register arg X:
// 0. No GC (so an uninitialized spill slot is okay)
// 1. GC at entry of F. GC is precise, but the spills around morestack initialize X's spill slot
// 2. Stack growth at entry of F. Same as GC.
// 3. GC occurs within F itself. This has to be from preemption, and thus GC is conservative.
// a. X is in a register -- then X is seen, and the spill slot is also scanned conservatively.
// b. X is spilled -- the spill slot is initialized, and scanned conservatively
// c. X is not live -- the spill slot is scanned conservatively, and it may contain X from an earlier spill.
// 4. GC within G, transitively called from F
// a. X is live at call site, therefore is spilled, to its spill slot (which is live because of subsequent LoadReg).
// b. X is not live at call site -- but neither is its spill slot.
n, _ := ssa.AutoVar(v)
return n, ssa.SymRead
case ssa.OpVarLive:
return v.Aux.(*ir.Name), ssa.SymRead
case ssa.OpVarDef, ssa.OpVarKill:

View File

@ -517,9 +517,13 @@ func (*Value) CanBeAnSSAAux() {}
// AutoVar returns a *Name and int64 representing the auto variable and offset within it
// where v should be spilled.
func AutoVar(v *Value) (*ir.Name, int64) {
loc := v.Block.Func.RegAlloc[v.ID].(LocalSlot)
if v.Type.Size() > loc.Type.Size() {
v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
if loc, ok := v.Block.Func.RegAlloc[v.ID].(LocalSlot); ok {
if v.Type.Size() > loc.Type.Size() {
v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
}
return loc.N, loc.Off
}
return loc.N, loc.Off
// Assume it is a register, return its spill slot, which needs to be live
nameOff := v.Aux.(*AuxNameOffset)
return nameOff.Name, nameOff.Offset
}

79
test/abi/uglyfib.go Normal file
View File

@ -0,0 +1,79 @@
// run
//go:build !wasm
// +build !wasm
// Copyright 2021 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 main
import "fmt"
// This test is designed to provoke a stack growth
// in a way that very likely leaves junk in the
// parameter save area if they aren't saved or spilled
// there, as appropriate.
//go:registerparams
//go:noinline
func f(x int, xm1, xm2, p *int) {
var y = [2]int{x - 4, 0}
if x < 2 {
*p += x
return
}
x -= 3
g(*xm1, xm2, &x, p) // xm1 is no longer live.
h(*xm2, &x, &y[0], p) // xm2 is no longer live, but was spilled.
}
//go:registerparams
//go:noinline
func g(x int, xm1, xm2, p *int) {
var y = [3]int{x - 4, 0, 0}
if x < 2 {
*p += x
return
}
x -= 3
k(*xm2, &x, &y[0], p)
h(*xm1, xm2, &x, p)
}
//go:registerparams
//go:noinline
func h(x int, xm1, xm2, p *int) {
var y = [4]int{x - 4, 0, 0, 0}
if x < 2 {
*p += x
return
}
x -= 3
k(*xm1, xm2, &x, p)
f(*xm2, &x, &y[0], p)
}
//go:registerparams
//go:noinline
func k(x int, xm1, xm2, p *int) {
var y = [5]int{x - 4, 0, 0, 0, 0}
if x < 2 {
*p += x
return
}
x -= 3
f(*xm2, &x, &y[0], p)
g(*xm1, xm2, &x, p)
}
func main() {
x := 40
var y int
xm1 := x - 1
xm2 := x - 2
f(x, &xm1, &xm2, &y)
fmt.Printf("Fib(%d)=%d\n", x, y)
}

1
test/abi/uglyfib.out Normal file
View File

@ -0,0 +1 @@
Fib(40)=102334155