]> Cypherpunks repositories - gostls13.git/commitdiff
exp/ssa: make Parameters values, not addresses.
authorAlan Donovan <adonovan@google.com>
Tue, 29 Jan 2013 15:49:16 +0000 (10:49 -0500)
committerAlan Donovan <adonovan@google.com>
Tue, 29 Jan 2013 15:49:16 +0000 (10:49 -0500)
We explicitly spill all parameters to the frame during initial
SSA construction.  (Later passes will remove spills.)
We now properly handle local Allocs escaping via Captures.

Also: allocate BasicBlock.Succs inline.

R=iant, iant
CC=golang-dev
https://golang.org/cl/7231050

src/pkg/exp/ssa/blockopt.go
src/pkg/exp/ssa/func.go
src/pkg/exp/ssa/ssa.go

index 77a98b3e011f50cd77a593a581f24950b6b469e2..a81be6aefe8476714bf88f83bdcbb756e6f26f62 100644 (file)
@@ -5,10 +5,6 @@ package ssa
 // TODO(adonovan): instead of creating several "unreachable" blocks
 // per function in the Builder, reuse a single one (e.g. at Blocks[1])
 // to reduce garbage.
-//
-// TODO(adonovan): in the absence of multiway branch instructions,
-// each BasicBlock has 0, 1, or 2 successors.  We should preallocate
-// the backing array for the Succs slice inline in BasicBlock.
 
 import (
        "fmt"
@@ -117,7 +113,7 @@ func fuseBlocks(f *Function, a *BasicBlock) bool {
        }
 
        // A inherits B's successors
-       a.Succs = b.Succs
+       a.Succs = append(a.succs2[:0], b.Succs...)
 
        // Fix up Preds links of all successors of B.
        for _, c := range b.Succs {
index 3751839b287a9cfaeecb56601f5249e1b7f8e1db..6af5e1efcd5495dc4e3640cd38664d1cdcfadf6f 100644 (file)
@@ -151,16 +151,27 @@ func (f *Function) labelledBlock(label *ast.Ident) *lblock {
 func (f *Function) addParam(name string, typ types.Type) *Parameter {
        v := &Parameter{
                Name_: name,
-               Type_: pointer(typ), // address of param
+               Type_: typ,
        }
        f.Params = append(f.Params, v)
        return v
 }
 
-func (f *Function) addObjParam(obj types.Object) *Parameter {
-       p := f.addParam(obj.GetName(), obj.GetType())
-       f.objects[obj] = p
-       return p
+// addSpilledParam declares a parameter that is pre-spilled to the
+// stack; the function body will load/store the spilled location.
+// Subsequent registerization will eliminate spills where possible.
+//
+func (f *Function) addSpilledParam(obj types.Object) {
+       name := obj.GetName()
+       param := f.addParam(name, obj.GetType())
+       spill := &Alloc{
+               Name_: name + "~", // "~" means "spilled"
+               Type_: pointer(obj.GetType()),
+       }
+       f.objects[obj] = spill
+       f.Locals = append(f.Locals, spill)
+       f.emit(spill)
+       f.emit(&Store{Addr: spill, Val: param})
 }
 
 // start initializes the function prior to generating SSA code for its body.
@@ -186,7 +197,7 @@ func (f *Function) start(mode BuilderMode, idents map[*ast.Ident]types.Object) {
        if f.syntax.recvField != nil {
                for _, field := range f.syntax.recvField.List {
                        for _, n := range field.Names {
-                               f.addObjParam(idents[n])
+                               f.addSpilledParam(idents[n])
                        }
                        if field.Names == nil {
                                f.addParam(f.Signature.Recv.Name, f.Signature.Recv.Type)
@@ -198,7 +209,7 @@ func (f *Function) start(mode BuilderMode, idents map[*ast.Ident]types.Object) {
        if f.syntax.paramFields != nil {
                for _, field := range f.syntax.paramFields.List {
                        for _, n := range field.Names {
-                               f.addObjParam(idents[n])
+                               f.addSpilledParam(idents[n])
                        }
                }
        }
@@ -300,18 +311,18 @@ func (f *Function) addLocal(typ types.Type) *Alloc {
 func (f *Function) lookup(obj types.Object, escaping bool) Value {
        if v, ok := f.objects[obj]; ok {
                if escaping {
-                       switch v := v.(type) {
-                       case *Capture:
-                               // TODO(adonovan): fix: we must support this case.
-                               // Requires copying to a 'new' Alloc.
-                               fmt.Fprintln(os.Stderr, "Error: escaping reference to Capture")
-                       case *Parameter:
-                               v.Heap = true
-                       case *Alloc:
-                               v.Heap = true
-                       default:
-                               panic(fmt.Sprintf("Unexpected Function.objects kind: %T", v))
+                       // Walk up the chain of Captures.
+                       x := v
+                       for {
+                               if c, ok := x.(*Capture); ok {
+                                       x = c.Outer
+                               } else {
+                                       break
+                               }
                        }
+                       // By construction, all captures are ultimately Allocs in the
+                       // naive SSA form.  Parameters are pre-spilled to the stack.
+                       x.(*Alloc).Heap = true
                }
                return v // function-local var (address)
        }
@@ -340,7 +351,7 @@ func (f *Function) emit(instr Instruction) Value {
 func (f *Function) DumpTo(w io.Writer) {
        fmt.Fprintf(w, "# Name: %s\n", f.FullName())
        fmt.Fprintf(w, "# Declared at %s\n", f.Prog.Files.Position(f.Pos))
-       fmt.Fprintf(w, "# Type: %s\n", f.Type())
+       fmt.Fprintf(w, "# Type: %s\n", f.Signature)
 
        if f.Enclosing != nil {
                fmt.Fprintf(w, "# Parent: %s\n", f.Enclosing.Name())
@@ -411,6 +422,7 @@ func (f *Function) newBasicBlock(name string) *BasicBlock {
                Name: fmt.Sprintf("%d.%s", len(f.Blocks), name),
                Func: f,
        }
+       b.Succs = b.succs2[:0]
        f.Blocks = append(f.Blocks, b)
        return b
 }
index 8e503dc35b8ea7782f1018e7e2fa8dea5b9aca4c..eb0f7fc0b07904dee3fa9a801cd8116f8f2291bd 100644 (file)
@@ -246,19 +246,20 @@ type Function struct {
 // instructions, respectively).
 //
 type BasicBlock struct {
-       Name         string        // label; no semantic significance
-       Func         *Function     // containing function
-       Instrs       []Instruction // instructions in order
-       Preds, Succs []*BasicBlock // predecessors and successors
+       Name         string         // label; no semantic significance
+       Func         *Function      // containing function
+       Instrs       []Instruction  // instructions in order
+       Preds, Succs []*BasicBlock  // predecessors and successors
+       succs2       [2]*BasicBlock // initial space for Succs.
 }
 
 // Pure values ----------------------------------------
 
 // A Capture is a pointer to a lexically enclosing local variable.
 //
-// The referent of a capture is a Parameter, Alloc or another Capture
-// and is always considered potentially escaping, so Captures are
-// always addresses in the heap, and have pointer types.
+// The referent of a capture is an Alloc or another Capture and is
+// always considered potentially escaping, so Captures are always
+// addresses in the heap, and have pointer types.
 //
 type Capture struct {
        Outer Value // the Value captured from the enclosing context.
@@ -266,22 +267,9 @@ type Capture struct {
 
 // A Parameter represents an input parameter of a function.
 //
-// Parameters are addresses and thus have pointer types.
-// TODO(adonovan): this will change.  We should just spill parameters
-// to ordinary Alloc-style locals if they are ever used in an
-// addressable context.  Then we can lose the Heap flag.
-//
-// In the common case where Heap=false, Parameters are pointers into
-// the function's stack frame.  If the case where Heap=true because a
-// parameter's address may escape from its function, Parameters are
-// pointers into a space in the heap implicitly allocated during the
-// function call.  (See also Alloc, which uses the Heap flag in a
-// similar manner.)
-//
 type Parameter struct {
        Name_ string
-       Type_ *types.Pointer
-       Heap  bool
+       Type_ types.Type
 }
 
 // A Literal represents a literal nil, boolean, string or numeric