]> Cypherpunks repositories - gostls13.git/commitdiff
exp/ssa: add Instruction.Operands and Value.Referrers methods.
authorAlan Donovan <adonovan@google.com>
Wed, 13 Feb 2013 05:15:07 +0000 (00:15 -0500)
committerAlan Donovan <adonovan@google.com>
Wed, 13 Feb 2013 05:15:07 +0000 (00:15 -0500)
Operands returns the SSA values used by an instruction.
Referrers returns the SSA instructions that use a value, for
some values.  These will be used for SSA renaming, to follow.

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

src/pkg/exp/ssa/func.go
src/pkg/exp/ssa/interp/interp.go
src/pkg/exp/ssa/literal.go
src/pkg/exp/ssa/ssa.go

index d8f11d9c578f23b550d9f4275daf8daa8c0dc7fd..dca3ca75104df0177de4a031ff9f21be0cef3ddc 100644 (file)
@@ -257,6 +257,21 @@ func (f *Function) finish() {
        }
        optimizeBlocks(f)
 
+       // Build immediate-use (referrers) graph.
+       var rands []*Value
+       for _, b := range f.Blocks {
+               for _, instr := range b.Instrs {
+                       rands = instr.Operands(rands[:0]) // recycle storage
+                       for _, rand := range rands {
+                               if r := *rand; r != nil {
+                                       if ref := r.Referrers(); ref != nil {
+                                               *ref = append(*ref, instr)
+                                       }
+                               }
+                       }
+               }
+       }
+
        if f.Prog.mode&LogFunctions != 0 {
                f.DumpTo(os.Stderr)
        }
