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() }) }
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() }) }
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") } }