diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 4b7a141666..85d68ae0ba 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -29,6 +29,7 @@ package inline import ( "fmt" "go/constant" + "internal/goexperiment" "sort" "strconv" @@ -292,11 +293,15 @@ func CanInline(fn *ir.Func, profile *pgo.Profile) { base.Fatalf("CanInline no nname %+v", fn) } + canInline := func(fn *ir.Func) { CanInline(fn, profile) } + + var funcProps *inlheur.FuncProps + if goexperiment.NewInliner { + funcProps = inlheur.AnalyzeFunc(fn, canInline) + } + if base.Debug.DumpInlFuncProps != "" { - inlheur.DumpFuncProps(fn, base.Debug.DumpInlFuncProps, - func(fn *ir.Func) { - CanInline(fn, profile) - }) + inlheur.DumpFuncProps(fn, base.Debug.DumpInlFuncProps, canInline) } var reason string // reason, if any, that the function was not inlined @@ -363,6 +368,9 @@ func CanInline(fn *ir.Func, profile *pgo.Profile) { CanDelayResults: canDelayResults(fn), } + if goexperiment.NewInliner { + n.Func.Inl.Properties = funcProps.SerializeToString() + } if base.Flag.LowerM > 1 { fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, budget-visitor.budget, fn.Type(), ir.Nodes(fn.Body)) diff --git a/src/cmd/compile/internal/inline/inlheur/analyze.go b/src/cmd/compile/internal/inline/inlheur/analyze.go index 8d44b37b6a..a52b7ba04b 100644 --- a/src/cmd/compile/internal/inline/inlheur/analyze.go +++ b/src/cmd/compile/internal/inline/inlheur/analyze.go @@ -9,6 +9,7 @@ import ( "cmd/compile/internal/ir" "encoding/json" "fmt" + "internal/goexperiment" "io" "os" "path/filepath" @@ -48,6 +49,24 @@ type fnInlHeur struct { props *FuncProps } +var fpmap = map[*ir.Func]fnInlHeur{} + +func AnalyzeFunc(fn *ir.Func, canInline func(*ir.Func)) *FuncProps { + if fih, ok := fpmap[fn]; ok { + return fih.props + } + fp := computeFuncProps(fn, canInline) + file, line := fnFileLine(fn) + entry := fnInlHeur{ + fname: fn.Sym().Name, + file: file, + line: line, + props: fp, + } + fpmap[fn] = entry + return fp +} + // computeFuncProps examines the Go function 'fn' and computes for it // a function "properties" object, to be used to drive inlining // heuristics. See comments on the FuncProps type for more info. @@ -148,6 +167,16 @@ func captureFuncDumpEntry(fn *ir.Func, canInline func(*ir.Func)) { if strings.HasPrefix(fn.Sym().Name, ".eq.") { return } + fih, ok := fpmap[fn] + if goexperiment.NewInliner { + // Props object should already be present. + if !ok { + panic("unexpected missing props") + } + } else { + AnalyzeFunc(fn, canInline) + fih = fpmap[fn] + } if dumpBuffer == nil { dumpBuffer = make(map[*ir.Func]fnInlHeur) } @@ -156,15 +185,7 @@ func captureFuncDumpEntry(fn *ir.Func, canInline func(*ir.Func)) { // so don't add them more than once. return } - fp := computeFuncProps(fn, canInline) - file, line := fnFileLine(fn) - entry := fnInlHeur{ - fname: fn.Sym().Name, - file: file, - line: line, - props: fp, - } - dumpBuffer[fn] = entry + dumpBuffer[fn] = fih } // dumpFilePreamble writes out a file-level preamble for a given diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index 0e44ea7c52..952f6fb929 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -200,6 +200,10 @@ type Inline struct { Dcl []*Name HaveDcl bool // whether we've loaded Dcl + // Function properties, encoded as a string (these are used for + // making inlining decisions). See cmd/compile/internal/inline/inlheur. + Properties string + // CanDelayResults reports whether it's safe for the inliner to delay // initializing the result parameters until immediately before the // "return" statement. diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go index 00a7743085..3bc5c32e1b 100644 --- a/src/cmd/compile/internal/noder/linker.go +++ b/src/cmd/compile/internal/noder/linker.go @@ -6,6 +6,7 @@ package noder import ( "internal/buildcfg" + "internal/goexperiment" "internal/pkgbits" "io" @@ -296,6 +297,9 @@ func (l *linker) relocFuncExt(w *pkgbits.Encoder, name *ir.Name) { if inl := name.Func.Inl; w.Bool(inl != nil) { w.Len(int(inl.Cost)) w.Bool(inl.CanDelayResults) + if goexperiment.NewInliner { + w.String(inl.Properties) + } } w.Sync(pkgbits.SyncEOF) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index bf7bfb7d48..35dfe3d674 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -8,6 +8,7 @@ import ( "fmt" "go/constant" "internal/buildcfg" + "internal/goexperiment" "internal/pkgbits" "path/filepath" "strings" @@ -1118,6 +1119,9 @@ func (r *reader) funcExt(name *ir.Name, method *types.Sym) { Cost: int32(r.Len()), CanDelayResults: r.Bool(), } + if goexperiment.NewInliner { + fn.Inl.Properties = r.String() + } } } else { r.addBody(name.Func, method)