1
0
mirror of https://github.com/golang/go synced 2024-09-23 17:10:13 -06:00

[dev.regabi] cmd/compile: move stack objects to liveness

Calculating and emitting stack objects are essentially part of
liveness analysis, so move the code from ssagen to liveness. Allows
unexporting liveness.ShouldTrack.

Passes toolstash -cmp.

Change-Id: I88b5b2e75b8dfb46b8b03a2fa09a9236865cbf3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/284413
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Matthew Dempsky 2021-01-17 22:05:50 -08:00
parent 6113db0bb4
commit 422f38fb6c
2 changed files with 50 additions and 53 deletions

View File

@ -17,12 +17,14 @@ package liveness
import (
"crypto/md5"
"fmt"
"sort"
"strings"
"cmd/compile/internal/base"
"cmd/compile/internal/bitvec"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw"
"cmd/compile/internal/reflectdata"
"cmd/compile/internal/ssa"
"cmd/compile/internal/typebits"
"cmd/compile/internal/types"
@ -174,13 +176,13 @@ type progeffectscache struct {
initialized bool
}
// ShouldTrack reports whether the liveness analysis
// shouldTrack reports whether the liveness analysis
// should track the variable n.
// We don't care about variables that have no pointers,
// nor do we care about non-local variables,
// nor do we care about empty structs (handled by the pointer check),
// nor do we care about the fake PAUTOHEAP variables.
func ShouldTrack(n *ir.Name) bool {
func shouldTrack(n *ir.Name) bool {
return (n.Class == ir.PAUTO && n.Esc() != ir.EscHeap || n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT) && n.Type().HasPointers()
}
@ -189,7 +191,7 @@ func ShouldTrack(n *ir.Name) bool {
func getvariables(fn *ir.Func) ([]*ir.Name, map[*ir.Name]int32) {
var vars []*ir.Name
for _, n := range fn.Dcl {
if ShouldTrack(n) {
if shouldTrack(n) {
vars = append(vars, n)
}
}
@ -1179,9 +1181,54 @@ func Compute(curfn *ir.Func, f *ssa.Func, stkptrsize int64, pp *objw.Progs) Map
p.To.Name = obj.NAME_EXTERN
p.To.Sym = fninfo.GCLocals
if x := lv.emitStackObjects(); x != nil {
p := pp.Prog(obj.AFUNCDATA)
p.From.SetConst(objabi.FUNCDATA_StackObjects)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = x
}
return lv.livenessMap
}
func (lv *liveness) emitStackObjects() *obj.LSym {
var vars []*ir.Name
for _, n := range lv.fn.Dcl {
if shouldTrack(n) && n.Addrtaken() && n.Esc() != ir.EscHeap {
vars = append(vars, n)
}
}
if len(vars) == 0 {
return nil
}
// Sort variables from lowest to highest address.
sort.Slice(vars, func(i, j int) bool { return vars[i].FrameOffset() < vars[j].FrameOffset() })
// Populate the stack object data.
// Format must match runtime/stack.go:stackObjectRecord.
x := base.Ctxt.Lookup(lv.fn.LSym.Name + ".stkobj")
lv.fn.LSym.Func().StackObjects = x
off := 0
off = objw.Uintptr(x, off, uint64(len(vars)))
for _, v := range vars {
// Note: arguments and return values have non-negative Xoffset,
// in which case the offset is relative to argp.
// Locals have a negative Xoffset, in which case the offset is relative to varp.
off = objw.Uintptr(x, off, uint64(v.FrameOffset()))
off = objw.SymPtr(x, off, reflectdata.TypeLinksym(v.Type()), 0)
}
if base.Flag.Live != 0 {
for _, v := range vars {
base.WarnfAt(v.Pos(), "stack object %v %v", v, v.Type())
}
}
return x
}
// isfat reports whether a variable of type t needs multiple assignments to initialize.
// For example:
//

View File

@ -6467,55 +6467,6 @@ func (s *State) DebugFriendlySetPosFrom(v *ssa.Value) {
}
}
// byXoffset implements sort.Interface for []*ir.Name using Xoffset as the ordering.
type byXoffset []*ir.Name
func (s byXoffset) Len() int { return len(s) }
func (s byXoffset) Less(i, j int) bool { return s[i].FrameOffset() < s[j].FrameOffset() }
func (s byXoffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func emitStackObjects(e *ssafn, pp *objw.Progs) {
var vars []*ir.Name
for _, n := range e.curfn.Dcl {
if liveness.ShouldTrack(n) && n.Addrtaken() && n.Esc() != ir.EscHeap {
vars = append(vars, n)
}
}
if len(vars) == 0 {
return
}
// Sort variables from lowest to highest address.
sort.Sort(byXoffset(vars))
// Populate the stack object data.
// Format must match runtime/stack.go:stackObjectRecord.
x := base.Ctxt.Lookup(e.curfn.LSym.Name + ".stkobj")
e.curfn.LSym.Func().StackObjects = x
off := 0
off = objw.Uintptr(x, off, uint64(len(vars)))
for _, v := range vars {
// Note: arguments and return values have non-negative Xoffset,
// in which case the offset is relative to argp.
// Locals have a negative Xoffset, in which case the offset is relative to varp.
off = objw.Uintptr(x, off, uint64(v.FrameOffset()))
off = objw.SymPtr(x, off, reflectdata.TypeLinksym(v.Type()), 0)
}
// Emit a funcdata pointing at the stack object data.
p := pp.Prog(obj.AFUNCDATA)
p.From.SetConst(objabi.FUNCDATA_StackObjects)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = x
if base.Flag.Live != 0 {
for _, v := range vars {
base.WarnfAt(v.Pos(), "stack object %v %s", v, v.Type().String())
}
}
}
// genssa appends entries to pp for each instruction in f.
func genssa(f *ssa.Func, pp *objw.Progs) {
var s State
@ -6523,7 +6474,6 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
e := f.Frontend().(*ssafn)
s.livenessMap = liveness.Compute(e.curfn, f, e.stkptrsize, pp)
emitStackObjects(e, pp)
openDeferInfo := e.curfn.LSym.Func().OpenCodedDeferInfo
if openDeferInfo != nil {