func run(t *testing.T, dir, input string) bool { fmt.Printf("Input: %s\n", input) var inputs []string for _, i := range strings.Split(input, " ") { inputs = append(inputs, dir+i) } b := ssa.NewBuilder(&ssa.Context{ Mode: ssa.SanityCheckFunctions, Loader: ssa.MakeGoBuildLoader(nil), }) files, err := ssa.ParseFiles(b.Prog.Files, ".", inputs...) if err != nil { t.Errorf("ssa.ParseFiles(%s) failed: %s", inputs, err.Error()) return false } // Print a helpful hint if we don't make it to the end. var hint string defer func() { if hint != "" { fmt.Println("FAIL") fmt.Println(hint) } else { fmt.Println("PASS") } }() hint = fmt.Sprintf("To dump SSA representation, run:\n%% go run exp/ssa/ssadump.go -build=CFP %s\n", input) mainpkg, err := b.CreatePackage("main", files) if err != nil { t.Errorf("ssa.Builder.CreatePackage(%s) failed: %s", inputs, err.Error()) return false } b.BuildAllPackages() b = nil // discard Builder hint = fmt.Sprintf("To trace execution, run:\n%% go run exp/ssa/ssadump.go -build=C -run --interp=T %s\n", input) if exitCode := interp.Interpret(mainpkg, 0, inputs[0], []string{}); exitCode != 0 { t.Errorf("interp.Interpret(%s) exited with code %d, want zero", inputs, exitCode) return false } hint = "" // call off the hounds return true }
func main() { flag.Parse() args := flag.Args() var mode ssa.BuilderMode for _, c := range *buildFlag { switch c { case 'P': mode |= ssa.LogPackages | ssa.BuildSerially case 'F': mode |= ssa.LogFunctions | ssa.BuildSerially case 'S': mode |= ssa.LogSource | ssa.BuildSerially case 'C': mode |= ssa.SanityCheckFunctions case 'N': mode |= ssa.NaiveForm case 'G': mode |= ssa.UseGCImporter case 'L': mode |= ssa.BuildSerially default: log.Fatalf("Unknown -build option: '%c'.", c) } } var interpMode interp.Mode for _, c := range *interpFlag { switch c { case 'T': interpMode |= interp.EnableTracing case 'R': interpMode |= interp.DisableRecover default: log.Fatalf("Unknown -interp option: '%c'.", c) } } if len(args) == 0 { fmt.Fprint(os.Stderr, usage) os.Exit(1) } // Profiling support. if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } context := &ssa.Context{ Mode: mode, Loader: ssa.MakeGoBuildLoader(nil), } b := ssa.NewBuilder(context) mainpkg, args, err := ssa.CreatePackageFromArgs(b, args) if err != nil { log.Fatal(err.Error()) } b.BuildAllPackages() b = nil // discard Builder if *runFlag { interp.Interpret(mainpkg, interpMode, mainpkg.Name(), args) } }
// This program demonstrates how to run the SSA builder on a "Hello, // World!" program and shows the printed representation of packages, // functions and instructions. // // Within the function listing, the name of each BasicBlock such as // ".0.entry" is printed left-aligned, followed by the block's // Instructions. // // For each instruction that defines an SSA virtual register // (i.e. implements Value), the type of that value is shown in the // right column. // // Build and run the ssadump.go program in this package if you want a // standalone tool with similar functionality. // func Example() { const hello = ` package main import "fmt" const message = "Hello, World!" func main() { fmt.Println(message) } ` // Construct a builder. Imports will be loaded as if by 'go build'. builder := ssa.NewBuilder(&ssa.Context{Loader: ssa.MakeGoBuildLoader(nil)}) // Parse the input file. file, err := parser.ParseFile(builder.Prog.Files, "hello.go", hello, parser.DeclarationErrors) if err != nil { fmt.Printf(err.Error()) // parse error return } // Create a "main" package containing one file. mainPkg, err := builder.CreatePackage("main", []*ast.File{file}) if err != nil { fmt.Printf(err.Error()) // type error return } // Print out the package. mainPkg.DumpTo(os.Stdout) fmt.Println() // Build SSA code for bodies of functions in mainPkg. builder.BuildPackage(mainPkg) // Print out the package-level functions. mainPkg.Init.DumpTo(os.Stdout) for _, mem := range mainPkg.Members { if fn, ok := mem.(*ssa.Function); ok { fn.DumpTo(os.Stdout) } } // Output: // // Package main: // var init$guard *bool // func main func() // const message message = "Hello, World!":untyped string // // # Name: main.init // # Synthetic // func init(): // .0.entry: P:0 S:2 // t0 = *init$guard bool // if t0 goto 2.init.done else 1.init.start // .1.init.start: P:1 S:1 // *init$guard = true:bool // t1 = fmt.init() () // jump 2.init.done // .2.init.done: P:2 S:0 // ret // // # Name: main.main // # Declared at hello.go:8:6 // func main(): // .0.entry: P:0 S:0 // a0 = new [1]interface{} *[1]interface{} // t0 = &a0[0:untyped integer] *interface{} // t1 = make interface interface{} <- string ("Hello, World!":string) interface{} // *t0 = t1 // t2 = slice a0[:] []interface{} // t3 = fmt.Println(t2) (n int, err error) // ret }