1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
10 "cmd/compile/internal/base"
11 "cmd/compile/internal/deadcode"
12 "cmd/compile/internal/devirtualize"
13 "cmd/compile/internal/dwarfgen"
14 "cmd/compile/internal/escape"
15 "cmd/compile/internal/inline"
16 "cmd/compile/internal/ir"
17 "cmd/compile/internal/logopt"
18 "cmd/compile/internal/noder"
19 "cmd/compile/internal/pkginit"
20 "cmd/compile/internal/reflectdata"
21 "cmd/compile/internal/ssa"
22 "cmd/compile/internal/ssagen"
23 "cmd/compile/internal/typecheck"
24 "cmd/compile/internal/types"
37 if base.Debug.Panic == 0 && base.Errors() > 0 {
38 // If we've already complained about things
39 // in the program, don't bother complaining
40 // about a panic too; let the user clean up
41 // the code and try again.
42 if err := recover(); err != nil {
51 // Main parses flags and Go source files specified in the command-line
52 // arguments, type-checks the parsed Go package, compiles functions to machine
53 // code, and finally writes the compiled package definition to disk.
54 func Main(archInit func(*ssagen.ArchInfo)) {
55 base.Timer.Start("fe", "init")
59 archInit(&ssagen.Arch)
61 base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch)
62 base.Ctxt.DiagFunc = base.Errorf
63 base.Ctxt.DiagFlush = base.FlushErrors
64 base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
66 // UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
67 // on Darwin don't support it properly, especially since macOS 10.14 (Mojave). This is exposed as a flag
68 // to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
69 // See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
70 base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin
72 types.LocalPkg = types.NewPkg("", "")
73 types.LocalPkg.Prefix = "\"\""
75 // We won't know localpkg's height until after import
76 // processing. In the mean time, set to MaxPkgHeight to ensure
77 // height comparisons at least work until then.
78 types.LocalPkg.Height = types.MaxPkgHeight
80 // pseudo-package, for scoping
81 types.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
82 types.BuiltinPkg.Prefix = "go.builtin" // not go%2ebuiltin
84 // pseudo-package, accessed by import "unsafe"
85 ir.Pkgs.Unsafe = types.NewPkg("unsafe", "unsafe")
87 // Pseudo-package that contains the compiler's builtin
88 // declarations for package runtime. These are declared in a
89 // separate package to avoid conflicts with package runtime's
90 // actual declarations, which may differ intentionally but
92 ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime")
93 ir.Pkgs.Runtime.Prefix = "runtime"
95 // pseudo-packages used in symbol tables
96 ir.Pkgs.Itab = types.NewPkg("go.itab", "go.itab")
97 ir.Pkgs.Itab.Prefix = "go.itab" // not go%2eitab
99 // pseudo-package used for methods with anonymous receivers
100 ir.Pkgs.Go = types.NewPkg("go", "")
102 base.DebugSSA = ssa.PhaseOption
105 // Record flags that affect the build result. (And don't
106 // record flags that don't, since that would cause spurious
107 // changes in the binary.)
108 dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
110 if !base.EnableTrace && base.Flag.LowerT {
111 log.Fatalf("compiler not built with support for -t")
114 // Enable inlining (after RecordFlags, to avoid recording the rewritten -l). For now:
115 // default: inlining on. (Flag.LowerL == 1)
116 // -l: inlining off (Flag.LowerL == 0)
117 // -l=2, -l=3: inlining on again, with extra debugging (Flag.LowerL > 1)
118 if base.Flag.LowerL <= 1 {
119 base.Flag.LowerL = 1 - base.Flag.LowerL
122 if base.Flag.SmallFrames {
123 ir.MaxStackVarSize = 128 * 1024
124 ir.MaxImplicitStackVarSize = 16 * 1024
128 base.Ctxt.DebugInfo = dwarfgen.Info
129 base.Ctxt.GenAbstractFunc = dwarfgen.AbstractFunc
130 base.Ctxt.DwFixups = obj.NewDwarfFixupTable(base.Ctxt)
132 // turn off inline generation if no dwarf at all
133 base.Flag.GenDwarfInl = 0
134 base.Ctxt.Flag_locationlists = false
136 if base.Ctxt.Flag_locationlists && len(base.Ctxt.Arch.DWARFRegisters) == 0 {
137 log.Fatalf("location lists requested but register mapping not available on %v", base.Ctxt.Arch.Name)
140 types.ParseLangFlag()
142 symABIs := ssagen.NewSymABIs(base.Ctxt.Pkgpath)
143 if base.Flag.SymABIs != "" {
144 symABIs.ReadSymABIs(base.Flag.SymABIs)
147 if base.Compiling(base.NoInstrumentPkgs) {
148 base.Flag.Race = false
149 base.Flag.MSan = false
152 ssagen.Arch.LinkArch.Init(base.Ctxt)
154 if base.Flag.Race || base.Flag.MSan {
155 base.Flag.Cfg.Instrumenting = true
158 dwarf.EnableLogging(base.Debug.DwarfInl != 0)
160 if base.Debug.SoftFloat != 0 {
161 if objabi.Experiment.RegabiArgs {
162 log.Fatalf("softfloat mode with GOEXPERIMENT=regabiargs not implemented ")
164 ssagen.Arch.SoftFloat = true
167 if base.Flag.JSON != "" { // parse version,destination from json logging optimization.
168 logopt.LogJsonOption(base.Flag.JSON)
171 ir.EscFmt = escape.Fmt
172 ir.IsIntrinsicCall = ssagen.IsIntrinsicCall
173 inline.SSADumpInline = ssagen.DumpInline
177 types.PtrSize = ssagen.Arch.LinkArch.PtrSize
178 types.RegSize = ssagen.Arch.LinkArch.RegSize
179 types.MaxWidth = ssagen.Arch.MAXWIDTH
181 typecheck.Target = new(ir.Package)
183 typecheck.NeedITab = func(t, iface *types.Type) { reflectdata.ITabAddr(t, iface) }
184 typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): TypeSym for lock?
186 base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
188 typecheck.InitUniverse()
190 // Parse and typecheck input.
191 noder.LoadPackage(flag.Args())
193 dwarfgen.RecordPackageName()
196 if initTask := pkginit.Task(); initTask != nil {
197 typecheck.Export(initTask)
200 // Eliminate some obviously dead code.
201 // Must happen after typechecking.
202 for _, n := range typecheck.Target.Decls {
203 if n.Op() == ir.ODCLFUNC {
204 deadcode.Func(n.(*ir.Func))
208 // Compute Addrtaken for names.
209 // We need to wait until typechecking is done so that when we see &x[i]
210 // we know that x has its address taken if x is an array, but not if x is a slice.
211 // We compute Addrtaken in bulk here.
212 // After this phase, we maintain Addrtaken incrementally.
213 if typecheck.DirtyAddrtaken {
214 typecheck.ComputeAddrtaken(typecheck.Target.Decls)
215 typecheck.DirtyAddrtaken = false
217 typecheck.IncrementalAddrtaken = true
219 if base.Debug.TypecheckInl != 0 {
220 // Typecheck imported function bodies if Debug.l > 1,
221 // otherwise lazily when used or re-exported.
222 typecheck.AllImportedBodies()
226 base.Timer.Start("fe", "inlining")
227 if base.Flag.LowerL != 0 {
228 inline.InlinePackage()
232 for _, n := range typecheck.Target.Decls {
233 if n.Op() == ir.ODCLFUNC {
234 devirtualize.Func(n.(*ir.Func))
239 // Generate ABI wrappers. Must happen before escape analysis
240 // and doesn't benefit from dead-coding or inlining.
241 symABIs.GenABIWrappers()
244 // Required for moving heap allocations onto stack,
245 // which in turn is required by the closure implementation,
246 // which stores the addresses of stack variables into the closure.
247 // If the closure does not escape, it needs to be on the stack
248 // or else the stack copier will not update it.
249 // Large values are also moved off stack in escape analysis;
250 // because large values may contain pointers, it must happen early.
251 base.Timer.Start("fe", "escapes")
252 escape.Funcs(typecheck.Target.Decls)
254 // Collect information for go:nowritebarrierrec
255 // checking. This must happen before transforming closures during Walk
256 // We'll do the final check after write barriers are
258 if base.Flag.CompilingRuntime {
259 ssagen.EnableNoWriteBarrierRecCheck()
262 // Prepare for SSA compilation.
263 // This must be before CompileITabs, because CompileITabs
264 // can trigger function compilation.
265 typecheck.InitRuntime()
268 // Just before compilation, compile itabs found on
269 // the right side of OCONVIFACE so that methods
270 // can be de-virtualized during compilation.
272 reflectdata.CompileITabs()
274 // Compile top level functions.
275 // Don't use range--walk can add functions to Target.Decls.
276 base.Timer.Start("be", "compilefuncs")
278 for i := 0; i < len(typecheck.Target.Decls); i++ {
279 if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
284 base.Timer.AddEvent(fcount, "funcs")
288 if base.Flag.CompilingRuntime {
289 // Write barriers are now known. Check the call graph.
290 ssagen.NoWriteBarrierRecCheck()
293 // Finalize DWARF inline routine DIEs, then explicitly turn off
294 // DWARF inlining gen so as to avoid problems with generated
296 if base.Ctxt.DwFixups != nil {
297 base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0)
298 base.Ctxt.DwFixups = nil
299 base.Flag.GenDwarfInl = 0
302 // Write object data to disk.
303 base.Timer.Start("be", "dumpobj")
305 base.Ctxt.NumberSyms()
307 if base.Flag.AsmHdr != "" {
311 ssagen.CheckLargeStacks()
312 typecheck.CheckFuncStack()
314 if len(compilequeue) != 0 {
315 base.Fatalf("%d uncompiled functions", len(compilequeue))
318 logopt.FlushLoggedOpts(base.Ctxt, base.Ctxt.Pkgpath)
324 if base.Flag.Bench != "" {
325 if err := writebench(base.Flag.Bench); err != nil {
326 log.Fatalf("cannot write benchmark data: %v", err)
331 func writebench(filename string) error {
332 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
338 fmt.Fprintln(&buf, "commit:", objabi.Version)
339 fmt.Fprintln(&buf, "goos:", runtime.GOOS)
340 fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
341 base.Timer.Write(&buf, "BenchmarkCompile:"+base.Ctxt.Pkgpath+":")
343 n, err := f.Write(buf.Bytes())
354 func makePos(b *src.PosBase, line, col uint) src.XPos {
355 return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col))