aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc/main.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2020-12-21 02:08:34 -0500
committerRuss Cox <rsc@golang.org>2020-12-22 19:32:10 +0000
commit572f168ed26bb32e83562cffb336f2df3a651d9c (patch)
tree9b63c61be606118972fc03d285c0893a85e6856f /src/cmd/compile/internal/gc/main.go
parent3b12c6dc089f63d0fe2eeda27e65feb51c5e36d4 (diff)
downloadgo-572f168ed26bb32e83562cffb336f2df3a651d9c.tar.gz
go-572f168ed26bb32e83562cffb336f2df3a651d9c.zip
[dev.regabi] cmd/compile: separate various from Main
Move various code out of Main itself and into helper functions that can be moved into other packages as package gc splits up. Similarly, move order and instrument inside walk to reduce the amount of API surface needed from the eventual package walk. Change-Id: I7849258038c6e39625a0385af9c0edd6a3b654a1 Reviewed-on: https://go-review.googlesource.com/c/go/+/279304 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/cmd/compile/internal/gc/main.go')
-rw-r--r--src/cmd/compile/internal/gc/main.go203
1 files changed, 37 insertions, 166 deletions
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 2a5ff3f5fd..4aa2a2ca47 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -191,24 +191,15 @@ func Main(archInit func(*Arch)) {
IsIntrinsicCall = isIntrinsicCall
SSADumpInline = ssaDumpInline
-
- ssaDump = os.Getenv("GOSSAFUNC")
- ssaDir = os.Getenv("GOSSADIR")
- if ssaDump != "" {
- if strings.HasSuffix(ssaDump, "+") {
- ssaDump = ssaDump[:len(ssaDump)-1]
- ssaDumpStdout = true
- }
- spl := strings.Split(ssaDump, ":")
- if len(spl) > 1 {
- ssaDump = spl[0]
- ssaDumpCFG = spl[1]
- }
- }
+ initSSAEnv()
+ initSSATables()
Widthptr = thearch.LinkArch.PtrSize
Widthreg = thearch.LinkArch.RegSize
MaxWidth = thearch.MAXWIDTH
+ types.TypeLinkSym = func(t *types.Type) *obj.LSym {
+ return typenamesym(t).Linksym()
+ }
Target = new(ir.Package)
@@ -216,152 +207,40 @@ func Main(archInit func(*Arch)) {
NeedITab = func(t, iface *types.Type) { itabname(t, iface) }
NeedRuntimeType = addsignat // TODO(rsc): typenamesym for lock?
- // initialize types package
- // (we need to do this to break dependencies that otherwise
- // would lead to import cycles)
- initializeTypesPackage()
-
- dclcontext = ir.PEXTERN
-
autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
- timings.Start("fe", "loadsys")
- loadsys()
+ types.TypeLinkSym = func(t *types.Type) *obj.LSym {
+ return typenamesym(t).Linksym()
+ }
+ TypecheckInit()
+ // Parse input.
timings.Start("fe", "parse")
lines := parseFiles(flag.Args())
cgoSymABIs()
timings.Stop()
timings.AddEvent(int64(lines), "lines")
-
- finishUniverse()
-
recordPackageName()
- typecheckok = true
-
- // Process top-level declarations in phases.
-
- // Phase 1: const, type, and names and types of funcs.
- // This will gather all the information about types
- // and methods but doesn't depend on any of it.
- //
- // We also defer type alias declarations until phase 2
- // to avoid cycles like #18640.
- // TODO(gri) Remove this again once we have a fix for #25838.
-
- // Don't use range--typecheck can add closures to Target.Decls.
- timings.Start("fe", "typecheck", "top1")
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
- if op := n.Op(); op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.(*ir.Decl).Left().Name().Alias()) {
- Target.Decls[i] = typecheck(n, ctxStmt)
- }
- }
+ // Typecheck.
+ TypecheckPackage()
- // Phase 2: Variable assignments.
- // To check interface assignments, depends on phase 1.
-
- // Don't use range--typecheck can add closures to Target.Decls.
- timings.Start("fe", "typecheck", "top2")
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
- if op := n.Op(); op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).Left().Name().Alias() {
- Target.Decls[i] = typecheck(n, ctxStmt)
- }
- }
-
- // Phase 3: Type check function bodies.
- // Don't use range--typecheck can add closures to Target.Decls.
- timings.Start("fe", "typecheck", "func")
- var fcount int64
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
- if n.Op() == ir.ODCLFUNC {
- Curfn = n.(*ir.Func)
- decldepth = 1
- errorsBefore := base.Errors()
- typecheckslice(Curfn.Body().Slice(), ctxStmt)
- checkreturn(Curfn)
- if base.Errors() > errorsBefore {
- Curfn.PtrBody().Set(nil) // type errors; do not compile
- }
- // Now that we've checked whether n terminates,
- // we can eliminate some obviously dead code.
- deadcode(Curfn)
- fcount++
- }
- }
-
- // Phase 3.11: Check external declarations.
- // TODO(mdempsky): This should be handled when type checking their
- // corresponding ODCL nodes.
- timings.Start("fe", "typecheck", "externdcls")
- for i, n := range Target.Externs {
- if n.Op() == ir.ONAME {
- Target.Externs[i] = typecheck(Target.Externs[i], ctxExpr)
- }
- }
-
- // Phase 3.14: With all user code type-checked, it's now safe to verify map keys
- // and unused dot imports.
- checkMapKeys()
+ // With all user code typechecked, it's now safe to verify unused dot imports.
checkDotImports()
base.ExitIfErrors()
- timings.AddEvent(fcount, "funcs")
-
+ // Build init task.
if initTask := fninit(); initTask != nil {
exportsym(initTask)
}
- // Phase 4: Decide how to capture closed variables.
- // This needs to run before escape analysis,
- // because variables captured by value do not escape.
- timings.Start("fe", "capturevars")
- for _, n := range Target.Decls {
- if n.Op() == ir.ODCLFUNC && n.Func().OClosure != nil {
- Curfn = n.(*ir.Func)
- capturevars(Curfn)
- }
- }
- capturevarscomplete = true
- Curfn = nil
- base.ExitIfErrors()
-
- // Phase 5: Inlining
+ // Inlining
timings.Start("fe", "inlining")
- if base.Debug.TypecheckInl != 0 {
- // Typecheck imported function bodies if Debug.l > 1,
- // otherwise lazily when used or re-exported.
- for _, n := range importlist {
- if n.Inl != nil {
- typecheckinl(n)
- }
- }
- base.ExitIfErrors()
- }
-
if base.Flag.LowerL != 0 {
- // Find functions that can be inlined and clone them before walk expands them.
- visitBottomUp(Target.Decls, func(list []*ir.Func, recursive bool) {
- numfns := numNonClosures(list)
- for _, n := range list {
- if !recursive || numfns > 1 {
- // We allow inlining if there is no
- // recursion, or the recursion cycle is
- // across more than one function.
- caninl(n)
- } else {
- if base.Flag.LowerM > 1 {
- fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(n), n.Nname)
- }
- }
- inlcalls(n)
- }
- })
+ InlinePackage()
}
+ // Devirtualize.
for _, n := range Target.Decls {
if n.Op() == ir.ODCLFUNC {
devirtualize(n.(*ir.Func))
@@ -369,7 +248,7 @@ func Main(archInit func(*Arch)) {
}
Curfn = nil
- // Phase 6: Escape analysis.
+ // Escape analysis.
// Required for moving heap allocations onto stack,
// which in turn is required by the closure implementation,
// which stores the addresses of stack variables into the closure.
@@ -388,7 +267,7 @@ func Main(archInit func(*Arch)) {
EnableNoWriteBarrierRecCheck()
}
- // Phase 7: Transform closure bodies to properly reference captured variables.
+ // Transform closure bodies to properly reference captured variables.
// This needs to happen before walk, because closures must be transformed
// before walk reaches a call of a closure.
timings.Start("fe", "xclosures")
@@ -410,10 +289,10 @@ func Main(archInit func(*Arch)) {
Curfn = nil
peekitabs()
- // Phase 8: Compile top level functions.
+ // Compile top level functions.
// Don't use range--walk can add functions to Target.Decls.
timings.Start("be", "compilefuncs")
- fcount = 0
+ fcount := int64(0)
for i := 0; i < len(Target.Decls); i++ {
n := Target.Decls[i]
if n.Op() == ir.ODCLFUNC {
@@ -448,21 +327,9 @@ func Main(archInit func(*Arch)) {
dumpasmhdr()
}
- // Check whether any of the functions we have compiled have gigantic stack frames.
- sort.Slice(largeStackFrames, func(i, j int) bool {
- return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
- })
- for _, large := range largeStackFrames {
- if large.callee != 0 {
- base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
- } else {
- base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
- }
- }
+ CheckLargeStacks()
+ CheckFuncStack()
- if len(funcStack) != 0 {
- base.Fatalf("funcStack is non-empty: %v", len(funcStack))
- }
if len(compilequeue) != 0 {
base.Fatalf("%d uncompiled functions", len(compilequeue))
}
@@ -480,6 +347,20 @@ func Main(archInit func(*Arch)) {
}
}
+func CheckLargeStacks() {
+ // Check whether any of the functions we have compiled have gigantic stack frames.
+ sort.Slice(largeStackFrames, func(i, j int) bool {
+ return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
+ })
+ for _, large := range largeStackFrames {
+ if large.callee != 0 {
+ base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
+ } else {
+ base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
+ }
+ }
+}
+
func cgoSymABIs() {
// The linker expects an ABI0 wrapper for all cgo-exported
// functions.
@@ -1140,16 +1021,6 @@ func parseLang(s string) (lang, error) {
return lang{major: major, minor: minor}, nil
}
-func initializeTypesPackage() {
- types.Widthptr = Widthptr
- types.Dowidth = dowidth
- types.TypeLinkSym = func(t *types.Type) *obj.LSym {
- return typenamesym(t).Linksym()
- }
-
- initUniverse()
-}
-
// useNewABIWrapGen returns TRUE if the compiler should generate an
// ABI wrapper for the function 'f'.
func useABIWrapGen(f *ir.Func) bool {