1
0
mirror of https://github.com/golang/go synced 2024-11-18 20:14:43 -07:00

go.tools/ssa: populate Function.Referrers(), for anon functions.

Added sanity check to ensure Operands/Referrers are complete and dual.

Also: unexport Instruction.setBlock (=> no longer user-implementable).

R=gri
CC=golang-dev
https://golang.org/cl/22150043
This commit is contained in:
Alan Donovan 2013-11-07 10:08:51 -05:00
parent 7123ca00a8
commit f1e5b03c6e
5 changed files with 65 additions and 23 deletions

View File

@ -85,7 +85,7 @@ func jumpThreading(f *Function, b *BasicBlock) bool {
// If a now has two edges to c, replace its degenerate If by Jump.
if len(a.Succs) == 2 && a.Succs[0] == c && a.Succs[1] == c {
jump := new(Jump)
jump.SetBlock(a)
jump.setBlock(a)
a.Instrs[len(a.Instrs)-1] = jump
a.Succs = a.Succs[:1]
c.removePred(b)
@ -120,7 +120,7 @@ func fuseBlocks(f *Function, a *BasicBlock) bool {
// Eliminate jump at end of A, then copy all of B across.
a.Instrs = append(a.Instrs[:len(a.Instrs)-1], b.Instrs...)
for _, instr := range b.Instrs {
instr.SetBlock(a)
instr.setBlock(a)
}
// A inherits B's successors

View File

@ -2040,8 +2040,6 @@ start:
fn.currentBlock = done
// TODO statement debug info.
case *ast.SwitchStmt:
b.switchStmt(fn, s, label)

View File

@ -37,7 +37,7 @@ func (b *BasicBlock) String() string {
// If the instruction defines a Value, it is returned.
//
func (b *BasicBlock) emit(i Instruction) Value {
i.SetBlock(b)
i.setBlock(b)
b.Instrs = append(b.Instrs, i)
v, _ := i.(Value)
return v

View File

@ -291,14 +291,11 @@ func (s *sanity) checkBlock(b *BasicBlock, index int) {
}
// Check each instruction is sane.
// TODO(adonovan): check Instruction invariants:
// - check Operands is dual to Value.Referrers.
// - check all Operands that are also Instructions belong to s.fn too
// (and for bonus marks, that their block dominates block b).
n := len(b.Instrs)
if n == 0 {
s.errorf("basic block contains no instructions")
}
var rands [10]*Value // reuse storage
for j, instr := range b.Instrs {
if instr == nil {
s.errorf("nil instruction at index %d", j)
@ -316,6 +313,48 @@ func (s *sanity) checkBlock(b *BasicBlock, index int) {
} else {
s.checkFinalInstr(j, instr)
}
// Check Instruction.Operands.
operands:
for i, op := range instr.Operands(rands[:0]) {
if op == nil {
s.errorf("nil operand pointer %d of %s", i, instr)
continue
}
val := *op
if val == nil {
continue // a nil operand is ok
}
// Check that Operands that are also Instructions belong to same function.
// TODO(adonovan): also check their block dominates block b.
if val, ok := val.(Instruction); ok {
if val.Parent() != s.fn {
s.errorf("operand %d of %s is an instruction (%s) from function %s", i, instr, val, val.Parent())
}
}
// Check that each function-local operand of
// instr refers back to instr. (NB: quadratic)
switch val := val.(type) {
case *Const, *Global, *Builtin:
continue // not local
case *Function:
if val.Enclosing == nil {
continue // only anon functions are local
}
}
if refs := val.Referrers(); refs != nil {
for _, ref := range *refs {
if ref == instr {
continue operands
}
}
s.errorf("operand %d of %s (%s) does not refer to us", i, instr, val)
} else {
s.errorf("operand %d of %s (%s) has no referrers", i, instr, val)
}
}
}
}

View File

@ -127,8 +127,9 @@ type Value interface {
// 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, Const and Global.
// values Capture, Parameter, Functions (iff anonymous) and
// all value-defining instructions.
// It returns nil for named Functions, Builtin, Const and Global.
//
// Instruction.Operands contains the inverse of this relation.
Referrers() *[]Instruction
@ -184,10 +185,8 @@ type Instruction interface {
// belongs.
Block() *BasicBlock
// SetBlock sets the basic block to which this instruction
// belongs.
// TODO(adonovan): unexport this.
SetBlock(*BasicBlock)
// setBlock sets the basic block to which this instruction belongs.
setBlock(*BasicBlock)
// Operands returns the operands of this instruction: the
// set of Values it references.
@ -279,6 +278,7 @@ type Function struct {
Blocks []*BasicBlock // basic blocks of the function; nil => external
Recover *BasicBlock // optional; control transfers here after recovered panic
AnonFuncs []*Function // anonymous functions directly beneath this one
referrers []Instruction // referring instructions (iff Enclosing != nil)
// The following fields are set transiently during building,
// then cleared.
@ -1212,7 +1212,7 @@ type register struct {
}
// anInstruction is a mix-in embedded by all Instructions.
// It provides the implementations of the Block and SetBlock methods.
// It provides the implementations of the Block and setBlock methods.
type anInstruction struct {
block *BasicBlock // the basic block of this instruction
}
@ -1371,9 +1371,14 @@ func (v *Global) Object() types.Object { return v.object }
func (v *Function) Name() string { return v.name }
func (v *Function) Type() types.Type { return v.Signature }
func (v *Function) Pos() token.Pos { return v.pos }
func (*Function) Referrers() *[]Instruction { return nil }
func (v *Function) Token() token.Token { return token.FUNC }
func (v *Function) Object() types.Object { return v.object }
func (v *Function) Referrers() *[]Instruction {
if v.Enclosing != nil {
return &v.referrers
}
return nil
}
func (v *Parameter) Type() types.Type { return v.typ }
func (v *Parameter) Name() string { return v.name }
@ -1396,7 +1401,7 @@ func (v *register) setPos(pos token.Pos) { v.pos = pos }
func (v *anInstruction) Parent() *Function { return v.block.parent }
func (v *anInstruction) Block() *BasicBlock { return v.block }
func (v *anInstruction) SetBlock(block *BasicBlock) { v.block = block }
func (v *anInstruction) setBlock(block *BasicBlock) { v.block = block }
func (t *Type) Name() string { return t.object.Name() }
func (t *Type) Pos() token.Pos { return t.object.Pos() }