func (tm *TypeMap) makeSlice(values []llvm.Value, slicetyp llvm.Type) llvm.Value { ptrtyp := slicetyp.StructElementTypes()[0] var globalptr llvm.Value if len(values) > 0 { array := llvm.ConstArray(ptrtyp.ElementType(), values) globalptr = llvm.AddGlobal(tm.module, array.Type(), "") globalptr.SetInitializer(array) globalptr = llvm.ConstBitCast(globalptr, ptrtyp) } else { globalptr = llvm.ConstNull(ptrtyp) } len_ := llvm.ConstInt(tm.inttype, uint64(len(values)), false) slice := llvm.ConstNull(slicetyp) slice = llvm.ConstInsertValue(slice, globalptr, []uint32{0}) slice = llvm.ConstInsertValue(slice, len_, []uint32{1}) slice = llvm.ConstInsertValue(slice, len_, []uint32{2}) return slice }
func (tm *TypeMap) interfaceRuntimeType(i *types.Interface) (global, ptr llvm.Value) { rtype := tm.makeRtype(i, reflect.Interface) interfaceType := llvm.ConstNull(tm.runtimeInterfaceType) interfaceType = llvm.ConstInsertValue(interfaceType, rtype, []uint32{0}) imethods := make([]llvm.Value, i.NumMethods()) for index := range imethods { method := i.Method(index) //name, pkgPath, type imethod := llvm.ConstNull(tm.runtimeImethod) name := tm.globalStringPtr(method.Name()) name = llvm.ConstBitCast(name, tm.runtimeImethod.StructElementTypes()[0]) imethod = llvm.ConstInsertValue(imethod, name, []uint32{0}) //imethod = llvm.ConstInsertValue(imethod, , []uint32{1}) //imethod = llvm.ConstInsertValue(imethod, , []uint32{2}) imethods[index] = imethod } var imethodsGlobalPtr llvm.Value imethodPtrType := llvm.PointerType(tm.runtimeImethod, 0) if len(imethods) > 0 { imethodsArray := llvm.ConstArray(tm.runtimeImethod, imethods) imethodsGlobalPtr = llvm.AddGlobal(tm.module, imethodsArray.Type(), "") imethodsGlobalPtr.SetInitializer(imethodsArray) imethodsGlobalPtr = llvm.ConstBitCast(imethodsGlobalPtr, imethodPtrType) } else { imethodsGlobalPtr = llvm.ConstNull(imethodPtrType) } len_ := llvm.ConstInt(tm.inttype, uint64(i.NumMethods()), false) imethodsSliceType := tm.runtimeInterfaceType.StructElementTypes()[1] imethodsSlice := llvm.ConstNull(imethodsSliceType) imethodsSlice = llvm.ConstInsertValue(imethodsSlice, imethodsGlobalPtr, []uint32{0}) imethodsSlice = llvm.ConstInsertValue(imethodsSlice, len_, []uint32{1}) imethodsSlice = llvm.ConstInsertValue(imethodsSlice, len_, []uint32{2}) interfaceType = llvm.ConstInsertValue(interfaceType, imethodsSlice, []uint32{1}) return tm.makeRuntimeTypeGlobal(interfaceType) }
// 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) }
func (c *compiler) NewConstValue(v exact.Value, typ types.Type) *LLVMValue { switch { case v.Kind() == exact.Unknown: // TODO nil literals should be represented more appropriately once the exact-package supports it. llvmtyp := c.types.ToLLVM(typ) return c.NewValue(llvm.ConstNull(llvmtyp), typ) case isString(typ): if isUntyped(typ) { typ = types.Typ[types.String] } llvmtyp := c.types.ToLLVM(typ) strval := exact.StringVal(v) strlen := len(strval) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var ptr llvm.Value if strlen > 0 { init := llvm.ConstString(strval, false) ptr = llvm.AddGlobal(c.module.Module, init.Type(), "") ptr.SetInitializer(init) ptr = llvm.ConstBitCast(ptr, i8ptr) } else { ptr = llvm.ConstNull(i8ptr) } len_ := llvm.ConstInt(c.types.inttype, uint64(strlen), false) llvmvalue := llvm.Undef(llvmtyp) llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0}) llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1}) return c.NewValue(llvmvalue, typ) case isInteger(typ): if isUntyped(typ) { typ = types.Typ[types.Int] } llvmtyp := c.types.ToLLVM(typ) var llvmvalue llvm.Value if isUnsigned(typ) { v, _ := exact.Uint64Val(v) llvmvalue = llvm.ConstInt(llvmtyp, v, false) } else { v, _ := exact.Int64Val(v) llvmvalue = llvm.ConstInt(llvmtyp, uint64(v), true) } return c.NewValue(llvmvalue, typ) case isBoolean(typ): if isUntyped(typ) { typ = types.Typ[types.Bool] } var llvmvalue llvm.Value if exact.BoolVal(v) { llvmvalue = llvm.ConstAllOnes(llvm.Int1Type()) } else { llvmvalue = llvm.ConstNull(llvm.Int1Type()) } return c.NewValue(llvmvalue, typ) case isFloat(typ): if isUntyped(typ) { typ = types.Typ[types.Float64] } llvmtyp := c.types.ToLLVM(typ) floatval, _ := exact.Float64Val(v) llvmvalue := llvm.ConstFloat(llvmtyp, floatval) return c.NewValue(llvmvalue, typ) case typ == types.Typ[types.UnsafePointer]: llvmtyp := c.types.ToLLVM(typ) v, _ := exact.Uint64Val(v) llvmvalue := llvm.ConstInt(llvmtyp, v, false) return c.NewValue(llvmvalue, typ) case isComplex(typ): if isUntyped(typ) { typ = types.Typ[types.Complex128] } llvmtyp := c.types.ToLLVM(typ) floattyp := llvmtyp.StructElementTypes()[0] llvmvalue := llvm.ConstNull(llvmtyp) realv := exact.Real(v) imagv := exact.Imag(v) realfloatval, _ := exact.Float64Val(realv) imagfloatval, _ := exact.Float64Val(imagv) llvmre := llvm.ConstFloat(floattyp, realfloatval) llvmim := llvm.ConstFloat(floattyp, imagfloatval) llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmre, []uint32{0}) llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmim, []uint32{1}) return c.NewValue(llvmvalue, typ) } // Special case for string -> [](byte|rune) if u, ok := typ.Underlying().(*types.Slice); ok && isInteger(u.Elem()) { if v.Kind() == exact.String { strval := c.NewConstValue(v, types.Typ[types.String]) return strval.Convert(typ).(*LLVMValue) } } panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", c.types.TypeString(typ), typ, v, v)) }
func (tm *TypeMap) pointerRuntimeType(p *types.Pointer) (global, ptr llvm.Value) { // Is the base type a named type from another package? If so, we'll // create a reference to the externally defined symbol. linkage := llvm.LinkOnceAnyLinkage switch elem := p.Elem().(type) { case *types.Basic: if tm.pkgpath != "runtime" { global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(typeString(p))) global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm)) global.SetLinkage(llvm.CommonLinkage) return global, global } linkage = llvm.ExternalLinkage case *types.Named: path := "runtime" if pkg := elem.Obj().Pkg(); pkg != nil { path = pkg.Path() } if path != tm.pkgpath { global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(typeString(p))) global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm)) global.SetLinkage(llvm.CommonLinkage) return global, global } linkage = llvm.ExternalLinkage } rtype := tm.makeRtype(p, reflect.Ptr) if n, ok := p.Elem().(*types.Named); ok { uncommonTypeInit := tm.uncommonType(n, p) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9}) } ptrType := llvm.ConstNull(tm.runtime.ptrType.llvm) var baseTypeGlobal llvm.Value if p.Elem().Underlying() == p { // Recursive pointer. ptrType = llvm.ConstInsertValue(ptrType, rtype, []uint32{0}) global, ptr = tm.makeRuntimeTypeGlobal(ptrType, typeString(p)) baseTypeGlobal = global // Update the global with its own pointer in the elem field. ptrType = global.Initializer() ptrType = llvm.ConstInsertValue(ptrType, ptr, []uint32{1}) global.SetInitializer(ptrType) } else { var baseTypePtr llvm.Value baseTypeGlobal, baseTypePtr = tm.toRuntime(p.Elem()) ptrType = llvm.ConstInsertValue(ptrType, rtype, []uint32{0}) ptrType = llvm.ConstInsertValue(ptrType, baseTypePtr, []uint32{1}) global, ptr = tm.makeRuntimeTypeGlobal(ptrType, typeString(p)) } global.SetLinkage(linkage) // Set ptrToThis in the base type's rtype. baseType := baseTypeGlobal.Initializer() if !baseType.IsNull() { if baseType.Type() == tm.runtime.rtype.llvm { baseType = llvm.ConstInsertValue(baseType, ptr, []uint32{10}) } else { rtype := llvm.ConstExtractValue(baseType, []uint32{0}) rtype = llvm.ConstInsertValue(rtype, ptr, []uint32{10}) baseType = llvm.ConstInsertValue(baseType, rtype, []uint32{0}) } baseTypeGlobal.SetInitializer(baseType) } return global, ptr }
func (tm *TypeMap) uncommonType(n *types.Named, ptr bool) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj().Name()) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) // FIXME clean this up var pkgpathPtr llvm.Value var path string if data, ok := tm.functions.objectdata[n.Obj()]; ok { path = pkgpath(data.Package) } if path != "" { pkgpathPtr = tm.globalStringPtr(path) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) } methodset := tm.functions.methods(n) methodfuncs := methodset.nonptr if ptr { methodfuncs = methodset.ptr } // Store methods. methods := make([]llvm.Value, len(methodfuncs)) for i, mfunc := range methodfuncs { ftyp := mfunc.Type().(*types.Signature) method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(mfunc.Name()) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { ftyp := types.NewSignature(nil, ftyp.Params(), ftyp.Results(), ftyp.IsVariadic()) mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() tfn = llvm.ConstExtractValue(tfn, []uint32{0}) tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn if !ptr && tm.Sizeof(ftyp.Recv().Type()) > int64(tm.target.PointerSize()) { mfunc := methodset.lookup(mfunc.Name(), true) ifn = tm.resolver.Resolve(tm.functions.objectdata[mfunc].Ident).LLVMValue() ifn = llvm.ConstExtractValue(ifn, []uint32{0}) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods[i] = method } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(tm.inttype, uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }
func (tm *TypeMap) pointerRuntimeType(p *types.Pointer) (global, ptr llvm.Value) { // Is the base type a named type from another package? If so, we'll // create a reference to the externally defined symbol. var globalname string if n, ok := p.Elem().(*types.Named); ok { // FIXME horrible circular relationship var path string if data, ok := tm.functions.objectdata[n.Obj()]; ok { path = pkgpath(data.Package) } if path == "" { path = "runtime" } globalname = "__llgo.type.*" + path + "." + n.Obj().Name() if path != tm.pkgpath { global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname) global.SetInitializer(llvm.ConstNull(tm.runtimeType)) global.SetLinkage(llvm.CommonLinkage) return global, global } } rtype := tm.makeRtype(p, reflect.Ptr) if n, ok := p.Elem().(*types.Named); ok { uncommonTypeInit := tm.uncommonType(n, true) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9}) } ptrType := llvm.ConstNull(tm.runtimePtrType) var baseTypeGlobal llvm.Value if p.Elem().Underlying() == p { // Recursive pointer. ptrType = llvm.ConstInsertValue(ptrType, rtype, []uint32{0}) global, ptr = tm.makeRuntimeTypeGlobal(ptrType) baseTypeGlobal = global // Update the global with its own pointer in the elem field. ptrType = global.Initializer() ptrType = llvm.ConstInsertValue(ptrType, ptr, []uint32{1}) global.SetInitializer(ptrType) } else { var baseTypePtr llvm.Value baseTypeGlobal, baseTypePtr = tm.toRuntime(p.Elem()) ptrType = llvm.ConstInsertValue(ptrType, rtype, []uint32{0}) ptrType = llvm.ConstInsertValue(ptrType, baseTypePtr, []uint32{1}) global, ptr = tm.makeRuntimeTypeGlobal(ptrType) } global.SetName(globalname) // Set ptrToThis in the base type's rtype. baseType := baseTypeGlobal.Initializer() if baseType.Type() == tm.runtimeType { baseType = llvm.ConstInsertValue(baseType, ptr, []uint32{10}) } else { rtype := llvm.ConstExtractValue(baseType, []uint32{0}) rtype = llvm.ConstInsertValue(rtype, ptr, []uint32{10}) baseType = llvm.ConstInsertValue(baseType, rtype, []uint32{0}) } baseTypeGlobal.SetInitializer(baseType) return global, ptr }
func (tm *TypeMap) pointerRuntimeType(p *types.Pointer) (global, ptr llvm.Value) { // Is the base type a named type from another package? If so, we'll // create a reference to the externally defined symbol. var globalname string switch elem := p.Elem().(type) { case *types.Basic: globalname = "__llgo.type.*runtime." + tm.TypeString(elem) if tm.pkgpath != "runtime" { global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname) global.SetInitializer(llvm.ConstNull(tm.runtimeType)) global.SetLinkage(llvm.CommonLinkage) return global, global } case *types.Named: qname, path := tm.qualifiedName(elem) globalname = "__llgo.type.*" + qname if path != tm.pkgpath { global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname) global.SetInitializer(llvm.ConstNull(tm.runtimeType)) global.SetLinkage(llvm.CommonLinkage) return global, global } else if !isGlobalObject(elem.Obj()) { globalname = "" } } rtype := tm.makeRtype(p, reflect.Ptr) if n, ok := p.Elem().(*types.Named); ok { uncommonTypeInit := tm.uncommonType(n, true) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9}) } ptrType := llvm.ConstNull(tm.runtimePtrType) var baseTypeGlobal llvm.Value if p.Elem().Underlying() == p { // Recursive pointer. ptrType = llvm.ConstInsertValue(ptrType, rtype, []uint32{0}) global, ptr = tm.makeRuntimeTypeGlobal(ptrType) baseTypeGlobal = global // Update the global with its own pointer in the elem field. ptrType = global.Initializer() ptrType = llvm.ConstInsertValue(ptrType, ptr, []uint32{1}) global.SetInitializer(ptrType) } else { var baseTypePtr llvm.Value baseTypeGlobal, baseTypePtr = tm.toRuntime(p.Elem()) ptrType = llvm.ConstInsertValue(ptrType, rtype, []uint32{0}) ptrType = llvm.ConstInsertValue(ptrType, baseTypePtr, []uint32{1}) global, ptr = tm.makeRuntimeTypeGlobal(ptrType) } global.SetName(globalname) // Set ptrToThis in the base type's rtype. baseType := baseTypeGlobal.Initializer() if baseType.Type() == tm.runtimeType { baseType = llvm.ConstInsertValue(baseType, ptr, []uint32{10}) } else { rtype := llvm.ConstExtractValue(baseType, []uint32{0}) rtype = llvm.ConstInsertValue(rtype, ptr, []uint32{10}) baseType = llvm.ConstInsertValue(baseType, rtype, []uint32{0}) } baseTypeGlobal.SetInitializer(baseType) return global, ptr }
func (tm *TypeMap) nameRuntimeType(n *types.Name) (global, ptr llvm.Value) { pkgpath := tm.pkgmap[n.Obj] if pkgpath == "" { // XXX "builtin"? pkgpath = "runtime" } globalname := "__llgo.type.name." + pkgpath + "." + n.Obj.Name if pkgpath != tm.pkgpath { // We're not compiling the package from whence the type came, // so we'll just create a pointer to it here. global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname) global.SetInitializer(llvm.ConstNull(tm.runtimeType)) global.SetLinkage(llvm.CommonLinkage) return global, global } underlying := n.Underlying if name, ok := underlying.(*types.Name); ok { underlying = name.Underlying } global, ptr = tm.makeRuntimeType(underlying) globalInit := global.Initializer() // Locate the common type. underlyingRuntimeType := llvm.ConstExtractValue(globalInit, []uint32{1}) commonType := underlyingRuntimeType if underlyingRuntimeType.Type() != tm.runtimeCommonType { commonType = llvm.ConstExtractValue(commonType, []uint32{0}) } // Insert the uncommon type. uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj.Name) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) pkgpathPtr := tm.globalStringPtr(pkgpath) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) // Replace the commonType's string representation. commonType = llvm.ConstInsertValue(commonType, namePtr, []uint32{8}) methods := make([]llvm.Value, len(n.Methods)) for index, m := range n.Methods { method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(m.Name) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) ftyp := m.Type.(*types.Func) { recv := ftyp.Recv ftyp.Recv = nil mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) ftyp.Recv = recv } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // ifn (single-word receiver function pointer for interface calls) ifn := tm.resolver.Resolve(m).LLVMValue() // TODO generate trampoline as necessary. ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) method = llvm.ConstInsertValue(method, ifn, []uint32{4}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(m).LLVMValue() tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods[index] = method } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{9}) // Update the global's initialiser. Note that we take a copy // of the underlying type; we're not updating a shared type. if underlyingRuntimeType.Type() != tm.runtimeCommonType { underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, commonType, []uint32{0}) } else { underlyingRuntimeType = commonType } globalInit = llvm.ConstInsertValue(globalInit, underlyingRuntimeType, []uint32{1}) global.SetName(globalname) global.SetInitializer(globalInit) return global, ptr }
func (tm *TypeMap) uncommonType(n *types.Name, ptr bool) llvm.Value { uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) namePtr := tm.globalStringPtr(n.Obj.Name) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, namePtr, []uint32{0}) var pkgpathPtr llvm.Value if n.Package != "" { pkgpathPtr = tm.globalStringPtr(n.Package) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, pkgpathPtr, []uint32{1}) } // Store methods. methods := make([]llvm.Value, 0, len(n.Methods)) for _, m := range n.Methods { ftyp := m.Type.(*types.Func) ptrrecv := !types.Identical(ftyp.Recv.Type.(types.Type), n) if !ptr && ptrrecv { // For a type T, we only store methods where the // receiver is T and not *T. For *T we store both. continue } method := llvm.ConstNull(tm.runtimeMethod) name := tm.globalStringPtr(m.Name) name = llvm.ConstBitCast(name, tm.runtimeMethod.StructElementTypes()[0]) // name method = llvm.ConstInsertValue(method, name, []uint32{0}) // pkgPath method = llvm.ConstInsertValue(method, pkgpathPtr, []uint32{1}) // mtyp (method type, no receiver) { recv := ftyp.Recv ftyp.Recv = nil mtyp := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, mtyp, []uint32{2}) ftyp.Recv = recv } // typ (function type, with receiver) typ := tm.ToRuntime(ftyp) method = llvm.ConstInsertValue(method, typ, []uint32{3}) // tfn (standard method/function pointer for plain method calls) tfn := tm.resolver.Resolve(m).LLVMValue() tfn = llvm.ConstPtrToInt(tfn, tm.target.IntPtrType()) // ifn (single-word receiver function pointer for interface calls) ifn := tfn needload := ptr && !ptrrecv if !needload { recvtyp := tm.ToLLVM(ftyp.Recv.Type.(types.Type)) needload = int(tm.target.TypeAllocSize(recvtyp)) > tm.target.PointerSize() } if needload { // If the receiver type is wider than a word, we // need to use an intermediate function which takes // a pointer-receiver, loads it, and then calls the // standard receiver function. fname := fmt.Sprintf("*%s.%s", ftyp.Recv.Type, m.Name) ifn = tm.module.NamedFunction(fname) ifn = llvm.ConstPtrToInt(ifn, tm.target.IntPtrType()) } method = llvm.ConstInsertValue(method, ifn, []uint32{4}) method = llvm.ConstInsertValue(method, tfn, []uint32{5}) methods = append(methods, method) } var methodsGlobalPtr llvm.Value if len(methods) > 0 { methodsArray := llvm.ConstArray(tm.runtimeMethod, methods) methodsGlobalPtr = llvm.AddGlobal(tm.module, methodsArray.Type(), "") methodsGlobalPtr.SetInitializer(methodsArray) i32zero := llvm.ConstNull(llvm.Int32Type()) methodsGlobalPtr = llvm.ConstGEP(methodsGlobalPtr, []llvm.Value{i32zero, i32zero}) } else { methodsGlobalPtr = llvm.ConstNull(llvm.PointerType(tm.runtimeMethod, 0)) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(methods)), false) methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := llvm.ConstNull(methodsSliceType) methodsSlice = llvm.ConstInsertValue(methodsSlice, methodsGlobalPtr, []uint32{0}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{1}) methodsSlice = llvm.ConstInsertValue(methodsSlice, len_, []uint32{2}) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }