Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/gc/main.go

Documentation: cmd/compile/internal/gc

     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  	"internal/buildcfg"
    32  	"log"
    33  	"os"
    34  	"runtime"
    35  )
    36  
    37  func hidePanic() {
    38  	if base.Debug.Panic == 0 && base.Errors() > 0 {
    39  		// If we've already complained about things
    40  		// in the program, don't bother complaining
    41  		// about a panic too; let the user clean up
    42  		// the code and try again.
    43  		if err := recover(); err != nil {
    44  			if err == "-h" {
    45  				panic(err)
    46  			}
    47  			base.ErrorExit()
    48  		}
    49  	}
    50  }
    51  
    52  // Main parses flags and Go source files specified in the command-line
    53  // arguments, type-checks the parsed Go package, compiles functions to machine
    54  // code, and finally writes the compiled package definition to disk.
    55  func Main(archInit func(*ssagen.ArchInfo)) {
    56  	base.Timer.Start("fe", "init")
    57  
    58  	defer hidePanic()
    59  
    60  	archInit(&ssagen.Arch)
    61  
    62  	base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch)
    63  	base.Ctxt.DiagFunc = base.Errorf
    64  	base.Ctxt.DiagFlush = base.FlushErrors
    65  	base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
    66  
    67  	// UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
    68  	// on Darwin don't support it properly, especially since macOS 10.14 (Mojave).  This is exposed as a flag
    69  	// to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
    70  	// See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
    71  	base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin
    72  
    73  	types.LocalPkg = types.NewPkg("", "")
    74  	types.LocalPkg.Prefix = "\"\""
    75  
    76  	// We won't know localpkg's height until after import
    77  	// processing. In the mean time, set to MaxPkgHeight to ensure
    78  	// height comparisons at least work until then.
    79  	types.LocalPkg.Height = types.MaxPkgHeight
    80  
    81  	// pseudo-package, for scoping
    82  	types.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
    83  	types.BuiltinPkg.Prefix = "go.builtin"            // not go%2ebuiltin
    84  
    85  	// pseudo-package, accessed by import "unsafe"
    86  	ir.Pkgs.Unsafe = types.NewPkg("unsafe", "unsafe")
    87  
    88  	// Pseudo-package that contains the compiler's builtin
    89  	// declarations for package runtime. These are declared in a
    90  	// separate package to avoid conflicts with package runtime's
    91  	// actual declarations, which may differ intentionally but
    92  	// insignificantly.
    93  	ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime")
    94  	ir.Pkgs.Runtime.Prefix = "runtime"
    95  
    96  	// pseudo-packages used in symbol tables
    97  	ir.Pkgs.Itab = types.NewPkg("go.itab", "go.itab")
    98  	ir.Pkgs.Itab.Prefix = "go.itab" // not go%2eitab
    99  
   100  	// pseudo-package used for methods with anonymous receivers
   101  	ir.Pkgs.Go = types.NewPkg("go", "")
   102  
   103  	base.DebugSSA = ssa.PhaseOption
   104  	base.ParseFlags()
   105  
   106  	// Record flags that affect the build result. (And don't
   107  	// record flags that don't, since that would cause spurious
   108  	// changes in the binary.)
   109  	dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
   110  
   111  	if !base.EnableTrace && base.Flag.LowerT {
   112  		log.Fatalf("compiler not built with support for -t")
   113  	}
   114  
   115  	// Enable inlining (after RecordFlags, to avoid recording the rewritten -l).  For now:
   116  	//	default: inlining on.  (Flag.LowerL == 1)
   117  	//	-l: inlining off  (Flag.LowerL == 0)
   118  	//	-l=2, -l=3: inlining on again, with extra debugging (Flag.LowerL > 1)
   119  	if base.Flag.LowerL <= 1 {
   120  		base.Flag.LowerL = 1 - base.Flag.LowerL
   121  	}
   122  
   123  	if base.Flag.SmallFrames {
   124  		ir.MaxStackVarSize = 128 * 1024
   125  		ir.MaxImplicitStackVarSize = 16 * 1024
   126  	}
   127  
   128  	if base.Flag.Dwarf {
   129  		base.Ctxt.DebugInfo = dwarfgen.Info
   130  		base.Ctxt.GenAbstractFunc = dwarfgen.AbstractFunc
   131  		base.Ctxt.DwFixups = obj.NewDwarfFixupTable(base.Ctxt)
   132  	} else {
   133  		// turn off inline generation if no dwarf at all
   134  		base.Flag.GenDwarfInl = 0
   135  		base.Ctxt.Flag_locationlists = false
   136  	}
   137  	if base.Ctxt.Flag_locationlists && len(base.Ctxt.Arch.DWARFRegisters) == 0 {
   138  		log.Fatalf("location lists requested but register mapping not available on %v", base.Ctxt.Arch.Name)
   139  	}
   140  
   141  	types.ParseLangFlag()
   142  
   143  	symABIs := ssagen.NewSymABIs(base.Ctxt.Pkgpath)
   144  	if base.Flag.SymABIs != "" {
   145  		symABIs.ReadSymABIs(base.Flag.SymABIs)
   146  	}
   147  
   148  	if base.Compiling(base.NoInstrumentPkgs) {
   149  		base.Flag.Race = false
   150  		base.Flag.MSan = false
   151  	}
   152  
   153  	ssagen.Arch.LinkArch.Init(base.Ctxt)
   154  	startProfile()
   155  	if base.Flag.Race || base.Flag.MSan {
   156  		base.Flag.Cfg.Instrumenting = true
   157  	}
   158  	if base.Flag.Dwarf {
   159  		dwarf.EnableLogging(base.Debug.DwarfInl != 0)
   160  	}
   161  	if base.Debug.SoftFloat != 0 {
   162  		if buildcfg.Experiment.RegabiArgs {
   163  			log.Fatalf("softfloat mode with GOEXPERIMENT=regabiargs not implemented ")
   164  		}
   165  		ssagen.Arch.SoftFloat = true
   166  	}
   167  
   168  	if base.Flag.JSON != "" { // parse version,destination from json logging optimization.
   169  		logopt.LogJsonOption(base.Flag.JSON)
   170  	}
   171  
   172  	ir.EscFmt = escape.Fmt
   173  	ir.IsIntrinsicCall = ssagen.IsIntrinsicCall
   174  	inline.SSADumpInline = ssagen.DumpInline
   175  	ssagen.InitEnv()
   176  	ssagen.InitTables()
   177  
   178  	types.PtrSize = ssagen.Arch.LinkArch.PtrSize
   179  	types.RegSize = ssagen.Arch.LinkArch.RegSize
   180  	types.MaxWidth = ssagen.Arch.MAXWIDTH
   181  
   182  	typecheck.Target = new(ir.Package)
   183  
   184  	typecheck.NeedITab = func(t, iface *types.Type) { reflectdata.ITabAddr(t, iface) }
   185  	typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): TypeSym for lock?
   186  
   187  	base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
   188  
   189  	typecheck.InitUniverse()
   190  
   191  	// Parse and typecheck input.
   192  	noder.LoadPackage(flag.Args())
   193  
   194  	dwarfgen.RecordPackageName()
   195  
   196  	// Build init task.
   197  	if initTask := pkginit.Task(); initTask != nil {
   198  		typecheck.Export(initTask)
   199  	}
   200  
   201  	// Eliminate some obviously dead code.
   202  	// Must happen after typechecking.
   203  	for _, n := range typecheck.Target.Decls {
   204  		if n.Op() == ir.ODCLFUNC {
   205  			deadcode.Func(n.(*ir.Func))
   206  		}
   207  	}
   208  
   209  	// Compute Addrtaken for names.
   210  	// We need to wait until typechecking is done so that when we see &x[i]
   211  	// we know that x has its address taken if x is an array, but not if x is a slice.
   212  	// We compute Addrtaken in bulk here.
   213  	// After this phase, we maintain Addrtaken incrementally.
   214  	if typecheck.DirtyAddrtaken {
   215  		typecheck.ComputeAddrtaken(typecheck.Target.Decls)
   216  		typecheck.DirtyAddrtaken = false
   217  	}
   218  	typecheck.IncrementalAddrtaken = true
   219  
   220  	if base.Debug.TypecheckInl != 0 {
   221  		// Typecheck imported function bodies if Debug.l > 1,
   222  		// otherwise lazily when used or re-exported.
   223  		typecheck.AllImportedBodies()
   224  	}
   225  
   226  	// Inlining
   227  	base.Timer.Start("fe", "inlining")
   228  	if base.Flag.LowerL != 0 {
   229  		inline.InlinePackage()
   230  	}
   231  
   232  	// Devirtualize.
   233  	for _, n := range typecheck.Target.Decls {
   234  		if n.Op() == ir.ODCLFUNC {
   235  			devirtualize.Func(n.(*ir.Func))
   236  		}
   237  	}
   238  	ir.CurFunc = nil
   239  
   240  	// Generate ABI wrappers. Must happen before escape analysis
   241  	// and doesn't benefit from dead-coding or inlining.
   242  	symABIs.GenABIWrappers()
   243  
   244  	// Escape analysis.
   245  	// Required for moving heap allocations onto stack,
   246  	// which in turn is required by the closure implementation,
   247  	// which stores the addresses of stack variables into the closure.
   248  	// If the closure does not escape, it needs to be on the stack
   249  	// or else the stack copier will not update it.
   250  	// Large values are also moved off stack in escape analysis;
   251  	// because large values may contain pointers, it must happen early.
   252  	base.Timer.Start("fe", "escapes")
   253  	escape.Funcs(typecheck.Target.Decls)
   254  
   255  	// Collect information for go:nowritebarrierrec
   256  	// checking. This must happen before transforming closures during Walk
   257  	// We'll do the final check after write barriers are
   258  	// inserted.
   259  	if base.Flag.CompilingRuntime {
   260  		ssagen.EnableNoWriteBarrierRecCheck()
   261  	}
   262  
   263  	// Prepare for SSA compilation.
   264  	// This must be before CompileITabs, because CompileITabs
   265  	// can trigger function compilation.
   266  	typecheck.InitRuntime()
   267  	ssagen.InitConfig()
   268  
   269  	// Just before compilation, compile itabs found on
   270  	// the right side of OCONVIFACE so that methods
   271  	// can be de-virtualized during compilation.
   272  	ir.CurFunc = nil
   273  	reflectdata.CompileITabs()
   274  
   275  	// Compile top level functions.
   276  	// Don't use range--walk can add functions to Target.Decls.
   277  	base.Timer.Start("be", "compilefuncs")
   278  	fcount := int64(0)
   279  	for i := 0; i < len(typecheck.Target.Decls); i++ {
   280  		if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
   281  			enqueueFunc(fn)
   282  			fcount++
   283  		}
   284  	}
   285  	base.Timer.AddEvent(fcount, "funcs")
   286  
   287  	compileFunctions()
   288  
   289  	if base.Flag.CompilingRuntime {
   290  		// Write barriers are now known. Check the call graph.
   291  		ssagen.NoWriteBarrierRecCheck()
   292  	}
   293  
   294  	// Finalize DWARF inline routine DIEs, then explicitly turn off
   295  	// DWARF inlining gen so as to avoid problems with generated
   296  	// method wrappers.
   297  	if base.Ctxt.DwFixups != nil {
   298  		base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0)
   299  		base.Ctxt.DwFixups = nil
   300  		base.Flag.GenDwarfInl = 0
   301  	}
   302  
   303  	// Write object data to disk.
   304  	base.Timer.Start("be", "dumpobj")
   305  	dumpdata()
   306  	base.Ctxt.NumberSyms()
   307  	dumpobj()
   308  	if base.Flag.AsmHdr != "" {
   309  		dumpasmhdr()
   310  	}
   311  
   312  	ssagen.CheckLargeStacks()
   313  	typecheck.CheckFuncStack()
   314  
   315  	if len(compilequeue) != 0 {
   316  		base.Fatalf("%d uncompiled functions", len(compilequeue))
   317  	}
   318  
   319  	logopt.FlushLoggedOpts(base.Ctxt, base.Ctxt.Pkgpath)
   320  	base.ExitIfErrors()
   321  
   322  	base.FlushErrors()
   323  	base.Timer.Stop()
   324  
   325  	if base.Flag.Bench != "" {
   326  		if err := writebench(base.Flag.Bench); err != nil {
   327  			log.Fatalf("cannot write benchmark data: %v", err)
   328  		}
   329  	}
   330  }
   331  
   332  func writebench(filename string) error {
   333  	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   334  	if err != nil {
   335  		return err
   336  	}
   337  
   338  	var buf bytes.Buffer
   339  	fmt.Fprintln(&buf, "commit:", buildcfg.Version)
   340  	fmt.Fprintln(&buf, "goos:", runtime.GOOS)
   341  	fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
   342  	base.Timer.Write(&buf, "BenchmarkCompile:"+base.Ctxt.Pkgpath+":")
   343  
   344  	n, err := f.Write(buf.Bytes())
   345  	if err != nil {
   346  		return err
   347  	}
   348  	if n != buf.Len() {
   349  		panic("bad writer")
   350  	}
   351  
   352  	return f.Close()
   353  }
   354  
   355  func makePos(b *src.PosBase, line, col uint) src.XPos {
   356  	return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col))
   357  }
   358  

View as plain text