]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: use existing instructions instead of nops for inline marks
authorKeith Randall <khr@google.com>
Tue, 15 Jan 2019 22:50:09 +0000 (14:50 -0800)
committerKeith Randall <khr@golang.org>
Mon, 25 Mar 2019 16:49:29 +0000 (16:49 +0000)
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 <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
misc/cgo/test/callback.go
src/cmd/compile/internal/gc/dwinl.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/internal/src/pos.go
src/cmd/internal/src/xpos.go

index d48aeaabd97886ba7c097c19a0cba97e2b327611..e749650293148ac715354c850f7c1371f17302c8 100644 (file)
@@ -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])
                }
index cc42a04c64d572eff8234e0d4fe9463a9d7d5909..27e2cbcd982c6101938a55e53278da0c3d7fd8f9 100644 (file)
@@ -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) {
index 52515bdb1da1426d64a280c71fea07e2565d2c80..a7c1917ff11ce7c00b611785440c338bfc4ed26d 100644 (file)
@@ -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
index 5063b133f30ab2c5d8c9a6aaee146b525757f6aa..a30b4b6e4a11b844cd939cba21748e9361bd1398 100644 (file)
@@ -430,3 +430,7 @@ func (x lico) lineNumberHTML() string {
        }
        return fmt.Sprintf("<%s>%s%d</%s>", style, pfx, x.Line(), style)
 }
+
+func (x lico) atColumn1() lico {
+       return makeLico(x.Line(), 1)
+}
index d7ec91f92c97b68daa8627f6a18b370c71e165a0..c94f9e997b62ac9704639425078dcf134e20dd9d 100644 (file)
@@ -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 {