Example #1
0
File: lower.go Project: mewmew/uc
// indexExpr lowers the given index expression to LLVM IR, emitting code to f.
func (m *Module) indexExpr(f *Function, n *ast.IndexExpr) value.Value {
	index := m.expr(f, n.Index)
	// Extend the index to a 64-bit integer.
	if !irtypes.Equal(index.Type(), irtypes.I64) {
		index = m.convert(f, index, irtypes.I64)
	}
	typ := m.typeOf(n.Name)
	array := m.valueFromIdent(f, n.Name)

	// Dereference pointer pointer.
	elem := typ
	addr := array
	zero := constZero(irtypes.I64)
	indices := []value.Value{zero, index}
	if typ, ok := typ.(*irtypes.Pointer); ok {
		elem = typ.Elem()

		// Emit load instruction.
		// TODO: Validate typ against array.Elem().
		loadInst, err := instruction.NewLoad(array)
		if err != nil {
			panic(fmt.Sprintf("unable to create load instruction; %v", err))
		}
		addr = f.emitInst(loadInst)
		indices = []value.Value{index}
	}

	// Emit getelementptr instruction.
	if m.isGlobal(n.Name) {
		var is []constant.Constant
		for _, index := range indices {
			i, ok := index.(constant.Constant)
			if !ok {
				break
			}
			is = append(is, i)
		}
		if len(is) == len(indices) {
			// In accordance with Clang, emit getelementptr constant expressions
			// for global variables.
			gepExpr, err := constant.NewGetElementPtr(elem, addr, is)
			if err != nil {
				panic(fmt.Sprintf("unable to create getelementptr expression; %v", err))
			}
			return gepExpr
		}
	}
	// TODO: Validate elem against array.Elem().
	gepInst, err := instruction.NewGetElementPtr(addr, indices)
	if err != nil {
		panic(fmt.Sprintf("unable to create getelementptr instruction; %v", err))
	}
	return f.emitInst(gepInst)
}
Example #2
0
File: lower.go Project: mewmew/uc
// indexExprUse lowers the given index expression usage to LLVM IR, emitting
// code to f.
func (m *Module) indexExprUse(f *Function, n *ast.IndexExpr) value.Value {
	v := m.indexExpr(f, n)
	typ := m.typeOf(n)
	if isRef(typ) {
		return v
	}
	// TODO: Validate typ against v.Elem().
	loadInst, err := instruction.NewLoad(v)
	if err != nil {
		panic(fmt.Sprintf("unable to create load instruction; %v", err))
	}
	// Emit load instruction.
	return f.emitInst(loadInst)
}
Example #3
0
File: lower.go Project: mewmew/uc
// identUse lowers the given identifier usage to LLVM IR, emitting code to f.
func (m *Module) identUse(f *Function, ident *ast.Ident) value.Value {
	v := m.ident(f, ident)
	typ := m.typeOf(ident)
	if isRef(typ) {
		return v
	}
	// TODO: Validate typ against v.Elem()
	loadInst, err := instruction.NewLoad(v)
	if err != nil {
		panic(fmt.Sprintf("unable to create load instruction; %v", err))
	}
	// Emit load instruction.
	return f.emitInst(loadInst)
}
Example #4
0
File: irx.go Project: llir/llvm
// NewLoadInst returns a new load instruction based on the given type and
// address.
func NewLoadInst(typ, srcAddrType, srcAddr interface{}) (*instruction.Load, error) {
	if typ, ok := typ.(types.Type); ok {
		srcAddr, err := NewValue(srcAddrType, srcAddr)
		if err != nil {
			return nil, errutil.Err(err)
		}
		srcAddrType, ok := srcAddr.Type().(*types.Pointer)
		if !ok {
			return nil, errutil.Newf("invalid source address pointer type; expected *types.Pointer, got %T", srcAddr.Type())
		}
		if !types.Equal(typ, srcAddrType.Elem()) {
			return nil, errutil.Newf("type mismatch between element type (%v) and source address element type (%v)", typ, srcAddrType.Elem())
		}
		return instruction.NewLoad(srcAddr)
	}
	return nil, errutil.Newf("invalid operand type; expected types.Type, got %T", typ)
}
Example #5
0
File: lower.go Project: mewmew/uc
// ident lowers the given identifier to LLVM IR, emitting code to f.
func (m *Module) ident(f *Function, ident *ast.Ident) value.Value {
	switch typ := m.typeOf(ident).(type) {
	case *irtypes.Array:
		array := m.valueFromIdent(f, ident)
		zero := constZero(irtypes.I64)
		indices := []value.Value{zero, zero}

		// Emit getelementptr instruction.
		if m.isGlobal(ident) {
			var is []constant.Constant
			for _, index := range indices {
				i, ok := index.(constant.Constant)
				if !ok {
					break
				}
				is = append(is, i)
			}
			if len(is) == len(indices) {
				// In accordance with Clang, emit getelementptr constant expressions
				// for global variables.
				gepExpr, err := constant.NewGetElementPtr(typ, array, is)
				if err != nil {
					panic(fmt.Sprintf("unable to create getelementptr expression; %v", err))
				}
				return gepExpr
			}
		}
		gepInst, err := instruction.NewGetElementPtr(array, indices)
		if err != nil {
			panic(fmt.Sprintf("unable to create getelementptr instruction; %v", err))
		}
		return f.emitInst(gepInst)
	case *irtypes.Pointer:
		// Emit load instruction.
		// TODO: Validate typ against srcAddr.Elem().
		loadInst, err := instruction.NewLoad(m.valueFromIdent(f, ident))
		if err != nil {
			panic(fmt.Sprintf("unable to create load instruction; %v", err))
		}
		return f.emitInst(loadInst)
	default:
		return m.valueFromIdent(f, ident)
	}
}
Example #6
0
File: fix.go Project: 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")
	}
}