[release-branch.go1.23] 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 #74693

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>
(cherry picked from commit f7cc61e7d7f77521e073137c6045ba73f66ef902)
Reviewed-on: https://go-review.googlesource.com/c/go/+/689595
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 20498bc..f15b6a9 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -882,18 +882,49 @@
 				p.To.Reg = REGFP
 				p.To.Offset = REGLINK
 
-				// ADD $aoffset, RSP, RSP
-				q = newprog()
-				q.As = AADD
-				q.From.Type = obj.TYPE_CONST
-				q.From.Offset = int64(aoffset)
-				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 aoffset < 1<<12 {
+					// ADD $aoffset, RSP, RSP
+					q = newprog()
+					q.As = AADD
+					q.From.Type = obj.TYPE_CONST
+					q.From.Offset = int64(aoffset)
+					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
+				} 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',