Commit e181852d authored by Heschi Kreinick's avatar Heschi Kreinick

cmd/compile/internal: use sparseSet, optimize isSynthetic

changedVars was functionally a set, but couldn't be iterated over
efficiently. In functions with many variables, the wasted iteration was
costly. Use a sparseSet instead.

(*gc.Node).String() is very expensive: it calls Sprintf, which does
reflection, etc, etc. Instead, just look at .Sym.Name, which is all we
care about.

Change-Id: Ib61cd7b5c796e1813b8859135e85da5bfe2ac686
Reviewed-on: https://go-review.googlesource.com/92402Reviewed-by: default avatarDavid Chase <drchase@google.com>
parent 108efc79
...@@ -59,6 +59,11 @@ type Node struct { ...@@ -59,6 +59,11 @@ type Node struct {
Etype types.EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg, ChanDir for OTCHAN, for OINDEXMAP 1=LHS,0=RHS Etype types.EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg, ChanDir for OTCHAN, for OINDEXMAP 1=LHS,0=RHS
} }
func (n *Node) IsSynthetic() bool {
name := n.Sym.Name
return name[0] == '.' || name[0] == '~'
}
// IsAutoTmp indicates if n was created by the compiler as a temporary, // IsAutoTmp indicates if n was created by the compiler as a temporary,
// based on the setting of the .AutoTemp flag in n's Name. // based on the setting of the .AutoTemp flag in n's Name.
func (n *Node) IsAutoTmp() bool { func (n *Node) IsAutoTmp() bool {
......
...@@ -142,6 +142,7 @@ type Frontend interface { ...@@ -142,6 +142,7 @@ type Frontend interface {
type GCNode interface { type GCNode interface {
Typ() *types.Type Typ() *types.Type
String() string String() string
IsSynthetic() bool
StorageClass() StorageClass StorageClass() StorageClass
} }
......
...@@ -183,7 +183,7 @@ type debugState struct { ...@@ -183,7 +183,7 @@ type debugState struct {
// The current state of whatever analysis is running. // The current state of whatever analysis is running.
currentState stateAtPC currentState stateAtPC
liveCount []int liveCount []int
changedVars []bool changedVars *sparseSet
} }
func (state *debugState) initializeCache() { func (state *debugState) initializeCache() {
...@@ -226,7 +226,7 @@ func (state *debugState) initializeCache() { ...@@ -226,7 +226,7 @@ func (state *debugState) initializeCache() {
state.liveCount = make([]int, len(state.slots)) state.liveCount = make([]int, len(state.slots))
// A relatively small slice, but used many times as the return from processValue. // A relatively small slice, but used many times as the return from processValue.
state.changedVars = make([]bool, len(state.vars)) state.changedVars = newSparseSet(len(state.vars))
// A pending entry per user variable, with space to track each of its pieces. // A pending entry per user variable, with space to track each of its pieces.
nPieces := 0 nPieces := 0
...@@ -310,7 +310,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu ...@@ -310,7 +310,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
for i, slot := range f.Names { for i, slot := range f.Names {
slot := slot slot := slot
state.slots[i] = &slot state.slots[i] = &slot
if isSynthetic(&slot) { if slot.N.IsSynthetic() {
continue continue
} }
...@@ -338,7 +338,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu ...@@ -338,7 +338,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
state.initializeCache() state.initializeCache()
for i, slot := range f.Names { for i, slot := range f.Names {
if isSynthetic(&slot) { if slot.N.IsSynthetic() {
continue continue
} }
for _, value := range f.NamedValues[slot] { for _, value := range f.NamedValues[slot] {
...@@ -357,13 +357,6 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu ...@@ -357,13 +357,6 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
} }
} }
// isSynthetic reports whether if slot represents a compiler-inserted variable,
// e.g. an autotmp or an anonymous return value that needed a stack slot.
func isSynthetic(slot *LocalSlot) bool {
c := slot.N.String()[0]
return c == '.' || c == '~'
}
// liveness walks the function in control flow order, calculating the start // liveness walks the function in control flow order, calculating the start
// and end state of each block. // and end state of each block.
func (state *debugState) liveness() []*BlockDebug { func (state *debugState) liveness() []*BlockDebug {
...@@ -519,16 +512,15 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([ ...@@ -519,16 +512,15 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([
// A slot is live if it was seen in all predecessors, and they all had // A slot is live if it was seen in all predecessors, and they all had
// some storage in common. // some storage in common.
for slotID, slotLoc := range slotLocs { for slotID := range p0 {
// Not seen in any predecessor. slotLoc := slotLocs[slotID]
if slotLoc.absent() {
continue
}
// Seen in only some predecessors. Clear it out.
if state.liveCount[slotID] != len(preds) { if state.liveCount[slotID] != len(preds) {
// Seen in only some predecessors. Clear it out.
slotLocs[slotID] = VarLoc{} slotLocs[slotID] = VarLoc{}
continue continue
} }
// Present in all predecessors. // Present in all predecessors.
mask := uint64(slotLoc.Registers) mask := uint64(slotLoc.Registers)
for { for {
...@@ -553,7 +545,7 @@ func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register) ...@@ -553,7 +545,7 @@ func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register)
changed := false changed := false
setSlot := func(slot SlotID, loc VarLoc) { setSlot := func(slot SlotID, loc VarLoc) {
changed = true changed = true
state.changedVars[state.slotVars[slot]] = true state.changedVars.add(ID(state.slotVars[slot]))
state.currentState.slots[slot] = loc state.currentState.slots[slot] = loc
} }
...@@ -860,13 +852,10 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe ...@@ -860,13 +852,10 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe
} }
phisPending = false phisPending = false
for varID := range state.changedVars { for _, varID := range state.changedVars.contents() {
if !state.changedVars[varID] {
continue
}
state.changedVars[varID] = false
updateVar(VarID(varID), v, state.currentState.slots) updateVar(VarID(varID), v, state.currentState.slots)
} }
state.changedVars.clear()
} }
} }
......
...@@ -79,6 +79,10 @@ func (d *DummyAuto) StorageClass() StorageClass { ...@@ -79,6 +79,10 @@ func (d *DummyAuto) StorageClass() StorageClass {
return ClassAuto return ClassAuto
} }
func (d *DummyAuto) IsSynthetic() bool {
return false
}
func (DummyFrontend) StringData(s string) interface{} { func (DummyFrontend) StringData(s string) interface{} {
return nil return nil
} }
......
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