Commit 2d57d94a authored by Heschi Kreinick's avatar Heschi Kreinick

[dev.debug] cmd/compile: track variable decomposition in LocalSlot

When the compiler decomposes a user variable, track its origin so that
it can be recomposed during DWARF generation.

Change-Id: Ia71c7f8e7f4d65f0652f1c97b0dda5d9cad41936
Reviewed-on: https://go-review.googlesource.com/50878Reviewed-by: default avatarJosh Bleecher Snyder <josharian@gmail.com>
parent 788aa88c
...@@ -4876,9 +4876,9 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { ...@@ -4876,9 +4876,9 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
lenType := types.Types[TINT] lenType := types.Types[TINT]
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Split this string up into two separate variables. // Split this string up into two separate variables.
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos) p := e.splitSlot(&name, ".ptr", 0, ptrType)
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos) l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0} return p, l
} }
// Return the two parts of the larger variable. // Return the two parts of the larger variable.
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)} return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
...@@ -4893,9 +4893,9 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot ...@@ -4893,9 +4893,9 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot
if n.Type.IsEmptyInterface() { if n.Type.IsEmptyInterface() {
f = ".type" f = ".type"
} }
c := e.namedAuto(n.Sym.Name+f, t, n.Pos) c := e.splitSlot(&name, f, 0, t)
d := e.namedAuto(n.Sym.Name+".data", t, n.Pos) d := e.splitSlot(&name, ".data", t.Size(), t)
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0} return c, d
} }
// Return the two parts of the larger variable. // Return the two parts of the larger variable.
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)} return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
...@@ -4907,10 +4907,10 @@ func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ss ...@@ -4907,10 +4907,10 @@ func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ss
lenType := types.Types[TINT] lenType := types.Types[TINT]
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Split this slice up into three separate variables. // Split this slice up into three separate variables.
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos) p := e.splitSlot(&name, ".ptr", 0, ptrType)
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos) l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
c := e.namedAuto(n.Sym.Name+".cap", lenType, n.Pos) c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}, ssa.LocalSlot{N: c, Type: lenType, Off: 0} return p, l, c
} }
// Return the three parts of the larger variable. // Return the three parts of the larger variable.
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
...@@ -4929,9 +4929,9 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) ...@@ -4929,9 +4929,9 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot)
} }
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Split this complex up into two separate variables. // Split this complex up into two separate variables.
c := e.namedAuto(n.Sym.Name+".real", t, n.Pos) r := e.splitSlot(&name, ".real", 0, t)
d := e.namedAuto(n.Sym.Name+".imag", t, n.Pos) i := e.splitSlot(&name, ".imag", t.Size(), t)
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0} return r, i
} }
// Return the two parts of the larger variable. // Return the two parts of the larger variable.
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s} return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
...@@ -4947,9 +4947,10 @@ func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { ...@@ -4947,9 +4947,10 @@ func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
} }
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Split this int64 up into two separate variables. // Split this int64 up into two separate variables.
h := e.namedAuto(n.Sym.Name+".hi", t, n.Pos) if thearch.LinkArch.ByteOrder == binary.BigEndian {
l := e.namedAuto(n.Sym.Name+".lo", types.Types[TUINT32], n.Pos) return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
return ssa.LocalSlot{N: h, Type: t, Off: 0}, ssa.LocalSlot{N: l, Type: types.Types[TUINT32], Off: 0} }
return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32])
} }
// Return the two parts of the larger variable. // Return the two parts of the larger variable.
if thearch.LinkArch.ByteOrder == binary.BigEndian { if thearch.LinkArch.ByteOrder == binary.BigEndian {
...@@ -4962,12 +4963,15 @@ func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot { ...@@ -4962,12 +4963,15 @@ func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
n := name.N.(*Node) n := name.N.(*Node)
st := name.Type st := name.Type
ft := st.FieldType(i) ft := st.FieldType(i)
var offset int64
for f := 0; f < i; f++ {
offset += st.FieldType(f).Size()
}
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
// Note: the _ field may appear several times. But // Note: the _ field may appear several times. But
// have no fear, identically-named but distinct Autos are // have no fear, identically-named but distinct Autos are
// ok, albeit maybe confusing for a debugger. // ok, albeit maybe confusing for a debugger.
x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft, n.Pos) return e.splitSlot(&name, "."+st.FieldName(i), offset, ft)
return ssa.LocalSlot{N: x, Type: ft, Off: 0}
} }
return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)} return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
} }
...@@ -4980,8 +4984,7 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot { ...@@ -4980,8 +4984,7 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
} }
et := at.ElemType() et := at.ElemType()
if n.Class() == PAUTO && !n.Addrtaken() { if n.Class() == PAUTO && !n.Addrtaken() {
x := e.namedAuto(n.Sym.Name+"[0]", et, n.Pos) return e.splitSlot(&name, "[0]", 0, et)
return ssa.LocalSlot{N: x, Type: et, Off: 0}
} }
return ssa.LocalSlot{N: n, Type: et, Off: name.Off} return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
} }
...@@ -4990,16 +4993,14 @@ func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym { ...@@ -4990,16 +4993,14 @@ func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
return itabsym(it, offset) return itabsym(it, offset)
} }
// namedAuto returns a new AUTO variable with the given name and type. // splitSlot returns a slot representing the data of parent starting at offset.
// These are exposed to the debugger. func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode { s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg}
t := typ
s := &types.Sym{Name: name, Pkg: localpkg}
n := new(Node) n := new(Node)
n.Name = new(Name) n.Name = new(Name)
n.Op = ONAME n.Op = ONAME
n.Pos = pos n.Pos = parent.N.(*Node).Pos
n.Orig = n n.Orig = n
s.Def = asTypesNode(n) s.Def = asTypesNode(n)
...@@ -5012,7 +5013,7 @@ func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode ...@@ -5012,7 +5013,7 @@ func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode
n.Name.Curfn = e.curfn n.Name.Curfn = e.curfn
e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n) e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n)
dowidth(t) dowidth(t)
return n return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
} }
func (e *ssafn) CanSSA(t *types.Type) bool { func (e *ssafn) CanSSA(t *types.Type) bool {
......
...@@ -82,33 +82,33 @@ func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode { ...@@ -82,33 +82,33 @@ func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode {
return &DummyAuto{t: t, s: "aDummyAuto"} return &DummyAuto{t: t, s: "aDummyAuto"}
} }
func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) { func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.Int, s.Off + 8} return LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8}
} }
func (d DummyFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) { func (d DummyFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) {
return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.BytePtr, s.Off + 8} return LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off + 8}
} }
func (d DummyFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) { func (d DummyFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) {
return LocalSlot{s.N, s.Type.ElemType().PtrTo(), s.Off}, return LocalSlot{N: s.N, Type: s.Type.ElemType().PtrTo(), Off: s.Off},
LocalSlot{s.N, dummyTypes.Int, s.Off + 8}, LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8},
LocalSlot{s.N, dummyTypes.Int, s.Off + 16} LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 16}
} }
func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) { func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
if s.Type.Size() == 16 { if s.Type.Size() == 16 {
return LocalSlot{s.N, dummyTypes.Float64, s.Off}, LocalSlot{s.N, dummyTypes.Float64, s.Off + 8} return LocalSlot{N: s.N, Type: dummyTypes.Float64, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Float64, Off: s.Off + 8}
} }
return LocalSlot{s.N, dummyTypes.Float32, s.Off}, LocalSlot{s.N, dummyTypes.Float32, s.Off + 4} return LocalSlot{N: s.N, Type: dummyTypes.Float32, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Float32, Off: s.Off + 4}
} }
func (d DummyFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) { func (d DummyFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
if s.Type.IsSigned() { if s.Type.IsSigned() {
return LocalSlot{s.N, dummyTypes.Int32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off} return LocalSlot{N: s.N, Type: dummyTypes.Int32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off}
} }
return LocalSlot{s.N, dummyTypes.UInt32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off} return LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off}
} }
func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot { func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)} return LocalSlot{N: s.N, Type: s.Type.FieldType(i), Off: s.Off + s.Type.FieldOff(i)}
} }
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot { func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
return LocalSlot{s.N, s.Type.ElemType(), s.Off} return LocalSlot{N: s.N, Type: s.Type.ElemType(), Off: s.Off}
} }
func (DummyFrontend) Line(_ src.XPos) string { func (DummyFrontend) Line(_ src.XPos) string {
return "unknown.go:0" return "unknown.go:0"
......
...@@ -26,12 +26,32 @@ func (r *Register) Name() string { ...@@ -26,12 +26,32 @@ func (r *Register) Name() string {
return r.name return r.name
} }
// A LocalSlot is a location in the stack frame. // A LocalSlot is a location in the stack frame, which identifies and stores
// It is (possibly a subpiece of) a PPARAM, PPARAMOUT, or PAUTO ONAME node. // part or all of a PPARAM, PPARAMOUT, or PAUTO ONAME node.
// It can represent a whole variable, part of a larger stack slot, or part of a
// variable that has been decomposed into multiple stack slots.
// As an example, a string could have the following configurations:
//
// stack layout LocalSlots
//
// Optimizations are disabled. s is on the stack and represented in its entirety.
// [ ------- s string ---- ] { N: s, Type: string, Off: 0 }
//
// s was not decomposed, but the SSA operates on its parts individually, so
// there is a LocalSlot for each of its fields that points into the single stack slot.
// [ ------- s string ---- ] { N: s, Type: *uint8, Off: 0 }, {N: s, Type: int, Off: 8}
//
// s was decomposed. Each of its fields is in its own stack slot and has its own LocalSLot.
// [ ptr *uint8 ] [ len int] { N: ptr, Type: *uint8, Off: 0, SplitOf: parent, SplitOffset: 0},
// { N: len, Type: int, Off: 0, SplitOf: parent, SplitOffset: 8}
// parent = &{N: s, Type: string}
type LocalSlot struct { type LocalSlot struct {
N GCNode // an ONAME *gc.Node representing a variable on the stack N GCNode // an ONAME *gc.Node representing a stack location.
Type *types.Type // type of slot Type *types.Type // type of slot
Off int64 // offset of slot in N Off int64 // offset of slot in N
SplitOf *LocalSlot // slot is a decomposition of SplitOf
SplitOffset int64 // .. at this offset.
} }
func (s LocalSlot) Name() string { func (s LocalSlot) Name() string {
......
...@@ -2118,8 +2118,8 @@ func (e *edgeState) findRegFor(typ *types.Type) Location { ...@@ -2118,8 +2118,8 @@ func (e *edgeState) findRegFor(typ *types.Type) Location {
// Allocate a temp location to spill a register to. // Allocate a temp location to spill a register to.
// The type of the slot is immaterial - it will not be live across // The type of the slot is immaterial - it will not be live across
// any safepoint. Just use a type big enough to hold any register. // any safepoint. Just use a type big enough to hold any register.
t := LocalSlot{e.s.f.fe.Auto(c.Pos, types.Int64), types.Int64, 0} t := LocalSlot{N: e.s.f.fe.Auto(c.Pos, types.Int64), Type: types.Int64}
// TODO: reuse these slots. // TODO: reuse these slots. They'll need to be erased first.
e.set(t, vid, x, false, c.Pos) e.set(t, vid, x, false, c.Pos)
if e.s.f.pass.debug > regDebug { if e.s.f.pass.debug > regDebug {
fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString()) fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())
......
...@@ -24,6 +24,7 @@ func TestSizeof(t *testing.T) { ...@@ -24,6 +24,7 @@ func TestSizeof(t *testing.T) {
}{ }{
{Value{}, 68, 112}, {Value{}, 68, 112},
{Block{}, 152, 288}, {Block{}, 152, 288},
{LocalSlot{}, 32, 48},
{valState{}, 28, 40}, {valState{}, 28, 40},
} }
......
...@@ -151,7 +151,7 @@ func (s *stackAllocState) stackalloc() { ...@@ -151,7 +151,7 @@ func (s *stackAllocState) stackalloc() {
if v.Op != OpArg { if v.Op != OpArg {
continue continue
} }
loc := LocalSlot{v.Aux.(GCNode), v.Type, v.AuxInt} loc := LocalSlot{N: v.Aux.(GCNode), Type: v.Type, Off: v.AuxInt}
if f.pass.debug > stackDebug { if f.pass.debug > stackDebug {
fmt.Printf("stackalloc %s to %s\n", v, loc.Name()) fmt.Printf("stackalloc %s to %s\n", v, loc.Name())
} }
......
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