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