Skip to content

cmd/compile: get struct member when inlining #69935

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

Closed
AlphaLxy opened this issue Oct 18, 2024 · 2 comments
Closed

cmd/compile: get struct member when inlining #69935

AlphaLxy opened this issue Oct 18, 2024 · 2 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime.

Comments

@AlphaLxy
Copy link

Go version

go version go1.23.0 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/*/.cache/go-build'
GOENV='/home/*/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/*/go/pkg/mod'
GOOS='linux'
GOPATH='/home/*/go'
GOROOT='/data00/home/*/go1.23.0'
GOSUMDB='sum.golang.google.cn'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/data00/home/*/go1.23.0/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.23.0'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/*/.config/go/telemetry'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/dev/null'
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 -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build104609920=/tmp/go-build -gno-record-gcc-switches'

What did you do?

I need to get field v from a value of type Foo, see testGetField1 and testGetField2.

package main

type Foo struct {
	v interface{}
	_ interface{}
	_ interface{}
	_ interface{}
}

//go:noinline
func testGetField1(foo Foo) interface{} {
	return foo.v
}

//go:noinline
func testGetField2(foo Foo) interface{} {
	return getValue(foo)
}

func getValue(foo Foo) interface{} {
	return foo.v
}

func main() {
	testGetField1(Foo{})
	testGetField2(Foo{})
}

What did you see happen?

I'm sure that getValue is inlined but the testGetField2 method has many useless copies.

TEXT main.testGetField1(SB)
main.go:11  4889442408        MOVQ AX, 0x8(SP)
main.go:11  48895c2410        MOVQ BX, 0x10(SP)
main.go:11  48894c2418        MOVQ CX, 0x18(SP)
main.go:11  48897c2420        MOVQ DI, 0x20(SP)
main.go:11  4889742428        MOVQ SI, 0x28(SP)
main.go:11  4c89442430        MOVQ R8, 0x30(SP)
main.go:11  4c894c2438        MOVQ R9, 0x38(SP)
main.go:11  4c89542440        MOVQ R10, 0x40(SP)
main.go:12  488b442408        MOVQ 0x8(SP), AX
main.go:12  488b5c2410        MOVQ 0x10(SP), BX
main.go:12  c3                RET
TEXT main.testGetField2(SB)
main.go:16  55                PUSHQ BP
main.go:16  4889e5            MOVQ SP, BP
main.go:16  4883ec40          SUBQ $0x40, SP
main.go:16  4889442450        MOVQ AX, 0x50(SP)
main.go:16  48895c2458        MOVQ BX, 0x58(SP)
main.go:16  48894c2460        MOVQ CX, 0x60(SP)
main.go:16  48897c2468        MOVQ DI, 0x68(SP)
main.go:16  4889742470        MOVQ SI, 0x70(SP)
main.go:16  4c89442478        MOVQ R8, 0x78(SP)
main.go:16  4c898c2480000000  MOVQ R9, 0x80(SP)
main.go:16  4c89942488000000  MOVQ R10, 0x88(SP)
main.go:17  0f10442450        MOVUPS 0x50(SP), X0   // useless copies
main.go:17  0f110424          MOVUPS X0, 0(SP)      //
main.go:17  0f10442460        MOVUPS 0x60(SP), X0   //
main.go:17  0f11442410        MOVUPS X0, 0x10(SP)   //
main.go:17  0f10442470        MOVUPS 0x70(SP), X0   //
main.go:17  0f11442420        MOVUPS X0, 0x20(SP)   //
main.go:17  0f10842480000000  MOVUPS 0x80(SP), X0   //
main.go:17  0f11442430        MOVUPS X0, 0x30(SP)   //
main.go:21  488b0424          MOVQ 0(SP), AX        // inlined getValue
main.go:21  488b5c2408        MOVQ 0x8(SP), BX      //
main.go:17  4883c440          ADDQ $0x40, SP
main.go:17  5d                POPQ BP
main.go:17  c3                RET

There's no such problem if i change func getValue(foo Foo) interface{} to func getValue(foo *Foo) interface{}. But we already have a lot of codes using getValue(foo). and it's difficult to change parameter type.

What did you expect to see?

The asm code of testGetField1 and testGetField2 should be same.

Why this kind of code can not be optimized?
Is there any other way i can optimize it without change parameter type?

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Oct 18, 2024
@randall77
Copy link
Contributor

This is probably a duplicate of #24416. We just don't do a very good job with large structs.

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.
Projects
None yet
Development

No branches or pull requests

4 participants