[dev.ssa] cmd/compile: default compile+test with SSA

Some tests disabled, some bifurcated into _ssa and not,
with appropriate logging added to compiler.

"tests/live.go" in particular needs attention.

SSA-specific testing removed, since it's all SSA now.

Added "-run_skips" option to tests/run.go to simplify
checking whether a test still fails (or how it fails)
on a skipped platform.

The compiler now compiles with SSA by default.
If you don't want SSA, specify GOSSAHASH=n (or N) as
an environment variable.  Function names ending in "_ssa"
are always SSA-compiled.

GOSSAFUNC=fname retains its "SSA for fname, log to ssa.html"
GOSSAPKG=pkg only has an effect when GOSSAHASH=n
GOSSAHASH=10101 etc retains its name-hash-matching behavior
for purposes of debugging.

See #13068

Change-Id: I8217bfeb34173533eaeb391b5f6935483c7d6b43
Reviewed-on: https://go-review.googlesource.com/16299
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: David Chase <drchase@google.com>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index b96661d..521e6d7 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -34,10 +34,10 @@
 	// 1. IF GOSSAFUNC == current function name THEN
 	//       compile this function with SSA and log output to ssa.html
 
-	// 2. IF GOSSAHASH == "y" or "Y" THEN
+	// 2. IF GOSSAHASH == "" THEN
 	//       compile this function (and everything else) with SSA
 
-	// 3. IF GOSSAHASH == "" THEN
+	// 3. IF GOSSAHASH == "n" or "N"
 	//       IF GOSSAPKG == current package name THEN
 	//          compile this function (and everything in this package) with SSA
 	//       ELSE
@@ -49,9 +49,10 @@
 	//       ELSE
 	//          compile this function with the old back end.
 
-	// Plan is for 3 to be remove, and the 2) dependence on GOSSAHASH changes
-	// from "y"/"Y" to empty -- then SSA is default, and is disabled by setting
-	// GOSSAHASH to a value that is neither 0 nor 1 (e.g., "N" or "X")
+	// Plan is for 3 to be removed when the tests are revised.
+	// SSA is now default, and is disabled by setting
+	// GOSSAHASH to n or N, or selectively with strings of
+	// 0 and 1.
 
 	if usessa {
 		fmt.Println("generating SSA for", name)
@@ -183,10 +184,11 @@
 	// Main call to ssa package to compile function
 	ssa.Compile(s.f)
 
-	if usessa || gossahash == "y" || gossahash == "Y" {
+	// gossahash = "y" is historical/symmetric-with-"n" -- i.e., not really needed.
+	if usessa || gossahash == "" || gossahash == "y" || gossahash == "Y" {
 		return s.f, true
 	}
-	if gossahash == "" {
+	if gossahash == "n" || gossahash == "N" {
 		if localpkg.Name != os.Getenv("GOSSAPKG") {
 			return s.f, false
 		}
@@ -298,9 +300,11 @@
 	return lab
 }
 
-func (s *state) Logf(msg string, args ...interface{})           { s.config.Logf(msg, args...) }
-func (s *state) Fatalf(msg string, args ...interface{})         { s.config.Fatalf(msg, args...) }
-func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimplementedf(msg, args...) }
+func (s *state) Logf(msg string, args ...interface{})            { s.config.Logf(msg, args...) }
+func (s *state) Fatalf(msg string, args ...interface{})          { s.config.Fatalf(msg, args...) }
+func (s *state) Unimplementedf(msg string, args ...interface{})  { s.config.Unimplementedf(msg, args...) }
+func (s *state) Warnl(line int, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
+func (s *state) Debug_checknil() bool                            { return s.config.Debug_checknil() }
 
 var (
 	// dummy node for the memory variable
@@ -1997,7 +2001,7 @@
 			if haspointers(et) {
 				// TODO: just one write barrier call for all of these writes?
 				// TODO: maybe just one writeBarrierEnabled check?
-				s.insertWB(et, addr)
+				s.insertWB(et, addr, n.Lineno)
 			}
 		}
 
@@ -2044,7 +2048,7 @@
 	}
 	s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
 	if wb {
-		s.insertWB(left.Type, addr)
+		s.insertWB(left.Type, addr, left.Lineno)
 	}
 }
 
@@ -2566,7 +2570,7 @@
 // been stored at location p.  Tell the runtime about this write.
 // Note: there must be no GC suspension points between the write and
 // the call that this function inserts.
-func (s *state) insertWB(t *Type, p *ssa.Value) {
+func (s *state) insertWB(t *Type, p *ssa.Value, line int32) {
 	// if writeBarrierEnabled {
 	//   typedmemmove_nostore(&t, p)
 	// }
@@ -2586,6 +2590,10 @@
 	taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
 	s.rtcall(typedmemmove_nostore, true, nil, taddr, p)
 
+	if Debug_wb > 0 {
+		Warnl(int(line), "write barrier")
+	}
+
 	b.AddEdgeTo(s.curBlock)
 }
 
@@ -2985,6 +2993,10 @@
 		Fatalf("dottype needs a direct iface type %s", n.Type)
 	}
 
+	if Debug_typeassert > 0 {
+		Warnl(int(n.Lineno), "type assertion inlined")
+	}
+
 	// TODO:  If we have a nonempty interface and its itab field is nil,
 	// then this test is redundant and ifaceType should just branch directly to bFail.
 	cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
@@ -4523,6 +4535,16 @@
 	e.unimplemented = true
 }
 
