Example #1
0
func NewCG() *CG {
	cg := &CG{
		Context:     llvm.GlobalContext(),
		Builder:     llvm.NewBuilder(),
		Mod:         llvm.NewModule("kaleidoscope"),
		NamedValues: make(map[string]llvm.Value),
		Protos:      make(map[string]*ProtoDecl),
	}
	cg.Init()
	return cg
}
Example #2
0
func Construct(tree *parser.AST) *Codegen {
	return &Codegen{
		tree:  tree,
		scope: &Scope{variables: map[string]llvm.Value{}},

		module:  llvm.NewModule("main"),
		builder: llvm.NewBuilder(),

		templates: map[string]*Template{},
		functions: map[string]llvm.BasicBlock{},
	}
}
Example #3
0
func (v *Codegen) Generate(input []*parser.Module, modules map[string]*parser.Module, verbose bool) {
	v.input = input
	v.builder = llvm.NewBuilder()
	v.variableLookup = make(map[*parser.Variable]llvm.Value)
	v.structLookup_UseHelperFunction = make(map[*parser.StructType]llvm.Type)

	if verbose {
		fmt.Println(util.TEXT_BOLD + util.TEXT_GREEN + "Started codegenning" + util.TEXT_RESET)
	}
	t := time.Now()

	passManager := llvm.NewPassManager()
	passBuilder := llvm.NewPassManagerBuilder()
	passBuilder.SetOptLevel(3)
	//passBuilder.Populate(passManager) //leave this off until the compiler is better

	v.modules = make(map[string]*parser.Module)

	for _, infile := range input {
		infile.Module = llvm.NewModule(infile.Name)
		v.curFile = infile

		fmt.Println("adding module " + v.curFile.Name)
		v.modules[v.curFile.Name] = v.curFile

		v.declareDecls(infile.Nodes)

		for _, node := range infile.Nodes {
			v.genNode(node)
		}

		if verbose {
			infile.Module.Dump()
		}

		if err := llvm.VerifyModule(infile.Module, llvm.ReturnStatusAction); err != nil {
			v.err("%s", err.Error())
		}

		passManager.Run(infile.Module)
	}

	passManager.Dispose()

	v.createBinary()

	dur := time.Since(t)
	if verbose {
		fmt.Printf(util.TEXT_BOLD+util.TEXT_GREEN+"Finished codegenning"+util.TEXT_RESET+" (%.2fms)\n",
			float32(dur.Nanoseconds())/1000000)
	}
}
Example #4
0
File: codegen.go Project: vnev/ark
func (v *Codegen) Generate(input []*parser.Module) {
	v.builders = make(map[*parser.Function]llvm.Builder)
	v.inBlocks = make(map[*parser.Function][]*parser.Block)
	v.globalBuilder = llvm.NewBuilder()
	defer v.globalBuilder.Dispose()

	v.curLoopExits = make(map[*parser.Function][]llvm.BasicBlock)
	v.curLoopNexts = make(map[*parser.Function][]llvm.BasicBlock)

	v.input = make([]*WrappedModule, len(input))
	for idx, mod := range input {
		v.input[idx] = &WrappedModule{Module: mod}
	}

	v.variableLookup = make(map[*parser.Variable]llvm.Value)
	v.namedTypeLookup = make(map[string]llvm.Type)

	// initialize llvm target
	llvm.InitializeNativeTarget()
	llvm.InitializeNativeAsmPrinter()

	// setup target stuff
	var err error
	v.target, err = llvm.GetTargetFromTriple(llvm.DefaultTargetTriple())
	if err != nil {
		panic(err)
	}
	v.targetMachine = v.target.CreateTargetMachine(llvm.DefaultTargetTriple(), "", "", llvm.CodeGenLevelNone, llvm.RelocDefault, llvm.CodeModelDefault)
	v.targetData = v.targetMachine.TargetData()

	passManager := llvm.NewPassManager()
	passBuilder := llvm.NewPassManagerBuilder()
	if v.OptLevel > 0 {
		passBuilder.SetOptLevel(v.OptLevel)
		passBuilder.Populate(passManager)
	}

	v.blockDeferData = make(map[*parser.Block][]*deferData)

	for _, infile := range v.input {
		log.Timed("codegenning", infile.Name.String(), func() {
			infile.LlvmModule = llvm.NewModule(infile.Name.String())
			v.curFile = infile

			for _, submod := range infile.Parts {
				v.declareDecls(submod.Nodes)

				for _, node := range submod.Nodes {
					v.genNode(node)
				}
			}

			if err := llvm.VerifyModule(infile.LlvmModule, llvm.ReturnStatusAction); err != nil {
				infile.LlvmModule.Dump()
				v.err("%s", err.Error())
			}

			passManager.Run(infile.LlvmModule)

			if log.AtLevel(log.LevelDebug) {
				infile.LlvmModule.Dump()
			}
		})
	}

	passManager.Dispose()

	log.Timed("creating binary", "", func() {
		v.createBinary()
	})

}
Example #5
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
	}

	initmap := make(map[*types.Package]gccgoimporter.InitData)
	var importer types.Importer
	if compiler.GccgoPath == "" {
		paths := append(append([]string{}, compiler.ImportPaths...), ".")
		importer = gccgoimporter.GetImporter(paths, initmap)
	} else {
		var inst gccgoimporter.GccgoInstallation
		err = inst.InitFromDriver(compiler.GccgoPath)
		if err != nil {
			return nil, err
		}
		importer = inst.GetImporter(compiler.ImportPaths, initmap)
	}

	impcfg := &loader.Config{
		Fset: token.NewFileSet(),
		TypeChecker: types.Config{
			Import: importer,
			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, then set the import
	// path to be the same as the package's name.
	if importpath == "" {
		importpath = astFiles[0].Name.String()
	}
	impcfg.CreateFromFiles(importpath, astFiles...)
	iprog, err := impcfg.Load()
	if err != nil {
		return nil, err
	}
	program := ssa.Create(iprog, ssa.BareInits)
	mainPkginfo := iprog.InitialPackages()[0]
	mainPkg := program.CreatePackage(mainPkginfo)

	// Create a Module, which contains the LLVM module.
	modulename := importpath
	compiler.module = &Module{Module: llvm.NewModule(modulename), Path: 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(compiler.module.Module, compiler.llvmtypes)
	if err != nil {
		return nil, err
	}

	mainPkg.Build()

	// Create a struct responsible for mapping static types to LLVM types,
	// and to runtime/dynamic type values.
	compiler.types = NewTypeMap(
		mainPkg,
		compiler.llvmtypes,
		compiler.module.Module,
		compiler.runtime,
		MethodResolver(unit),
	)

	if compiler.GenerateDebug {
		compiler.debug = debug.NewDIBuilder(
			types.Sizes(compiler.llvmtypes),
			compiler.module.Module,
			impcfg.Fset,
			compiler.DebugPrefixMaps,
		)
		defer compiler.debug.Destroy()
		defer compiler.debug.Finalize()
	}

	unit.translatePackage(mainPkg)
	compiler.processAnnotations(unit, mainPkginfo)

	if importpath == "main" {
		if err = compiler.createInitMainFunction(mainPkg, initmap); err != nil {
			return nil, fmt.Errorf("failed to create __go_init_main: %v", err)
		}
	} else {
		compiler.module.ExportData = compiler.buildExportData(mainPkg, initmap)
	}

	return compiler.module, nil
}
Example #6
0
func (v *Codegen) Generate(input []*parser.Module, modules map[string]*parser.Module) {
	v.input = input
	v.builder = llvm.NewBuilder()
	v.variableLookup = make(map[*parser.Variable]llvm.Value)
	v.structLookup_UseHelperFunction = make(map[*parser.StructType]llvm.Type)
	v.enumLookup_UseHelperFunction = make(map[*parser.EnumType]llvm.Type)

	// initialize llvm target
	llvm.InitializeNativeTarget()

	// setup target stuff
	var err error
	v.target, err = llvm.GetTargetFromTriple(llvm.DefaultTargetTriple())
	if err != nil {
		panic(err)
	}
	v.targetMachine = v.target.CreateTargetMachine(llvm.DefaultTargetTriple(), "", "", llvm.CodeGenLevelNone, llvm.RelocDefault, llvm.CodeModelDefault)
	v.targetData = v.targetMachine.TargetData()

	passManager := llvm.NewPassManager()
	passBuilder := llvm.NewPassManagerBuilder()
	if v.OptLevel > 0 {
		passBuilder.SetOptLevel(v.OptLevel)
		passBuilder.Populate(passManager)
	}

	v.modules = make(map[string]*parser.Module)
	v.blockDeferData = make(map[*parser.Block][]*deferData)

	for _, infile := range input {
		log.Verboseln("codegen", util.TEXT_BOLD+util.TEXT_GREEN+"Started codegenning "+util.TEXT_RESET+infile.Name)
		t := time.Now()

		infile.Module = llvm.NewModule(infile.Name)
		v.curFile = infile

		v.modules[v.curFile.Name] = v.curFile

		v.declareDecls(infile.Nodes)

		for _, node := range infile.Nodes {
			v.genNode(node)
		}

		if err := llvm.VerifyModule(infile.Module, llvm.ReturnStatusAction); err != nil {
			infile.Module.Dump()
			v.err("%s", err.Error())
		}

		passManager.Run(infile.Module)

		if log.AtLevel(log.LevelVerbose) {
			infile.Module.Dump()
		}

		dur := time.Since(t)
		log.Verbose("codegen", util.TEXT_BOLD+util.TEXT_GREEN+"Finished codegenning "+util.TEXT_RESET+infile.Name+" (%.2fms)\n",
			float32(dur.Nanoseconds())/1000000)
	}

	passManager.Dispose()

	log.Timed("create binary", func() {
		v.createBinary()
	})

}
Example #7
0
func (compiler *compiler) compile(fset *token.FileSet, astFiles []*ast.File, importpath string) (m *Module, err error) {
	buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple)
	if err != nil {
		return nil, err
	}

	if compiler.Importer == nil {
		err = compiler.MakeImporter()
		if err != nil {
			return nil, err
		}
	}

	impcfg := &loader.Config{
		Fset: fset,
		TypeChecker: types.Config{
			Packages: compiler.Packages,
			Import:   compiler.Importer,
			Sizes:    compiler.llvmtypes,
			DisableUnusedImportCheck: compiler.DisableUnusedImportCheck,
		},
		ImportFromBinary: true,
		Build:            &buildctx.Context,
		PackageCreated:   compiler.PackageCreated,
	}
	// If no import path is specified, then set the import
	// path to be the same as the package's name.
	if importpath == "" {
		importpath = astFiles[0].Name.String()
	}
	impcfg.CreateFromFiles(importpath, astFiles...)
	iprog, err := impcfg.Load()
	if err != nil {
		return nil, err
	}
	program := ssa.Create(iprog, ssa.BareInits)
	mainPkginfo := iprog.InitialPackages()[0]
	mainPkg := program.CreatePackage(mainPkginfo)

	// Create a Module, which contains the LLVM module.
	modulename := importpath
	compiler.module = &Module{Module: llvm.NewModule(modulename), Path: modulename, Package: mainPkg.Object}
	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(compiler.module.Module, compiler.llvmtypes)
	if err != nil {
		return nil, err
	}

	mainPkg.Build()

	// Create a struct responsible for mapping static types to LLVM types,
	// and to runtime/dynamic type values.
	compiler.types = NewTypeMap(
		mainPkg,
		compiler.llvmtypes,
		compiler.module.Module,
		compiler.runtime,
		MethodResolver(unit),
	)

	if compiler.GenerateDebug {
		compiler.debug = debug.NewDIBuilder(
			types.Sizes(compiler.llvmtypes),
			compiler.module.Module,
			impcfg.Fset,
			compiler.DebugPrefixMaps,
		)
		defer compiler.debug.Destroy()
		defer compiler.debug.Finalize()
	}

	unit.translatePackage(mainPkg)
	compiler.processAnnotations(unit, mainPkginfo)

	if importpath == "main" {
		compiler.createInitMainFunction(mainPkg)
	} else {
		compiler.module.ExportData = compiler.buildExportData(mainPkg)
	}

	return compiler.module, nil
}
Example #8
0
func performAction(opts *driverOptions, kind actionKind, inputs []string, output string) error {
	switch kind {
	case actionPrint:
		switch opts.output {
		case "-dumpversion":
			fmt.Println("llgo-" + llvmVersion())
			return nil
		case "-print-libgcc-file-name":
			cmd := exec.Command(opts.bprefix+"gcc", "-print-libgcc-file-name")
			out, err := cmd.CombinedOutput()
			os.Stdout.Write(out)
			return err
		case "-print-multi-os-directory":
			fmt.Println(filepath.Join("..", getLibDir(opts)))
			return nil
		case "--version":
			displayVersion()
			return nil
		default:
			panic("unexpected print command")
		}

	case actionCompile, actionAssemble:
		compiler, err := initCompiler(opts)
		if err != nil {
			return err
		}

		fset := token.NewFileSet()
		files, err := driver.ParseFiles(fset, inputs)
		if err != nil {
			return err
		}

		module, err := compiler.Compile(fset, files, opts.pkgpath)
		if err != nil {
			return err
		}

		defer module.Dispose()

		target, err := llvm.GetTargetFromTriple(opts.triple)
		if err != nil {
			return err
		}

		optLevel := [...]llvm.CodeGenOptLevel{
			llvm.CodeGenLevelNone,
			llvm.CodeGenLevelLess,
			llvm.CodeGenLevelDefault,
			llvm.CodeGenLevelAggressive,
		}[opts.optLevel]

		relocMode := llvm.RelocStatic
		if opts.pic {
			relocMode = llvm.RelocPIC
		}

		tm := target.CreateTargetMachine(opts.triple, "", "", optLevel,
			relocMode, llvm.CodeModelDefault)
		defer tm.Dispose()

		runPasses(opts, tm, module.Module)

		var file *os.File
		if output == "-" {
			file = os.Stdout
		} else {
			file, err = os.Create(output)
			if err != nil {
				return err
			}
			defer file.Close()
		}

		switch {
		case !opts.lto && !opts.emitIR:
			if module.ExportData != nil {
				asm := getMetadataSectionInlineAsm(".go_export")
				asm += getDataInlineAsm(module.ExportData)
				module.Module.SetInlineAsm(asm)
			}

			fileType := llvm.AssemblyFile
			if kind == actionCompile {
				fileType = llvm.ObjectFile
			}
			mb, err := tm.EmitToMemoryBuffer(module.Module, fileType)
			if err != nil {
				return err
			}
			defer mb.Dispose()

			bytes := mb.Bytes()
			_, err = file.Write(bytes)
			return err

		case opts.lto:
			bcmb := llvm.WriteBitcodeToMemoryBuffer(module.Module)
			defer bcmb.Dispose()

			// This is a bit of a hack. We just want an object file
			// containing some metadata sections. This might be simpler
			// if we had bindings for the MC library, but for now we create
			// a fresh module containing only inline asm that creates the
			// sections.
			outmodule := llvm.NewModule("")
			defer outmodule.Dispose()
			asm := getMetadataSectionInlineAsm(".llvmbc")
			asm += getDataInlineAsm(bcmb.Bytes())
			if module.ExportData != nil {
				asm += getMetadataSectionInlineAsm(".go_export")
				asm += getDataInlineAsm(module.ExportData)
			}
			outmodule.SetInlineAsm(asm)

			fileType := llvm.AssemblyFile
			if kind == actionCompile {
				fileType = llvm.ObjectFile
			}
			mb, err := tm.EmitToMemoryBuffer(outmodule, fileType)
			if err != nil {
				return err
			}
			defer mb.Dispose()

			bytes := mb.Bytes()
			_, err = file.Write(bytes)
			return err

		case kind == actionCompile:
			err := llvm.WriteBitcodeToFile(module.Module, file)
			return err

		case kind == actionAssemble:
			_, err := file.WriteString(module.Module.String())
			return err

		default:
			panic("unexpected action kind")
		}

	case actionLink:
		// TODO(pcc): Teach this to do LTO.
		args := []string{"-o", output}
		if opts.pic {
			args = append(args, "-fPIC")
		}
		if opts.pieLink {
			args = append(args, "-pie")
		}
		if opts.staticLink {
			args = append(args, "-static")
		}
		if opts.staticLibgcc {
			args = append(args, "-static-libgcc")
		}
		for _, p := range opts.libPaths {
			args = append(args, "-L", p)
		}
		for _, p := range opts.importPaths {
			args = append(args, "-I", p)
		}
		args = append(args, inputs...)
		var linkerPath string
		if opts.gccgoPath == "" {
			// TODO(pcc): See if we can avoid calling gcc here.
			// We currently rely on it to find crt*.o and compile
			// any C source files passed as arguments.
			linkerPath = opts.bprefix + "gcc"

			if opts.prefix != "" {
				libdir := filepath.Join(opts.prefix, getLibDir(opts))
				args = append(args, "-L", libdir)
				if !opts.staticLibgo {
					args = append(args, "-Wl,-rpath,"+libdir)
				}
			}

			args = append(args, "-lgobegin-llgo")
			if opts.staticLibgo {
				args = append(args, "-Wl,-Bstatic", "-lgo-llgo", "-Wl,-Bdynamic", "-lpthread", "-lm")
			} else {
				args = append(args, "-lgo-llgo")
			}
		} else {
			linkerPath = opts.gccgoPath
			if opts.staticLibgo {
				args = append(args, "-static-libgo")
			}
		}

		args = opts.sanitizer.addLibs(opts.triple, args)

		cmd := exec.Command(linkerPath, args...)
		out, err := cmd.CombinedOutput()
		if err != nil {
			os.Stderr.Write(out)
		}
		return err

	default:
		panic("unexpected action kind")
	}
}