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.
5 //go:generate go run mkbuiltin.go
12 "cmd/compile/internal/base"
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/staticdata"
24 "cmd/compile/internal/typecheck"
25 "cmd/compile/internal/types"
26 "cmd/compile/internal/walk"
39 if base.Debug.Panic == 0 && base.Errors() > 0 {
40 // If we've already complained about things
41 // in the program, don't bother complaining
42 // about a panic too; let the user clean up
43 // the code and try again.
44 if err := recover(); err != nil {
53 // Main parses flags and Go source files specified in the command-line
54 // arguments, type-checks the parsed Go package, compiles functions to machine
55 // code, and finally writes the compiled package definition to disk.
56 func Main(archInit func(*ssagen.ArchInfo)) {
57 base.Timer.Start("fe", "init")
61 archInit(&ssagen.Arch)
63 base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch)
64 base.Ctxt.DiagFunc = base.Errorf
65 base.Ctxt.DiagFlush = base.FlushErrors
66 base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
68 // UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
69 // on Darwin don't support it properly, especially since macOS 10.14 (Mojave). This is exposed as a flag
70 // to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
71 // See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
72 base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin
74 types.LocalPkg = types.NewPkg("", "")
75 types.LocalPkg.Prefix = "\"\""
77 // We won't know localpkg's height until after import
78 // processing. In the mean time, set to MaxPkgHeight to ensure
79 // height comparisons at least work until then.
80 types.LocalPkg.Height = types.MaxPkgHeight
82 // pseudo-package, for scoping
83 types.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
84 types.BuiltinPkg.Prefix = "go.builtin" // not go%2ebuiltin
86 // pseudo-package, accessed by import "unsafe"
87 ir.Pkgs.Unsafe = types.NewPkg("unsafe", "unsafe")
89 // Pseudo-package that contains the compiler's builtin
90 // declarations for package runtime. These are declared in a
91 // separate package to avoid conflicts with package runtime's
92 // actual declarations, which may differ intentionally but
94 ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime")
95 ir.Pkgs.Runtime.Prefix = "runtime"
97 // pseudo-packages used in symbol tables
98 ir.Pkgs.Itab = types.NewPkg("go.itab", "go.itab")
99 ir.Pkgs.Itab.Prefix = "go.itab" // not go%2eitab
101 ir.Pkgs.Itablink = types.NewPkg("go.itablink", "go.itablink")
102 ir.Pkgs.Itablink.Prefix = "go.itablink" // not go%2eitablink
104 ir.Pkgs.Track = types.NewPkg("go.track", "go.track")
105 ir.Pkgs.Track.Prefix = "go.track" // not go%2etrack
107 // pseudo-package used for map zero values
108 ir.Pkgs.Map = types.NewPkg("go.map", "go.map")
109 ir.Pkgs.Map.Prefix = "go.map"
111 // pseudo-package used for methods with anonymous receivers
112 ir.Pkgs.Go = types.NewPkg("go", "")
114 base.DebugSSA = ssa.PhaseOption
117 // Record flags that affect the build result. (And don't
118 // record flags that don't, since that would cause spurious
119 // changes in the binary.)
120 dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
122 if !base.EnableTrace && base.Flag.LowerT {
123 log.Fatalf("compiler not built with support for -t")
126 // Enable inlining (after recordFlags, to avoid recording the rewritten -l). For now:
127 // default: inlining on. (Flag.LowerL == 1)
128 // -l: inlining off (Flag.LowerL == 0)
129 // -l=2, -l=3: inlining on again, with extra debugging (Flag.LowerL > 1)
130 if base.Flag.LowerL <= 1 {
131 base.Flag.LowerL = 1 - base.Flag.LowerL
134 if base.Flag.SmallFrames {
135 ir.MaxStackVarSize = 128 * 1024
136 ir.MaxImplicitStackVarSize = 16 * 1024
140 base.Ctxt.DebugInfo = dwarfgen.Info
141 base.Ctxt.GenAbstractFunc = dwarfgen.AbstractFunc
142 base.Ctxt.DwFixups = obj.NewDwarfFixupTable(base.Ctxt)
144 // turn off inline generation if no dwarf at all
145 base.Flag.GenDwarfInl = 0
146 base.Ctxt.Flag_locationlists = false
148 if base.Ctxt.Flag_locationlists && len(base.Ctxt.Arch.DWARFRegisters) == 0 {
149 log.Fatalf("location lists requested but register mapping not available on %v", base.Ctxt.Arch.Name)
152 types.ParseLangFlag()
154 if base.Flag.SymABIs != "" {
155 ssagen.ReadSymABIs(base.Flag.SymABIs, base.Ctxt.Pkgpath)
158 if base.Compiling(base.NoInstrumentPkgs) {
159 base.Flag.Race = false
160 base.Flag.MSan = false
163 ssagen.Arch.LinkArch.Init(base.Ctxt)
166 ir.Pkgs.Race = types.NewPkg("runtime/race", "")
169 ir.Pkgs.Msan = types.NewPkg("runtime/msan", "")
171 if base.Flag.Race || base.Flag.MSan {
172 base.Flag.Cfg.Instrumenting = true
175 dwarf.EnableLogging(base.Debug.DwarfInl != 0)
177 if base.Debug.SoftFloat != 0 {
178 ssagen.Arch.SoftFloat = true
181 if base.Flag.JSON != "" { // parse version,destination from json logging optimization.
182 logopt.LogJsonOption(base.Flag.JSON)
185 ir.EscFmt = escape.Fmt
186 ir.IsIntrinsicCall = ssagen.IsIntrinsicCall
187 inline.SSADumpInline = ssagen.DumpInline
191 types.PtrSize = ssagen.Arch.LinkArch.PtrSize
192 types.RegSize = ssagen.Arch.LinkArch.RegSize
193 types.MaxWidth = ssagen.Arch.MAXWIDTH
194 types.TypeLinkSym = func(t *types.Type) *obj.LSym {
195 return reflectdata.TypeSym(t).Linksym()
198 typecheck.Target = new(ir.Package)
200 typecheck.NeedFuncSym = staticdata.NeedFuncSym
201 typecheck.NeedITab = func(t, iface *types.Type) { reflectdata.ITabAddr(t, iface) }
202 typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): typenamesym for lock?
204 base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
206 types.TypeLinkSym = func(t *types.Type) *obj.LSym {
207 return reflectdata.TypeSym(t).Linksym()
212 base.Timer.Start("fe", "parse")
213 lines := noder.ParseFiles(flag.Args())
216 base.Timer.AddEvent(int64(lines), "lines")
217 if base.Flag.G != 0 && base.Flag.G < 3 {
218 // can only parse generic code for now
223 dwarfgen.RecordPackageName()
228 // With all user code typechecked, it's now safe to verify unused dot imports.
229 noder.CheckDotImports()
233 if initTask := pkginit.Task(); initTask != nil {
234 typecheck.Export(initTask)
238 base.Timer.Start("fe", "inlining")
239 if base.Flag.LowerL != 0 {
240 inline.InlinePackage()
244 for _, n := range typecheck.Target.Decls {
245 if n.Op() == ir.ODCLFUNC {
246 inline.Devirtualize(n.(*ir.Func))
252 // Required for moving heap allocations onto stack,
253 // which in turn is required by the closure implementation,
254 // which stores the addresses of stack variables into the closure.
255 // If the closure does not escape, it needs to be on the stack
256 // or else the stack copier will not update it.
257 // Large values are also moved off stack in escape analysis;
258 // because large values may contain pointers, it must happen early.
259 base.Timer.Start("fe", "escapes")
260 escape.Funcs(typecheck.Target.Decls)
262 // Collect information for go:nowritebarrierrec
263 // checking. This must happen before transformclosure.
264 // We'll do the final check after write barriers are
266 if base.Flag.CompilingRuntime {
267 ssagen.EnableNoWriteBarrierRecCheck()
270 // Transform closure bodies to properly reference captured variables.
271 // This needs to happen before walk, because closures must be transformed
272 // before walk reaches a call of a closure.
273 base.Timer.Start("fe", "xclosures")
274 for _, n := range typecheck.Target.Decls {
275 if n.Op() == ir.ODCLFUNC {
277 if n.OClosure != nil {
284 // Prepare for SSA compilation.
285 // This must be before peekitabs, because peekitabs
286 // can trigger function compilation.
289 // Just before compilation, compile itabs found on
290 // the right side of OCONVIFACE so that methods
291 // can be de-virtualized during compilation.
293 reflectdata.CompileITabs()
295 // Compile top level functions.
296 // Don't use range--walk can add functions to Target.Decls.
297 base.Timer.Start("be", "compilefuncs")
299 for i := 0; i < len(typecheck.Target.Decls); i++ {
300 n := typecheck.Target.Decls[i]
301 if n.Op() == ir.ODCLFUNC {
302 funccompile(n.(*ir.Func))
306 base.Timer.AddEvent(fcount, "funcs")
310 if base.Flag.CompilingRuntime {
311 // Write barriers are now known. Check the call graph.
312 ssagen.NoWriteBarrierRecCheck()
315 // Finalize DWARF inline routine DIEs, then explicitly turn off
316 // DWARF inlining gen so as to avoid problems with generated
318 if base.Ctxt.DwFixups != nil {
319 base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0)
320 base.Ctxt.DwFixups = nil
321 base.Flag.GenDwarfInl = 0
324 // Write object data to disk.
325 base.Timer.Start("be", "dumpobj")
327 base.Ctxt.NumberSyms()
329 if base.Flag.AsmHdr != "" {
333 ssagen.CheckLargeStacks()
334 typecheck.CheckFuncStack()
336 if len(compilequeue) != 0 {
337 base.Fatalf("%d uncompiled functions", len(compilequeue))
340 logopt.FlushLoggedOpts(base.Ctxt, base.Ctxt.Pkgpath)
346 if base.Flag.Bench != "" {
347 if err := writebench(base.Flag.Bench); err != nil {
348 log.Fatalf("cannot write benchmark data: %v", err)
353 func writebench(filename string) error {
354 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
360 fmt.Fprintln(&buf, "commit:", objabi.Version)
361 fmt.Fprintln(&buf, "goos:", runtime.GOOS)
362 fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
363 base.Timer.Write(&buf, "BenchmarkCompile:"+base.Ctxt.Pkgpath+":")
365 n, err := f.Write(buf.Bytes())
376 func makePos(b *src.PosBase, line, col uint) src.XPos {
377 return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col))