Commit a306341d authored by Heschi Kreinick's avatar Heschi Kreinick

cmd/compile/internal/ssa: don't store block start states

Keeping the start state of each block around costs more than just
recomputing them as necessary, especially because many blocks only have
one predecessor and don't need any merging at all. Stop storing the
start state, and reuse predecessors' end states as much as conveniently
possible.

Change-Id: I549bad9e1a35af76a974e46fe69f74cd4dce873b
Reviewed-on: https://go-review.googlesource.com/92399Reviewed-by: default avatarDavid Chase <drchase@google.com>
parent 0cacc4d0
......@@ -33,12 +33,7 @@ type FuncDebug struct {
}
type BlockDebug struct {
// The SSA block that this tracks. For debug logging only.
Block *Block
// State at entry to the block. Both this and endState are immutable
// once initialized.
startState []liveSlot
// State at the end of the block if it's fully processed.
// State at the end of the block if it's fully processed. Immutable once initialized.
endState []liveSlot
}
......@@ -85,11 +80,10 @@ func (state *stateAtPC) reset(live []liveSlot) {
state.slots, state.registers = slots, registers
}
func (b *BlockDebug) LocString(loc VarLoc) string {
func (s *debugState) LocString(loc VarLoc) string {
if loc.absent() {
return "<nil>"
}
registers := b.Block.Func.Config.registers
var storage []string
if loc.OnStack {
......@@ -104,11 +98,7 @@ func (b *BlockDebug) LocString(loc VarLoc) string {
reg := uint8(TrailingZeros64(mask))
mask &^= 1 << reg
if registers != nil {
storage = append(storage, registers[reg].String())
} else {
storage = append(storage, fmt.Sprintf("reg%d", reg))
}
storage = append(storage, s.registers[reg].String())
}
if len(storage) == 0 {
storage = append(storage, "!!!no storage!!!")
......@@ -249,14 +239,14 @@ func (state *debugState) allocBlock(b *Block) *BlockDebug {
func (s *debugState) blockEndStateString(b *BlockDebug) string {
endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.slots))}
endState.reset(b.endState)
return s.stateString(b, endState)
return s.stateString(endState)
}
func (s *debugState) stateString(b *BlockDebug, state stateAtPC) string {
func (s *debugState) stateString(state stateAtPC) string {
var strs []string
for slotID, loc := range state.slots {
if !loc.absent() {
strs = append(strs, fmt.Sprintf("\t%v = %v\n", s.slots[slotID], b.LocString(loc)))
strs = append(strs, fmt.Sprintf("\t%v = %v\n", s.slots[slotID], s.LocString(loc)))
}
}
......@@ -366,10 +356,10 @@ func (state *debugState) liveness() []*BlockDebug {
// Build the starting state for the block from the final
// state of its predecessors.
locs := state.mergePredecessors(b, blockLocs)
startState, startValid := state.mergePredecessors(b, blockLocs)
changed := false
if state.loggingEnabled {
state.logf("Processing %v, initial state:\n%v", b, state.stateString(locs, state.currentState))
state.logf("Processing %v, initial state:\n%v", b, state.stateString(state.currentState))
}
// Update locs/registers with the effects of each Value.
......@@ -404,11 +394,12 @@ func (state *debugState) liveness() []*BlockDebug {
}
if state.loggingEnabled {
state.f.Logf("Block %v done, locs:\n%v", b, state.stateString(locs, state.currentState))
state.f.Logf("Block %v done, locs:\n%v", b, state.stateString(state.currentState))
}
if !changed {
locs.endState = locs.startState
locs := state.allocBlock(b)
if !changed && startValid {
locs.endState = startState
} else {
for slotID, slotLoc := range state.currentState.slots {
if slotLoc.absent() {
......@@ -426,14 +417,10 @@ func (state *debugState) liveness() []*BlockDebug {
// mergePredecessors takes the end state of each of b's predecessors and
// intersects them to form the starting state for b. It returns that state in
// the BlockDebug, and fills state.currentState with it.
func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *BlockDebug {
result := state.allocBlock(b)
if state.loggingEnabled {
result.Block = b
}
func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([]liveSlot, bool) {
// Filter out back branches.
var preds []*Block
var predsBuf [10]*Block
preds := predsBuf[:0]
for _, pred := range b.Preds {
if blockLocs[pred.b.ID] != nil {
preds = append(preds, pred.b)
......@@ -441,21 +428,24 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B
}
if state.loggingEnabled {
state.logf("Merging %v into %v\n", preds, b)
// The logf below would cause preds to be heap-allocated if
// it were passed directly.
preds2 := make([]*Block, len(preds))
copy(preds2, preds)
state.logf("Merging %v into %v\n", preds2, b)
}
if len(preds) == 0 {
if state.loggingEnabled {
}
state.currentState.reset(nil)
return result
return nil, true
}
p0 := blockLocs[preds[0].ID].endState
if len(preds) == 1 {
result.startState = p0
state.currentState.reset(p0)
return result
return p0, true
}
if state.loggingEnabled {
......@@ -497,9 +487,8 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B
if state.loggingEnabled {
state.logf("After merge, %v matches %v exactly.\n", b, preds[0])
}
result.startState = p0
state.currentState.reset(p0)
return result
return p0, true
}
for reg := range state.currentState.registers {
......@@ -519,10 +508,6 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B
continue
}
// Present in all predecessors.
state.cache.AppendLiveSlot(liveSlot{SlotID(slotID), slotLoc})
if slotLoc.Registers == 0 {
continue
}
mask := uint64(slotLoc.Registers)
for {
if mask == 0 {
......@@ -534,8 +519,7 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B
state.currentState.registers[reg] = append(state.currentState.registers[reg], SlotID(slotID))
}
}
result.startState = state.cache.GetLiveSlotSlice()
return result
return nil, false
}
// processValue updates locs and state.registerContents to reflect v, a value with
......@@ -753,7 +737,7 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe
if state.loggingEnabled {
var partStrs []string
for _, slot := range state.varSlots[varID] {
partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], blockLocs[endBlock].LocString(pending.pieces[slot])))
partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[slot])))
}
state.logf("Add entry for %v: \tb%vv%v-b%vv%v = \t%v\n", state.vars[varID], pending.startBlock, pending.startValue, endBlock, endValue, strings.Join(partStrs, " "))
}
......@@ -834,7 +818,7 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe
// Run through the function in program text order, building up location
// lists as we go. The heavy lifting has mostly already been done.
for _, b := range state.f.Blocks {
state.currentState.reset(blockLocs[b.ID].startState)
state.mergePredecessors(b, blockLocs)
phisPending := false
for _, v := range b.Values {
......
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