Go version
go1.21.3 darwin/arm64
What operating system and processor architecture are you using (go env)?
GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/homebrew/Cellar/go/1.21.3/libexec'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/opt/homebrew/Cellar/go/1.21.3/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.21.3'
GCCGO='gccgo'
AR='ar'
CC='cc'
CXX='c++'
CGO_ENABLED='1'
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 -ffile-prefix-map=/var/folders/03/7b5nrjcj4b31k3mvrqswnxxm0000gn/T/go-build1450472713=/tmp/go-build -gno-record-gcc-switches -fno-common'
What did you do?
The following simple application:
package main
import "fmt"
type Value interface {
GetValue() int
}
type Array[T Value] struct {
x T
}
func (a *Array[T]) method() {
fmt.Printf("%v\n", a.x.GetValue())
}
type myVal struct{}
func (_ myVal) GetValue() int {
return 5
}
func main() {
a := Array[myVal]{}
a.method()
}
most importantly it does indirect call of myVal.GetValue() (not speaking about missing inline possibility):
a) why it is calling main.(*Array[go.shape.struct {}]).method(SB) instead concrete type main.(*Array[main.myVal]).method?
main.main STEXT size=64 args=0x0 locals=0x18 funcid=0x0 align=0x0
...
0x001c 00028 (/tmp/xxxx/main.go:25) MOVD $main..dict.Array[main.myVal](SB), R1
0x0024 00036 (/tmp/xxxx/main.go:25) PCDATA $1, $0
0x0024 00036 (/tmp/xxxx/main.go:25) CALL main.(*Array[go.shape.struct {}]).method(SB)
b) main.(*Array[go.shape.struct {}]).method doesn't exploit knowledge of concrete type (myVal) and performs indirect call to GetValue():
main.(*Array[go.shape.struct {}]).method STEXT dupok size=160 args=0x10 locals=0x58 funcid=0x0 align=0x0
...
0x0024 00036 (/tmp/xxxx/main.go:14) CALL (R0)
c) what is even more stranger, compiler generates unused concrete type main.(*Array[main.myVal]).method but it doesn't exploit type knowledge as well and instead calls main.(*Array[go.shape.struct {}]).method(SB):
main.(*Array[main.myVal]).method STEXT dupok size=112 args=0x8 locals=0x18 funcid=0x15 align=0x0
...
0x0020 00032 (/tmp/xxxx/main.go:13) MOVD $main..dict.Array[main.myVal](SB), R1
0x0028 00040 (/tmp/xxxx/main.go:13) PCDATA $1, $1
0x0028 00040 (/tmp/xxxx/main.go:13) CALL main.(*Array[go.shape.struct {}]).method(SB)
would appreciate some hints why code is generated this way and why expected optimizations are not performed.
What did you expect to see?
ideally, inlining of GetValue() method and simply passing const 5 to fmt.Printf().
less ideally direct call of myVal.GetValue() in method()
What did you see instead?
indirect call, not concrete type knowledge used.
Go version
go1.21.3 darwin/arm64
What operating system and processor architecture are you using (
go env)?What did you do?
The following simple application:
most importantly it does indirect call of myVal.GetValue() (not speaking about missing inline possibility):
a) why it is calling
main.(*Array[go.shape.struct {}]).method(SB)instead concrete typemain.(*Array[main.myVal]).method?b)
main.(*Array[go.shape.struct {}]).methoddoesn't exploit knowledge of concrete type (myVal) and performs indirect call to GetValue():c) what is even more stranger, compiler generates unused concrete type
main.(*Array[main.myVal]).methodbut it doesn't exploit type knowledge as well and instead callsmain.(*Array[go.shape.struct {}]).method(SB):would appreciate some hints why code is generated this way and why expected optimizations are not performed.
What did you expect to see?
ideally, inlining of GetValue() method and simply passing const 5 to fmt.Printf().
less ideally direct call of myVal.GetValue() in method()
What did you see instead?
indirect call, not concrete type knowledge used.