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) }
// 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) }
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) }
// 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) }
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 }
// 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) }
// 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) }
// 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) }