Commit ac81c5c4 authored by Heschi Kreinick's avatar Heschi Kreinick

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/92403Reviewed-by: 's avatarDavid Chase <drchase@google.com>
parent e181852d
...@@ -167,6 +167,7 @@ type debugState struct { ...@@ -167,6 +167,7 @@ type debugState struct {
slots []*LocalSlot slots []*LocalSlot
vars []GCNode vars []GCNode
varSlots [][]SlotID varSlots [][]SlotID
lists [][]byte
// The user variable that each slot rolls up to, indexed by SlotID. // The user variable that each slot rolls up to, indexed by SlotID.
slotVars []VarID slotVars []VarID
...@@ -176,6 +177,7 @@ type debugState struct { ...@@ -176,6 +177,7 @@ type debugState struct {
cache *Cache cache *Cache
registers []Register registers []Register
stackOffset func(LocalSlot) int32 stackOffset func(LocalSlot) int32
ctxt *obj.Link
// The names (slots) associated with each value, indexed by Value ID. // The names (slots) associated with each value, indexed by Value ID.
valueNames [][]SlotID valueNames [][]SlotID
...@@ -184,6 +186,9 @@ type debugState struct { ...@@ -184,6 +186,9 @@ type debugState struct {
currentState stateAtPC currentState stateAtPC
liveCount []int liveCount []int
changedVars *sparseSet changedVars *sparseSet
// The pending location list entry for each user variable, indexed by VarID.
pendingEntries []pendingEntry
} }
func (state *debugState) initializeCache() { func (state *debugState) initializeCache() {
...@@ -251,6 +256,7 @@ func (state *debugState) initializeCache() { ...@@ -251,6 +256,7 @@ func (state *debugState) initializeCache() {
} }
freePieceIdx += len(slots) freePieceIdx += len(slots)
} }
state.pendingEntries = pe
} }
func (state *debugState) allocBlock(b *Block) *BlockDebug { func (state *debugState) allocBlock(b *Block) *BlockDebug {
...@@ -303,6 +309,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu ...@@ -303,6 +309,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
cache: f.Cache, cache: f.Cache,
registers: f.Config.registers, registers: f.Config.registers,
stackOffset: stackOffset, stackOffset: stackOffset,
ctxt: ctxt,
} }
// Recompose any decomposed variables, and record the names associated with each value. // 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 ...@@ -327,6 +334,8 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
// Fill in the var<->slot mappings. // Fill in the var<->slot mappings.
state.varSlots = make([][]SlotID, len(state.vars)) state.varSlots = make([][]SlotID, len(state.vars))
state.slotVars = make([]VarID, len(state.slots)) state.slotVars = make([]VarID, len(state.slots))
state.lists = make([][]byte, len(state.vars))
for varID, n := range state.vars { for varID, n := range state.vars {
parts := varParts[n] parts := varParts[n]
state.varSlots[varID] = parts state.varSlots[varID] = parts
...@@ -347,13 +356,13 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu ...@@ -347,13 +356,13 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset fu
} }
blockLocs := state.liveness() blockLocs := state.liveness()
lists := state.buildLocationLists(ctxt, blockLocs) state.buildLocationLists(blockLocs)
return &FuncDebug{ return &FuncDebug{
Slots: state.slots, Slots: state.slots,
VarSlots: state.varSlots, VarSlots: state.varSlots,
Vars: state.vars, Vars: state.vars,
LocationLists: lists, LocationLists: state.lists,
} }
} }
...@@ -717,78 +726,59 @@ func firstReg(set RegisterSet) uint8 { ...@@ -717,78 +726,59 @@ func firstReg(set RegisterSet) uint8 {
// The returned location lists are not fully complete. They are in terms of // 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 // SSA values rather than PCs, and have no base address/end entries. They will
// be finished by PutLocationList. // be finished by PutLocationList.
func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDebug) [][]byte { func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
lists := make([][]byte, len(state.vars)) // Run through the function in program text order, building up location
pendingEntries := state.cache.pendingEntries // lists as we go. The heavy lifting has mostly already been done.
for _, b := range state.f.Blocks {
// writePendingEntry writes out the pending entry for varID, if any, state.mergePredecessors(b, blockLocs)
// terminated at endBlock/Value.
writePendingEntry := func(varID VarID, endBlock, endValue ID) {
list := lists[varID]
pending := pendingEntries[varID]
if !pending.present {
return
}
// Pack the start/end coordinates into the start/end addresses phisPending := false
// of the entry, for decoding by PutLocationList. for _, v := range b.Values {
start, startOK := encodeValue(Ctxt, pending.startBlock, pending.startValue) slots := state.valueNames[v.ID]
end, endOK := encodeValue(Ctxt, endBlock, endValue) reg, _ := state.f.getHome(v.ID).(*Register)
if !startOK || !endOK { changed := state.processValue(v, slots, reg)
// 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)
// Where to write the length of the location description once
// we know how big it is.
sizeIdx := len(list)
list = list[:len(list)+2]
if state.loggingEnabled { if v.Op == OpPhi {
var partStrs []string if changed {
for i, slot := range state.varSlots[varID] { phisPending = true
partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[i])))
} }
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, " ")) continue
} }
for i, slotID := range state.varSlots[varID] { if !changed && !phisPending {
loc := pending.pieces[i] continue
slot := state.slots[slotID] }
if !loc.absent() { phisPending = false
if loc.onStack() { for _, varID := range state.changedVars.contents() {
if loc.stackOffsetValue() == 0 { state.updateVar(VarID(varID), v, state.currentState.slots)
list = append(list, dwarf.DW_OP_call_frame_cfa)
} else {
list = append(list, dwarf.DW_OP_fbreg)
list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue()))
} }
} else { state.changedVars.clear()
regnum := Ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()]
if regnum < 32 {
list = append(list, dwarf.DW_OP_reg0+byte(regnum))
} else {
list = append(list, dwarf.DW_OP_regx)
list = dwarf.AppendUleb128(list, uint64(regnum))
} }
} }
if state.loggingEnabled {
state.logf("location lists:\n")
} }
if len(state.varSlots[varID]) > 1 { // Flush any leftover entries live at the end of the last block.
list = append(list, dwarf.DW_OP_piece) for varID := range state.lists {
list = dwarf.AppendUleb128(list, uint64(slot.Type.Size())) 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]))
} }
Ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2))
lists[varID] = list
} }
}
// updateVar updates the pending location list entry for varID to // updateVar updates the pending location list entry for varID to
// reflect the new locations in curLoc, caused by v. // reflect the new locations in curLoc, caused by v.
updateVar := func(varID VarID, v *Value, curLoc []VarLoc) { func (state *debugState) updateVar(varID VarID, v *Value, curLoc []VarLoc) {
// Assemble the location list entry with whatever's live. // Assemble the location list entry with whatever's live.
empty := true empty := true
for _, slotID := range state.varSlots[varID] { for _, slotID := range state.varSlots[varID] {
...@@ -797,9 +787,9 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe ...@@ -797,9 +787,9 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe
break break
} }
} }
pending := &pendingEntries[varID] pending := &state.pendingEntries[varID]
if empty { if empty {
writePendingEntry(varID, v.Block.ID, v.ID) state.writePendingEntry(varID, v.Block.ID, v.ID)
pending.clear() pending.clear()
return return
} }
...@@ -818,7 +808,7 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe ...@@ -818,7 +808,7 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe
} }
} }
writePendingEntry(varID, v.Block.ID, v.ID) state.writePendingEntry(varID, v.Block.ID, v.ID)
pending.present = true pending.present = true
pending.startBlock = v.Block.ID pending.startBlock = v.Block.ID
pending.startValue = v.ID pending.startValue = v.ID
...@@ -827,56 +817,71 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe ...@@ -827,56 +817,71 @@ func (state *debugState) buildLocationLists(Ctxt *obj.Link, blockLocs []*BlockDe
} }
return 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 { // writePendingEntry writes out the pending entry for varID, if any,
if changed { // terminated at endBlock/Value.
phisPending = true func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) {
} pending := state.pendingEntries[varID]
continue if !pending.present {
return
} }
if !changed && !phisPending { // Pack the start/end coordinates into the start/end addresses
continue // of the entry, for decoding by PutLocationList.
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 := 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)
list = list[:len(list)+2]
phisPending = false if state.loggingEnabled {
for _, varID := range state.changedVars.contents() { var partStrs []string
updateVar(VarID(varID), v, state.currentState.slots) for i, slot := range state.varSlots[varID] {
partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[i])))
} }
state.changedVars.clear() 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, " "))
} }
} for i, slotID := range state.varSlots[varID] {
loc := pending.pieces[i]
slot := state.slots[slotID]
if state.loggingEnabled { if !loc.absent() {
state.logf("location lists:\n") if loc.onStack() {
if loc.stackOffsetValue() == 0 {
list = append(list, dwarf.DW_OP_call_frame_cfa)
} else {
list = append(list, dwarf.DW_OP_fbreg)
list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue()))
}
} else {
regnum := state.ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()]
if regnum < 32 {
list = append(list, dwarf.DW_OP_reg0+byte(regnum))
} else {
list = append(list, dwarf.DW_OP_regx)
list = dwarf.AppendUleb128(list, uint64(regnum))
}
} }
// 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 { if len(state.varSlots[varID]) > 1 {
state.logf("\t%v : %q\n", state.vars[varID], hex.EncodeToString(lists[varID])) list = append(list, dwarf.DW_OP_piece)
list = dwarf.AppendUleb128(list, uint64(slot.Type.Size()))
} }
} }
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. // PutLocationList adds list (a location list in its intermediate representation) to listSym.
......
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