Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: does not inline method of generic type across packages when there are multiple instantiations #59070

Open
578559967 opened this issue Mar 16, 2023 · 4 comments
Assignees
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@578559967
Copy link

What version of Go are you using (go version)?

$ go version
go version go1.20.2 darwin/arm64

Does this issue reproduce with the latest release?

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/r/Library/Caches/go-build"
GOENV="/Users/r/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/r/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/r/go"
GOPRIVATE=""
GOPROXY="https://goproxy.cn,direct"
GOROOT="/Users/r/sdk/go1.20.2"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/r/sdk/go1.20.2/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.20.2"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/r/workspace/testcode/testinlinegeneric/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/j_/rq9ph2cd3h50w468sgv34lwh0000gn/T/go-build2389814434=/tmp/go-build -gno-record-gcc-switches -fno-common"
GOROOT/bin/go version: go version go1.20.2 darwin/arm64
GOROOT/bin/go tool compile -V: compile version go1.20.2
uname -v: Darwin Kernel Version 22.3.0: Mon Jan 30 20:38:37 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6000
ProductName:		macOS
ProductVersion:		13.2.1
BuildVersion:		22D68
lldb --version: lldb-1400.0.38.17
Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)

What did you do?

go.mod:

module test/inlinegeneric

go 1.20

a/a.go:

package a

type Foo1[T any] struct {
}

func (*Foo1[T]) Run() {
}

type Foo2 struct {
}

func (*Foo2) Run() {
}

b/b.go:

package b

import "test/inlinegeneric/a"

func Bar() {
	var f1 a.Foo1[int]
	f1.Run()
	var f2 a.Foo2
	f2.Run()
}

type Boo struct {
	f1 a.Foo1[int]
	f2 a.Foo2
}

main.go:

package main

import "test/inlinegeneric/b"

func main() {
	var x b.Boo
	_ = x
	b.Bar()
}

go1.20.2 build --gcflags="-m=2" ./main.go

go1.19.7 build --gcflags="-m=2" ./main.go

What did you expect to see?

For go1.20.2:

# command-line-arguments
./main.go:5:6: can inline main with cost 20 as: func() { b.Bar() }
./main.go:8:7: inlining call to b.Bar
./main.go:8:7: inlining call to a.(*Foo1[go.shape.int]).Run
./main.go:8:7: inlining call to a.(*Foo2).Run

For go1.19.7

# command-line-arguments
./main.go:5:6: can inline main with cost 20 as: func() { b.Bar() }
./main.go:8:7: inlining call to b.Bar
./main.go:8:7: inlining call to a.(*Foo1[go.shape.int_0]).Run
./main.go:8:7: inlining call to a.(*Foo2).Run

What did you see instead?

For go1.20.2:

# command-line-arguments
./main.go:5:6: can inline main with cost 27 as: func() { x = <nil>; _ = x; b.Bar() }
./main.go:8:7: inlining call to b.Bar
./main.go:8:7: inlining call to a.(*Foo2).Run
./a/a.go:6:6: can inline a.(*Foo1[go.shape.int]).Run with cost 0 as: method(*a.Foo1[go.shape.int]) func(*[0]uintptr) {  }
./a/a.go:6:6: can inline a.(*Foo1[int]).Run with cost 9 as: method(*a.Foo1[int]) func() { var .autotmp_0 *a.Foo1[int]; .autotmp_0 = <nil>; (*a.Foo1[go.shape.int]).Run(.autotmp_0, &a..dict.Foo1[int]) }
./a/a.go:6:6: inlining call to a.(*Foo1[go.shape.int]).Run

For go1.19.7

# command-line-arguments
./main.go:5:6: can inline main with cost 27 as: func() { var x b.Boo; x = <nil>; _ = x; b.Bar() }
./main.go:8:7: inlining call to b.Bar
./main.go:8:7: inlining call to a.(*Foo2).Run
./a/a.go:6:17: can inline a.(*Foo1[go.shape.int_0]).Run with cost 0 as: func(uintptr, *a.Foo1[go.shape.int_0]) {  }
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Mar 16, 2023
@cherrymui
Copy link
Member

See #57505. Closing as a dup.

@cherrymui cherrymui closed this as not planned Won't fix, can't repro, duplicate, stale Mar 16, 2023
@578559967
Copy link
Author

See #57505. Closing as a dup.

I don't think this issue is same as #57505.
Neither go1.19 nor go1.20 nor go1.20 with non-unified does inline the method of the generic type.
But in #57505, only go1.20 does not inline.

And I found that if we remove the field f1 in b.Boo struct or remove the variable x in main, then go1.20 will do inline the method, but go1.19 or non-unified will not inline.

b/b.go:

package b

func Bar() {
	var f1 Foo1[int]
	f1.Run()
	var f2 Foo2[int]
	f2.Run()
}

