From: Heschi Kreinick Date: Fri, 21 Jul 2017 22:28:06 +0000 (-0400) Subject: [dev.debug] cmd/compile: track variable decomposition in LocalSlot X-Git-Tag: go1.10beta1~1641^2^2~3 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=2d57d94ac314fd32529b1b2a92a086cb2dce0057;p=gostls13.git [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/50878 Reviewed-by: Josh Bleecher Snyder --- diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 7f179847fa..f8aefaae5e 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -4876,9 +4876,9 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { lenType := types.Types[TINT] if n.Class() == PAUTO && !n.Addrtaken() { // Split this string up into two separate variables. - p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos) - l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos) - return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0} + p := e.splitSlot(&name, ".ptr", 0, ptrType) + l := e.splitSlot(&name, ".len", ptrType.Size(), lenType) + return p, l } // 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)} @@ -4893,9 +4893,9 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot if n.Type.IsEmptyInterface() { f = ".type" } - c := e.namedAuto(n.Sym.Name+f, t, n.Pos) - d := e.namedAuto(n.Sym.Name+".data", t, n.Pos) - return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0} + c := e.splitSlot(&name, f, 0, t) + d := e.splitSlot(&name, ".data", t.Size(), t) + return c, d } // 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)} @@ -4907,10 +4907,10 @@ func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ss lenType := types.Types[TINT] if n.Class() == PAUTO && !n.Addrtaken() { // Split this slice up into three separate variables. - p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos) - l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos) - c := e.namedAuto(n.Sym.Name+".cap", lenType, n.Pos) - 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} + p := e.splitSlot(&name, ".ptr", 0, ptrType) + l := e.splitSlot(&name, ".len", ptrType.Size(), lenType) + c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType) + return p, l, c } // Return the three parts of the larger variable. 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) } if n.Class() == PAUTO && !n.Addrtaken() { // Split this complex up into two separate variables. - c := e.namedAuto(n.Sym.Name+".real", t, n.Pos) - d := e.namedAuto(n.Sym.Name+".imag", t, n.Pos) - return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0} + r := e.splitSlot(&name, ".real", 0, t) + i := e.splitSlot(&name, ".imag", t.Size(), t) + return r, i } // 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} @@ -4947,9 +4947,10 @@ func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { } if n.Class() == PAUTO && !n.Addrtaken() { // Split this int64 up into two separate variables. - h := e.namedAuto(n.Sym.Name+".hi", t, n.Pos) - l := e.namedAuto(n.Sym.Name+".lo", types.Types[TUINT32], n.Pos) - return ssa.LocalSlot{N: h, Type: t, Off: 0}, ssa.LocalSlot{N: l, Type: types.Types[TUINT32], Off: 0} + if thearch.LinkArch.ByteOrder == binary.BigEndian { + return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32]) + } + return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32]) } // Return the two parts of the larger variable. if thearch.LinkArch.ByteOrder == binary.BigEndian { @@ -4962,12 +4963,15 @@ func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot { n := name.N.(*Node) st := name.Type ft := st.FieldType(i) + var offset int64 + for f := 0; f < i; f++ { + offset += st.FieldType(f).Size() + } if n.Class() == PAUTO && !n.Addrtaken() { // Note: the _ field may appear several times. But // have no fear, identically-named but distinct Autos are // ok, albeit maybe confusing for a debugger. - x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft, n.Pos) - return ssa.LocalSlot{N: x, Type: ft, Off: 0} + return e.splitSlot(&name, "."+st.FieldName(i), offset, ft) } 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 { } et := at.ElemType() if n.Class() == PAUTO && !n.Addrtaken() { - x := e.namedAuto(n.Sym.Name+"[0]", et, n.Pos) - return ssa.LocalSlot{N: x, Type: et, Off: 0} + return e.splitSlot(&name, "[0]", 0, et) } 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 { return itabsym(it, offset) } -// namedAuto returns a new AUTO variable with the given name and type. -// These are exposed to the debugger. -func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode { - t := typ - s := &types.Sym{Name: name, Pkg: localpkg} +// splitSlot returns a slot representing the data of parent starting at offset. +func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot { + s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg} n := new(Node) n.Name = new(Name) n.Op = ONAME - n.Pos = pos + n.Pos = parent.N.(*Node).Pos n.Orig = n s.Def = asTypesNode(n) @@ -5012,7 +5013,7 @@ func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode n.Name.Curfn = e.curfn e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n) 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 { diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index 3bb67a951b..54cd96beaa 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -82,33 +82,33 @@ func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode { return &DummyAuto{t: t, s: "aDummyAuto"} } 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) { - 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) { - return LocalSlot{s.N, s.Type.ElemType().PtrTo(), s.Off}, - LocalSlot{s.N, dummyTypes.Int, s.Off + 8}, - LocalSlot{s.N, dummyTypes.Int, s.Off + 16} + return LocalSlot{N: s.N, Type: s.Type.ElemType().PtrTo(), Off: s.Off}, + LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8}, + LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 16} } func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) { 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) { 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 { - 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 { - 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 { return "unknown.go:0" diff --git a/src/cmd/compile/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go index 41b48947aa..70afa47e9d 100644 --- a/src/cmd/compile/internal/ssa/location.go +++ b/src/cmd/compile/internal/ssa/location.go @@ -26,12 +26,32 @@ func (r *Register) Name() string { return r.name } -// A LocalSlot is a location in the stack frame. -// It is (possibly a subpiece of) a PPARAM, PPARAMOUT, or PAUTO ONAME node. +// A LocalSlot is a location in the stack frame, which identifies and stores +// 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 { - 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 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 { diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 137e5fc4c2..e297e6bce7 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -2118,8 +2118,8 @@ func (e *edgeState) findRegFor(typ *types.Type) Location { // Allocate a temp location to spill a register to. // 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. - t := LocalSlot{e.s.f.fe.Auto(c.Pos, types.Int64), types.Int64, 0} - // TODO: reuse these slots. + t := LocalSlot{N: e.s.f.fe.Auto(c.Pos, types.Int64), Type: types.Int64} + // TODO: reuse these slots. They'll need to be erased first. e.set(t, vid, x, false, c.Pos) if e.s.f.pass.debug > regDebug { fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString()) diff --git a/src/cmd/compile/internal/ssa/sizeof_test.go b/src/cmd/compile/internal/ssa/sizeof_test.go index 9fab7b664f..f8bbed91b4 100644 --- a/src/cmd/compile/internal/ssa/sizeof_test.go +++ b/src/cmd/compile/internal/ssa/sizeof_test.go @@ -24,6 +24,7 @@ func TestSizeof(t *testing.T) { }{ {Value{}, 68, 112}, {Block{}, 152, 288}, + {LocalSlot{}, 32, 48}, {valState{}, 28, 40}, } diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 3b44986eee..341bb7b871 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -151,7 +151,7 @@ func (s *stackAllocState) stackalloc() { if v.Op != OpArg { 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 { fmt.Printf("stackalloc %s to %s\n", v, loc.Name()) }