[dev.ssa] cmd/compile: add HTML SSA printer

This is an initial implementation.
There are many rough edges and TODOs,
which will hopefully be polished out
with use.

Fixes #12071.

Change-Id: I1d6fd5a343063b5200623bceef2c2cfcc885794e
Reviewed-on: https://go-review.googlesource.com/13472
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index c8ec01f..882efc0 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -5,7 +5,9 @@
 package gc
 
 import (
+	"bytes"
 	"fmt"
+	"html"
 	"os"
 	"strings"
 
@@ -40,6 +42,18 @@
 	s.f = s.config.NewFunc()
 	s.f.Name = name
 
+	if name == os.Getenv("GOSSAFUNC") {
+		// TODO: tempfile? it is handy to have the location
+		// of this file be stable, so you can just reload in the browser.
+		s.config.HTML = ssa.NewHTMLWriter("ssa.html", &s, name)
+		// TODO: generate and print a mapping from nodes to values and blocks
+	}
+	defer func() {
+		if !usessa {
+			s.config.HTML.Close()
+		}
+	}()
+
 	// If SSA support for the function is incomplete,
 	// assume that any panics are due to violated
 	// invariants. Swallow them silently.
@@ -1811,6 +1825,30 @@
 			}
 			f.Logf("%s\t%s\n", s, p)
 		}
+		if f.Config.HTML != nil {
+			saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
+			ptxt.Ctxt.LineHist.PrintFilenameOnly = true
+			var buf bytes.Buffer
+			buf.WriteString("<code>")
+			buf.WriteString("<dl class=\"ssa-gen\">")
+			for p := ptxt; p != nil; p = p.Link {
+				buf.WriteString("<dt class=\"ssa-prog-src\">")
+				if v, ok := valueProgs[p]; ok {
+					buf.WriteString(v.HTML())
+				} else if b, ok := blockProgs[p]; ok {
+					buf.WriteString(b.HTML())
+				}
+				buf.WriteString("</dt>")
+				buf.WriteString("<dd class=\"ssa-prog\">")
+				buf.WriteString(html.EscapeString(p.String()))
+				buf.WriteString("</dd>")
+				buf.WriteString("</li>")
+			}
+			buf.WriteString("</dl>")
+			buf.WriteString("</code>")
+			f.Config.HTML.WriteColumn("genssa", buf.String())
+			ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
+		}
 	}
 
 	// Emit static data
@@ -1834,6 +1872,8 @@
 	ggloblsym(gcargs, 4, obj.RODATA|obj.DUPOK)
 	duint32(gclocals, 0, 0)
 	ggloblsym(gclocals, 4, obj.RODATA|obj.DUPOK)
+
+	f.Config.HTML.Close()
 }
 
 func genValue(v *ssa.Value) {