]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add line numbers to values & blocks in ssa.html
authorDavid Chase <drchase@google.com>
Tue, 10 Oct 2017 18:44:15 +0000 (14:44 -0400)
committerDavid Chase <drchase@google.com>
Wed, 11 Oct 2017 21:46:20 +0000 (21:46 +0000)
In order to improve the line numbering for debuggers,
it's necessary to trace lines through compilation.
This makes it (much) easier to follow.

The format of the last column of the ssa.html output was
also changed to reduce the spamminess of the file name,
which is usually the same and makes it far harder to read
instructions and line numbers, and to make it wider and also
able to break words when wrapping (long path names still
can push off the end otherwise; side-to-side scrolling was
tried but was more annoying than the occasional wrapped
line).

Sample output now, where [...] is elision for sake of making
the CL character-counter happy -- and the (##) line numbers
are rendered in italics and a smaller font (11 point) under
control of a CSS class "line-number".

genssa
      # /Users/drchase/[...]/ssa/testdata/hist.go
      00000 (35) TEXT "".main(SB)
      00001 (35) FUNCDATA $0, gclocals·7be4bb[...]1e8b(SB)
      00002 (35) FUNCDATA $1, gclocals·9ab98a[...]4568(SB)
v920  00003 (36) LEAQ ""..autotmp_31-640(SP), DI
v858  00004 (36) XORPS X0, X0
v6    00005 (36) LEAQ -48(DI), DI
v6    00006 (36) DUFFZERO $277
v576  00007 (36) LEAQ ""..autotmp_31-640(SP), AX
v10   00008 (36) TESTB AX, (AX)
b1    00009 (36) JMP 10

and from an earlier phase:

b18: ← b17
v242 (47) = Copy <mem> v238
v243 (47) = VarKill <mem> {.autotmp_16} v242
v244 (48) = Addr <**bufio.Scanner> {scanner} v2
v245 (48) = Load <*bufio.Scanner> v244 v243
[...]
v279 (49) = Store <mem> {int64} v277 v276 v278
v280 (49) = Addr <*error> {.autotmp_18} v2
v281 (49) = Load <error> v280 v279
v282 (49) = Addr <*error> {err} v2
v283 (49) = VarDef <mem> {err} v279
v284 (49) = Store <mem> {error} v282 v281 v283
v285 (47) = VarKill <mem> {.autotmp_18} v284
v286 (47) = VarKill <mem> {.autotmp_17} v285
v287 (50) = Addr <*error> {err} v2
v288 (50) = Load <error> v287 v286
v289 (50) = NeqInter <bool> v288 v51
If v289 → b21 b22 (line 50)

Change-Id: I3f46310918f965761f59e6f03ea53067237c28a8
Reviewed-on: https://go-review.googlesource.com/69591
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/compile/fmt_test.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/html.go
src/cmd/internal/obj/util.go

index 6d18d495c37bf91c9dc11bb10e98afe204bacb91..17716f82f257aab34bb5bd2f92a1a42f37bc88b7 100644 (file)
@@ -229,7 +229,7 @@ func TestFormats(t *testing.T) {
                        }
                }
                if mismatch {
-                       t.Errorf("knownFormats is out of date; please run with -v to regenerate")
+                       t.Errorf("knownFormats is out of date; please 'go test -v fmt_test.go > foo', then extract new definition of knownFormats from foo")
                }
        }
 
@@ -683,6 +683,7 @@ var knownFormats = map[string]string{
        "int32 %d":                                        "",
        "int32 %v":                                        "",
        "int32 %x":                                        "",
+       "int64 %.5d":                                      "",
        "int64 %+d":                                       "",
        "int64 %-10d":                                     "",
        "int64 %X":                                        "",
index c633ee4c932f927f44991a7227e0c70d1d4f4573..69ed613412ea16f55c64c44120b7d056a3abde53 100644 (file)
@@ -4606,22 +4606,31 @@ func genssa(f *ssa.Func, pp *Progs) {
                        var buf bytes.Buffer
                        buf.WriteString("<code>")
                        buf.WriteString("<dl class=\"ssa-gen\">")
+                       filename := ""
                        for p := pp.Text; p != nil; p = p.Link {
+                               // Don't spam every line with the file name, which is often huge.
+                               // Only print changes.
+                               if f := p.FileName(); f != filename {
+                                       filename = f
+                                       buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
+                                       buf.WriteString(html.EscapeString("# " + filename))
+                                       buf.WriteString("</dd>")
+                               }
+
                                buf.WriteString("<dt class=\"ssa-prog-src\">")
                                if v, ok := progToValue[p]; ok {
                                        buf.WriteString(v.HTML())
                                } else if b, ok := progToBlock[p]; ok {
-                                       buf.WriteString(b.HTML())
+                                       buf.WriteString("<b>" + b.HTML() + "</b>")
                                }
                                buf.WriteString("</dt>")
                                buf.WriteString("<dd class=\"ssa-prog\">")
-                               buf.WriteString(html.EscapeString(p.String()))
+                               buf.WriteString(fmt.Sprintf("%.5d <span class=\"line-number\">(%s)</span> %s", p.Pc, p.LineNumber(), html.EscapeString(p.InstructionString())))
                                buf.WriteString("</dd>")
-                               buf.WriteString("</li>")
                        }
                        buf.WriteString("</dl>")
                        buf.WriteString("</code>")
-                       f.HTMLWriter.WriteColumn("genssa", buf.String())
+                       f.HTMLWriter.WriteColumn("genssa", "ssa-prog", buf.String())
                        // pp.Text.Ctxt.LineHist.PrintFilenameOnly = saved
                }
        }
