cmd/compile: teach rulegen to remove unused decls

First, add cpu and memory profiling flags, as these are useful to see
where rulegen is spending its time. It now takes many seconds to run on
a recent laptop, so we have to keep an eye on what it's doing.

Second, stop writing '_ = var' lines to keep imports and variables used
at all times. Now that rulegen removes all such unused names, they're
unnecessary.

To perform the removal, lean on go/types to first detect what names are
unused. We can configure it to give us all the type-checking errors in a
file, so we can collect all "declared but not used" errors in a single
pass.

We then use astutil.Apply to remove the relevant nodes based on the line
information from each unused error. This allows us to apply the changes
without having to do extra parser+printer roundtrips to plaintext, which
are far too expensive.

We need to do multiple such passes, as removing an unused variable
declaration might then make another declaration unused. Two passes are
enough to clean every file at the moment, so add a limit of three passes
for now to avoid eating cpu uncontrollably by accident.

The resulting performance of the changes above is a ~30% loss across the
table, since go/types is fairly expensive. The numbers were obtained
with 'benchcmd Rulegen go run *.go', which involves compiling rulegen
itself, but that seems reflective of how the program is used.

	name     old time/op         new time/op         delta
	Rulegen          5.61s ± 0%          7.36s ± 0%  +31.17%  (p=0.016 n=5+4)

	name     old user-time/op    new user-time/op    delta
	Rulegen          7.20s ± 1%          9.92s ± 1%  +37.76%  (p=0.016 n=5+4)

	name     old sys-time/op     new sys-time/op     delta
	Rulegen          135ms ±19%          169ms ±17%  +25.66%  (p=0.032 n=5+5)

	name     old peak-RSS-bytes  new peak-RSS-bytes  delta
	Rulegen         71.0MB ± 2%         85.6MB ± 2%  +20.56%  (p=0.008 n=5+5)

We can live with a bit more resource usage, but the time/op getting
close to 10s isn't good. To win that back, introduce concurrency in
main.go. This further increases resource usage a bit, but the real time
on this quad-core laptop is greatly reduced. The final benchstat is as
follows:

	name     old time/op         new time/op         delta
	Rulegen          5.61s ± 0%          3.97s ± 1%   -29.26%  (p=0.008 n=5+5)

	name     old user-time/op    new user-time/op    delta
	Rulegen          7.20s ± 1%         13.91s ± 1%   +93.09%  (p=0.008 n=5+5)

	name     old sys-time/op     new sys-time/op     delta
	Rulegen          135ms ±19%          269ms ± 9%   +99.17%  (p=0.008 n=5+5)

	name     old peak-RSS-bytes  new peak-RSS-bytes  delta
	Rulegen         71.0MB ± 2%        226.3MB ± 1%  +218.72%  (p=0.008 n=5+5)

It might be possible to reduce the cpu or memory usage in the future,
such as configuring go/types to do less work, or taking shortcuts to
avoid having to run it many times. For now, ~2x cpu and ~4x memory usage
seems like a fair trade for a faster and better rulegen.

Finally, we can remove the old code that tried to remove some unused
variables in a hacky and unmaintainable way.

Change-Id: Iff9e83e3f253babf5a1bd48cc993033b8550cee6
Reviewed-on: https://go-review.googlesource.com/c/go/+/189798
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go
index bfecb9b..9c0e090 100644
--- a/src/cmd/compile/internal/ssa/gen/main.go
+++ b/src/cmd/compile/internal/ssa/gen/main.go
@@ -15,10 +15,14 @@
 	"go/format"
 	"io/ioutil"
 	"log"
+	"os"
 	"path"
 	"regexp"
+	"runtime"
+	"runtime/pprof"
 	"sort"
 	"strings"
