Transform (ADDQconst SP) into (LEA SP), because lea is rematerializeable,
so this avoids register spill. We can't mark ADDQconst as rematerializeable,
because it clobbers flags. This makes go binary ~2kb smaller.
For reference here is generated code for function from bug report.
Before:
CALL "".g(SB)
MOVBLZX (SP), AX
LEAQ 8(SP), DI
TESTB AX, AX
JEQ 15
MOVQ "".p(SP), SI
DUFFCOPY $196
MOVQ $0, (SP)
PCDATA $0, $1
CALL "".h(SB)
RET
MOVQ DI, ""..autotmp_2-8(SP) // extra spill
PCDATA $0, $2
CALL "".g(SB)
MOVQ ""..autotmp_2-8(SP), DI // extra register fill
MOVQ "".p(SP), SI
DUFFCOPY $196
MOVQ $1, (SP)
PCDATA $0, $1
CALL "".h(SB)
JMP 14
END
After:
CALL "".g(SB)
MOVBLZX (SP), AX
TESTB AX, AX
JEQ 15
LEAQ 8(SP), DI
MOVQ "".p(SP), SI
DUFFCOPY $196
MOVQ $0, (SP)
PCDATA $0, $1
CALL "".h(SB)
RET
PCDATA $0, $0 // no spill
CALL "".g(SB)
LEAQ 8(SP), DI // rematerialized instead
MOVQ "".p(SP), SI
DUFFCOPY $196
MOVQ $1, (SP)
PCDATA $0, $1
CALL "".h(SB)
JMP 14
END
Fixes #22947
Change-Id: I8f33b860dc6c8828373477171b172ca2ce30074f
Reviewed-on: https://go-review.googlesource.com/81815
Run-TryBot: Ilya Tocar <ilya.tocar@intel.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
(MOVLf2i <t> (Arg [off] {sym})) -> @b.Func.Entry (Arg <t> [off] {sym})
(MOVQi2f <t> (Arg [off] {sym})) -> @b.Func.Entry (Arg <t> [off] {sym})
(MOVLi2f <t> (Arg [off] {sym})) -> @b.Func.Entry (Arg <t> [off] {sym})
+
+// LEAQ is rematerializeable, so this helps to avoid register spill.
+// See isuue 22947 for details
+(ADDQconst [off] x:(SP)) -> (LEAQ [off] x)
v.AddArg(x)
return true
}
+ // match: (ADDQconst [off] x:(SP))
+ // cond:
+ // result: (LEAQ [off] x)
+ for {
+ off := v.AuxInt
+ x := v.Args[0]
+ if x.Op != OpSP {
+ break
+ }
+ v.reset(OpAMD64LEAQ)
+ v.AuxInt = off
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64ADDQconstmem_0(v *Value) bool {