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