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 (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 }
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 (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 (c *compiler) VisitCompositeLit(lit *ast.CompositeLit) Value { typ := c.types.expr[lit] var valuemap map[interface{}]Value var valuelist []Value _, isstruct := types.Underlying(typ).(*types.Struct) if lit.Elts != nil { for _, elt := range lit.Elts { var value Value if kv, iskv := elt.(*ast.KeyValueExpr); iskv { value = c.VisitExpr(kv.Value) if valuemap == nil { valuemap = make(map[interface{}]Value) } var key interface{} if isstruct { key = kv.Key.(*ast.Ident).Name } else { key = c.VisitExpr(kv.Key) } valuemap[key] = value } else { value = c.VisitExpr(elt) valuelist = append(valuelist, value) } } } // For array/slice types, convert key:value to contiguous // values initialiser. switch types.Underlying(typ).(type) { case *types.Array, *types.Slice: if len(valuemap) > 0 { maxi := int64(-1) for key, _ := range valuemap { i := key.(ConstValue).Int64() if i < 0 { panic("array index must be non-negative integer constant") } else if i > maxi { maxi = i } } valuelist = make([]Value, maxi+1) for key, value := range valuemap { i := key.(ConstValue).Int64() valuelist[i] = value } } } origtyp := typ switch typ := types.Underlying(typ).(type) { case *types.Array: elttype := typ.Elt llvmelttype := c.types.ToLLVM(elttype) llvmvalues := make([]llvm.Value, typ.Len) for i := range llvmvalues { var value Value if i < len(valuelist) { value = valuelist[i] } if value == nil { llvmvalues[i] = llvm.ConstNull(llvmelttype) } else if _, ok := value.(ConstValue); ok || value.LLVMValue().IsConstant() { llvmvalues[i] = value.Convert(elttype).LLVMValue() } else { llvmvalues[i] = llvm.Undef(llvmelttype) } } array := llvm.ConstArray(llvmelttype, llvmvalues) for i, value := range valuelist { if llvmvalues[i].IsUndef() { value := value.Convert(elttype).LLVMValue() array = c.builder.CreateInsertValue(array, value, i, "") } } return c.NewLLVMValue(array, origtyp) case *types.Slice: ptr := c.createTypeMalloc(c.types.ToLLVM(typ)) eltType := c.types.ToLLVM(typ.Elt) arrayType := llvm.ArrayType(eltType, len(valuelist)) valuesPtr := c.createMalloc(llvm.SizeOf(arrayType)) valuesPtr = c.builder.CreateIntToPtr(valuesPtr, llvm.PointerType(eltType, 0), "") //valuesPtr = c.builder.CreateBitCast(valuesPtr, llvm.PointerType(valuesPtr.Type(), 0), "") // TODO check result of mallocs length := llvm.ConstInt(llvm.Int32Type(), uint64(len(valuelist)), false) c.builder.CreateStore(valuesPtr, c.builder.CreateStructGEP(ptr, 0, "")) // data c.builder.CreateStore(length, c.builder.CreateStructGEP(ptr, 1, "")) // len c.builder.CreateStore(length, c.builder.CreateStructGEP(ptr, 2, "")) // cap null := llvm.ConstNull(c.types.ToLLVM(typ.Elt)) for i, value := range valuelist { index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false) valuePtr := c.builder.CreateGEP(valuesPtr, []llvm.Value{index}, "") if value == nil { c.builder.CreateStore(null, valuePtr) } else { c.builder.CreateStore(value.Convert(typ.Elt).LLVMValue(), valuePtr) } } m := c.NewLLVMValue(ptr, &types.Pointer{Base: origtyp}) return m.makePointee() case *types.Struct: values := valuelist llvmtyp := c.types.ToLLVM(typ) ptr := c.createTypeMalloc(llvmtyp) bzero := c.NamedFunction("runtime.bzero", "func f(unsafe.Pointer, uintptr)") ptrintval := c.builder.CreatePtrToInt(ptr, c.target.IntPtrType(), "") args := []llvm.Value{ptrintval, llvm.SizeOf(llvmtyp)} c.builder.CreateCall(bzero, args, "") if valuemap != nil { for key, value := range valuemap { fieldName := key.(string) index := typ.FieldIndices[fieldName] for len(values) <= int(index) { values = append(values, nil) } values[index] = value } } for i, value := range values { if value != nil { elttype := typ.Fields[i].Type.(types.Type) llvm_value := value.Convert(elttype).LLVMValue() ptr := c.builder.CreateStructGEP(ptr, i, "") c.builder.CreateStore(llvm_value, ptr) } } m := c.NewLLVMValue(ptr, &types.Pointer{Base: origtyp}) return m.makePointee() case *types.Map: value := llvm.ConstNull(c.types.ToLLVM(typ)) // TODO initialise map return c.NewLLVMValue(value, origtyp) } panic(fmt.Sprint("Unhandled type kind: ", typ)) }
func (compiler *compiler) Compile(fset *token.FileSet, pkg *ast.Package, importpath string, exprTypes map[ast.Expr]types.Type) (m *Module, err error) { // FIXME I'd prefer if we didn't modify global state. Perhaps // we should always take a copy of types.Universe? defer func() { types.Universe.Lookup("true").Data = types.Const{true} types.Universe.Lookup("false").Data = types.Const{false} }() // FIXME create a compilation state, rather than storing in 'compiler'. compiler.fileset = fset compiler.pkg = pkg compiler.importpath = importpath compiler.initfuncs = nil compiler.varinitfuncs = nil // Create a Builder, for building LLVM instructions. compiler.builder = llvm.GlobalContext().NewBuilder() defer compiler.builder.Dispose() // 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.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) //err = e.(error) } }() // Create a mapping from objects back to packages, so we can create the // appropriate symbol names. compiler.pkgmap = createPackageMap(pkg, importpath) // 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, exprTypes, compiler.FunctionCache, resolver) // 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. // These could be defined in LLVM IR, and may be moved there later. if pkg.Name == "runtime" { compiler.defineRuntimeIntrinsics() } // Export runtime type information. if pkg.Name == "runtime" { compiler.exportBuiltinRuntimeTypes() } // Wrap "main.main" in a call to runtime.main. if pkg.Name == "main" { err = compiler.createMainFunction() if 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 [][]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.FunctionType(llvm.VoidType(), nil, false), 0) var ctors []llvm.Value var index int = 0 for _, initfuncs := range initfuncs { for _, fn := range initfuncs { fnval := fn.LLVMValue() fnval.SetName("__llgo.ctor." + compiler.importpath + strconv.Itoa(index)) ctors = append(ctors, fnval) 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 }
func (c *compiler) VisitCompositeLit(lit *ast.CompositeLit) (v *LLVMValue) { typ := c.types.expr[lit].Type var valuemap map[interface{}]Value var valuelist []Value if ptr, ok := typ.(*types.Pointer); ok { typ = ptr.Elem() defer func() { v = v.pointer }() } var isstruct, isarray, isslice, ismap bool switch typ.Underlying().(type) { case *types.Struct: isstruct = true case *types.Array: isarray = true case *types.Slice: isslice = true case *types.Map: ismap = true default: panic(fmt.Errorf("Unhandled type: %s", typ)) } if lit.Elts != nil { for i, elt := range lit.Elts { if kv, iskv := elt.(*ast.KeyValueExpr); iskv { if valuemap == nil { valuemap = make(map[interface{}]Value) } var key interface{} var elttyp types.Type switch { case isstruct: name := kv.Key.(*ast.Ident).Name key = name typ := typ.Underlying().(*types.Struct) elttyp = typ.Field(fieldIndex(typ, name)).Type case isarray: key = c.types.expr[kv.Key].Value typ := typ.Underlying().(*types.Array) elttyp = typ.Elem() case isslice: key = c.types.expr[kv.Key].Value typ := typ.Underlying().(*types.Slice) elttyp = typ.Elem() case ismap: key = c.VisitExpr(kv.Key) typ := typ.Underlying().(*types.Map) elttyp = typ.Elem() default: panic("unreachable") } c.convertUntyped(kv.Value, elttyp) valuemap[key] = c.VisitExpr(kv.Value) } else { switch { case isstruct: typ := typ.Underlying().(*types.Struct) c.convertUntyped(elt, typ.Field(i).Type) case isarray: typ := typ.Underlying().(*types.Array) c.convertUntyped(elt, typ.Elem()) case isslice: typ := typ.Underlying().(*types.Slice) c.convertUntyped(elt, typ.Elem()) } value := c.VisitExpr(elt) valuelist = append(valuelist, value) } } } // For array/slice types, convert key:value to contiguous // values initialiser. switch typ.Underlying().(type) { case *types.Array, *types.Slice: if len(valuemap) > 0 { var maxkey uint64 for key, _ := range valuemap { key, _ := exact.Uint64Val(key.(exact.Value)) if key > maxkey { maxkey = key } } valuelist = make([]Value, maxkey+1) for key, value := range valuemap { key, _ := exact.Uint64Val(key.(exact.Value)) valuelist[key] = value } } } origtyp := typ switch typ := typ.Underlying().(type) { case *types.Array: elttype := typ.Elem() llvmelttype := c.types.ToLLVM(elttype) llvmvalues := make([]llvm.Value, typ.Len()) for i := range llvmvalues { var value Value if i < len(valuelist) { value = valuelist[i] } if value == nil { llvmvalues[i] = llvm.ConstNull(llvmelttype) } else if value.LLVMValue().IsConstant() { llvmvalues[i] = value.Convert(elttype).LLVMValue() } else { llvmvalues[i] = llvm.Undef(llvmelttype) } } array := llvm.ConstArray(llvmelttype, llvmvalues) for i, value := range valuelist { if llvmvalues[i].IsUndef() { value := value.Convert(elttype).LLVMValue() array = c.builder.CreateInsertValue(array, value, i, "") } } return c.NewValue(array, origtyp) case *types.Slice: ptr := c.createTypeMalloc(c.types.ToLLVM(typ)) eltType := c.types.ToLLVM(typ.Elem()) arrayType := llvm.ArrayType(eltType, len(valuelist)) valuesPtr := c.createMalloc(llvm.SizeOf(arrayType)) valuesPtr = c.builder.CreateIntToPtr(valuesPtr, llvm.PointerType(eltType, 0), "") //valuesPtr = c.builder.CreateBitCast(valuesPtr, llvm.PointerType(valuesPtr.Type(), 0), "") length := llvm.ConstInt(c.types.inttype, uint64(len(valuelist)), false) c.builder.CreateStore(valuesPtr, c.builder.CreateStructGEP(ptr, 0, "")) // data c.builder.CreateStore(length, c.builder.CreateStructGEP(ptr, 1, "")) // len c.builder.CreateStore(length, c.builder.CreateStructGEP(ptr, 2, "")) // cap null := llvm.ConstNull(c.types.ToLLVM(typ.Elem())) for i, value := range valuelist { index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false) valuePtr := c.builder.CreateGEP(valuesPtr, []llvm.Value{index}, "") if value == nil { c.builder.CreateStore(null, valuePtr) } else { c.builder.CreateStore(value.Convert(typ.Elem()).LLVMValue(), valuePtr) } } m := c.NewValue(ptr, types.NewPointer(origtyp)) return m.makePointee() case *types.Struct: values := valuelist llvmtyp := c.types.ToLLVM(typ) ptr := c.createTypeMalloc(llvmtyp) if valuemap != nil { for key, value := range valuemap { index := fieldIndex(typ, key.(string)) for len(values) <= index { values = append(values, nil) } values[index] = value } } for i, value := range values { if value != nil { elttype := typ.Field(i).Type llvm_value := value.Convert(elttype).LLVMValue() ptr := c.builder.CreateStructGEP(ptr, i, "") c.builder.CreateStore(llvm_value, ptr) } } m := c.NewValue(ptr, types.NewPointer(origtyp)) return m.makePointee() case *types.Map: value := llvm.ConstNull(c.types.ToLLVM(typ)) // TODO initialise map return c.NewValue(value, origtyp) } panic(fmt.Sprint("Unhandled type kind: ", typ)) }
func (c *compiler) VisitCompositeLit(lit *ast.CompositeLit) Value { typ := c.GetType(lit.Type) var valuemap map[interface{}]Value var valuelist []Value _, isstruct := types.Underlying(typ).(*types.Struct) if lit.Elts != nil { for _, elt := range lit.Elts { var value Value if kv, iskv := elt.(*ast.KeyValueExpr); iskv { value = c.VisitExpr(kv.Value) if valuemap == nil { valuemap = make(map[interface{}]Value) } var key interface{} if isstruct { key = kv.Key.(*ast.Ident).Name } else { key = c.VisitExpr(kv.Key) } valuemap[key] = value } else { value = c.VisitExpr(elt) valuelist = append(valuelist, value) } } } // For array/slice types, convert key:value to contiguous // values initialiser. switch types.Underlying(typ).(type) { case *types.Array, *types.Slice: if len(valuemap) > 0 { maxi := int64(-1) for key, _ := range valuemap { i := key.(ConstValue).Int64() if i < 0 { panic("array index must be non-negative integer constant") } else if i > maxi { maxi = i } } valuelist = make([]Value, maxi+1) for key, value := range valuemap { i := key.(ConstValue).Int64() valuelist[i] = value } } } origtyp := typ switch typ := types.Underlying(typ).(type) { case *types.Array: typ.Len = uint64(len(valuelist)) elttype := typ.Elt llvm_values := make([]llvm.Value, typ.Len) for i, value := range valuelist { if value == nil { llvm_values[i] = llvm.ConstNull(c.types.ToLLVM(elttype)) } else { llvm_values[i] = value.Convert(elttype).LLVMValue() } } // TODO set non-const values after creating const array. return c.NewLLVMValue( llvm.ConstArray(c.types.ToLLVM(elttype), llvm_values), origtyp) case *types.Slice: ptr := c.builder.CreateMalloc(c.types.ToLLVM(typ), "") length := llvm.ConstInt(llvm.Int32Type(), uint64(len(valuelist)), false) valuesPtr := c.builder.CreateArrayMalloc(c.types.ToLLVM(typ.Elt), length, "") //valuesPtr = c.builder.CreateBitCast(valuesPtr, llvm.PointerType(valuesPtr.Type(), 0), "") // TODO check result of mallocs c.builder.CreateStore(valuesPtr, c.builder.CreateStructGEP(ptr, 0, "")) // data c.builder.CreateStore(length, c.builder.CreateStructGEP(ptr, 1, "")) // len c.builder.CreateStore(length, c.builder.CreateStructGEP(ptr, 2, "")) // cap null := llvm.ConstNull(c.types.ToLLVM(typ.Elt)) for i, value := range valuelist { index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false) valuePtr := c.builder.CreateGEP(valuesPtr, []llvm.Value{index}, "") if value == nil { c.builder.CreateStore(null, valuePtr) } else { c.builder.CreateStore(value.Convert(typ.Elt).LLVMValue(), valuePtr) } } m := c.NewLLVMValue(ptr, &types.Pointer{Base: origtyp}) return m.makePointee() case *types.Struct: values := valuelist struct_value := c.builder.CreateMalloc(c.types.ToLLVM(typ), "") if valuemap != nil { for key, value := range valuemap { fieldName := key.(string) index := typ.FieldIndices[fieldName] for len(values) <= int(index) { values = append(values, nil) } values[index] = value } } for i, value := range values { elttype := c.ObjGetType(typ.Fields[i]) var llvm_value llvm.Value if value == nil { llvm_value = llvm.ConstNull(c.types.ToLLVM(elttype)) } else { llvm_value = value.Convert(elttype).LLVMValue() } ptr := c.builder.CreateStructGEP(struct_value, i, "") c.builder.CreateStore(llvm_value, ptr) } m := c.NewLLVMValue(struct_value, &types.Pointer{Base: origtyp}) return m.makePointee() case *types.Map: value := llvm.ConstNull(c.types.ToLLVM(typ)) // TODO initialise map return c.NewLLVMValue(value, origtyp) } panic(fmt.Sprint("Unhandled type kind: ", typ)) }
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 // Type-check, and store object data. compiler.objects = make(map[*ast.Ident]types.Object) compiler.objectdata = make(map[types.Object]*ObjectData) compiler.methodsets = make(map[types.Type]*methodset) compiler.llvmtypes = NewLLVMTypeMap(compiler.target) pkg, exprtypes, err := compiler.typecheck(importpath, fset, files) if err != nil { return nil, err } compiler.pkg = pkg importpath = pkgpath(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, exprtypes, compiler.FunctionCache, resolver) // Create a Builder, for building LLVM instructions. compiler.builder = newBuilder(compiler.types) defer compiler.builder.Dispose() // Compile each file in the package. for _, file := range files { for _, decl := range file.Decls { compiler.VisitDecl(decl) } } // Define intrinsics for use by the runtime: malloc, free, memcpy, etc. // These could be defined in LLVM IR, and may be moved there later. if importpath == "runtime" { compiler.defineRuntimeIntrinsics() } // Export runtime type information. if importpath == "runtime" { compiler.exportBuiltinRuntimeTypes() } // Wrap "main.main" in a call to runtime.main. if importpath == "main" { err = compiler.createMainFunction() if 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 }
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 (compiler *compiler) Compile(fset *token.FileSet, pkg *ast.Package, importpath string, exprTypes map[ast.Expr]types.Type) (m *Module, err error) { // FIXME I'd prefer if we didn't modify global state. Perhaps // we should always take a copy of types.Universe? defer func() { types.Universe.Lookup("true").Data = types.Const{true} types.Universe.Lookup("false").Data = types.Const{false} }() // FIXME create a compilation state, rather than storing in 'compiler'. compiler.fileset = fset compiler.pkg = pkg compiler.importpath = importpath compiler.initfuncs = nil compiler.varinitfuncs = nil // Create a Builder, for building LLVM instructions. compiler.builder = llvm.GlobalContext().NewBuilder() defer compiler.builder.Dispose() // 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.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) //err = e.(error) } }() // Create a mapping from objects back to packages, so we can create the // appropriate symbol names. compiler.pkgmap = createPackageMap(pkg, importpath) // 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, exprTypes, compiler.FunctionCache, resolver) // 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. // These could be defined in LLVM IR, and may be moved there later. if pkg.Name == "runtime" { compiler.defineRuntimeIntrinsics() } // Export runtime type information. if pkg.Name == "runtime" { compiler.exportBuiltinRuntimeTypes() } // Create global constructors. The initfuncs/varinitfuncs // slices are in the order of visitation, and that is how // their priorities are assigned. // // The llgo linker (llgo-link) is responsible for reordering // global constructors according to package dependency order. var initfuncs [][]Value if compiler.varinitfuncs != nil { initfuncs = append(initfuncs, compiler.varinitfuncs) } if compiler.initfuncs != nil { initfuncs = append(initfuncs, compiler.initfuncs) } if initfuncs != nil { elttypes := []llvm.Type{llvm.Int32Type(), llvm.PointerType(llvm.FunctionType(llvm.VoidType(), nil, false), 0)} ctortype := llvm.StructType(elttypes, false) var ctors []llvm.Value var priority uint64 = 1 for _, initfuncs := range initfuncs { for _, fn := range initfuncs { priorityval := llvm.ConstInt(llvm.Int32Type(), uint64(priority), false) struct_values := []llvm.Value{priorityval, fn.LLVMValue()} ctors = append(ctors, llvm.ConstStruct(struct_values, false)) priority++ } } 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 (compiler *compiler) Compile(fset *token.FileSet, pkg *ast.Package, importpath string, 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.importpath = importpath compiler.initfuncs = nil compiler.varinitfuncs = nil // Create a Builder, for building LLVM instructions. compiler.builder = llvm.GlobalContext().NewBuilder() defer compiler.builder.Dispose() // Create a TargetMachine from the OS & Arch. triple := compiler.GetTargetTriple() 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) } }() // Create a mapping from objects back to packages, so we can create the // appropriate symbol names. compiler.pkgmap = createPackageMap(pkg, importpath) // Create a struct responsible for mapping static types to LLVM types, // and to runtime/dynamic type values. var resolver Resolver = compiler llvmtypemap := NewLLVMTypeMap(compiler.module.Module, compiler.target) compiler.FunctionCache = NewFunctionCache(compiler) compiler.types = NewTypeMap(llvmtypemap, importpath, exprTypes, compiler.FunctionCache, compiler.pkgmap, resolver) // 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. // These could be defined in LLVM IR, and may be moved there later. if pkg.Name == "runtime" { compiler.defineRuntimeIntrinsics() } // Export runtime type information. if pkg.Name == "runtime" { compiler.exportBuiltinRuntimeTypes() } // 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. var initfuncs [][]Value if compiler.varinitfuncs != nil { initfuncs = append(initfuncs, compiler.varinitfuncs) } if compiler.initfuncs != nil { initfuncs = append(initfuncs, compiler.initfuncs) } if initfuncs != nil { elttypes := []llvm.Type{llvm.Int32Type(), llvm.PointerType(llvm.FunctionType(llvm.VoidType(), nil, false), 0)} ctortype := llvm.StructType(elttypes, false) var ctors []llvm.Value var priority uint64 for _, initfuncs := range initfuncs { for _, fn := range initfuncs { priorityval := llvm.ConstInt(llvm.Int32Type(), uint64(priority), false) struct_values := []llvm.Value{priorityval, fn.LLVMValue()} ctors = append(ctors, llvm.ConstStruct(struct_values, false)) priority++ } } 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 (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 }