type Boo struct {
	f1 Foo1[int]
}

type Foo1[T any] struct {
}

func (*Foo1[T]) Run() {
}

type Foo2[T any] struct {
}

func (*Foo2[T]) Run() {
}

main.go:

package main

import "test/inlinegeneric/b"

func main() {
	var x b.Boo
	_ = x
	b.Bar()
}

go1.19.7 & go1.20 non-unified: None of the methods Run of Foo1[T] or Foo2[T] is inlined.

$ go1.19.7 build --gcflags="-m=2" ./main.go
# command-line-arguments
./main.go:5:6: can inline main with cost 29 as: func() { var x b.Boo; x = <nil>; _ = x; b.Bar() }
./main.go:8:7: inlining call to b.Bar
./b/b.go:17:17: can inline b.(*Foo1[go.shape.int_0]).Run with cost 0 as: func(uintptr, *b.Foo1[go.shape.int_0]) {  }

$ GOEXPERIMENT=nounified go1.20.2 build --gcflags="-m=2" ./main.go                                         [0](0s)[14:35:03]
# command-line-arguments
./main.go:5:6: can inline main with cost 29 as: func() { var x b.Boo; x = <nil>; _ = x; b.Bar() }
./main.go:8:7: inlining call to b.Bar
./b/b.go:17:17: can inline b.(*Foo1[go.shape.int_0]).Run with cost 0 as: func(uintptr, *b.Foo1[go.shape.int_0]) {  }

go1.20: Only Foo1[T].Run is not inlined, Foo2[T].Run is inlined. And the difference between Foo1[T] and Foo2[T] is that Boo has a field of type Foo1[T] and Boo is used in main package.

$ go1.20.2 build --gcflags="-m=2" ./main.go                                                             [146](38s)[14:35:00]
# command-line-arguments
./main.go:5:6: can inline main with cost 29 as: func() { x = <nil>; _ = x; b.Bar() }
./main.go:8:7: inlining call to b.Bar
./main.go:8:7: inlining call to b.(*Foo2[go.shape.int]).Run
./b/b.go:17:6: can inline b.(*Foo1[go.shape.int]).Run with cost 0 as: method(*b.Foo1[go.shape.int]) func(*[0]uintptr) {  }
./b/b.go:17:6: can inline b.(*Foo1[int]).Run with cost 9 as: method(*b.Foo1[int]) func() { var .autotmp_0 *b.Foo1[int]; .autotmp_0 = <nil>; (*b.Foo1[go.shape.int]).Run(.autotmp_0, &b..dict.Foo1[int]) }
./b/b.go:17:6: inlining call to b.(*Foo1[go.shape.int]).Run

@cherrymui cherrymui changed the title cmd/compile: Not inline method of generic type across packages. cmd/compile: does not inline method of generic type across packages Mar 17, 2023
@cherrymui
Copy link
Member

Could you clarify which function(s) you expect to inline, but not? Is it a.(*Foo1[go.shape.int]).Run not inlined into main? Just pasting the diagnostics without explanation is not clear. Thanks.

And I found that if we remove the field f1 in b.Boo struct or remove the variable x in main, then go1.20 will do inline the method

So, it sounds like the two instantiations of a.Foo1[int], one in b.Boo and one in b.Bar (inlined into main) causes the compiler to confuse?

Also, it doesn't seem to require two levels of imports. Even if I put Foo1 and Foo2's definitions into package b, it seems (*Foo1[go.shape.int]).Run still not inlined into main.

cc @mdempsky @thanm @golang/compiler

@cherrymui cherrymui reopened this Mar 17, 2023
@cherrymui cherrymui added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Mar 17, 2023
@cherrymui cherrymui added this to the Backlog milestone Mar 17, 2023
@cherrymui cherrymui changed the title cmd/compile: does not inline method of generic type across packages cmd/compile: does not inline method of generic type across packages when there are multiple instantiations Mar 17, 2023
@578559967
Copy link
Author

Could you clarify which function(s) you expect to inline, but not? Is it a.(*Foo1[go.shape.int]).Run not inlined into main? Just pasting the diagnostics without explanation is not clear. Thanks.

Yes, a.(*Foo1[go.shape.int]).Run is expected to be inlined into main but actually not.

And I found that if we remove the field f1 in b.Boo struct or remove the variable x in main, then go1.20 will do inline the method

So, it sounds like the two instantiations of a.Foo1[int], one in b.Boo and one in b.Bar (inlined into main) causes the compiler to confuse?

Yes.

Also, it doesn't seem to require two levels of imports. Even if I put Foo1 and Foo2's definitions into package b, it seems (*Foo1[go.shape.int]).Run still not inlined into main.

cc @mdempsky @thanm @golang/compiler

Yes, no need package a.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
Development

No branches or pull requests

4 participants