Open
Description
go tip
While working on changing runtime.growslice to not return the length of the new slice (like was done for runtime.makeslice 020a18c) I ran into the issue of not being able to make the compiler rematerialize the new slice length instead of spilling it in
go/src/cmd/compile/internal/gc/ssa.go
Line 2479 in d97bd5d
There generally seems to be a missed opportunity for the compiler to prefer recomputing a value that is cheap to compute from other values that too need to be loaded after a call.
Hand distilled example:
//go:noinline
func spilltest(s []int, a int) (int, int) {
b := a + 1
if b > len(s) {
somecall()
}
return a, b
}
produces:
0x450380 MOVQ FS:0xfffffff8, CX
0x450389 CMPQ 0x10(CX), SP
0x45038d JBE 0x4503d8
0x45038f SUBQ $0x10, SP
0x450393 MOVQ BP, 0x8(SP)
0x450398 LEAQ 0x8(SP), BP
0x45039d MOVQ 0x30(SP), AX
0x4503a2 LEAQ 0x1(AX), CX // first computation of b
0x4503a6 MOVQ 0x20(SP), DX
0x4503ab CMPQ DX, CX
0x4503ae JG 0x4503c4
0x4503b0 MOVQ AX, 0x38(SP)
0x4503b5 MOVQ CX, 0x40(SP)
0x4503ba MOVQ 0x8(SP), BP
0x4503bf ADDQ $0x10, SP
0x4503c3 RET
0x4503c4 MOVQ CX, 0(SP) // Avoid this spill
0x4503c8 CALL main.somecall(SB)
0x4503cd MOVQ 0x30(SP), AX
0x4503d2 MOVQ 0(SP), CX // do LEAQ 0x1(AX), CX here instead to compute b
0x4503d6 JMP 0x4503b0
0x4503d8 CALL runtime.morestack_noctxt(SB)
0x4503dd JMP main.spilltest(SB)
Neither
func spilltest(s []int, a int) (int, int) {
b := a + 1
if b > len(s) {
somecall()
b = a + 1
}
return a, b
}
Or
func spilltest(s []int, a int) (int, int) {
b := a + 1
if b > len(s) {
somecall()
}
c := a + 1
return a, c
}
avoids the spilling.