]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/main.go
68506c7a7b7d5e6074106f994d414754616a49b6
[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 package gc
6
7 import (
8         "bufio"
9         "bytes"
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"
25         "cmd/internal/dwarf"
26         "cmd/internal/obj"
27         "cmd/internal/objabi"
28         "cmd/internal/src"
29         "flag"
30         "fmt"
31         "log"
32         "os"
33         "runtime"
34 )
35
36 func hidePanic() {
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 {
43                         if err == "-h" {
44                                 panic(err)
45                         }
46                         base.ErrorExit()
47                 }
48         }
49 }
50
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")
56
57         defer hidePanic()
58
59         archInit(&ssagen.Arch)
60
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)
65
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
71
72         types.LocalPkg = types.NewPkg("", "")
73         types.LocalPkg.Prefix = "\"\""
74
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
79
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
83
84         // pseudo-package, accessed by import "unsafe"
85         ir.Pkgs.Unsafe = types.NewPkg("unsafe", "unsafe")
86
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
91         // insignificantly.
92         ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime")
93         ir.Pkgs.Runtime.Prefix = "runtime"
94
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
98
99         // pseudo-package used for methods with anonymous receivers
100         ir.Pkgs.Go = types.NewPkg("go", "")
101
102         base.DebugSSA = ssa.PhaseOption
103         base.ParseFlags()
104
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")
109
110         if !base.EnableTrace && base.Flag.LowerT {
111                 log.Fatalf("compiler not built with support for -t")
112         }
113
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
120         }
121
122         if base.Flag.SmallFrames {
123                 ir.MaxStackVarSize = 128 * 1024
124                 ir.MaxImplicitStackVarSize = 16 * 1024
125         }
126
127         if base.Flag.Dwarf {
128                 base.Ctxt.DebugInfo = dwarfgen.Info
129                 base.Ctxt.GenAbstractFunc = dwarfgen.AbstractFunc
130                 base.Ctxt.DwFixups = obj.NewDwarfFixupTable(base.Ctxt)
131         } else {
132                 // turn off inline generation if no dwarf at all
133                 base.Flag.GenDwarfInl = 0
134                 base.Ctxt.Flag_locationlists = false
135         }
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)
138         }
139
140         types.ParseLangFlag()
141
142         symABIs := ssagen.NewSymABIs(base.Ctxt.Pkgpath)
143         if base.Flag.SymABIs != "" {
144                 symABIs.ReadSymABIs(base.Flag.SymABIs)
145         }
146
147         if base.Compiling(base.NoInstrumentPkgs) {
148                 base.Flag.Race = false
149                 base.Flag.MSan = false
150         }
151
152         ssagen.Arch.LinkArch.Init(base.Ctxt)
153         startProfile()
154         if base.Flag.Race || base.Flag.MSan {
155                 base.Flag.Cfg.Instrumenting = true
156         }
157         if base.Flag.Dwarf {
158                 dwarf.EnableLogging(base.Debug.DwarfInl != 0)
159         }
160         if base.Debug.SoftFloat != 0 {
161                 if objabi.Experiment.RegabiArgs {
162                         log.Fatalf("softfloat mode with GOEXPERIMENT=regabiargs not implemented ")
163                 }
164                 ssagen.Arch.SoftFloat = true
165         }
166
167         if base.Flag.JSON != "" { // parse version,destination from json logging optimization.
168                 logopt.LogJsonOption(base.Flag.JSON)
169         }
170
171         ir.EscFmt = escape.Fmt
172         ir.IsIntrinsicCall = ssagen.IsIntrinsicCall
173         inline.SSADumpInline = ssagen.DumpInline
174         ssagen.InitEnv()
175         ssagen.InitTables()
176
177         types.PtrSize = ssagen.Arch.LinkArch.PtrSize
178         types.RegSize = ssagen.Arch.LinkArch.RegSize
179         types.MaxWidth = ssagen.Arch.MAXWIDTH
180
181         typecheck.Target = new(ir.Package)
182
183         typecheck.NeedITab = func(t, iface *types.Type) { reflectdata.ITabAddr(t, iface) }
184         typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): TypeSym for lock?
185
186         base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
187
188         typecheck.InitUniverse()
189
190         // Parse and typecheck input.
191         noder.LoadPackage(flag.Args())
192
193         dwarfgen.RecordPackageName()
194
195         // Build init task.
196         if initTask := pkginit.Task(); initTask != nil {
197                 typecheck.Export(initTask)
198         }
199
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))
205                 }
206         }
207
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
216         }
217         typecheck.IncrementalAddrtaken = true
218
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()
223         }
224
225         // Inlining
226         base.Timer.Start("fe", "inlining")
227         if base.Flag.LowerL != 0 {
228                 inline.InlinePackage()
229         }
230
231         // Devirtualize.
232         for _, n := range typecheck.Target.Decls {
233                 if n.Op() == ir.ODCLFUNC {
234                         devirtualize.Func(n.(*ir.Func))
235                 }
236         }
237         ir.CurFunc = nil
238
239         // Generate ABI wrappers. Must happen before escape analysis
240         // and doesn't benefit from dead-coding or inlining.
241         symABIs.GenABIWrappers()
242
243         // Escape analysis.
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)
253
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
257         // inserted.
258         if base.Flag.CompilingRuntime {
259                 ssagen.EnableNoWriteBarrierRecCheck()
260         }
261
262         // Prepare for SSA compilation.
263         // This must be before CompileITabs, because CompileITabs
264         // can trigger function compilation.
265         typecheck.InitRuntime()
266         ssagen.InitConfig()
267
268         // Just before compilation, compile itabs found on
269         // the right side of OCONVIFACE so that methods
270         // can be de-virtualized during compilation.
271         ir.CurFunc = nil
272         reflectdata.CompileITabs()
273
274         // Compile top level functions.
275         // Don't use range--walk can add functions to Target.Decls.
276         base.Timer.Start("be", "compilefuncs")
277         fcount := int64(0)
278         for i := 0; i < len(typecheck.Target.Decls); i++ {
279                 if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
280                         enqueueFunc(fn)
281                         fcount++
282                 }
283         }
284         base.Timer.AddEvent(fcount, "funcs")
285
286         compileFunctions()
287
288         if base.Flag.CompilingRuntime {
289                 // Write barriers are now known. Check the call graph.
290                 ssagen.NoWriteBarrierRecCheck()
291         }
292
293         // Finalize DWARF inline routine DIEs, then explicitly turn off
294         // DWARF inlining gen so as to avoid problems with generated
295         // method wrappers.
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
300         }
301
302         // Write object data to disk.
303         base.Timer.Start("be", "dumpobj")
304         dumpdata()
305         base.Ctxt.NumberSyms()
306         dumpobj()
307         if base.Flag.AsmHdr != "" {
308                 dumpasmhdr()
309         }
310
311         ssagen.CheckLargeStacks()
312         typecheck.CheckFuncStack()
313
314         if len(compilequeue) != 0 {
315                 base.Fatalf("%d uncompiled functions", len(compilequeue))
316         }
317
318         logopt.FlushLoggedOpts(base.Ctxt, base.Ctxt.Pkgpath)
319         base.ExitIfErrors()
320
321         base.FlushErrors()
322         base.Timer.Stop()
323
324         if base.Flag.Bench != "" {
325                 if err := writebench(base.Flag.Bench); err != nil {
326                         log.Fatalf("cannot write benchmark data: %v", err)
327                 }
328         }
329 }
330
331 func writebench(filename string) error {
332         f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
333         if err != nil {
334                 return err
335         }
336
337         var buf bytes.Buffer
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+":")
342
343         n, err := f.Write(buf.Bytes())
344         if err != nil {
345                 return err
346         }
347         if n != buf.Len() {
348                 panic("bad writer")
349         }
350
351         return f.Close()
352 }
353
354 func makePos(b *src.PosBase, line, col uint) src.XPos {
355         return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col))
356 }