func (compiler *compiler) compile(filenames []string, importpath string) (m *Module, err error) { buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple) if err != nil { return nil, err } impcfg := &loader.Config{ Fset: token.NewFileSet(), TypeChecker: types.Config{ Import: llgoimporter.NewImporter(buildctx).Import, Sizes: compiler.llvmtypes, }, Build: &buildctx.Context, } // Must use parseFiles, so we retain comments; // this is important for annotation processing. astFiles, err := parseFiles(impcfg.Fset, filenames) if err != nil { return nil, err } // 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 pkgname := astFiles[0].Name.String(); importpath == "" || pkgname == "main" { importpath = pkgname } impcfg.CreateFromFiles(importpath, astFiles...) // Create a "runtime" package too, so we can reference // its types and functions in the compiler and generated // code. if importpath != "runtime" { astFiles, err := parseRuntime(&buildctx.Context, impcfg.Fset) if err != nil { return nil, err } impcfg.CreateFromFiles("runtime", astFiles...) } iprog, err := impcfg.Load() if err != nil { return nil, err } program := ssa.Create(iprog, 0) var mainPkginfo, runtimePkginfo *loader.PackageInfo if pkgs := iprog.InitialPackages(); len(pkgs) == 1 { mainPkginfo, runtimePkginfo = pkgs[0], pkgs[0] } else { mainPkginfo, runtimePkginfo = pkgs[0], pkgs[1] } mainPkg := program.CreatePackage(mainPkginfo) // Create a Module, which contains the LLVM bitcode. modulename := importpath compiler.module = &Module{Module: llvm.NewModule(modulename), Name: modulename} compiler.module.SetTarget(compiler.TargetTriple) compiler.module.SetDataLayout(compiler.dataLayout) // Create a new translation unit. unit := newUnit(compiler, mainPkg) // Create the runtime interface. compiler.runtime, err = newRuntimeInterface( runtimePkginfo.Pkg, compiler.module.Module, compiler.llvmtypes, FuncResolver(unit), ) if err != nil { return nil, err } // Create a struct responsible for mapping static types to LLVM types, // and to runtime/dynamic type values. compiler.types = NewTypeMap( importpath, compiler.llvmtypes, compiler.module.Module, compiler.runtime, MethodResolver(unit), ) // Create a Builder, for building LLVM instructions. compiler.builder = llvm.GlobalContext().NewBuilder() defer compiler.builder.Dispose() // Initialise debugging. compiler.debug.module = compiler.module.Module compiler.debug.Fset = impcfg.Fset compiler.debug.Sizes = compiler.llvmtypes mainPkg.Build() unit.translatePackage(mainPkg) compiler.processAnnotations(unit, mainPkginfo) if runtimePkginfo != mainPkginfo { compiler.processAnnotations(unit, runtimePkginfo) } // Finalise debugging. for _, cu := range compiler.debug.cu { compiler.module.AddNamedMetadataOperand( "llvm.dbg.cu", compiler.debug.MDNode(cu), ) } // Export runtime type information. var exportedTypes []types.Type for _, m := range mainPkg.Members { if t, ok := m.(*ssa.Type); ok && ast.IsExported(t.Name()) { exportedTypes = append(exportedTypes, t.Type()) } } compiler.exportRuntimeTypes(exportedTypes, importpath == "runtime") if importpath == "main" { // Wrap "main.main" in a call to runtime.main. if err = compiler.createMainFunction(); err != nil { return nil, fmt.Errorf("failed to create main.main: %v", err) } } else { if err := llgoimporter.Export(buildctx, mainPkg.Object); err != nil { return nil, fmt.Errorf("failed to export package data: %v", err) } } return compiler.module, nil }
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(filenames []string, importpath string) (m *Module, err error) { // FIXME create a compilation state, rather than storing in 'compiler'. compiler.llvmtypes = NewLLVMTypeMap(compiler.target) buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple) if err != nil { return nil, err } impcfg := &goimporter.Config{ TypeChecker: types.Config{ Import: llgoimporter.NewImporter(buildctx).Import, Sizes: compiler.llvmtypes, }, Build: &buildctx.Context, } compiler.typechecker = &impcfg.TypeChecker compiler.importer = goimporter.New(impcfg) program := ssa.NewProgram(compiler.importer.Fset, 0) astFiles, err := parseFiles(compiler.importer.Fset, filenames) if err != nil { return nil, err } // 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 pkgname := astFiles[0].Name.String(); importpath == "" || pkgname == "main" { importpath = pkgname } mainPkginfo := compiler.importer.CreatePackage(importpath, astFiles...) if mainPkginfo.Err != nil { return nil, mainPkginfo.Err } // First call CreatePackages to resolve imports, and then CreatePackage // to obtain the main package. The latter simply returns the package // created by the former. if err := program.CreatePackages(compiler.importer); err != nil { return nil, err } mainpkg := program.CreatePackage(mainPkginfo) // 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()) // Map runtime types and functions. runtimePkginfo := mainPkginfo runtimePkg := mainpkg if importpath != "runtime" { astFiles, err := parseRuntime(&buildctx.Context, compiler.importer.Fset) if err != nil { return nil, err } runtimePkginfo = compiler.importer.CreatePackage("runtime", astFiles...) if runtimePkginfo.Err != nil { return nil, err } runtimePkg = program.CreatePackage(runtimePkginfo) } // Create a new translation unit. unit := newUnit(compiler, mainpkg) // Create the runtime interface. compiler.runtime, err = newRuntimeInterface( runtimePkg.Object, compiler.module.Module, compiler.llvmtypes, FuncResolver(unit), ) if err != nil { return nil, err } // Create a struct responsible for mapping static types to LLVM types, // and to runtime/dynamic type values. compiler.types = NewTypeMap( importpath, compiler.llvmtypes, compiler.module.Module, compiler.runtime, MethodResolver(unit), ) // Create a Builder, for building LLVM instructions. compiler.builder = llvm.GlobalContext().NewBuilder() defer compiler.builder.Dispose() mainpkg.Build() unit.translatePackage(mainpkg) compiler.processAnnotations(unit, mainPkginfo) if runtimePkginfo != mainPkginfo { compiler.processAnnotations(unit, runtimePkginfo) } /* compiler.debug_info = &llvm.DebugInfo{} // Compile each file in the package. for _, file := range files { if compiler.GenerateDebug { cu := &llvm.CompileUnitDescriptor{ Language: llvm.DW_LANG_Go, Path: llvm.FileDescriptor(fset.File(file.Pos()).Name()), Producer: LLGOProducer, Runtime: LLGORuntimeVersion, } compiler.pushDebugContext(cu) compiler.pushDebugContext(&cu.Path) } for _, decl := range file.Decls { compiler.VisitDecl(decl) } if compiler.GenerateDebug { compiler.popDebugContext() cu := compiler.popDebugContext() if len(compiler.debug_context) > 0 { log.Panicln(compiler.debug_context) } compiler.module.AddNamedMetadataOperand( "llvm.dbg.cu", compiler.debug_info.MDNode(cu), ) } } */ // Export runtime type information. var exportedTypes []types.Type for _, m := range mainpkg.Members { if t, ok := m.(*ssa.Type); ok && ast.IsExported(t.Name()) { exportedTypes = append(exportedTypes, t.Type()) } } compiler.exportRuntimeTypes(exportedTypes, importpath == "runtime") if importpath == "main" { // Wrap "main.main" in a call to runtime.main. if err = compiler.createMainFunction(); err != nil { return nil, fmt.Errorf("failed to create main.main: %v", err) } } else { if err := llgoimporter.Export(buildctx, mainpkg.Object); err != nil { return nil, fmt.Errorf("failed to export package data: %v", err) } } 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 (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 test() { llvm.LinkInJIT() llvm.InitializeNativeTarget() mod := llvm.NewModule("fac_module") // don't do that, because ExecutionEngine takes ownership over module //defer mod.Dispose() fac_args := []llvm.Type{llvm.Int32Type()} fac_type := llvm.FunctionType(llvm.Int32Type(), fac_args, false) fac := llvm.AddFunction(mod, "fac", fac_type) fac.SetFunctionCallConv(llvm.CCallConv) n := fac.Param(0) entry := llvm.AddBasicBlock(fac, "entry") iftrue := llvm.AddBasicBlock(fac, "iftrue") iffalse := llvm.AddBasicBlock(fac, "iffalse") end := llvm.AddBasicBlock(fac, "end") builder := llvm.NewBuilder() defer builder.Dispose() builder.SetInsertPointAtEnd(entry) If := builder.CreateICmp(llvm.IntEQ, n, llvm.ConstInt(llvm.Int32Type(), 0, false), "cmptmp") builder.CreateCondBr(If, iftrue, iffalse) builder.SetInsertPointAtEnd(iftrue) res_iftrue := llvm.ConstInt(llvm.Int32Type(), 1, false) builder.CreateBr(end) builder.SetInsertPointAtEnd(iffalse) n_minus := builder.CreateSub(n, llvm.ConstInt(llvm.Int32Type(), 1, false), "subtmp") call_fac_args := []llvm.Value{n_minus} call_fac := builder.CreateCall(fac, call_fac_args, "calltmp") res_iffalse := builder.CreateMul(n, call_fac, "multmp") builder.CreateBr(end) builder.SetInsertPointAtEnd(end) res := builder.CreatePHI(llvm.Int32Type(), "result") phi_vals := []llvm.Value{res_iftrue, res_iffalse} phi_blocks := []llvm.BasicBlock{iftrue, iffalse} res.AddIncoming(phi_vals, phi_blocks) builder.CreateRet(res) err := llvm.VerifyModule(mod, llvm.ReturnStatusAction) if err != nil { fmt.Println(err) return } engine, err := llvm.NewJITCompiler(mod, 2) if err != nil { fmt.Println(err) return } defer engine.Dispose() pass := llvm.NewPassManager() defer pass.Dispose() pass.Add(engine.TargetData()) pass.AddConstantPropagationPass() pass.AddInstructionCombiningPass() pass.AddPromoteMemoryToRegisterPass() pass.AddGVNPass() pass.AddCFGSimplificationPass() pass.Run(mod) mod.Dump() exec_args := []llvm.GenericValue{llvm.NewGenericValueFromInt(llvm.Int32Type(), 10, false)} exec_res := engine.RunFunction(fac, exec_args) fmt.Println("-----------------------------------------") fmt.Println("Running fac(10) with JIT...") fmt.Printf("Result: %d\n", exec_res.Int(false)) }
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 (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 }