+	"sync"
 )
 
 type arch struct {
@@ -93,11 +97,36 @@
 
 var archs []arch
 
+var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
+var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
+
 func main() {
 	flag.Parse()
+	if *cpuprofile != "" {
+		f, err := os.Create(*cpuprofile)
+		if err != nil {
+			log.Fatal("could not create CPU profile: ", err)
+		}
+		defer f.Close()
+		if err := pprof.StartCPUProfile(f); err != nil {
+			log.Fatal("could not start CPU profile: ", err)
+		}
+		defer pprof.StopCPUProfile()
+	}
 	sort.Sort(ArchsByName(archs))
 	genOp()
 	genLower()
+	if *memprofile != "" {
+		f, err := os.Create(*memprofile)
+		if err != nil {
+			log.Fatal("could not create memory profile: ", err)
+		}
+		defer f.Close()
+		runtime.GC() // get up-to-date statistics
+		if err := pprof.WriteHeapProfile(f); err != nil {
+			log.Fatal("could not write memory profile: ", err)
+		}
+	}
 }
 
 func genOp() {
@@ -395,11 +424,26 @@
 	return s
 }
 
+// genLower generates all arch-specific rewrite Go source files. The files are
+// generated and written concurrently, since it's a CPU-intensive task that can
+// easily make use of many cores on a machine.
+//
+// Note that there is no limit on the concurrency at the moment. On a four-core
+// laptop at the time of writing, peak RSS usually reached ~230MiB, which seems
+// doable by practially any machine nowadays. If that stops being the case, we
+// can cap this func to a fixed number of architectures being generated at once.
 func genLower() {
+	var wg sync.WaitGroup
 	for _, a := range archs {
-		genRules(a)
-		genSplitLoadRules(a)
+		a := a
+		wg.Add(1)
+		go func() {
+			genRules(a)
+			genSplitLoadRules(a)
+			wg.Done()
+		}()
 	}
+	wg.Wait()
 }
 
 // countRegs returns the number of set bits in the register mask.
diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
index 0e89af7..500d984 100644
--- a/src/cmd/compile/internal/ssa/gen/rulegen.go
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -21,14 +21,15 @@
 	"go/parser"
 	"go/printer"
 	"go/token"
+	"go/types"
 	"io"
-	"io/ioutil"
 	"log"
-	"math"
 	"os"
 	"regexp"
 	"sort"
 	"strings"
+
+	"golang.org/x/tools/go/ast/astutil"
 )
 
 // rule syntax:
@@ -165,7 +166,7 @@
 	}
 	sort.Strings(ops)
 
-	file := &File{arch: arch, suffix: suff}
+	genFile := &File{arch: arch, suffix: suff}
 	const chunkSize = 10
 	// Main rewrite routine is a switch on v.Op.
 	fn := &Func{kind: "Value"}
@@ -182,7 +183,7 @@
 	}
 	fn.add(sw)
 	fn.add(stmtf("return false"))
-	file.add(fn)
+	genFile.add(fn)
 
 	// Generate a routine per op. Note that we don't make one giant routine
 	// because it is too big for some compilers.
@@ -201,7 +202,10 @@
 				kind:   "Value",
 				suffix: fmt.Sprintf("_%s_%d", op, chunk),
 			}
