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 }
func reorderGlobalConstructors(m llvm.Module) error { ctors := m.NamedGlobal("llvm.global_ctors") if ctors.IsNil() { // No global constructors. return nil } init := ctors.Initializer() arraylength := init.Type().ArrayLength() zeroindex := []uint32{0} // The constructors are ordered within each package, but the packages // are in reverse order. We must go backwards through the constructors, // reassigning priorities. ceiling, npackagectors := -1, -1 for i := arraylength - 1; i >= 0; i-- { indices := []uint32{uint32(i)} ctor := llvm.ConstExtractValue(init, indices) priority := int(llvm.ConstExtractValue(ctor, zeroindex).ZExtValue()) if npackagectors == -1 { ceiling = arraylength - (i + 1) + priority npackagectors = priority } newpriority := ceiling - (npackagectors - priority) newpriorityvalue := llvm.ConstInt(llvm.Int32Type(), uint64(newpriority), false) ctor = llvm.ConstInsertValue(ctor, newpriorityvalue, zeroindex) if priority == 1 { npackagectors = -1 } init = llvm.ConstInsertValue(init, ctor, indices) } ctors.SetInitializer(init) return nil }
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}) _, path := tm.qualifiedName(n) 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, 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 } methodsSliceType := tm.runtimeUncommonType.StructElementTypes()[2] methodsSlice := tm.makeSlice(methods, methodsSliceType) uncommonTypeInit = llvm.ConstInsertValue(uncommonTypeInit, methodsSlice, []uint32{2}) return uncommonTypeInit }
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 }
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 }
func (c *compiler) VisitFuncDecl(f *ast.FuncDecl) Value { fn := c.Resolve(f.Name).(*LLVMValue) attributes := parseAttributes(f.Doc) for _, attr := range attributes { attr.Apply(fn) } if f.Body == nil { return fn } var paramVars []*types.Var ftyp := fn.Type().(*types.Signature) if recv := ftyp.Recv(); recv != nil { paramVars = append(paramVars, recv) } if ftyp.Params != nil { ftyp.Params().ForEach(func(p *types.Var) { paramVars = append(paramVars, p) }) } paramVarsTuple := types.NewTuple(paramVars...) c.buildFunction(fn, nil, paramVarsTuple, ftyp.Results(), f.Body, ftyp.IsVariadic()) if f.Recv == nil && f.Name.Name == "init" { // Is it an 'init' function? Then record it. fnptr := llvm.ConstExtractValue(fn.value, []uint32{0}) c.initfuncs = append(c.initfuncs, fnptr) } return fn }
func (a llvmAttribute) Apply(v Value) { if _, isfunc := v.Type().(*types.Signature); isfunc { fn := v.LLVMValue() fn = llvm.ConstExtractValue(fn, []uint32{0}) fn.AddFunctionAttr(llvm.Attribute(a)) } else { v.LLVMValue().AddAttribute(llvm.Attribute(a)) } }
func (a nameAttribute) Apply(v Value) { if _, isfunc := v.Type().(*types.Signature); isfunc { fn := v.LLVMValue() fn = llvm.ConstExtractValue(fn, []uint32{0}) fn.SetName(string(a)) } else { global := v.(*LLVMValue).pointer.value global.SetName(string(a)) } }
func (c *compiler) createFunctionMetadata(f *ast.FuncDecl, fn *LLVMValue) llvm.DebugDescriptor { if len(c.debug_context) == 0 { return nil } file := c.fileset.File(f.Pos()) fnptr := fn.value fun := fnptr.IsAFunction() if fun.IsNil() { fnptr = llvm.ConstExtractValue(fn.value, []uint32{0}) } meta := &llvm.SubprogramDescriptor{ Name: fnptr.Name(), DisplayName: f.Name.Name, Path: llvm.FileDescriptor(file.Name()), Line: uint32(file.Line(f.Pos())), ScopeLine: uint32(file.Line(f.Body.Pos())), Context: &llvm.ContextDescriptor{llvm.FileDescriptor(file.Name())}, Function: fnptr} var result types.Type var metaparams []llvm.DebugDescriptor if ftyp, ok := fn.Type().(*types.Signature); ok { if recv := ftyp.Recv(); recv != nil { metaparams = append(metaparams, c.tollvmDebugDescriptor(recv.Type())) } if ftyp.Params() != nil { for i := 0; i < ftyp.Params().Len(); i++ { p := ftyp.Params().At(i) metaparams = append(metaparams, c.tollvmDebugDescriptor(p.Type())) } } if ftyp.Results() != nil { result = ftyp.Results().At(0).Type() // TODO: what to do with multiple returns? for i := 1; i < ftyp.Results().Len(); i++ { p := ftyp.Results().At(i) metaparams = append(metaparams, c.tollvmDebugDescriptor(p.Type())) } } } meta.Type = llvm.NewSubroutineCompositeType( c.tollvmDebugDescriptor(result), metaparams, ) // compile unit is the first context object pushed compileUnit := c.debug_context[0].(*llvm.CompileUnitDescriptor) compileUnit.Subprograms = append(compileUnit.Subprograms, meta) return meta }
func (c *FunctionCache) NamedFunction(name string, signature string) llvm.Value { f, _ := c.functions[name+":"+signature] if !f.IsNil() { return f } if strings.HasPrefix(name, c.module.Name+".") { obj := c.pkg.Scope().Lookup(name[len(c.module.Name)+1:]) if obj == nil { panic("Missing function: " + name) } value := c.Resolve(c.objectdata[obj].Ident) f = llvm.ConstExtractValue(value.LLVMValue(), []uint32{0}) } else { fset := token.NewFileSet() code := `package runtime;import("unsafe");` + signature + `{panic("")}` file, err := parser.ParseFile(fset, "", code, 0) if err != nil { panic(err) } // Parse the runtime package, since we may need to refer to // its types. Can't be cached, because type-checking can't // be done twice on the AST. buildpkg, err := build.Import("github.com/axw/llgo/pkg/runtime", "", 0) if err != nil { panic(err) } // All types visible to the compiler are in "types.go". runtimefiles := []string{path.Join(buildpkg.Dir, "types.go")} files, err := parseFiles(fset, runtimefiles) if err != nil { panic(err) } files = append(files, file) _, _, err = c.typecheck("runtime", fset, files) if err != nil { panic(err) } fdecl := file.Decls[len(file.Decls)-1].(*ast.FuncDecl) ftype := c.objects[fdecl.Name].Type().(*types.Signature) llvmfntyp := c.types.ToLLVM(ftype).StructElementTypes()[0].ElementType() f = llvm.AddFunction(c.module.Module, name, llvmfntyp) } c.functions[name+":"+signature] = f return f }
func (c *FunctionCache) NamedFunction(name string, signature string) llvm.Value { f, _ := c.functions[name+":"+signature] if !f.IsNil() { return f } if strings.HasPrefix(name, c.module.Name+".") { obj := c.pkg.Scope().Lookup(name[len(c.module.Name)+1:]) if obj == nil { panic("Missing function: " + name) } value := c.Resolve(c.objectdata[obj].Ident) f = llvm.ConstExtractValue(value.LLVMValue(), []uint32{0}) } else { if c.runtimetypespkg == nil { // Parse the runtime package, since we may need to refer to // its types. buildpkg, err := build.Import("github.com/axw/llgo/pkg/runtime", "", 0) if err != nil { panic(err) } // All types visible to the compiler are in "types.go". runtimefiles := []string{path.Join(buildpkg.Dir, "types.go")} fset := token.NewFileSet() files, err := parseFiles(fset, runtimefiles) if err != nil { panic(err) } c.runtimetypespkg, err = c.typecheck("runtime", fset, files) if err != nil { panic(err) } } pkg := c.runtimetypespkg scope := pkg.Scope().Child(0) ftype, _, err := types.Eval(signature+"{panic()}", pkg, scope) if err != nil { panic(err) } llvmfntyp := c.types.ToLLVM(ftype).StructElementTypes()[0].ElementType() f = llvm.AddFunction(c.module.Module, name, llvmfntyp) } c.functions[name+":"+signature] = f return f }
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 }
func (a nameAttribute) Apply(v Value) { if _, isfunc := v.Type().(*types.Signature); isfunc { fn := v.LLVMValue() fn = llvm.ConstExtractValue(fn, []uint32{0}) name := string(a) curr := fn.GlobalParent().NamedFunction(name) if !curr.IsNil() && curr != fn { if curr.BasicBlocksCount() != 0 { panic(fmt.Errorf("Want to take the name %s from a function that has a body!", name)) } curr.SetName(name + "_llgo_replaced") curr.ReplaceAllUsesWith(fn) } fn.SetName(name) } else { global := v.(*LLVMValue).pointer.value global.SetName(string(a)) } }
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 }
func (c *compiler) VisitFuncDecl(f *ast.FuncDecl) Value { fn := c.Resolve(f.Name).(*LLVMValue) attributes := parseAttributes(f.Doc) for _, attr := range attributes { attr.Apply(fn) } if f.Body == nil { return fn } var paramVars []*types.Var ftyp := fn.Type().(*types.Signature) if recv := ftyp.Recv(); recv != nil { paramVars = append(paramVars, recv) } if ftyp.Params() != nil { for i := 0; i < ftyp.Params().Len(); i++ { p := ftyp.Params().At(i) paramVars = append(paramVars, p) } } c.pushDebugContext(c.createFunctionMetadata(f, fn)) defer c.popDebugContext() c.setDebugLine(f.Pos()) paramVarsTuple := types.NewTuple(paramVars...) c.buildFunction(fn, nil, paramVarsTuple, ftyp.Results(), f.Body) if f.Recv == nil && f.Name.Name == "init" { // Is it an 'init' function? Then record it. fnptr := llvm.ConstExtractValue(fn.value, []uint32{0}) c.initfuncs = append(c.initfuncs, fnptr) } return fn }
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) 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 }
// indirectFunction creates an indirect function from a // given function and arguments, suitable for use with // "defer" and "go". func (c *compiler) indirectFunction(fn *LLVMValue, args []*LLVMValue) *LLVMValue { nilarytyp := types.NewSignature(nil, nil, nil, nil, false) if len(args) == 0 { val := fn.LLVMValue() ptr := c.builder.CreateExtractValue(val, 0, "") ctx := c.builder.CreateExtractValue(val, 1, "") fnval := llvm.Undef(c.types.ToLLVM(nilarytyp)) ptr = c.builder.CreateBitCast(ptr, fnval.Type().StructElementTypes()[0], "") ctx = c.builder.CreateBitCast(ctx, fnval.Type().StructElementTypes()[1], "") fnval = c.builder.CreateInsertValue(fnval, ptr, 0, "") fnval = c.builder.CreateInsertValue(fnval, ctx, 1, "") return c.NewValue(fnval, nilarytyp) } // Check if function pointer or context pointer is global/null. fnval := fn.LLVMValue() fnptr := fnval var nctx int var fnctx llvm.Value var fnctxindex uint64 var globalfn bool if fnptr.Type().TypeKind() == llvm.StructTypeKind { fnptr = c.builder.CreateExtractValue(fnval, 0, "") fnctx = c.builder.CreateExtractValue(fnval, 1, "") globalfn = !fnptr.IsAFunction().IsNil() if !globalfn { nctx++ } if !fnctx.IsNull() { fnctxindex = uint64(nctx) nctx++ } } else { // We've got a raw global function pointer. Convert to <ptr,ctx>. fnval = llvm.ConstNull(c.types.ToLLVM(fn.Type())) fnval = llvm.ConstInsertValue(fnval, fnptr, []uint32{0}) fn = c.NewValue(fnval, fn.Type()) fnctx = llvm.ConstExtractValue(fnval, []uint32{1}) globalfn = true } i8ptr := llvm.PointerType(llvm.Int8Type(), 0) llvmargs := make([]llvm.Value, len(args)+nctx) llvmargtypes := make([]llvm.Type, len(args)+nctx) for i, arg := range args { llvmargs[i+nctx] = arg.LLVMValue() llvmargtypes[i+nctx] = llvmargs[i+nctx].Type() } if !globalfn { llvmargtypes[0] = fnptr.Type() llvmargs[0] = fnptr } if !fnctx.IsNull() { llvmargtypes[fnctxindex] = fnctx.Type() llvmargs[fnctxindex] = fnctx } // TODO(axw) investigate an option for go statements // to allocate argument structure on the stack in the // initiator, and block until the spawned goroutine // has loaded the arguments from it. structtyp := llvm.StructType(llvmargtypes, false) argstruct := c.createTypeMalloc(structtyp) for i, llvmarg := range llvmargs { argptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(i), false)}, "") c.builder.CreateStore(llvmarg, argptr) } // Create a function that will take a pointer to a structure of the type // defined above, or no parameters if there are none to pass. fntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{argstruct.Type()}, false) indirectfn := llvm.AddFunction(c.module.Module, "", fntype) i8argstruct := c.builder.CreateBitCast(argstruct, i8ptr, "") currblock := c.builder.GetInsertBlock() c.builder.SetInsertPointAtEnd(llvm.AddBasicBlock(indirectfn, "entry")) argstruct = indirectfn.Param(0) newargs := make([]*LLVMValue, len(args)) for i := range llvmargs[nctx:] { argptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(i+nctx), false)}, "") newargs[i] = c.NewValue(c.builder.CreateLoad(argptr, ""), args[i].Type()) } // Unless we've got a global function, extract the // function pointer from the context. if !globalfn { fnval = llvm.Undef(fnval.Type()) fnptrptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 0, false)}, "") fnptr = c.builder.CreateLoad(fnptrptr, "") fnval = c.builder.CreateInsertValue(fnval, fnptr, 0, "") } if !fnctx.IsNull() { fnctxptr := c.builder.CreateGEP(argstruct, []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), fnctxindex, false)}, "") fnctx = c.builder.CreateLoad(fnctxptr, "") fnval = c.builder.CreateInsertValue(fnval, fnctx, 1, "") fn = c.NewValue(fnval, fn.Type()) } c.createCall(fn, newargs) // Indirect function calls' return values are always ignored. c.builder.CreateRetVoid() c.builder.SetInsertPointAtEnd(currblock) fnval = llvm.Undef(c.types.ToLLVM(nilarytyp)) indirectfn = c.builder.CreateBitCast(indirectfn, fnval.Type().StructElementTypes()[0], "") fnval = c.builder.CreateInsertValue(fnval, indirectfn, 0, "") fnval = c.builder.CreateInsertValue(fnval, i8argstruct, 1, "") fn = c.NewValue(fnval, nilarytyp) return fn }
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 }
// buildFunction takes a function Value, a list of parameters, and a body, // and generates code for the function. func (c *compiler) buildFunction(f *LLVMValue, context, params, results *types.Tuple, body *ast.BlockStmt) { if currblock := c.builder.GetInsertBlock(); !currblock.IsNil() { defer c.builder.SetInsertPointAtEnd(currblock) } llvm_fn := llvm.ConstExtractValue(f.LLVMValue(), []uint32{0}) entry := llvm.AddBasicBlock(llvm_fn, "entry") c.builder.SetInsertPointAtEnd(entry) // For closures, context is the captured context values. var paramoffset int if context != nil { paramoffset++ // Store the existing values. We're going to temporarily // replace the values with offsets into the context param. oldvalues := make([]*LLVMValue, context.Len()) for i := range oldvalues { v := context.At(i) oldvalues[i] = c.objectdata[v].Value } defer func() { for i := range oldvalues { v := context.At(i) c.objectdata[v].Value = oldvalues[i] } }() // The context parameter is a pointer to a struct // whose elements are pointers to captured values. arg0 := llvm_fn.Param(0) for i := range oldvalues { v := context.At(i) argptr := c.builder.CreateStructGEP(arg0, i, "") argptr = c.builder.CreateLoad(argptr, "") ptrtyp := oldvalues[i].pointer.Type() newvalue := c.NewValue(argptr, ptrtyp) c.objectdata[v].Value = newvalue.makePointee() } } // Bind receiver, arguments and return values to their // identifiers/objects. We'll store each parameter on the stack so // they're addressable. nparams := int(params.Len()) for i := 0; i < nparams; i++ { v := params.At(i) name := v.Name() if !isBlank(name) { value := llvm_fn.Param(i + paramoffset) c.newArgStackVar(i+1, f, v, value, name) } } funcstate := &function{LLVMValue: f, results: results} c.functions.push(funcstate) hasdefer := hasDefer(funcstate, body) // Allocate space on the stack for named results. for i := 0; i < results.Len(); i++ { v := results.At(i) name := v.Name() allocstack := !isBlank(name) if !allocstack && hasdefer { c.objectdata[v] = &ObjectData{} allocstack = true } if allocstack { typ := v.Type() llvmtyp := c.types.ToLLVM(typ) c.newStackVar(f, v, llvm.ConstNull(llvmtyp), name) } } // Create the function body. if hasdefer { c.makeDeferBlock(funcstate, body) } c.VisitBlockStmt(body, false) c.functions.pop() c.setDebugLine(body.End()) // If the last instruction in the function is not a terminator, then // we either have unreachable code or a missing optional return statement // (the latter case is allowable only for functions without results). // // Use GetInsertBlock rather than LastBasicBlock, since the // last basic block might actually be a "defer" block. last := c.builder.GetInsertBlock() if in := last.LastInstruction(); in.IsNil() || in.IsATerminatorInst().IsNil() { c.builder.SetInsertPointAtEnd(last) if results.Len() == 0 { if funcstate.deferblock.IsNil() { c.builder.CreateRetVoid() } else { c.builder.CreateBr(funcstate.deferblock) } } else { c.builder.CreateUnreachable() } } }