]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/main.go
[dev.typeparams] all: merge dev.regabi (37f138d) into dev.typeparams
[gostls13.git] / src / cmd / compile / internal / gc / main.go
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.
4
5 //go:generate go run mkbuiltin.go
6
7 package gc
8
9 import (
10         "bufio"
11         "bytes"
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"
27         "cmd/internal/dwarf"
28         "cmd/internal/obj"
29         "cmd/internal/objabi"
30         "cmd/internal/src"
31         "flag"
32         "fmt"
33         "log"
34         "os"
35         "runtime"
36 )
37
38 func hidePanic() {
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 {
45                         if err == "-h" {
46                                 panic(err)
47                         }
48                         base.ErrorExit()
49                 }
50         }
51 }
52
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")
58
59         defer hidePanic()
60
61         archInit(&ssagen.Arch)
62
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)
67
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
73
74         types.LocalPkg = types.NewPkg("", "")
75         types.LocalPkg.Prefix = "\"\""
76
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
81
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
85
86         // pseudo-package, accessed by import "unsafe"
87         ir.Pkgs.Unsafe = types.NewPkg("unsafe", "unsafe")
88
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
93         // insignificantly.
94         ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime")
95         ir.Pkgs.Runtime.Prefix = "runtime"
96
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
100
101         ir.Pkgs.Itablink = types.NewPkg("go.itablink", "go.itablink")
102         ir.Pkgs.Itablink.Prefix = "go.itablink" // not go%2eitablink
103
104         ir.Pkgs.Track = types.NewPkg("go.track", "go.track")
105         ir.Pkgs.Track.Prefix = "go.track" // not go%2etrack
106
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"
110
111         // pseudo-package used for methods with anonymous receivers
112         ir.Pkgs.Go = types.NewPkg("go", "")
113
114         base.DebugSSA = ssa.PhaseOption
115         base.ParseFlags()
116
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")
121
122         if !base.EnableTrace && base.Flag.LowerT {
123                 log.Fatalf("compiler not built with support for -t")
124         }
125
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
132         }
133
134         if base.Flag.SmallFrames {
135                 ir.MaxStackVarSize = 128 * 1024
136                 ir.MaxImplicitStackVarSize = 16 * 1024
137         }
138
139         if base.Flag.Dwarf {
140                 base.Ctxt.DebugInfo = dwarfgen.Info
141                 base.Ctxt.GenAbstractFunc = dwarfgen.AbstractFunc
142                 base.Ctxt.DwFixups = obj.NewDwarfFixupTable(base.Ctxt)
143         } else {
144                 // turn off inline generation if no dwarf at all
145                 base.Flag.GenDwarfInl = 0
146                 base.Ctxt.Flag_locationlists = false
147         }
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)
150         }
151
152         types.ParseLangFlag()
153
154         if base.Flag.SymABIs != "" {
155                 ssagen.ReadSymABIs(base.Flag.SymABIs, base.Ctxt.Pkgpath)
156         }
157
158         if base.Compiling(base.NoInstrumentPkgs) {
159                 base.Flag.Race = false
160                 base.Flag.MSan = false
161         }
162
163         ssagen.Arch.LinkArch.Init(base.Ctxt)
164         startProfile()
165         if base.Flag.Race {
166                 ir.Pkgs.Race = types.NewPkg("runtime/race", "")
167         }
168         if base.Flag.MSan {
169                 ir.Pkgs.Msan = types.NewPkg("runtime/msan", "")
170         }
171         if base.Flag.Race || base.Flag.MSan {
172                 base.Flag.Cfg.Instrumenting = true
173         }
174         if base.Flag.Dwarf {
175                 dwarf.EnableLogging(base.Debug.DwarfInl != 0)
176         }
177         if base.Debug.SoftFloat != 0 {
178                 ssagen.Arch.SoftFloat = true
179         }
180
181         if base.Flag.JSON != "" { // parse version,destination from json logging optimization.
182                 logopt.LogJsonOption(base.Flag.JSON)
183         }
184
185         ir.EscFmt = escape.Fmt
186         ir.IsIntrinsicCall = ssagen.IsIntrinsicCall
187         inline.SSADumpInline = ssagen.DumpInline
188         ssagen.InitEnv()
189         ssagen.InitTables()
190
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()
196         }
197
198         typecheck.Target = new(ir.Package)
199
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?
203
204         base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
205
206         types.TypeLinkSym = func(t *types.Type) *obj.LSym {
207                 return reflectdata.TypeSym(t).Linksym()
208         }
209         typecheck.Init()
210
211         // Parse input.
212         base.Timer.Start("fe", "parse")
213         lines := noder.ParseFiles(flag.Args())
214         ssagen.CgoSymABIs()
215         base.Timer.Stop()
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
219                 base.ExitIfErrors()
220                 return
221         }
222
223         dwarfgen.RecordPackageName()
224
225         // Typecheck.
226         typecheck.Package()
227
228         // With all user code typechecked, it's now safe to verify unused dot imports.
229         noder.CheckDotImports()
230         base.ExitIfErrors()
231
232         // Build init task.
233         if initTask := pkginit.Task(); initTask != nil {
234                 typecheck.Export(initTask)
235         }
236
237         // Inlining
238         base.Timer.Start("fe", "inlining")
239         if base.Flag.LowerL != 0 {
240                 inline.InlinePackage()
241         }
242
243         // Devirtualize.
244         for _, n := range typecheck.Target.Decls {
245                 if n.Op() == ir.ODCLFUNC {
246                         inline.Devirtualize(n.(*ir.Func))
247                 }
248         }
249         ir.CurFunc = nil
250
251         // Escape analysis.
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)
261
262         // Collect information for go:nowritebarrierrec
263         // checking. This must happen before transformclosure.
264         // We'll do the final check after write barriers are
265         // inserted.
266         if base.Flag.CompilingRuntime {
267                 ssagen.EnableNoWriteBarrierRecCheck()
268         }
269
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 {
276                         n := n.(*ir.Func)
277                         if n.OClosure != nil {
278                                 ir.CurFunc = n
279                                 walk.Closure(n)
280                         }
281                 }
282         }
283
284         // Prepare for SSA compilation.
285         // This must be before peekitabs, because peekitabs
286         // can trigger function compilation.
287         ssagen.InitConfig()
288
289         // Just before compilation, compile itabs found on
290         // the right side of OCONVIFACE so that methods
291         // can be de-virtualized during compilation.
292         ir.CurFunc = nil
293         reflectdata.CompileITabs()
294
295         // Compile top level functions.
296         // Don't use range--walk can add functions to Target.Decls.
297         base.Timer.Start("be", "compilefuncs")
298         fcount := int64(0)
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))
303                         fcount++
304                 }
305         }
306         base.Timer.AddEvent(fcount, "funcs")
307
308         compileFunctions()
309
310         if base.Flag.CompilingRuntime {
311                 // Write barriers are now known. Check the call graph.
312                 ssagen.NoWriteBarrierRecCheck()
313         }
314
315         // Finalize DWARF inline routine DIEs, then explicitly turn off
316         // DWARF inlining gen so as to avoid problems with generated
317         // method wrappers.
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
322         }
323
324         // Write object data to disk.
325         base.Timer.Start("be", "dumpobj")
326         dumpdata()
327         base.Ctxt.NumberSyms()
328         dumpobj()
329         if base.Flag.AsmHdr != "" {
330                 dumpasmhdr()
331         }
332
333         ssagen.CheckLargeStacks()
334         typecheck.CheckFuncStack()
335
336         if len(compilequeue) != 0 {
337                 base.Fatalf("%d uncompiled functions", len(compilequeue))
338         }
339
340         logopt.FlushLoggedOpts(base.Ctxt, base.Ctxt.Pkgpath)
341         base.ExitIfErrors()
342
343         base.FlushErrors()
344         base.Timer.Stop()
345
346         if base.Flag.Bench != "" {
347                 if err := writebench(base.Flag.Bench); err != nil {
348                         log.Fatalf("cannot write benchmark data: %v", err)
349                 }
350         }
351 }
352
353 func writebench(filename string) error {
354         f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
355         if err != nil {
356                 return err
357         }
358
359         var buf bytes.Buffer
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+":")
364
365         n, err := f.Write(buf.Bytes())
366         if err != nil {
367                 return err
368         }
369         if n != buf.Len() {
370                 panic("bad writer")
371         }
372
373         return f.Close()
374 }
375
376 func makePos(b *src.PosBase, line, col uint) src.XPos {
377         return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col))
378 }