func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0)) const eqalgsig = "func(uintptr, unsafe.Pointer, unsafe.Pointer) bool" var equalAlg llvm.Value switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.String: equalAlg = tm.functions.NamedFunction("runtime.streqalg", eqalgsig) case types.Float32: equalAlg = tm.functions.NamedFunction("runtime.f32eqalg", eqalgsig) case types.Float64: equalAlg = tm.functions.NamedFunction("runtime.f64eqalg", eqalgsig) case types.Complex64: equalAlg = tm.functions.NamedFunction("runtime.c64eqalg", eqalgsig) case types.Complex128: equalAlg = tm.functions.NamedFunction("runtime.c128eqalg", eqalgsig) } } if equalAlg.IsNil() { equalAlg = tm.functions.NamedFunction("runtime.memequal", eqalgsig) } elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg} return llvm.ConstStruct(elems, false) }
func (v ConstValue) LLVMValue() llvm.Value { typ := types.Underlying(v.Type()) switch typ { case types.Int, types.Uint: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) // TODO 32/64bit (probably wait for gc) //int_val := v.Val.(*big.Int) //if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 { // panic(fmt.Sprint("const ", int_val, " overflows int")) //} //return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true) case types.Uint: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int8: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true) case types.Uint8, types.Byte: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false) case types.Int16: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true) case types.Uint16: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false) case types.Int32, types.Rune: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) case types.Uint32: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int64: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Uint64: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Float32: return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64())) case types.Float64: return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64())) case types.UnsafePointer, types.Uintptr: inttype := v.compiler.target.IntPtrType() return llvm.ConstInt(inttype, uint64(v.Int64()), false) case types.String: strval := (v.Val).(string) ptr := v.compiler.builder.CreateGlobalStringPtr(strval, "") len_ := llvm.ConstInt(llvm.Int32Type(), uint64(len(strval)), false) return llvm.ConstStruct([]llvm.Value{ptr, len_}, false) case types.Bool: if v := v.Val.(bool); v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) } panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind)) }
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0)) equalAlg := tm.functions.NamedFunction("runtime.memequal", "func f(uintptr, unsafe.Pointer, unsafe.Pointer) bool") elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg} return llvm.ConstStruct(elems, false) }
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0)) equalAlg := llvm.ConstNull(llvm.PointerType(tm.equalAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0)) elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg} return llvm.ConstStruct(elems, false) }
// 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) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.alg.hashAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.alg.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.alg.copyAlgFunctionType, 0)) equalAlg := tm.alg.eqalg(t) elems := []llvm.Value{ AlgorithmHash: hashAlg, AlgorithmEqual: equalAlg, AlgorithmPrint: printAlg, AlgorithmCopy: copyAlg, } return llvm.ConstStruct(elems, false) }
func (tm *TypeMap) makeAlgorithmTable(t types.Type) llvm.Value { // TODO set these to actual functions. hashAlg := llvm.ConstNull(llvm.PointerType(tm.hashAlgFunctionType, 0)) printAlg := llvm.ConstNull(llvm.PointerType(tm.printAlgFunctionType, 0)) copyAlg := llvm.ConstNull(llvm.PointerType(tm.copyAlgFunctionType, 0)) equalAlgName := "runtime.memequal" equalAlg := tm.module.NamedFunction(equalAlgName) if equalAlg.IsNil() { equalAlg = llvm.AddFunction( tm.module, equalAlgName, tm.equalAlgFunctionType) } elems := []llvm.Value{hashAlg, equalAlg, printAlg, copyAlg} return llvm.ConstStruct(elems, false) }
// convertI2I converts an interface to another interface. func (v *LLVMValue) convertI2I(iface *types.Interface) Value { builder := v.compiler.builder src_typ := v.Type() vptr := v.pointer.LLVMValue() src_typ = src_typ.(*types.Name).Underlying iface_struct_type := v.compiler.types.ToLLVM(iface) element_types := iface_struct_type.StructElementTypes() iface_elements := make([]llvm.Value, len(element_types)) for i, _ := range iface_elements { iface_elements[i] = llvm.ConstNull(element_types[i]) } iface_struct := llvm.ConstStruct(iface_elements, false) receiver := builder.CreateLoad(builder.CreateStructGEP(vptr, 0, ""), "") iface_struct = builder.CreateInsertValue(iface_struct, receiver, 0, "") // TODO check whether the functions in the struct take // value or pointer receivers. // TODO handle dynamic interface conversion (non-subset). methods := src_typ.(*types.Interface).Methods for i, m := range iface.Methods { // TODO make this loop linear by iterating through the // interface methods and type methods together. mi := sort.Search(len(methods), func(i int) bool { return methods[i].Name >= m.Name }) if mi >= len(methods) || methods[mi].Name != m.Name { panic("Failed to locate method: " + m.Name) } method := builder.CreateStructGEP(vptr, mi+2, "") iface_struct = builder.CreateInsertValue( iface_struct, builder.CreateLoad(method, ""), i+2, "") } return v.compiler.NewLLVMValue(iface_struct, iface) }
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 }
// convertV2I converts a value to an interface. func (v *LLVMValue) convertV2I(iface *types.Interface) Value { // TODO deref indirect value, then use 'pointer' as pointer value. var srcname *types.Name srctyp := v.Type() if name, isname := srctyp.(*types.Name); isname { srcname = name srctyp = name.Underlying } isptr := false if p, fromptr := srctyp.(*types.Pointer); fromptr { isptr = true srctyp = p.Base if name, isname := srctyp.(*types.Name); isname { srcname = name srctyp = name.Underlying } } iface_struct_type := v.compiler.types.ToLLVM(iface) element_types := iface_struct_type.StructElementTypes() iface_elements := make([]llvm.Value, len(element_types)) for i, _ := range iface_elements { iface_elements[i] = llvm.ConstNull(element_types[i]) } iface_struct := llvm.ConstStruct(iface_elements, false) builder := v.compiler.builder var ptr llvm.Value if isptr { ptr = v.LLVMValue() } else { // If the value fits exactly in a pointer, then we can just // bitcast it. Otherwise we need to malloc, and create a shim // function to load the receiver. lv := v.LLVMValue() c := v.compiler ptrsize := c.target.PointerSize() if c.target.TypeStoreSize(lv.Type()) <= uint64(ptrsize) { bits := c.target.TypeSizeInBits(lv.Type()) if bits > 0 { lv = builder.CreateBitCast(lv, llvm.IntType(int(bits)), "") ptr = builder.CreateIntToPtr(lv, element_types[0], "") } else { ptr = llvm.ConstNull(element_types[0]) } } else { ptr = builder.CreateMalloc(v.compiler.types.ToLLVM(srctyp), "") builder.CreateStore(lv, ptr) // TODO signal that shim functions are required. Probably later // we'll have the CallExpr handler pick out the type, and check // if the receiver is a pointer or a value type, and load as // necessary. } } ptr = builder.CreateBitCast(ptr, element_types[0], "") iface_struct = builder.CreateInsertValue(iface_struct, ptr, 0, "") var runtimeType llvm.Value if srcname != nil { runtimeType = v.compiler.types.ToRuntime(srcname) } else { runtimeType = v.compiler.types.ToRuntime(srctyp) } runtimeType = builder.CreateBitCast(runtimeType, element_types[1], "") iface_struct = builder.CreateInsertValue(iface_struct, runtimeType, 1, "") // TODO assert either source is a named type (or pointer to), or the // interface has an empty methodset. if srcname != nil { // TODO check whether the functions in the struct take // value or pointer receivers. // Look up the method by name. methods := srcname.Methods for i, m := range iface.Methods { // TODO make this loop linear by iterating through the // interface methods and type methods together. mi := sort.Search(len(methods), func(i int) bool { return methods[i].Name >= m.Name }) if mi >= len(methods) || methods[mi].Name != m.Name { panic("Failed to locate method: " + m.Name) } method_obj := methods[mi] method := v.compiler.Resolve(method_obj).(*LLVMValue) llvm_value := method.LLVMValue() llvm_value = builder.CreateBitCast( llvm_value, element_types[i+2], "") iface_struct = builder.CreateInsertValue( iface_struct, llvm_value, i+2, "") } } return v.compiler.NewLLVMValue(iface_struct, iface) }
func (v ConstValue) LLVMValue() llvm.Value { typ := types.Underlying(v.Type()) if name, ok := typ.(*types.Name); ok { typ = name.Underlying } switch typ.(*types.Basic).Kind { case types.IntKind, types.UintKind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) // TODO 32/64bit (probably wait for gc) //int_val := v.Val.(*big.Int) //if int_val.Cmp(maxBigInt32) > 0 || int_val.Cmp(minBigInt32) < 0 { // panic(fmt.Sprint("const ", int_val, " overflows int")) //} //return llvm.ConstInt(v.compiler.target.IntPtrType(), uint64(v.Int64()), true) case types.Int8Kind: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), true) case types.Uint8Kind: return llvm.ConstInt(llvm.Int8Type(), uint64(v.Int64()), false) case types.Int16Kind: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), true) case types.Uint16Kind: return llvm.ConstInt(llvm.Int16Type(), uint64(v.Int64()), false) case types.Int32Kind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), true) case types.Uint32Kind: return llvm.ConstInt(llvm.Int32Type(), uint64(v.Int64()), false) case types.Int64Kind: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), true) case types.Uint64Kind: return llvm.ConstInt(llvm.Int64Type(), uint64(v.Int64()), false) case types.Float32Kind: return llvm.ConstFloat(llvm.FloatType(), float64(v.Float64())) case types.Float64Kind: return llvm.ConstFloat(llvm.DoubleType(), float64(v.Float64())) case types.Complex64Kind: r_, i_ := v.Complex() r := llvm.ConstFloat(llvm.FloatType(), r_) i := llvm.ConstFloat(llvm.FloatType(), i_) return llvm.ConstStruct([]llvm.Value{r, i}, false) case types.Complex128Kind: r_, i_ := v.Complex() r := llvm.ConstFloat(llvm.DoubleType(), r_) i := llvm.ConstFloat(llvm.DoubleType(), i_) return llvm.ConstStruct([]llvm.Value{r, i}, false) case types.UnsafePointerKind, types.UintptrKind: inttype := v.compiler.target.IntPtrType() return llvm.ConstInt(inttype, uint64(v.Int64()), false) case types.StringKind: strval := (v.Val).(string) strlen := len(strval) i8ptr := llvm.PointerType(llvm.Int8Type(), 0) var ptr llvm.Value if strlen > 0 { ptr = v.compiler.builder.CreateGlobalStringPtr(strval, "") ptr = llvm.ConstBitCast(ptr, i8ptr) } else { ptr = llvm.ConstNull(i8ptr) } len_ := llvm.ConstInt(llvm.Int32Type(), uint64(strlen), false) return llvm.ConstStruct([]llvm.Value{ptr, len_}, false) case types.BoolKind: if v := v.Val.(bool); v { return llvm.ConstAllOnes(llvm.Int1Type()) } return llvm.ConstNull(llvm.Int1Type()) } panic(fmt.Errorf("Unhandled type: %v", typ)) //v.typ.Kind)) }
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 }