Commit 928fe516 authored by Alan Donovan's avatar Alan Donovan

exp/ssa: add Instruction.Operands and Value.Referrers methods.

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
parent 27970af5
......@@ -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
......
......@@ -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 {
......
......@@ -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)
......
......@@ -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)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment