func (tm *TypeMap) nameRuntimeType(n *types.Named) (global, ptr llvm.Value) { name := typeString(n) path := "runtime" if pkg := n.Obj().Pkg(); pkg != nil { path = pkg.Path() } if path != 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.runtime.rtype.llvm, typeSymbol(name)) global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm)) global.SetLinkage(llvm.CommonLinkage) return global, global } // If the underlying type is Basic, then we always create // a new global. Otherwise, we clone the value returned // from toRuntime in case it is cached and reused. underlying := n.Underlying() if basic, ok := underlying.(*types.Basic); ok { global, ptr = tm.basicRuntimeType(basic, true) global.SetName(typeSymbol(name)) } else { global, ptr = tm.toRuntime(underlying) clone := llvm.AddGlobal(tm.module, global.Type().ElementType(), typeSymbol(name)) clone.SetInitializer(global.Initializer()) global = clone ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtime.rtype.llvm, 0)) } global.SetLinkage(llvm.ExternalLinkage) // Locate the rtype. underlyingRuntimeType := global.Initializer() rtype := underlyingRuntimeType if rtype.Type() != tm.runtime.rtype.llvm { rtype = llvm.ConstExtractValue(rtype, []uint32{0}) } // Insert the uncommon type. uncommonTypeInit := tm.uncommonType(n, nil) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9}) // Replace the rtype's string representation with the one from // uncommonType. XXX should we have the package name prepended? Probably. namePtr := llvm.ConstExtractValue(uncommonTypeInit, []uint32{0}) rtype = llvm.ConstInsertValue(rtype, namePtr, []uint32{8}) // 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.runtime.rtype.llvm { underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, rtype, []uint32{0}) } else { underlyingRuntimeType = rtype } global.SetInitializer(underlyingRuntimeType) return global, ptr }
func (tm *TypeMap) nameRuntimeType(n *types.Named) (global, ptr llvm.Value) { var path string if data, ok := tm.functions.objectdata[n.Obj()]; ok { path = pkgpath(data.Package) } if path == "" { // Set to "runtime", so the builtin types have a home. path = "runtime" } globalname := "__llgo.type." + path + "." + n.Obj().Name() if path != 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.Named); ok { underlying = name.Underlying() } global, ptr = tm.toRuntime(underlying) // Locate the rtype. underlyingRuntimeType := global.Initializer() rtype := underlyingRuntimeType if rtype.Type() != tm.runtimeType { rtype = llvm.ConstExtractValue(rtype, []uint32{0}) } // Insert the uncommon type. uncommonTypeInit := tm.uncommonType(n, false) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) rtype = llvm.ConstInsertValue(rtype, uncommonType, []uint32{9}) // Replace the rtype's string representation with the one from // uncommonType. XXX should we have the package name prepended? Probably. namePtr := llvm.ConstExtractValue(uncommonTypeInit, []uint32{0}) rtype = llvm.ConstInsertValue(rtype, namePtr, []uint32{8}) // 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.runtimeType { underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, rtype, []uint32{0}) } else { underlyingRuntimeType = rtype } global.SetName(globalname) global.SetInitializer(underlyingRuntimeType) return global, ptr }
// globalStringPtr returns a *string with the specified value. func (tm *TypeMap) globalStringPtr(value string) llvm.Value { strval := llvm.ConstString(value, false) strglobal := llvm.AddGlobal(tm.module, strval.Type(), "") strglobal.SetInitializer(strval) strglobal = llvm.ConstBitCast(strglobal, llvm.PointerType(llvm.Int8Type(), 0)) strlen := llvm.ConstInt(tm.inttype, uint64(len(value)), false) str := llvm.ConstStruct([]llvm.Value{strglobal, strlen}, false) g := llvm.AddGlobal(tm.module, str.Type(), "") g.SetInitializer(str) return g }
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.Base.(*types.Name); ok { pkgpath := n.Package if pkgpath == "" { pkgpath = "runtime" } globalname = "__llgo.type.*" + n.String() if pkgpath != tm.pkgpath { global := llvm.AddGlobal(tm.module, tm.runtimeType, globalname) global.SetInitializer(llvm.ConstNull(tm.runtimeType)) global.SetLinkage(llvm.CommonLinkage) return global, global } } commonType := tm.makeCommonType(p, reflect.Ptr) if n, ok := p.Base.(*types.Name); ok { uncommonTypeInit := tm.uncommonType(n, true) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{9}) } baseTypeGlobal, baseTypePtr := tm.toRuntime(p.Base) ptrType := llvm.ConstNull(tm.runtimePtrType) ptrType = llvm.ConstInsertValue(ptrType, commonType, []uint32{0}) ptrType = llvm.ConstInsertValue(ptrType, baseTypePtr, []uint32{1}) global, ptr = tm.makeRuntimeTypeGlobal(ptrType) global.SetName(globalname) // Set ptrToThis in the base type's commonType. baseRuntimeType := baseTypeGlobal.Initializer() baseType := llvm.ConstExtractValue(baseRuntimeType, []uint32{1}) if baseType.Type() == tm.runtimeCommonType { baseType = llvm.ConstInsertValue(baseType, ptr, []uint32{10}) } else { commonType := llvm.ConstExtractValue(baseType, []uint32{0}) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{10}) baseType = llvm.ConstInsertValue(baseType, commonType, []uint32{0}) } baseRuntimeType = llvm.ConstInsertValue(baseRuntimeType, baseType, []uint32{1}) baseTypeGlobal.SetInitializer(baseRuntimeType) return global, ptr }
// basicRuntimeType creates the runtime type structure for // a basic type. If underlying is true, then a new global // is always created. func (tm *TypeMap) basicRuntimeType(b *types.Basic, underlying bool) (global, ptr llvm.Value) { b = types.Typ[b.Kind()] // unalias var name string if !underlying { name = typeString(b) if tm.pkgpath != "runtime" { global := llvm.AddGlobal(tm.module, tm.runtime.rtype.llvm, typeSymbol(name)) global.SetInitializer(llvm.ConstNull(tm.runtime.rtype.llvm)) global.SetLinkage(llvm.CommonLinkage) return global, global } } rtype := tm.makeRtype(b, basicReflectKinds[b.Kind()]) global, ptr = tm.makeRuntimeTypeGlobal(rtype, name) global.SetLinkage(llvm.ExternalLinkage) if !underlying { switch b.Kind() { case types.Int32: llvm.AddAlias(tm.module, global.Type(), global, typeSymbol("rune")) case types.Uint8: llvm.AddAlias(tm.module, global.Type(), global, typeSymbol("byte")) } } return global, ptr }
func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value, name string) (global, ptr llvm.Value) { global = llvm.AddGlobal(tm.module, v.Type(), typeSymbol(name)) global.SetInitializer(v) global.SetLinkage(llvm.LinkOnceAnyLinkage) ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtime.rtype.llvm, 0)) return global, ptr }
func (tm *TypeMap) nameRuntimeType(n *types.Name) (global, ptr llvm.Value) { global, ptr = tm.makeRuntimeType(n.Underlying) globalInit := global.Initializer() // Locate the common type. underlyingRuntimeType := llvm.ConstExtractValue(globalInit, []uint32{1}) commonType := underlyingRuntimeType if _, ok := n.Underlying.(*types.Basic); !ok { commonType = llvm.ConstExtractValue(commonType, []uint32{0}) } // Insert the uncommon type. uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{8}) // Update the global's initialiser. if _, ok := n.Underlying.(*types.Basic); !ok { underlyingRuntimeType = llvm.ConstInsertValue(underlyingRuntimeType, commonType, []uint32{0}) } else { underlyingRuntimeType = commonType } globalInit = llvm.ConstInsertValue(globalInit, underlyingRuntimeType, []uint32{1}) global.SetName("__llgo.reflect." + n.Obj.Name) return global, ptr }
// mapLookup searches a map for a specified key, returning a pointer to the // memory location for the value. If insert is given as true, and the key // does not exist in the map, it will be added with an uninitialised value. func (c *compiler) mapLookup(m *LLVMValue, key Value, insert bool) (elem *LLVMValue, notnull *LLVMValue) { mapType := m.Type().Underlying().(*types.Map) maplookup := c.NamedFunction("runtime.maplookup", "func f(t, m, k uintptr, insert bool) uintptr") ptrType := c.target.IntPtrType() args := make([]llvm.Value, 4) args[0] = llvm.ConstPtrToInt(c.types.ToRuntime(mapType), ptrType) args[1] = c.builder.CreatePtrToInt(m.LLVMValue(), ptrType, "") if insert { args[3] = llvm.ConstAllOnes(llvm.Int1Type()) } else { args[3] = llvm.ConstNull(llvm.Int1Type()) } if lv, islv := key.(*LLVMValue); islv && lv.pointer != nil { args[2] = c.builder.CreatePtrToInt(lv.pointer.LLVMValue(), ptrType, "") } if args[2].IsNil() { stackval := c.builder.CreateAlloca(c.types.ToLLVM(key.Type()), "") c.builder.CreateStore(key.LLVMValue(), stackval) args[2] = c.builder.CreatePtrToInt(stackval, ptrType, "") } eltPtrType := types.NewPointer(mapType.Elem()) llvmtyp := c.types.ToLLVM(eltPtrType) zeroglobal := llvm.AddGlobal(c.module.Module, llvmtyp.ElementType(), "") zeroglobal.SetInitializer(llvm.ConstNull(llvmtyp.ElementType())) result := c.builder.CreateCall(maplookup, args, "") result = c.builder.CreateIntToPtr(result, llvmtyp, "") notnull_ := c.builder.CreateIsNotNull(result, "") result = c.builder.CreateSelect(notnull_, result, zeroglobal, "") value := c.NewValue(result, eltPtrType) return value.makePointee(), c.NewValue(notnull_, types.Typ[types.Bool]) }
// mapInsert inserts a key into a map, returning a pointer to the memory // location for the value. func (c *compiler) mapInsert(m *LLVMValue, key Value) *LLVMValue { mapType := m.Type().(*types.Map) mapinsert := c.module.Module.NamedFunction("runtime.mapinsert") ptrType := c.target.IntPtrType() if mapinsert.IsNil() { // params: dynamic type, mapptr, keyptr paramTypes := []llvm.Type{ptrType, ptrType, ptrType} funcType := llvm.FunctionType(ptrType, paramTypes, false) mapinsert = llvm.AddFunction(c.module.Module, "runtime.mapinsert", funcType) } args := make([]llvm.Value, 3) args[0] = llvm.ConstPtrToInt(c.types.ToRuntime(m.Type()), ptrType) args[1] = c.builder.CreatePtrToInt(m.pointer.LLVMValue(), ptrType, "") if lv, islv := key.(*LLVMValue); islv && lv.pointer != nil { args[2] = c.builder.CreatePtrToInt(lv.pointer.LLVMValue(), ptrType, "") } if args[2].IsNil() { // Create global constant, so we can take its address. global := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(key.Type()), "") global.SetGlobalConstant(true) global.SetInitializer(key.LLVMValue()) args[2] = c.builder.CreatePtrToInt(global, ptrType, "") } eltPtrType := &types.Pointer{Base: mapType.Elt} result := c.builder.CreateCall(mapinsert, args, "") result = c.builder.CreateIntToPtr(result, c.types.ToLLVM(eltPtrType), "") value := c.NewLLVMValue(result, eltPtrType) return value.makePointee() }
func (tm *TypeMap) nameRuntimeType(n *types.Name) llvm.Value { underlyingRuntimeType := tm.ToRuntime(n.Underlying).Initializer() result := llvm.AddGlobal(tm.module, underlyingRuntimeType.Type(), "") result.SetName("__llgo.reflect." + n.Obj.Name) elementTypes := tm.runtimeCommonType.StructElementTypes() ptr := llvm.ConstBitCast(result, elementTypes[9]) commonType := llvm.ConstInsertValue(underlyingRuntimeType, ptr, []uint32{9}) uncommonTypeInit := llvm.ConstNull(tm.runtimeUncommonType) // TODO uncommonType := llvm.AddGlobal(tm.module, uncommonTypeInit.Type(), "") uncommonType.SetInitializer(uncommonTypeInit) commonType = llvm.ConstInsertValue(commonType, uncommonType, []uint32{8}) // TODO set string, uncommonType. result.SetInitializer(commonType) return result }
func (tm *TypeMap) basicRuntimeType(b *types.Basic) llvm.Value { commonType := tm.makeCommonType(b, reflect.Kind(b.Kind)) result := llvm.AddGlobal(tm.module, commonType.Type(), "") elementTypes := tm.runtimeCommonType.StructElementTypes() ptr := llvm.ConstBitCast(result, elementTypes[9]) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9}) result.SetInitializer(commonType) return result }
func (c *compiler) Resolve(ident *ast.Ident) Value { obj := c.typeinfo.Objects[ident] data := c.objectdata[obj] if data.Value != nil { return data.Value } var value *LLVMValue switch obj := obj.(type) { case *types.Func: value = c.makeFunc(ident, obj.Type().(*types.Signature)) case *synthFunc: value = c.makeFunc(ident, obj.Type().(*types.Signature)) case *types.Var: if data.Ident.Obj != nil { switch decl := data.Ident.Obj.Decl.(type) { case *ast.ValueSpec: c.VisitValueSpec(decl) case *ast.Field: // No-op. Fields will be yielded for function // arg/recv/ret. We update the .Data field of the // object when we enter the function definition. if data.Value == nil { panic("expected object value") } } } // If it's an external variable, we'll need to create a global // value reference here. It may be possible for multiple objects // to refer to the same variable. value = data.Value if value == nil { module := c.module.Module t := obj.Type() name := obj.Pkg().Path() + "." + obj.Name() g := module.NamedGlobal(name) if g.IsNil() { g = llvm.AddGlobal(module, c.types.ToLLVM(t), name) } value = c.NewValue(g, types.NewPointer(t)).makePointee() } case *types.Const: value = c.NewConstValue(obj.Val(), obj.Type()) default: panic(fmt.Sprintf("unreachable (%T)", obj)) } data.Value = value return value }
func (tm *TypeMap) mapRuntimeType(m *types.Map) llvm.Value { result := llvm.AddGlobal(tm.module, tm.runtimeMapType, "") elementTypes := tm.runtimeCommonType.StructElementTypes() ptr := llvm.ConstBitCast(result, elementTypes[9]) commonType := tm.makeCommonType(m, reflect.Map) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9}) init := llvm.ConstNull(tm.runtimeMapType) init = llvm.ConstInsertValue(init, commonType, []uint32{0}) result.SetInitializer(init) // TODO set key, elem return result }
func (tm *TypeMap) structRuntimeType(s *types.Struct) llvm.Value { result := llvm.AddGlobal(tm.module, tm.runtimeStructType, "") elementTypes := tm.runtimeCommonType.StructElementTypes() ptr := llvm.ConstBitCast(result, elementTypes[9]) commonType := tm.makeCommonType(s, reflect.Struct) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9}) init := llvm.ConstNull(tm.runtimeStructType) init = llvm.ConstInsertValue(init, commonType, []uint32{0}) result.SetInitializer(init) // TODO set fields //panic("unimplemented") return result }
func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value) (global, ptr llvm.Value) { // Each runtime type is preceded by an interface{}. initType := llvm.StructType([]llvm.Type{tm.runtimeType, v.Type()}, false) global = llvm.AddGlobal(tm.module, initType, "") ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtimeType, 0)) // interface{} containing v's *commonType representation. runtimeTypeValue := llvm.Undef(tm.runtimeType) zero := llvm.ConstNull(llvm.Int32Type()) one := llvm.ConstInt(llvm.Int32Type(), 1, false) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) if tm.commonTypePtrRuntimeType.IsNil() { // Create a dummy pointer value, which we'll update straight after // defining the runtime type info for commonType. tm.commonTypePtrRuntimeType = llvm.Undef(i8ptr) commonTypePtr := &types.Pointer{Base: tm.commonType} commonTypeGlobal, commonTypeRuntimeType := tm.makeRuntimeType(tm.commonType) tm.types[tm.commonType.String()] = runtimeTypeInfo{commonTypeGlobal, commonTypeRuntimeType} commonTypePtrGlobal, commonTypePtrRuntimeType := tm.makeRuntimeType(commonTypePtr) tm.types[commonTypePtr.String()] = runtimeTypeInfo{commonTypePtrGlobal, commonTypePtrRuntimeType} tm.commonTypePtrRuntimeType = llvm.ConstBitCast(commonTypePtrRuntimeType, i8ptr) if tm.pkgpath == tm.commonType.Package { // Update the interace{} header of the commonType/*commonType // runtime types we just created. for _, g := range [...]llvm.Value{commonTypeGlobal, commonTypePtrGlobal} { init := g.Initializer() typptr := tm.commonTypePtrRuntimeType runtimeTypeValue := llvm.ConstExtractValue(init, []uint32{0}) runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, typptr, []uint32{0}) init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0}) g.SetInitializer(init) } } } commonTypePtr := llvm.ConstGEP(global, []llvm.Value{zero, one}) commonTypePtr = llvm.ConstBitCast(commonTypePtr, i8ptr) runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, tm.commonTypePtrRuntimeType, []uint32{0}) runtimeTypeValue = llvm.ConstInsertValue(runtimeTypeValue, commonTypePtr, []uint32{1}) init := llvm.Undef(initType) init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0}) init = llvm.ConstInsertValue(init, v, []uint32{1}) global.SetInitializer(init) return global, ptr }
// basicRuntimeType creates the runtime type structure for // a basic type. If underlying is true, then a new global // is always created. func (tm *TypeMap) basicRuntimeType(b *types.Basic, underlying bool) (global, ptr llvm.Value) { var globalname string if !underlying { globalname = "__llgo.type.runtime." + tm.TypeString(b) 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 } } rtype := tm.makeRtype(b, basicReflectKinds[b.Kind()]) global, ptr = tm.makeRuntimeTypeGlobal(rtype) if globalname != "" { global.SetName(globalname) } return global, ptr }
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) }
func (tm *TypeMap) makeRtype(t types.Type, k reflect.Kind) llvm.Value { // Not sure if there's an easier way to do this, but if you just // use ConstStruct, you end up getting a different llvm.Type. lt := tm.ToLLVM(t) typ := llvm.ConstNull(tm.runtimeType) elementTypes := tm.runtimeType.StructElementTypes() // Size. size := llvm.SizeOf(lt) if size.Type().IntTypeWidth() > elementTypes[0].IntTypeWidth() { size = llvm.ConstTrunc(size, elementTypes[0]) } typ = llvm.ConstInsertValue(typ, size, []uint32{0}) // TODO hash // TODO padding // Alignment. align := llvm.ConstTrunc(llvm.AlignOf(lt), llvm.Int8Type()) typ = llvm.ConstInsertValue(typ, align, []uint32{3}) // var typ = llvm.ConstInsertValue(typ, align, []uint32{4}) // field // Kind. kind := llvm.ConstInt(llvm.Int8Type(), uint64(k), false) typ = llvm.ConstInsertValue(typ, kind, []uint32{5}) // Algorithm table. alg := tm.makeAlgorithmTable(t) algptr := llvm.AddGlobal(tm.module, alg.Type(), "") algptr.SetInitializer(alg) algptr = llvm.ConstBitCast(algptr, elementTypes[6]) typ = llvm.ConstInsertValue(typ, algptr, []uint32{6}) // String representation. stringrep := tm.globalStringPtr(tm.TypeString(t)) typ = llvm.ConstInsertValue(typ, stringrep, []uint32{8}) // TODO gc return typ }
func (tm *TypeMap) makeRuntimeTypeGlobal(v llvm.Value) (global, ptr llvm.Value) { runtimeTypeValue := llvm.ConstNull(tm.runtimeType) initType := llvm.StructType([]llvm.Type{tm.runtimeType, v.Type()}, false) global = llvm.AddGlobal(tm.module, initType, "") ptr = llvm.ConstBitCast(global, llvm.PointerType(tm.runtimeType, 0)) // Set ptrToThis in v's commonType. if v.Type() == tm.runtimeCommonType { v = llvm.ConstInsertValue(v, ptr, []uint32{9}) } else { commonType := llvm.ConstExtractValue(v, []uint32{0}) commonType = llvm.ConstInsertValue(commonType, ptr, []uint32{9}) v = llvm.ConstInsertValue(v, commonType, []uint32{0}) } init := llvm.Undef(initType) //runtimeTypeValue = llvm.ConstInsertValue() TODO init = llvm.ConstInsertValue(init, runtimeTypeValue, []uint32{0}) init = llvm.ConstInsertValue(init, v, []uint32{1}) global.SetInitializer(init) return }
// translatePackage translates an *ssa.Package into an LLVM module, and returns // the translation unit information. func (u *unit) translatePackage(pkg *ssa.Package) { // Initialize global storage. for _, m := range pkg.Members { switch v := m.(type) { case *ssa.Global: llelemtyp := u.llvmtypes.ToLLVM(deref(v.Type())) global := llvm.AddGlobal(u.module.Module, llelemtyp, v.String()) global.SetInitializer(llvm.ConstNull(llelemtyp)) u.globals[v] = u.NewValue(global, v.Type()) } } // Define functions. // Sort if flag is set for deterministic behaviour (for debugging) functions := ssautil.AllFunctions(pkg.Prog) if !u.compiler.OrderedCompilation { for f, _ := range functions { u.defineFunction(f) } } else { fns := []*ssa.Function{} for f, _ := range functions { fns = append(fns, f) } sort.Sort(byName(fns)) for _, f := range fns { u.defineFunction(f) } } // Define remaining functions that were resolved during // runtime type mapping, but not defined. for f, _ := range u.undefinedFuncs { u.defineFunction(f) } }
// Create a constructor function which initialises a global. // TODO collapse all global inits into one init function? func (c *compiler) createGlobal(e ast.Expr, t types.Type, name string, export bool) (g *LLVMValue) { if e == nil { gv := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(t), name) if !export { gv.SetLinkage(llvm.InternalLinkage) } g = c.NewLLVMValue(gv, &types.Pointer{Base: t}) if !isArray(t) { return g.makePointee() } return g } if block := c.builder.GetInsertBlock(); !block.IsNil() { defer c.builder.SetInsertPointAtEnd(block) } fn_type := new(types.Func) llvm_fn_type := c.types.ToLLVM(fn_type).ElementType() fn := llvm.AddFunction(c.module.Module, "", llvm_fn_type) fn.SetLinkage(llvm.InternalLinkage) entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) // Visit the expression. Dereference if necessary, and generalise // the type if one hasn't been specified. init_ := c.VisitExpr(e) _, isconst := init_.(ConstValue) if t == nil { t = init_.Type() } else { init_ = init_.Convert(t) } // If the result is a constant, discard the function before // creating any llvm.Value's. if isconst { fn.EraseFromParentAsFunction() fn = llvm.Value{nil} } // Set the initialiser. If it's a non-const value, then // we'll have to do the assignment in a global constructor // function. gv := llvm.AddGlobal(c.module.Module, c.types.ToLLVM(t), name) if !export { gv.SetLinkage(llvm.InternalLinkage) } g = c.NewLLVMValue(gv, &types.Pointer{Base: t}) if !isArray(t) { g = g.makePointee() } if isconst { // Initialiser is constant; discard function and return global now. gv.SetInitializer(init_.LLVMValue()) } else { gv.SetInitializer(llvm.ConstNull(c.types.ToLLVM(t))) c.builder.CreateStore(init_.LLVMValue(), gv) } if !fn.IsNil() { c.builder.CreateRetVoid() // FIXME order global ctors fn_value := c.NewLLVMValue(fn, fn_type) c.initfuncs = append(c.initfuncs, fn_value) } return g }
func (fr *frame) value(v ssa.Value) (result *LLVMValue) { switch v := v.(type) { case nil: return nil case *ssa.Function: result, ok := fr.funcvals[v] if ok { return result } // fr.globals[v] has the function in raw pointer form; // we must convert it to <f,ctx> form. If the function // does not have a receiver, then create a wrapper // function that has an additional "context" parameter. f := fr.resolveFunction(v) if v.Signature.Recv() == nil && len(v.FreeVars) == 0 { f = contextFunction(fr.compiler, f) } pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(f.Type())) fnptr := llvm.ConstBitCast(f.LLVMValue(), pair.Type().StructElementTypes()[0]) pair = llvm.ConstInsertValue(pair, fnptr, []uint32{0}) result = fr.NewValue(pair, f.Type()) fr.funcvals[v] = result return result case *ssa.Const: return fr.NewConstValue(v.Value, v.Type()) case *ssa.Global: if g, ok := fr.globals[v]; ok { return g } // Create an external global. Globals for this package are defined // on entry to translatePackage, and have initialisers. llelemtyp := fr.llvmtypes.ToLLVM(deref(v.Type())) llglobal := llvm.AddGlobal(fr.module.Module, llelemtyp, v.String()) global := fr.NewValue(llglobal, v.Type()) fr.globals[v] = global return global } if value, ok := fr.env[v]; ok { return value } // Instructions are not necessarily visited before they are used (e.g. Phi // edges) so we must "backpatch": create a value with the resultant type, // and then replace it when we visit the instruction. if b, ok := fr.backpatch[v]; ok { return b } if fr.backpatch == nil { fr.backpatch = make(map[ssa.Value]*LLVMValue) } // Note: we must not create a constant here (e.g. Undef/ConstNull), as // it is not permissible to replace a constant with a non-constant. // We must create the value in its own standalone basic block, so we can // dispose of it after replacing. currBlock := fr.builder.GetInsertBlock() fr.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(currBlock.Parent(), "")) placeholder := fr.compiler.builder.CreatePHI(fr.llvmtypes.ToLLVM(v.Type()), "") fr.builder.SetInsertPointAtEnd(currBlock) value := fr.NewValue(placeholder, v.Type()) fr.backpatch[v] = value return value }
func (compiler *compiler) Compile(fset *token.FileSet, pkg *ast.Package, exprTypes map[ast.Expr]types.Type) (m *Module, err error) { // FIXME create a compilation state, rather than storing in 'compiler'. compiler.fileset = fset compiler.pkg = pkg compiler.initfuncs = make([]Value, 0) // Create a Builder, for building LLVM instructions. compiler.builder = llvm.GlobalContext().NewBuilder() defer compiler.builder.Dispose() // Create a TargetMachine from the OS & Arch. triple := fmt.Sprintf("%s-unknown-%s", getTripleArchName(compiler.targetArch), compiler.targetOs) var machine llvm.TargetMachine for target := llvm.FirstTarget(); target.C != nil && machine.C == nil; target = target.NextTarget() { if target.Name() == compiler.targetArch { machine = target.CreateTargetMachine(triple, "", "", llvm.CodeGenLevelDefault, llvm.RelocDefault, llvm.CodeModelDefault) defer machine.Dispose() } } if machine.C == nil { err = fmt.Errorf("Invalid target triple: %s", triple) return } // Create a Module, which contains the LLVM bitcode. Dispose it on panic, // otherwise we'll set a finalizer at the end. The caller may invoke // Dispose manually, which will render the finalizer a no-op. modulename := pkg.Name compiler.target = machine.TargetData() compiler.module = &Module{llvm.NewModule(modulename), modulename, false} compiler.module.SetTarget(triple) compiler.module.SetDataLayout(compiler.target.String()) defer func() { if e := recover(); e != nil { compiler.module.Dispose() panic(e) //err = e.(error) } }() compiler.types = NewTypeMap(compiler.module.Module, compiler.target, exprTypes) // Create a mapping from objects back to packages, so we can create the // appropriate symbol names. compiler.pkgmap = createPackageMap(pkg) // Compile each file in the package. for _, file := range pkg.Files { file.Scope.Outer = pkg.Scope compiler.filescope = file.Scope compiler.scope = file.Scope compiler.fixConstDecls(file) for _, decl := range file.Decls { compiler.VisitDecl(decl) } } // Define intrinsics for use by the runtime: malloc, free, memcpy, etc. compiler.defineRuntimeIntrinsics() // Create global constructors. // // XXX When imports are handled, we'll need to defer creating // llvm.global_ctors until we create an executable. This is // due to (a) imports having to be initialised before the // importer, and (b) LLVM having no specified order of // initialisation for ctors with the same priority. if len(compiler.initfuncs) > 0 { elttypes := []llvm.Type{ llvm.Int32Type(), llvm.PointerType( llvm.FunctionType(llvm.VoidType(), nil, false), 0)} ctortype := llvm.StructType(elttypes, false) ctors := make([]llvm.Value, len(compiler.initfuncs)) for i, fn := range compiler.initfuncs { struct_values := []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 1, false), fn.LLVMValue()} ctors[i] = llvm.ConstStruct(struct_values, false) } global_ctors_init := llvm.ConstArray(ctortype, ctors) global_ctors_var := llvm.AddGlobal( compiler.module.Module, global_ctors_init.Type(), "llvm.global_ctors") global_ctors_var.SetInitializer(global_ctors_init) global_ctors_var.SetLinkage(llvm.AppendingLinkage) } // Create debug metadata. compiler.createMetadata() return compiler.module, nil }
func (c *compiler) Resolve(obj *ast.Object) Value { if obj.Kind == ast.Pkg { return nil } else if obj.Kind == ast.Typ { return TypeValue{obj.Type.(types.Type)} } value, isvalue := (obj.Data).(Value) if isvalue { return value } switch obj.Kind { case ast.Con: if obj.Decl != nil { valspec := obj.Decl.(*ast.ValueSpec) c.VisitValueSpec(valspec, true) value = (obj.Data).(Value) } else if obj == types.Nil { return NilValue{c} } else { var typ types.Type switch x := obj.Type.(type) { case *types.Basic: typ = x case *types.Name: typ = x.Underlying.(*types.Basic) default: panic(fmt.Sprintf("unreachable (%T)", x)) } value = ConstValue{(obj.Data.(types.Const)), c, typ} obj.Data = value } case ast.Fun: var funcdecl *ast.FuncDecl if obj.Decl != nil { funcdecl = obj.Decl.(*ast.FuncDecl) } else { funcdecl = &ast.FuncDecl{ Name: &ast.Ident{Name: obj.Name, Obj: obj}, } } value = c.VisitFuncProtoDecl(funcdecl) obj.Data = value case ast.Var: switch x := (obj.Decl).(type) { case *ast.ValueSpec: c.VisitValueSpec(x, false) case *ast.Field: // No-op. Fields will be yielded for function // arg/recv/ret. We update the .Data field of the // object when we enter the function definition. if obj.Data == nil { panic("expected obj.Data value") } } // If it's an external variable, we'll need to create a global // value reference here. if obj.Data == nil { module := c.module.Module t := obj.Type.(types.Type) name := c.pkgmap[obj] + "." + obj.Name g := llvm.AddGlobal(module, c.types.ToLLVM(t), name) g.SetLinkage(llvm.AvailableExternallyLinkage) obj.Data = c.NewLLVMValue(g, t) } value = (obj.Data).(Value) } return value }
func (compiler *compiler) Compile(fset *token.FileSet, files []*ast.File, importpath string) (m *Module, err error) { // FIXME create a compilation state, rather than storing in 'compiler'. compiler.fileset = fset compiler.initfuncs = nil compiler.varinitfuncs = nil // If no import path is specified, or the package's // name (not path) is "main", then set the import // path to be the same as the package's name. if importpath == "" || files[0].Name.String() == "main" { importpath = files[0].Name.String() } // Type-check, and store object data. compiler.typeinfo.Types = make(map[ast.Expr]types.Type) compiler.typeinfo.Values = make(map[ast.Expr]exact.Value) compiler.typeinfo.Objects = make(map[*ast.Ident]types.Object) compiler.typeinfo.Implicits = make(map[ast.Node]types.Object) compiler.typeinfo.Selections = make(map[*ast.SelectorExpr]*types.Selection) compiler.objectdata = make(map[types.Object]*ObjectData) compiler.methodsets = make(map[types.Type]*methodset) compiler.exportedtypes = nil compiler.llvmtypes = NewLLVMTypeMap(compiler.target) pkg, err := compiler.typecheck(importpath, fset, files) if err != nil { return nil, err } compiler.pkg = pkg // Create a Module, which contains the LLVM bitcode. Dispose it on panic, // otherwise we'll set a finalizer at the end. The caller may invoke // Dispose manually, which will render the finalizer a no-op. modulename := importpath compiler.module = &Module{llvm.NewModule(modulename), modulename, false} compiler.module.SetTarget(compiler.TargetTriple) compiler.module.SetDataLayout(compiler.target.String()) defer func() { if e := recover(); e != nil { compiler.module.Dispose() panic(e) } }() // Create a struct responsible for mapping static types to LLVM types, // and to runtime/dynamic type values. var resolver Resolver = compiler compiler.FunctionCache = NewFunctionCache(compiler) compiler.types = NewTypeMap(compiler.llvmtypes, compiler.module.Module, importpath, compiler.FunctionCache, resolver) // Create a Builder, for building LLVM instructions. compiler.builder = newBuilder(compiler.types) defer compiler.builder.Dispose() compiler.debug_info = &llvm.DebugInfo{} // Compile each file in the package. for _, file := range files { compiler.compile_unit = &llvm.CompileUnitDescriptor{ Language: llvm.DW_LANG_Go, Path: llvm.FileDescriptor(fset.File(file.Pos()).Name()), Producer: LLGOProducer, Runtime: LLGORuntimeVersion, } compiler.pushDebugContext(&compiler.compile_unit.Path) for _, decl := range file.Decls { compiler.VisitDecl(decl) } compiler.popDebugContext() if len(compiler.debug_context) > 0 { log.Panicln(compiler.debug_context) } compiler.module.AddNamedMetadataOperand("llvm.dbg.cu", compiler.debug_info.MDNode(compiler.compile_unit)) } // Export runtime type information. compiler.exportRuntimeTypes() // Wrap "main.main" in a call to runtime.main. if importpath == "main" { err = compiler.createMainFunction() if err != nil { return nil, err } } else { var e = exporter{compiler: compiler} if err := e.Export(pkg); err != nil { return nil, err } } // Create global constructors. The initfuncs/varinitfuncs // slices are in the order of visitation; we generate the // list of constructors in the reverse order. // // The llgo linker will link modules in the order of // package dependency, i.e. if A requires B, then llgo-link // will link the modules in the order A, B. The "runtime" // package is always last. // // At program initialisation, the runtime initialisation // function (runtime.main) will invoke the constructors // in reverse order. var initfuncs [][]llvm.Value if compiler.varinitfuncs != nil { initfuncs = append(initfuncs, compiler.varinitfuncs) } if compiler.initfuncs != nil { initfuncs = append(initfuncs, compiler.initfuncs) } if initfuncs != nil { ctortype := llvm.PointerType(llvm.Int8Type(), 0) var ctors []llvm.Value var index int = 0 for _, initfuncs := range initfuncs { for _, fnptr := range initfuncs { name := fmt.Sprintf("__llgo.ctor.%s.%d", importpath, index) fnptr.SetName(name) fnptr = llvm.ConstBitCast(fnptr, ctortype) ctors = append(ctors, fnptr) index++ } } for i, n := 0, len(ctors); i < n/2; i++ { ctors[i], ctors[n-i-1] = ctors[n-i-1], ctors[i] } ctorsInit := llvm.ConstArray(ctortype, ctors) ctorsVar := llvm.AddGlobal(compiler.module.Module, ctorsInit.Type(), "runtime.ctors") ctorsVar.SetInitializer(ctorsInit) ctorsVar.SetLinkage(llvm.AppendingLinkage) } // Create debug metadata. //compiler.createMetadata() return compiler.module, nil }
// Create a constructor function which initialises a global. // TODO collapse all global inits into one init function? func (c *compiler) createGlobals(idents []*ast.Ident, values []ast.Expr, pkg string) { globals := make([]*LLVMValue, len(idents)) for i, ident := range idents { if ident.Name != "_" { t := ident.Obj.Type.(types.Type) llvmtyp := c.types.ToLLVM(t) gv := llvm.AddGlobal(c.module.Module, llvmtyp, pkg+"."+ident.Name) g := c.NewLLVMValue(gv, &types.Pointer{Base: t}).makePointee() globals[i] = g ident.Obj.Data = g } } if len(values) == 0 { for _, g := range globals { if g != nil { initializer := llvm.ConstNull(g.pointer.value.Type().ElementType()) g.pointer.value.SetInitializer(initializer) } } return } // FIXME Once we have constant folding, we can check first if the value is // a constant. For now we'll create a function and then erase it if the // computed value is a constant. if block := c.builder.GetInsertBlock(); !block.IsNil() { defer c.builder.SetInsertPointAtEnd(block) } fntype := &types.Func{} llvmfntype := c.types.ToLLVM(fntype).ElementType() fn := llvm.AddFunction(c.module.Module, "", llvmfntype) entry := llvm.AddBasicBlock(fn, "entry") c.builder.SetInsertPointAtEnd(entry) if len(values) == 1 && len(idents) > 1 { // Compound values are always non-constant. values := c.destructureExpr(values[0]) for i, ident := range idents { if globals[i] != nil { v := values[i].Convert(ident.Obj.Type.(types.Type)) gv := globals[i].pointer.value gv.SetInitializer(llvm.Undef(gv.Type().ElementType())) c.builder.CreateStore(v.LLVMValue(), gv) } } } else { allconst := true for i, expr := range values { if globals[i] != nil { gv := globals[i].pointer.value ident := idents[i] value := c.VisitExpr(expr) value = value.Convert(ident.Obj.Type.(types.Type)) _, isconst := value.(ConstValue) if isconst { gv.SetInitializer(value.LLVMValue()) } else { allconst = false gv.SetInitializer(llvm.Undef(gv.Type().ElementType())) c.builder.CreateStore(value.LLVMValue(), gv) } } } if allconst { fn.EraseFromParentAsFunction() fn = llvm.Value{nil} } } // FIXME order global ctors if !fn.IsNil() { c.builder.CreateRetVoid() fnvalue := c.NewLLVMValue(fn, fntype) c.varinitfuncs = append(c.varinitfuncs, fnvalue) } }
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)) }
// 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 (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 }