-			var rewrites bodyBase
+			fn.add(declf("b", "v.Block"))
+			fn.add(declf("config", "b.Func.Config"))
+			fn.add(declf("fe", "b.Func.fe"))
+			fn.add(declf("typ", "&b.Func.Config.Types"))
 			for _, rule := range rules[chunk:endchunk] {
 				if rr != nil && !rr.canFail {
 					log.Fatalf("unconditional rule %s is followed by other rules", rr.match)
@@ -219,38 +223,12 @@
 				if *genLog {
 					rr.add(stmtf("logRule(%q)", rule.loc))
 				}
-				rewrites.add(rr)
+				fn.add(rr)
 			}
-
-			// TODO(mvdan): remove unused vars later instead
-			uses := make(map[string]int)
-			walk(&rewrites, func(node Node) {
-				switch node := node.(type) {
-				case *Declare:
-					// work around var shadowing
-					// TODO(mvdan): forbid it instead.
-					uses[node.name] = math.MinInt32
-				case *ast.Ident:
-					uses[node.Name]++
-				}
-			})
-			if uses["b"]+uses["config"]+uses["fe"]+uses["typ"] > 0 {
-				fn.add(declf("b", "v.Block"))
-			}
-			if uses["config"] > 0 {
-				fn.add(declf("config", "b.Func.Config"))
-			}
-			if uses["fe"] > 0 {
-				fn.add(declf("fe", "b.Func.fe"))
-			}
-			if uses["typ"] > 0 {
-				fn.add(declf("typ", "&b.Func.Config.Types"))
-			}
-			fn.add(rewrites.list...)
 			if rr.canFail {
 				fn.add(stmtf("return false"))
 			}
-			file.add(fn)
+			genFile.add(fn)
 		}
 	}
 
@@ -258,11 +236,8 @@
 	// so we can make this one function with a switch.
 	fn = &Func{kind: "Block"}
 	fn.add(declf("config", "b.Func.Config"))
-	// TODO(mvdan): declare these only if needed
 	fn.add(declf("typ", "&config.Types"))
-	fn.add(stmtf("_ = typ"))
 	fn.add(declf("v", "b.Control"))
-	fn.add(stmtf("_ = v"))
 
 	sw = &Switch{expr: exprf("b.Kind")}
 	ops = ops[:0]
@@ -279,52 +254,69 @@
 	}
 	fn.add(sw)
 	fn.add(stmtf("return false"))
-	file.add(fn)
+	genFile.add(fn)
 
-	// gofmt result
+	// Remove unused imports and variables.
 	buf := new(bytes.Buffer)
-	fprint(buf, file)
-	b := buf.Bytes()
-	src, err := format.Source(b)
+	fprint(buf, genFile)
+	fset := token.NewFileSet()
+	file, err := parser.ParseFile(fset, "", buf, parser.ParseComments)
 	if err != nil {
-		fmt.Printf("%s\n", b)
-		panic(err)
+		log.Fatal(err)
 	}
-	// Write to file
-	if err := ioutil.WriteFile("../rewrite"+arch.name+suff+".go", src, 0666); err != nil {
-		log.Fatalf("can't write output: %v\n", err)
-	}
-}
+	tfile := fset.File(file.Pos())
 
