func test() { llvm.LinkInMCJIT() llvm.InitializeNativeTarget() llvm.InitializeNativeAsmPrinter() 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.NewMCJITCompiler(mod, llvm.MCJITCompilerOptions{OptLevel: 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(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 }