[clang] [llvm] Delegate __builtin_setjmp FP save to backend on windows CFI targets (PR #186843)
Pyry Kovanen via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 16 11:53:11 PDT 2026
https://github.com/pkova updated https://github.com/llvm/llvm-project/pull/186843
>From c05ddfc5dfccb732f0bcf36cca15d9d87878068e Mon Sep 17 00:00:00 2001
From: pkova <pyry at urbit.org>
Date: Mon, 16 Mar 2026 18:42:17 +0200
Subject: [PATCH] Delegate __builtin_setjmp FP save to backend on windows CFI
targets
---
clang/lib/CodeGen/CGBuiltin.cpp | 22 ++++++++++++++++------
llvm/lib/Target/X86/X86ISelLowering.cpp | 21 ++++++++++++++++++++-
2 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index df03e84ce9f81..0af1c957d86bb 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4927,12 +4927,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this)));
}
- // Store the frame pointer to the setjmp buffer.
- Value *FrameAddr = Builder.CreateCall(
- CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy),
- ConstantInt::get(Int32Ty, 0));
- Builder.CreateStore(FrameAddr, Buf);
-
// Store the stack pointer to the setjmp buffer.
Value *StackAddr = Builder.CreateStackSave();
assert(Buf.emitRawPointer(*this)->getType() == StackAddr->getType());
@@ -4940,6 +4934,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Address StackSaveSlot = Builder.CreateConstInBoundsGEP(Buf, 2);
Builder.CreateStore(StackAddr, StackSaveSlot);
+ if (getTarget().getTriple().getArch() == llvm::Triple::x86_64 &&
+ (getTarget().getTriple().isOSWindows() ||
+ getTarget().getTriple().isUEFI())) {
+ // On WindowsCFI targets, @llvm.frameaddress returns an SEH-adjusted
+ // address rather than the raw register value that __builtin_longjmp
+ // needs. We delegate the store to the llvm backend in these cases.
+ Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp);
+ return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this)));
+ }
+
+ // Store the frame pointer to the setjmp buffer.
+ Value *FrameAddr = Builder.CreateCall(
+ CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy),
+ ConstantInt::get(Int32Ty, 0));
+ Builder.CreateStore(FrameAddr, Buf);
+
// Call LLVM's EH setjmp, which is lightweight.
Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp);
return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this)));
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 1e9d7aecd41a2..b96fddc9c9e4c 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -37557,6 +37557,26 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
MIB.addMBB(restoreMBB);
MIB.setMemRefs(MMOs);
+ const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
+
+ // On WindowsCFI targets, @llvm.frameaddress returns an SEH-adjusted address
+ // rather than the raw register value that __builtin_longjmp needs. The
+ // frontend skips the @llvm.frameaddress store on these targets, so we store
+ // the raw FP register value here.
+ if (MF->getTarget().getMCAsmInfo()->usesWindowsCFI()) {
+ unsigned RegStoreOpc = (PVT == MVT::i64) ? X86::MOV64mr : X86::MOV32mr;
+
+ bool HasFP = Subtarget.getFrameLowering()->hasFP(*MF);
+ if (HasFP) {
+ // Store FP to jmp_buf[0].
+ MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(RegStoreOpc));
+ for (unsigned i = 0; i < X86::AddrNumOperands; ++i)
+ MIB.add(MI.getOperand(MemOpndSlot + i));
+ MIB.addReg(RegInfo->getFrameRegister(*MF));
+ MIB.setMemRefs(MMOs);
+ }
+ }
+
if (MF->getFunction().getParent()->getModuleFlag("cf-protection-return")) {
emitSetJmpShadowStackFix(MI, thisMBB);
}
@@ -37565,7 +37585,6 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(X86::EH_SjLj_Setup))
.addMBB(restoreMBB);
- const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
MIB.addRegMask(RegInfo->getNoPreservedMask());
thisMBB->addSuccessor(mainMBB);
thisMBB->addSuccessor(restoreMBB);
More information about the cfe-commits
mailing list