+// Warnl reports a "warning", which is usually flag-triggered
+// logging output for the benefit of tests.
+func (e *ssaExport) Warnl(line int, fmt_ string, args ...interface{}) {
+	Warnl(line, fmt_, args...)
+}
+
+func (e *ssaExport) Debug_checknil() bool {
+	return Debug_checknil != 0
+}
+
 func (n *Node) Typ() ssa.Type {
 	return n.Type
 }
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index cfba10b..014c960 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -49,6 +49,12 @@
 	// Unimplemented reports that the function cannot be compiled.
 	// It will be removed once SSA work is complete.
 	Unimplementedf(msg string, args ...interface{})
+
+	// Warnl writes compiler messages in the form expected by "errorcheck" tests
+	Warnl(line int, fmt_ string, args ...interface{})
+
+	// Fowards the Debug_checknil flag from gc
+	Debug_checknil() bool
 }
 
 type Frontend interface {
@@ -100,9 +106,11 @@
 	return &Func{Config: c, NamedValues: map[GCNode][]*Value{}}
 }
 
-func (c *Config) Logf(msg string, args ...interface{})           { c.fe.Logf(msg, args...) }
-func (c *Config) Fatalf(msg string, args ...interface{})         { c.fe.Fatalf(msg, args...) }
-func (c *Config) Unimplementedf(msg string, args ...interface{}) { c.fe.Unimplementedf(msg, args...) }
+func (c *Config) Logf(msg string, args ...interface{})            { c.fe.Logf(msg, args...) }
+func (c *Config) Fatalf(msg string, args ...interface{})          { c.fe.Fatalf(msg, args...) }
+func (c *Config) Unimplementedf(msg string, args ...interface{})  { c.fe.Unimplementedf(msg, args...) }
+func (c *Config) Warnl(line int, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) }
+func (c *Config) Debug_checknil() bool                            { return c.fe.Debug_checknil() }
 
 // TODO(khr): do we really need a separate Config, or can we just
 // store all its fields inside a Func?
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index d0ba7b1..c37db75 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -32,9 +32,11 @@
 	return nil
 }
 
-func (d DummyFrontend) Logf(msg string, args ...interface{})           { d.t.Logf(msg, args...) }
-func (d DummyFrontend) Fatalf(msg string, args ...interface{})         { d.t.Fatalf(msg, args...) }
-func (d DummyFrontend) Unimplementedf(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
+func (d DummyFrontend) Logf(msg string, args ...interface{})            { d.t.Logf(msg, args...) }
+func (d DummyFrontend) Fatalf(msg string, args ...interface{})          { d.t.Fatalf(msg, args...) }
+func (d DummyFrontend) Unimplementedf(msg string, args ...interface{})  { d.t.Fatalf(msg, args...) }
+func (d DummyFrontend) Warnl(line int, msg string, args ...interface{}) { d.t.Logf(msg, args...) }
+func (d DummyFrontend) Debug_checknil() bool                            { return false }
 
 func (d DummyFrontend) TypeBool() Type    { return TypeBool }
 func (d DummyFrontend) TypeInt8() Type    { return TypeInt8 }
diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go
index 5b012a8..f8caa7b 100644
--- a/src/cmd/compile/internal/ssa/nilcheck.go
+++ b/src/cmd/compile/internal/ssa/nilcheck.go
@@ -88,6 +88,13 @@
 					// Eliminate the nil check.
 					// The deadcode pass will remove vestigial values,
 					// and the fuse pass will join this block with its successor.
+
+					// Logging in the style of the former compiler -- and omit line 1,
+					// which is usually in generated code.
+					if f.Config.Debug_checknil() && int(node.block.Control.Line) > 1 {
+						f.Config.Warnl(int(node.block.Control.Line), "removed nil check")
+					}
+
 					switch node.block.Kind {
 					case BlockIf:
 						node.block.Kind = BlockFirst