[llvm] 4a0b5bc - [MC] [Win64EH] Produce packed unwind for the special case of X19+LR (#169697)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 2 03:29:56 PST 2025
Author: Martin Storsjö
Date: 2025-12-02T13:29:51+02:00
New Revision: 4a0b5bc2b5ddacc12260761a0ea18fdf2442e412
URL: https://github.com/llvm/llvm-project/commit/4a0b5bc2b5ddacc12260761a0ea18fdf2442e412
DIFF: https://github.com/llvm/llvm-project/commit/4a0b5bc2b5ddacc12260761a0ea18fdf2442e412.diff
LOG: [MC] [Win64EH] Produce packed unwind for the special case of X19+LR (#169697)
Added:
Modified:
llvm/lib/MC/MCWin64EH.cpp
llvm/test/MC/AArch64/seh-packed-unwind.s
Removed:
################################################################################
diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index f5f8bbb6a3859..6835ba73ffab8 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -1051,7 +1051,9 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
// the order - that would work fine when unwinding from within
// functions, but not be exactly right if unwinding happens within
// prologs/epilogs.
- for (const WinEH::Instruction &Inst : info->Instructions) {
+ for (auto It = info->Instructions.begin(), EndIt = info->Instructions.end();
+ It != EndIt; It++) {
+ const WinEH::Instruction &Inst = *It;
switch (Inst.Operation) {
case Win64EH::UOP_End:
if (Location != Start)
@@ -1169,6 +1171,28 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
Location != FloatRegs && Location != InputArgs &&
Location != StackAdjust)
return false;
+ // Becuase there's no save_lrpair_x opcode, the case of CR=01,
+ // RegI=1 is handled as a special case with a pair of instructions; an
+ // alloc followed by a regular save_lrpair. So when encountering an
+ // alloc here, check if this is the start of such an instruction pair.
+ if (Location == Start2) { // Can't have this at Start3, after PACSignLR
+ auto NextIt = It + 1;
+ if (NextIt != EndIt) {
+ const WinEH::Instruction &NextInst = *NextIt;
+ if (NextInst.Operation == Win64EH::UOP_SaveLRPair &&
+ NextInst.Offset == 0 && NextInst.Register == 19) {
+ assert(Predecrement == 0);
+ assert(RegI == 0);
+ assert(!StandaloneLR);
+ Predecrement = Inst.Offset;
+ RegI = 1;
+ StandaloneLR = true;
+ Location = FloatRegs;
+ It++; // Consume both the Alloc and the SaveLRPair
+ continue;
+ }
+ }
+ }
// Can have either a single decrement, or a pair of decrements with
// 4080 and another decrement.
if (StackOffset == 0)
@@ -1269,6 +1293,15 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
// according to the documentation.
if (H)
return false;
+ // Older versions of Windows (at least in 10.0.22000.2176) incorrectly
+ // unwind packed unwind info with CR=01, RegI=1, RegF>0, see
+ // https://github.com/llvm/llvm-project/issues/169588#issuecomment-3584907886.
+ // This issue only exists in older versions; current versions
+ // (10.0.26100.6899) do handle it correctly. As long as we can't be sure
+ // that we won't run on older versions, avoid producing the packed form
+ // here.
+ if (StandaloneLR && RegI == 1 && RegF > 0)
+ return false;
int IntSZ = 8 * RegI;
if (StandaloneLR)
IntSZ += 8;
diff --git a/llvm/test/MC/AArch64/seh-packed-unwind.s b/llvm/test/MC/AArch64/seh-packed-unwind.s
index 5b86ab4bc0d49..4c0f30b2536cd 100644
--- a/llvm/test/MC/AArch64/seh-packed-unwind.s
+++ b/llvm/test/MC/AArch64/seh-packed-unwind.s
@@ -295,6 +295,26 @@
// CHECK-NEXT: end
// CHECK-NEXT: ]
// CHECK-NEXT: }
+// CHECK-NEXT: RuntimeFunction {
+// CHECK-NEXT: Function: func19
+// CHECK-NEXT: Fragment: No
+// CHECK-NEXT: FunctionLength: 32
+// CHECK-NEXT: RegF: 0
+// CHECK-NEXT: RegI: 1
+// CHECK-NEXT: HomedParameters: No
+// CHECK-NEXT: CR: 1
+// CHECK-NEXT: FrameSize: 80
+// CHECK-NEXT: Prologue [
+// CHECK-NEXT: sub sp, sp, #64
+// CHECK-NEXT: stp x19, lr, [sp]
+// CHECK-NEXT: sub sp, sp, #16
+// CHECK-NEXT: end
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: RuntimeFunction {
+// CHECK-NEXT: Function: notpacked_func20
+// CHECK-NEXT: ExceptionRecord:
+// CHECK-NEXT: ExceptionData {
// CHECK: RuntimeFunction {
// CHECK-NEXT: Function: nonpacked1
// CHECK-NEXT: ExceptionRecord:
@@ -374,6 +394,11 @@
// CHECK-NEXT: Function: nonpacked16
// CHECK-NEXT: ExceptionRecord:
// CHECK-NEXT: ExceptionData {
+// CHECK: EpiloguePacked: Yes
+// CHECK: RuntimeFunction {
+// CHECK-NEXT: Function: nonpacked17
+// CHECK-NEXT: ExceptionRecord:
+// CHECK-NEXT: ExceptionData {
// CHECK: EpiloguePacked: Yes
@@ -809,6 +834,59 @@ func18:
ret
.seh_endproc
+func19:
+ .seh_proc func19
+ sub sp, sp, #16
+ .seh_stackalloc 16
+ stp x19, lr, [sp]
+ .seh_save_lrpair x19, 0
+ sub sp, sp, #64
+ .seh_stackalloc 64
+ .seh_endprologue
+ nop
+ .seh_startepilogue
+ add sp, sp, #64
+ .seh_stackalloc 64
+ ldp x19, lr, [sp]
+ .seh_save_lrpair x19, 0
+ add sp, sp, #16
+ .seh_stackalloc 16
+ .seh_endepilogue
+ ret
+ .seh_endproc
+
+notpacked_func20:
+ // This function is expressible with packed unwind info, but older
+ // versions of Windows unwind cases with CR=01, RegI=1, RegF>0
+ // incorrectly; therefore, we choose not to pack this case.
+ .seh_proc notpacked_func20
+ sub sp, sp, #48
+ .seh_stackalloc 48
+ stp x19, lr, [sp]
+ .seh_save_lrpair x19, 0
+ stp d8, d9, [sp, #16]
+ .seh_save_fregp d8, 16
+ str d10, [sp, #32]
+ .seh_save_freg d10, 32
+ sub sp, sp, #64
+ .seh_stackalloc 64
+ .seh_endprologue
+ nop
+ .seh_startepilogue
+ add sp, sp, #64
+ .seh_stackalloc 64
+ ldr d10, [sp, #32]
+ .seh_save_freg d10, 32
+ ldp d8, d9, [sp, #16]
+ .seh_save_fregp d8, 16
+ ldp x19, lr, [sp]
+ .seh_save_lrpair x19, 0
+ add sp, sp, #48
+ .seh_stackalloc 48
+ .seh_endepilogue
+ ret
+ .seh_endproc
+
nonpacked1:
.seh_proc nonpacked1
// Can't be packed; can't save integer registers after float registers.
@@ -1157,3 +1235,34 @@ nonpacked16:
.seh_endepilogue
br x9
.seh_endproc
+
+nonpacked17:
+ .seh_proc nonpacked17
+ // Can't be packed; more predecrement for SavSZ than used for
+ // corresponding RegI/RegF/LR saves
+ sub sp, sp, #64
+ .seh_stackalloc 64
+ stp x19, lr, [sp]
+ .seh_save_lrpair x19, 0
+ stp d8, d9, [sp, #16]
+ .seh_save_fregp d8, 16
+ str d10, [sp, #32]
+ .seh_save_freg d10, 32
+ sub sp, sp, #64
+ .seh_stackalloc 64
+ .seh_endprologue
+ nop
+ .seh_startepilogue
+ add sp, sp, #64
+ .seh_stackalloc 64
+ ldr d10, [sp, #32]
+ .seh_save_freg d10, 32
+ ldp d8, d9, [sp, #16]
+ .seh_save_fregp d8, 16
+ ldp x19, lr, [sp]
+ .seh_save_lrpair x19, 0
+ add sp, sp, #64
+ .seh_stackalloc 64
+ .seh_endepilogue
+ ret
+ .seh_endproc
More information about the llvm-commits
mailing list