Commit 325904fe authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: port liveness analysis to SSA

Passes toolstash-check -all.

Change-Id: I92c3c25d6c053f971f346f4fa3bbc76419b58183
Reviewed-on: https://go-review.googlesource.com/38087
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarKeith Randall <khr@golang.org>
parent ea8c7dae
......@@ -593,7 +593,6 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
"*cmd/internal/obj.Addr %v": "",
"*cmd/internal/obj.LSym %v": "",
"*cmd/internal/obj.Prog %p": "",
"*cmd/internal/obj.Prog %s": "",
"*cmd/internal/obj.Prog %v": "",
"*math/big.Int %#x": "",
......
......@@ -282,7 +282,7 @@ func Patch(p *obj.Prog, to *obj.Prog) {
// Gins inserts instruction as. f is from, t is to.
func Gins(as obj.As, f, t *Node) *obj.Prog {
switch as {
case obj.AVARKILL, obj.AVARLIVE, obj.AVARDEF, obj.ATEXT, obj.AFUNCDATA:
case obj.ATEXT, obj.AFUNCDATA:
default:
Fatalf("unhandled gins op %v", as)
}
......
......@@ -22,14 +22,17 @@ var makefuncdatasym_nsym int
func makefuncdatasym(nameprefix string, funcdatakind int64) *Sym {
sym := lookupN(nameprefix, makefuncdatasym_nsym)
makefuncdatasym_nsym++
pnod := newname(sym)
pnod.Class = PEXTERN
p := Gins(obj.AFUNCDATA, nil, pnod)
p := Prog(obj.AFUNCDATA)
Addrconst(&p.From, funcdatakind)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = Linksym(sym)
return sym
}
// gvardef inserts a VARDEF for n into the instruction stream.
// TODO(mdempsky): Update to reference OpVar{Def,Kill,Live} instead
// and move to plive.go.
// VARDEF is an annotation for the liveness analysis, marking a place
// where a complete initialization (definition) of a variable begins.
// Since the liveness analysis can see initialization of single-word
......@@ -85,55 +88,6 @@ func makefuncdatasym(nameprefix string, funcdatakind int64) *Sym {
// that its argument is certainly dead, for use when the liveness analysis
// would not otherwise be able to deduce that fact.
func gvardefx(n *Node, as obj.As) {
if n == nil {
Fatalf("gvardef nil")
}
if n.Op != ONAME {
Fatalf("gvardef %#v; %v", n.Op, n)
return
}
switch n.Class {
case PAUTO, PPARAM, PPARAMOUT:
if !n.Used() {
Prog(obj.ANOP)
return
}
if as == obj.AVARLIVE {
Gins(as, n, nil)
} else {
Gins(as, nil, n)
}
}
}
func Gvardef(n *Node) {
gvardefx(n, obj.AVARDEF)
}
func Gvarkill(n *Node) {
gvardefx(n, obj.AVARKILL)
}
func Gvarlive(n *Node) {
gvardefx(n, obj.AVARLIVE)
}
func removevardef(firstp *obj.Prog) {
for p := firstp; p != nil; p = p.Link {
for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) {
p.Link = p.Link.Link
}
if p.To.Type == obj.TYPE_BRANCH {
for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL || p.To.Val.(*obj.Prog).As == obj.AVARLIVE) {
p.To.Val = p.To.Val.(*obj.Prog).Link
}
}
}
}
func emitptrargsmap() {
if Curfn.Func.Nname.Sym.Name == "_" {
return
......@@ -407,10 +361,7 @@ func compile(fn *Node) {
}
}
gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)
genssa(ssafn, ptxt, gcargs, gclocals)
genssa(ssafn, ptxt)
obj.Flushplist(Ctxt, plist) // convert from Prog list to machine code
ptxt = nil // nil to prevent misuse; Prog may have been freed by Flushplist
......
This diff is collapsed.
......@@ -4231,6 +4231,10 @@ type SSAGenState struct {
ScratchFpMem *Node
maxarg int64 // largest frame size for arguments to calls made by the function
// Map from GC safe points to stack map index, generated by
// liveness analysis.
stackMapIndex map[*ssa.Value]int
}
// Pc returns the current Prog.
......@@ -4244,12 +4248,16 @@ func (s *SSAGenState) SetPos(pos src.XPos) {
}
// genssa appends entries to ptxt for each instruction in f.
// gcargs and gclocals are filled in with pointer maps for the frame.
func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
func genssa(f *ssa.Func, ptxt *obj.Prog) {
var s SSAGenState
e := f.Frontend().(*ssafn)
// Generate GC bitmaps.
gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)
s.stackMapIndex = liveness(e, f, gcargs, gclocals)
// Remember where each block starts.
s.bstart = make([]*obj.Prog, f.NumBlocks())
......@@ -4291,14 +4299,8 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
case ssa.OpGetG:
// nothing to do when there's a g register,
// and checkLower complains if there's not
case ssa.OpVarDef:
Gvardef(v.Aux.(*Node))
case ssa.OpVarKill:
Gvarkill(v.Aux.(*Node))
case ssa.OpVarLive:
Gvarlive(v.Aux.(*Node))
case ssa.OpKeepAlive:
KeepAlive(v)
case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive:
// nothing to do; already used by liveness
case ssa.OpPhi:
CheckLoweredPhi(v)
......@@ -4378,18 +4380,12 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
}
}
// Generate gc bitmaps.
liveness(e, ptxt, gcargs, gclocals)
// Add frame prologue. Zero ambiguously live variables.
thearch.Defframe(ptxt, e.curfn, e.stksize+s.maxarg)
if Debug['f'] != 0 {
frame(0)
}
// Remove leftover instrumentation from the instruction stream.
removevardef(ptxt)
f.HTMLWriter.Close()
f.HTMLWriter = nil
}
......@@ -4572,26 +4568,6 @@ func CheckLoweredGetClosurePtr(v *ssa.Value) {
}
}
// KeepAlive marks the variable referenced by OpKeepAlive as live.
// Called during ssaGenValue.
func KeepAlive(v *ssa.Value) {
if v.Op != ssa.OpKeepAlive {
v.Fatalf("KeepAlive called with non-KeepAlive value: %v", v.LongString())
}
if !v.Args[0].Type.IsPtrShaped() {
v.Fatalf("keeping non-pointer alive %v", v.Args[0])
}
n, _ := AutoVar(v.Args[0])
if n == nil {
v.Fatalf("KeepAlive with non-spilled value %s %s", v, v.Args[0])
}
// Note: KeepAlive arg may be a small part of a larger variable n. We keep the
// whole variable n alive at this point. (Typically, this happens when
// we are requested to keep the idata portion of an interface{} alive, and
// we end up keeping the whole interface{} alive. That's ok.)
Gvarlive(n)
}
// AutoVar returns a *Node and int64 representing the auto variable and offset within it
// where v should be spilled.
func AutoVar(v *ssa.Value) (*Node, int64) {
......@@ -4629,6 +4605,14 @@ func (s *SSAGenState) AddrScratch(a *obj.Addr) {
}
func (s *SSAGenState) Call(v *ssa.Value) *obj.Prog {
idx, ok := s.stackMapIndex[v]
if !ok {
Fatalf("missing stack map index for %v", v.LongString())
}
p := Prog(obj.APCDATA)
Addrconst(&p.From, obj.PCDATA_StackMapIndex)
Addrconst(&p.To, int64(idx))
if sym, _ := v.Aux.(*obj.LSym); sym == Deferreturn {
// Deferred calls will appear to be returning to
// the CALL deferreturn(SB) that we are about to emit.
......@@ -4641,7 +4625,7 @@ func (s *SSAGenState) Call(v *ssa.Value) *obj.Prog {
thearch.Ginsnop()
}
p := Prog(obj.ACALL)
p = Prog(obj.ACALL)
if sym, ok := v.Aux.(*obj.LSym); ok {
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
......
......@@ -497,6 +497,10 @@ func (f *Func) postorder() []*Block {
return f.cachedPostorder
}
func (f *Func) Postorder() []*Block {
return f.postorder()
}
// Idom returns a map from block ID to the immediate dominator of that block.
// f.Entry.ID maps to nil. Unreachable blocks map to nil as well.
func (f *Func) Idom() []*Block {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment