Commit d7d9df8a authored by Austin Clements's avatar Austin Clements

cmd/compile: introduce LivenessMap and LivenessIndex

Currently liveness only produces a stack map index at each safe point,
so the information is summarized in a map[*ssa.Value]int. We're about
to have both a stack map index and a register map index, so replace
the int with a LivenessIndex type we can extend, and replace the map
with a LivenessMap that we can also change more easily in the future.

This also gives us an easy hook for defining the value that means "not
a safe point".

Passes toolstash -cmp.

For #24543.

Change-Id: Ic4c069839635efed4fd0f603899b80f8be3b56ec
Reviewed-on: https://go-review.googlesource.com/109347
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent 02495da6
...@@ -120,14 +120,42 @@ type Liveness struct { ...@@ -120,14 +120,42 @@ type Liveness struct {
// Indexed sequentially by safe points in Block and Value order. // Indexed sequentially by safe points in Block and Value order.
livevars []bvec livevars []bvec
// stackMapIndex maps from safe points (i.e., CALLs) to their // livenessMap maps from safe points (i.e., CALLs) to their
// index within stackMaps. // liveness map indexes.
stackMapIndex map[*ssa.Value]int //
// TODO(austin): Now that we have liveness at almost every PC,
// should this be a dense structure?
livenessMap LivenessMap
stackMaps []bvec stackMaps []bvec
cache progeffectscache cache progeffectscache
} }
// LivenessMap maps from *ssa.Value to LivenessIndex.
type LivenessMap struct {
m map[*ssa.Value]LivenessIndex
}
func (m LivenessMap) Get(v *ssa.Value) LivenessIndex {
if i, ok := m.m[v]; ok {
return i
}
// Not a safe point.
return LivenessInvalid
}
// LivenessIndex stores the liveness map index for a safe-point.
type LivenessIndex struct {
stackMapIndex int
}
// LivenessInvalid indicates an unsafe point.
var LivenessInvalid = LivenessIndex{-1}
func (idx LivenessIndex) Valid() bool {
return idx.stackMapIndex >= 0
}
type progeffectscache struct { type progeffectscache struct {
textavarinit []int32 textavarinit []int32
retuevar []int32 retuevar []int32
...@@ -817,10 +845,10 @@ func (lv *Liveness) clobber() { ...@@ -817,10 +845,10 @@ func (lv *Liveness) clobber() {
before = false before = false
} }
if before { if before {
clobber(lv, b, lv.stackMaps[lv.stackMapIndex[v]]) clobber(lv, b, lv.stackMaps[lv.livenessMap.Get(v).stackMapIndex])
} }
b.Values = append(b.Values, v) b.Values = append(b.Values, v)
clobber(lv, b, lv.stackMaps[lv.stackMapIndex[v]]) clobber(lv, b, lv.stackMaps[lv.livenessMap.Get(v).stackMapIndex])
} }
} }
} }
...@@ -1006,12 +1034,12 @@ Outer: ...@@ -1006,12 +1034,12 @@ Outer:
// These will later become PCDATA instructions. // These will later become PCDATA instructions.
lv.showlive(nil, lv.stackMaps[0]) lv.showlive(nil, lv.stackMaps[0])
pos := 1 pos := 1
lv.stackMapIndex = make(map[*ssa.Value]int) lv.livenessMap = LivenessMap{make(map[*ssa.Value]LivenessIndex)}
for _, b := range lv.f.Blocks { for _, b := range lv.f.Blocks {
for _, v := range b.Values { for _, v := range b.Values {
if issafepoint(v) { if issafepoint(v) {
lv.showlive(v, lv.stackMaps[remap[pos]]) lv.showlive(v, lv.stackMaps[remap[pos]])
lv.stackMapIndex[v] = remap[pos] lv.livenessMap.m[v] = LivenessIndex{remap[pos]}
pos++ pos++
} }
} }
...@@ -1153,8 +1181,8 @@ func (lv *Liveness) printDebug() { ...@@ -1153,8 +1181,8 @@ func (lv *Liveness) printDebug() {
for _, v := range b.Values { for _, v := range b.Values {
fmt.Printf("(%s) %v\n", linestr(v.Pos), v.LongString()) fmt.Printf("(%s) %v\n", linestr(v.Pos), v.LongString())
if pos, ok := lv.stackMapIndex[v]; ok { if pos := lv.livenessMap.Get(v); pos.Valid() {
pcdata = pos pcdata = pos.stackMapIndex
} }
pos, effect := lv.valueEffects(v) pos, effect := lv.valueEffects(v)
...@@ -1265,7 +1293,7 @@ func (lv *Liveness) emit(argssym, livesym *obj.LSym) { ...@@ -1265,7 +1293,7 @@ func (lv *Liveness) emit(argssym, livesym *obj.LSym) {
// pointer variables in the function and emits a runtime data // pointer variables in the function and emits a runtime data
// structure read by the garbage collector. // structure read by the garbage collector.
// Returns a map from GC safe points to their corresponding stack map index. // Returns a map from GC safe points to their corresponding stack map index.
func liveness(e *ssafn, f *ssa.Func) map[*ssa.Value]int { func liveness(e *ssafn, f *ssa.Func) LivenessMap {
// Construct the global liveness state. // Construct the global liveness state.
vars, idx := getvariables(e.curfn) vars, idx := getvariables(e.curfn)
lv := newliveness(e.curfn, f, vars, idx, e.stkptrsize) lv := newliveness(e.curfn, f, vars, idx, e.stkptrsize)
...@@ -1284,5 +1312,5 @@ func liveness(e *ssafn, f *ssa.Func) map[*ssa.Value]int { ...@@ -1284,5 +1312,5 @@ func liveness(e *ssafn, f *ssa.Func) map[*ssa.Value]int {
if ls := e.curfn.Func.lsym; ls != nil { if ls := e.curfn.Func.lsym; ls != nil {
lv.emit(&ls.Func.GCArgs, &ls.Func.GCLocals) lv.emit(&ls.Func.GCArgs, &ls.Func.GCLocals)
} }
return lv.stackMapIndex return lv.livenessMap
} }
...@@ -4694,9 +4694,9 @@ type SSAGenState struct { ...@@ -4694,9 +4694,9 @@ type SSAGenState struct {
maxarg int64 // largest frame size for arguments to calls made by the function maxarg int64 // largest frame size for arguments to calls made by the function
// Map from GC safe points to stack map index, generated by // Map from GC safe points to liveness index, generated by
// liveness analysis. // liveness analysis.
stackMapIndex map[*ssa.Value]int livenessMap LivenessMap
// lineRunStart records the beginning of the current run of instructions // lineRunStart records the beginning of the current run of instructions
// within a single block sharing the same line number // within a single block sharing the same line number
...@@ -4772,7 +4772,7 @@ func genssa(f *ssa.Func, pp *Progs) { ...@@ -4772,7 +4772,7 @@ func genssa(f *ssa.Func, pp *Progs) {
e := f.Frontend().(*ssafn) e := f.Frontend().(*ssafn)
s.stackMapIndex = liveness(e, f) s.livenessMap = liveness(e, f)
// Remember where each block starts. // Remember where each block starts.
s.bstart = make([]*obj.Prog, f.NumBlocks()) s.bstart = make([]*obj.Prog, f.NumBlocks())
...@@ -5270,13 +5270,13 @@ func (s *SSAGenState) Call(v *ssa.Value) *obj.Prog { ...@@ -5270,13 +5270,13 @@ func (s *SSAGenState) Call(v *ssa.Value) *obj.Prog {
// It must be called immediately before emitting the actual CALL instruction, // It must be called immediately before emitting the actual CALL instruction,
// since it emits PCDATA for the stack map at the call (calls are safe points). // since it emits PCDATA for the stack map at the call (calls are safe points).
func (s *SSAGenState) PrepareCall(v *ssa.Value) { func (s *SSAGenState) PrepareCall(v *ssa.Value) {
idx, ok := s.stackMapIndex[v] idx := s.livenessMap.Get(v)
if !ok { if !idx.Valid() {
Fatalf("missing stack map index for %v", v.LongString()) Fatalf("missing stack map index for %v", v.LongString())
} }
p := s.Prog(obj.APCDATA) p := s.Prog(obj.APCDATA)
Addrconst(&p.From, objabi.PCDATA_StackMapIndex) Addrconst(&p.From, objabi.PCDATA_StackMapIndex)
Addrconst(&p.To, int64(idx)) Addrconst(&p.To, int64(idx.stackMapIndex))
if sym, _ := v.Aux.(*obj.LSym); sym == Deferreturn { if sym, _ := v.Aux.(*obj.LSym); sym == Deferreturn {
// Deferred calls will appear to be returning to // Deferred calls will appear to be returning to
......
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