// NewBlock creates a new block enclosed by the given function. func NewBlock(parent *Function, block *ssa.BasicBlock, curr int) *Block { blockFn := fmt.Sprintf("%s#%d", parent.Fn.String(), block.Index) parent.ChildBlocks[block.Index] = &Block{ Function: parent, MigoDef: migo.NewFunction(blockFn), Pred: curr, Index: block.Index, } return parent.ChildBlocks[block.Index] }
// NewMainFunction returns a new main() call context. func NewMainFunction(prog *Program, mainFn *ssa.Function) *Function { return &Function{ Fn: mainFn, Prog: prog, Visited: make(map[*ssa.BasicBlock]int), FuncDef: migo.NewFunction("main.main"), ChildBlocks: make(map[int]*Block), commaok: make(map[Instance]*CommaOk), defers: []*ssa.Defer{}, locals: make(map[ssa.Value]Instance), retvals: []Instance{}, extraargs: []ssa.Value{}, revlookup: make(map[string]string), selects: make(map[Instance]*Select), tuples: make(map[Instance]Tuples), loopstack: NewLoopStack(), Storage: NewStorage(), } }
// NewFunction returns a new function call context, and takes the caller's // context as parameter. func NewFunction(caller *Function) *Function { return &Function{ Caller: caller, Prog: caller.Prog, Visited: make(map[*ssa.BasicBlock]int), FuncDef: migo.NewFunction("__uninitialised__"), Level: caller.Level + 1, ChildBlocks: make(map[int]*Block), commaok: make(map[Instance]*CommaOk), defers: []*ssa.Defer{}, locals: make(map[ssa.Value]Instance), revlookup: make(map[string]string), extraargs: []ssa.Value{}, retvals: []Instance{}, selects: make(map[Instance]*Select), tuples: make(map[Instance]Tuples), loopstack: NewLoopStack(), Storage: NewStorage(), } }
func visitJump(jump *ssa.Jump, infer *TypeInfer, ctx *Context) { if len(jump.Block().Succs) != 1 { infer.Logger.Fatal(ErrInvalidJumpSucc) } curr, next := jump.Block(), jump.Block().Succs[0] infer.Logger.Printf(ctx.F.Sprintf(SkipSymbol+"block %d%s%d", curr.Index, fmtLoopHL(JumpSymbol), next.Index)) switch ctx.L.State { case Exit: ctx.L.State = NonLoop } if len(next.Preds) > 1 { infer.Logger.Printf(ctx.F.Sprintf(SplitSymbol+"Jump (%d ⇾ %d) %s", curr.Index, next.Index, ctx.L.String())) var stmt *migo.CallStatement //if ctx.L.Bound == Static && ctx.L.HasNext() { //stmt = &migo.CallStatement{Name: fmt.Sprintf("%s#%d_loop%d", ctx.F.Fn.String(), next.Index, ctx.L.Index), Params: []*migo.Parameter{}} //} else { stmt = &migo.CallStatement{Name: fmt.Sprintf("%s#%d", ctx.F.Fn.String(), next.Index)} for i := 0; i < len(ctx.F.FuncDef.Params); i++ { for k, ea := range ctx.F.extraargs { if phi, ok := ea.(*ssa.Phi); ok { if jump.Block().Index < len(phi.Edges) { for _, e := range phi.Edges { if ctx.F.FuncDef.Params[i].Caller.Name() == e.Name() { ctx.F.FuncDef.Params[i].Callee = phi // Remove from extra args if k < len(ctx.F.extraargs) { ctx.F.extraargs = append(ctx.F.extraargs[:k], ctx.F.extraargs[k+1:]...) } else { ctx.F.extraargs = ctx.F.extraargs[:k] } } } } } } // This loop copies args from current function to Successor. if phi, ok := ctx.F.FuncDef.Params[i].Callee.(*ssa.Phi); ok { // Resolve in current scope if phi stmt.AddParams(&migo.Parameter{Caller: phi.Edges[jump.Block().Index], Callee: ctx.F.FuncDef.Params[i].Callee}) } else { stmt.AddParams(&migo.Parameter{Caller: ctx.F.FuncDef.Params[i].Callee, Callee: ctx.F.FuncDef.Params[i].Callee}) } } for _, ea := range ctx.F.extraargs { if phi, ok := ea.(*ssa.Phi); ok { stmt.AddParams(&migo.Parameter{Caller: phi.Edges[jump.Block().Index], Callee: phi}) } else { stmt.AddParams(&migo.Parameter{Caller: ea, Callee: ea}) } } //} ctx.F.FuncDef.AddStmts(stmt) if _, visited := ctx.F.Visited[next]; !visited { newBlock := NewBlock(ctx.F, next, ctx.B.Index) oldFunc, newFunc := ctx.F.FuncDef, newBlock.MigoDef if ctx.L.Bound == Static && ctx.L.HasNext() { newFunc = migo.NewFunction(fmt.Sprintf("%s#%d_loop%d", ctx.F.Fn.String(), next.Index, ctx.L.Index)) } for _, p := range stmt.Params { newFunc.AddParams(&migo.Parameter{Caller: p.Callee, Callee: p.Callee}) } ctx.F.FuncDef = newFunc infer.Env.MigoProg.AddFunction(newFunc) visitBasicBlock(next, infer, ctx.F, newBlock, ctx.L) ctx.F.FuncDef = oldFunc return } } visitBasicBlock(next, infer, ctx.F, NewBlock(ctx.F, next, ctx.B.Index), ctx.L) }