[llvm] [X86] Don't skip frame setup/destroy on SEH pseudos and regenerate tests (PR #225445)

Mikołaj Piróg via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 05:50:07 PDT 2026


https://github.com/mikolaj-pirog updated https://github.com/llvm/llvm-project/pull/225445

>From 151bcee08391fa0efceed10ba78a32071b85329b Mon Sep 17 00:00:00 2001
From: "Pirog, Mikolaj Maciej" <mikolaj.maciej.pirog at intel.com>
Date: Tue, 22 Sep 2026 17:50:36 +0200
Subject: [PATCH 1/2] Use framesetup/destroy on SEH pseudos and regenrate tests

---
 llvm/lib/Target/X86/X86FrameLowering.cpp      |  9 ++-
 llvm/lib/Target/X86/X86WinEHUnwindV2.cpp      |  6 +-
 .../test/CodeGen/X86/taildup-callsiteinfo.mir |  4 +-
 .../CodeGen/X86/win64-eh-empty-block-2.mir    |  8 +--
 .../CodeGen/X86/win64-eh-unwindv2-errors.mir  | 56 +++++++--------
 ...win64-eh-unwindv2-push-pop-stack-alloc.mir | 36 +++++-----
 .../win64-eh-unwindv2-too-many-epilogs.mir    | 42 ++++++------
 .../X86/win64-eh-unwindv2-too-many-instr.mir  | 40 ++++++-----
 .../win64-eh-unwindv3-too-many-epilog-ops.mir | 68 +++++++++----------
 .../win64-eh-unwindv3-too-many-prolog-ops.mir |  4 +-
 .../MIR/X86/instr-ref-join-def-vphi.mir       |  4 +-
 11 files changed, 146 insertions(+), 131 deletions(-)

diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index fad665e31bbe59..5e120a9c9f22b2 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -2753,7 +2753,8 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
     }
 
     // For V3, SEH_BeginEpilogue must be emitted before any epilog SEH pseudos.
-    BuildMI(MBB, EpilogStart, DL, TII.get(X86::SEH_BeginEpilogue));
+    BuildMI(MBB, EpilogStart, DL, TII.get(X86::SEH_BeginEpilogue))
+        .setMIFlag(MachineInstr::FrameDestroy);
   }
 
   // If dynamic alloca is used, then reset esp to point to the last callee-saved
@@ -2816,7 +2817,8 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
 
   // For V1/V2, emit SEH_BeginEpilogue after stack restore code.
   if (!IsWin64UnwindV3 && NeedsWin64CFI && MF.hasWinCFI())
