Exemple #1
0
// NewCharArray returns a character array constant based on the given array type
// and string.
func NewCharArray(typ types.Type, s string) (*Array, error) {
	// Verify array type.
	v := new(Array)
	var ok bool
	v.typ, ok = typ.(*types.Array)
	if !ok {
		return nil, fmt.Errorf("invalid type %q for array constant", typ)
	}
	var err error
	s, err = unquote(s)
	if err != nil {
		return nil, errutil.Err(err)
	}

	// Verify array element types.
	if len(s) != v.typ.Len() {
		return nil, fmt.Errorf("incorrect number of elements in character array constant; expected %d, got %d", v.typ.Len(), len(s))
	}
	elemType := v.typ.Elem()
	if !types.Equal(elemType, types.I8) {
		return nil, fmt.Errorf("invalid character array element type; expected %q, got %q", types.I8, elemType)
	}
	for i := 0; i < len(s); i++ {
		elem, err := NewInt(elemType, strconv.Itoa(int(s[i])))
		if err != nil {
			return nil, errutil.Err(err)
		}
		v.elems = append(v.elems, elem)
	}

	return v, nil
}
Exemple #2
0
Fichier : irx.go Projet : llir/llvm
// NewGetElementPtrInst returns a new getelementptr instruction based on the
// given element type, address and element indices.
func NewGetElementPtrInst(elem, srcAddrType, srcAddr, elemIndices interface{}) (*instruction.GetElementPtr, error) {
	if elem, ok := elem.(types.Type); ok {
		srcAddr, err := NewValue(srcAddrType, srcAddr)
		if err != nil {
			return nil, errutil.Err(err)
		}
		var indices []value.Value
		switch elemIndices := elemIndices.(type) {
		case []value.Value:
			indices = elemIndices
		case nil:
		default:
			panic(fmt.Sprintf("support for element indices type %T not yet implemented", elemIndices))
		}
		// Validate that elem is of identical type as the element type of srcAddr.
		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(elem, srcAddrType.Elem()) {
			return nil, errutil.Newf("type mismatch between element type (%v) and source address element type (%v)", elem, srcAddrType.Elem())
		}
		return instruction.NewGetElementPtr(srcAddr, indices)
	}
	return nil, errutil.Newf("invalid operand type; expected types.Type, got %T", elem)
}
Exemple #3
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 #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
// 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)
}
Exemple #7
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 #8
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 #9
0
// NewPHI returns a new phi instruction based on the given incoming values.
//
// Pre-condition: incs is non-empty and each incoming value is of identical
// type.
func NewPHI(incs []*Incoming) (*PHI, error) {
	// Validate that incs is non-empty.
	if len(incs) < 1 {
		return nil, errutil.Newf("invalid number of incoming values; expected > 0, got %d", len(incs))
	}
	// Validate that each incoming value is of identical type.
	a := incs[0].val.Type()
	for i := 1; i < len(incs); i++ {
		b := incs[i].val.Type()
		if !types.Equal(a, b) {
			return nil, errutil.Newf("type mismatch between incoming value 0 (%v) and %d (%v)", a, i, b)
		}
	}
	return &PHI{incs: incs}, nil
}
Exemple #10
0
Fichier : irx.go Projet : 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)
}
Exemple #11
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 #12
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 #13
0
func TestEqual(t *testing.T) {
	golden := []struct {
		want bool
		a, b types.Type
	}{
		{want: true, a: voidTyp, b: voidTyp},
		{want: true, a: i1Typ, b: i1Typ},
		{want: true, a: i8Typ, b: i8Typ},
		{want: true, a: i32Typ, b: i32Typ},
		{want: true, a: f16Typ, b: f16Typ},
		{want: true, a: f32Typ, b: f32Typ},
		{want: true, a: f64Typ, b: f64Typ},
		{want: true, a: f128Typ, b: f128Typ},
		{want: true, a: f80_x86Typ, b: f80_x86Typ},
		{want: true, a: f128_ppcTyp, b: f128_ppcTyp},
		{want: true, a: mmxTyp, b: mmxTyp},
		{want: true, a: labelTyp, b: labelTyp},
		{want: true, a: metadataTyp, b: metadataTyp},
		{want: true, a: voidFuncTyp, b: voidFuncTyp},
		{want: true, a: i32FuncTyp, b: i32FuncTyp},
		{want: true, a: voidFunci32Typ, b: voidFunci32Typ},
		{want: true, a: voidFuncf32Typ, b: voidFuncf32Typ},
		{want: true, a: voidFunci32EllipsisTyp, b: voidFunci32EllipsisTyp},
		{want: true, a: funcTyp, b: funcTyp},
		{want: true, a: i8PtrTyp, b: i8PtrTyp},
		{want: true, a: f16PtrTyp, b: f16PtrTyp},
		{want: true, a: mmxPtrTyp, b: mmxPtrTyp},
		{want: true, a: funcPtrTyp, b: funcPtrTyp},
		{want: true, a: i8x1VecTyp, b: i8x1VecTyp},
		{want: true, a: i32x2VecTyp, b: i32x2VecTyp},
		{want: true, a: f16x3VecTyp, b: f16x3VecTyp},
		{want: true, a: f32x4VecTyp, b: f32x4VecTyp},
		{want: true, a: f64x5VecTyp, b: f64x5VecTyp},
		{want: true, a: f128x6VecTyp, b: f128x6VecTyp},
		{want: true, a: f80_x86x7VecTyp, b: f80_x86x7VecTyp},
		{want: true, a: f128_ppcx8VecTyp, b: f128_ppcx8VecTyp},
		{want: true, a: i8Ptrx9VecTyp, b: i8Ptrx9VecTyp},
		{want: true, a: f16Ptrx10VecTyp, b: f16Ptrx10VecTyp},
		{want: true, a: i8x1ArrTyp, b: i8x1ArrTyp},
		{want: true, a: i32x2ArrTyp, b: i32x2ArrTyp},
		{want: true, a: f16x3ArrTyp, b: f16x3ArrTyp},
		{want: true, a: f32x4ArrTyp, b: f32x4ArrTyp},
		{want: true, a: f64x5ArrTyp, b: f64x5ArrTyp},
		{want: true, a: f128x6ArrTyp, b: f128x6ArrTyp},
		{want: true, a: f80_x86x7ArrTyp, b: f80_x86x7ArrTyp},
		{want: true, a: f128_ppcx8ArrTyp, b: f128_ppcx8ArrTyp},
		{want: true, a: i8Ptrx9ArrTyp, b: i8Ptrx9ArrTyp},
		{want: true, a: f16Ptrx10ArrTyp, b: f16Ptrx10ArrTyp},
		{want: true, a: i32i8structTyp, b: i32i8structTyp},
		{want: true, a: i32i32structTyp, b: i32i32structTyp},
		{want: true, a: i32i8i8structTyp, b: i32i8i8structTyp},
		{want: true, a: structTyp, b: structTyp},
		{want: false, a: voidTyp, b: structTyp},
		{want: false, a: i1Typ, b: voidTyp},
		{want: false, a: i8Typ, b: i1Typ},
		{want: false, a: i32Typ, b: i8Typ},
		{want: false, a: f16Typ, b: i32Typ},
		{want: false, a: f32Typ, b: f16Typ},
		{want: false, a: f64Typ, b: f32Typ},
		{want: false, a: f128Typ, b: f64Typ},
		{want: false, a: f80_x86Typ, b: f128Typ},
		{want: false, a: f128_ppcTyp, b: f80_x86Typ},
		{want: false, a: mmxTyp, b: f128_ppcTyp},
		{want: false, a: labelTyp, b: mmxTyp},
		{want: false, a: metadataTyp, b: labelTyp},
		{want: false, a: voidFuncTyp, b: i32FuncTyp},
		{want: false, a: voidFuncTyp, b: voidFunci32Typ},
		{want: false, a: voidFunci32Typ, b: voidFuncf32Typ},
		{want: false, a: voidFunci32Typ, b: voidFunci32EllipsisTyp},
		{want: false, a: funcTyp, b: metadataTyp},
		{want: false, a: i8PtrTyp, b: funcTyp},
		{want: false, a: f16PtrTyp, b: i8PtrTyp},
		{want: false, a: mmxPtrTyp, b: f16PtrTyp},
		{want: false, a: funcPtrTyp, b: mmxPtrTyp},
		{want: false, a: i8x1VecTyp, b: funcPtrTyp},
		{want: false, a: i32x2VecTyp, b: i8x1VecTyp},
		{want: false, a: f16x3VecTyp, b: i32x2VecTyp},
		{want: false, a: f32x4VecTyp, b: f16x3VecTyp},
		{want: false, a: f64x5VecTyp, b: f32x4VecTyp},
		{want: false, a: f128x6VecTyp, b: f64x5VecTyp},
		{want: false, a: f80_x86x7VecTyp, b: f128x6VecTyp},
		{want: false, a: f128_ppcx8VecTyp, b: f80_x86x7VecTyp},
		{want: false, a: i8Ptrx9VecTyp, b: f128_ppcx8VecTyp},
		{want: false, a: f16Ptrx10VecTyp, b: i8Ptrx9VecTyp},
		{want: false, a: i8x1ArrTyp, b: f16Ptrx10VecTyp},
		{want: false, a: i32x2ArrTyp, b: i8x1ArrTyp},
		{want: false, a: f16x3ArrTyp, b: i32x2ArrTyp},
		{want: false, a: f32x4ArrTyp, b: f16x3ArrTyp},
		{want: false, a: f64x5ArrTyp, b: f32x4ArrTyp},
		{want: false, a: f128x6ArrTyp, b: f64x5ArrTyp},
		{want: false, a: f80_x86x7ArrTyp, b: f128x6ArrTyp},
		{want: false, a: f128_ppcx8ArrTyp, b: f80_x86x7ArrTyp},
		{want: false, a: i8Ptrx9ArrTyp, b: f128_ppcx8ArrTyp},
		{want: false, a: f16Ptrx10ArrTyp, b: i8Ptrx9ArrTyp},
		{want: false, a: i32i8structTyp, b: i32i8i8structTyp},
		{want: false, a: i32i8structTyp, b: i32i32structTyp},
		{want: false, a: structTyp, b: f16Ptrx10ArrTyp},
	}

	for i, g := range golden {
		got := types.Equal(g.a, g.b)
		if got != g.want {
			t.Errorf("i=%d: expected %v, got %v", i, g.want, got)
		}
	}
}