@@ -320,7 +335,7 @@ func (f *Function) lookup(obj types.Object, escaping bool) Value {
        if f.Enclosing == nil {
                panic("no Value for type.Object " + obj.GetName())
        }
-       v := &Capture{f.Enclosing.lookup(obj, true)} // escaping
+       v := &Capture{Outer: f.Enclosing.lookup(obj, true)} // escaping
        f.objects[obj] = v
        f.FreeVars = append(f.FreeVars, v)
        return v
index c4ea75c94d30e443c1b49f067af6fa634bae6aa5..d2c54d91d67a86f06c1b1474db018aebcbd18393 100644 (file)
@@ -279,7 +279,7 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation {
                for _, binding := range instr.Bindings {
                        bindings = append(bindings, fr.get(binding))
                }
-               fr.env[instr] = &closure{instr.Fn, bindings}
+               fr.env[instr] = &closure{instr.Fn.(*ssa.Function), bindings}
 
        case *ssa.Phi:
                for i, pred := range instr.Block_.Preds {
index fa26c47e927197efab8f9305e6a46336da542c0e..168178882dc634e700f7f62b4bbe1554a1dc7b8f 100644 (file)
@@ -60,6 +60,10 @@ func (l *Literal) Type() types.Type {
        return l.Type_
 }
 
+func (l *Literal) Referrers() *[]Instruction {
+       return nil
+}
+
 // IsNil returns true if this literal represents a typed or untyped nil value.
 func (l *Literal) IsNil() bool {
        _, ok := l.Value.(types.NilType)
index acc84c6130f22047b5ac977094b8f3ec6447a362..110ddd7b19ef6937e5a00094fad252c760e66168 100644 (file)
@@ -95,10 +95,6 @@ type Type struct {
 }
 
 // An SSA value that can be referenced by an instruction.
-//
-// TODO(adonovan): add methods:
-// - Referrers() []*Instruction // all instructions that refer to this value.
-//
 type Value interface {
        // Name returns the name of this value, and determines how
        // this Value appears when used as an operand of an
@@ -129,6 +125,20 @@ type Value interface {
        // the case of NamedTypes.
        Type() types.Type
 
+       // Referrers returns the list of instructions that have this
+       // value as one of their operands; it may contain duplicates
+       // if an instruction has a repeated operand.
+       //
+       // Referrers actually returns a pointer through which the
+       // caller may perform mutations to the object's state.
+       //
+       // Referrers is currently only defined for the function-local
+       // values Capture, Parameter and all value-defining instructions.
+       // It returns nil for Function, Builtin, Literal and Global.
+       //
+       // Instruction.Operands contains the inverse of this relation.
+       Referrers() *[]Instruction
+
        // Dummy method to indicate the "implements" relation.
        ImplementsValue()
 }
@@ -140,9 +150,6 @@ type Value interface {
 // the Value interface; an Instruction that only has an effect (e.g. Store)
 // does not.
 //
-// TODO(adonovan): add method:
-// - Operands() []Value  // all Values referenced by this instruction.
-//
 type Instruction interface {
        // String returns the disassembled form of this value.  e.g.
        //
@@ -169,6 +176,23 @@ type Instruction interface {
        // belongs.
        SetBlock(*BasicBlock)
 
+       // Operands returns the operands of this instruction: the
+       // set of Values it references.
+       //
+       // Specifically, it appends their addresses to rands, a
+       // user-provided slice, and returns the resulting slice,
+       // permitting avoidance of memory allocation.
+       //
+       // The operands are appended in undefined order; the addresses
+       // are always non-nil but may point to a nil Value.  Clients
+       // may store through the pointers, e.g. to effect a value
+       // renaming.
+       //
+       // Value.Referrers is a subset of the inverse of this
+       // relation.  (Referrers are not tracked for all types of
+       // Values.)
+       Operands(rands []*Value) []*Value
+
        // Dummy method to indicate the "implements" relation.
        ImplementsInstruction()
 }
@@ -253,14 +277,16 @@ type BasicBlock struct {
 // addresses in the heap, and have pointer types.
 //
 type Capture struct {
-       Outer Value // the Value captured from the enclosing context.
+       Outer     Value // the Value captured from the enclosing context.
+       referrers []Instruction
 }
 
 // A Parameter represents an input parameter of a function.
 //
 type Parameter struct {
-       Name_ string
-       Type_ types.Type
+       Name_     string
+       Type_     types.Type
+       referrers []Instruction
 }
 
 // A Literal represents a literal nil, boolean, string or numeric
@@ -342,9 +368,10 @@ type Builtin struct {
 //
 type Alloc struct {
        anInstruction
-       Name_ string
-       Type_ types.Type
-       Heap  bool
+       Name_     string
+       Type_     types.Type
+       Heap      bool
+       referrers []Instruction
 }
 
 // Phi represents an SSA φ-node, which combines values that differ
@@ -486,7 +513,7 @@ type MakeInterface struct {
 //
 type MakeClosure struct {
        Register
-       Fn       *Function
+       Fn       Value   // always a *Function
        Bindings []Value // values for each free variable in Fn.FreeVars
 }
 
@@ -891,8 +918,9 @@ type MapUpdate struct {
 //
 type Register struct {
        anInstruction
-       num   int        // "name" of virtual register, e.g. "t0".  Not guaranteed unique.
-       Type_ types.Type // type of virtual register
+       num       int        // "name" of virtual register, e.g. "t0".  Not guaranteed unique.
+       Type_     types.Type // type of virtual register
+       referrers []Instruction
 }
 
 // AnInstruction is a mix-in embedded by all Instructions.
@@ -957,28 +985,36 @@ type CallCommon struct {
        Pos         token.Pos // position of call expression
 }
 
-func (v *Builtin) Type() types.Type { return v.Object.GetType() }
-func (v *Builtin) Name() string     { return v.Object.GetName() }
+func (v *Builtin) Type() types.Type        { return v.Object.GetType() }
+func (v *Builtin) Name() string            { return v.Object.GetName() }
+func (*Builtin) Referrers() *[]Instruction { return nil }
 
-func (v *Capture) Type() types.Type { return v.Outer.Type() }
-func (v *Capture) Name() string     { return v.Outer.Name() }
+func (v *Capture) Type() types.Type          { return v.Outer.Type() }
+func (v *Capture) Name() string              { return v.Outer.Name() }
+func (v *Capture) Referrers() *[]Instruction { return &v.referrers }
 
-func (v *Global) Type() types.Type { return v.Type_ }
-func (v *Global) Name() string     { return v.Name_ }
+func (v *Global) Type() types.Type        { return v.Type_ }
+func (v *Global) Name() string            { return v.Name_ }
+func (*Global) Referrers() *[]Instruction { return nil }
 
-func (v *Function) Name() string     { return v.Name_ }
-func (v *Function) Type() types.Type { return v.Signature }
+func (v *Function) Name() string            { return v.Name_ }
+func (v *Function) Type() types.Type        { return v.Signature }
+func (*Function) Referrers() *[]Instruction { return nil }
 
-func (v *Parameter) Type() types.Type { return v.Type_ }
-func (v *Parameter) Name() string     { return v.Name_ }
+func (v *Parameter) Type() types.Type          { return v.Type_ }
+func (v *Parameter) Name() string              { return v.Name_ }
+func (v *Parameter) Referrers() *[]Instruction { return &v.referrers }
 
-func (v *Alloc) Type() types.Type { return v.Type_ }
-func (v *Alloc) Name() string     { return v.Name_ }
+func (v *Alloc) Type() types.Type          { return v.Type_ }
+func (v *Alloc) Name() string              { return v.Name_ }
+func (v *Alloc) Referrers() *[]Instruction { return &v.referrers }
 
-func (v *Register) Type() types.Type       { return v.Type_ }
-func (v *Register) setType(typ types.Type) { v.Type_ = typ }
-func (v *Register) Name() string           { return fmt.Sprintf("t%d", v.num) }
-func (v *Register) setNum(num int)         { v.num = num }
+func (v *Register) Type() types.Type          { return v.Type_ }
+func (v *Register) setType(typ types.Type)    { v.Type_ = typ }
+func (v *Register) Name() string              { return fmt.Sprintf("t%d", v.num) }
+func (v *Register) setNum(num int)            { v.num = num }
+func (v *Register) Referrers() *[]Instruction { return &v.referrers }
+func (v *Register) asRegister() *Register     { return v }
 
 func (v *anInstruction) Block() *BasicBlock         { return v.Block_ }
 func (v *anInstruction) SetBlock(block *BasicBlock) { v.Block_ = block }
@@ -1091,3 +1127,140 @@ func (*Slice) ImplementsInstruction()           {}
 func (*Store) ImplementsInstruction()           {}
 func (*TypeAssert) ImplementsInstruction()      {}
 func (*UnOp) ImplementsInstruction()            {}
+
+// Operands.
+
+// REVIEWERS: Should this method be defined nearer each type to avoid skew?
+
+func (v *Alloc) Operands(rands []*Value) []*Value {
+       return rands
+}
+
+func (v *BinOp) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X, &v.Y)
+}
+
+func (c *CallCommon) Operands(rands []*Value) []*Value {
+       rands = append(rands, &c.Recv, &c.Func)
+       for i := range c.Args {
+               rands = append(rands, &c.Args[i])
+       }
+       return rands
+}
+
+func (v *ChangeInterface) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X)
+}
+
+func (v *Conv) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X)
+}
+
+func (v *Extract) Operands(rands []*Value) []*Value {
+       return append(rands, &v.Tuple)
+}
+
+func (v *Field) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X)
+}
+
+func (v *FieldAddr) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X)
+}
+
+func (s *If) Operands(rands []*Value) []*Value {
+       return append(rands, &s.Cond)
+}
+
+func (v *Index) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X, &v.Index)
+}
+
+func (v *IndexAddr) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X, &v.Index)
+}
+
+func (*Jump) Operands(rands []*Value) []*Value {
+       return rands
+}
+
+func (v *Lookup) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X, &v.Index)
+}
+
+func (v *MakeChan) Operands(rands []*Value) []*Value {
+       return append(rands, &v.Size)
+}
+
+func (v *MakeClosure) Operands(rands []*Value) []*Value {
+       rands = append(rands, &v.Fn)
+       for i := range v.Bindings {
+               rands = append(rands, &v.Bindings[i])
+       }
+       return rands
+}
+
+func (v *MakeInterface) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X)
+}
+
+func (v *MakeMap) Operands(rands []*Value) []*Value {
+       return append(rands, &v.Reserve)
+}
+
+func (v *MakeSlice) Operands(rands []*Value) []*Value {
+       return append(rands, &v.Len, &v.Cap)
+}
+
+func (v *MapUpdate) Operands(rands []*Value) []*Value {
+       return append(rands, &v.Map, &v.Key, &v.Value)
+}
+
+func (v *Next) Operands(rands []*Value) []*Value {
+       return append(rands, &v.Iter)
+}
+
+func (v *Phi) Operands(rands []*Value) []*Value {
+       for i := range v.Edges {
+               rands = append(rands, &v.Edges[i])
+       }
+       return rands
+}
+
+func (v *Range) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X)
+}
+
+func (s *Ret) Operands(rands []*Value) []*Value {
+       for i := range s.Results {
+               rands = append(rands, &s.Results[i])
+       }
+       return rands
+}
+
+func (v *Select) Operands(rands []*Value) []*Value {
+       for _, st := range v.States {
+               rands = append(rands, &st.Chan, &st.Send)
+       }
+       return rands
+}
+
+func (s *Send) Operands(rands []*Value) []*Value {
+       return append(rands, &s.Chan, &s.X)
+}
+
+func (v *Slice) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X, &v.Low, &v.High)
+}
+
+func (s *Store) Operands(rands []*Value) []*Value {
+       return append(rands, &s.Addr, &s.Val)
+}
+
+func (v *TypeAssert) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X)
+}
+
+func (v *UnOp) Operands(rands []*Value) []*Value {
+       return append(rands, &v.X)
+}