Skip to content

cmd/compile: code generated by generics seems inefficient #64699

@xaurx

Description

@xaurx

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions