1
0
mirror of https://github.com/golang/go synced 2024-11-23 18:40:03 -07:00

cmd/compile/internal/gc: steps towards work-queue

[This is a reattempt of go.dev/cl/520611.]

This CL reorganizes the top-level functions for handling package-level
declarations, runtime type descriptors, and SSA compilation to work in
a loop. This generalizes the loop that previously existed in dumpdata.

Change-Id: I7502798a8662b3cec92d3001169f3af4f804df2a
Reviewed-on: https://go-review.googlesource.com/c/go/+/522339
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Matthew Dempsky 2023-08-18 00:32:11 -07:00 committed by Gopher Robot
parent 96b6e78ea9
commit cf68384674
5 changed files with 86 additions and 74 deletions

View File

@ -113,10 +113,6 @@ func prepareFunc(fn *ir.Func) {
// It fans out nBackendWorkers to do the work // It fans out nBackendWorkers to do the work
// and waits for them to complete. // and waits for them to complete.
func compileFunctions() { func compileFunctions() {
if len(compilequeue) == 0 {
return
}
if race.Enabled { if race.Enabled {
// Randomize compilation order to try to shake out races. // Randomize compilation order to try to shake out races.
tmp := make([]*ir.Func, len(compilequeue)) tmp := make([]*ir.Func, len(compilequeue))

View File

@ -19,6 +19,7 @@ import (
"cmd/compile/internal/noder" "cmd/compile/internal/noder"
"cmd/compile/internal/pgo" "cmd/compile/internal/pgo"
"cmd/compile/internal/pkginit" "cmd/compile/internal/pkginit"
"cmd/compile/internal/reflectdata"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/ssagen" "cmd/compile/internal/ssagen"
"cmd/compile/internal/staticinit" "cmd/compile/internal/staticinit"
@ -295,18 +296,62 @@ func Main(archInit func(*ssagen.ArchInfo)) {
ir.CurFunc = nil ir.CurFunc = nil
// Compile top level functions. reflectdata.WriteBasicTypes()
// Don't use range--walk can add functions to Target.Decls.
base.Timer.Start("be", "compilefuncs")
fcount := int64(0)
for i := 0; i < len(typecheck.Target.Funcs); i++ {
fn := typecheck.Target.Funcs[i]
enqueueFunc(fn)
fcount++
}
base.Timer.AddEvent(fcount, "funcs")
// Compile top-level declarations.
//
// There are cyclic dependencies between all of these phases, so we
// need to iterate all of them until we reach a fixed point.
base.Timer.Start("be", "compilefuncs")
for nextFunc, nextExtern := 0, 0; ; {
reflectdata.WriteRuntimeTypes()
if nextExtern < len(typecheck.Target.Externs) {
switch n := typecheck.Target.Externs[nextExtern]; n.Op() {
case ir.ONAME:
dumpGlobal(n)
case ir.OLITERAL:
dumpGlobalConst(n)
case ir.OTYPE:
reflectdata.NeedRuntimeType(n.Type())
}
nextExtern++
continue
}
if nextFunc < len(typecheck.Target.Funcs) {
enqueueFunc(typecheck.Target.Funcs[nextFunc])
nextFunc++
continue
}
// The SSA backend supports using multiple goroutines, so keep it
// as late as possible to maximize how much work we can batch and
// process concurrently.
if len(compilequeue) != 0 {
compileFunctions() compileFunctions()
continue
}
// Finalize DWARF inline routine DIEs, then explicitly turn off
// further DWARF inlining generation to avoid problems with
// generated method wrappers.
//
// Note: The DWARF fixup code for inlined calls currently doesn't
// allow multiple invocations, so we intentionally run it just
// once after everything else. Worst case, some generated
// functions have slightly larger DWARF DIEs.
if base.Ctxt.DwFixups != nil {
base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0)
base.Ctxt.DwFixups = nil
base.Flag.GenDwarfInl = 0
continue // may have called reflectdata.TypeLinksym (#62156)
}
break
}
base.Timer.AddEvent(int64(len(typecheck.Target.Funcs)), "funcs")
if base.Flag.CompilingRuntime { if base.Flag.CompilingRuntime {
// Write barriers are now known. Check the call graph. // Write barriers are now known. Check the call graph.
@ -318,15 +363,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
staticinit.AddKeepRelocations() staticinit.AddKeepRelocations()
} }
// Finalize DWARF inline routine DIEs, then explicitly turn off
// DWARF inlining gen so as to avoid problems with generated
// method wrappers.
if base.Ctxt.DwFixups != nil {
base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0)
base.Ctxt.DwFixups = nil
base.Flag.GenDwarfInl = 0
}
// Write object data to disk. // Write object data to disk.
base.Timer.Start("be", "dumpobj") base.Timer.Start("be", "dumpobj")
dumpdata() dumpdata()

View File

@ -110,39 +110,11 @@ func dumpCompilerObj(bout *bio.Writer) {
} }
func dumpdata() { func dumpdata() {
numExterns := len(typecheck.Target.Externs) reflectdata.WriteGCSymbols()
numDecls := len(typecheck.Target.Funcs)
dumpglobls(typecheck.Target.Externs)
addsignats(typecheck.Target.Externs)
reflectdata.WriteRuntimeTypes()
reflectdata.WritePluginTable() reflectdata.WritePluginTable()
reflectdata.WriteImportStrings() reflectdata.WriteImportStrings()
reflectdata.WriteBasicTypes()
dumpembeds() dumpembeds()
// Calls to WriteRuntimeTypes can generate functions,
// like method wrappers and hash and equality routines.
// Compile any generated functions, process any new resulting types, repeat.
// This can't loop forever, because there is no way to generate an infinite
// number of types in a finite amount of code.
// In the typical case, we loop 0 or 1 times.
// It was not until issue 24761 that we found any code that required a loop at all.
for {
for i := numDecls; i < len(typecheck.Target.Funcs); i++ {
fn := typecheck.Target.Funcs[i]
enqueueFunc(fn)
}
numDecls = len(typecheck.Target.Funcs)
compileFunctions()
reflectdata.WriteRuntimeTypes()
if numDecls == len(typecheck.Target.Funcs) {
break
}
}
// Dump extra globals.
dumpglobls(typecheck.Target.Externs[numExterns:])
if reflectdata.ZeroSize > 0 { if reflectdata.ZeroSize > 0 {
zero := base.PkgLinksym("go:map", "zero", obj.ABI0) zero := base.PkgLinksym("go:map", "zero", obj.ABI0)
objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA) objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
@ -217,18 +189,6 @@ func dumpGlobalConst(n *ir.Name) {
base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v)) base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
} }
func dumpglobls(externs []*ir.Name) {
// add globals
for _, n := range externs {
switch n.Op() {
case ir.ONAME:
dumpGlobal(n)
case ir.OLITERAL:
dumpGlobalConst(n)
}
}
}
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data. // addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
// //
// This is done during the sequential phase after compilation, since // This is done during the sequential phase after compilation, since
@ -323,12 +283,3 @@ func dumpembeds() {
staticdata.WriteEmbed(v) staticdata.WriteEmbed(v)
} }
} }
func addsignats(dcls []*ir.Name) {
// copy types from dcl list to signatset
for _, n := range dcls {
if n.Op() == ir.OTYPE {
reflectdata.NeedRuntimeType(n.Type())
}
}
}

View File

@ -1266,7 +1266,9 @@ func WriteRuntimeTypes() {
} }
signatslice = signatslice[len(signats):] signatslice = signatslice[len(signats):]
} }
}
func WriteGCSymbols() {
// Emit GC data symbols. // Emit GC data symbols.
gcsyms := make([]typeAndStr, 0, len(gcsymset)) gcsyms := make([]typeAndStr, 0, len(gcsymset))
for t := range gcsymset { for t := range gcsymset {

View File

@ -0,0 +1,27 @@
# Regression test for https://go.dev/issue/62156:
# DWARF generation for inlined functions may require more runtime type
# descriptors to be written.
go build
-- go.mod --
module m
go 1.20
-- main.go --
package main
import "m/sub"
func main() { sub.F() }
-- sub/sub.go --
package sub
type iface interface{ m() }
func F() {
f := func(rt []iface) []iface {
return append([]iface{}, rt...)
}
f(nil)
}