func (f *Function) If(instr *ssa.If) (string, *Error) { asm := "" ctx := context{f, instr} tblock, fblock := -1, -1 if instr.Block() != nil && len(instr.Block().Succs) == 2 { tblock = instr.Block().Succs[0].Index fblock = instr.Block().Succs[1].Index } if tblock == -1 || fblock == -1 { ice("malformed CFG with if stmt") } cond, ok := f.identifiers[instr.Cond.Name()] if !ok { return ErrorMsg(fmt.Sprintf("If: unhandled case, cond (%v)", instr.Cond)) } a, reg, err := f.LoadIdentSimple(instr, cond) if err != nil { return "", err } asm += a a, err = f.JumpPreamble(instr, instr.Block().Index, fblock) if err != nil { return "", err } asm += a asm += CmpRegImm32(ctx, reg, uint32(0), cond.size()) f.freeReg(reg) asm += fmt.Sprintf("%-9v ", JEQ) + "block" + strconv.Itoa(fblock) + "\n" a, err = f.JumpPreamble(instr, instr.Block().Index, tblock) if err != nil { return "", err } asm += a jmp := "JMP" asm += fmt.Sprintf("%-9v ", jmp) + "block" + strconv.Itoa(tblock) + "\n" asm = fmt.Sprintf("// BEGIN ssa.If, %v\n", instr) + asm asm += fmt.Sprintf("// END ssa.If, %v\n", instr) return asm, nil }
func visitIf(instr *ssa.If, infer *TypeInfer, ctx *Context) { if len(instr.Block().Succs) != 2 { infer.Logger.Fatal(ErrInvalidIfSucc) } // Detect and unroll ctx.L. if ctx.L.State != NonLoop && ctx.L.Bound == Static && instr.Cond == ctx.L.CondVar { if ctx.L.HasNext() { infer.Logger.Printf(ctx.F.Sprintf(LoopSymbol+"loop continue %s", ctx.L)) visitBasicBlock(instr.Block().Succs[0], infer, ctx.F, NewBlock(ctx.F, instr.Block().Succs[0], ctx.B.Index), ctx.L) } else { infer.Logger.Printf(ctx.F.Sprintf(LoopSymbol+"loop exit %s", ctx.L)) visitBasicBlock(instr.Block().Succs[1], infer, ctx.F, NewBlock(ctx.F, instr.Block().Succs[1], ctx.B.Index), ctx.L) } return } // Detect Select branches. if bin, ok := instr.Cond.(*ssa.BinOp); ok && bin.Op == token.EQL { for _, sel := range ctx.F.selects { if bin.X == sel.Index.(*Value).Value { if i, ok := bin.Y.(*ssa.Const); ok && i.Value.Kind() == constant.Int { //infer.Logger.Print(fmt.Sprintf("[select-%d]", i.Int64()), ctx.F.FuncDef.String()) parDef := ctx.F.FuncDef parDef.PutAway() // Save select visitBasicBlock(instr.Block().Succs[0], infer, ctx.F, NewBlock(ctx.F, instr.Block().Succs[0], ctx.B.Index), ctx.L) ctx.F.FuncDef.PutAway() // Save case selCase, err := ctx.F.FuncDef.Restore() if err != nil { infer.Logger.Fatal("select-case:", err) } sel.MigoStmt.Cases[i.Int64()] = append(sel.MigoStmt.Cases[i.Int64()], selCase...) selParent, err := parDef.Restore() if err != nil { infer.Logger.Fatal("select-parent:", err) } parDef.AddStmts(selParent...) // Test if select has default branch & if this is default if !sel.Instr.Blocking && i.Int64() == int64(len(sel.Instr.States)-1) { infer.Logger.Print(ctx.F.Sprintf(SelectSymbol + "default")) if instr.Block().Succs[1].Comment == "select.done" { // Looks like it's empty infer.Logger.Printf(SplitSymbol+"Empty default branch (%d ⇾ %d)", instr.Block().Index, instr.Block().Succs[1].Index) selDefault := &migo.CallStatement{Name: fmt.Sprintf("%s#%d", ctx.F.Fn.String(), instr.Block().Succs[1].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 instr.Block().Succs[1].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 selDefault.AddParams(&migo.Parameter{Caller: phi.Edges[instr.Block().Succs[1].Index], Callee: ctx.F.FuncDef.Params[i].Callee}) } else { selDefault.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 { selDefault.AddParams(&migo.Parameter{Caller: phi.Edges[instr.Block().Succs[1].Index], Callee: phi}) } else { selDefault.AddParams(&migo.Parameter{Caller: ea, Callee: ea}) } } parDef := ctx.F.FuncDef parDef.PutAway() // Save select sel.MigoStmt.Cases[len(sel.MigoStmt.Cases)-1] = append(sel.MigoStmt.Cases[len(sel.MigoStmt.Cases)-1], selDefault) selParent, err := parDef.Restore() if err != nil { infer.Logger.Fatal("select-parent:", err) } parDef.AddStmts(selParent...) } else { parDef := ctx.F.FuncDef parDef.PutAway() // Save select visitBasicBlock(instr.Block().Succs[1], infer, ctx.F, NewBlock(ctx.F, instr.Block().Succs[1], ctx.B.Index), ctx.L) ctx.F.FuncDef.PutAway() // Save case selDefault, err := ctx.F.FuncDef.Restore() if err != nil { infer.Logger.Fatal("select-default:", err) } sel.MigoStmt.Cases[len(sel.MigoStmt.Cases)-1] = append(sel.MigoStmt.Cases[len(sel.MigoStmt.Cases)-1], selDefault...) selParent, err := parDef.Restore() if err != nil { infer.Logger.Fatal("select-parent:", err) } parDef.AddStmts(selParent...) } } else { infer.Logger.Printf(ctx.F.Sprintf(IfSymbol+"select-else "+JumpSymbol+"%d", instr.Block().Succs[1].Index)) visitBasicBlock(instr.Block().Succs[1], infer, ctx.F, NewBlock(ctx.F, instr.Block().Succs[1], ctx.B.Index), ctx.L) } return // Select if-then-else handled } } } } var cond string if inst, ok := ctx.F.locals[instr.Cond]; ok && isCommaOk(ctx.F, inst) { cond = fmt.Sprintf("comma-ok %s", instr.Cond.Name()) } else { cond = fmt.Sprintf("%s", instr.Cond.Name()) } // Save parent. ctx.F.FuncDef.PutAway() infer.Logger.Printf(ctx.F.Sprintf(IfSymbol+"if %s then"+JumpSymbol+"%d", cond, instr.Block().Succs[0].Index)) visitBasicBlock(instr.Block().Succs[0], infer, ctx.F, NewBlock(ctx.F, instr.Block().Succs[0], ctx.B.Index), ctx.L) // Save then. ctx.F.FuncDef.PutAway() infer.Logger.Printf(ctx.F.Sprintf(IfSymbol+"if %s else"+JumpSymbol+"%d", cond, instr.Block().Succs[1].Index)) if ctx.L.State == Body && ctx.L.LoopBlock == ctx.B.Index { // Infinite loop. infer.Logger.Printf(ctx.F.Sprintf(LoopSymbol + " infinite loop")) stmt := &migo.CallStatement{Name: fmt.Sprintf("%s#%d", ctx.F.Fn.String(), ctx.B.Index)} for _, p := range ctx.F.FuncDef.Params { stmt.AddParams(&migo.Parameter{Caller: p.Callee, Callee: p.Callee}) } ctx.F.FuncDef.AddStmts(stmt) } else { visitBasicBlock(instr.Block().Succs[1], infer, ctx.F, NewBlock(ctx.F, instr.Block().Succs[1], ctx.B.Index), ctx.L) } // Save else. ctx.F.FuncDef.PutAway() elseStmts, err := ctx.F.FuncDef.Restore() // Else if err != nil { infer.Logger.Fatal("restore else:", err) } thenStmts, err := ctx.F.FuncDef.Restore() // Then if err != nil { infer.Logger.Fatal("restore then:", err) } parentStmts, err := ctx.F.FuncDef.Restore() // Parent if err != nil { infer.Logger.Fatal("restore if-then-else parent:", err) } ctx.F.FuncDef.AddStmts(parentStmts...) ctx.F.FuncDef.AddStmts(&migo.IfStatement{Then: thenStmts, Else: elseStmts}) }
func visitIf(inst *ssa.If, fr *frame) { if len(inst.Block().Succs) != 2 { panic("If: Cannot handle If with more or less than 2 successor blocks!") } ifparent := fr.gortn.leaf if ifparent == nil { panic("If: Parent is nil") } if ch, isRecvTest := fr.env.recvTest[inst.Cond]; isRecvTest { fmt.Fprintf(os.Stderr, " @ Switch to recvtest true\n") fr.gortn.leaf = ifparent fr.gortn.AddNode(sesstype.NewRecvNode(*ch, fr.gortn.role, ch.Type())) fmt.Fprintf(os.Stderr, " %s\n", orange((*fr.gortn.leaf).String())) visitBlock(inst.Block().Succs[0], fr) fmt.Fprintf(os.Stderr, " @ Switch to recvtest false\n") fr.gortn.leaf = ifparent fr.gortn.AddNode(sesstype.NewRecvStopNode(*ch, fr.gortn.role, ch.Type())) fmt.Fprintf(os.Stderr, " %s\n", orange((*fr.gortn.leaf).String())) visitBlock(inst.Block().Succs[1], fr) } else if selTest, isSelTest := fr.env.selTest[inst.Cond]; isSelTest { // Check if this is a select-test-jump, if so handle separately. fmt.Fprintf(os.Stderr, " @ Switch to select branch #%d\n", selTest.idx) if selParent, ok := fr.env.selNode[selTest.tpl]; ok { fr.gortn.leaf = ifparent *fr.gortn.leaf = (*selParent.parent).Child(selTest.idx) visitBlock(inst.Block().Succs[0], fr) if !selParent.blocking && len((*selParent.parent).Children()) > selTest.idx+1 { *fr.gortn.leaf = (*selParent.parent).Child(selTest.idx + 1) } visitBlock(inst.Block().Succs[1], fr) } else { panic("Select without corresponding sesstype.Node") } } else { fr.env.ifparent.Push(*fr.gortn.leaf) parent := fr.env.ifparent.Top() fr.gortn.leaf = &parent fr.gortn.AddNode(&sesstype.EmptyBodyNode{}) visitBlock(inst.Block().Succs[0], fr) parent = fr.env.ifparent.Top() fr.gortn.leaf = &parent fr.gortn.AddNode(&sesstype.EmptyBodyNode{}) visitBlock(inst.Block().Succs[1], fr) fr.env.ifparent.Pop() } // This is end of the block so no continuation }