Esempio n. 1
0
File: lower.go Progetto: mewmew/uc
// ifStmt lowers the given if statement to LLVM IR, emitting code to f.
func (m *Module) ifStmt(f *Function, stmt *ast.IfStmt) {
	cond := m.cond(f, stmt.Cond)
	trueBranch := f.NewBasicBlock("")
	end := f.NewBasicBlock("")
	falseBranch := end
	if stmt.Else != nil {
		falseBranch = f.NewBasicBlock("")
	}
	term, err := instruction.NewBr(cond, trueBranch, falseBranch)
	if err != nil {
		panic(fmt.Sprintf("unable to create br terminator; %v", err))
	}
	f.curBlock.SetTerm(term)
	f.curBlock = trueBranch
	m.stmt(f, stmt.Body)
	// Emit jump if body doesn't end with return statement (i.e. the current
	// basic block is none nil).
	if f.curBlock != nil {
		f.curBlock.emitJmp(end)
	}
	if stmt.Else != nil {
		f.curBlock = falseBranch
		m.stmt(f, stmt.Else)
		// Emit jump if body doesn't end with return statement (i.e. the current
		// basic block is none nil).
		if f.curBlock != nil {
			f.curBlock.emitJmp(end)
		}
	}
	f.curBlock = end
}
Esempio n. 2
0
File: fix.go Progetto: llir/llvm
// fixTerm replaces dummy values within the given terminator with their
// corresponding local variables.
func (m dummyMap) fixTerm(oldTerm instruction.Terminator) instruction.Terminator {
	switch oldTerm := oldTerm.(type) {
	case *instruction.Ret:
		oldVal := oldTerm.Value()
		var val value.Value
		if oldVal != nil {
			val = m.fixValue(oldVal)
		}
		term, err := instruction.NewRet(val)
		if err != nil {
			panic(errutil.Err(err))
		}
		return term
	case *instruction.Jmp:
		target := m.fixNamedValue(oldTerm.Target())
		term, err := instruction.NewJmp(target)
		if err != nil {
			panic(errutil.Err(err))
		}
		return term
	case *instruction.Br:
		cond := m.fixValue(oldTerm.Cond())
		trueBranch := m.fixNamedValue(oldTerm.TrueBranch())
		falseBranch := m.fixNamedValue(oldTerm.FalseBranch())
		term, err := instruction.NewBr(cond, trueBranch, falseBranch)
		if err != nil {
			panic(errutil.Err(err))
		}
		return term
	case *instruction.Switch:
		panic("irx.dummyMap.fixTerm: Switch not yet implemented")
	case *instruction.IndirectBr:
		panic("irx.dummyMap.fixTerm: IndirectBr not yet implemented")
	case *instruction.Invoke:
		panic("irx.dummyMap.fixTerm: Invoke not yet implemented")
	case *instruction.Resume:
		panic("irx.dummyMap.fixTerm: Resume not yet implemented")
	case *instruction.CatchSwitch:
		panic("irx.dummyMap.fixTerm: CatchSwitch not yet implemented")
	case *instruction.CatchRet:
		panic("irx.dummyMap.fixTerm: CatchRet not yet implemented")
	case *instruction.CleanupRet:
		panic("irx.dummyMap.fixTerm: CleanupRet not yet implemented")
	case *instruction.Unreachable:
		panic("irx.dummyMap.fixTerm: Unreachable not yet implemented")
	default:
		panic(fmt.Sprintf("support for terminator type %T not yet implemented", oldTerm))
	}
}
Esempio n. 3
0
File: irx.go Progetto: llir/llvm
// NewBrInst returns a new br instruction based on the given branching
// condition, and the true and false target branches.
func NewBrInst(condType, condVal, ltrueBranch, lfalseBranch interface{}) (*instruction.Br, error) {
	cond, err := NewValue(condType, condVal)
	if err != nil {
		return nil, errutil.Err(err)
	}
	falseBranch, ok := lfalseBranch.(*LocalDummy)
	if !ok {
		return nil, errutil.Newf("invalid false branch type; expected *LocalDummy, got %T", lfalseBranch)
	}
	trueBranch, ok := ltrueBranch.(*LocalDummy)
	if !ok {
		return nil, errutil.Newf("invalid true branch type; expected *LocalDummy, got %T", ltrueBranch)
	}
	return instruction.NewBr(cond, trueBranch, falseBranch)
}
Esempio n. 4
0
File: lower.go Progetto: mewmew/uc
// whileStmt lowers the given while statement to LLVM IR, emitting code to f.
func (m *Module) whileStmt(f *Function, stmt *ast.WhileStmt) {
	condBranch := f.NewBasicBlock("")
	f.curBlock.emitJmp(condBranch)
	f.curBlock = condBranch
	cond := m.cond(f, stmt.Cond)
	bodyBranch := f.NewBasicBlock("")
	endBranch := f.NewBasicBlock("")
	term, err := instruction.NewBr(cond, bodyBranch, endBranch)
	if err != nil {
		panic(fmt.Sprintf("unable to create br terminator; %v", err))
	}
	f.curBlock.SetTerm(term)
	f.curBlock = bodyBranch
	m.stmt(f, stmt.Body)
	// Emit jump if body doesn't end with return statement (i.e. the current
	// basic block is none nil).
	if f.curBlock != nil {
		f.curBlock.emitJmp(condBranch)
	}
	f.curBlock = endBranch
}
Esempio n. 5
0
File: lower.go Progetto: mewmew/uc
// binaryExpr lowers the given binary expression to LLVM IR, emitting code to f.
func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
	switch n.Op {
	// +
	case token.Add:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		addInst, err := instruction.NewAdd(x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create add instruction; %v", err))
		}
		// Emit add instruction.
		return f.emitInst(addInst)

	// -
	case token.Sub:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		subInst, err := instruction.NewSub(x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create sub instruction; %v", err))
		}
		// Emit sub instruction.
		return f.emitInst(subInst)

	// *
	case token.Mul:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		mulInst, err := instruction.NewMul(x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create mul instruction; %v", err))
		}
		// Emit mul instruction.
		return f.emitInst(mulInst)

	// /
	case token.Div:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		// TODO: Add support for unsigned division.
		sdivInst, err := instruction.NewSDiv(x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create sdiv instruction; %v", err))
		}
		// Emit sdiv instruction.
		return f.emitInst(sdivInst)

	// <
	case token.Lt:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		icmpInst, err := instruction.NewICmp(instruction.ICondSLT, x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
		}
		// Emit icmp instruction.
		return f.emitInst(icmpInst)

	// >
	case token.Gt:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		icmpInst, err := instruction.NewICmp(instruction.ICondSGT, x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
		}
		// Emit icmp instruction.
		return f.emitInst(icmpInst)

	// <=
	case token.Le:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		icmpInst, err := instruction.NewICmp(instruction.ICondSLE, x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
		}
		// Emit icmp instruction.
		return f.emitInst(icmpInst)

	// >=
	case token.Ge:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		icmpInst, err := instruction.NewICmp(instruction.ICondSGE, x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
		}
		// Emit icmp instruction.
		return f.emitInst(icmpInst)

	// !=
	case token.Ne:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		icmpInst, err := instruction.NewICmp(instruction.ICondNE, x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
		}
		// Emit icmp instruction.
		return f.emitInst(icmpInst)

	// ==
	case token.Eq:
		x, y := m.expr(f, n.X), m.expr(f, n.Y)
		x, y = m.implicitConversion(f, x, y)
		icmpInst, err := instruction.NewICmp(instruction.ICondEQ, x, y)
		if err != nil {
			panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
		}
		// Emit icmp instruction.
		return f.emitInst(icmpInst)

	// &&
	case token.Land:
		x := m.cond(f, n.X)

		start := f.curBlock
		trueBranch := f.NewBasicBlock("")
		end := f.NewBasicBlock("")
		term, err := instruction.NewBr(x, trueBranch, end)
		if err != nil {
			panic(fmt.Sprintf("unable to create br terminator; %v", err))
		}
		f.curBlock.SetTerm(term)
		f.curBlock = trueBranch

		y := m.cond(f, n.Y)
		trueBranch.emitJmp(end)
		f.curBlock = end

		var incs []*instruction.Incoming
		zero := constZero(irtypes.I1)
		inc, err := instruction.NewIncoming(zero, start)
		if err != nil {
			panic(fmt.Sprintf("unable to create incoming value; %v", err))
		}
		incs = append(incs, inc)
		inc, err = instruction.NewIncoming(y, trueBranch)
		if err != nil {
			panic(fmt.Sprintf("unable to create incoming value; %v", err))
		}
		incs = append(incs, inc)
		phiInst, err := instruction.NewPHI(incs)
		if err != nil {
			panic(fmt.Sprintf("unable to create br terminator; %v", err))
		}
		// Emit phi instruction.
		return f.emitInst(phiInst)

	// =
	case token.Assign:
		y := m.expr(f, n.Y)
		switch expr := n.X.(type) {
		case *ast.Ident:
			m.identDef(f, expr, y)
		case *ast.IndexExpr:
			m.indexExprDef(f, expr, y)
		default:
			panic(fmt.Sprintf("support for assignment to type %T not yet implemented", expr))
		}
		return y

	default:
		panic(fmt.Sprintf("support for binary operator %v not yet implemented", n.Op))
	}
}