cmd/compile: for arm64 epilog, do SP increment with a single instruction

That way, the frame is atomically popped. Previously, for big frames
the SP was unwound in two steps (because arm64 can only add constants
up to 1<<12 in a single instruction).

Fixes #73259

Change-Id: I382c249194ad7bc9fc19607c27487c58d90d49e5
Reviewed-on: https://go-review.googlesource.com/c/go/+/689235
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
Keith Randall 2025-07-21 10:09:35 -07:00 committed by Keith Randall
parent 5dac42363b
commit f7cc61e7d7

View file

@ -907,6 +907,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Reg = REGFP p.To.Reg = REGFP
p.To.Offset = REGLINK p.To.Offset = REGLINK
if aoffset < 1<<12 {
// ADD $aoffset, RSP, RSP // ADD $aoffset, RSP, RSP
q = newprog() q = newprog()
q.As = AADD q.As = AADD
@ -919,6 +920,36 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Link = p.Link q.Link = p.Link
p.Link = q p.Link = q
p = q p = q
} else {
// Put frame size in a separate register and
// add it in with a single instruction,
// so we never have a partial frame during
// the epilog. See issue 73259.
// MOVD $aoffset, REGTMP
q = newprog()
q.As = AMOVD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(aoffset)
q.To.Type = obj.TYPE_REG
q.To.Reg = REGTMP
q.Pos = p.Pos
q.Link = p.Link
p.Link = q
p = q
// ADD REGTMP, RSP, RSP
q = newprog()
q.As = AADD
q.From.Type = obj.TYPE_REG
q.From.Reg = REGTMP
q.To.Type = obj.TYPE_REG
q.To.Reg = REGSP
q.Spadj = -aoffset
q.Pos = p.Pos
q.Link = p.Link
p.Link = q
p = q
}
} }
// If enabled, this code emits 'MOV PC, R27' before every 'MOV LR, PC', // If enabled, this code emits 'MOV PC, R27' before every 'MOV LR, PC',