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)
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))
}
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.
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")
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 {
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))
}
}
}
+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.
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 {
NeedRuntimeType = func(*types.Type) {}
)
+func TypecheckInit() {
+ types.Widthptr = Widthptr
+ types.Dowidth = dowidth
+ initUniverse()
+ dclcontext = ir.PEXTERN
+ timings.Start("fe", "loadsys")
+ loadsys()
+}
+
+func TypecheckPackage() {
+ finishUniverse()
+
+ 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)
+ }
+ }
+
+ // 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 {
+ TypecheckFuncBody(n.(*ir.Func))
+ fcount++
+ }
+ }
+
+ // Phase 4: 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 5: With all user code type-checked, it's now safe to verify map keys.
+ checkMapKeys()
+
+ // Phase 6: 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
+
+ if base.Debug.TypecheckInl != 0 {
+ // Typecheck imported function bodies if Debug.l > 1,
+ // otherwise lazily when used or re-exported.
+ TypecheckImports()
+ }
+}
+
func TypecheckAssignExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr|ctxAssign) }
func TypecheckExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr) }
func TypecheckStmt(n ir.Node) ir.Node { return typecheck(n, ctxStmt) }
return typecheck(n, ctxExpr|ctxCallee)
}
+func TypecheckFuncBody(n *ir.Func) {
+ Curfn = n
+ decldepth = 1
+ errorsBefore := base.Errors()
+ typecheckslice(n.Body(), ctxStmt)
+ checkreturn(n)
+ if base.Errors() > errorsBefore {
+ n.PtrBody().Set(nil) // type errors; do not compile
+ }
+ // Now that we've checked whether n terminates,
+ // we can eliminate some obviously dead code.
+ deadcode(n)
+}
+
+var importlist []*ir.Func
+
+func TypecheckImports() {
+ for _, n := range importlist {
+ if n.Inl != nil {
+ typecheckinl(n)
+ }
+ }
+}
+
// To enable tracing support (-t flag), set enableTrace to true.
const enableTrace = false