Esempio n. 1
0
func (c *compiler) makeInterface(v *LLVMValue, iface types.Type) *LLVMValue {
	llv := v.LLVMValue()
	lltyp := llv.Type()
	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	if lltyp.TypeKind() == llvm.PointerTypeKind {
		llv = c.builder.CreateBitCast(llv, i8ptr, "")
	} else {
		// If the value fits exactly in a pointer, then we can just
		// bitcast it. Otherwise we need to malloc.
		if c.target.TypeStoreSize(lltyp) <= uint64(c.target.PointerSize()) {
			bits := c.target.TypeSizeInBits(lltyp)
			if bits > 0 {
				llv = coerce(c.builder, llv, llvm.IntType(int(bits)))
				llv = c.builder.CreateIntToPtr(llv, i8ptr, "")
			} else {
				llv = llvm.ConstNull(i8ptr)
			}
		} else {
			ptr := c.createTypeMalloc(lltyp)
			c.builder.CreateStore(llv, ptr)
			llv = c.builder.CreateBitCast(ptr, i8ptr, "")
		}
	}
	value := llvm.Undef(c.types.ToLLVM(iface))
	rtype := c.types.ToRuntime(v.Type())
	rtype = c.builder.CreateBitCast(rtype, llvm.PointerType(llvm.Int8Type(), 0), "")
	value = c.builder.CreateInsertValue(value, rtype, 0, "")
	value = c.builder.CreateInsertValue(value, llv, 1, "")
	if iface.Underlying().(*types.Interface).NumMethods() > 0 {
		result := c.NewValue(value, types.NewInterface(nil, nil))
		result, _ = result.convertE2I(iface)
		return result
	}
	return c.NewValue(value, iface)
}
Esempio n. 2
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.sizeofType(typ) > c.target.PointerSize() {
		ptr := c.builder.CreateExtractValue(v.LLVMValue(), 0, "")
		typ = &types.Pointer{Base: typ}
		ptr = c.builder.CreateBitCast(ptr, c.types.ToLLVM(typ), "")
		return c.NewLLVMValue(ptr, typ).makePointee()
	}
	bits := c.target.TypeSizeInBits(c.types.ToLLVM(typ))
	value := c.builder.CreateExtractValue(v.LLVMValue(), 0, "")
	value = c.builder.CreatePtrToInt(value, llvm.IntType(int(bits)), "")
	value = c.builder.CreateBitCast(value, c.types.ToLLVM(typ), "")
	return c.NewLLVMValue(value, typ)
}
Esempio n. 3
0
func (v *LLVMValue) convertMethodValue(dsttyp types.Type) *LLVMValue {
	b := v.compiler.builder
	dstlt := v.compiler.types.ToLLVM(dsttyp)
	dstltelems := dstlt.StructElementTypes()

	srclv := v.LLVMValue()
	fnptr := b.CreateExtractValue(srclv, 0, "")
	fnctx := b.CreateExtractValue(srclv, 1, "")

	// TODO(axw) There's a lot of overlap between this
	// and the code that converts concrete methods to
	// interface methods. Refactor.
	if fnctx.Type().TypeKind() == llvm.PointerTypeKind {
		fnctx = b.CreateBitCast(fnctx, dstltelems[1], "")
	} else {
		c := v.compiler
		ptrsize := c.target.PointerSize()
		if c.target.TypeStoreSize(fnctx.Type()) <= uint64(ptrsize) {
			bits := c.target.TypeSizeInBits(fnctx.Type())
			if bits > 0 {
				fnctx = c.coerce(fnctx, llvm.IntType(int(bits)))
				fnctx = b.CreateIntToPtr(fnctx, dstltelems[1], "")
			} else {
				fnctx = llvm.ConstNull(dstltelems[1])
			}
		} else {
			ptr := c.createTypeMalloc(fnctx.Type())
			b.CreateStore(fnctx, ptr)
			fnctx = b.CreateBitCast(ptr, dstltelems[1], "")

			// Switch to the pointer-receiver method.
			methodset := c.methods(v.Type().(*types.Signature).Recv().Type())
			ptrmethod := methodset.lookup(v.method.Name(), true)
			if f, ok := ptrmethod.(*types.Func); ok {
				ptrmethod = c.methodfunc(f)
			}
			lv := c.Resolve(c.objectdata[ptrmethod].Ident).LLVMValue()
			fnptr = c.builder.CreateExtractValue(lv, 0, "")
		}
	}

	dstlv := llvm.Undef(dstlt)
	fnptr = b.CreateBitCast(fnptr, dstltelems[0], "")
	dstlv = b.CreateInsertValue(dstlv, fnptr, 0, "")
	dstlv = b.CreateInsertValue(dstlv, fnctx, 1, "")
	return v.compiler.NewValue(dstlv, dsttyp)
}
Esempio n. 4
0
// loadI2V loads an interface value to a type, without checking
// that the interface type matches.
func (v *LLVMValue) loadI2V(typ types.Type) *LLVMValue {
	c := v.compiler
	if c.types.Sizeof(typ) > int64(c.target.PointerSize()) {
		ptr := c.builder.CreateExtractValue(v.LLVMValue(), 1, "")
		typ = types.NewPointer(typ)
		ptr = c.builder.CreateBitCast(ptr, c.types.ToLLVM(typ), "")
		return c.NewValue(ptr, typ).makePointee()
	}

	value := c.builder.CreateExtractValue(v.LLVMValue(), 1, "")
	if _, ok := typ.Underlying().(*types.Pointer); ok {
		value = c.builder.CreateBitCast(value, c.types.ToLLVM(typ), "")
		return c.NewValue(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.NewValue(value, typ)
}
Esempio n. 5
0
func (tm *TypeMap) interfaceFuncWrapper(f llvm.Value) llvm.Value {
	ftyp := f.Type().ElementType()
	paramTypes := ftyp.ParamTypes()
	recvType := paramTypes[0]
	paramTypes[0] = llvm.PointerType(llvm.Int8Type(), 0)
	newf := llvm.AddFunction(f.GlobalParent(), f.Name()+".ifn", llvm.FunctionType(
		ftyp.ReturnType(),
		paramTypes,
		ftyp.IsFunctionVarArg(),
	))

	b := llvm.GlobalContext().NewBuilder()
	defer b.Dispose()
	entry := llvm.AddBasicBlock(newf, "entry")
	b.SetInsertPointAtEnd(entry)
	args := make([]llvm.Value, len(paramTypes))
	for i := range paramTypes {
		args[i] = newf.Param(i)
	}

	recvBits := int(tm.target.TypeSizeInBits(recvType))
	if recvBits > 0 {
		args[0] = b.CreatePtrToInt(args[0], tm.target.IntPtrType(), "")
		if args[0].Type().IntTypeWidth() > recvBits {
			args[0] = b.CreateTrunc(args[0], llvm.IntType(recvBits), "")
		}
		args[0] = coerce(b, args[0], recvType)
	} else {
		args[0] = llvm.ConstNull(recvType)
	}

	result := b.CreateCall(f, args, "")
	if result.Type().TypeKind() == llvm.VoidTypeKind {
		b.CreateRetVoid()
	} else {
		b.CreateRet(result)
	}
	return newf
}
Esempio n. 6
0
// convertV2I converts a value to an interface.
func (v *LLVMValue) convertV2I(iface *types.Interface) *LLVMValue {
	var srcname *types.Named
	srctyp := v.Type()
	if name, isname := srctyp.(*types.Named); isname {
		srcname = name
		srctyp = name.Underlying()
	}

	var isptr bool
	if p, fromptr := srctyp.(*types.Pointer); fromptr {
		isptr = true
		srctyp = p.Elem()
		if name, isname := srctyp.(*types.Named); 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()
	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 {
			if lv.IsConstant() {
				ptr = llvm.AddGlobal(c.module.Module, lv.Type(), "")
				ptr.SetInitializer(lv)
			} else {
				ptr = c.createTypeMalloc(lv.Type())
				builder.CreateStore(lv, ptr)
			}
			ptr = builder.CreateBitCast(ptr, element_types[1], "")
			isptr = 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, "")

	if srcname != nil {
		// Look up the method by name.
		for i := 0; i < iface.NumMethods(); i++ {
			m := iface.Method(i)
			method := v.compiler.methods(srcname).lookup(m.Name(), isptr)
			methodident := v.compiler.objectdata[method].Ident
			llvm_value := v.compiler.Resolve(methodident).LLVMValue()
			llvm_value = builder.CreateExtractValue(llvm_value, 0, "")
			llvm_value = builder.CreateBitCast(llvm_value, element_types[i+2], "")
			iface_struct = builder.CreateInsertValue(iface_struct, llvm_value, i+2, "")
		}
	}

	return v.compiler.NewValue(iface_struct, iface)
}
Esempio n. 7
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)
}
Esempio n. 8
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
	}

	isptr := false
	if p, fromptr := srctyp.(*types.Pointer); fromptr {
		isptr = true
		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()
	iface_elements := make([]llvm.Value, len(element_types))
	for i, _ := range iface_elements {
		iface_elements[i] = llvm.ConstNull(element_types[i])
	}
	iface_struct := llvm.ConstStruct(iface_elements, false)

	builder := v.compiler.builder
	var ptr llvm.Value
	if isptr {
		ptr = v.LLVMValue()
	} 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.
		lv := v.LLVMValue()
		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 = builder.CreateBitCast(lv, llvm.IntType(int(bits)), "")
				ptr = builder.CreateIntToPtr(lv, element_types[0], "")
			} else {
				ptr = llvm.ConstNull(element_types[0])
			}
		} else {
			ptr = builder.CreateMalloc(v.compiler.types.ToLLVM(srctyp), "")
			builder.CreateStore(lv, ptr)
			// TODO signal that shim functions are required. Probably later
			// we'll have the CallExpr handler pick out the type, and check
			// if the receiver is a pointer or a value type, and load as
			// necessary.
		}
	}
	ptr = builder.CreateBitCast(ptr, element_types[0], "")
	iface_struct = builder.CreateInsertValue(iface_struct, ptr, 0, "")

	var runtimeType llvm.Value
	if srcname != nil {
		runtimeType = v.compiler.types.ToRuntime(srcname)
	} else {
		runtimeType = v.compiler.types.ToRuntime(srctyp)
	}
	runtimeType = builder.CreateBitCast(runtimeType, element_types[1], "")
	iface_struct = builder.CreateInsertValue(iface_struct, runtimeType, 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.
		methods := srcname.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)
			}
			method_obj := methods[mi]
			method := v.compiler.Resolve(method_obj).(*LLVMValue)
			llvm_value := method.LLVMValue()
			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)
}