Example #1
0
func (v ConstValue) Convert(dst_typ types.Type) Value {
	// Get the underlying type, if any.
	if name, isname := dst_typ.(*types.Name); isname {
		dst_typ = types.Underlying(name)
	}

	if !types.Identical(v.typ, dst_typ) {
		// Get the Basic type.
		isBasic := false
		if name, isname := types.Underlying(dst_typ).(*types.Name); isname {
			_, isBasic = name.Underlying.(*types.Basic)
		}

		compiler := v.compiler
		if isBasic {
			return ConstValue{*v.Const.Convert(&dst_typ), compiler, dst_typ}
		} else {
			return compiler.NewLLVMValue(v.LLVMValue(), v.Type()).Convert(dst_typ)
			//panic(fmt.Errorf("unhandled conversion from %v to %v", v.typ, dst_typ))
		}
	} else {
		// TODO convert to dst type. ConstValue may need to change to allow
		// storage of types other than Basic.
	}
	return v
}
Example #2
0
File: value.go Project: spate/llgo
func (v *LLVMValue) UnaryOp(op token.Token) Value {
	b := v.compiler.builder
	switch op {
	case token.SUB:
		var value llvm.Value
		isfp := types.Identical(types.Underlying(v.typ), types.Float32) ||
			types.Identical(types.Underlying(v.typ), types.Float64)
		if isfp {
			zero := llvm.ConstNull(v.compiler.types.ToLLVM(v.Type()))
			value = b.CreateFSub(zero, v.LLVMValue(), "")
		} else {
			value = b.CreateNeg(v.LLVMValue(), "")
		}
		return v.compiler.NewLLVMValue(value, v.typ)
	case token.ADD:
		return v // No-op
	case token.AND:
		return v.pointer
	case token.NOT:
		value := b.CreateNot(v.LLVMValue(), "")
		return v.compiler.NewLLVMValue(value, v.typ)
	case token.XOR:
		lhs := v.LLVMValue()
		rhs := llvm.ConstAllOnes(lhs.Type())
		value := b.CreateXor(lhs, rhs, "")
		return v.compiler.NewLLVMValue(value, v.typ)
	default:
		panic("Unhandled operator: ") // + expr.Op)
	}
	panic("unreachable")
}
Example #3
0
func (c *compiler) VisitSliceExpr(expr *ast.SliceExpr) Value {
	// expr.X, expr.Low, expr.High
	value := c.VisitExpr(expr.X)
	var low, high llvm.Value
	if expr.Low != nil {
		low = c.VisitExpr(expr.Low).Convert(types.Int32).LLVMValue()
	} else {
		low = llvm.ConstNull(llvm.Int32Type())
	}
	if expr.High != nil {
		high = c.VisitExpr(expr.High).Convert(types.Int32).LLVMValue()
	} else {
		high = llvm.ConstAllOnes(llvm.Int32Type()) // -1
	}

	if _, ok := types.Underlying(value.Type()).(*types.Pointer); ok {
		value = value.(*LLVMValue).makePointee()
	}

	switch typ := types.Underlying(value.Type()).(type) {
	case *types.Array:
		sliceslice := c.NamedFunction("runtime.sliceslice", "func f(t uintptr, s slice, low, high int32) slice")
		i8slice := sliceslice.Type().ElementType().ReturnType()
		sliceValue := llvm.Undef(i8slice) // temporary slice
		arrayptr := value.(*LLVMValue).pointer.LLVMValue()
		arrayptr = c.builder.CreateBitCast(arrayptr, i8slice.StructElementTypes()[0], "")
		arraylen := llvm.ConstInt(llvm.Int32Type(), typ.Len, false)
		sliceValue = c.builder.CreateInsertValue(sliceValue, arrayptr, 0, "")
		sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 1, "")
		sliceValue = c.builder.CreateInsertValue(sliceValue, arraylen, 2, "")
		sliceTyp := &types.Slice{Elt: typ.Elt}
		runtimeTyp := c.types.ToRuntime(sliceTyp)
		runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "")
		args := []llvm.Value{runtimeTyp, sliceValue, low, high}
		result := c.builder.CreateCall(sliceslice, args, "")
		llvmSliceTyp := c.types.ToLLVM(sliceTyp)
		return c.NewLLVMValue(c.coerceSlice(result, llvmSliceTyp), sliceTyp)
	case *types.Slice:
		sliceslice := c.NamedFunction("runtime.sliceslice", "func f(t uintptr, s slice, low, high int32) slice")
		i8slice := sliceslice.Type().ElementType().ReturnType()
		sliceValue := value.LLVMValue()
		sliceTyp := sliceValue.Type()
		sliceValue = c.coerceSlice(sliceValue, i8slice)
		runtimeTyp := c.types.ToRuntime(value.Type())
		runtimeTyp = c.builder.CreatePtrToInt(runtimeTyp, c.target.IntPtrType(), "")
		args := []llvm.Value{runtimeTyp, sliceValue, low, high}
		result := c.builder.CreateCall(sliceslice, args, "")
		return c.NewLLVMValue(c.coerceSlice(result, sliceTyp), value.Type())
	case *types.Name: // String
		stringslice := c.NamedFunction("runtime.stringslice", "func f(a string, low, high int32) string")
		args := []llvm.Value{value.LLVMValue(), low, high}
		result := c.builder.CreateCall(stringslice, args, "")
		return c.NewLLVMValue(result, value.Type())
	default:
		panic("unimplemented")
	}
	panic("unreachable")
}
Example #4
0
func (c *compiler) VisitLen(expr *ast.CallExpr) Value {
	if len(expr.Args) > 1 {
		panic("Expecting only one argument to len")
	}

	value := c.VisitExpr(expr.Args[0])
	typ := value.Type()
	if name, ok := types.Underlying(typ).(*types.Name); ok {
		typ = name.Underlying
	}

	switch typ := types.Underlying(typ).(type) {
	case *types.Pointer:
		// XXX Converting to a string to be converted back to an int is
		// silly. The values need an overhaul? Perhaps have types based
		// on fundamental types, with the additional methods to make
		// them llgo.Value's.
		if a, isarray := typ.Base.(*types.Array); isarray {
			return c.NewConstValue(token.INT,
				strconv.FormatUint(a.Len, 10))
		}
		v := strconv.FormatUint(uint64(unsafe.Sizeof(uintptr(0))), 10)
		return c.NewConstValue(token.INT, v)

	case *types.Slice:
		sliceval := value.LLVMValue()
		lenval := c.builder.CreateExtractValue(sliceval, 1, "")
		return c.NewLLVMValue(lenval, types.Int32).Convert(types.Int)

	case *types.Map:
		mapval := value.LLVMValue()
		f := c.NamedFunction("runtime.maplen", "func f(m uintptr) int")
		lenval := c.builder.CreateCall(f, []llvm.Value{mapval}, "")
		return c.NewLLVMValue(lenval, types.Int)

	case *types.Array:
		v := strconv.FormatUint(typ.Len, 10)
		return c.NewConstValue(token.INT, v)

	case *types.Basic:
		if typ == types.String.Underlying {
			switch value := value.(type) {
			case *LLVMValue:
				ptr := value.pointer
				len_field := c.builder.CreateStructGEP(ptr.LLVMValue(), 1, "")
				len_value := c.builder.CreateLoad(len_field, "")
				return c.NewLLVMValue(len_value, types.Int32).Convert(types.Int)
			case ConstValue:
				s := value.Val.(string)
				n := uint64(len(s))
				return c.NewConstValue(token.INT, strconv.FormatUint(n, 10))
			}
		}
	}
	panic(fmt.Sprint("Unhandled value type: ", value.Type()))
}
Example #5
0
File: expr.go Project: kisielk/llgo
func (c *compiler) VisitIndexExpr(expr *ast.IndexExpr) Value {
	value := c.VisitExpr(expr.X)
	index := c.VisitExpr(expr.Index)

	typ := types.Underlying(value.Type())
	if typ == types.String {
		ptr := c.builder.CreateExtractValue(value.LLVMValue(), 0, "")
		gepindices := []llvm.Value{index.LLVMValue()}
		ptr = c.builder.CreateGEP(ptr, gepindices, "")
		result := c.NewLLVMValue(ptr, &types.Pointer{Base: types.Byte})
		return result.makePointee()
	}

	// We can index a pointer to an array.
	if _, ok := typ.(*types.Pointer); ok {
		value = value.(*LLVMValue).makePointee()
		typ = value.Type()
	}

	switch typ := types.Underlying(typ).(type) {
	case *types.Array:
		index := index.LLVMValue()
		var ptr llvm.Value
		value := value.(*LLVMValue)
		if value.pointer != nil {
			ptr = value.pointer.LLVMValue()
		} else {
			init := value.LLVMValue()
			ptr = c.builder.CreateAlloca(init.Type(), "")
			c.builder.CreateStore(init, ptr)
		}
		zero := llvm.ConstNull(llvm.Int32Type())
		element := c.builder.CreateGEP(ptr, []llvm.Value{zero, index}, "")
		result := c.NewLLVMValue(element, &types.Pointer{Base: typ.Elt})
		return result.makePointee()

	case *types.Slice:
		index := index.LLVMValue()
		ptr := c.builder.CreateExtractValue(value.LLVMValue(), 0, "")
		element := c.builder.CreateGEP(ptr, []llvm.Value{index}, "")
		result := c.NewLLVMValue(element, &types.Pointer{Base: typ.Elt})
		return result.makePointee()

	case *types.Map:
		value, _ = c.mapLookup(value.(*LLVMValue), index, false)
		return value
	}
	panic(fmt.Sprintf("unreachable (%s)", typ))
}
Example #6
0
func (c *compiler) VisitMake(expr *ast.CallExpr) Value {
	typ := c.types.expr[expr]
	switch utyp := types.Underlying(typ).(type) {
	case *types.Slice:
		var length, capacity Value
		switch len(expr.Args) {
		case 3:
			capacity = c.VisitExpr(expr.Args[2])
			fallthrough
		case 2:
			length = c.VisitExpr(expr.Args[1])
		}
		slice := c.makeSlice(utyp.Elt, length, capacity)
		return c.NewLLVMValue(slice, typ)
	case *types.Chan:
		f := c.NamedFunction("runtime.makechan", "func f(t uintptr, cap uint32) uintptr")
		dyntyp := c.types.ToRuntime(typ)
		dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "")
		var cap_ llvm.Value
		if len(expr.Args) > 1 {
			cap_ = c.VisitExpr(expr.Args[1]).LLVMValue()
		}
		args := []llvm.Value{dyntyp, cap_}
		ptr := c.builder.CreateCall(f, args, "")
		return c.NewLLVMValue(ptr, typ)
	case *types.Map:
		f := c.NamedFunction("runtime.makemap", "func f(t uintptr) uintptr")
		dyntyp := c.types.ToRuntime(typ)
		dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "")
		mapval := c.builder.CreateCall(f, []llvm.Value{dyntyp}, "")
		return c.NewLLVMValue(mapval, typ)
	}
	panic(fmt.Sprintf("unhandled type: %s", typ))
}
Example #7
0
File: stmt.go Project: kisielk/llgo
// destructureExpr evaluates the right-hand side of a
// multiple assignment where the right-hand side is a single expression.
func (c *compiler) destructureExpr(x ast.Expr) []Value {
	var values []Value
	switch x := x.(type) {
	case *ast.IndexExpr:
		// value, ok := m[k]
		m := c.VisitExpr(x.X).(*LLVMValue)
		index := c.VisitExpr(x.Index)
		value, notnull := c.mapLookup(m, index, false)
		values = []Value{value, notnull}
	case *ast.CallExpr:
		value := c.VisitExpr(x)
		aggregate := value.LLVMValue()
		struct_type := value.Type().(*types.Struct)
		values = make([]Value, len(struct_type.Fields))
		for i, f := range struct_type.Fields {
			t := f.Type.(types.Type)
			value_ := c.builder.CreateExtractValue(aggregate, i, "")
			values[i] = c.NewLLVMValue(value_, t)
		}
	case *ast.TypeAssertExpr:
		lhs := c.VisitExpr(x.X).(*LLVMValue)
		typ := c.types.expr[x]
		switch typ := types.Underlying(typ).(type) {
		case *types.Interface:
			value, ok := lhs.convertI2I(typ)
			values = []Value{value, ok}
		default:
			value, ok := lhs.convertI2V(typ)
			values = []Value{value, ok}
		}
	}
	return values
}
Example #8
0
File: expr.go Project: spate/llgo
func (c *compiler) VisitIndexExpr(expr *ast.IndexExpr) Value {
	value := c.VisitExpr(expr.X).(*LLVMValue)
	index := c.VisitExpr(expr.Index)

	typ := value.Type()
	if typ == types.String {
		ptr := c.builder.CreateExtractValue(value.LLVMValue(), 0, "")
		gepindices := []llvm.Value{index.LLVMValue()}
		ptr = c.builder.CreateGEP(ptr, gepindices, "")
		result := c.NewLLVMValue(ptr, &types.Pointer{Base: types.Byte})
		return result.makePointee()
	}

	// We can index a pointer to an array.
	if _, ok := types.Underlying(typ).(*types.Pointer); ok {
		value = value.makePointee()
		typ = value.Type()
	}

	switch types.Underlying(typ).(type) {
	case *types.Array, *types.Slice:
		var gep_indices []llvm.Value
		var ptr llvm.Value
		var result_type types.Type
		switch typ := types.Underlying(typ).(type) {
		case *types.Array:
			// FIXME what to do if value is not addressable?
			// Do we have to load the array onto the stack?
			result_type = typ.Elt
			ptr = value.pointer.LLVMValue()
			gep_indices = append(gep_indices, llvm.ConstNull(llvm.Int32Type()))
		case *types.Slice:
			result_type = typ.Elt
			ptr = c.builder.CreateExtractValue(value.LLVMValue(), 0, "")
		}

		gep_indices = append(gep_indices, index.LLVMValue())
		element := c.builder.CreateGEP(ptr, gep_indices, "")
		result := c.NewLLVMValue(element, &types.Pointer{Base: result_type})
		return result.makePointee()

	case *types.Map:
		value, _ = c.mapLookup(value, index, false)
		return value
	}
	panic(fmt.Sprintf("unreachable (%s)", typ))
}
Example #9
0
File: value.go Project: spate/llgo
func (v ConstValue) LLVMValue() llvm.Value {
	typ := types.Underlying(v.Type())
	switch typ {
	case types.Int, types.Uint:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true)
		// TODO 32/64bit (probably wait for gc)
		//int_val := v.Val.(*big.Int)
		//if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 {
		//	panic(fmt.Sprint("const ", int_val, " overflows int"))
		//}
		//return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true)
	case types.Uint:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false)

	case types.Int8:
		return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true)
	case types.Uint8, types.Byte:
		return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false)

	case types.Int16:
		return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true)
	case types.Uint16:
		return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false)

	case types.Int32, types.Rune:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true)
	case types.Uint32:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false)

	case types.Int64:
		return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true)
	case types.Uint64:
		return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true)

	case types.Float32:
		return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64()))
	case types.Float64:
		return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64()))

	case types.UnsafePointer, types.Uintptr:
		inttype := v.compiler.target.IntPtrType()
		return llvm.ConstInt(inttype, uint64(v.Int64()), false)

	case types.String:
		strval := (v.Val).(string)
		ptr := v.compiler.builder.CreateGlobalStringPtr(strval, "")
		len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(strval)), false)
		return llvm.ConstStruct([]llvm.Value{ptr, len_}, false)

	case types.Bool:
		if v := v.Val.(bool); v {
			return llvm.ConstAllOnes(llvm.Int1Type())
		}
		return llvm.ConstNull(llvm.Int1Type())
	}
	panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind))
}
Example #10
0
func (v *LLVMValue) chanRecv() *LLVMValue {
	c := v.compiler
	elttyp := types.Underlying(v.typ).(*types.Chan).Elt
	ptr := c.builder.CreateAlloca(c.types.ToLLVM(elttyp), "")
	uintptr_ := c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "")
	f := c.NamedFunction("runtime.chanrecv", "func f(c, ptr uintptr)")
	c.builder.CreateCall(f, []llvm.Value{v.LLVMValue(), uintptr_}, "")
	value := c.builder.CreateLoad(ptr, "")
	return c.NewLLVMValue(value, elttyp)
}
Example #11
0
// convertI2I converts an interface to another interface.
func (v *LLVMValue) convertI2I(iface *types.Interface) (result Value, success Value) {
	c := v.compiler
	builder := v.compiler.builder
	src_typ := types.Underlying(v.Type())
	vptr := v.pointer.LLVMValue()

	zero_iface_struct := llvm.ConstNull(c.types.ToLLVM(iface))
	iface_struct := zero_iface_struct
	dynamicType := builder.CreateLoad(builder.CreateStructGEP(vptr, 0, ""), "")
	receiver := builder.CreateLoad(builder.CreateStructGEP(vptr, 1, ""), "")

	// TODO check whether the functions in the struct take
	// value or pointer receivers.

	// TODO handle dynamic interface conversion (non-subset).
	methods := src_typ.(*types.Interface).Methods
	for i, m := range iface.Methods {
		// TODO make this loop linear by iterating through the
		// interface methods and type methods together.
		mi := sort.Search(len(methods), func(i int) bool {
			return methods[i].Name >= m.Name
		})
		if mi >= len(methods) || methods[mi].Name != m.Name {
			//panic("Failed to locate method: " + m.Name)
			goto check_dynamic
		} else {
			method := builder.CreateStructGEP(vptr, mi+2, "")
			fptr := builder.CreateLoad(method, "")
			iface_struct = builder.CreateInsertValue(iface_struct, fptr, i+2, "")
		}
	}
	iface_struct = builder.CreateInsertValue(iface_struct, dynamicType, 0, "")
	iface_struct = builder.CreateInsertValue(iface_struct, receiver, 1, "")
	result = c.NewLLVMValue(iface_struct, iface)
	success = ConstValue{types.Const{true}, c, types.Bool}
	return result, success

check_dynamic:
	runtimeConvertI2I := c.NamedFunction("runtime.convertI2I", "func f(typ, from, to uintptr) bool")
	llvmUintptr := runtimeConvertI2I.Type().ElementType().ParamTypes()[0]

	runtimeType := c.builder.CreatePtrToInt(c.types.ToRuntime(iface), llvmUintptr, "")
	from := c.builder.CreatePtrToInt(vptr, llvmUintptr, "")
	to := c.builder.CreateAlloca(iface_struct.Type(), "")
	c.builder.CreateStore(iface_struct, to)
	toUintptr := c.builder.CreatePtrToInt(to, llvmUintptr, "")
	args := []llvm.Value{runtimeType, from, toUintptr}
	ok := c.builder.CreateCall(runtimeConvertI2I, args, "")

	value := c.builder.CreateLoad(to, "")
	value = c.builder.CreateSelect(ok, value, zero_iface_struct, "")
	result = c.NewLLVMValue(value, iface)
	success = c.NewLLVMValue(ok, types.Bool)
	return result, success
}
Example #12
0
func (c *compiler) VisitTypeSpec(spec *ast.TypeSpec) {
	obj := spec.Name.Obj
	type_, istype := (obj.Type).(types.Type)
	if !istype {
		type_ = c.GetType(spec.Type)
		if name, isname := type_.(*types.Name); isname {
			type_ = types.Underlying(name)
		}
		obj.Type = &types.Name{Underlying: type_, Obj: obj}
	}
}
Example #13
0
func (tm *TypeMap) ToLLVM(t types.Type) llvm.Type {
	t = types.Underlying(t)
	lt, ok := tm.types[t]
	if !ok {
		lt = tm.makeLLVMType(t)
		if lt.IsNil() {
			panic(fmt.Sprint("Failed to create LLVM type for: ", t))
		}
		tm.types[t] = lt
	}
	return lt
}
Example #14
0
func (tm *TypeMap) ToRuntime(t types.Type) llvm.Value {
	t = types.Underlying(t)
	r, ok := tm.runtime[t]
	if !ok {
		_, r = tm.makeRuntimeType(t)
		if r.IsNil() {
			panic(fmt.Sprint("Failed to create runtime type for: ", t))
		}
		tm.runtime[t] = r
	}
	return r
}
Example #15
0
File: value.go Project: spate/llgo
func (v ConstValue) Convert(dstTyp types.Type) Value {
	// Get the underlying type, if any.
	origDstTyp := dstTyp
	dstTyp = types.Underlying(dstTyp)

	if !types.Identical(v.typ, dstTyp) {
		isBasic := false
		if name, isname := types.Underlying(dstTyp).(*types.Name); isname {
			_, isBasic = name.Underlying.(*types.Basic)
		}

		compiler := v.compiler
		if isBasic {
			return ConstValue{v.Const.Convert(&dstTyp), compiler, origDstTyp}
		} else {
			return compiler.NewLLVMValue(v.LLVMValue(), v.Type()).Convert(origDstTyp)
			//panic(fmt.Errorf("unhandled conversion from %v to %v", v.typ, dstTyp))
		}
	} else {
		v.typ = origDstTyp
	}
	return v
}
Example #16
0
func (v *LLVMValue) chanSend(value Value) {
	var ptr llvm.Value
	if value, ok := value.(*LLVMValue); ok && value.pointer != nil {
		ptr = value.pointer.LLVMValue()
	}
	elttyp := types.Underlying(v.typ).(*types.Chan).Elt
	c := v.compiler
	if ptr.IsNil() {
		ptr = c.builder.CreateAlloca(c.types.ToLLVM(elttyp), "")
		value := value.Convert(elttyp).LLVMValue()
		c.builder.CreateStore(value, ptr)
	}
	uintptr_ := c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "")
	f := c.NamedFunction("runtime.chansend", "func f(c, ptr uintptr)")
	c.builder.CreateCall(f, []llvm.Value{v.LLVMValue(), uintptr_}, "")
}
Example #17
0
File: make.go Project: spate/llgo
func (c *compiler) VisitMake(expr *ast.CallExpr) Value {
	typ := c.GetType(expr.Args[0])
	switch utyp := types.Underlying(typ).(type) {
	case *types.Slice:
		var length, capacity Value
		switch len(expr.Args) {
		case 3:
			capacity = c.VisitExpr(expr.Args[2])
			fallthrough
		case 2:
			length = c.VisitExpr(expr.Args[1])
		}
		slice := c.makeSlice(utyp.Elt, length, capacity)
		return c.NewLLVMValue(slice, typ)
	}
	// TODO map, chan
	return c.NewLLVMValue(llvm.ConstNull(c.types.ToLLVM(typ)), typ)
}
Example #18
0
// loadI2V loads an interface value to a type, without checking
// that the interface type matches.
func (v *LLVMValue) loadI2V(typ types.Type) Value {
	c := v.compiler
	if c.Sizeof(typ) > c.target.PointerSize() {
		ptr := c.builder.CreateExtractValue(v.LLVMValue(), 1, "")
		typ = &types.Pointer{Base: typ}
		ptr = c.builder.CreateBitCast(ptr, c.types.ToLLVM(typ), "")
		return c.NewLLVMValue(ptr, typ).makePointee()
	}

	value := c.builder.CreateExtractValue(v.LLVMValue(), 1, "")
	if _, ok := types.Underlying(typ).(*types.Pointer); ok {
		value = c.builder.CreateBitCast(value, c.types.ToLLVM(typ), "")
		return c.NewLLVMValue(value, typ)
	}
	bits := c.target.TypeSizeInBits(c.types.ToLLVM(typ))
	value = c.builder.CreatePtrToInt(value, llvm.IntType(int(bits)), "")
	value = c.coerce(value, c.types.ToLLVM(typ))
	return c.NewLLVMValue(value, typ)
}
Example #19
0
File: value.go Project: spate/llgo
func (v *LLVMValue) Convert(dst_typ types.Type) Value {
	// If it's a stack allocated value, we'll want to compare the
	// value type, not the pointer type.
	src_typ := v.typ

	// Get the underlying type, if any.
	orig_dst_typ := dst_typ
	if name, isname := dst_typ.(*types.Name); isname {
		dst_typ = types.Underlying(name)
	}

	// Get the underlying type, if any.
	if name, isname := src_typ.(*types.Name); isname {
		src_typ = types.Underlying(name)
	}

	// Identical (underlying) types? Just swap in the destination type.
	if types.Identical(src_typ, dst_typ) {
		dst_typ = orig_dst_typ
		// TODO avoid load here by reusing pointer value, if exists.
		return v.compiler.NewLLVMValue(v.LLVMValue(), dst_typ)
	}

	// Convert from an interface type.
	if _, isinterface := src_typ.(*types.Interface); isinterface {
		if interface_, isinterface := dst_typ.(*types.Interface); isinterface {
			return v.convertI2I(interface_)
		} else {
			return v.convertI2V(dst_typ)
		}
	}

	// Converting to an interface type.
	if interface_, isinterface := dst_typ.(*types.Interface); isinterface {
		return v.convertV2I(interface_)
	}

	// string -> []byte
	byteslice := &types.Slice{Elt: types.Byte}
	if src_typ == types.String && types.Identical(dst_typ, byteslice) {
		c := v.compiler
		value := v.LLVMValue()
		strdata := c.builder.CreateExtractValue(value, 0, "")
		strlen := c.builder.CreateExtractValue(value, 1, "")
		struct_ := llvm.Undef(c.types.ToLLVM(byteslice))
		struct_ = c.builder.CreateInsertValue(struct_, strdata, 0, "")
		struct_ = c.builder.CreateInsertValue(struct_, strlen, 1, "")
		struct_ = c.builder.CreateInsertValue(struct_, strlen, 2, "")
		return c.NewLLVMValue(struct_, byteslice)
	}
	// []byte -> string
	if types.Identical(src_typ, byteslice) && dst_typ == types.String {
		c := v.compiler
		value := v.LLVMValue()
		data := c.builder.CreateExtractValue(value, 0, "")
		len := c.builder.CreateExtractValue(value, 1, "")
		struct_ := llvm.Undef(c.types.ToLLVM(types.String))
		struct_ = c.builder.CreateInsertValue(struct_, data, 0, "")
		struct_ = c.builder.CreateInsertValue(struct_, len, 1, "")
		return c.NewLLVMValue(struct_, types.String)
	}

	// TODO other special conversions, e.g. int->string.
	llvm_type := v.compiler.types.ToLLVM(dst_typ)

	// Unsafe pointer conversions.
	if dst_typ == types.UnsafePointer { // X -> unsafe.Pointer
		if _, isptr := src_typ.(*types.Pointer); isptr {
			value := v.compiler.builder.CreatePtrToInt(v.LLVMValue(), llvm_type, "")
			return v.compiler.NewLLVMValue(value, dst_typ)
		} else if src_typ == types.Uintptr {
			return v.compiler.NewLLVMValue(v.LLVMValue(), dst_typ)
		}
	} else if src_typ == types.UnsafePointer { // unsafe.Pointer -> X
		if _, isptr := dst_typ.(*types.Pointer); isptr {
			value := v.compiler.builder.CreateIntToPtr(v.LLVMValue(), llvm_type, "")
			return v.compiler.NewLLVMValue(value, dst_typ)
		} else if dst_typ == types.Uintptr {
			return v.compiler.NewLLVMValue(v.LLVMValue(), dst_typ)
		}
	}

	// FIXME select the appropriate cast here, depending on size, type (int/float)
	// and sign.
	lv := v.LLVMValue()
	srcType := lv.Type()
	switch srcType.TypeKind() { // source type
	case llvm.IntegerTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.IntegerTypeKind:
			srcBits := srcType.IntTypeWidth()
			dstBits := llvm_type.IntTypeWidth()
			delta := srcBits - dstBits
			switch {
			case delta < 0:
				// TODO check if (un)signed, use S/ZExt accordingly.
				lv = v.compiler.builder.CreateZExt(lv, llvm_type, "")
			case delta > 0:
				lv = v.compiler.builder.CreateTrunc(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, dst_typ)
		}
	case llvm.DoubleTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.FloatTypeKind:
			lv = v.compiler.builder.CreateFPTrunc(lv, llvm_type, "")
			return v.compiler.NewLLVMValue(lv, dst_typ)
		}
	case llvm.FloatTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.DoubleTypeKind:
			lv = v.compiler.builder.CreateFPExt(lv, llvm_type, "")
			return v.compiler.NewLLVMValue(lv, dst_typ)
		}
	}
	//bitcast_value := v.compiler.builder.CreateBitCast(lv, llvm_type, "")

	/*
	   value_type := value.Type()
	   switch value_type.TypeKind() {
	   case llvm.IntegerTypeKind:
	       switch totype.TypeKind() {
	       case llvm.IntegerTypeKind:
	           //delta := value_type.IntTypeWidth() - totype.IntTypeWidth()
	           //var
	           switch {
	           case delta == 0: return value
	           // TODO handle signed/unsigned (SExt/ZExt)
	           case delta < 0: return c.compiler.builder.CreateZExt(value, totype, "")
	           case delta > 0: return c.compiler.builder.CreateTrunc(value, totype, "")
	           }
	           return LLVMValue{lhs.compiler.builder, value}
	       }
	   }
	*/
	panic(fmt.Sprint("unimplemented conversion: ", v.typ, " -> ", orig_dst_typ))
}
Example #20
0
func (c *compiler) VisitCompositeLit(lit *ast.CompositeLit) Value {
	typ := c.types.expr[lit]
	var valuemap map[interface{}]Value
	var valuelist []Value
	_, isstruct := types.Underlying(typ).(*types.Struct)
	if lit.Elts != nil {
		for _, elt := range lit.Elts {
			var value Value
			if kv, iskv := elt.(*ast.KeyValueExpr); iskv {
				value = c.VisitExpr(kv.Value)
				if valuemap == nil {
					valuemap = make(map[interface{}]Value)
				}
				var key interface{}
				if isstruct {
					key = kv.Key.(*ast.Ident).Name
				} else {
					key = c.VisitExpr(kv.Key)
				}
				valuemap[key] = value
			} else {
				value = c.VisitExpr(elt)
				valuelist = append(valuelist, value)
			}
		}
	}

	// For array/slice types, convert key:value to contiguous
	// values initialiser.
	switch types.Underlying(typ).(type) {
	case *types.Array, *types.Slice:
		if len(valuemap) > 0 {
			maxi := int64(-1)
			for key, _ := range valuemap {
				i := key.(ConstValue).Int64()
				if i < 0 {
					panic("array index must be non-negative integer constant")
				} else if i > maxi {
					maxi = i
				}
			}
			valuelist = make([]Value, maxi+1)
			for key, value := range valuemap {
				i := key.(ConstValue).Int64()
				valuelist[i] = value
			}
		}
	}

	origtyp := typ
	switch typ := types.Underlying(typ).(type) {
	case *types.Array:
		elttype := typ.Elt
		llvmelttype := c.types.ToLLVM(elttype)
		llvmvalues := make([]llvm.Value, typ.Len)
		for i := range llvmvalues {
			var value Value
			if i < len(valuelist) {
				value = valuelist[i]
			}
			if value == nil {
				llvmvalues[i] = llvm.ConstNull(llvmelttype)
			} else if _, ok := value.(ConstValue); ok || value.LLVMValue().IsConstant() {
				llvmvalues[i] = value.Convert(elttype).LLVMValue()
			} else {
				llvmvalues[i] = llvm.Undef(llvmelttype)
			}
		}
		array := llvm.ConstArray(llvmelttype, llvmvalues)
		for i, value := range valuelist {
			if llvmvalues[i].IsUndef() {
				value := value.Convert(elttype).LLVMValue()
				array = c.builder.CreateInsertValue(array, value, i, "")
			}
		}
		return c.NewLLVMValue(array, origtyp)

	case *types.Slice:
		ptr := c.createTypeMalloc(c.types.ToLLVM(typ))

		eltType := c.types.ToLLVM(typ.Elt)
		arrayType := llvm.ArrayType(eltType, len(valuelist))
		valuesPtr := c.createMalloc(llvm.SizeOf(arrayType))
		valuesPtr = c.builder.CreateIntToPtr(valuesPtr, llvm.PointerType(eltType, 0), "")

		//valuesPtr = c.builder.CreateBitCast(valuesPtr, llvm.PointerType(valuesPtr.Type(), 0), "")
		// TODO check result of mallocs
		length := llvm.ConstInt(llvm.Int32Type(), uint64(len(valuelist)), false)
		c.builder.CreateStore(valuesPtr, c.builder.CreateStructGEP(ptr, 0, "")) // data
		c.builder.CreateStore(length, c.builder.CreateStructGEP(ptr, 1, ""))    // len
		c.builder.CreateStore(length, c.builder.CreateStructGEP(ptr, 2, ""))    // cap
		null := llvm.ConstNull(c.types.ToLLVM(typ.Elt))
		for i, value := range valuelist {
			index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false)
			valuePtr := c.builder.CreateGEP(valuesPtr, []llvm.Value{index}, "")
			if value == nil {
				c.builder.CreateStore(null, valuePtr)
			} else {
				c.builder.CreateStore(value.Convert(typ.Elt).LLVMValue(), valuePtr)
			}
		}
		m := c.NewLLVMValue(ptr, &types.Pointer{Base: origtyp})
		return m.makePointee()

	case *types.Struct:
		values := valuelist
		llvmtyp := c.types.ToLLVM(typ)
		ptr := c.createTypeMalloc(llvmtyp)

		bzero := c.NamedFunction("runtime.bzero", "func f(unsafe.Pointer, uintptr)")
		ptrintval := c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "")
		args := []llvm.Value{ptrintval, llvm.SizeOf(llvmtyp)}
		c.builder.CreateCall(bzero, args, "")

		if valuemap != nil {
			for key, value := range valuemap {
				fieldName := key.(string)
				index := typ.FieldIndices[fieldName]
				for len(values) <= int(index) {
					values = append(values, nil)
				}
				values[index] = value
			}
		}
		for i, value := range values {
			if value != nil {
				elttype := typ.Fields[i].Type.(types.Type)
				llvm_value := value.Convert(elttype).LLVMValue()
				ptr := c.builder.CreateStructGEP(ptr, i, "")
				c.builder.CreateStore(llvm_value, ptr)
			}
		}
		m := c.NewLLVMValue(ptr, &types.Pointer{Base: origtyp})
		return m.makePointee()

	case *types.Map:
		value := llvm.ConstNull(c.types.ToLLVM(typ))
		// TODO initialise map
		return c.NewLLVMValue(value, origtyp)
	}
	panic(fmt.Sprint("Unhandled type kind: ", typ))
}
Example #21
0
File: expr.go Project: kisielk/llgo
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value {
	lhs := c.VisitExpr(expr.X)
	if lhs == nil {
		// The only time we should get a nil result is if the object is
		// a package.
		obj := expr.Sel.Obj
		if obj.Kind == ast.Typ {
			return TypeValue{obj.Type.(types.Type)}
		}
		return c.Resolve(obj)
	}

	// Method expression. Returns an unbound function pointer.
	// FIXME this is just the most basic case. It's also possible to
	// create a pointer-receiver function from a method that has a
	// value receiver (see Method Expressions in spec).
	name := expr.Sel.Name
	if _, ok := lhs.(TypeValue); ok {
		methodobj := expr.Sel.Obj
		value := c.Resolve(methodobj).(*LLVMValue)
		ftyp := value.typ.(*types.Func)
		methodParams := make(types.ObjList, len(ftyp.Params)+1)
		methodParams[0] = ftyp.Recv
		copy(methodParams[1:], ftyp.Params)
		ftyp = &types.Func{
			Recv:       nil,
			Params:     methodParams,
			Results:    ftyp.Results,
			IsVariadic: ftyp.IsVariadic,
		}
		return c.NewLLVMValue(value.value, ftyp)
	}

	// TODO(?) record path to field/method during typechecking, so we don't
	// have to search again here.

	if iface, ok := types.Underlying(lhs.Type()).(*types.Interface); ok {
		i := sort.Search(len(iface.Methods), func(i int) bool {
			return iface.Methods[i].Name >= name
		})
		structValue := lhs.LLVMValue()
		receiver := c.builder.CreateExtractValue(structValue, 1, "")
		f := c.builder.CreateExtractValue(structValue, i+2, "")
		i8ptr := &types.Pointer{Base: types.Int8}
		ftype := iface.Methods[i].Type.(*types.Func)
		ftype.Recv = ast.NewObj(ast.Var, "")
		ftype.Recv.Type = i8ptr
		f = c.builder.CreateBitCast(f, c.types.ToLLVM(ftype), "")
		ftype.Recv = nil
		method := c.NewLLVMValue(f, ftype)
		method.receiver = c.NewLLVMValue(receiver, i8ptr)
		return method
	}

	// Search through embedded types for field/method.
	var result selectorCandidate
	curr := []selectorCandidate{{nil, lhs.Type()}}
	for result.Type == nil && len(curr) > 0 {
		var next []selectorCandidate
		for _, candidate := range curr {
			indices := candidate.Indices[0:]
			t := candidate.Type

			if p, ok := types.Underlying(t).(*types.Pointer); ok {
				if _, ok := types.Underlying(p.Base).(*types.Struct); ok {
					t = p.Base
				}
			}

			if n, ok := t.(*types.Name); ok {
				i := sort.Search(len(n.Methods), func(i int) bool {
					return n.Methods[i].Name >= name
				})
				if i < len(n.Methods) && n.Methods[i].Name == name {
					result.Indices = indices
					result.Type = t
				}
			}

			if t, ok := types.Underlying(t).(*types.Struct); ok {
				if i, ok := t.FieldIndices[name]; ok {
					result.Indices = append(indices, int(i))
					result.Type = t
				} else {
					// Add embedded types to the next set of types
					// to check.
					for i, field := range t.Fields {
						if field.Name == "" {
							indices = append(indices[0:], i)
							t := field.Type.(types.Type)
							candidate := selectorCandidate{indices, t}
							next = append(next, candidate)
						}
					}
				}
			}
		}
		curr = next
	}

	// Get a pointer to the field/receiver.
	recvValue := lhs.(*LLVMValue)
	if len(result.Indices) > 0 {
		if _, ok := types.Underlying(lhs.Type()).(*types.Pointer); !ok {
			recvValue = recvValue.pointer
			//recvValue = c.NewLLVMValue(recvValue.LLVMValue(), recvValue.Type())
		}
		for _, v := range result.Indices {
			ptr := recvValue.LLVMValue()
			field := types.Underlying(types.Deref(recvValue.typ)).(*types.Struct).Fields[v]
			fieldPtr := c.builder.CreateStructGEP(ptr, v, "")
			fieldPtrTyp := &types.Pointer{Base: field.Type.(types.Type)}
			recvValue = c.NewLLVMValue(fieldPtr, fieldPtrTyp)

			// GEP returns a pointer; if the field is a pointer,
			// we must load our pointer-to-a-pointer.
			if _, ok := field.Type.(*types.Pointer); ok {
				recvValue = recvValue.makePointee()
			}
		}
	}

	// Method?
	if expr.Sel.Obj.Kind == ast.Fun {
		method := c.Resolve(expr.Sel.Obj).(*LLVMValue)
		methodType := expr.Sel.Obj.Type.(*types.Func)
		receiverType := methodType.Recv.Type.(types.Type)
		if types.Identical(recvValue.Type(), receiverType) {
			method.receiver = recvValue
		} else if types.Identical(&types.Pointer{Base: recvValue.Type()}, receiverType) {
			method.receiver = recvValue.pointer
		} else {
			method.receiver = recvValue.makePointee()
		}
		return method
	} else {
		resultType := expr.Sel.Obj.Type.(types.Type)
		if types.Identical(recvValue.Type(), resultType) {
			// no-op
		} else if types.Identical(&types.Pointer{Base: recvValue.Type()}, resultType) {
			recvValue = recvValue.pointer
		} else {
			recvValue = recvValue.makePointee()
		}
		return recvValue
	}
	panic("unreachable")
}
Example #22
0
func (v *LLVMValue) Convert(dst_typ types.Type) Value {
	b := v.compiler.builder

	// If it's a stack allocated value, we'll want to compare the
	// value type, not the pointer type.
	src_typ := v.typ

	// Get the underlying type, if any.
	orig_dst_typ := dst_typ
	dst_typ = types.Underlying(dst_typ)
	src_typ = types.Underlying(src_typ)

	// Identical (underlying) types? Just swap in the destination type.
	if types.Identical(src_typ, dst_typ) {
		// TODO avoid load here by reusing pointer value, if exists.
		return v.compiler.NewLLVMValue(v.LLVMValue(), orig_dst_typ)
	}

	// Both pointer types with identical underlying types? Same as above.
	if src_typ, ok := src_typ.(*types.Pointer); ok {
		if dst_typ, ok := dst_typ.(*types.Pointer); ok {
			src_typ := types.Underlying(src_typ.Base)
			dst_typ := types.Underlying(dst_typ.Base)
			if types.Identical(src_typ, dst_typ) {
				return v.compiler.NewLLVMValue(v.LLVMValue(), orig_dst_typ)
			}
		}
	}

	// Convert from an interface type.
	if _, isinterface := src_typ.(*types.Interface); isinterface {
		if interface_, isinterface := dst_typ.(*types.Interface); isinterface {
			result, _ := v.convertI2I(interface_)
			return result
		} else {
			result, _ := v.convertI2V(orig_dst_typ)
			return result
		}
	}

	// Converting to an interface type.
	if interface_, isinterface := dst_typ.(*types.Interface); isinterface {
		return v.convertV2I(interface_)
	}

	// string -> []byte
	byteslice := &types.Slice{Elt: types.Byte}
	if src_typ == types.String && types.Identical(dst_typ, byteslice) {
		c := v.compiler
		value := v.LLVMValue()
		strdata := c.builder.CreateExtractValue(value, 0, "")
		strlen := c.builder.CreateExtractValue(value, 1, "")
		struct_ := llvm.Undef(c.types.ToLLVM(byteslice))
		struct_ = c.builder.CreateInsertValue(struct_, strdata, 0, "")
		struct_ = c.builder.CreateInsertValue(struct_, strlen, 1, "")
		struct_ = c.builder.CreateInsertValue(struct_, strlen, 2, "")
		return c.NewLLVMValue(struct_, byteslice)
	}

	// []byte -> string
	if types.Identical(src_typ, byteslice) && dst_typ == types.String {
		c := v.compiler
		value := v.LLVMValue()
		data := c.builder.CreateExtractValue(value, 0, "")
		len := c.builder.CreateExtractValue(value, 1, "")
		struct_ := llvm.Undef(c.types.ToLLVM(types.String))
		struct_ = c.builder.CreateInsertValue(struct_, data, 0, "")
		struct_ = c.builder.CreateInsertValue(struct_, len, 1, "")
		return c.NewLLVMValue(struct_, types.String)
	}

	// Rune to string conversion.
	if dst_typ == types.String && isIntType(src_typ) {
		return v.runeToString()
	}

	// TODO other special conversions?
	llvm_type := v.compiler.types.ToLLVM(dst_typ)

	// Unsafe pointer conversions.
	if dst_typ == types.UnsafePointer { // X -> unsafe.Pointer
		if _, isptr := src_typ.(*types.Pointer); isptr {
			value := b.CreatePtrToInt(v.LLVMValue(), llvm_type, "")
			return v.compiler.NewLLVMValue(value, orig_dst_typ)
		} else if src_typ == types.Uintptr {
			return v.compiler.NewLLVMValue(v.LLVMValue(), orig_dst_typ)
		}
	} else if src_typ == types.UnsafePointer { // unsafe.Pointer -> X
		if _, isptr := dst_typ.(*types.Pointer); isptr {
			value := b.CreateIntToPtr(v.LLVMValue(), llvm_type, "")
			return v.compiler.NewLLVMValue(value, orig_dst_typ)
		} else if dst_typ == types.Uintptr {
			return v.compiler.NewLLVMValue(v.LLVMValue(), orig_dst_typ)
		}
	}

	// FIXME select the appropriate cast here, depending on size, type (int/float)
	// and sign.
	lv := v.LLVMValue()
	srcType := lv.Type()
	switch srcType.TypeKind() { // source type
	case llvm.IntegerTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.IntegerTypeKind:
			srcBits := srcType.IntTypeWidth()
			dstBits := llvm_type.IntTypeWidth()
			delta := srcBits - dstBits
			switch {
			case delta < 0:
				// TODO check if (un)signed, use S/ZExt accordingly.
				lv = b.CreateZExt(lv, llvm_type, "")
			case delta > 0:
				lv = b.CreateTrunc(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		case llvm.FloatTypeKind, llvm.DoubleTypeKind:
			if signed(v.Type()) {
				lv = b.CreateSIToFP(lv, llvm_type, "")
			} else {
				lv = b.CreateUIToFP(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		}
	case llvm.DoubleTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.FloatTypeKind:
			lv = b.CreateFPTrunc(lv, llvm_type, "")
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		case llvm.IntegerTypeKind:
			if signed(dst_typ) {
				lv = b.CreateFPToSI(lv, llvm_type, "")
			} else {
				lv = b.CreateFPToUI(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		}
	case llvm.FloatTypeKind:
		switch llvm_type.TypeKind() {
		case llvm.DoubleTypeKind:
			lv = b.CreateFPExt(lv, llvm_type, "")
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		case llvm.IntegerTypeKind:
			if signed(dst_typ) {
				lv = b.CreateFPToSI(lv, llvm_type, "")
			} else {
				lv = b.CreateFPToUI(lv, llvm_type, "")
			}
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		}
	}

	// Complex -> complex. Complexes are only convertible to other
	// complexes, contant conversions aside. So we can just check the
	// source type here; given that the types are not identical
	// (checked above), we can assume the destination type is the alternate
	// complex type.
	if src_typ == types.Complex64 || src_typ == types.Complex128 {
		var fpcast func(llvm.Builder, llvm.Value, llvm.Type, string) llvm.Value
		var fptype llvm.Type
		if src_typ == types.Complex64 {
			fpcast = llvm.Builder.CreateFPExt
			fptype = llvm.DoubleType()
		} else {
			fpcast = llvm.Builder.CreateFPTrunc
			fptype = llvm.FloatType()
		}
		if fpcast != nil {
			realv := b.CreateExtractValue(lv, 0, "")
			imagv := b.CreateExtractValue(lv, 1, "")
			realv = fpcast(b, realv, fptype, "")
			imagv = fpcast(b, imagv, fptype, "")
			lv = llvm.Undef(v.compiler.types.ToLLVM(dst_typ))
			lv = b.CreateInsertValue(lv, realv, 0, "")
			lv = b.CreateInsertValue(lv, imagv, 1, "")
			return v.compiler.NewLLVMValue(lv, orig_dst_typ)
		}
	}

	panic(fmt.Sprint("unimplemented conversion: ", v.typ, " -> ", orig_dst_typ))
}
Example #23
0
File: expr.go Project: kisielk/llgo
func (c *compiler) VisitCallExpr(expr *ast.CallExpr) Value {
	switch x := (expr.Fun).(type) {
	case *ast.Ident:
		switch x.String() {
		case "copy":
			// TODO
			zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
			return c.NewLLVMValue(zero, types.Int)
		case "print":
			return c.VisitPrint(expr, false)
		case "println":
			return c.VisitPrint(expr, true)
		case "cap":
			return c.VisitCap(expr)
		case "len":
			return c.VisitLen(expr)
		case "new":
			return c.VisitNew(expr)
		case "make":
			return c.VisitMake(expr)
		case "append":
			return c.VisitAppend(expr)
		case "delete":
			m := c.VisitExpr(expr.Args[0]).(*LLVMValue)
			key := c.VisitExpr(expr.Args[1])
			c.mapDelete(m, key)
			return nil
		case "panic":
			var arg Value
			if len(expr.Args) > 0 {
				arg = c.VisitExpr(expr.Args[0])
			}
			c.visitPanic(arg)
			return nil
		case "recover":
			return c.visitRecover()
		case "real":
			cmplx := c.VisitExpr(expr.Args[0]).(*LLVMValue)
			return cmplx.extractComplexComponent(0)
		case "imag":
			cmplx := c.VisitExpr(expr.Args[0]).(*LLVMValue)
			return cmplx.extractComplexComponent(1)
		case "complex":
			r := c.VisitExpr(expr.Args[0]).LLVMValue()
			i := c.VisitExpr(expr.Args[1]).LLVMValue()
			typ := c.types.expr[expr]
			cmplx := llvm.Undef(c.types.ToLLVM(typ))
			cmplx = c.builder.CreateInsertValue(cmplx, r, 0, "")
			cmplx = c.builder.CreateInsertValue(cmplx, i, 1, "")
			return c.NewLLVMValue(cmplx, typ)
		}

	case *ast.SelectorExpr:
		// Handle unsafe functions specially.
		if pkgobj, ok := x.X.(*ast.Ident); ok && pkgobj.Obj.Data == types.Unsafe.Data {
			var value int
			switch x.Sel.Name {
			case "Alignof":
				argtype := c.types.expr[expr.Args[0]]
				value = c.alignofType(argtype)
				value := c.NewConstValue(token.INT, strconv.Itoa(value))
				value.typ = types.Uintptr
				return value
			case "Sizeof":
				argtype := c.types.expr[expr.Args[0]]
				value = c.sizeofType(argtype)
				value := c.NewConstValue(token.INT, strconv.Itoa(value))
				value.typ = types.Uintptr
				return value
			case "Offsetof":
				// FIXME this should be constant, but I'm lazy, and this ought
				// to be done when we're doing constant folding anyway.
				lhs := expr.Args[0].(*ast.SelectorExpr).X
				baseaddr := c.VisitExpr(lhs).(*LLVMValue).pointer.LLVMValue()
				addr := c.VisitExpr(expr.Args[0]).(*LLVMValue).pointer.LLVMValue()
				baseaddr = c.builder.CreatePtrToInt(baseaddr, c.target.IntPtrType(), "")
				addr = c.builder.CreatePtrToInt(addr, c.target.IntPtrType(), "")
				diff := c.builder.CreateSub(addr, baseaddr, "")
				return c.NewLLVMValue(diff, types.Uintptr)
			}
		}
	}

	// Is it a type conversion?
	if len(expr.Args) == 1 && isType(expr.Fun) {
		typ := c.types.expr[expr]
		value := c.VisitExpr(expr.Args[0])
		return value.Convert(typ)
	}

	// Not a type conversion, so must be a function call.
	lhs := c.VisitExpr(expr.Fun)
	fn := lhs.(*LLVMValue)
	fn_type := types.Underlying(fn.Type()).(*types.Func)
	args := make([]llvm.Value, 0)
	if fn.receiver != nil {
		// Don't dereference the receiver here. It'll have been worked out in
		// the selector.
		receiver := fn.receiver
		args = append(args, receiver.LLVMValue())
	}
	if nparams := len(fn_type.Params); nparams > 0 {
		if fn_type.IsVariadic {
			nparams--
		}
		for i := 0; i < nparams; i++ {
			value := c.VisitExpr(expr.Args[i])
			param_type := fn_type.Params[i].Type.(types.Type)
			args = append(args, value.Convert(param_type).LLVMValue())
		}
		if fn_type.IsVariadic {
			param_type := fn_type.Params[nparams].Type.(*types.Slice).Elt
			varargs := make([]llvm.Value, 0)
			for i := nparams; i < len(expr.Args); i++ {
				value := c.VisitExpr(expr.Args[i])
				value = value.Convert(param_type)
				varargs = append(varargs, value.LLVMValue())
			}
			slice_value := c.makeLiteralSlice(varargs, param_type)
			args = append(args, slice_value)
		}
	}

	var result_type types.Type
	switch len(fn_type.Results) {
	case 0: // no-op
	case 1:
		result_type = fn_type.Results[0].Type.(types.Type)
	default:
		fields := make([]*ast.Object, len(fn_type.Results))
		for i, result := range fn_type.Results {
			fields[i] = result
		}
		result_type = &types.Struct{Fields: fields}
	}

	// After calling the function, we must bitcast to the computed LLVM
	// type. This is a no-op, and exists just to satisfy LLVM's type
	// comparisons.
	result := c.builder.CreateCall(fn.LLVMValue(), args, "")
	if len(fn_type.Results) == 1 {
		result = c.builder.CreateBitCast(result, c.types.ToLLVM(result_type), "")
	}
	return c.NewLLVMValue(result, result_type)
}
Example #24
0
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value {
	lhs := c.VisitExpr(expr.X)
	if lhs == nil {
		// The only time we should get a nil result is if the object is
		// a package.
		obj := expr.Sel.Obj
		if obj.Kind == ast.Typ {
			return TypeValue{obj.Type.(types.Type)}
		}
		return c.Resolve(obj)
	}

	// TODO(?) record path to field/method during typechecking, so we don't
	// have to search again here.

	name := expr.Sel.Name
	if iface, ok := types.Underlying(lhs.Type()).(*types.Interface); ok {
		// validity checked during typechecking.
		i := sort.Search(len(iface.Methods), func(i int) bool {
			return iface.Methods[i].Name >= name
		})
		struct_value := lhs.LLVMValue()
		receiver_value := c.builder.CreateStructGEP(struct_value, 0, "")
		fn_value := c.builder.CreateStructGEP(struct_value, i+2, "")
		method_type := c.ObjGetType(iface.Methods[i]).(*types.Func)
		method := c.NewLLVMValue(
			c.builder.CreateBitCast(
				c.builder.CreateLoad(fn_value, ""),
				c.types.ToLLVM(method_type), ""), method_type)
		method.receiver = c.NewLLVMValue(
			c.builder.CreateLoad(receiver_value, ""),
			method_type.Recv.Type.(types.Type))
		return method
	}

	// Search through embedded types for field/method.
	var result selectorCandidate
	curr := []selectorCandidate{{nil, lhs.Type()}}
	for result.Type == nil && len(curr) > 0 {
		var next []selectorCandidate
		for _, candidate := range curr {
			indices := candidate.Indices[0:]
			t := candidate.Type

			if p, ok := types.Underlying(t).(*types.Pointer); ok {
				if _, ok := types.Underlying(p.Base).(*types.Struct); ok {
					indices = append(indices, 0)
					t = p.Base
				}
			}

			if n, ok := t.(*types.Name); ok {
				i := sort.Search(len(n.Methods), func(i int) bool {
					return n.Methods[i].Name >= name
				})
				if i < len(n.Methods) && n.Methods[i].Name == name {
					result.Indices = indices
					result.Type = t
				}
			}

			if t, ok := types.Underlying(t).(*types.Struct); ok {
				if i, ok := t.FieldIndices[name]; ok {
					result.Indices = append(indices, i)
					result.Type = t
				} else {
					// Add embedded types to the next set of types
					// to check.
					for i, field := range t.Fields {
						if field.Name == "" {
							indices = append(indices[0:], uint64(i))
							t := field.Type.(types.Type)
							candidate := selectorCandidate{indices, t}
							next = append(next, candidate)
						}
					}
				}
			}
		}
		curr = next
	}

	// Get a pointer to the field/struct for field/method invocation.
	indices := make([]llvm.Value, len(result.Indices))
	for i, v := range result.Indices {
		indices[i] = llvm.ConstInt(llvm.Int32Type(), v, false)
	}

	// Method?
	if expr.Sel.Obj.Kind == ast.Fun {
		method := c.Resolve(expr.Sel.Obj).(*LLVMValue)
		methodType := expr.Sel.Obj.Type.(*types.Func)
		receiverType := methodType.Recv.Type.(types.Type)
		if len(indices) > 0 {
			receiverValue := c.builder.CreateGEP(lhs.LLVMValue(), indices, "")
			if types.Identical(result.Type, receiverType) {
				receiverValue = c.builder.CreateLoad(receiverValue, "")
			}
			method.receiver = c.NewLLVMValue(receiverValue, receiverType)
		} else {
			lhs := lhs.(*LLVMValue)
			if types.Identical(result.Type, receiverType) {
				method.receiver = lhs
			} else if types.Identical(result.Type, &types.Pointer{Base: receiverType}) {
				method.receiver = lhs.makePointee()
			} else if types.Identical(&types.Pointer{Base: result.Type}, receiverType) {
				method.receiver = lhs.pointer
			}
		}
		return method
	} else {
		var ptr llvm.Value
		if _, ok := types.Underlying(lhs.Type()).(*types.Pointer); ok {
			ptr = lhs.LLVMValue()
		} else {
			if lhs, ok := lhs.(*LLVMValue); ok && lhs.pointer != nil {
				ptr = lhs.pointer.LLVMValue()
				zero := llvm.ConstNull(llvm.Int32Type())
				indices = append([]llvm.Value{zero}, indices...)
			} else {
				// TODO handle struct literal selectors.
				panic("selectors on struct literals unimplemented")
			}
		}
		fieldValue := c.builder.CreateGEP(ptr, indices, "")
		fieldType := &types.Pointer{Base: expr.Sel.Obj.Type.(types.Type)}
		return c.NewLLVMValue(fieldValue, fieldType).makePointee()
	}
	panic("unreachable")
}
Example #25
0
func (v ConstValue) LLVMValue() llvm.Value {
	typ := types.Underlying(v.Type())
	if name, ok := typ.(*types.Name); ok {
		typ = name.Underlying
	}

	switch typ.(*types.Basic).Kind {
	case types.IntKind, types.UintKind:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true)
		// TODO 32/64bit (probably wait for gc)
		//int_val := v.Val.(*big.Int)
		//if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 {
		//	panic(fmt.Sprint("const ", int_val, " overflows int"))
		//}
		//return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true)

	case types.Int8Kind:
		return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true)
	case types.Uint8Kind:
		return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false)

	case types.Int16Kind:
		return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true)
	case types.Uint16Kind:
		return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false)

	case types.Int32Kind:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true)
	case types.Uint32Kind:
		return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false)

	case types.Int64Kind:
		return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true)
	case types.Uint64Kind:
		return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), false)

	case types.Float32Kind:
		return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64()))
	case types.Float64Kind:
		return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64()))

	case types.Complex64Kind:
		r_, i_ := v.Complex()
		r := llvm.ConstFloat(llvm.FloatType(), r_)
		i := llvm.ConstFloat(llvm.FloatType(), i_)
		return llvm.ConstStruct([]llvm.Value{r, i}, false)
	case types.Complex128Kind:
		r_, i_ := v.Complex()
		r := llvm.ConstFloat(llvm.DoubleType(), r_)
		i := llvm.ConstFloat(llvm.DoubleType(), i_)
		return llvm.ConstStruct([]llvm.Value{r, i}, false)

	case types.UnsafePointerKind, types.UintptrKind:
		inttype := v.compiler.target.IntPtrType()
		return llvm.ConstInt(inttype, uint64(v.Int64()), false)

	case types.StringKind:
		strval := (v.Val).(string)
		strlen := len(strval)
		i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
		var ptr llvm.Value
		if strlen > 0 {
			ptr = v.compiler.builder.CreateGlobalStringPtr(strval, "")
			ptr = llvm.ConstBitCast(ptr, i8ptr)
		} else {
			ptr = llvm.ConstNull(i8ptr)
		}
		len_ := llvm.ConstInt(llvm.Int32Type(), uint64(strlen), false)
		return llvm.ConstStruct([]llvm.Value{ptr, len_}, false)

	case types.BoolKind:
		if v := v.Val.(bool); v {
			return llvm.ConstAllOnes(llvm.Int1Type())
		}
		return llvm.ConstNull(llvm.Int1Type())
	}
	panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind))
}
Example #26
0
File: stmt.go Project: kisielk/llgo
func (c *compiler) VisitRangeStmt(stmt *ast.RangeStmt) {
	currBlock := c.builder.GetInsertBlock()
	doneBlock := llvm.AddBasicBlock(currBlock.Parent(), "done")
	doneBlock.MoveAfter(currBlock)
	postBlock := llvm.InsertBasicBlock(doneBlock, "post")
	loopBlock := llvm.InsertBasicBlock(postBlock, "loop")
	condBlock := llvm.InsertBasicBlock(loopBlock, "cond")
	defer c.builder.SetInsertPointAtEnd(doneBlock)

	// Evaluate range expression first.
	x := c.VisitExpr(stmt.X)

	// If it's a pointer type, we'll first check that it's non-nil.
	typ := types.Underlying(x.Type())
	if _, ok := typ.(*types.Pointer); ok {
		ifBlock := llvm.InsertBasicBlock(doneBlock, "if")
		isnotnull := c.builder.CreateIsNotNull(x.LLVMValue(), "")
		c.builder.CreateCondBr(isnotnull, ifBlock, doneBlock)
		c.builder.SetInsertPointAtEnd(ifBlock)
	}

	// Is it a new var definition? Then allocate some memory on the stack.
	var keyType, valueType types.Type
	var keyPtr, valuePtr llvm.Value
	if stmt.Tok == token.DEFINE {
		if key := stmt.Key.(*ast.Ident); key.Name != "_" {
			keyType = key.Obj.Type.(types.Type)
			keyPtr = c.builder.CreateAlloca(c.types.ToLLVM(keyType), "")
			key.Obj.Data = c.NewLLVMValue(keyPtr, &types.Pointer{Base: keyType}).makePointee()
		}
		if stmt.Value != nil {
			if value := stmt.Value.(*ast.Ident); value.Name != "_" {
				valueType = value.Obj.Type.(types.Type)
				valuePtr = c.builder.CreateAlloca(c.types.ToLLVM(valueType), "")
				value.Obj.Data = c.NewLLVMValue(valuePtr, &types.Pointer{Base: valueType}).makePointee()
			}
		}
	}

	c.breakblocks = append(c.breakblocks, doneBlock)
	c.continueblocks = append(c.continueblocks, postBlock)
	defer func() {
		c.breakblocks = c.breakblocks[:len(c.breakblocks)-1]
		c.continueblocks = c.continueblocks[:len(c.continueblocks)-1]
	}()

	isarray := false
	var base, length llvm.Value
	_, isptr := typ.(*types.Pointer)
	if isptr {
		typ = typ.(*types.Pointer).Base
	}
	switch typ := types.Underlying(typ).(type) {
	case *types.Map:
		goto maprange
	case *types.Name:
		stringvalue := x.LLVMValue()
		length = c.builder.CreateExtractValue(stringvalue, 1, "")
		goto stringrange
	case *types.Array:
		isarray = true
		x := x
		if !isptr {
			if x_, ok := x.(*LLVMValue); ok && x_.pointer != nil {
				x = x_.pointer
			} else {
				// TODO load value onto stack for indexing?
			}
		}
		base = x.LLVMValue()
		length = llvm.ConstInt(llvm.Int32Type(), typ.Len, false)
		goto arrayrange
	case *types.Slice:
		slicevalue := x.LLVMValue()
		base = c.builder.CreateExtractValue(slicevalue, 0, "")
		length = c.builder.CreateExtractValue(slicevalue, 1, "")
		goto arrayrange
	}

maprange:
	{
		currBlock = c.builder.GetInsertBlock()
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		nextptrphi := c.builder.CreatePHI(c.target.IntPtrType(), "next")
		nextptr, pk, pv := c.mapNext(x.(*LLVMValue), nextptrphi)
		notnull := c.builder.CreateIsNotNull(nextptr, "")
		c.builder.CreateCondBr(notnull, loopBlock, doneBlock)
		c.builder.SetInsertPointAtEnd(loopBlock)
		if !keyPtr.IsNil() {
			keyval := c.builder.CreateLoad(pk, "")
			c.builder.CreateStore(keyval, keyPtr)
		}
		if !valuePtr.IsNil() {
			valval := c.builder.CreateLoad(pv, "")
			c.builder.CreateStore(valval, valuePtr)
		}
		c.VisitBlockStmt(stmt.Body, false)
		c.maybeImplicitBranch(postBlock)
		c.builder.SetInsertPointAtEnd(postBlock)
		c.builder.CreateBr(condBlock)
		nextptrphi.AddIncoming([]llvm.Value{llvm.ConstNull(c.target.IntPtrType()), nextptr}, []llvm.BasicBlock{currBlock, postBlock})
		return
	}

stringrange:
	{
		zero := llvm.ConstNull(llvm.Int32Type())
		currBlock = c.builder.GetInsertBlock()
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		index := c.builder.CreatePHI(llvm.Int32Type(), "index")
		lessthan := c.builder.CreateICmp(llvm.IntULT, index, length, "")
		c.builder.CreateCondBr(lessthan, loopBlock, doneBlock)
		c.builder.SetInsertPointAtEnd(loopBlock)
		consumed, value := c.stringNext(x.LLVMValue(), index)
		if !keyPtr.IsNil() {
			c.builder.CreateStore(index, keyPtr)
		}
		if !valuePtr.IsNil() {
			c.builder.CreateStore(value, valuePtr)
		}
		c.VisitBlockStmt(stmt.Body, false)
		c.maybeImplicitBranch(postBlock)
		c.builder.SetInsertPointAtEnd(postBlock)
		newindex := c.builder.CreateAdd(index, consumed, "")
		c.builder.CreateBr(condBlock)
		index.AddIncoming([]llvm.Value{zero, newindex}, []llvm.BasicBlock{currBlock, postBlock})
		return
	}

arrayrange:
	{
		zero := llvm.ConstNull(llvm.Int32Type())
		currBlock = c.builder.GetInsertBlock()
		c.builder.CreateBr(condBlock)
		c.builder.SetInsertPointAtEnd(condBlock)
		index := c.builder.CreatePHI(llvm.Int32Type(), "index")
		lessthan := c.builder.CreateICmp(llvm.IntULT, index, length, "")
		c.builder.CreateCondBr(lessthan, loopBlock, doneBlock)
		c.builder.SetInsertPointAtEnd(loopBlock)
		if !keyPtr.IsNil() {
			c.builder.CreateStore(index, keyPtr)
		}
		if !valuePtr.IsNil() {
			var indices []llvm.Value
			if isarray {
				indices = []llvm.Value{zero, index}
			} else {
				indices = []llvm.Value{index}
			}
			elementptr := c.builder.CreateGEP(base, indices, "")
			element := c.builder.CreateLoad(elementptr, "")
			c.builder.CreateStore(element, valuePtr)
		}
		c.VisitBlockStmt(stmt.Body, false)
		c.maybeImplicitBranch(postBlock)
		c.builder.SetInsertPointAtEnd(postBlock)
		newindex := c.builder.CreateAdd(index, llvm.ConstInt(llvm.Int32Type(), 1, false), "")
		c.builder.CreateBr(condBlock)
		index.AddIncoming([]llvm.Value{zero, newindex}, []llvm.BasicBlock{currBlock, postBlock})
		return
	}
}
Example #27
0
File: expr.go Project: spate/llgo
func (c *compiler) VisitCallExpr(expr *ast.CallExpr) Value {
	switch x := (expr.Fun).(type) {
	case *ast.Ident:
		switch x.String() {
		case "print":
			return c.VisitPrint(expr, false)
		case "println":
			return c.VisitPrint(expr, true)
		case "len":
			return c.VisitLen(expr)
		case "new":
			return c.VisitNew(expr)
		case "make":
			return c.VisitMake(expr)
		case "append":
			return c.VisitAppend(expr)
		case "delete":
			m := c.VisitExpr(expr.Args[0]).(*LLVMValue)
			key := c.VisitExpr(expr.Args[1])
			c.mapDelete(m, key)
			return nil
		case "panic":
			// TODO
			return nil
		}

	case *ast.SelectorExpr:
		// Handle unsafe functions specially.
		if pkgobj, ok := x.X.(*ast.Ident); ok && pkgobj.Obj.Data == types.Unsafe.Data {
			var value int
			switch x.Sel.Name {
			case "Alignof", "Offsetof":
				panic("unimplemented")
			case "Sizeof":
				argtype := c.types.expr[expr.Args[0]]
				value = c.sizeofType(argtype)
				value := c.NewConstValue(token.INT, strconv.Itoa(value))
				value.typ = types.Uintptr
				return value
			}
		}
	}
	lhs := c.VisitExpr(expr.Fun)

	// Is it a type conversion?
	if len(expr.Args) == 1 {
		if _, ok := lhs.(TypeValue); ok {
			typ := lhs.Type()
			value := c.VisitExpr(expr.Args[0])
			return value.Convert(typ)
		}
	}

	// Not a type conversion, so must be a function call.
	fn := lhs.(*LLVMValue)
	fn_type := types.Underlying(fn.Type()).(*types.Func)
	args := make([]llvm.Value, 0)
	if fn_type.Recv != nil {
		// Don't dereference the receiver here. It'll have been worked out in
		// the selector.
		receiver := fn.receiver
		args = append(args, receiver.LLVMValue())
	}
	if nparams := len(fn_type.Params); nparams > 0 {
		if fn_type.IsVariadic {
			nparams--
		}
		for i := 0; i < nparams; i++ {
			value := c.VisitExpr(expr.Args[i])
			param_type := fn_type.Params[i].Type.(types.Type)
			args = append(args, value.Convert(param_type).LLVMValue())
		}
		if fn_type.IsVariadic {
			param_type := fn_type.Params[nparams].Type.(*types.Slice).Elt
			varargs := make([]llvm.Value, 0)
			for i := nparams; i < len(expr.Args); i++ {
				value := c.VisitExpr(expr.Args[i])
				value = value.Convert(param_type)
				varargs = append(varargs, value.LLVMValue())
			}
			slice_value := c.makeLiteralSlice(varargs, param_type)
			args = append(args, slice_value)
		}
	}

	var result_type types.Type
	switch len(fn_type.Results) {
	case 0: // no-op
	case 1:
		result_type = fn_type.Results[0].Type.(types.Type)
	default:
		fields := make([]*ast.Object, len(fn_type.Results))
		for i, result := range fn_type.Results {
			fields[i] = result
		}
		result_type = &types.Struct{Fields: fields}
	}

	// After calling the function, we must bitcast to the computed LLVM
	// type. This is a no-op, and exists just to satisfy LLVM's type
	// comparisons.
	result := c.builder.CreateCall(fn.LLVMValue(), args, "")
	if len(fn_type.Results) == 1 {
		result = c.builder.CreateBitCast(result, c.types.ToLLVM(result_type), "")
	}
	return c.NewLLVMValue(result, result_type)
}
Example #28
0
// convertV2I converts a value to an interface.
func (v *LLVMValue) convertV2I(iface *types.Interface) Value {
	// TODO deref indirect value, then use 'pointer' as pointer value.
	var srcname *types.Name
	srctyp := v.Type()
	if name, isname := srctyp.(*types.Name); isname {
		srcname = name
		srctyp = name.Underlying
	}

	if p, fromptr := srctyp.(*types.Pointer); fromptr {
		srctyp = p.Base
		if name, isname := srctyp.(*types.Name); isname {
			srcname = name
			srctyp = name.Underlying
		}
	}

	iface_struct_type := v.compiler.types.ToLLVM(iface)
	element_types := iface_struct_type.StructElementTypes()
	zero_iface_struct := llvm.ConstNull(iface_struct_type)
	iface_struct := zero_iface_struct

	builder := v.compiler.builder
	var ptr llvm.Value
	lv := v.LLVMValue()
	var overwide bool
	if lv.Type().TypeKind() == llvm.PointerTypeKind {
		ptr = builder.CreateBitCast(lv, element_types[1], "")
	} else {
		// If the value fits exactly in a pointer, then we can just
		// bitcast it. Otherwise we need to malloc, and create a shim
		// function to load the receiver.
		c := v.compiler
		ptrsize := c.target.PointerSize()
		if c.target.TypeStoreSize(lv.Type()) <= uint64(ptrsize) {
			bits := c.target.TypeSizeInBits(lv.Type())
			if bits > 0 {
				lv = c.coerce(lv, llvm.IntType(int(bits)))
				ptr = builder.CreateIntToPtr(lv, element_types[1], "")
			} else {
				ptr = llvm.ConstNull(element_types[1])
			}
		} else {
			ptr = c.createTypeMalloc(v.compiler.types.ToLLVM(srctyp))
			builder.CreateStore(lv, ptr)
			ptr = builder.CreateBitCast(ptr, element_types[1], "")
			overwide = true
		}
	}
	runtimeType := v.compiler.types.ToRuntime(v.Type())
	runtimeType = builder.CreateBitCast(runtimeType, element_types[0], "")
	iface_struct = builder.CreateInsertValue(iface_struct, runtimeType, 0, "")
	iface_struct = builder.CreateInsertValue(iface_struct, ptr, 1, "")

	// TODO assert either source is a named type (or pointer to), or the
	// interface has an empty methodset.

	if srcname != nil {
		// TODO check whether the functions in the struct take
		// value or pointer receivers.

		// Look up the method by name.
		// TODO check embedded types.
		for i, m := range iface.Methods {
			// TODO make this loop linear by iterating through the
			// interface methods and type methods together.
			var methodobj *ast.Object
			curr := []types.Type{srcname}
			for methodobj == nil && len(curr) > 0 {
				var next []types.Type
				for _, typ := range curr {
					if p, ok := types.Underlying(typ).(*types.Pointer); ok {
						if _, ok := types.Underlying(p.Base).(*types.Struct); ok {
							typ = p.Base
						}
					}
					if n, ok := typ.(*types.Name); ok {
						methods := n.Methods
						mi := sort.Search(len(methods), func(i int) bool {
							return methods[i].Name >= m.Name
						})
						if mi < len(methods) && methods[mi].Name == m.Name {
							methodobj = methods[mi]
							break
						}
					}
					if typ, ok := types.Underlying(typ).(*types.Struct); ok {
						for _, field := range typ.Fields {
							if field.Name == "" {
								typ := field.Type.(types.Type)
								next = append(next, typ)
							}
						}
					}
				}
				curr = next
			}
			if methodobj == nil {
				msg := fmt.Sprintf("Failed to locate (%s).%s", srcname.Obj.Name, m.Name)
				panic(msg)
			}
			method := v.compiler.Resolve(methodobj).(*LLVMValue)
			llvm_value := method.LLVMValue()

			// If we have a receiver wider than a word, or a pointer
			// receiver value and non-pointer receiver method, then
			// we must use the "wrapper" pointer method.
			fntyp := methodobj.Type.(*types.Func)
			recvtyp := fntyp.Recv.Type.(types.Type)
			needload := overwide
			if !needload {
				// TODO handle embedded types here.
				//needload = types.Identical(v.Type(), recvtyp)
				if p, ok := v.Type().(*types.Pointer); ok {
					needload = types.Identical(p.Base, recvtyp)
				}
			}
			if needload {
				ifname := fmt.Sprintf("*%s.%s", recvtyp, methodobj.Name)
				llvm_value = v.compiler.module.NamedFunction(ifname)
			}
			llvm_value = builder.CreateBitCast(llvm_value, element_types[i+2], "")
			iface_struct = builder.CreateInsertValue(iface_struct, llvm_value, i+2, "")
		}
	}

	return v.compiler.NewLLVMValue(iface_struct, iface)
}
Example #29
0
File: expr.go Project: spate/llgo
func (c *compiler) VisitSelectorExpr(expr *ast.SelectorExpr) Value {
	lhs := c.VisitExpr(expr.X)
	if lhs == nil {
		// The only time we should get a nil result is if the object is
		// a package.
		obj := expr.Sel.Obj
		if obj.Kind == ast.Typ {
			return TypeValue{obj.Type.(types.Type)}
		}
		return c.Resolve(obj)
	}

	// TODO(?) record path to field/method during typechecking, so we don't
	// have to search again here.

	name := expr.Sel.Name
	if iface, ok := types.Underlying(lhs.Type()).(*types.Interface); ok {
		i := sort.Search(len(iface.Methods), func(i int) bool {
			return iface.Methods[i].Name >= name
		})
		structValue := lhs.LLVMValue()
		receiver := c.builder.CreateExtractValue(structValue, 0, "")
		f := c.builder.CreateExtractValue(structValue, i+2, "")
		ftype := c.ObjGetType(iface.Methods[i]).(*types.Func)
		method := c.NewLLVMValue(c.builder.CreateBitCast(f, c.types.ToLLVM(ftype), ""), ftype)
		method.receiver = c.NewLLVMValue(receiver, ftype.Recv.Type.(types.Type))
		return method
	}

	// Search through embedded types for field/method.
	var result selectorCandidate
	curr := []selectorCandidate{{nil, lhs.Type()}}
	for result.Type == nil && len(curr) > 0 {
		var next []selectorCandidate
		for _, candidate := range curr {
			indices := candidate.Indices[0:]
			t := candidate.Type

			if p, ok := types.Underlying(t).(*types.Pointer); ok {
				if _, ok := types.Underlying(p.Base).(*types.Struct); ok {
					t = p.Base
				}
			}

			if n, ok := t.(*types.Name); ok {
				i := sort.Search(len(n.Methods), func(i int) bool {
					return n.Methods[i].Name >= name
				})
				if i < len(n.Methods) && n.Methods[i].Name == name {
					result.Indices = indices
					result.Type = t
				}
			}

			if t, ok := types.Underlying(t).(*types.Struct); ok {
				if i, ok := t.FieldIndices[name]; ok {
					result.Indices = append(indices, int(i))
					result.Type = t
				} else {
					// Add embedded types to the next set of types
					// to check.
					for i, field := range t.Fields {
						if field.Name == "" {
							indices = append(indices[0:], i)
							t := field.Type.(types.Type)
							candidate := selectorCandidate{indices, t}
							next = append(next, candidate)
						}
					}
				}
			}
		}
		curr = next
	}

	// Get a pointer to the field/receiver.
	recvValue := lhs.(*LLVMValue)
	if _, ok := types.Underlying(lhs.Type()).(*types.Pointer); !ok {
		recvValue = recvValue.pointer
	}
	recvValue = c.NewLLVMValue(recvValue.LLVMValue(), recvValue.Type())
	if len(result.Indices) > 0 {
		for _, v := range result.Indices {
			ptr := recvValue.LLVMValue()
			field := types.Underlying(types.Deref(recvValue.typ)).(*types.Struct).Fields[v]
			fieldPtr := c.builder.CreateStructGEP(ptr, v, "")
			fieldPtrTyp := &types.Pointer{Base: field.Type.(types.Type)}
			recvValue = c.NewLLVMValue(fieldPtr, fieldPtrTyp)

			// GEP returns a pointer; if the field is a pointer,
			// we must load our pointer-to-a-pointer.
			if _, ok := field.Type.(*types.Pointer); ok {
				recvValue = recvValue.makePointee()
			}
		}
	}
	if !types.Identical(recvValue.typ, expr.Sel.Obj.Type.(types.Type)) {
		recvValue = recvValue.makePointee()
	}

	// Method?
	if expr.Sel.Obj.Kind == ast.Fun {
		method := c.Resolve(expr.Sel.Obj).(*LLVMValue)
		methodType := expr.Sel.Obj.Type.(*types.Func)
		receiverType := methodType.Recv.Type.(types.Type)
		if types.Identical(recvValue.Type(), receiverType) {
			method.receiver = recvValue
		} else if types.Identical(&types.Pointer{Base: recvValue.Type()}, receiverType) {
			method.receiver = recvValue.pointer
		} else {
			method.receiver = recvValue.makePointee()
		}
		return method
	} else {
		return recvValue
	}
	panic("unreachable")
}
Example #30
0
File: value.go Project: spate/llgo
func (lhs *LLVMValue) BinaryOp(op token.Token, rhs_ Value) Value {
	if op == token.NEQ {
		result := lhs.BinaryOp(token.EQL, rhs_)
		return result.UnaryOp(token.NOT)
	}

	var result llvm.Value
	c := lhs.compiler
	b := lhs.compiler.builder

	// Later we can do better by treating constants specially. For now, let's
	// convert to LLVMValue's.
	var rhs *LLVMValue
	rhsisnil := false
	switch rhs_ := rhs_.(type) {
	case *LLVMValue:
		rhs = rhs_
	case NilValue:
		rhsisnil = true
		switch rhs_ := rhs_.Convert(lhs.Type()).(type) {
		case ConstValue:
			rhs = c.NewLLVMValue(rhs_.LLVMValue(), rhs_.Type())
		case *LLVMValue:
			rhs = rhs_
		}
	case ConstValue:
		value := rhs_.Convert(lhs.Type())
		rhs = c.NewLLVMValue(value.LLVMValue(), value.Type())
	}

	switch typ := types.Underlying(lhs.typ).(type) {
	case *types.Struct:
		// TODO check types are the same.
		element_types_count := lhs.LLVMValue().Type().StructElementTypesCount()
		struct_fields := typ.Fields
		if element_types_count > 0 {
			t := c.ObjGetType(struct_fields[0])
			first_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), t)
			first_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), 0, ""), t)
			first := first_lhs.BinaryOp(op, first_rhs)

			logical_op := token.LAND
			if op == token.NEQ {
				logical_op = token.LOR
			}

			result := first
			for i := 1; i < element_types_count; i++ {
				t := c.ObjGetType(struct_fields[i])
				next_lhs := c.NewLLVMValue(b.CreateExtractValue(lhs.LLVMValue(), i, ""), t)
				next_rhs := c.NewLLVMValue(b.CreateExtractValue(rhs.LLVMValue(), i, ""), t)
				next := next_lhs.BinaryOp(op, next_rhs)
				result = result.BinaryOp(logical_op, next)
			}
			return result
		}

	case *types.Interface:
		if rhsisnil {
			valueNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "")
			typeNull := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 1, ""), "")
			result := b.CreateAnd(typeNull, valueNull, "")
			return c.NewLLVMValue(result, types.Bool)
		}
		// TODO check for interface/interface comparison vs. interface/value comparison.
		return lhs.compareI2I(rhs)

	case *types.Slice:
		// []T == nil
		isnil := b.CreateIsNull(b.CreateExtractValue(lhs.LLVMValue(), 0, ""), "")
		return c.NewLLVMValue(isnil, types.Bool)
	}

	// Strings.
	if types.Underlying(lhs.typ) == types.String {
		if types.Underlying(rhs.typ) == types.String {
			switch op {
			case token.ADD:
				return c.concatenateStrings(lhs, rhs)
			case token.EQL, token.LSS, token.GTR, token.LEQ, token.GEQ:
				return c.compareStrings(lhs, rhs, op)
			default:
				panic(fmt.Sprint("Unimplemented operator: ", op))
			}
		}
		panic("unimplemented")
	}

	// Determine whether to use integer or floating point instructions.
	// TODO determine the NaN rules.
	isfp := types.Identical(types.Underlying(lhs.typ), types.Float32) ||
		types.Identical(types.Underlying(lhs.typ), types.Float64)

	switch op {
	case token.MUL:
		if isfp {
			result = b.CreateFMul(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateMul(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.QUO:
		if isfp {
			result = b.CreateFDiv(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateUDiv(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.REM:
		if isfp {
			result = b.CreateFRem(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateURem(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.ADD:
		if isfp {
			result = b.CreateFAdd(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateAdd(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.SUB:
		if isfp {
			result = b.CreateFSub(lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateSub(lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.SHL:
		rhs = rhs.Convert(lhs.Type()).(*LLVMValue)
		result = b.CreateShl(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.SHR:
		rhs = rhs.Convert(lhs.Type()).(*LLVMValue)
		result = b.CreateAShr(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.NEQ:
		if isfp {
			result = b.CreateFCmp(llvm.FloatONE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntNE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.EQL:
		if isfp {
			result = b.CreateFCmp(llvm.FloatOEQ, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntEQ, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.LSS:
		if isfp {
			result = b.CreateFCmp(llvm.FloatOLT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntULT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.LEQ: // TODO signed/unsigned
		if isfp {
			result = b.CreateFCmp(llvm.FloatOLE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntULE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.GTR:
		if isfp {
			result = b.CreateFCmp(llvm.FloatOGT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntUGT, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.GEQ:
		if isfp {
			result = b.CreateFCmp(llvm.FloatOGE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		} else {
			result = b.CreateICmp(llvm.IntUGE, lhs.LLVMValue(), rhs.LLVMValue(), "")
		}
		return lhs.compiler.NewLLVMValue(result, types.Bool)
	case token.AND: // a & b
		result = b.CreateAnd(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.OR: // a | b
		result = b.CreateOr(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	case token.XOR: // a ^ b
		result = b.CreateXor(lhs.LLVMValue(), rhs.LLVMValue(), "")
		return lhs.compiler.NewLLVMValue(result, lhs.typ)
	default:
		panic(fmt.Sprint("Unimplemented operator: ", op))
	}
	panic("unreachable")
}