[llvm] ba1c26c - [X86] Fix missing CFI after the Swift async context push (#202570)

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 3 01:44:50 PDT 2026


Author: Akshat Dalal
Date: 2026-08-03T14:14:45+05:30
New Revision: ba1c26cf9f4826c9e82d43859c91fab9facf689f

URL: https://github.com/llvm/llvm-project/commit/ba1c26cf9f4826c9e82d43859c91fab9facf689f
DIFF: https://github.com/llvm/llvm-project/commit/ba1c26cf9f4826c9e82d43859c91fab9facf689f.diff

LOG: [X86] Fix missing CFI after the Swift async context push (#202570)

The Swift async prologue pushes the context slot (pushq %r14 / $0) but
doesn't touch the CFA until the later .cfi_def_cfa_register %rbp. So the
CFA still describes the stack from before the push and stays stale all
the way through the leaq and the subq. If something unwinds in that
window (debugger, profiler, signal) it reads the wrong slot. Normal
execution is fine.

FIX: account for the push with .cfi_adjust_cfa_offset 8, then switch to
an %rbp-relative CFA (.cfi_def_cfa %rbp, 16) right after the leaq and
before the subq, so the rule is correct before rsp moves again.

Adds swift-async-cfi-prologue.ll (directives + .eh_frame rows, plus a
locals case for the subq) and updates swift-async.ll.

Added: 
    llvm/test/CodeGen/X86/swift-async-cfi-prologue.ll

Modified: 
    llvm/lib/Target/X86/X86FrameLowering.cpp
    llvm/test/CodeGen/X86/swift-async.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index dbe0beb83ac4f..7251bdda1dd05 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -1918,6 +1918,15 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
               .addImm(0)
               .setMIFlag(MachineInstr::FrameSetup);
         }
+
+        // Update CFA offset for the async-context push.
+        if (NeedsDwarfCFI && !ArgBaseReg.isValid()) {
+          BuildCFI(
+              MBB, MBBI, DL,
+              MCCFIInstruction::createAdjustCfaOffset(nullptr, -stackGrowth),
+              MachineInstr::FrameSetup);
+        }
+
         EmitSEHAfter(EmitSEHPushR14);
 
         BuildMI(MBB, MBBI, DL, TII.get(X86::LEA64r), FramePtr)
@@ -1927,6 +1936,17 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
             .addImm(8)
             .addUse(X86::NoRegister)
             .setMIFlag(MachineInstr::FrameSetup);
+
+        // Switch to an FP-relative CFA before adjusting RSP below.
+        if (NeedsDwarfCFI && !ArgBaseReg.isValid()) {
+          unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true);
+          BuildCFI(MBB, MBBI, DL,
+                   MCCFIInstruction::cfiDefCfa(nullptr, DwarfFramePtr,
+                                               -2 * stackGrowth +
+                                                   (int)TailCallArgReserveSize),
+                   MachineInstr::FrameSetup);
+        }
+
         BuildMI(MBB, MBBI, DL, TII.get(X86::SUB64ri32), X86::RSP)
             .addUse(X86::RSP)
             .addImm(8)
@@ -1956,7 +1976,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
             BuildCFI(MBB, MBBI, DL,
                      MCCFIInstruction::createEscape(nullptr, CfaExpr.str()),
                      MachineInstr::FrameSetup);
-          } else {
+          } else if (!X86FI->hasSwiftAsyncContext()) {
             // Mark effective beginning of when frame pointer becomes valid.
             // Define the current CFA to use the EBP/RBP register.
             unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true);

