Beispiel #1
0
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))
}
Beispiel #2
0
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
}