github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/gc/main.go (about) 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 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 11 "github.com/bir3/gocompiler/src/cmd/compile/internal/coverage" 12 "github.com/bir3/gocompiler/src/cmd/compile/internal/deadcode" 13 "github.com/bir3/gocompiler/src/cmd/compile/internal/devirtualize" 14 "github.com/bir3/gocompiler/src/cmd/compile/internal/dwarfgen" 15 "github.com/bir3/gocompiler/src/cmd/compile/internal/escape" 16 "github.com/bir3/gocompiler/src/cmd/compile/internal/inline" 17 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 18 "github.com/bir3/gocompiler/src/cmd/compile/internal/logopt" 19 "github.com/bir3/gocompiler/src/cmd/compile/internal/noder" 20 "github.com/bir3/gocompiler/src/cmd/compile/internal/pgo" 21 "github.com/bir3/gocompiler/src/cmd/compile/internal/pkginit" 22 "github.com/bir3/gocompiler/src/cmd/compile/internal/reflectdata" 23 "github.com/bir3/gocompiler/src/cmd/compile/internal/ssa" 24 "github.com/bir3/gocompiler/src/cmd/compile/internal/ssagen" 25 "github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck" 26 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 27 "github.com/bir3/gocompiler/src/cmd/internal/dwarf" 28 "github.com/bir3/gocompiler/src/cmd/internal/obj" 29 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 30 "github.com/bir3/gocompiler/src/cmd/internal/src" 31 "github.com/bir3/gocompiler/src/cmd/compile/flag" 32 "fmt" 33 "github.com/bir3/gocompiler/src/internal/buildcfg" 34 "log" 35 "os" 36 "runtime" 37 ) 38 39 // handlePanic ensures that we print out an "internal compiler error" for any panic 40 // or runtime exception during front-end compiler processing (unless there have 41 // already been some compiler errors). It may also be invoked from the explicit panic in 42 // hcrash(), in which case, we pass the panic on through. 43 func handlePanic() { 44 if err := recover(); err != nil { 45 if err == "-h" { 46 // Force real panic now with -h option (hcrash) - the error 47 // information will have already been printed. 48 panic(err) 49 } 50 base.Fatalf("panic: %v", err) 51 } 52 } 53 54 // Main parses flags and Go source files specified in the command-line 55 // arguments, type-checks the parsed Go package, compiles functions to machine 56 // code, and finally writes the compiled package definition to disk. 57 func Main(archInit func(*ssagen.ArchInfo)) { 58 base.Timer.Start("fe", "init") 59 60 defer handlePanic() 61 62 archInit(&ssagen.Arch) 63 64 base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch) 65 base.Ctxt.DiagFunc = base.Errorf 66 base.Ctxt.DiagFlush = base.FlushErrors 67 base.Ctxt.Bso = bufio.NewWriter(os.Stdout) 68 69 // UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump 70 // on Darwin don't support it properly, especially since macOS 10.14 (Mojave). This is exposed as a flag 71 // to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project. 72 // See bugs 31188 and 21945 (CLs 170638, 98075, 72371). 73 base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin 74 75 base.DebugSSA = ssa.PhaseOption 76 base.ParseFlags() 77 78 if os.Getenv("GOGC") == "" { // GOGC set disables starting heap adjustment 79 // More processors will use more heap, but assume that more memory is available. 80 // So 1 processor -> 40MB, 4 -> 64MB, 12 -> 128MB 81 base.AdjustStartingHeap(uint64(32+8*base.Flag.LowerC) << 20) 82 } 83 84 types.LocalPkg = types.NewPkg(base.Ctxt.Pkgpath, "") 85 86 // pseudo-package, for scoping 87 types.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin? 88 types.BuiltinPkg.Prefix = "go:builtin" 89 90 // pseudo-package, accessed by import "unsafe" 91 types.UnsafePkg = types.NewPkg("unsafe", "unsafe") 92 93 // Pseudo-package that contains the compiler's builtin 94 // declarations for package runtime. These are declared in a 95 // separate package to avoid conflicts with package runtime's 96 // actual declarations, which may differ intentionally but 97 // insignificantly. 98 ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime") 99 ir.Pkgs.Runtime.Prefix = "runtime" 100 101 // pseudo-packages used in symbol tables 102 ir.Pkgs.Itab = types.NewPkg("go.itab", "go.itab") 103 ir.Pkgs.Itab.Prefix = "go:itab" 104 105 // pseudo-package used for methods with anonymous receivers 106 ir.Pkgs.Go = types.NewPkg("go", "") 107 108 // pseudo-package for use with code coverage instrumentation. 109 ir.Pkgs.Coverage = types.NewPkg("go.coverage", "runtime/coverage") 110 ir.Pkgs.Coverage.Prefix = "runtime/coverage" 111 112 // Record flags that affect the build result. (And don't 113 // record flags that don't, since that would cause spurious 114 // changes in the binary.) 115 dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "asan", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre") 116 117 if !base.EnableTrace && base.Flag.LowerT { 118 log.Fatalf("compiler not built with support for -t") 119 } 120 121 // Enable inlining (after RecordFlags, to avoid recording the rewritten -l). For now: 122 // default: inlining on. (Flag.LowerL == 1) 123 // -l: inlining off (Flag.LowerL == 0) 124 // -l=2, -l=3: inlining on again, with extra debugging (Flag.LowerL > 1) 125 if base.Flag.LowerL <= 1 { 126 base.Flag.LowerL = 1 - base.Flag.LowerL 127 } 128 129 if base.Flag.SmallFrames { 130 ir.MaxStackVarSize = 128 * 1024 131 ir.MaxImplicitStackVarSize = 16 * 1024 132 } 133 134 if base.Flag.Dwarf { 135 base.Ctxt.DebugInfo = dwarfgen.Info 136 base.Ctxt.GenAbstractFunc = dwarfgen.AbstractFunc 137 base.Ctxt.DwFixups = obj.NewDwarfFixupTable(base.Ctxt) 138 } else { 139 // turn off inline generation if no dwarf at all 140 base.Flag.GenDwarfInl = 0 141 base.Ctxt.Flag_locationlists = false 142 } 143 if base.Ctxt.Flag_locationlists && len(base.Ctxt.Arch.DWARFRegisters) == 0 { 144 log.Fatalf("location lists requested but register mapping not available on %v", base.Ctxt.Arch.Name) 145 } 146 147 types.ParseLangFlag() 148 149 symABIs := ssagen.NewSymABIs() 150 if base.Flag.SymABIs != "" { 151 symABIs.ReadSymABIs(base.Flag.SymABIs) 152 } 153 154 if base.Compiling(base.NoInstrumentPkgs) { 155 base.Flag.Race = false 156 base.Flag.MSan = false 157 base.Flag.ASan = false 158 } 159 160 ssagen.Arch.LinkArch.Init(base.Ctxt) 161 startProfile() 162 if base.Flag.Race || base.Flag.MSan || base.Flag.ASan { 163 base.Flag.Cfg.Instrumenting = true 164 } 165 if base.Flag.Dwarf { 166 dwarf.EnableLogging(base.Debug.DwarfInl != 0) 167 } 168 if base.Debug.SoftFloat != 0 { 169 ssagen.Arch.SoftFloat = true 170 } 171 172 if base.Flag.JSON != "" { // parse version,destination from json logging optimization. 173 logopt.LogJsonOption(base.Flag.JSON) 174 } 175 176 ir.EscFmt = escape.Fmt 177 ir.IsIntrinsicCall = ssagen.IsIntrinsicCall 178 inline.SSADumpInline = ssagen.DumpInline 179 ssagen.InitEnv() 180 ssagen.InitTables() 181 182 types.PtrSize = ssagen.Arch.LinkArch.PtrSize 183 types.RegSize = ssagen.Arch.LinkArch.RegSize 184 types.MaxWidth = ssagen.Arch.MAXWIDTH 185 186 typecheck.Target = new(ir.Package) 187 188 typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): TypeSym for lock? 189 190 base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0) 191 192 typecheck.InitUniverse() 193 typecheck.InitRuntime() 194 195 // Parse and typecheck input. 196 noder.LoadPackage(flag.Args()) 197 198 // As a convenience to users (toolchain maintainers, in particular), 199 // when compiling a package named "main", we default the package 200 // path to "main" if the -p flag was not specified. 201 if base.Ctxt.Pkgpath == obj.UnlinkablePkg && types.LocalPkg.Name == "main" { 202 base.Ctxt.Pkgpath = "main" 203 types.LocalPkg.Path = "main" 204 types.LocalPkg.Prefix = "main" 205 } 206 207 dwarfgen.RecordPackageName() 208 209 // Prepare for backend processing. This must happen before pkginit, 210 // because it generates itabs for initializing global variables. 211 ssagen.InitConfig() 212 213 // First part of coverage fixup (if applicable). 214 var cnames coverage.Names 215 if base.Flag.Cfg.CoverageInfo != nil { 216 cnames = coverage.FixupVars() 217 } 218 219 // Create "init" function for package-scope variable initialization 220 // statements, if any. 221 // 222 // Note: This needs to happen early, before any optimizations. The 223 // Go spec defines a precise order than initialization should be 224 // carried out in, and even mundane optimizations like dead code 225 // removal can skew the results (e.g., #43444). 226 pkginit.MakeInit() 227 228 // Second part of code coverage fixup (init func modification), 229 // if applicable. 230 if base.Flag.Cfg.CoverageInfo != nil { 231 coverage.FixupInit(cnames) 232 } 233 234 // Eliminate some obviously dead code. 235 // Must happen after typechecking. 236 for _, n := range typecheck.Target.Decls { 237 if n.Op() == ir.ODCLFUNC { 238 deadcode.Func(n.(*ir.Func)) 239 } 240 } 241 242 // Compute Addrtaken for names. 243 // We need to wait until typechecking is done so that when we see &x[i] 244 // we know that x has its address taken if x is an array, but not if x is a slice. 245 // We compute Addrtaken in bulk here. 246 // After this phase, we maintain Addrtaken incrementally. 247 if typecheck.DirtyAddrtaken { 248 typecheck.ComputeAddrtaken(typecheck.Target.Decls) 249 typecheck.DirtyAddrtaken = false 250 } 251 typecheck.IncrementalAddrtaken = true 252 253 if base.Debug.TypecheckInl != 0 { 254 // Typecheck imported function bodies if Debug.l > 1, 255 // otherwise lazily when used or re-exported. 256 typecheck.AllImportedBodies() 257 } 258 259 // Read profile file and build profile-graph and weighted-call-graph. 260 base.Timer.Start("fe", "pgoprofile") 261 var profile *pgo.Profile 262 if base.Flag.PgoProfile != "" { 263 profile = pgo.New(base.Flag.PgoProfile) 264 } 265 266 // Inlining 267 base.Timer.Start("fe", "inlining") 268 if base.Flag.LowerL != 0 { 269 inline.InlinePackage(profile) 270 } 271 noder.MakeWrappers(typecheck.Target) // must happen after inlining 272 273 // Devirtualize. 274 for _, n := range typecheck.Target.Decls { 275 if n.Op() == ir.ODCLFUNC { 276 devirtualize.Func(n.(*ir.Func)) 277 } 278 } 279 ir.CurFunc = nil 280 281 // Build init task, if needed. 282 if initTask := pkginit.Task(); initTask != nil { 283 typecheck.Export(initTask) 284 } 285 286 // Generate ABI wrappers. Must happen before escape analysis 287 // and doesn't benefit from dead-coding or inlining. 288 symABIs.GenABIWrappers() 289 290 // Escape analysis. 291 // Required for moving heap allocations onto stack, 292 // which in turn is required by the closure implementation, 293 // which stores the addresses of stack variables into the closure. 294 // If the closure does not escape, it needs to be on the stack 295 // or else the stack copier will not update it. 296 // Large values are also moved off stack in escape analysis; 297 // because large values may contain pointers, it must happen early. 298 base.Timer.Start("fe", "escapes") 299 escape.Funcs(typecheck.Target.Decls) 300 301 // TODO(mdempsky): This is a hack. We need a proper, global work 302 // queue for scheduling function compilation so components don't 303 // need to adjust their behavior depending on when they're called. 304 reflectdata.AfterGlobalEscapeAnalysis = true 305 306 // Collect information for go:nowritebarrierrec 307 // checking. This must happen before transforming closures during Walk 308 // We'll do the final check after write barriers are 309 // inserted. 310 if base.Flag.CompilingRuntime { 311 ssagen.EnableNoWriteBarrierRecCheck() 312 } 313 314 ir.CurFunc = nil 315 316 // Compile top level functions. 317 // Don't use range--walk can add functions to Target.Decls. 318 base.Timer.Start("be", "compilefuncs") 319 fcount := int64(0) 320 for i := 0; i < len(typecheck.Target.Decls); i++ { 321 if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok { 322 // Don't try compiling dead hidden closure. 323 if fn.IsDeadcodeClosure() { 324 continue 325 } 326 enqueueFunc(fn) 327 fcount++ 328 } 329 } 330 base.Timer.AddEvent(fcount, "funcs") 331 332 compileFunctions() 333 334 if base.Flag.CompilingRuntime { 335 // Write barriers are now known. Check the call graph. 336 ssagen.NoWriteBarrierRecCheck() 337 } 338 339 // Finalize DWARF inline routine DIEs, then explicitly turn off 340 // DWARF inlining gen so as to avoid problems with generated 341 // method wrappers. 342 if base.Ctxt.DwFixups != nil { 343 base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0) 344 base.Ctxt.DwFixups = nil 345 base.Flag.GenDwarfInl = 0 346 } 347 348 // Write object data to disk. 349 base.Timer.Start("be", "dumpobj") 350 dumpdata() 351 base.Ctxt.NumberSyms() 352 dumpobj() 353 if base.Flag.AsmHdr != "" { 354 dumpasmhdr() 355 } 356 357 ssagen.CheckLargeStacks() 358 typecheck.CheckFuncStack() 359 360 if len(compilequeue) != 0 { 361 base.Fatalf("%d uncompiled functions", len(compilequeue)) 362 } 363 364 logopt.FlushLoggedOpts(base.Ctxt, base.Ctxt.Pkgpath) 365 base.ExitIfErrors() 366 367 base.FlushErrors() 368 base.Timer.Stop() 369 370 if base.Flag.Bench != "" { 371 if err := writebench(base.Flag.Bench); err != nil { 372 log.Fatalf("cannot write benchmark data: %v", err) 373 } 374 } 375 } 376 377 func writebench(filename string) error { 378 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) 379 if err != nil { 380 return err 381 } 382 383 var buf bytes.Buffer 384 fmt.Fprintln(&buf, "commit:", buildcfg.Version) 385 fmt.Fprintln(&buf, "goos:", runtime.GOOS) 386 fmt.Fprintln(&buf, "goarch:", runtime.GOARCH) 387 base.Timer.Write(&buf, "BenchmarkCompile:"+base.Ctxt.Pkgpath+":") 388 389 n, err := f.Write(buf.Bytes()) 390 if err != nil { 391 return err 392 } 393 if n != buf.Len() { 394 panic("bad writer") 395 } 396 397 return f.Close() 398 } 399 400 func makePos(b *src.PosBase, line, col uint) src.XPos { 401 return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col)) 402 }