// loopDetectBounds detects static bounds (or set as dynamic bounds) from based // on loop state machine. func loopDetectBounds(instr *ssa.Phi, infer *TypeInfer, ctx *Context) { switch ctx.L.State { case Enter: switch ctx.L.Bound { case Unknown: phiSelectEdge(instr, infer, ctx) loopSetIndex(instr, infer, ctx) case Static: switch ctx.L.Bound { case Static: phiSelectEdge(instr, infer, ctx) if instr == ctx.L.IndexVar { ctx.L.Next() infer.Logger.Printf(ctx.F.Sprintf(LoopSymbol+"Increment %s by %s to %s", ctx.L.IndexVar.Name(), fmtLoopHL(ctx.L.Step), fmtLoopHL(ctx.L.Index))) } default: visitSkip(instr, infer, ctx) } case Dynamic: phiSelectEdge(instr, infer, ctx) infer.Logger.Printf(ctx.F.Sprintf(PhiSymbol+"(dynamic bound) %s", instr.String())) } default: phiSelectEdge(instr, infer, ctx) } }
// phiSelectEdge selects edge based on predecessor block and returns the edge index. func phiSelectEdge(instr *ssa.Phi, infer *TypeInfer, ctx *Context) (edge int) { for i, pred := range instr.Block().Preds { if pred.Index == ctx.B.Pred { e, ok := ctx.F.locals[instr.Edges[i]] if !ok { switch t := instr.Edges[i].(type) { case *ssa.Const: ctx.F.locals[instr.Edges[i]] = &Const{t} e, edge = ctx.F.locals[instr.Edges[i]], pred.Index infer.Logger.Printf(ctx.F.Sprintf(PhiSymbol+"%s/%s = %s, selected const from block %d", instr.Name(), e, instr.String(), edge)) case *ssa.Function: ctx.F.locals[instr.Edges[i]] = &Value{instr.Edges[i], ctx.F.InstanceID(), ctx.L.Index} e, edge = ctx.F.locals[instr.Edges[i]], pred.Index infer.Logger.Printf(ctx.F.Sprintf(PhiSymbol+"%s/%s = %s, selected function from block %d", instr.Name(), e, instr.String(), edge)) case *ssa.Call: ctx.F.locals[instr.Edges[i]] = &Value{instr.Edges[i], ctx.F.InstanceID(), ctx.L.Index} e, edge = ctx.F.locals[instr.Edges[i]], pred.Index infer.Logger.Printf(ctx.F.Sprintf(PhiSymbol+"%s/%s = %s, selected call from block %d", instr.Name(), e, instr.String(), edge)) case *ssa.UnOp: ctx.F.locals[instr.Edges[i]] = &Value{instr.Edges[i], ctx.F.InstanceID(), ctx.L.Index} e, edge = ctx.F.locals[instr.Edges[i]], pred.Index infer.Logger.Printf(ctx.F.Sprintf(PhiSymbol+"%s/%s = %s, selected UnOp from block %d", instr.Name(), e, instr.String(), edge)) default: infer.Logger.Fatalf("phi: create instance Edge[%d]=%#v: %s", i, instr.Edges[i], ErrUnknownValue) return } } ctx.F.locals[instr], edge = e, pred.Index infer.Logger.Printf(ctx.F.Sprintf(PhiSymbol+"%s/%s = %s, selected from block %d", instr.Name(), e, instr.String(), edge)) ctx.F.revlookup[instr.Name()] = instr.Edges[i].Name() if a, ok := ctx.F.arrays[e]; ok { ctx.F.arrays[ctx.F.locals[instr]] = a } if s, ok := ctx.F.structs[e]; ok { ctx.F.structs[ctx.F.locals[instr]] = s } return } } infer.Logger.Fatalf("phi: %d->%d: %s", ctx.B.Pred, instr.Block().Index, ErrPhiUnknownEdge) return }