-func walk(node Node, fn func(Node)) {
-	fn(node)
-	switch node := node.(type) {
-	case *bodyBase:
-	case *File:
-	case *Func:
-	case *Switch:
-		walk(node.expr, fn)
-	case *Case:
-		walk(node.expr, fn)
-	case *RuleRewrite:
-	case *Declare:
-		walk(node.value, fn)
-	case *CondBreak:
-		walk(node.expr, fn)
-	case ast.Node:
-		ast.Inspect(node, func(node ast.Node) bool {
-			fn(node)
-			return true
-		})
-	default:
-		log.Fatalf("cannot walk %T", node)
-	}
-	if wb, ok := node.(interface{ body() []Statement }); ok {
-		for _, node := range wb.body() {
-			walk(node, fn)
+	for n := 0; n < 3; n++ {
+		unused := make(map[token.Pos]bool)
+		conf := types.Config{Error: func(err error) {
+			if terr, ok := err.(types.Error); ok && strings.Contains(terr.Msg, "not used") {
+				unused[terr.Pos] = true
+			}
+		}}
+		_, _ = conf.Check("ssa", fset, []*ast.File{file}, nil)
+		if len(unused) == 0 {
+			break
 		}
+		pre := func(c *astutil.Cursor) bool {
+			if node := c.Node(); node != nil && unused[node.Pos()] {
+				c.Delete()
+				// Unused imports and declarations use exactly
+				// one line. Prevent leaving an empty line.
+				tfile.MergeLine(tfile.Position(node.Pos()).Line)
+				return false
+			}
+			return true
+		}
+		post := func(c *astutil.Cursor) bool {
+			switch node := c.Node().(type) {
+			case *ast.GenDecl:
+				if len(node.Specs) == 0 {
+					c.Delete()
+				}
+			}
+			return true
+		}
+		file = astutil.Apply(file, pre, post).(*ast.File)
 	}
-	fn(nil)
+
+	// Write the well-formatted source to file
+	f, err := os.Create("../rewrite" + arch.name + suff + ".go")
+	if err != nil {
+		log.Fatalf("can't write output: %v", err)
+	}
+	defer f.Close()
+	// gofmt result; use a buffered writer, as otherwise go/format spends
+	// far too much time in syscalls.
+	bw := bufio.NewWriter(f)
+	if err := format.Node(bw, fset, file); err != nil {
+		log.Fatalf("can't format output: %v", err)
+	}
+	if err := bw.Flush(); err != nil {
+		log.Fatalf("can't write output: %v", err)
+	}
+	if err := f.Close(); err != nil {
+		log.Fatalf("can't write output: %v", err)
+	}
 }
 
 func fprint(w io.Writer, n Node) {
@@ -333,18 +325,13 @@
 		fmt.Fprintf(w, "// Code generated from gen/%s%s.rules; DO NOT EDIT.\n", n.arch.name, n.suffix)
 		fmt.Fprintf(w, "// generated with: cd gen; go run *.go\n")
 		fmt.Fprintf(w, "\npackage ssa\n")
-		// TODO(mvdan): keep the needed imports only
-		fmt.Fprintln(w, "import \"fmt\"")
-		fmt.Fprintln(w, "import \"math\"")
-		fmt.Fprintln(w, "import \"cmd/internal/obj\"")
-		fmt.Fprintln(w, "import \"cmd/internal/objabi\"")
-		fmt.Fprintln(w, "import \"cmd/compile/internal/types\"")
-		fmt.Fprintln(w, "var _ = fmt.Println   // in case not otherwise used")
-		fmt.Fprintln(w, "var _ = math.MinInt8  // in case not otherwise used")
-		fmt.Fprintln(w, "var _ = obj.ANOP      // in case not otherwise used")
-		fmt.Fprintln(w, "var _ = objabi.GOROOT // in case not otherwise used")
-		fmt.Fprintln(w, "var _ = types.TypeMem // in case not otherwise used")
-		fmt.Fprintln(w)
+		for _, path := range []string{
+			"fmt", "math",
+			"cmd/internal/obj", "cmd/internal/objabi",
+			"cmd/compile/internal/types",
+		} {
+			fmt.Fprintf(w, "import %q\n", path)
+		}
 		for _, f := range n.list {
 			f := f.(*Func)
 			fmt.Fprintf(w, "func rewrite%s%s%s%s(", f.kind, n.arch.name, n.suffix, f.suffix)
diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go
index 8f896ec..812aa94 100644
--- a/src/cmd/compile/internal/ssa/rewrite386.go
+++ b/src/cmd/compile/internal/ssa/rewrite386.go
@@ -3,18 +3,9 @@
 
 package ssa
 
-import "fmt"
 import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValue386(v *Value) bool {
 	switch v.Op {
 	case Op386ADCL:
@@ -24539,11 +24530,7 @@
 	}
 }
 func rewriteBlock386(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
 	v := b.Control
-	_ = v
 	switch b.Kind {
 	case Block386EQ:
 		// match: (EQ (InvertFlags cmp) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewrite386splitload.go b/src/cmd/compile/internal/ssa/rewrite386splitload.go
index 1eaf2d9..b6c1989 100644
--- a/src/cmd/compile/internal/ssa/rewrite386splitload.go
+++ b/src/cmd/compile/internal/ssa/rewrite386splitload.go
@@ -3,18 +3,6 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
-import "cmd/compile/internal/types"
-
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValue386splitload(v *Value) bool {
 	switch v.Op {
 	case Op386CMPBconstload:
@@ -168,11 +156,6 @@
 	}
 }
 func rewriteBlock386splitload(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
-	v := b.Control
-	_ = v
 	switch b.Kind {
 	}
 	return false
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index 8c02897..1f88821 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -3,18 +3,9 @@
 
 package ssa
 
-import "fmt"
 import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValueAMD64(v *Value) bool {
 	switch v.Op {
 	case OpAMD64ADCQ:
@@ -64753,10 +64744,7 @@
 }
 func rewriteBlockAMD64(b *Block) bool {
 	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
 	v := b.Control
-	_ = v
 	switch b.Kind {
 	case BlockAMD64EQ:
 		// match: (EQ (TESTL (SHLL (MOVLconst [1]) x) y))
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go b/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go
index 0a0ff2d..2cccc8d 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64splitload.go
@@ -3,18 +3,6 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
-import "cmd/compile/internal/types"
-
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValueAMD64splitload(v *Value) bool {
 	switch v.Op {
 	case OpAMD64CMPBconstload:
@@ -217,11 +205,6 @@
 	}
 }
 func rewriteBlockAMD64splitload(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
-	v := b.Control
-	_ = v
 	switch b.Kind {
 	}
 	return false
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index 72c07c9..6a32374 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -3,18 +3,9 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
 import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValueARM(v *Value) bool {
 	switch v.Op {
 	case OpARMADC:
@@ -21785,11 +21776,7 @@
 	}
 }
 func rewriteBlockARM(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
 	v := b.Control
-	_ = v
 	switch b.Kind {
 	case BlockARMEQ:
 		// match: (EQ (FlagEQ) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index 9dfd848..fc67772 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -3,18 +3,8 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValueARM64(v *Value) bool {
 	switch v.Op {
 	case OpARM64ADCSflags:
@@ -38293,11 +38283,7 @@
 	}
 }
 func rewriteBlockARM64(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
 	v := b.Control
-	_ = v
 	switch b.Kind {
 	case BlockARM64EQ:
 		// match: (EQ (CMPWconst [0] x:(ANDconst [c] y)) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go
index 6e0fa2b..5ce0ec3 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go
@@ -3,18 +3,8 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValueMIPS(v *Value) bool {
 	switch v.Op {
 	case OpAdd16:
@@ -9452,11 +9442,7 @@
 	}
 }
 func rewriteBlockMIPS(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
 	v := b.Control
-	_ = v
 	switch b.Kind {
 	case BlockMIPSEQ:
 		// match: (EQ (FPFlagTrue cmp) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
index db10450..8b75c03 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
@@ -3,18 +3,8 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValueMIPS64(v *Value) bool {
 	switch v.Op {
 	case OpAdd16:
@@ -10186,11 +10176,7 @@
 	}
 }
 func rewriteBlockMIPS64(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
 	v := b.Control
-	_ = v
 	switch b.Kind {
 	case BlockMIPS64EQ:
 		// match: (EQ (FPFlagTrue cmp) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index d35cf6e..1bc1651 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -3,18 +3,10 @@
 
 package ssa
 
-import "fmt"
 import "math"
-import "cmd/internal/obj"
 import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValuePPC64(v *Value) bool {
 	switch v.Op {
 	case OpAbs:
@@ -30305,11 +30297,7 @@
 	}
 }
 func rewriteBlockPPC64(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
 	v := b.Control
-	_ = v
 	switch b.Kind {
 	case BlockPPC64EQ:
 		// match: (EQ (CMPconst [0] (ANDconst [c] x)) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go
index fa1de9a..2de5e1b 100644
--- a/src/cmd/compile/internal/ssa/rewriteS390X.go
+++ b/src/cmd/compile/internal/ssa/rewriteS390X.go
@@ -3,18 +3,8 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValueS390X(v *Value) bool {
 	switch v.Op {
 	case OpAdd16:
@@ -41547,9 +41537,7 @@
 func rewriteBlockS390X(b *Block) bool {
 	config := b.Func.Config
 	typ := &config.Types
-	_ = typ
 	v := b.Control
-	_ = v
 	switch b.Kind {
 	case BlockS390XEQ:
 		// match: (EQ (InvertFlags cmp) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go
index acfbb24..98ca6f6 100644
--- a/src/cmd/compile/internal/ssa/rewriteWasm.go
+++ b/src/cmd/compile/internal/ssa/rewriteWasm.go
@@ -3,18 +3,9 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
 import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValueWasm(v *Value) bool {
 	switch v.Op {
 	case OpAbs:
@@ -6555,11 +6546,6 @@
 	}
 }
 func rewriteBlockWasm(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
-	v := b.Control
-	_ = v
 	switch b.Kind {
 	}
 	return false
diff --git a/src/cmd/compile/internal/ssa/rewritedec.go b/src/cmd/compile/internal/ssa/rewritedec.go
index fe13582..389e692 100644
--- a/src/cmd/compile/internal/ssa/rewritedec.go
+++ b/src/cmd/compile/internal/ssa/rewritedec.go
@@ -3,18 +3,8 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValuedec(v *Value) bool {
 	switch v.Op {
 	case OpComplexImag:
@@ -492,11 +482,6 @@
 	return false
 }
 func rewriteBlockdec(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
-	v := b.Control
-	_ = v
 	switch b.Kind {
 	}
 	return false
diff --git a/src/cmd/compile/internal/ssa/rewritedec64.go b/src/cmd/compile/internal/ssa/rewritedec64.go
index a67ae1e..3c15dde 100644
--- a/src/cmd/compile/internal/ssa/rewritedec64.go
+++ b/src/cmd/compile/internal/ssa/rewritedec64.go
@@ -3,18 +3,8 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValuedec64(v *Value) bool {
 	switch v.Op {
 	case OpAdd64:
@@ -2726,11 +2716,6 @@
 	}
 }
 func rewriteBlockdec64(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
-	v := b.Control
-	_ = v
 	switch b.Kind {
 	}
 	return false
diff --git a/src/cmd/compile/internal/ssa/rewritedecArgs.go b/src/cmd/compile/internal/ssa/rewritedecArgs.go
index 6b81129..0f6d01f 100644
--- a/src/cmd/compile/internal/ssa/rewritedecArgs.go
+++ b/src/cmd/compile/internal/ssa/rewritedecArgs.go
@@ -3,18 +3,6 @@
 
 package ssa
 
-import "fmt"
-import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
-import "cmd/compile/internal/types"
-
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValuedecArgs(v *Value) bool {
 	switch v.Op {
 	case OpArg:
@@ -270,11 +258,6 @@
 	return false
 }
 func rewriteBlockdecArgs(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
-	v := b.Control
-	_ = v
 	switch b.Kind {
 	}
 	return false
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 7117f77..db0b174 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -3,18 +3,9 @@
 
 package ssa
 
-import "fmt"
 import "math"
-import "cmd/internal/obj"
-import "cmd/internal/objabi"
 import "cmd/compile/internal/types"
 
-var _ = fmt.Println   // in case not otherwise used
-var _ = math.MinInt8  // in case not otherwise used
-var _ = obj.ANOP      // in case not otherwise used
-var _ = objabi.GOROOT // in case not otherwise used
-var _ = types.TypeMem // in case not otherwise used
-
 func rewriteValuegeneric(v *Value) bool {
 	switch v.Op {
 	case OpAdd16:
@@ -49166,11 +49157,7 @@
 	return false
 }
 func rewriteBlockgeneric(b *Block) bool {
-	config := b.Func.Config
-	typ := &config.Types
-	_ = typ
 	v := b.Control
-	_ = v
 	switch b.Kind {
 	case BlockIf:
 		// match: (If (Not cond) yes no)