From: Keith Randall Date: Tue, 15 Jan 2019 22:50:09 +0000 (-0800) Subject: cmd/compile: use existing instructions instead of nops for inline marks X-Git-Tag: go1.13beta1~912 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=2034fbab5b1d11bc59cb476bc3f49ee1b344839d;p=gostls13.git cmd/compile: use existing instructions instead of nops for inline marks Instead of always inserting a nop to use as the target of an inline mark, see if we can instead find an instruction we're issuing anyway with the correct line number, and use that instruction. That way, we don't need to issue a nop. Makes cmd/go 0.3% smaller. Update #29571 Change-Id: If6cfc93ab3352ec2c6e0878f8074a3bf0786b2f8 Reviewed-on: https://go-review.googlesource.com/c/go/+/158021 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Josh Bleecher Snyder --- diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go index d48aeaabd9..e749650293 100644 --- a/misc/cgo/test/callback.go +++ b/misc/cgo/test/callback.go @@ -199,7 +199,7 @@ func testCallbackCallers(t *testing.T) { t.Errorf("expected %d frames, got %d", len(name), n) } for i := 0; i < n; i++ { - f := runtime.FuncForPC(pc[i]) + f := runtime.FuncForPC(pc[i] - 1) // TODO: use runtime.CallersFrames if f == nil { t.Fatalf("expected non-nil Func for pc %d", pc[i]) } diff --git a/src/cmd/compile/internal/gc/dwinl.go b/src/cmd/compile/internal/gc/dwinl.go index cc42a04c64..27e2cbcd98 100644 --- a/src/cmd/compile/internal/gc/dwinl.go +++ b/src/cmd/compile/internal/gc/dwinl.go @@ -147,8 +147,8 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls { // Make a second pass through the progs to compute PC ranges for // the various inlined calls. + start := int64(-1) curii := -1 - var crange *dwarf.Range var prevp *obj.Prog for p := fnsym.Func.Text; p != nil; prevp, p = p, p.Link { if prevp != nil && p.Pos == prevp.Pos { @@ -157,17 +157,17 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls { ii := posInlIndex(p.Pos) if ii == curii { continue - } else { - // Close out the current range - endRange(crange, p) - - // Begin new range - crange = beginRange(inlcalls.Calls, p, ii, imap) - curii = ii } + // Close out the current range + if start != -1 { + addRange(inlcalls.Calls, start, p.Pc, curii, imap) + } + // Begin new range + start = p.Pc + curii = ii } - if crange != nil { - crange.End = fnsym.Size + if start != -1 { + addRange(inlcalls.Calls, start, fnsym.Size, curii, imap) } // Debugging @@ -287,26 +287,26 @@ func posInlIndex(xpos src.XPos) int { return -1 } -func endRange(crange *dwarf.Range, p *obj.Prog) { - if crange == nil { - return +func addRange(calls []dwarf.InlCall, start, end int64, ii int, imap map[int]int) { + if start == -1 { + panic("bad range start") + } + if end == -1 { + panic("bad range end") } - crange.End = p.Pc -} - -func beginRange(calls []dwarf.InlCall, p *obj.Prog, ii int, imap map[int]int) *dwarf.Range { if ii == -1 { - return nil + return } + if start == end { + return + } + // Append range to correct inlined call callIdx, found := imap[ii] if !found { - Fatalf("can't find inlIndex %d in imap for prog at %d\n", ii, p.Pc) + Fatalf("can't find inlIndex %d in imap for prog at %d\n", ii, start) } call := &calls[callIdx] - - // Set up range and append to correct inlined call - call.Ranges = append(call.Ranges, dwarf.Range{Start: p.Pc, End: -1}) - return &call.Ranges[len(call.Ranges)-1] + call.Ranges = append(call.Ranges, dwarf.Range{Start: start, End: end}) } func dumpInlCall(inlcalls dwarf.InlCalls, idx, ilevel int) { diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 52515bdb1d..a7c1917ff1 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -5239,6 +5239,16 @@ func genssa(f *ssa.Func, pp *Progs) { } } + // inlMarks has an entry for each Prog that implements an inline mark. + // It maps from that Prog to the global inlining id of the inlined body + // which should unwind to this Prog's location. + var inlMarks map[*obj.Prog]int32 + var inlMarkList []*obj.Prog + + // inlMarksByPos maps from a (column 1) source position to the set of + // Progs that are in the set above and have that source position. + var inlMarksByPos map[src.XPos][]*obj.Prog + // Emit basic blocks for i, b := range f.Blocks { s.bstart[b.ID] = s.pp.next @@ -5276,8 +5286,14 @@ func genssa(f *ssa.Func, pp *Progs) { } case ssa.OpInlMark: p := thearch.Ginsnop(s.pp) - pp.curfn.Func.lsym.Func.AddInlMark(p, v.AuxInt32()) - // TODO: if matching line number, merge somehow with previous instruction? + if inlMarks == nil { + inlMarks = map[*obj.Prog]int32{} + inlMarksByPos = map[src.XPos][]*obj.Prog{} + } + inlMarks[p] = v.AuxInt32() + inlMarkList = append(inlMarkList, p) + pos := v.Pos.AtColumn1() + inlMarksByPos[pos] = append(inlMarksByPos[pos], p) default: // let the backend handle it @@ -5318,6 +5334,50 @@ func genssa(f *ssa.Func, pp *Progs) { } } + if inlMarks != nil { + // We have some inline marks. Try to find other instructions we're + // going to emit anyway, and use those instructions instead of the + // inline marks. + for p := pp.Text; p != nil; p = p.Link { + if p.As == obj.ANOP || p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT || p.As == obj.APCALIGN || thearch.LinkArch.Family == sys.Wasm { + // Don't use 0-sized instructions as inline marks, because we need + // to identify inline mark instructions by pc offset. + // (Some of these instructions are sometimes zero-sized, sometimes not. + // We must not use anything that even might be zero-sized.) + // TODO: are there others? + continue + } + if _, ok := inlMarks[p]; ok { + // Don't use inline marks themselves. We don't know + // whether they will be zero-sized or not yet. + continue + } + pos := p.Pos.AtColumn1() + s := inlMarksByPos[pos] + if len(s) == 0 { + continue + } + for _, m := range s { + // We found an instruction with the same source position as + // some of the inline marks. + // Use this instruction instead. + pp.curfn.Func.lsym.Func.AddInlMark(p, inlMarks[m]) + // Make the inline mark a real nop, so it doesn't generate any code. + m.As = obj.ANOP + m.Pos = src.NoXPos + m.From = obj.Addr{} + m.To = obj.Addr{} + } + delete(inlMarksByPos, pos) + } + // Any unmatched inline marks now need to be added to the inlining tree (and will generate a nop instruction). + for _, p := range inlMarkList { + if p.As != obj.ANOP { + pp.curfn.Func.lsym.Func.AddInlMark(p, inlMarks[p]) + } + } + } + if Ctxt.Flag_locationlists { e.curfn.Func.DebugInfo = ssa.BuildFuncDebug(Ctxt, f, Debug_locationlist > 1, stackOffset) bstart := s.bstart diff --git a/src/cmd/internal/src/pos.go b/src/cmd/internal/src/pos.go index 5063b133f3..a30b4b6e4a 100644 --- a/src/cmd/internal/src/pos.go +++ b/src/cmd/internal/src/pos.go @@ -430,3 +430,7 @@ func (x lico) lineNumberHTML() string { } return fmt.Sprintf("<%s>%s%d", style, pfx, x.Line(), style) } + +func (x lico) atColumn1() lico { + return makeLico(x.Line(), 1) +} diff --git a/src/cmd/internal/src/xpos.go b/src/cmd/internal/src/xpos.go index d7ec91f92c..c94f9e997b 100644 --- a/src/cmd/internal/src/xpos.go +++ b/src/cmd/internal/src/xpos.go @@ -80,6 +80,12 @@ func (p XPos) LineNumberHTML() string { return p.lico.lineNumberHTML() } +// AtColumn1 returns the same location but shifted to column 1. +func (p XPos) AtColumn1() XPos { + p.lico = p.lico.atColumn1() + return p +} + // A PosTable tracks Pos -> XPos conversions and vice versa. // Its zero value is a ready-to-use PosTable. type PosTable struct {