go/ssa: standardize parsing of BuilderMode flags.

ssadump's -build=G option is now spelled -import; it was never related to ssa.

Change-Id: Ic21cd8b6990c0ffd25651c17a842a63bfa5019cf
Reviewed-on: https://go-review.googlesource.com/5172
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/cmd/ssadump/main.go b/cmd/ssadump/main.go
index 1901b30..8ca6aa4 100644
--- a/cmd/ssadump/main.go
+++ b/cmd/ssadump/main.go
@@ -19,28 +19,23 @@
 	"golang.org/x/tools/go/types"
 )
 
-var buildFlag = flag.String("build", "", `Options controlling the SSA builder.
-The value is a sequence of zero or more of these letters:
-C	perform sanity [C]hecking of the SSA form.
-D	include [D]ebug info for every function.
-P	print [P]ackage inventory.
-F	print [F]unction SSA code.
-S	log [S]ource locations as SSA builder progresses.
-G	use binary object files from gc to provide imports (no code).
-L	build distinct packages seria[L]ly instead of in parallel.
-N	build [N]aive SSA form: don't replace local loads/stores with registers.
-I	build bare [I]nit functions: no init guards or calls to dependent inits.
-`)
+var (
+	importbinFlag = flag.Bool("importbin", false,
+		"Import binary export data from gc's object files, not source. "+
+			"Imported functions will have no bodies.")
 
-var testFlag = flag.Bool("test", false, "Loads test code (*_test.go) for imported packages.")
+	modeFlag = ssa.BuilderModeFlag(flag.CommandLine, "build", 0)
 
-var runFlag = flag.Bool("run", false, "Invokes the SSA interpreter on the program.")
+	testFlag = flag.Bool("test", false, "Loads test code (*_test.go) for imported packages.")
 
-var interpFlag = flag.String("interp", "", `Options controlling the SSA test interpreter.
+	runFlag = flag.Bool("run", false, "Invokes the SSA interpreter on the program.")
+
+	interpFlag = flag.String("interp", "", `Options controlling the SSA test interpreter.
 The value is a sequence of zero or more more of these letters:
 R	disable [R]ecover() from panic; show interpreter crash instead.
 T	[T]race execution of the program.  Best for single-threaded programs!
 `)
+)
 
 const usage = `SSA builder and interpreter.
 Usage: ssadump [<flag> ...] <args> ...
@@ -85,7 +80,7 @@
 
 	conf := loader.Config{
 		Build:         &build.Default,
-		SourceImports: true,
+		SourceImports: !*importbinFlag,
 	}
 	// TODO(adonovan): make go/types choose its default Sizes from
 	// build.Default or a specified *build.Context.
@@ -99,32 +94,6 @@
 		WordSize: wordSize,
 	}
 
-	var mode ssa.BuilderMode
-	for _, c := range *buildFlag {
-		switch c {
-		case 'D':
-			mode |= ssa.GlobalDebug
-		case 'P':
-			mode |= ssa.PrintPackages
-		case 'F':
-			mode |= ssa.PrintFunctions
-		case 'S':
-			mode |= ssa.LogSource | ssa.BuildSerially
-		case 'C':
-			mode |= ssa.SanityCheckFunctions
-		case 'N':
-			mode |= ssa.NaiveForm
-		case 'G':
-			conf.SourceImports = false
-		case 'L':
-			mode |= ssa.BuildSerially
-		case 'I':
-			mode |= ssa.BareInits
-		default:
-			return fmt.Errorf("unknown -build option: '%c'", c)
-		}
-	}
-
 	var interpMode interp.Mode
 	for _, c := range *interpFlag {
 		switch c {
@@ -171,7 +140,7 @@
 	}
 
 	// Create and build SSA-form program representation.
-	prog := ssa.Create(iprog, mode)
+	prog := ssa.Create(iprog, *modeFlag)
 	prog.BuildAll()
 
 	// Run the interpreter.
diff --git a/go/ssa/create.go b/go/ssa/create.go
index 9b3a91b..c2985eb 100644
--- a/go/ssa/create.go
+++ b/go/ssa/create.go
@@ -18,20 +18,6 @@
 	"golang.org/x/tools/go/types/typeutil"
 )
 
-// BuilderMode is a bitmask of options for diagnostics and checking.
-type BuilderMode uint
-
-const (
-	PrintPackages        BuilderMode = 1 << iota // Print package inventory to stdout
-	PrintFunctions                               // Print function SSA code to stdout
-	LogSource                                    // Log source locations as SSA builder progresses
-	SanityCheckFunctions                         // Perform sanity checking of function bodies
-	NaiveForm                                    // Build naïve SSA form: don't replace local loads/stores with registers
-	BuildSerially                                // Build packages serially, not in parallel.
-	GlobalDebug                                  // Enable debug info for all packages
-	BareInits                                    // Build init functions without guards or calls to dependent inits
-)
-
 // Create returns a new SSA Program.  An SSA Package is created for
 // each transitively error-free package of iprog.
 //
@@ -257,7 +243,7 @@
 	return p
 }
 
