Beispiel #1
0
Datei: irx.go Projekt: llir/llvm
// NewICmpInst returns a new icmp instruction based on the given condition and
// operands.
func NewICmpInst(cond, typ, x, y interface{}) (*instruction.ICmp, error) {
	if cond, ok := cond.(instruction.ICond); ok {
		x, err := NewValue(typ, x)
		if err != nil {
			return nil, errutil.Err(err)
		}
		y, err := NewValue(typ, y)
		if err != nil {
			return nil, errutil.Err(err)
		}
		return instruction.NewICmp(cond, x, y)
	}
	return nil, errutil.Newf("invalid condition type; expected instruction.ICond, got %T", cond)
}
Beispiel #2
0
// cond lowers the given condition expression to LLVM IR, emitting code to f.
func (m *Module) cond(f *Function, expr ast.Expr) value.Value {
	cond := m.expr(f, expr)
	if irtypes.IsBool(cond.Type()) {
		return cond
	}
	// Create boolean expression if cond is not already of boolean type.
	//
	//    cond != 0
	// zero is the integer constant 0.
	zero := constZero(cond.Type())
	icmpInst, err := instruction.NewICmp(instruction.ICondNE, cond, zero)
	if err != nil {
		panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
	}
	return f.emitInst(icmpInst)
}
Beispiel #3
0
Datei: fix.go Projekt: llir/llvm
// fixValueInst replaces dummy values within the given value instruction with
// their corresponding local variables.
func (m dummyMap) fixValueInst(oldValInst instruction.ValueInst) instruction.ValueInst {
	switch oldValInst := oldValInst.(type) {
	// Binary Operations
	case *instruction.Add:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewAdd(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FAdd:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewFAdd(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.Sub:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewSub(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FSub:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewFSub(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.Mul:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewMul(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FMul:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewFMul(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.UDiv:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewUDiv(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.SDiv:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewSDiv(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FDiv:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewFDiv(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.URem:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewURem(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.SRem:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewSRem(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FRem:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewFRem(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst

	// Bitwise Binary Operations
	case *instruction.ShL:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewShL(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.LShR:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewLShR(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.AShR:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewAShR(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.And:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewAnd(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.Or:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewOr(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.Xor:
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewXor(x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst

	// Vector Operations
	case *instruction.ExtractElement:
		panic("irx.dummyMap.fixValueInst: ExtractElement not yet implemented")
	case *instruction.InsertElement:
		panic("irx.dummyMap.fixValueInst: InsertElement not yet implemented")
	case *instruction.ShuffleVector:
		panic("irx.dummyMap.fixValueInst: ShuffleVector not yet implemented")

	// Aggregate Operations
	case *instruction.ExtractValue:
		panic("irx.dummyMap.fixValueInst: ExtractValue not yet implemented")
	case *instruction.InsertValue:
		panic("irx.dummyMap.fixValueInst: InsertValue not yet implemented")

	// Memory Access and Addressing Operations
	case *instruction.Alloca:
		// Nothing to do; alloca contains no dummy values.
		return oldValInst
	case *instruction.Load:
		srcAddr := m.fixValue(oldValInst.SrcAddr())
		inst, err := instruction.NewLoad(srcAddr)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.CmpXchg:
		panic("irx.dummyMap.fixValueInst: CmpXchg not yet implemented")
	case *instruction.AtomicRMW:
		panic("irx.dummyMap.fixValueInst: AtomicRMW not yet implemented")
	case *instruction.GetElementPtr:
		srcAddr := m.fixValue(oldValInst.SrcAddr())
		var indices []value.Value
		for _, oldIndex := range oldValInst.Indices() {
			index := m.fixValue(oldIndex)
			indices = append(indices, index)
		}
		inst, err := instruction.NewGetElementPtr(srcAddr, indices)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst

	// Conversion Operations
	case *instruction.Trunc:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewTrunc(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.ZExt:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewZExt(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.SExt:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewSExt(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FPTrunc:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewFPTrunc(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FPExt:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewFPExt(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FPToUI:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewFPToUI(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FPToSI:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewFPToSI(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.UIToFP:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewUIToFP(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.SIToFP:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewSIToFP(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.PtrToInt:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewPtrToInt(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.IntToPtr:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewIntToPtr(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.BitCast:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewBitCast(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.AddrSpaceCast:
		from := m.fixValue(oldValInst.From())
		to := oldValInst.RetType()
		inst, err := instruction.NewAddrSpaceCast(from, to)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst

	// Other Operations
	case *instruction.ICmp:
		cond := oldValInst.Cond()
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewICmp(cond, x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.FCmp:
		panic("irx.dummyMap.fixValueInst: FCmp not yet implemented")
	case *instruction.PHI:
		oldIncs := oldValInst.Incs()
		var incs []*instruction.Incoming
		for _, oldInc := range oldIncs {
			val := m.fixValue(oldInc.Value())
			pred := m.fixNamedValue(oldInc.Pred())
			inc, err := instruction.NewIncoming(val, pred)
			if err != nil {
				panic(errutil.Err(err))
			}
			incs = append(incs, inc)
		}
		inst, err := instruction.NewPHI(incs)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.Select:
		cond := m.fixValue(oldValInst.Cond())
		x := m.fixValue(oldValInst.X())
		y := m.fixValue(oldValInst.Y())
		inst, err := instruction.NewSelect(cond, x, y)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.Call:
		result := oldValInst.RetType()
		// TODO: Fix value of callee if the type of Callee changes from string to
		// value.Value.
		callee := oldValInst.Callee()
		var args []value.Value
		for _, oldArg := range oldValInst.Args() {
			arg := m.fixValue(oldArg)
			args = append(args, arg)
		}
		inst, err := instruction.NewCall(result, callee, args)
		if err != nil {
			panic(errutil.Err(err))
		}
		return inst
	case *instruction.VAArg:
		panic("irx.dummyMap.fixValueInst: VAArg not yet implemented")
	case *instruction.LandingPad:
		panic("irx.dummyMap.fixValueInst: LandingPad not yet implemented")
	case *instruction.CatchPad:
		panic("irx.dummyMap.fixValueInst: CatchPad not yet implemented")
	case *instruction.CleanupPad:
		panic("irx.dummyMap.fixValueInst: CleanupPad not yet implemented")
	default:
		panic("irx.dummyMap.fixValueInst: not yet implemented")
	}
}
Beispiel #4
0
// 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))
	}
}