From 46ba59025f527b2cfc5ef0d5ec47be45971ba672 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 20 Jul 2016 10:09:40 -0400 Subject: [PATCH] cmd/compile: label LoadReg with line number of the use A tentative fix of #16380. It adds "line" everywhere... This also reduces binary size slightly (cmd/go on ARM as an example): before after total binary size 8068097 8018945 (-0.6%) .gopclntab 1195341 1179929 (-1.3%) .debug_line 689692 652017 (-5.5%) Change-Id: Ibda657c6999783c5bac180cbbba487006dbf0ed7 Reviewed-on: https://go-review.googlesource.com/25082 Reviewed-by: David Chase Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/ssa/deadstore.go | 2 +- src/cmd/compile/internal/ssa/regalloc.go | 83 ++++++++++++----------- src/cmd/compile/internal/ssa/sparsemap.go | 8 ++- 3 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go index 3386a227ed..89ab17a427 100644 --- a/src/cmd/compile/internal/ssa/deadstore.go +++ b/src/cmd/compile/internal/ssa/deadstore.go @@ -111,7 +111,7 @@ func dse(f *Func) { if sz > 0x7fffffff { // work around sparseMap's int32 value type sz = 0x7fffffff } - shadowed.set(v.Args[0].ID, int32(sz)) + shadowed.set(v.Args[0].ID, int32(sz), 0) } } // walk to previous store diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index f6a118bf22..ba4ffedc50 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -180,6 +180,7 @@ func pickReg(r regMask) register { type use struct { dist int32 // distance from start of the block to a use of a value + line int32 // line number of the use next *use // linked list of uses of a value in nondecreasing dist order } @@ -277,8 +278,9 @@ type endReg struct { } type startReg struct { - r register - vid ID // pre-regalloc value needed in this register + r register + vid ID // pre-regalloc value needed in this register + line int32 // line number of use of this register } // freeReg frees up register r. Any current user of r is kicked out. @@ -567,7 +569,7 @@ func (s *regAllocState) init(f *Func) { // Adds a use record for id at distance dist from the start of the block. // All calls to addUse must happen with nonincreasing dist. -func (s *regAllocState) addUse(id ID, dist int32) { +func (s *regAllocState) addUse(id ID, dist int32, line int32) { r := s.freeUseRecords if r != nil { s.freeUseRecords = r.next @@ -575,6 +577,7 @@ func (s *regAllocState) addUse(id ID, dist int32) { r = &use{} } r.dist = dist + r.line = line r.next = s.values[id].uses s.values[id].uses = r if r.next != nil && dist > r.next.dist { @@ -701,11 +704,11 @@ func (s *regAllocState) regalloc(f *Func) { // Walk backwards through the block doing liveness analysis. liveSet.clear() for _, e := range s.live[b.ID] { - s.addUse(e.ID, int32(len(b.Values))+e.dist) // pseudo-uses from beyond end of block + s.addUse(e.ID, int32(len(b.Values))+e.dist, e.line) // pseudo-uses from beyond end of block liveSet.add(e.ID) } if v := b.Control; v != nil && s.values[v.ID].needReg { - s.addUse(v.ID, int32(len(b.Values))) // psuedo-use by control value + s.addUse(v.ID, int32(len(b.Values)), b.Line) // psuedo-use by control value liveSet.add(v.ID) } for i := len(b.Values) - 1; i >= 0; i-- { @@ -721,7 +724,7 @@ func (s *regAllocState) regalloc(f *Func) { if !s.values[a.ID].needReg { continue } - s.addUse(a.ID, int32(i)) + s.addUse(a.ID, int32(i), v.Line) liveSet.add(a.ID) } } @@ -893,7 +896,7 @@ func (s *regAllocState) regalloc(f *Func) { // specially during merge edge processing. continue } - regList = append(regList, startReg{r, v.ID}) + regList = append(regList, startReg{r, v.ID, s.values[v.ID].uses.line}) } s.startRegs[b.ID] = regList @@ -1747,12 +1750,14 @@ type contentRecord struct { vid ID // pre-regalloc value c *Value // cached value final bool // this is a satisfied destination + line int32 // line number of use of the value } type dstRecord struct { loc Location // register or stack slot vid ID // pre-regalloc value it should contain splice **Value // place to store reference to the generating instruction + line int32 // line number of use of this location } // setup initializes the edge state for shuffling. @@ -1775,19 +1780,19 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive // Live registers can be sources. for _, x := range srcReg { - e.set(&e.s.registers[x.r], x.v.ID, x.c, false) + e.set(&e.s.registers[x.r], x.v.ID, x.c, false, 0) // don't care the line number of the source } // So can all of the spill locations. for _, spillID := range stacklive { v := e.s.orig[spillID] spill := e.s.values[v.ID].spill - e.set(e.s.f.getHome(spillID), v.ID, spill, false) + e.set(e.s.f.getHome(spillID), v.ID, spill, false, 0) // don't care the line number of the source } // Figure out all the destinations we need. dsts := e.destinations[:0] for _, x := range dstReg { - dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil}) + dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil, x.line}) } // Phis need their args to end up in a specific location. for _, v := range e.b.Values { @@ -1798,7 +1803,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive if loc == nil { continue } - dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx]}) + dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Line}) } e.destinations = dsts @@ -1823,7 +1828,7 @@ func (e *edgeState) process() { for len(dsts) > 0 { i := 0 for _, d := range dsts { - if !e.processDest(d.loc, d.vid, d.splice) { + if !e.processDest(d.loc, d.vid, d.splice, d.line) { // Failed - save for next iteration. dsts[i] = d i++ @@ -1861,7 +1866,8 @@ func (e *edgeState) process() { // Copy any cycle location to a temp register. This duplicates // one of the cycle entries, allowing the just duplicated value // to be overwritten and the cycle to proceed. - loc := dsts[0].loc + d := dsts[0] + loc := d.loc vid := e.contents[loc].vid c := e.contents[loc].c r := e.findRegFor(c.Type) @@ -1869,22 +1875,22 @@ func (e *edgeState) process() { fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c) } if _, isReg := loc.(*Register); isReg { - c = e.p.NewValue1(c.Line, OpCopy, c.Type, c) + c = e.p.NewValue1(d.line, OpCopy, c.Type, c) } else { e.s.lateSpillUse(vid) - c = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c) + c = e.p.NewValue1(d.line, OpLoadReg, c.Type, c) } - e.set(r, vid, c, false) + e.set(r, vid, c, false, d.line) } } // processDest generates code to put value vid into location loc. Returns true // if progress was made. -func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool { +func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32) bool { occupant := e.contents[loc] if occupant.vid == vid { // Value is already in the correct place. - e.contents[loc] = contentRecord{vid, occupant.c, true} + e.contents[loc] = contentRecord{vid, occupant.c, true, line} if splice != nil { (*splice).Uses-- *splice = occupant.c @@ -1946,25 +1952,25 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool { e.erase(loc) // see pre-clobber comment below r := e.findRegFor(v.Type) x = v.copyInto(e.p) - e.set(r, vid, x, false) + e.set(r, vid, x, false, line) // Make sure we spill with the size of the slot, not the // size of x (which might be wider due to our dropping // of narrowing conversions). - x = e.p.NewValue1(x.Line, OpStoreReg, loc.(LocalSlot).Type, x) + x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, x) } } else { // Emit move from src to dst. _, srcReg := src.(*Register) if srcReg { if dstReg { - x = e.p.NewValue1(c.Line, OpCopy, c.Type, c) + x = e.p.NewValue1(line, OpCopy, c.Type, c) } else { - x = e.p.NewValue1(c.Line, OpStoreReg, loc.(LocalSlot).Type, c) + x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, c) } } else { if dstReg { e.s.lateSpillUse(vid) - x = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c) + x = e.p.NewValue1(line, OpLoadReg, c.Type, c) } else { // mem->mem. Use temp register. @@ -1982,13 +1988,13 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool { r := e.findRegFor(c.Type) e.s.lateSpillUse(vid) - t := e.p.NewValue1(c.Line, OpLoadReg, c.Type, c) - e.set(r, vid, t, false) - x = e.p.NewValue1(c.Line, OpStoreReg, loc.(LocalSlot).Type, t) + t := e.p.NewValue1(line, OpLoadReg, c.Type, c) + e.set(r, vid, t, false, line) + x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, t) } } } - e.set(loc, vid, x, true) + e.set(loc, vid, x, true, line) if splice != nil { (*splice).Uses-- *splice = x @@ -1998,10 +2004,10 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool { } // set changes the contents of location loc to hold the given value and its cached representative. -func (e *edgeState) set(loc Location, vid ID, c *Value, final bool) { +func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, line int32) { e.s.f.setHome(c, loc) e.erase(loc) - e.contents[loc] = contentRecord{vid, c, final} + e.contents[loc] = contentRecord{vid, c, final, line} a := e.cache[vid] if len(a) == 0 { e.cachedVals = append(e.cachedVals, vid) @@ -2040,7 +2046,7 @@ func (e *edgeState) erase(loc Location) { // Add a destination to move this value back into place. // Make sure it gets added to the tail of the destination queue // so we make progress on other moves first. - e.extra = append(e.extra, dstRecord{loc, cr.vid, nil}) + e.extra = append(e.extra, dstRecord{loc, cr.vid, nil, cr.line}) } // Remove c from the list of cached values. @@ -2110,7 +2116,7 @@ func (e *edgeState) findRegFor(typ Type) Location { for _, c := range a { if r, ok := e.s.f.getHome(c.ID).(*Register); ok && m>>uint(r.Num)&1 != 0 { x := e.p.NewValue1(c.Line, OpStoreReg, c.Type, c) - e.set(t, vid, x, false) + e.set(t, vid, x, false, c.Line) if e.s.f.pass.debug > regDebug { fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString()) } @@ -2151,6 +2157,7 @@ func (v *Value) rematerializeable() bool { type liveInfo struct { ID ID // ID of value dist int32 // # of instructions before next use + line int32 // line number of next use } // dblock contains information about desired & avoid registers at the end of a block. @@ -2199,12 +2206,12 @@ func (s *regAllocState) computeLive() { // to beginning-of-block distance. live.clear() for _, e := range s.live[b.ID] { - live.set(e.ID, e.dist+int32(len(b.Values))) + live.set(e.ID, e.dist+int32(len(b.Values)), e.line) } // Mark control value as live if b.Control != nil && s.values[b.Control.ID].needReg { - live.set(b.Control.ID, int32(len(b.Values))) + live.set(b.Control.ID, int32(len(b.Values)), b.Line) } // Propagate backwards to the start of the block @@ -2226,7 +2233,7 @@ func (s *regAllocState) computeLive() { } for _, a := range v.Args { if s.values[a.ID].needReg { - live.set(a.ID, int32(i)) + live.set(a.ID, int32(i), v.Line) } } } @@ -2285,7 +2292,7 @@ func (s *regAllocState) computeLive() { // Start t off with the previously known live values at the end of p. t.clear() for _, e := range s.live[p.ID] { - t.set(e.ID, e.dist) + t.set(e.ID, e.dist, e.line) } update := false @@ -2294,7 +2301,7 @@ func (s *regAllocState) computeLive() { d := e.val + delta if !t.contains(e.key) || d < t.get(e.key) { update = true - t.set(e.key, d) + t.set(e.key, d, e.aux) } } // Also add the correct arg from the saved phi values. @@ -2304,7 +2311,7 @@ func (s *regAllocState) computeLive() { id := v.Args[i].ID if s.values[id].needReg && (!t.contains(id) || delta < t.get(id)) { update = true - t.set(id, delta) + t.set(id, delta, v.Line) } } @@ -2317,7 +2324,7 @@ func (s *regAllocState) computeLive() { l = make([]liveInfo, 0, t.size()) } for _, e := range t.contents() { - l = append(l, liveInfo{e.key, e.val}) + l = append(l, liveInfo{e.key, e.val, e.aux}) } s.live[p.ID] = l changed = true diff --git a/src/cmd/compile/internal/ssa/sparsemap.go b/src/cmd/compile/internal/ssa/sparsemap.go index afb9f60491..70c4f6190c 100644 --- a/src/cmd/compile/internal/ssa/sparsemap.go +++ b/src/cmd/compile/internal/ssa/sparsemap.go @@ -10,6 +10,7 @@ package ssa type sparseEntry struct { key ID val int32 + aux int32 } type sparseMap struct { @@ -42,13 +43,14 @@ func (s *sparseMap) get(k ID) int32 { return -1 } -func (s *sparseMap) set(k ID, v int32) { +func (s *sparseMap) set(k ID, v, a int32) { i := s.sparse[k] if i < int32(len(s.dense)) && s.dense[i].key == k { s.dense[i].val = v + s.dense[i].aux = a return } - s.dense = append(s.dense, sparseEntry{k, v}) + s.dense = append(s.dense, sparseEntry{k, v, a}) s.sparse[k] = int32(len(s.dense)) - 1 } @@ -62,7 +64,7 @@ func (s *sparseMap) setBit(k ID, v uint) { s.dense[i].val |= 1 << v return } - s.dense = append(s.dense, sparseEntry{k, 1 << v}) + s.dense = append(s.dense, sparseEntry{k, 1 << v, 0}) s.sparse[k] = int32(len(s.dense)) - 1 }