-// printMu serializes printing of Packages/Functions to stdout
+// printMu serializes printing of Packages/Functions to stdout.
 var printMu sync.Mutex
 
 // AllPackages returns a new slice containing all packages in the
diff --git a/go/ssa/mode.go b/go/ssa/mode.go
new file mode 100644
index 0000000..bbd613a
--- /dev/null
+++ b/go/ssa/mode.go
@@ -0,0 +1,107 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// This file defines the BuilderMode type and its command-line flag.
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+)
+
+// BuilderMode is a bitmask of options for diagnostics and checking.
+type BuilderMode uint
+
+const (
+	PrintPackages        BuilderMode = 1 << iota // Print package inventory to stdout
+	PrintFunctions                               // Print function SSA code to stdout
+	LogSource                                    // Log source locations as SSA builder progresses
+	SanityCheckFunctions                         // Perform sanity checking of function bodies
+	NaiveForm                                    // Build naïve SSA form: don't replace local loads/stores with registers
+	BuildSerially                                // Build packages serially, not in parallel.
+	GlobalDebug                                  // Enable debug info for all packages
+	BareInits                                    // Build init functions without guards or calls to dependent inits
+)
+
+const modeFlagUsage = `Options controlling the SSA builder.
+The value is a sequence of zero or more of these letters:
+C	perform sanity [C]hecking of the SSA form.
+D	include [D]ebug info for every function.
+P	print [P]ackage inventory.
+F	print [F]unction SSA code.
+S	log [S]ource locations as SSA builder progresses.
+L	build distinct packages seria[L]ly instead of in parallel.
+N	build [N]aive SSA form: don't replace local loads/stores with registers.
+I	build bare [I]nit functions: no init guards or calls to dependent inits.
+`
+
+// BuilderModeFlag creates a new command line flag of type BuilderMode,
+// adds it to the specified flag set, and returns it.
+//
+// Example:
+// 	var ssabuild = BuilderModeFlag(flag.CommandLine, "ssabuild", 0)
+//
+func BuilderModeFlag(set *flag.FlagSet, name string, value BuilderMode) *BuilderMode {
+	set.Var((*builderModeValue)(&value), name, modeFlagUsage)
+	return &value
+}
+
+type builderModeValue BuilderMode // satisfies flag.Value and flag.Getter.
+
+func (v *builderModeValue) Set(s string) error {
+	var mode BuilderMode
+	for _, c := range s {
+		switch c {
+		case 'D':
+			mode |= GlobalDebug
+		case 'P':
+			mode |= PrintPackages
+		case 'F':
+			mode |= PrintFunctions
+		case 'S':
+			mode |= LogSource | BuildSerially
+		case 'C':
+			mode |= SanityCheckFunctions
+		case 'N':
+			mode |= NaiveForm
+		case 'L':
+			mode |= BuildSerially
+		default:
+			return fmt.Errorf("unknown BuilderMode option: %q", c)
+		}
+	}
+	*v = builderModeValue(mode)
+	return nil
+}
+
+func (v *builderModeValue) Get() interface{} { return BuilderMode(*v) }
+
+func (v *builderModeValue) String() string {
+	mode := BuilderMode(*v)
+	var buf bytes.Buffer
+	if mode&GlobalDebug != 0 {
+		buf.WriteByte('D')
+	}
+	if mode&PrintPackages != 0 {
+		buf.WriteByte('P')
+	}
+	if mode&PrintFunctions != 0 {
+		buf.WriteByte('F')
+	}
+	if mode&LogSource != 0 {
+		buf.WriteByte('S')
+	}
+	if mode&SanityCheckFunctions != 0 {
+		buf.WriteByte('C')
+	}
+	if mode&NaiveForm != 0 {
+		buf.WriteByte('N')
+	}
+	if mode&BuildSerially != 0 {
+		buf.WriteByte('L')
+	}
+	return buf.String()
+}