-    BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_BeginEpilogue));
+    BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_BeginEpilogue))
+        .setMIFlag(MachineInstr::FrameDestroy);
 
   if (!HasFP && NeedsDwarfCFI) {
     MBBI = FirstCSPop;
@@ -2863,7 +2865,8 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
     BuildMI(MBB, Terminator, DL, TII.get(X86::TILERELEASE));
 
   if (NeedsWin64CFI && MF.hasWinCFI())
-    BuildMI(MBB, Terminator, DL, TII.get(X86::SEH_EndEpilogue));
+    BuildMI(MBB, Terminator, DL, TII.get(X86::SEH_EndEpilogue))
+        .setMIFlag(MachineInstr::FrameDestroy);
 }
 
 StackOffset X86FrameLowering::getFrameIndexReference(const MachineFunction &MF,
diff --git a/llvm/lib/Target/X86/X86WinEHUnwindV2.cpp b/llvm/lib/Target/X86/X86WinEHUnwindV2.cpp
index 79b91206e9d5b1..cf291634e7d9be 100644
--- a/llvm/lib/Target/X86/X86WinEHUnwindV2.cpp
+++ b/llvm/lib/Target/X86/X86WinEHUnwindV2.cpp
@@ -418,7 +418,8 @@ bool runX86WinEHUnwindV2(MachineFunction &MF) {
       MachineBasicBlock &MBB = *Info.UnwindV2StartLocation->getParent();
       const DebugLoc &DL = Info.UnwindV2StartLocation->getDebugLoc();
       BuildMI(MBB, Info.UnwindV2StartLocation, DL,
-              TII->get(X86::SEH_UnwindV2Start));
+              TII->get(X86::SEH_UnwindV2Start))
+          .setMIFlag(MachineInstr::FrameDestroy);
 
       if ((LastUnwindInfoEndPosition - Info.ApproximateInstructionPosition >=
            InstructionCountThreshold) ||
@@ -438,7 +439,8 @@ bool runX86WinEHUnwindV2(MachineFunction &MF) {
   MachineBasicBlock &FirstMBB = MF.front();
   BuildMI(FirstMBB, FirstMBB.front(), findDebugLoc(FirstMBB),
           TII->get(X86::SEH_UnwindVersion))
-      .addImm(2);
+      .addImm(2)
+      .setMIFlag(MachineInstr::FrameSetup);
 
   return true;
 }
diff --git a/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir b/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir
index 93991799aeb2a9..8aa25324a8cb3f 100644
--- a/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir
+++ b/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir
@@ -68,9 +68,9 @@ body:             |
     liveins: $ecx
 
     CALL64pcrel32 @alloc, csr_win64, implicit $rsp, implicit $ssp, implicit $ecx, implicit-def $rsp, implicit-def $ssp, implicit-def dead $rax
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rsp = frame-destroy ADD64ri8 $rsp, 40, implicit-def dead $eflags
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     TAILJMPd64 @f2, csr_win64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp
 
 ...
diff --git a/llvm/test/CodeGen/X86/win64-eh-empty-block-2.mir b/llvm/test/CodeGen/X86/win64-eh-empty-block-2.mir
index b97bccd11705d0..6efb7aa59ea861 100644
--- a/llvm/test/CodeGen/X86/win64-eh-empty-block-2.mir
+++ b/llvm/test/CodeGen/X86/win64-eh-empty-block-2.mir
@@ -170,10 +170,10 @@ body:             |
 
   bb.8.return (machine-block-address-taken):
     $eax = MOV32rm $rbp, 1, $noreg, -12, $noreg :: (load (s32) from %stack.0)
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rsp = frame-destroy ADD64ri8 $rsp, 48, implicit-def dead $eflags
     $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 $eax
 
   bb.1.if.then:
@@ -216,10 +216,10 @@ body:             |
     frame-setup SEH_EndPrologue
     MOV32mi $rbp, 1, $noreg, -12, $noreg, 1 :: (store (s32) into %stack.0)
     $rax = LEA64r $rip, 0, $noreg, %bb.8, $noreg
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rsp = frame-destroy ADD64ri8 $rsp, 32, implicit-def dead $eflags
     $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     CATCHRET %bb.8, %bb.0
 
 ...
diff --git a/llvm/test/CodeGen/X86/win64-eh-unwindv2-errors.mir b/llvm/test/CodeGen/X86/win64-eh-unwindv2-errors.mir
index 32023d1d85f253..dc224d31a138a2 100644
--- a/llvm/test/CodeGen/X86/win64-eh-unwindv2-errors.mir
+++ b/llvm/test/CodeGen/X86/win64-eh-unwindv2-errors.mir
@@ -36,8 +36,8 @@ body:             |
     $rsp = frame-setup SUB64ri32 $rsp, 40, implicit-def dead $eflags
     frame-setup SEH_StackAlloc 40
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 
@@ -74,9 +74,9 @@ body:             |
     frame-setup PUSH64r killed $rdi, implicit-def $rsp, implicit $rsp
     frame-setup SEH_PushReg 55
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rdi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 
@@ -109,9 +109,9 @@ name:            dealloc_no_alloc
 body:             |
   bb.0.entry:
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rsp = frame-destroy ADD64ri32 $rsp, 40, implicit-def dead $eflags
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 
@@ -146,8 +146,8 @@ name:            dealloc_after_epilog
 body:             |
   bb.0.entry:
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     $rsp = frame-destroy ADD64ri32 $rsp, 40, implicit-def dead $eflags
     RET64
 ...
@@ -185,10 +185,10 @@ body:             |
     $rsp = frame-setup SUB64ri32 $rsp, 40, implicit-def dead $eflags
     frame-setup SEH_StackAlloc 40
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rdi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     $rsp = frame-destroy ADD64ri32 $rsp, 40, implicit-def dead $eflags
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 
@@ -221,9 +221,9 @@ name:            mov_no_setframe
 body:             |
   bb.0.entry:
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rsp = MOV64rr $rbp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 
@@ -260,8 +260,8 @@ body:             |
     $rbp = MOV64rr $rsp
     frame-setup SEH_SetFrame 52, 0
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     $rsp = MOV64rr $rbp
     RET64
 ...
@@ -299,10 +299,10 @@ body:             |
     $rbp = MOV64rr $rsp
     frame-setup SEH_SetFrame 52, 0
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rdi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     $rsp = MOV64rr $rbp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 
@@ -339,10 +339,10 @@ body:             |
     $rsp = frame-setup SUB64ri32 $rsp, 40, implicit-def dead $eflags
     frame-setup SEH_StackAlloc 40
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rsp = frame-destroy ADD64ri32 $rsp, 40, implicit-def dead $eflags
     $rsp = MOV64rr $rbp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 
@@ -377,10 +377,10 @@ body:             |
     frame-setup PUSH64r killed $rdi, implicit-def $rsp, implicit $rsp
     frame-setup SEH_PushReg 55
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rdi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     $rsi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 
@@ -417,10 +417,10 @@ body:             |
     frame-setup PUSH64r killed $rsi, implicit-def $rsp, implicit $rsp
     frame-setup SEH_PushReg 60
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rdi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     $rsi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 
@@ -453,8 +453,8 @@ name:            pop_after_epilog
 body:             |
   bb.0.entry:
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     $rdi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     RET64
 ...
@@ -488,8 +488,8 @@ name:            instr_after_epilog
 body:             |
   bb.0.entry:
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     $ecx = MOV32rr killed $eax
     RET64
 ...
@@ -527,10 +527,10 @@ body:             |
     $rsp = frame-setup SUB64ri32 $rsp, 40, implicit-def dead $eflags
     frame-setup SEH_StackAlloc 40
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rsp = frame-destroy ADD64ri32 $rsp, 20, implicit-def dead $eflags
     $rdi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     $rsp = frame-destroy ADD64ri32 $rsp, 20, implicit-def dead $eflags
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
diff --git a/llvm/test/CodeGen/X86/win64-eh-unwindv2-push-pop-stack-alloc.mir b/llvm/test/CodeGen/X86/win64-eh-unwindv2-push-pop-stack-alloc.mir
index 8207ba3d97bd66..cb30162b70d162 100644
--- a/llvm/test/CodeGen/X86/win64-eh-unwindv2-push-pop-stack-alloc.mir
+++ b/llvm/test/CodeGen/X86/win64-eh-unwindv2-push-pop-stack-alloc.mir
@@ -12,35 +12,35 @@
 # CHECK-LABEL:  name:            push_pop_same
 # CHECK:        body:
 # CHECK-NEXT:     bb.0
-# CHECK-NEXT:       SEH_UnwindVersion 2
+# CHECK-NEXT:       frame-setup SEH_UnwindVersion 2
 # CHECK-NEXT:       frame-setup PUSH64r undef $rax
 # CHECK-NEXT:       frame-setup SEH_StackAlloc 8
 # CHECK-NEXT:       frame-setup SEH_EndPrologue
-# CHECK-NEXT:       SEH_BeginEpilogue
+# CHECK-NEXT:       frame-destroy SEH_BeginEpilogue
 # CHECK-NEXT:       $rax = frame-destroy
-# CHECK-NEXT:       SEH_UnwindV2Start
-# CHECK-NEXT:       SEH_EndEpilogue
+# CHECK-NEXT:       frame-destroy SEH_UnwindV2Start
+# CHECK-NEXT:       frame-destroy SEH_EndEpilogue
 # CHECK-NEXT:       RET64
 
 # Pushes and pops a different register.
 # CHECK-LABEL:  name:            push_pop_different
 # CHECK:        body:
 # CHECK-NEXT:     bb.0
-# CHECK-NEXT:       SEH_UnwindVersion 2
+# CHECK-NEXT:       frame-setup SEH_UnwindVersion 2
 # CHECK-NEXT:       frame-setup PUSH64r undef $rax
 # CHECK-NEXT:       frame-setup SEH_StackAlloc 8
 # CHECK-NEXT:       frame-setup SEH_EndPrologue
-# CHECK:            SEH_BeginEpilogue
+# CHECK:            frame-destroy SEH_BeginEpilogue
 # CHECK-NEXT:       $rcx = frame-destroy POP64r
-# CHECK-NEXT:       SEH_UnwindV2Start
-# CHECK-NEXT:       SEH_EndEpilogue
+# CHECK-NEXT:       frame-destroy SEH_UnwindV2Start
+# CHECK-NEXT:       frame-destroy SEH_EndEpilogue
 # CHECK-NEXT:       RET64 $eax
 
 # Pushes in the prolog, adds in the epilog.
 # CHECK-LABEL:  name:            push_add
 # CHECK:        body:
 # CHECK-NEXT:     bb.0
-# CHECK-NEXT:       SEH_UnwindVersion 2
+# CHECK-NEXT:       frame-setup SEH_UnwindVersion 2
 # CHECK-NEXT:       frame-setup PUSH64r killed $r15
 # CHECK-NEXT:       frame-setup SEH_PushReg 126
 # CHECK-NEXT:       frame-setup PUSH64r killed $r14
@@ -54,15 +54,15 @@
 # CHECK-NEXT:       frame-setup PUSH64r undef $rax
 # CHECK-NEXT:       frame-setup SEH_StackAlloc 8
 # CHECK-NEXT:       frame-setup SEH_EndPrologue
-# CHECK:            SEH_BeginEpilogue
+# CHECK:            frame-destroy SEH_BeginEpilogue
 # CHECK-NEXT:       $rsp = frame-destroy ADD64ri32 $rsp, 8
-# CHECK-NEXT:       SEH_UnwindV2Start
+# CHECK-NEXT:       frame-destroy SEH_UnwindV2Start
 # CHECK-NEXT:       $rbx = frame-destroy POP64r
 # CHECK-NEXT:       $rdi = frame-destroy POP64r
 # CHECK-NEXT:       $rsi = frame-destroy POP64r
 # CHECK-NEXT:       $r14 = frame-destroy POP64r
 # CHECK-NEXT:       $r15 = frame-destroy POP64r
-# CHECK-NEXT:       SEH_EndEpilogue
+# CHECK-NEXT:       frame-destroy SEH_EndEpilogue
 # CHECK-NEXT:       RET64
 
 --- |
@@ -97,9 +97,9 @@ body:             |
     frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp
     frame-setup SEH_StackAlloc 8
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rax = frame-destroy POP64r implicit-def $rsp, implicit $rsp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
 ---
@@ -112,9 +112,9 @@ body:             |
     renamable $edx = KILL $edx, implicit-def $rdx
     renamable $ecx = KILL $ecx, implicit-def $rcx
     renamable $eax = LEA64_32r killed renamable $rcx, 1, killed renamable $rdx, 0, $noreg
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rcx = frame-destroy POP64r implicit-def $rsp, implicit $rsp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 $eax
 ...
 ---
@@ -189,13 +189,13 @@ body:             |
     MOV64mr renamable $r8, 1, $noreg, 8, $noreg, killed renamable $r9 :: (store (s64) into %ir.out + 8, basealign 16)
     MOV64mr renamable $r8, 1, $noreg, 16, $noreg, killed renamable $rax :: (store (s64) into %ir.out + 16, align 16)
     MOV64mr killed renamable $r8, 1, $noreg, 24, $noreg, killed renamable $rdx :: (store (s64) into %ir.out + 24, basealign 16)
-    SEH_BeginEpilogue
+    frame-destroy SEH_BeginEpilogue
     $rsp = frame-destroy ADD64ri32 $rsp, 8, implicit-def dead $eflags
     $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     $rdi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     $rsi = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     $r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
     $r15 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
-    SEH_EndEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
diff --git a/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-epilogs.mir b/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-epilogs.mir
index 8edc43c83f1951..d3ddb882ebc59b 100644
--- a/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-epilogs.mir
+++ b/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-epilogs.mir
@@ -17,8 +17,10 @@
 # RUN:    -check-prefixes=ALLOWMORE,CHECK
 
 # CHECK-LABEL: too_many_epilogs
-# CHECK: SEH_UnwindVersion 2
-# CHECK: SEH_UnwindV2Start
+# CHECK: frame-setup SEH_UnwindVersion 2
+# CHECK: frame-destroy SEH_BeginEpilogue
+# CHECK-NEXT: frame-destroy SEH_UnwindV2Start
+# CHECK-NEXT: frame-destroy SEH_EndEpilogue
 
 # If we restricted the number of unwind codes, then we expect to use chained
 # infos.
@@ -52,40 +54,40 @@ name:            too_many_epilogs
 body:             |
   bb.0.entry:
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !10
   bb.1:
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !11
   bb.2:
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !11
   bb.3:
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !11
   bb.4:
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !11
   bb.5:
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !11
   bb.6:
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !11
   bb.7:
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !11
   bb.8:
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !11
 
 ...
diff --git a/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-instr.mir b/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-instr.mir
index 44d89356ecae7e..aaae584eb42ce4 100644
--- a/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-instr.mir
+++ b/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-instr.mir
@@ -45,25 +45,25 @@ name:            too_many_instr
 body:             |
   bb.0.entry:
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !10
   bb.1:
     $rcx = MOV64rr $rax
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !11
   bb.2:
     $rcx = MOV64rr $rax
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !12
   bb.3:
     $rcx = MOV64rr $rax
     $rcx = MOV64rr $rax
     $rcx = MOV64rr $rax
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64 debug-location !13
 
 ...
@@ -73,24 +73,32 @@ body:             |
 # bb.1 + bb.2 have enough instructions that bb.0 has its own info.
 # ALLOWLESS:      SEH_SplitChainedAtEndOfBlock
 # ALLOWMORE-NOT:  SEH_SplitChainedAtEndOfBlock
-# CHECK:          SEH_UnwindV2Start
-# CHECK:          RET64 debug-location !10
+# CHECK:          frame-destroy SEH_BeginEpilogue
+# CHECK-NEXT:     frame-destroy SEH_UnwindV2Start
+# CHECK-NEXT:     frame-destroy SEH_EndEpilogue
+# CHECK-NEXT:     RET64 debug-location !10
 
 # CHECK-LABEL:   bb.1
 # bb.2 doesn't fill the current info, so bb.1 gets added as well.
 # CHECK-NOT:      SEH_SplitChainedAtEndOfBlock
-# CHECK:          SEH_UnwindV2Start
-# CHECK:          RET64 debug-location !DILocation(line: 3, column: 1, scope: !6)
+# CHECK:          frame-destroy SEH_BeginEpilogue
+# CHECK-NEXT:     frame-destroy SEH_UnwindV2Start
+# CHECK-NEXT:     frame-destroy SEH_EndEpilogue
+# CHECK-NEXT:     RET64 debug-location !DILocation(line: 3, column: 1, scope: !6)
 
 # CHECK-LABEL:   bb.2
 # bb.3 has enough instructions by itself that bb.2 needs to split.
 # ALLOWLESS-NEXT: SEH_SplitChainedAtEndOfBlock
 # ALLOWMORE-NOT:  SEH_SplitChainedAtEndOfBlock
-# CHECK:          SEH_UnwindV2Start
-# CHECK:          RET64 debug-location !DILocation(line: 4, column: 1, scope: !6)
+# CHECK:          frame-destroy SEH_BeginEpilogue
+# CHECK-NEXT:     frame-destroy SEH_UnwindV2Start
+# CHECK-NEXT:     frame-destroy SEH_EndEpilogue
+# CHECK-NEXT:     RET64 debug-location !DILocation(line: 4, column: 1, scope: !6)
 
 # CHECK-LABEL:   bb.3
 # Never split at the end.
 # CHECK-NOT:      SEH_SplitChainedAtEndOfBlock
-# CHECK:          SEH_UnwindV2Start
-# CHECK:          RET64 debug-location !DILocation(line: 5, column: 1, scope: !6)
+# CHECK:          frame-destroy SEH_BeginEpilogue
+# CHECK-NEXT:     frame-destroy SEH_UnwindV2Start
+# CHECK-NEXT:     frame-destroy SEH_EndEpilogue
+# CHECK-NEXT:     RET64 debug-location !DILocation(line: 5, column: 1, scope: !6)
diff --git a/llvm/test/CodeGen/X86/win64-eh-unwindv3-too-many-epilog-ops.mir b/llvm/test/CodeGen/X86/win64-eh-unwindv3-too-many-epilog-ops.mir
index 99d72faa834a12..0c49f6a49874ba 100644
--- a/llvm/test/CodeGen/X86/win64-eh-unwindv3-too-many-epilog-ops.mir
+++ b/llvm/test/CodeGen/X86/win64-eh-unwindv3-too-many-epilog-ops.mir
@@ -23,39 +23,39 @@ body:             |
   bb.0.entry:
     frame-setup SEH_PushReg 51
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_StackAlloc 8
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_StackAlloc 8
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
diff --git a/llvm/test/CodeGen/X86/win64-eh-unwindv3-too-many-prolog-ops.mir b/llvm/test/CodeGen/X86/win64-eh-unwindv3-too-many-prolog-ops.mir
index fcfd32ab006251..1fa47e443ab9d0 100644
--- a/llvm/test/CodeGen/X86/win64-eh-unwindv3-too-many-prolog-ops.mir
+++ b/llvm/test/CodeGen/X86/win64-eh-unwindv3-too-many-prolog-ops.mir
@@ -53,7 +53,7 @@ body:             |
     frame-setup SEH_StackAlloc 8
     frame-setup SEH_StackAlloc 8
     frame-setup SEH_EndPrologue
-    SEH_BeginEpilogue
-    SEH_EndEpilogue
+    frame-destroy SEH_BeginEpilogue
+    frame-destroy SEH_EndEpilogue
     RET64
 ...
diff --git a/llvm/test/DebugInfo/MIR/X86/instr-ref-join-def-vphi.mir b/llvm/test/DebugInfo/MIR/X86/instr-ref-join-def-vphi.mir
index 431325aea7db0b..16ff022b2c022c 100644
--- a/llvm/test/DebugInfo/MIR/X86/instr-ref-join-def-vphi.mir
+++ b/llvm/test/DebugInfo/MIR/X86/instr-ref-join-def-vphi.mir
@@ -233,11 +233,11 @@ body:             |
     liveins: $esi
 
     $eax = MOV32rr killed $esi, debug-location !35
-    SEH_BeginEpilogue debug-location !35
+    frame-destroy SEH_BeginEpilogue debug-location !35
     $rsp = frame-destroy ADD64ri8 $rsp, 40, implicit-def dead $eflags, debug-location !35
     $rdi = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !35
     $rsi = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !35
-    SEH_EndEpilogue debug-location !35
+    frame-destroy SEH_EndEpilogue debug-location !35
     RET64 $eax, debug-location !35
 
 ...

>From b38a7e43311adca0b0c6824caba79abdfdbc3e94 Mon Sep 17 00:00:00 2001
From: "Pirog, Mikolaj Maciej" <mikolaj.maciej.pirog at intel.com>
Date: Wed, 23 Sep 2026 13:05:19 +0200
Subject: [PATCH 2/2] Mark split chain pseudos as frame destroy as well

---
 llvm/lib/Target/X86/X86WinEHUnwindV2.cpp       |  3 ++-
 llvm/lib/Target/X86/X86WinEHUnwindV3.cpp       |  3 ++-
 .../X86/win64-eh-unwindv2-too-many-epilogs.mir |  2 +-
 .../X86/win64-eh-unwindv2-too-many-instr.mir   |  4 ++--
 .../X86/win64-eh-unwindv3-split-large.ll       | 18 ++++++++++++++++++
 5 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/X86/X86WinEHUnwindV2.cpp b/llvm/lib/Target/X86/X86WinEHUnwindV2.cpp
index cf291634e7d9be..bfab37f4871c6c 100644
--- a/llvm/lib/Target/X86/X86WinEHUnwindV2.cpp
+++ b/llvm/lib/Target/X86/X86WinEHUnwindV2.cpp
@@ -425,7 +425,8 @@ bool runX86WinEHUnwindV2(MachineFunction &MF) {
            InstructionCountThreshold) ||
           (UnwindCodeCount >= UnwindCodeThreshold)) {
         BuildMI(MBB, MBB.begin(), DL,
-                TII->get(X86::SEH_SplitChainedAtEndOfBlock));
+                TII->get(X86::SEH_SplitChainedAtEndOfBlock))
+            .setMIFlag(MachineInstr::FrameDestroy);
         LastUnwindInfoEndPosition = Info.ApproximateInstructionPosition;
         // Doesn't reset to 0, as the prolog unwind codes are now in this info.
         UnwindCodeCount = FI.ApproximatePrologCodeCount + 1;
diff --git a/llvm/lib/Target/X86/X86WinEHUnwindV3.cpp b/llvm/lib/Target/X86/X86WinEHUnwindV3.cpp
index 97529c5c5e7951..11d14696cc2932 100644
--- a/llvm/lib/Target/X86/X86WinEHUnwindV3.cpp
+++ b/llvm/lib/Target/X86/X86WinEHUnwindV3.cpp
@@ -309,7 +309,8 @@ bool X86WinEHUnwindV3::runOnMachineFunction(MachineFunction &MF) {
     auto SplitAfter = [&](const EpilogSplitPoint &Epilog) {
       MachineBasicBlock *MBB = Epilog.BeginEpilog->getParent();
       BuildMI(*MBB, MBB->begin(), Epilog.BeginEpilog->getDebugLoc(),
-              TII->get(X86::SEH_SplitChainedAtEndOfBlock));
+              TII->get(X86::SEH_SplitChainedAtEndOfBlock))
+          .setMIFlag(MachineInstr::FrameDestroy);
       SubFragmentSplits++;
       Changed = true;
     };
diff --git a/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-epilogs.mir b/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-epilogs.mir
index d3ddb882ebc59b..6488f34c0512b5 100644
--- a/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-epilogs.mir
+++ b/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-epilogs.mir
@@ -24,7 +24,7 @@
 
 # If we restricted the number of unwind codes, then we expect to use chained
 # infos.
-# ALLOWLESS:      SEH_SplitChainedAtEndOfBlock
+# ALLOWLESS:      frame-destroy SEH_SplitChainedAtEndOfBlock
 # ALLOWMORE-NOT:  SEH_SplitChainedAtEndOfBlock
 
 --- |
diff --git a/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-instr.mir b/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-instr.mir
index aaae584eb42ce4..ea31e65494ea73 100644
--- a/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-instr.mir
+++ b/llvm/test/CodeGen/X86/win64-eh-unwindv2-too-many-instr.mir
@@ -71,7 +71,7 @@ body:             |
 # CHECK-LABEL: too_many_instr
 # CHECK-LABEL:   bb.0.entry:
 # bb.1 + bb.2 have enough instructions that bb.0 has its own info.
-# ALLOWLESS:      SEH_SplitChainedAtEndOfBlock
+# ALLOWLESS:      frame-destroy SEH_SplitChainedAtEndOfBlock
 # ALLOWMORE-NOT:  SEH_SplitChainedAtEndOfBlock
 # CHECK:          frame-destroy SEH_BeginEpilogue
 # CHECK-NEXT:     frame-destroy SEH_UnwindV2Start
@@ -88,7 +88,7 @@ body:             |
 
 # CHECK-LABEL:   bb.2
 # bb.3 has enough instructions by itself that bb.2 needs to split.
-# ALLOWLESS-NEXT: SEH_SplitChainedAtEndOfBlock
+# ALLOWLESS-NEXT: frame-destroy SEH_SplitChainedAtEndOfBlock
 # ALLOWMORE-NOT:  SEH_SplitChainedAtEndOfBlock
 # CHECK:          frame-destroy SEH_BeginEpilogue
 # CHECK-NEXT:     frame-destroy SEH_UnwindV2Start
diff --git a/llvm/test/CodeGen/X86/win64-eh-unwindv3-split-large.ll b/llvm/test/CodeGen/X86/win64-eh-unwindv3-split-large.ll
index 50b36fb9edc1d2..f75891d4cbdd6f 100644
--- a/llvm/test/CodeGen/X86/win64-eh-unwindv3-split-large.ll
+++ b/llvm/test/CodeGen/X86/win64-eh-unwindv3-split-large.ll
@@ -3,6 +3,9 @@
 ; RUN: llc -mtriple=x86_64-unknown-windows-msvc \
 ; RUN:   -x86-wineh-unwindv3-instr-avg-size=100000 -filetype=obj %s -o - \
 ; RUN:   | llvm-readobj --unwind - | FileCheck %s --check-prefix=OBJ
+; RUN: llc -mtriple=x86_64-unknown-windows-msvc \
+; RUN:   -x86-wineh-unwindv3-instr-avg-size=100000 \
+; RUN:   -stop-after=x86-wineh-unwindv3 -o - %s | FileCheck %s --check-prefix=MIR
 
 ; Test V3 *size-based* sub-fragment splitting (the "Unwind v2 style" heuristic).
 ; With a very small distance threshold, every epilog is forced into its own
@@ -28,6 +31,21 @@ declare i32 @c(i32)
 ; CHECK:         .seh_endepilogue
 ; CHECK:         .seh_endproc
 
+; MIR-LABEL: name:            three_epilogs
+; MIR:         frame-setup SEH_EndPrologue
+; MIR:         frame-destroy SEH_SplitChainedAtEndOfBlock
+; MIR:         frame-destroy SEH_BeginEpilogue
+; MIR-NEXT:    frame-destroy SEH_StackAlloc 40
+; MIR:         frame-destroy SEH_EndEpilogue
+; MIR:         frame-destroy SEH_SplitChainedAtEndOfBlock
+; MIR:         frame-destroy SEH_BeginEpilogue
+; MIR-NEXT:    frame-destroy SEH_StackAlloc 40
+; MIR:         frame-destroy SEH_EndEpilogue
+; MIR:         frame-destroy SEH_SplitChainedAtEndOfBlock
+; MIR:         frame-destroy SEH_BeginEpilogue
+; MIR-NEXT:    frame-destroy SEH_StackAlloc 40
+; MIR:         frame-destroy SEH_EndEpilogue
+
 ; Each epilog ends up in its own fragment with a small, in-range, tail-relative
 ; (negative) EpilogOffset. The main fragment holds the prolog; each subsequent
 ; fragment is an epilog-only chained fragment, and the trailing code after the



More information about the llvm-commits mailing list