Exemple #1
0
// NewGlobalDef returns a new global variable definition of the given name and
// initial value. The variable is read-only if immutable is true.
func NewGlobalDef(name string, val value.Value, immutable bool) (*GlobalDecl, error) {
	d, err := NewGlobalDecl(name, val.Type(), immutable)
	if err != nil {
		return nil, errutil.Err(err)
	}
	d.val = val
	return d, nil
}
Exemple #2
0
// convert converts the given value to the specified type, emitting code to f.
// No conversion is made, if v is already of the correct type.
func (m *Module) convert(f *Function, v value.Value, to irtypes.Type) value.Value {
	// Early return if v is already of the correct type.
	from := v.Type()
	if irtypes.Equal(from, to) {
		return v
	}
	fromType, ok := from.(*irtypes.Int)
	if !ok {
		panic(fmt.Sprintf("support for converting from type %T not yet implemented", from))
	}
	toType, ok := to.(*irtypes.Int)
	if !ok {
		panic(fmt.Sprintf("support for converting to type %T not yet implemented", to))
	}

	// Convert constant values.
	if v, ok := v.(constant.Constant); ok {
		switch v := v.(type) {
		case *constant.Int:
			v, err := constant.NewInt(toType, v.ValueString())
			if err != nil {
				panic(fmt.Sprintf("unable to create integer constant; %v", err))
			}
			return v
		default:
			panic(fmt.Sprintf("support for converting type %T not yet implemented", v))
		}
	}

	// TODO: Add proper support for converting signed and unsigned values, using
	// sext and zext, respectively.

	// Convert unsigned values.
	if irtypes.IsBool(fromType) {
		// Zero extend boolean values.
		zextInst, err := instruction.NewZExt(v, toType)
		if err != nil {
			panic(fmt.Sprintf("unable to create sext instruction; %v", err))
		}
		return f.emitInst(zextInst)
	}

	// Convert signed values.
	if toType.Size() > fromType.Size() {
		// Sign extend.
		sextInst, err := instruction.NewSExt(v, toType)
		if err != nil {
			panic(fmt.Sprintf("unable to create sext instruction; %v", err))
		}
		return f.emitInst(sextInst)
	}
	// Truncate.
	truncInst, err := instruction.NewTrunc(v, toType)
	if err != nil {
		panic(fmt.Sprintf("unable to create trunc instruction; %v", err))
	}
	return f.emitInst(truncInst)
}
Exemple #3
0
// NewLoad returns a new load instruction based on the given source address.
//
// Pre-conditions:
//    1. srcAddr is of pointer type
func NewLoad(srcAddr value.Value) (*Load, error) {
	// Validate that srcAddr is of pointer type.
	srcAddrType, ok := srcAddr.Type().(*types.Pointer)
	if !ok {
		return nil, errutil.Newf("invalid source address pointer type; expected *types.Pointer, got %T", srcAddr.Type())
	}
	// Determine result type.
	typ := srcAddrType.Elem()
	return &Load{srcAddr: srcAddr, typ: typ}, nil
}
Exemple #4
0
// NewBr returns a new conditional branch instruction based on the given
// branching condition, and the true and false target branches.
func NewBr(cond value.Value, trueBranch, falseBranch value.NamedValue) (*Br, error) {
	// TODO: Validate that trueBranch and falseBranch are of type *ir.BasicBlock.
	// Better yet, chance the signature of NewBr to enforce this. Another
	// approach, is to simply check that the type of trueBranch and falseBranch
	// are both "label".
	if !types.Equal(cond.Type(), types.I1) {
		return nil, errutil.Newf("conditional type mismatch; expected i1, got %v", cond.Type())
	}
	return &Br{cond: cond, trueBranch: trueBranch, falseBranch: falseBranch}, nil
}
Exemple #5
0
// NewSelect returns a new select instruction based on the given selection
// condition, and operands.
//
// Pre-condition: cond is of boolean or boolean vector type. x and y are of
// identical types.
func NewSelect(cond, x, y value.Value) (*Select, error) {
	// Validate that cond is of boolean or boolean vector type.
	if !types.IsBools(cond.Type()) {
		return nil, errutil.Newf("invalid selection condition type; expected boolean or boolean vector, got %v", cond.Type())
	}
	// Validate that x and y are of identical types.
	if !types.Equal(x.Type(), y.Type()) {
		return nil, errutil.Newf("type mismatch between x (%v) and y (%v)", x.Type(), y.Type())
	}
	return &Select{cond: cond, x: x, y: y}, nil
}
Exemple #6
0
// NewStore returns a new store instruction based on the given source value and
// destination address.
//
// Pre-condition:
//    1. dstAddr is of pointer type
//    2. src is of identical type as the element type of dstAddr
func NewStore(src, dstAddr value.Value) (*Store, error) {
	// Validate that dstAddr is of pointer type.
	dstAddrType, ok := dstAddr.Type().(*types.Pointer)
	if !ok {
		return nil, errutil.Newf("invalid destination address pointer type; expected *types.Pointer, got %T", dstAddr.Type())
	}
	// Validate that src is of identical type as the element type of dstAddr.
	if !types.Equal(src.Type(), dstAddrType.Elem()) {
		return nil, errutil.Newf("type mismatch between source value (%v) and destination address element type (%v)", src.Type(), dstAddrType.Elem())
	}
	return &Store{src: src, dstAddr: dstAddr}, nil
}
Exemple #7
0
// NewGetElementPtr returns a new getelementptr instruction based on the given
// source address and element indices.
//
// Pre-condition:
//    1. srcAddr is of pointer type
//    2. indices used to index structure fields are integer constants
func NewGetElementPtr(srcAddr value.Value, indices []value.Value) (*GetElementPtr, error) {
	// Validate that srcAddr is of pointer type.
	srcAddrType, ok := srcAddr.Type().(*types.Pointer)
	if !ok {
		return nil, errutil.Newf("invalid source address pointer type; expected *types.Pointer, got %T", srcAddr.Type())
	}
	// Validate that indices used to index structure fields are integer
	// constants.
	e := srcAddrType.Elem()
	for i, index := range indices {
		if i == 0 {
			// Ignore checking the 0th index as it simply follows the pointer of
			// srcAddr.
			//
			// ref: http://llvm.org/docs/GetElementPtr.html#why-is-the-extra-0-index-required
			continue
		}
		switch ee := e.(type) {
		case *types.Pointer:
			// ref: http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep
			return nil, errutil.Newf(`unable to index into element of pointer type; for more information, see http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep`)
		case *types.Array:
			e = ee.Elem()
		case *types.Struct:
			idx, ok := index.(*constant.Int)
			if !ok {
				return nil, errutil.Newf("invalid index type for structure element; expected *constant.Int, got %T", index)
			}
			e = ee.Fields()[idx.Value().Int64()]
		default:
			panic(fmt.Sprintf("instruction.NewGetElementPtr: support for indexing element type %T not yet implemented", e))
		}
	}
	// Determine result type.
	typ, err := types.NewPointer(e)
	if err != nil {
		return nil, errutil.Err(err)
	}
	// Determine element type.
	elem := srcAddrType.Elem()
	return &GetElementPtr{srcAddr: srcAddr, indices: indices, typ: typ, elem: elem}, nil
}
Exemple #8
0
// NewGetElementPtr returns a new getelementptr expression based on the given
// element type, address and element indices.
//
// Preconditions:
//    * elem is of the same type as addr.Type().Elem().
//    * addr is of pointer type.
//    * indices used to index structure fields are integer constants.
func NewGetElementPtr(elem types.Type, addr value.Value, indices []Constant) (*GetElementPtr, error) {
	// Sanity checks.
	addrType, ok := addr.Type().(*types.Pointer)
	if !ok {
		return nil, errutil.Newf("invalid pointer type; expected *types.Pointer, got %T", addr.Type())
	}
	if !types.Equal(elem, addrType.Elem()) {
		return nil, errutil.Newf("type mismatch between %v and %v", elem, addrType.Elem())
	}

	e := addrType.Elem()
	for i, index := range indices {
		if i == 0 {
			// Ignore checking the 0th index as it simply follows the pointer of
			// addr.
			//
			// ref: http://llvm.org/docs/GetElementPtr.html#why-is-the-extra-0-index-required
			continue
		}
		switch ee := e.(type) {
		case *types.Pointer:
			// ref: http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep
			return nil, errutil.Newf(`unable to index into element of pointer type; for more information, see http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep`)
		case *types.Array:
			e = ee.Elem()
		case *types.Struct:
			idx, ok := index.(*Int)
			if !ok {
				return nil, errutil.Newf("invalid index type for structure element; expected *constant.Int, got %T", index)
			}
			e = ee.Fields()[idx.Value().Int64()]
		default:
			panic(fmt.Sprintf("constant.NewGetElementPtr: support for indexing element type %T not yet implemented", e))
		}
	}
	typ, err := types.NewPointer(e)
	if err != nil {
		return nil, errutil.Err(err)
	}
	return &GetElementPtr{typ: typ, elem: elem, addr: addr, indices: indices}, nil
}
Exemple #9
0
// NewRet returns a new ret instruction based on the given return value. A nil
// return value indicates a "void" return instruction.
func NewRet(val value.Value) (*Ret, error) {
	if val != nil && types.IsVoid(val.Type()) {
		return nil, errutil.Newf(`expected no return value for return type "void"; got %q`, val)
	}
	return &Ret{val: val}, nil
}
Exemple #10
0
// NewFAdd returns a new fadd instruction based on the given operands.
func NewFAdd(x, y value.Value) (*FAdd, error) {
	if !types.Equal(x.Type(), y.Type()) {
		return nil, errutil.Newf("type mismatch between x (%v) and y (%v)", x.Type(), y.Type())
	}
	return &FAdd{x: x, y: y}, nil
}
Exemple #11
0
// NewICmp returns a new icmp instruction based on the given condition and
// operands.
//
// Pre-condition: x and y are of identical types. x and y are of integer,
// integer vector, pointer or pointer vector type.
func NewICmp(cond ICond, x, y value.Value) (*ICmp, error) {
	// Validate that x and y are of identical types.
	if !types.Equal(x.Type(), y.Type()) {
		return nil, errutil.Newf("type mismatch between x (%v) and y (%v)", x.Type(), y.Type())
	}
	// Validate that x and y are of integer, integer vector, pointer or pointer
	// vector type.
	if !types.IsInts(x.Type()) && !types.IsPointers(x.Type()) {
		return nil, errutil.Newf("invalid x operand type; expected integer, integer vector, pointer or pointer vector, got %v", x.Type())
	}
	if !types.IsInts(y.Type()) && !types.IsPointers(y.Type()) {
		return nil, errutil.Newf("invalid y operand type; expected integer, integer vector, pointer or pointer vector, got %v", y.Type())
	}
	return &ICmp{cond: cond, x: x, y: y}, nil
}
Exemple #12
0
// implicitConversion implicitly converts the value of the smallest type to the
// largest type of x and y, emitting code to f. The new values of x and y are
// returned.
func (m *Module) implicitConversion(f *Function, x, y value.Value) (value.Value, value.Value) {
	// Implicit conversion.
	switch {
	case isLarger(x.Type(), y.Type()):
		y = m.convert(f, y, x.Type())
	case isLarger(y.Type(), x.Type()):
		x = m.convert(f, x, y.Type())
	}
	return x, y
}