index bb87378bddf3826bb921f2e5666ec09ff3e0a297..47f37f23375201b090e9de98a7eb86dcb86cb0f3 100644 (file)
@@ -66,6 +66,11 @@ th, td {
     padding: 5px;
 }
 
+td.ssa-prog {
+    width: 600px;
+    word-wrap: break-word;
+}
+
 li {
     list-style-type: none;
 }
@@ -121,6 +126,11 @@ dd.ssa-prog {
     font-style: italic;
 }
 
+.line-number {
+    font-style: italic;
+    font-size: 11px;
+}
+
 .highlight-yellow         { background-color: yellow; }
 .highlight-aquamarine     { background-color: aquamarine; }
 .highlight-coral          { background-color: coral; }
@@ -310,17 +320,21 @@ func (w *HTMLWriter) WriteFunc(title string, f *Func) {
        if w == nil {
                return // avoid generating HTML just to discard it
        }
-       w.WriteColumn(title, f.HTML())
+       w.WriteColumn(title, "", f.HTML())
        // TODO: Add visual representation of f's CFG.
 }
 
 // WriteColumn writes raw HTML in a column headed by title.
 // It is intended for pre- and post-compilation log output.
-func (w *HTMLWriter) WriteColumn(title string, html string) {
+func (w *HTMLWriter) WriteColumn(title, class, html string) {
        if w == nil {
                return
        }
-       w.WriteString("<td>")
+       if class == "" {
+               w.WriteString("<td>")
+       } else {
+               w.WriteString("<td class=\"" + class + "\">")
+       }
        w.WriteString("<h2>" + title + "</h2>")
        w.WriteString(html)
        w.WriteString("</td>")
@@ -353,7 +367,14 @@ func (v *Value) LongHTML() string {
        // We already have visual noise in the form of punctuation
        // maybe we could replace some of that with formatting.
        s := fmt.Sprintf("<span class=\"%s ssa-long-value\">", v.String())
-       s += fmt.Sprintf("%s = %s", v.HTML(), v.Op.String())
+
+       linenumber := "<span class=\"line-number\">(?)</span>"
+       if v.Pos.IsKnown() {
+               linenumber = fmt.Sprintf("<span class=\"line-number\">(%d)</span>", v.Pos.Line())
+       }
+
+       s += fmt.Sprintf("%s %s = %s", v.HTML(), linenumber, v.Op.String())
+
        s += " &lt;" + html.EscapeString(v.Type.String()) + "&gt;"
        s += html.EscapeString(v.auxString())
        for _, a := range v.Args {
@@ -375,6 +396,7 @@ func (v *Value) LongHTML() string {
        if len(names) != 0 {
                s += " (" + strings.Join(names, ", ") + ")"
        }
+
        s += "</span>"
        return s
 }
@@ -409,6 +431,11 @@ func (b *Block) LongHTML() string {
        case BranchLikely:
                s += " (likely)"
        }
+       if b.Pos.IsKnown() {
+               // TODO does not begin to deal with the full complexity of line numbers.
+               // Maybe we want a string/slice instead, of outer-inner when inlining.
+               s += fmt.Sprintf(" (line %d)", b.Pos.Line())
+       }
        return s
 }
 
index bf2d209d7f10d0dbeec9bdd3802a1cd0c71a014a..67c74c2f898330e1e86a2e0a676f9d014acd2cfd 100644 (file)
@@ -13,10 +13,34 @@ import (
 
 const REG_NONE = 0
 
+// Line returns a string containing the filename and line number for p
 func (p *Prog) Line() string {
        return p.Ctxt.OutermostPos(p.Pos).Format(false)
 }
 
+// LineNumber returns a string containing the line number for p's position
+func (p *Prog) LineNumber() string {
+       pos := p.Ctxt.OutermostPos(p.Pos)
+       if !pos.IsKnown() {
+               return "?"
+       }
+       return fmt.Sprintf("%d", pos.Line())
+}
+
+// FileName returns a string containing the filename for p's position
+func (p *Prog) FileName() string {
+       // TODO LineNumber and FileName cases don't handle full generality of positions,
+       // but because these are currently used only for GOSSAFUNC debugging output, that
+       // is okay.  The intent is that "LineNumber()" yields the rapidly varying part,
+       // while "FileName()" yields the longer and slightly more constant material.
+       pos := p.Ctxt.OutermostPos(p.Pos)
+       if !pos.IsKnown() {
+               return "<unknown file name>"
+       }
+
+       return pos.Filename()
+}
+
 var armCondCode = []string{
        ".EQ",
        ".NE",
@@ -72,6 +96,18 @@ func (p *Prog) String() string {
        if p == nil {
                return "<nil Prog>"
        }
+       if p.Ctxt == nil {
+               return "<Prog without ctxt>"
+       }
+       return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString())
+}
+
+// InstructionString returns a string representation of the instruction without preceding
+// program counter or file and line number.
+func (p *Prog) InstructionString() string {
+       if p == nil {
+               return "<nil Prog>"
+       }
 
        if p.Ctxt == nil {
                return "<Prog without ctxt>"
@@ -81,7 +117,7 @@ func (p *Prog) String() string {
 
        var buf bytes.Buffer
 
-       fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc)
+       fmt.Fprintf(&buf, "%v%s", p.As, sc)
        sep := "\t"
 
        if p.From.Type != TYPE_NONE {