mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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/92399 Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
0cacc4d0e2
commit
a306341db7
1 changed files with 26 additions and 42 deletions
|
|
@ -33,12 +33,7 @@ type FuncDebug struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockDebug struct {
|
type BlockDebug struct {
|
||||||
// The SSA block that this tracks. For debug logging only.
|
// State at the end of the block if it's fully processed. Immutable once initialized.
|
||||||
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.
|
|
||||||
endState []liveSlot
|
endState []liveSlot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,11 +80,10 @@ func (state *stateAtPC) reset(live []liveSlot) {
|
||||||
state.slots, state.registers = slots, registers
|
state.slots, state.registers = slots, registers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BlockDebug) LocString(loc VarLoc) string {
|
func (s *debugState) LocString(loc VarLoc) string {
|
||||||
if loc.absent() {
|
if loc.absent() {
|
||||||
return "<nil>"
|
return "<nil>"
|
||||||
}
|
}
|
||||||
registers := b.Block.Func.Config.registers
|
|
||||||
|
|
||||||
var storage []string
|
var storage []string
|
||||||
if loc.OnStack {
|
if loc.OnStack {
|
||||||
|
|
@ -104,11 +98,7 @@ func (b *BlockDebug) LocString(loc VarLoc) string {
|
||||||
reg := uint8(TrailingZeros64(mask))
|
reg := uint8(TrailingZeros64(mask))
|
||||||
mask &^= 1 << reg
|
mask &^= 1 << reg
|
||||||
|
|
||||||
if registers != nil {
|
storage = append(storage, s.registers[reg].String())
|
||||||
storage = append(storage, registers[reg].String())
|
|
||||||
} else {
|
|
||||||
storage = append(storage, fmt.Sprintf("reg%d", reg))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(storage) == 0 {
|
if len(storage) == 0 {
|
||||||
storage = append(storage, "!!!no storage!!!")
|
storage = append(storage, "!!!no storage!!!")
|
||||||
|
|
@ -249,14 +239,14 @@ func (state *debugState) allocBlock(b *Block) *BlockDebug {
|
||||||
func (s *debugState) blockEndStateString(b *BlockDebug) string {
|
func (s *debugState) blockEndStateString(b *BlockDebug) string {
|
||||||
endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.slots))}
|
endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.slots))}
|
||||||
endState.reset(b.endState)
|
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
|
var strs []string
|
||||||
for slotID, loc := range state.slots {
|
for slotID, loc := range state.slots {
|
||||||
if !loc.absent() {
|
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
|
// Build the starting state for the block from the final
|
||||||
// state of its predecessors.
|
// state of its predecessors.
|
||||||
locs := state.mergePredecessors(b, blockLocs)
|
startState, startValid := state.mergePredecessors(b, blockLocs)
|
||||||
changed := false
|
changed := false
|
||||||
if state.loggingEnabled {
|
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.
|
// Update locs/registers with the effects of each Value.
|
||||||
|
|
@ -404,11 +394,12 @@ func (state *debugState) liveness() []*BlockDebug {
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.loggingEnabled {
|
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 := state.allocBlock(b)
|
||||||
locs.endState = locs.startState
|
if !changed && startValid {
|
||||||
|
locs.endState = startState
|
||||||
} else {
|
} else {
|
||||||
for slotID, slotLoc := range state.currentState.slots {
|
for slotID, slotLoc := range state.currentState.slots {
|
||||||
if slotLoc.absent() {
|
if slotLoc.absent() {
|
||||||
|
|
@ -426,14 +417,10 @@ func (state *debugState) liveness() []*BlockDebug {
|
||||||
// mergePredecessors takes the end state of each of b's predecessors and
|
// 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
|
// intersects them to form the starting state for b. It returns that state in
|
||||||
// the BlockDebug, and fills state.currentState with it.
|
// the BlockDebug, and fills state.currentState with it.
|
||||||
func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *BlockDebug {
|
func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([]liveSlot, bool) {
|
||||||
result := state.allocBlock(b)
|
|
||||||
if state.loggingEnabled {
|
|
||||||
result.Block = b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter out back branches.
|
// Filter out back branches.
|
||||||
var preds []*Block
|
var predsBuf [10]*Block
|
||||||
|
preds := predsBuf[:0]
|
||||||
for _, pred := range b.Preds {
|
for _, pred := range b.Preds {
|
||||||
if blockLocs[pred.b.ID] != nil {
|
if blockLocs[pred.b.ID] != nil {
|
||||||
preds = append(preds, pred.b)
|
preds = append(preds, pred.b)
|
||||||
|
|
@ -441,21 +428,24 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.loggingEnabled {
|
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 len(preds) == 0 {
|
||||||
if state.loggingEnabled {
|
if state.loggingEnabled {
|
||||||
}
|
}
|
||||||
state.currentState.reset(nil)
|
state.currentState.reset(nil)
|
||||||
return result
|
return nil, true
|
||||||
}
|
}
|
||||||
|
|
||||||
p0 := blockLocs[preds[0].ID].endState
|
p0 := blockLocs[preds[0].ID].endState
|
||||||
if len(preds) == 1 {
|
if len(preds) == 1 {
|
||||||
result.startState = p0
|
|
||||||
state.currentState.reset(p0)
|
state.currentState.reset(p0)
|
||||||
return result
|
return p0, true
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.loggingEnabled {
|
if state.loggingEnabled {
|
||||||
|
|
@ -497,9 +487,8 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B
|
||||||
if state.loggingEnabled {
|
if state.loggingEnabled {
|
||||||
state.logf("After merge, %v matches %v exactly.\n", b, preds[0])
|
state.logf("After merge, %v matches %v exactly.\n", b, preds[0])
|
||||||
}
|
}
|
||||||
result.startState = p0
|
|
||||||
state.currentState.reset(p0)
|
state.currentState.reset(p0)
|
||||||
return result
|
return p0, true
|
||||||
}
|
}
|
||||||
|
|
||||||
for reg := range state.currentState.registers {
|
for reg := range state.currentState.registers {
|
||||||
|
|
@ -519,10 +508,6 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Present in all predecessors.
|
// Present in all predecessors.
|
||||||
state.cache.AppendLiveSlot(liveSlot{SlotID(slotID), slotLoc})
|
|
||||||
if slotLoc.Registers == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
mask := uint64(slotLoc.Registers)
|
mask := uint64(slotLoc.Registers)
|
||||||
for {
|
for {
|
||||||
if mask == 0 {
|
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))
|
state.currentState.registers[reg] = append(state.currentState.registers[reg], SlotID(slotID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.startState = state.cache.GetLiveSlotSlice()
|
return nil, false
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// processValue updates locs and state.registerContents to reflect v, a value with
|
// 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 {
|
if state.loggingEnabled {
|
||||||
var partStrs []string
|
var partStrs []string
|
||||||
for _, slot := range state.varSlots[varID] {
|
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, " "))
|
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
|
// Run through the function in program text order, building up location
|
||||||
// lists as we go. The heavy lifting has mostly already been done.
|
// lists as we go. The heavy lifting has mostly already been done.
|
||||||
for _, b := range state.f.Blocks {
|
for _, b := range state.f.Blocks {
|
||||||
state.currentState.reset(blockLocs[b.ID].startState)
|
state.mergePredecessors(b, blockLocs)
|
||||||
|
|
||||||
phisPending := false
|
phisPending := false
|
||||||
for _, v := range b.Values {
|
for _, v := range b.Values {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue