Skip to content
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

cmd/compile: deadstores and nilchecks solvable after memory to ssa renames are not handled #69174

Open
mariecurried opened this issue Aug 30, 2024 · 5 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@mariecurried
Copy link

mariecurried commented Aug 30, 2024

Go version

go version devel go1.24-7fcd4a7 Mon Aug 19 23:36:23 2024 +0000 linux/amd64

What did you do?

I was reading https://www.dolthub.com/blog/2024-08-23-the-4-chan-go-programmer and there was a piece of code that caught my attention (keep in mind that it is a contrived example, but could reveal a bigger problem). So I decided to check the generated assembly (https://go.godbolt.org/z/oxqbPnPxn).

package test

func f() {
	i := 1
	setInt1(&i)
}

func setInt1(i *int) {
	setInt2(&i)
}

func setInt2(i **int) {
	setInt3(&i)
}

func setInt3(i ***int) {
	setInt4(&i)
}

func setInt4(i ****int) {
	****i = 100
}

What did you see happen?

In some of the functions there were redundant instructions (marked with ; REDUNDANT).

setInt4 is compiled to:

MOVQ    (AX), AX
MOVQ    (AX), AX
MOVQ    (AX), AX
MOVQ    $100, (AX)
RET

setInt3 is compiled to:

MOVQ    AX, command-line-arguments.i+8(SP) ; REDUNDANT
MOVQ    (AX), AX
MOVQ    (AX), AX
XCHGL   AX, AX
MOVQ    $100, (AX)
RET

setInt2 is compiled to:

MOVQ    AX, command-line-arguments.i+8(SP)  ; REDUNDANT
LEAQ    command-line-arguments.i+8(SP), AX  ; REDUNDANT
MOVQ    (AX), AX                            ; REDUNDANT
MOVQ    (AX), AX
XCHGL   AX, AX
XCHGL   AX, AX
MOVQ    $100, (AX)
RET

setInt1 is compiled to:

(...stack handling...)
MOVQ    AX, command-line-arguments.i+24(SP)  ; REDUNDANT
LEAQ    command-line-arguments.i+24(SP), AX  ; REDUNDANT
MOVQ    AX, command-line-arguments.i(SP)     ; REDUNDANT
LEAQ    command-line-arguments.i(SP), AX     ; REDUNDANT
MOVQ    (AX), AX                             ; REDUNDANT
MOVQ    (AX), AX                             ; REDUNDANT
NOP
XCHGL   AX, AX
XCHGL   AX, AX
MOVQ    $100, (AX)
(...stack handling...)
RET

What did you expect to see?

I expected to see no redundant instructions.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Aug 30, 2024
@prattmic
Copy link
Member

cc @golang/compiler @randall77

@prattmic prattmic added this to the Backlog milestone Aug 30, 2024
@prattmic prattmic added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Aug 30, 2024
@Jorropo
Copy link
Member

Jorropo commented Aug 31, 2024

This happens without inlining: https://go.godbolt.org/z/v58b47zf3

I know why it fails, there is a systemic tradeoff in most of the compiler only operating on SSA values, when you store things in memory (&i) a lot of optimization information is lost, here in this case nilcheckelim abandon.
So only the outer most *& pair is being optimized because the ****p is never stored in memory.

Solving this for all possible cases is impossible, and getting right often is extremely costy both in term of compilation time and compiler code complexity which is a tradeoff the go compiler usually do not accept.
The CPU perform store → load forward at runtime, I doubt this has huge cost impact at runtime.
image

I have an idea on how to cheaply improve this extremely naive example but this wont solve much more cases.

@Jorropo Jorropo self-assigned this Aug 31, 2024
@Jorropo Jorropo added NeedsFix The path to resolution is known, but the work has not been done. and removed NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Aug 31, 2024
@Jorropo
Copy link
Member

Jorropo commented Aug 31, 2024

Well I was only able to improve the situation slightly:

    # /tmp/a.go
    00000 (3) TEXT command-line-arguments.f(SB), ABIInternal
    00001 (3) FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
    00002 (3) FUNCDATA $1, gclocals·EaPwxsZ75yY1hHMVZLmk6g==(SB)
    00003 (3) FUNCDATA $2, command-line-arguments.f.stkobj(SB)
v6  00004 (+4) MOVQ $1, command-line-arguments.i-24(SP)
v27 00005 (+5) LEAQ command-line-arguments.i-24(SP), AX
v10 00006 (5) MOVQ AX, command-line-arguments.p1-8(SP)
v16 00007 (+6) LEAQ command-line-arguments.p1-8(SP), AX
v14 00008 (6) MOVQ AX, command-line-arguments.p2-16(SP)
v24 00009 (+9) MOVQ command-line-arguments.p2-16(SP), AX
v26 00010 (9) MOVQ (AX), AX
v28 00011 (9) MOVQ $100, (AX)
b1  00012 (10) RET
    00013 (?) END

I removed the in the way nilchecks, which removes one more load, however then the dead stores become in the way and I don't know of a cheap way to run theses during late opt.
I think this fall in the « passes ordering is hard » kind of camp, given it would solve itself if we reran the core generic passes in a loop until things stabilize but that expensive.

@Jorropo Jorropo added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. and removed NeedsFix The path to resolution is known, but the work has not been done. labels Aug 31, 2024
@Jorropo Jorropo removed their assignment Aug 31, 2024
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/609995 mentions this issue: cmd/compile: remove some uneeded nilchecks during opt

@Jorropo Jorropo changed the title cmd/compile: redundant instructions after inlining cmd/compile: deadstore and nilchecks solvable after memory to ssa renames are not handled Sep 2, 2024
@Jorropo Jorropo changed the title cmd/compile: deadstore and nilchecks solvable after memory to ssa renames are not handled cmd/compile: deadstores and nilchecks solvable after memory to ssa renames are not handled Sep 2, 2024
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. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
Status: In Progress
Development

No branches or pull requests

5 participants