cmd/compile/internal/ssa: refactor buildLocationLists

Change the closures to methods on debugState, mostly just for aesthetic
reasons.

Change-Id: I5242807f7300efafc7efb4eb3bd305ac3ec8e826
Reviewed-on: https://go-review.googlesource.com/92403
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Heschi Kreinick 2018-02-05 16:55:54 -05:00
parent e181852dd4
commit ac81c5c402

View file

@ -167,6 +167,7 @@ type debugState struct {
slots []*LocalSlot
vars []GCNode
varSlots [][]SlotID
lists [][]byte
// The user variable that each slot rolls up to, indexed by SlotID.
slotVars []VarID
@ -176,6 +177,7 @@ type debugState struct {
cache *Cache
registers []Register
stackOffset func(LocalSlot) int32
ctxt *obj.Link
// The names (slots) associated with each value, indexed by Value ID.
valueNames [][]SlotID
@ -184,6 +186,9 @@ type debugState struct {
currentState stateAtPC
liveCount []int
changedVars *sparseSet
// The pending location list entry for each user variable, indexed by VarID.
pendingEntries []pendingEntry
}
func (state *debugState) initializeCache() {
@ -251,6 +256,7 @@ func (state *debugState) initializeCache() {
}
freePieceIdx += len(slots)
}
state.pendingEntries = pe
}
func (state *debugState) allocBlock(b *Block) *BlockDebug {
@ -303,6 +309,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
cache: f.Cache,
registers: f.Config.registers,
stackOffset: stackOffset,
ctxt: ctxt,
}
// Recompose any decomposed variables, and record the names associated with each value.
@ -327,6 +334,8 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
// Fill in the var<->slot mappings.
state.varSlots = make([][]SlotID, len(state.vars))
state.slotVars = make([]VarID, len(state.slots))
state.lists = make([][]byte, len(state.vars))
for varID, n := range state.vars {
parts := varParts[n]
state.varSlots[varID] = parts
@ -347,13 +356,13 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
}
blockLocs := state.liveness()
lists := state.buildLocationLists(ctxt, blockLocs)
state.buildLocationLists(blockLocs)
return &FuncDebug{
Slots: state.slots,
VarSlots: state.varSlots,
Vars: state.vars,
LocationLists: lists,
LocationLists: state.lists,
}
}
@ -717,30 +726,119 @@ func firstReg(set RegisterSet) uint8 {
// The returned location lists are not fully complete. They are in terms of
// SSA values rather than PCs, and have no base address/end entries. They will
// be finished by PutLocationList.
func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDebug) [][]byte {
lists := make([][]byte, len(state.vars))
pendingEntries := state.cache.pendingEntries
func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
// 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.mergePredecessors(b, blockLocs)
// writePendingEntry writes out the pending entry for varID, if any,
// terminated at endBlock/Value.
writePendingEntry := func(varID VarID, endBlock, endValue ID) {
list := lists[varID]
pending := pendingEntries[varID]
phisPending := false
for _, v := range b.Values {
slots := state.valueNames[v.ID]
reg, _ := state.f.getHome(v.ID).(*Register)
changed := state.processValue(v, slots, reg)
if v.Op == OpPhi {
if changed {
phisPending = true
}
continue
}
if !changed && !phisPending {
continue
}
phisPending = false
for _, varID := range state.changedVars.contents() {
state.updateVar(VarID(varID), v, state.currentState.slots)
}
state.changedVars.clear()
}
}
if state.loggingEnabled {
state.logf("location lists:\n")
}
// Flush any leftover entries live at the end of the last block.
for varID := range state.lists {
state.writePendingEntry(VarID(varID), state.f.Blocks[len(state.f.Blocks)-1].ID, BlockEnd.ID)
list := state.lists[varID]
if len(list) == 0 {
continue
}
if state.loggingEnabled {
state.logf("\t%v : %q\n", state.vars[varID], hex.EncodeToString(state.lists[varID]))
}
}
}
// updateVar updates the pending location list entry for varID to
// reflect the new locations in curLoc, caused by v.
func (state *debugState) updateVar(varID VarID, v *Value, curLoc []VarLoc) {
// Assemble the location list entry with whatever's live.
empty := true
for _, slotID := range state.varSlots[varID] {
if !curLoc[slotID].absent() {
empty = false
break
}
}
pending := &state.pendingEntries[varID]
if empty {
state.writePendingEntry(varID, v.Block.ID, v.ID)
pending.clear()
return
}
// Extend the previous entry if possible.
if pending.present {
merge := true
for i, slotID := range state.varSlots[varID] {
if !canMerge(pending.pieces[i], curLoc[slotID]) {
merge = false
break
}
}
if merge {
return
}
}
state.writePendingEntry(varID, v.Block.ID, v.ID)
pending.present = true
pending.startBlock = v.Block.ID
pending.startValue = v.ID
for i, slot := range state.varSlots[varID] {
pending.pieces[i] = curLoc[slot]
}
return
}
// writePendingEntry writes out the pending entry for varID, if any,
// terminated at endBlock/Value.
func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) {
pending := state.pendingEntries[varID]
if !pending.present {
return
}
// Pack the start/end coordinates into the start/end addresses
// of the entry, for decoding by PutLocationList.
start, startOK := encodeValue(Ctxt, pending.startBlock, pending.startValue)
end, endOK := encodeValue(Ctxt, endBlock, endValue)
start, startOK := encodeValue(state.ctxt, pending.startBlock, pending.startValue)
end, endOK := encodeValue(state.ctxt, endBlock, endValue)
if !startOK || !endOK {
// If someone writes a function that uses >65K values,
// they get incomplete debug info on 32-bit platforms.
return
}
list = appendPtr(Ctxt, list, start)
list = appendPtr(Ctxt, list, end)
list := state.lists[varID]
list = appendPtr(state.ctxt, list, start)
list = appendPtr(state.ctxt, list, end)
// Where to write the length of the location description once
// we know how big it is.
sizeIdx := len(list)
@ -767,7 +865,7 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe
list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue()))
}
} else {
regnum := Ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()]
regnum := state.ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()]
if regnum < 32 {
list = append(list, dwarf.DW_OP_reg0+byte(regnum))
} else {
@ -782,101 +880,8 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe
list = dwarf.AppendUleb128(list, uint64(slot.Type.Size()))
}
}
Ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2))
lists[varID] = list
}
// updateVar updates the pending location list entry for varID to
// reflect the new locations in curLoc, caused by v.
updateVar := func(varID VarID, v *Value, curLoc []VarLoc) {
// Assemble the location list entry with whatever's live.
empty := true
for _, slotID := range state.varSlots[varID] {
if !curLoc[slotID].absent() {
empty = false
break
}
}
pending := &pendingEntries[varID]
if empty {
writePendingEntry(varID, v.Block.ID, v.ID)
pending.clear()
return
}
// Extend the previous entry if possible.
if pending.present {
merge := true
for i, slotID := range state.varSlots[varID] {
if !canMerge(pending.pieces[i], curLoc[slotID]) {
merge = false
break
}
}
if merge {
return
}
}
writePendingEntry(varID, v.Block.ID, v.ID)
pending.present = true
pending.startBlock = v.Block.ID
pending.startValue = v.ID
for i, slot := range state.varSlots[varID] {
pending.pieces[i] = curLoc[slot]
}
return
}
// 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.mergePredecessors(b, blockLocs)
phisPending := false
for _, v := range b.Values {
slots := state.valueNames[v.ID]
reg, _ := state.f.getHome(v.ID).(*Register)
changed := state.processValue(v, slots, reg)
if v.Op == OpPhi {
if changed {
phisPending = true
}
continue
}
if !changed && !phisPending {
continue
}
phisPending = false
for _, varID := range state.changedVars.contents() {
updateVar(VarID(varID), v, state.currentState.slots)
}
state.changedVars.clear()
}
}
if state.loggingEnabled {
state.logf("location lists:\n")
}
// Flush any leftover entries live at the end of the last block.
for varID := range lists {
writePendingEntry(VarID(varID), state.f.Blocks[len(state.f.Blocks)-1].ID, BlockEnd.ID)
list := lists[varID]
if len(list) == 0 {
continue
}
if state.loggingEnabled {
state.logf("\t%v : %q\n", state.vars[varID], hex.EncodeToString(lists[varID]))
}
}
return lists
state.ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2))
state.lists[varID] = list
}
// PutLocationList adds list (a location list in its intermediate representation) to listSym.