diff  --git a/llvm/test/CodeGen/X86/swift-async-cfi-prologue.ll b/llvm/test/CodeGen/X86/swift-async-cfi-prologue.ll
new file mode 100644
index 0000000000000..f572595ad2118
--- /dev/null
+++ b/llvm/test/CodeGen/X86/swift-async-cfi-prologue.ll
@@ -0,0 +1,41 @@
+; RUN: llc -mtriple=x86_64-apple-macosx -O0 %s -o - | FileCheck %s --check-prefix=ASM
+; RUN: llc -mtriple=x86_64-apple-macosx -O0 -filetype=obj %s -o - | \
+; RUN:   llvm-dwarfdump --eh-frame - | FileCheck %s --check-prefix=UNWIND
+
+; Verify Swift async prologue CFA updates after the context push.
+
+; ASM-LABEL: foo:
+; ASM:        pushq   %rbp
+; ASM-NEXT:   .cfi_def_cfa_offset 16
+; ASM-NEXT:   .cfi_offset %rbp, -16
+; ASM-NEXT:   pushq   %r14
+; ASM-NEXT:   .cfi_adjust_cfa_offset 8
+; ASM-NEXT:   leaq    8(%rsp), %rbp
+; ASM-NEXT:   .cfi_def_cfa %rbp, 16
+; ASM-NOT:    .cfi_def_cfa_register
+
+; UNWIND:      0x0: CFA=RSP+8:
+; UNWIND-NEXT: 0x6: CFA=RSP+16:
+; UNWIND-NEXT: 0x8: CFA=RSP+24:
+; UNWIND-NEXT: 0xd: CFA=RBP+16:
+
+define void @foo(ptr swiftasync %ctx) "frame-pointer"="all" {
+  call void asm sideeffect "int3", ""()
+  ret void
+}
+
+; A frame with locals emits a real stack adjustment after the FP is set up.
+; The CFA must already be %rbp-relative before that subq, so no CFI directive
+; appears between the .cfi_def_cfa and the subq.
+; ASM-LABEL: with_locals:
+; ASM:        pushq   %r14
+; ASM-NEXT:   .cfi_adjust_cfa_offset 8
+; ASM-NEXT:   leaq    8(%rsp), %rbp
+; ASM-NEXT:   .cfi_def_cfa %rbp, 16
+; ASM-NEXT:   subq    ${{[0-9]+}}, %rsp
+
+define void @with_locals(ptr swiftasync %ctx) "frame-pointer"="all" {
+  %a = alloca [128 x i8]
+  call void asm sideeffect "int3", "r"(ptr %a)
+  ret void
+}

diff  --git a/llvm/test/CodeGen/X86/swift-async.ll b/llvm/test/CodeGen/X86/swift-async.ll
index 0017d2af85878..c31cceeb88f17 100644
--- a/llvm/test/CodeGen/X86/swift-async.ll
+++ b/llvm/test/CodeGen/X86/swift-async.ll
@@ -27,9 +27,12 @@ define void @more_csrs(ptr swiftasync %ctx) "frame-pointer"="all" {
 ; CHECK-LABEL: more_csrs:
 ; CHECK: btsq    $60, %rbp
 ; CHECK: pushq   %rbp
+; CHECK: .cfi_def_cfa_offset 16
 ; CHECK: .cfi_offset %rbp, -16
 ; CHECK: pushq   %r14
+; CHECK: .cfi_adjust_cfa_offset 8
 ; CHECK: leaq    8(%rsp), %rbp
+; CHECK: .cfi_def_cfa %rbp, 16
 ; CHECK: subq    $8, %rsp
 ; CHECK: pushq   %r15
 ; CHECK: .cfi_offset %r15, -40
@@ -52,8 +55,9 @@ define void @locals(ptr swiftasync %ctx) "frame-pointer"="all" {
 ; CHECK: .cfi_def_cfa_offset 16
 ; CHECK: .cfi_offset %rbp, -16
 ; CHECK: pushq   %r14
+; CHECK: .cfi_adjust_cfa_offset 8
 ; CHECK: leaq    8(%rsp), %rbp
-; CHECK: .cfi_def_cfa_register %rbp
+; CHECK: .cfi_def_cfa %rbp, 16
 ; CHECK: subq    $56, %rsp
 
 ; CHECK: leaq    -48(%rbp), %rdi
@@ -80,6 +84,13 @@ define void @use_input_context(ptr swiftasync %ctx, ptr %ptr) "frame-pointer"="a
 
 define ptr @context_in_func() "frame-pointer"="non-leaf" {
 ; CHECK-LABEL: context_in_func:
+; CHECK: pushq   %rbp
+; CHECK: .cfi_def_cfa_offset 16
+; CHECK: .cfi_offset %rbp, -16
+; CHECK: pushq   $0
+; CHECK: .cfi_adjust_cfa_offset 8
+; CHECK: leaq    8(%rsp), %rbp
+; CHECK: .cfi_def_cfa %rbp, 16
 ; CHECK: leaq    -8(%rbp), %rax
 
 ; CHECK-32-LABEL: context_in_func


        


More information about the llvm-commits mailing list