Example #1
0
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
}
Example #2
0
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})
}
Example #3
0
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
}