diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index 4332305c7aa..0db5f369adc 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -437,7 +437,7 @@ func createComplexVars(fnsym *obj.LSym, debugInfo *ssa.FuncDebug) ([]*Node, []*d // Group SSA variables by the user variable they were decomposed from. varParts := map[*Node][]varPart{} - for slotID, slot := range debugInfo.Slots { + for slotID, slot := range debugInfo.VarSlots { for slot.SplitOf != nil { slot = slot.SplitOf } @@ -450,7 +450,7 @@ func createComplexVars(fnsym *obj.LSym, debugInfo *ssa.FuncDebug) ([]*Node, []*d // createComplexVar has side effects. Instead, go by slot. var decls []*Node var vars []*dwarf.Var - for _, slot := range debugInfo.Slots { + for _, slot := range debugInfo.VarSlots { for slot.SplitOf != nil { slot = slot.SplitOf } @@ -490,6 +490,26 @@ func (a partsByVarOffset) Len() int { return len(a) } func (a partsByVarOffset) Less(i, j int) bool { return a[i].varOffset < a[j].varOffset } func (a partsByVarOffset) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +// stackOffset returns the stack location of a LocalSlot relative to the +// stack pointer, suitable for use in a DWARF location entry. This has nothing +// to do with its offset in the user variable. +func stackOffset(slot *ssa.LocalSlot) int32 { + n := slot.N.(*Node) + var base int64 + switch n.Class() { + case PAUTO: + if Ctxt.FixedFrameSize() == 0 { + base -= int64(Widthptr) + } + if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { + base -= int64(Widthptr) + } + case PPARAM, PPARAMOUT: + base += Ctxt.FixedFrameSize() + } + return int32(base + n.Xoffset + slot.Off) +} + // createComplexVar builds a DWARF variable entry and location list representing n. func createComplexVar(debugInfo *ssa.FuncDebug, n *Node, parts []varPart) *dwarf.Var { slots := debugInfo.Slots @@ -514,14 +534,15 @@ func createComplexVar(debugInfo *ssa.FuncDebug, n *Node, parts []varPart) *dwarf gotype := ngotype(n).Linksym() typename := dwarf.InfoPrefix + gotype.Name[len("type."):] - // The stack offset is used as a sorting key, so for decomposed - // variables just give it the lowest one. It's not used otherwise. - stackOffset := debugInfo.Slots[parts[0].slot].N.(*Node).Xoffset + offs dvar := &dwarf.Var{ - Name: n.Sym.Name, - Abbrev: abbrev, - Type: Ctxt.Lookup(typename), - StackOffset: int32(stackOffset), + Name: n.Sym.Name, + Abbrev: abbrev, + Type: Ctxt.Lookup(typename), + // The stack offset is used as a sorting key, so for decomposed + // variables just give it the lowest one. It's not used otherwise. + // This won't work well if the first slot hasn't been assigned a stack + // location, but it's not obvious how to do better. + StackOffset: int32(stackOffset(slots[parts[0].slot])), DeclLine: n.Pos.Line(), } @@ -666,7 +687,7 @@ func createComplexVar(debugInfo *ssa.FuncDebug, n *Node, parts []varPart) *dwarf } if loc.OnStack { dpiece.OnStack = true - dpiece.StackOffset = int32(offs + slots[part.slot].Off + slots[part.slot].N.(*Node).Xoffset) + dpiece.StackOffset = stackOffset(slots[loc.StackLocation]) } else { for reg := 0; reg < len(debugInfo.Registers); reg++ { if loc.Registers&(1< %v\n", info.Slots[slot], info.SlotLocsString(SlotID(slot))) } } @@ -406,6 +430,7 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B loc := state.cache.NewVarLoc() loc.Start = BlockStart loc.OnStack = last.OnStack + loc.StackLocation = last.StackLocation loc.Registers = last.Registers live[slot].append(loc) } @@ -433,7 +458,10 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) *B } // Unify storage locations. - liveLoc.OnStack = liveLoc.OnStack && predLoc.OnStack + if !liveLoc.OnStack || !predLoc.OnStack || liveLoc.StackLocation != predLoc.StackLocation { + liveLoc.OnStack = false + liveLoc.StackLocation = 0 + } liveLoc.Registers &= predLoc.Registers } } @@ -506,6 +534,7 @@ func (state *debugState) processValue(locs *BlockDebug, v *Value, vSlots []SlotI loc := state.cache.NewVarLoc() loc.Start = v loc.OnStack = last.OnStack + loc.StackLocation = last.StackLocation loc.Registers = regs locs.append(slot, loc) } @@ -515,20 +544,18 @@ func (state *debugState) processValue(locs *BlockDebug, v *Value, vSlots []SlotI state.unexpected(v, "Arg op on already-live slot %v", state.slots[slot]) last.End = v } - if state.loggingEnabled { - state.logf("at %v: %v now on stack from arg\n", v.ID, state.slots[slot]) - } loc := state.cache.NewVarLoc() loc.Start = v loc.OnStack = true + loc.StackLocation = state.getHomeSlot(v) locs.append(slot, loc) + if state.loggingEnabled { + state.logf("at %v: arg %v now on stack in location %v\n", v.ID, state.slots[slot], state.slots[loc.StackLocation]) + } } case v.Op == OpStoreReg: for _, slot := range vSlots { - if state.loggingEnabled { - state.logf("at %v: %v spilled to stack\n", v.ID, state.slots[slot]) - } last := locs.lastLoc(slot) if last == nil { state.unexpected(v, "spill of unnamed register %s\n", vReg) @@ -538,8 +565,13 @@ func (state *debugState) processValue(locs *BlockDebug, v *Value, vSlots []SlotI loc := state.cache.NewVarLoc() loc.Start = v loc.OnStack = true + loc.StackLocation = state.getHomeSlot(v) loc.Registers = last.Registers locs.append(slot, loc) + if state.loggingEnabled { + state.logf("at %v: %v spilled to stack location %v\n", v.ID, state.slots[slot], state.slots[loc.StackLocation]) + } + } case vReg != nil: @@ -569,6 +601,7 @@ func (state *debugState) processValue(locs *BlockDebug, v *Value, vSlots []SlotI loc.Start = v if last != nil { loc.OnStack = last.OnStack + loc.StackLocation = last.StackLocation loc.Registers = last.Registers } loc.Registers |= 1 << uint8(vReg.num)