}
}
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")
}
}
"int32 %d": "",
"int32 %v": "",
"int32 %x": "",
+ "int64 %.5d": "",
"int64 %+d": "",
"int64 %-10d": "",
"int64 %X": "",
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
}
}
padding: 5px;
}
+td.ssa-prog {
+ width: 600px;
+ word-wrap: break-word;
+}
+
li {
list-style-type: none;
}
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; }
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>")
// 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 += " <" + html.EscapeString(v.Type.String()) + ">"
s += html.EscapeString(v.auxString())
for _, a := range v.Args {
if len(names) != 0 {
s += " (" + strings.Join(names, ", ") + ")"
}
+
s += "</span>"
return s
}
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
}
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",
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>"
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 {