mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: always use the compile queue
The compiler currently has two modes for compilation: one where it compiles each function as it sees them, and another where it enqueues them all into a work queue. A subsequent CL is going to reorder function compilation to ensure that functions are always compiled before any non-trivial function literals they enclose, and this will be easier if we always use the compile work queue. Also, fewer compilation modes makes things simpler to reason about. Change-Id: Ie090e81f7476c49486296f2b90911fa0a466a5dd Reviewed-on: https://go-review.googlesource.com/c/go/+/283313 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
cd5b74d2df
commit
cc90e7a51e
6 changed files with 28 additions and 73 deletions
|
|
@ -32,7 +32,6 @@ type DebugFlags struct {
|
||||||
Append int `help:"print information about append compilation"`
|
Append int `help:"print information about append compilation"`
|
||||||
Checkptr int `help:"instrument unsafe pointer conversions"`
|
Checkptr int `help:"instrument unsafe pointer conversions"`
|
||||||
Closure int `help:"print information about closure compilation"`
|
Closure int `help:"print information about closure compilation"`
|
||||||
CompileLater int `help:"compile functions as late as possible"`
|
|
||||||
DclStack int `help:"run internal dclstack check"`
|
DclStack int `help:"run internal dclstack check"`
|
||||||
Defer int `help:"print information about defer compilation"`
|
Defer int `help:"print information about defer compilation"`
|
||||||
DisableNil int `help:"disable nil checks"`
|
DisableNil int `help:"disable nil checks"`
|
||||||
|
|
|
||||||
|
|
@ -26,21 +26,17 @@ var (
|
||||||
compilequeue []*ir.Func // functions waiting to be compiled
|
compilequeue []*ir.Func // functions waiting to be compiled
|
||||||
)
|
)
|
||||||
|
|
||||||
func funccompile(fn *ir.Func) {
|
func enqueueFunc(fn *ir.Func) {
|
||||||
if ir.CurFunc != nil {
|
if ir.CurFunc != nil {
|
||||||
base.Fatalf("funccompile %v inside %v", fn.Sym(), ir.CurFunc.Sym())
|
base.FatalfAt(fn.Pos(), "enqueueFunc %v inside %v", fn, ir.CurFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fn.Type() == nil {
|
if ir.FuncName(fn) == "_" {
|
||||||
if base.Errors() == 0 {
|
// Skip compiling blank functions.
|
||||||
base.Fatalf("funccompile missing type")
|
// Frontend already reported any spec-mandated errors (#29870).
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign parameter offsets
|
|
||||||
types.CalcSize(fn.Type())
|
|
||||||
|
|
||||||
if len(fn.Body) == 0 {
|
if len(fn.Body) == 0 {
|
||||||
// Initialize ABI wrappers if necessary.
|
// Initialize ABI wrappers if necessary.
|
||||||
ssagen.InitLSym(fn, false)
|
ssagen.InitLSym(fn, false)
|
||||||
|
|
@ -48,35 +44,31 @@ func funccompile(fn *ir.Func) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
typecheck.DeclContext = ir.PAUTO
|
errorsBefore := base.Errors()
|
||||||
ir.CurFunc = fn
|
prepareFunc(fn)
|
||||||
compile(fn)
|
if base.Errors() > errorsBefore {
|
||||||
ir.CurFunc = nil
|
return
|
||||||
typecheck.DeclContext = ir.PEXTERN
|
}
|
||||||
|
|
||||||
|
compilequeue = append(compilequeue, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compile(fn *ir.Func) {
|
// prepareFunc handles any remaining frontend compilation tasks that
|
||||||
|
// aren't yet safe to perform concurrently.
|
||||||
|
func prepareFunc(fn *ir.Func) {
|
||||||
// Set up the function's LSym early to avoid data races with the assemblers.
|
// Set up the function's LSym early to avoid data races with the assemblers.
|
||||||
// Do this before walk, as walk needs the LSym to set attributes/relocations
|
// Do this before walk, as walk needs the LSym to set attributes/relocations
|
||||||
// (e.g. in markTypeUsedInInterface).
|
// (e.g. in markTypeUsedInInterface).
|
||||||
ssagen.InitLSym(fn, true)
|
ssagen.InitLSym(fn, true)
|
||||||
|
|
||||||
errorsBefore := base.Errors()
|
// Calculate parameter offsets.
|
||||||
|
types.CalcSize(fn.Type())
|
||||||
|
|
||||||
|
typecheck.DeclContext = ir.PAUTO
|
||||||
|
ir.CurFunc = fn
|
||||||
walk.Walk(fn)
|
walk.Walk(fn)
|
||||||
if base.Errors() > errorsBefore {
|
ir.CurFunc = nil // enforce no further uses of CurFunc
|
||||||
return
|
typecheck.DeclContext = ir.PEXTERN
|
||||||
}
|
|
||||||
|
|
||||||
// From this point, there should be no uses of Curfn. Enforce that.
|
|
||||||
ir.CurFunc = nil
|
|
||||||
|
|
||||||
if ir.FuncName(fn) == "_" {
|
|
||||||
// We don't need to generate code for this function, just report errors in its body.
|
|
||||||
// At this point we've generated any errors needed.
|
|
||||||
// (Beyond here we generate only non-spec errors, like "stack frame too large".)
|
|
||||||
// See issue 29870.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure type syms are declared for all types that might
|
// Make sure type syms are declared for all types that might
|
||||||
// be types of stack objects. We need to do this here
|
// be types of stack objects. We need to do this here
|
||||||
|
|
@ -95,28 +87,6 @@ func compile(fn *ir.Func) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if compilenow(fn) {
|
|
||||||
ssagen.Compile(fn, 0)
|
|
||||||
} else {
|
|
||||||
compilequeue = append(compilequeue, fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// compilenow reports whether to compile immediately.
|
|
||||||
// If functions are not compiled immediately,
|
|
||||||
// they are enqueued in compilequeue,
|
|
||||||
// which is drained by compileFunctions.
|
|
||||||
func compilenow(fn *ir.Func) bool {
|
|
||||||
// Issue 38068: if this function is a method AND an inline
|
|
||||||
// candidate AND was not inlined (yet), put it onto the compile
|
|
||||||
// queue instead of compiling it immediately. This is in case we
|
|
||||||
// wind up inlining it into a method wrapper that is generated by
|
|
||||||
// compiling a function later on in the Target.Decls list.
|
|
||||||
if ir.IsMethod(fn) && isInlinableButNotInlined(fn) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return base.Flag.LowerC == 1 && base.Debug.CompileLater == 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// compileFunctions compiles all functions in compilequeue.
|
// compileFunctions compiles all functions in compilequeue.
|
||||||
|
|
@ -163,16 +133,3 @@ func compileFunctions() {
|
||||||
types.CalcSizeDisabled = false
|
types.CalcSizeDisabled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isInlinableButNotInlined returns true if 'fn' was marked as an
|
|
||||||
// inline candidate but then never inlined (presumably because we
|
|
||||||
// found no call sites).
|
|
||||||
func isInlinableButNotInlined(fn *ir.Func) bool {
|
|
||||||
if fn.Inl == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if fn.Sym() == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return !fn.Linksym().WasInlined()
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -300,9 +300,8 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
||||||
base.Timer.Start("be", "compilefuncs")
|
base.Timer.Start("be", "compilefuncs")
|
||||||
fcount := int64(0)
|
fcount := int64(0)
|
||||||
for i := 0; i < len(typecheck.Target.Decls); i++ {
|
for i := 0; i < len(typecheck.Target.Decls); i++ {
|
||||||
n := typecheck.Target.Decls[i]
|
if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
|
||||||
if n.Op() == ir.ODCLFUNC {
|
enqueueFunc(fn)
|
||||||
funccompile(n.(*ir.Func))
|
|
||||||
fcount++
|
fcount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,9 +131,8 @@ func dumpdata() {
|
||||||
// It was not until issue 24761 that we found any code that required a loop at all.
|
// It was not until issue 24761 that we found any code that required a loop at all.
|
||||||
for {
|
for {
|
||||||
for i := numDecls; i < len(typecheck.Target.Decls); i++ {
|
for i := numDecls; i < len(typecheck.Target.Decls); i++ {
|
||||||
n := typecheck.Target.Decls[i]
|
if n, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
|
||||||
if n.Op() == ir.ODCLFUNC {
|
enqueueFunc(n)
|
||||||
funccompile(n.(*ir.Func))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
numDecls = len(typecheck.Target.Decls)
|
numDecls = len(typecheck.Target.Decls)
|
||||||
|
|
|
||||||
|
|
@ -1223,6 +1223,7 @@ func WriteFuncMap(fn *ir.Func) {
|
||||||
if ir.FuncName(fn) == "_" || fn.Sym().Linkname != "" {
|
if ir.FuncName(fn) == "_" || fn.Sym().Linkname != "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
types.CalcSize(fn.Type())
|
||||||
lsym := base.Ctxt.Lookup(fn.LSym.Name + ".args_stackmap")
|
lsym := base.Ctxt.Lookup(fn.LSym.Name + ".args_stackmap")
|
||||||
nptr := int(fn.Type().ArgWidth() / int64(types.PtrSize))
|
nptr := int(fn.Type().ArgWidth() / int64(types.PtrSize))
|
||||||
bv := bitvec.New(int32(nptr) * 2)
|
bv := bitvec.New(int32(nptr) * 2)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// errorcheck -0 -live -l -d=compilelater
|
// errorcheck -0 -live -l
|
||||||
|
|
||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue