Skip to content

cmd/compile: functions and methods calls for indirect imports not inlined #71598

@ArsenySamoylov

Description

@ArsenySamoylov

Go version

go version devel go1.24-6d39245514 Thu Oct 31 01:28:37 2024 +0000 linux/arm64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='arm64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/asamoylov/.cache/go-build'
GOENV='/home/asamoylov/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/asamoylov/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/asamoylov/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/asamoylov/repos/go-gh/'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/asamoylov/repos/go-gh/pkg/tool/linux_arm64'
GOVCS=''
GOVERSION='devel go1.24-6d39245514 Thu Oct 31 01:28:37 2024 +0000'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/asamoylov/.config/go/telemetry'
GCCGO='gccgo'
GOARM64='v8.0'
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 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2613944426=/tmp/go-build -gno-record-gcc-switches'

What did you do?

Hello! I found error in inlining. Basically, if module A imports module B. Module B imports module C. Module A can call functions from module C but can't inline them! However, if you directly import module C into A, then inlining succeeds.

Here is a example:

project/
--- go.mod
--- transform.go
--- Descriptor/
  --- go.mod
  --- descriptor.go
--- DescriptorWrapper/
  --- go.mod
  --- wrapper.go

descriptor.go

package Descriptor

type Descriptor struct {
	numberKind int64
}

func (d Descriptor) NumberKind() int64 {
	return d.numberKind
}

wrapper.go

package DescriptorWrapper

import "Descriptor"

type Wrapper struct {
	Desc Descriptor.Descriptor
}

transform.go

package transform

import (
   "DescriptorWrapper"
)

func GaugeArray(wr DescriptorWrapper.Wrapper) {
   desc := wr.Desc
   _ = desc.NumberKind()
}

Here we can see that call to NumberKind() wasn't inlined:

go build -a -gcflags="-m" transform.go 
# command-line-arguments
./transform.go:8:6: can inline GaugeArray

However, if we add direct import of "Descriptor":
transform.go

package transform

import (
	_ "Descriptor"
	"DescriptorWrapper"
)

func GaugeArray(wr DescriptorWrapper.Wrapper) {
	desc := wr.Desc
	_ = desc.NumberKind()
}

Here call to NumberKind() is inlined!

go build -a -gcflags="-m" transform.go 
# command-line-arguments
./transform.go:8:6: can inline GaugeArray
./transform.go:10:21: inlining call to Descriptor.Descriptor.NumberKind

In this example, in first case (when inlining do not happen) 'bodyReaderFor' from 'unifiedHaveInlineBody' return false and inlining fails (in second case it returns true):

cmd/compile/internal/noder/reader.go

// unifiedHaveInlineBody reports whether we have the function body for
// fn, so we can inline it.
func unifiedHaveInlineBody(fn *ir.Func) bool {
	if fn.Inl == nil {
		return false
	}

	_, ok := bodyReaderFor(fn)
	return ok
}

What did you see happen?

Function that can be inlined wasn't inlined.

What did you expect to see?

Inlining of function that can be inlined

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Performancecompiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions