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

$ go version
go version go1.25rc2 windows/amd64

Does this issue reproduce with the latest release?

Not on released 1.24.x or earlier

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

go env Output
$ go env
set AR=ar
set CC=gcc
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_ENABLED=0
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set CXX=g++
set GCCGO=gccgo
set GO111MODULE=
set GOAMD64=v1
set GOARCH=amd64
set GOAUTH=netrc
set GOBIN=
set GOCACHE=C:\Users\Christ910185\AppData\Local\go-build
set GOCACHEPROG=
set GODEBUG=
set GOENV=C:\Users\Christ910185\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFIPS140=off
set GOFLAGS=
set GOGCCFLAGS=-m64 -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\CHRIST~1\AppData\Local\Temp\go-build45565215=/tmp/go-build -gno-record-gcc-switches
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMOD=NUL
set GOMODCACHE=C:\Users\Christ910185\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\Christ910185\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Users\Christ910185\lang\go\go1.25rc2
set GOSUMDB=sum.golang.org
set GOTELEMETRY=off
set GOTELEMETRYDIR=C:\Users\Christ910185\AppData\Roaming\go\telemetry
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Users\Christ910185\lang\go\go1.25rc2\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.25rc2
set GOWORK=
set PKG_CONFIG=pkg-config

What did you do?

Greatly increased compile time for programs of a certain form. Git bisect traced the performance regression to commit ed24bb4e This proggie below shows the pattern - expanding the main() function with copies of the canonical line shows the performance lag in "go build" This program as written below (N=2) runs fine in go play, but if expanded to ~4000 lines by repeating the line in the main() function, it only runs in go1.24, times out in build using Go development version in go.dev/play

program-4000.txt

here is the "small" (N=2) version, see main() function

// "go build" of this program takes much longer using go1.25rc1 (and rc2) than using go <= 1.24.4.
// git bisect identified this commit as the cause, and reverting it cures the problem:
//
// ---
// commit ed24bb4e6047890af272733c5a8bdcc43834e517
// Date:   Wed Feb 12 18:55:04 2025 -0500
//
//   cmd/compile/internal/escape: propagate constants to interface conversions to avoid allocs
// ---
//
// The problem is also cured by setting GOTOOLCHAIN=go1.24.4
// Procedure: go clean -cache ; go build program.go ; alter program.go source code ; time go build program.go
//
// Build times in Win 11 on my machine (Intel i7-1365U, 1.80 GHz, 32 GB RAM):
//
//   Lines in main()  |    go1.24.4  |  go1.25rc2
//                    +              +
//        4200        |      ~3 sec. |    30 sec. (!)
//        8400        | also ~3 sec. |   200 sec. (!!)

package main

// The complex data structures here are not directly involved in the performance regression,
// but further simplification makes the regression less obvious. We have many programs like this.

type ErrAtom string
func (e ErrAtom) String() string { return "" }
func (e ErrAtom) Value() float64 { return 0.0 }
func (e ErrAtom) Desc() string   { return "error" }

type Atom interface {
    String() string
    Value() float64
    Desc() string
}

type Block struct {}

func (b Block) String() string   { return "block" }
func (b Block) Value() float64   { return 0.0 }
func (b Block) Desc() string     { return "block" }

const (
    NA_ERR    = ErrAtom("#N/A")
    True_Atom  = BoolAtom(true)
)

type NumAtom float64
func (v NumAtom) String() string { return "" }
func (v NumAtom) Value() float64 { return 0.0 }
func (v NumAtom) Desc() string   { return "number" }

type BoolAtom bool
func (b BoolAtom) Desc() string   { return "bool" }
func (b BoolAtom) String() string { return "bool" }
func (b BoolAtom) Value() float64 { return 0.0 }

type FunAtom struct {
    Func  func() Atom
}

type AnyAtom interface {
    Desc() string
}

func V(a, b, c, d Atom) Atom { return NA_ERR }

func main() {

// This is the canonical line:

    _ = &FunAtom{Func: func() Atom { return V(True_Atom, Block{}, NumAtom(2), True_Atom) }}

// ... add additional N-2 copies of the canonical line here to study case N ...

    _ = &FunAtom{Func: func() Atom { return V(True_Atom, Block{}, NumAtom(2), True_Atom) }}
}

What did you expect to see?

Compile time (go build) between 2 and 3 seconds, even for very large main() functions with many repetitions of the same line.

What did you see instead?

Compile times of 30 sec for main() with 4000 lines (attached as program-4000.txt), and compile time of 3.3 min. for 8000-line version.

Comment From: chris99742

This program takes under 3 seconds to build in go1.24.4 or earlier, but takes over 30 sec with go1.25rc1 and rc2

program-4000.txt

Comment From: thepudds

Hi @chris99742, I'll take a look. Thanks for the report!

Comment From: cherrymui

cc @golang/compiler

Comment From: gopherbot

Change https://go.dev/cl/688075 mentions this issue: cmd/compile/internal/escape: make the ir.ReassignOracle cache more broadly scoped

Comment From: thepudds

Hi @chris99742, I sent https://go.dev/cl/688075, which is a test change and still WIP, but the CL does seem to restore the compile time for your program-4000.txt example, at least in a quick initial test.

Comparing go1.24 vs. go1.25rc2 vs. that CL for program-4000.txt:

                   build time (wall clock)

       go1.24.4      ~0.5 sec
      go1.25rc2     ~26.4 sec
  cl-688075-ps1      ~0.5 sec

Would you be able to try that CL out locally to see if there is any improvement?

For example, one way is via the official gotip utility:

# download and build CL 688075 (currently patchset 3):

$ go install golang.org/dl/gotip@latest  
$ gotip download 688075 

# get example program:

$ wget -O 4000.go https://github.com/user-attachments/files/21222862/program-4000.txt

# compile example program using CL 688075:

$ gotip tool compile 4000.go

Comment From: chris99742

Hi @thepudds, I followed your gotip instructions and the times look great, not just for the example program, but I used the resulting gotip (go version go1.25-devel_02eba975fa) to run our test suite and the overall time is the same as when running it with go1.24.4 (back to about 42 minutes). Thank you very much! I did see a related issue about ReassignOracle before I created this one, but I was not able to confidently test it. A separate thank you for the gotip instructions. If it is my responsibility to somehow close this issue or mark it resolved, I will do so (but I do hope the CL is slated for inclusion in the 1.25 release!)

Comment From: thepudds

Hi @chris99742, thanks for trying it out! And glad to hear your overall times seem to be back to Go 1.24 speeds.

If it is my responsibility to somehow close this issue or mark it resolved, I will do so

This issue will be automatically closed when a fix for it is merged, so no need for you to close it. (Hopefully that fix will be some flavor of the CL I sent, though I'm still looking at it and I'm about to tweak it some).

Comment From: thepudds

Hi @chris99742, I tweaked the implementation a bit (to make it a simpler and cleaner change).

Now that the fix is merged, would you mind trying with master/tip on your ~40 min test suite to confirm things still look good?

You can use the gotip utility again, but this time do not supply a CL number, which means it will automatically download and build the latest Go toolchain on master.

$ gotip download