cmd/compile: Increasing complexity when inlining
Go version
go version go1.23.1 linux/amd64
Output of go env in your module/workspace:
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/xxx/.cache/go-build'
GOENV='/home/xxx/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/xxx/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/xxx/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.23.1'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/xxx/.config/go/telemetry'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/xxx/go.mod'
GOWORK='/xxx/go.work'
CGO_CFLAGS='-I/snap/ego-dev/current/opt/ego/include'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-L/snap/ego-dev/current/opt/ego/lib -L/usr/lib/openssl-1.1'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2403704166=/tmp/go-build -gno-record-gcc-switches'
What did you do?
With the code below the following inlining decisions are made/shown:
can inline (*BasicWallet).Address with cost 3 as: method(*BasicWallet) func() common.Address { return w.Addr }
can inline (*BasicWallet).Address2 with cost 6 as: method(*BasicWallet) func() common.Address { return (*BasicWallet).Address(w) }
can inline (*BasicWallet).Address3 with cost 9 as: method(*BasicWallet) func() common.Address { return (*BasicWallet).Address2(w) }
Although this works, it reduces the chance of something getting inlined, as it increases the complexity of the function something is inlined into, even though the resulting bytecode will/should be identical for all 3 methods (otherwise there would be no inlining).
What did you see happen?
(see above)
What did you expect to see?
Correct me if I'm wrong, but shouldn't these be something like the following, as that's actually what inlining does:
can inline (*BasicWallet).Address with cost 3 as: method(*BasicWallet) func() common.Address { return w.Addr }
can inline (*BasicWallet).Address2 with cost 3 as: method(*BasicWallet) func() common.Address { return w.Addr }
can inline (*BasicWallet).Address3 with cost 3 as: method(*BasicWallet) func() common.Address { return w.Addr }
Since inlining effectively reduces the effort/size of a function, these should probably not increase in complexity.
Related Issues and Documentation
- inlining reduces performance compared to manual inlining #35687 (closed)
- cmd/compile: functions with type parameters cannot inline multiple levels deep across packages #56280 (closed)
- cmd/compile: does not inline method of generic type across packages when there are multiple instantiations #59070
- cmd/compile: combining two inlined functions with interfaces produces non-inlineable code #61036 (closed)
- cmd/compile: don't emit inltree for closure within body of inlined func
- net/netip: failed TestInlining #67354 (closed)
- cmd/compile: compiler/inliner leads to suboptimal register usage #49634
- cmd/compile: set stricter inlining threshold in large functions
- cmd/compile: elide unnecessary copies #54613
- cmd/compile: output cost while inlining function with `Debug['m'] > 1` #36780 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Also same thing happens with field embeding, i once noticed that binary.NativeEndian has bigger inlining cost than binary.LittleEndian/binary.BigEndian, even though it looks like this:
https://github.com/golang/go/blob/ef3e1dae2f151ddca4ba50ed8b9a98381d7e9158/src/encoding/binary/native_endian_little.go#L9-L14
This is a consequence of deciding inlining complexity early in compilation, before we know how many instructions a function will actually take. The wrapper around the inline looks like it would require some cost, even though code generation can eliminate all of that cost.
Improvements in this area probably fall under the general umbrella of #61502.
@randall77 Is there anything specific we should keep this issue for, or shall we just close in favor of the more general #61502?