code.google.com/p/go.tools/ssa: include ssa.Package and init() function in example output.

Also:
- remove redundant text in doc.go.
- fix (yet more) cases of missing parens in Printf, fallout from
  go/types accessors refactoring.
- don't mix spaces and tabs within lines printed by ssa.Function.DumpTo:
  it makes it too hard to constructed expected outputs for tests.
  (Tabs may appear at line start though.)

Sadly godoc -play won't run this program; it complains it
can't import "code.google.com/p/go.exp/ssa".  Any idea why?

R=gri
CC=golang-dev
https://golang.org/cl/9481044
This commit is contained in:
Alan Donovan 2013-05-17 17:33:09 -04:00
parent 87334f402b
commit 113d6d30b1
4 changed files with 55 additions and 60 deletions

View File

@ -107,56 +107,6 @@
// either accurate or unambiguous. The public API exposes a number of
// name-based maps for client convenience.
//
// Given a Go source package such as this:
//
// package main
//
// import "fmt"
//
// const message = "Hello, World!"
//
// func main() {
// fmt.Println(message)
// }
//
// The SSA Builder creates a *Program containing a main *Package such
// as this:
//
// Package (Name: "main")
// Members:
// "message": *Constant (Type: untyped string, Value: "Hello, World!")
// "init·guard": *Global (Type: *bool)
// "main": *Function (Type: func())
// Init: *Function (Type: func())
//
// The printed representation of the function main.main is shown
// below. 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.
//
// # Name: main.main
// # Declared at hello.go:7:6
// func main():
// .0.entry:
// t0 = new [1]interface{} *[1]interface{}
// t1 = &t0[0:untyped integer] *interface{}
// t2 = make interface interface{} <- string ("Hello, World!":string) interface{}
// *t1 = t2
// t3 = slice t0[:] []interface{}
// t4 = fmt.Println(t3) (n int, err error)
// ret
//
//
// The ssadump utility is an example of an application that loads and
// dumps the SSA form of a Go program, whether a single package or a
// whole program.
//
// TODO(adonovan): demonstrate more features in the example:
// parameters and control flow at the least.
//
// TODO(adonovan): Consider the exceptional control-flow implications
// of defer and recover().
//
@ -174,4 +124,5 @@
// flexibility. For example, analysis tools may wish to construct a
// fake ssa.Function for the root of the callgraph, a fake "reflect"
// package, etc.
//
package ssa

View File

@ -8,15 +8,31 @@ import (
"os"
)
// This example demonstrates the SSA builder.
// 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("Hello, World!")
fmt.Println(message)
}
`
@ -26,21 +42,26 @@ func main() {
// Parse the input file.
file, err := parser.ParseFile(builder.Prog.Files, "hello.go", hello, parser.DeclarationErrors)
if err != nil {
fmt.Printf("Parsing failed: %s\n", err.Error())
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("Type-checking failed: %s\n", err.Error())
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)
@ -48,10 +69,29 @@ func main() {
}
// Output:
//
// Package main:
// var init·guard *bool
// func main func()
// const message message = "Hello, World!":untyped string
//
// # Name: main.init
// # Declared at -
// 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:6:6
// # Declared at hello.go:8:6
// func main():
// .0.entry: P:0 S:0
// .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{}

View File

@ -554,13 +554,17 @@ func (f *Function) DumpTo(w io.Writer) {
io.WriteString(w, "\t(external)\n")
}
// NB. column calculations are confused by non-ASCII characters.
const punchcard = 80 // for old time's sake.
for _, b := range f.Blocks {
if b == nil {
// Corrupt CFG.
fmt.Fprintf(w, ".nil:\n")
continue
}
fmt.Fprintf(w, ".%s:\t\t\t\t\t\t\t P:%d S:%d\n", b, len(b.Preds), len(b.Succs))
n, _ := fmt.Fprintf(w, ".%s:", b)
fmt.Fprintf(w, "%*sP:%d S:%d\n", punchcard-1-n-len("P:n S:n"), "", len(b.Preds), len(b.Succs))
if false { // CFG debugging
fmt.Fprintf(w, "\t# CFG: %s --> %s --> %s\n", b.Preds, b, b.Succs)
}
@ -568,7 +572,7 @@ func (f *Function) DumpTo(w io.Writer) {
io.WriteString(w, "\t")
switch v := instr.(type) {
case Value:
l := 80 // for old time's sake.
l := punchcard
// Left-align the instruction.
if name := v.Name(); name != "" {
n, _ := fmt.Fprintf(w, "%s = ", name)

View File

@ -17,7 +17,7 @@ func (id Id) String() string {
if id.Pkg == nil {
return id.Name
}
return fmt.Sprintf("%s/%s", id.Pkg.Path, id.Name)
return fmt.Sprintf("%s/%s", id.Pkg.Path(), id.Name)
}
// relName returns the name of v relative to i.
@ -360,7 +360,7 @@ func (p *Package) String() string {
}
func (p *Package) DumpTo(w io.Writer) {
fmt.Fprintf(w, "Package %s:\n", p.Types.Path)
fmt.Fprintf(w, "Package %s:\n", p.Types.Path())
var names []string
maxname := 0