Skip to content

Commit

Permalink
cmd/compile: separate inline cost analysis from applying inlining
Browse files Browse the repository at this point in the history
This CL separates the pass that computes inlinability from the pass
that performs inlinability. In particular, the latter can now happen
in any flat order, rather than bottom-up order. This also allows
inlining of calls exposed by devirtualization.

Change-Id: I389c0665fdc8288a6e25129a6744bfb1ace1eff7
Reviewed-on: https://go-review.googlesource.com/c/go/+/562319
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
  • Loading branch information
mdempsky authored and gopherbot committed Feb 9, 2024
1 parent a517131 commit b158ca9
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 44 deletions.
41 changes: 16 additions & 25 deletions src/cmd/compile/internal/inline/inl.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,38 +141,29 @@ func CanInlineFuncs(funcs []*ir.Func, profile *pgo.Profile) {
PGOInlinePrologue(profile)
}

ir.VisitFuncsBottomUp(funcs, func(list []*ir.Func, recursive bool) {
CanInlineSCC(list, recursive, profile)
})
}

// CanInlineSCC computes the inlinability of functions within an SCC
// (strongly connected component).
//
// CanInlineSCC is designed to be used by ir.VisitFuncsBottomUp
// callbacks.
func CanInlineSCC(funcs []*ir.Func, recursive bool, profile *pgo.Profile) {
if base.Flag.LowerL == 0 {
return
}

numfns := numNonClosures(funcs)
ir.VisitFuncsBottomUp(funcs, func(funcs []*ir.Func, recursive bool) {
numfns := numNonClosures(funcs)

for _, fn := range funcs {
if !recursive || numfns > 1 {
// We allow inlining if there is no
// recursion, or the recursion cycle is
// across more than one function.
CanInline(fn, profile)
} else {
if base.Flag.LowerM > 1 && fn.OClosure == nil {
fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(fn), fn.Nname)
for _, fn := range funcs {
if !recursive || numfns > 1 {
// We allow inlining if there is no
// recursion, or the recursion cycle is
// across more than one function.
CanInline(fn, profile)
} else {
if base.Flag.LowerM > 1 && fn.OClosure == nil {
fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(fn), fn.Nname)
}
}
if inlheur.Enabled() {
analyzeFuncProps(fn, profile)
}
}
if inlheur.Enabled() {
analyzeFuncProps(fn, profile)
}
}
})
}

// GarbageCollectUnreferencedHiddenClosures makes a pass over all the
Expand Down
25 changes: 7 additions & 18 deletions src/cmd/compile/internal/inline/interleaved/interleaved.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,15 @@ func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgo.Profile) {
if base.Debug.PGOInline != 0 {
inlProfile = profile
}
if inlProfile != nil {
inline.PGOInlinePrologue(inlProfile)
}

ir.VisitFuncsBottomUp(pkg.Funcs, func(funcs []*ir.Func, recursive bool) {
// We visit functions within an SCC in fairly arbitrary order,
// so by computing inlinability for all functions in the SCC
// before performing any inlining, the results are less
// sensitive to the order within the SCC (see #58905 for an
// example).

// First compute inlinability for all functions in the SCC ...
inline.CanInlineSCC(funcs, recursive, inlProfile)
// First compute inlinability of all functions in the package.
inline.CanInlineFuncs(pkg.Funcs, inlProfile)

// ... then make a second pass to do devirtualization and inlining
// of calls.
for _, fn := range funcs {
DevirtualizeAndInlineFunc(fn, inlProfile)
}
})
// Now we make a second pass to do devirtualization and inlining of
// calls. Order here should not matter.
for _, fn := range pkg.Funcs {
DevirtualizeAndInlineFunc(fn, inlProfile)
}

if base.Flag.LowerL != 0 {
// Perform a garbage collection of hidden closures functions that
Expand Down
2 changes: 1 addition & 1 deletion test/fixedbugs/issue52193.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func F(peerShare []byte) ([]byte, error) { // ERROR "leaking param: peerShare"

func f() { // ERROR "can inline f"
var i interface{ m() } = T(0) // ERROR "T\(0\) does not escape"
i.m() // ERROR "devirtualizing i.m"
i.m() // ERROR "devirtualizing i.m" "inlining call to T.m"
}

type T int
Expand Down

0 comments on commit b158ca9

Please sign in to comment.