[clang] [llvm] Delegate __builtin_setjmp FP save to backend on windows CFI targets (PR #186843)
Pyry Kovanen via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 30 07:42:20 PDT 2026
https://github.com/pkova updated https://github.com/llvm/llvm-project/pull/186843
>From e3ca0fbfb3dc2c2327aa974f6024a94c6f2fdc67 Mon Sep 17 00:00:00 2001
From: pkova <pyry at urbit.org>
Date: Thu, 19 Mar 2026 18:06:29 +0200
Subject: [PATCH 1/6] Add @llvm.setjmp intrinsic to store FP, IP and SP on the
backend
---
clang/lib/CodeGen/CGBuiltin.cpp | 26 +--
.../CodeGen/SystemZ/builtin-setjmp-logjmp.c | 2 +-
clang/test/Sema/builtin-longjmp.c | 2 +-
llvm/include/llvm/CodeGen/ISDOpcodes.h | 6 +
llvm/include/llvm/IR/Intrinsics.td | 2 +
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 2 +
.../SelectionDAG/SelectionDAGBuilder.cpp | 10 +
.../SelectionDAG/SelectionDAGDumper.cpp | 1 +
llvm/lib/Target/ARM/ARMISelLowering.cpp | 33 +++-
llvm/lib/Target/ARM/ARMISelLowering.h | 1 +
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 160 +++++++++++++++-
llvm/lib/Target/PowerPC/PPCISelLowering.h | 3 +
llvm/lib/Target/PowerPC/PPCInstr64Bit.td | 7 +-
llvm/lib/Target/PowerPC/PPCInstrInfo.td | 11 +-
.../Target/SystemZ/SystemZISelLowering.cpp | 12 ++
llvm/lib/Target/SystemZ/SystemZISelLowering.h | 1 +
llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 4 +-
llvm/lib/Target/SystemZ/SystemZOperators.td | 2 +
llvm/lib/Target/VE/VEISelLowering.cpp | 144 ++++++++++++++
llvm/lib/Target/VE/VEISelLowering.h | 2 +
llvm/lib/Target/VE/VEInstrInfo.td | 7 +
llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 9 +-
llvm/lib/Target/X86/X86ISelLowering.cpp | 177 +++++++++++++++++-
llvm/lib/Target/X86/X86ISelLowering.h | 3 +
llvm/lib/Target/X86/X86InstrCompiler.td | 8 +
llvm/lib/Target/X86/X86InstrFragments.td | 4 +
llvm/test/CodeGen/ARM/setjmp.ll | 47 +++++
llvm/test/CodeGen/PowerPC/setjmp.ll | 39 ++++
llvm/test/CodeGen/SystemZ/setjmp.ll | 35 ++++
llvm/test/CodeGen/VE/Scalar/setjmp.ll | 39 ++++
llvm/test/CodeGen/X86/setjmp.ll | 55 ++++++
31 files changed, 818 insertions(+), 36 deletions(-)
create mode 100644 llvm/test/CodeGen/ARM/setjmp.ll
create mode 100644 llvm/test/CodeGen/PowerPC/setjmp.ll
create mode 100644 llvm/test/CodeGen/SystemZ/setjmp.ll
create mode 100644 llvm/test/CodeGen/VE/Scalar/setjmp.ll
create mode 100644 llvm/test/CodeGen/X86/setjmp.ll
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index df03e84ce9f81..34aedc111ee4c 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4916,32 +4916,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Builder.CreateZExt(Result, Int64Ty, "extend.zext"));
}
case Builtin::BI__builtin_setjmp: {
- // Buffer is a void**.
Address Buf = EmitPointerWithAlignment(E->getArg(0));
- if (getTarget().getTriple().getArch() == llvm::Triple::systemz) {
- // On this target, the back end fills in the context buffer completely.
- // It doesn't really matter if the frontend stores to the buffer before
- // calling setjmp, the back-end is going to overwrite them anyway.
- 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);
-
- // Store the stack pointer to the setjmp buffer.
- Value *StackAddr = Builder.CreateStackSave();
- assert(Buf.emitRawPointer(*this)->getType() == StackAddr->getType());
-
- Address StackSaveSlot = Builder.CreateConstInBoundsGEP(Buf, 2);
- Builder.CreateStore(StackAddr, StackSaveSlot);
-
- // Call LLVM's EH setjmp, which is lightweight.
- Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp);
+ // The backend handles all buffer stores (FP, SP, IP) via @llvm.setjmp.
+ Function *F = CGM.getIntrinsic(Intrinsic::setjmp);
return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this)));
}
case Builtin::BI__builtin_longjmp: {
diff --git a/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c b/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
index 898891fa182ea..d2522c6bab7df 100644
--- a/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
+++ b/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
@@ -6,7 +6,7 @@ void *buf[20];
// CHECK-LABEL: define dso_local void @foo(
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
+// CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.setjmp(ptr @buf)
// CHECK-NEXT: ret void
//
void foo()
diff --git a/clang/test/Sema/builtin-longjmp.c b/clang/test/Sema/builtin-longjmp.c
index 99463cf3385a1..b320ec0b6a2d2 100644
--- a/clang/test/Sema/builtin-longjmp.c
+++ b/clang/test/Sema/builtin-longjmp.c
@@ -21,7 +21,7 @@ jmp_buf buf;
// CHECK: call{{.*}} void @llvm.eh.sjlj.longjmp
// CHECK: define{{.*}} void @do_setjmp()
-// CHECK: call{{.*}} i32 @llvm.eh.sjlj.setjmp
+// CHECK: call{{.*}} i32 @llvm.setjmp
void do_jump(void) {
__builtin_longjmp(buf, 1); // expected-error {{__builtin_longjmp is not supported for the current target}}
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index fa578f733d4e8..2a49f30210b2c 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -161,6 +161,12 @@ enum NodeType {
/// and returns an outchain.
EH_SJLJ_SETJMP,
+ /// RESULT, OUTCHAIN = SETJMP(INCHAIN, buffer)
+ /// This corresponds to the setjmp intrinsic. Like EH_SJLJ_SETJMP but the
+ /// backend is responsible for storing all of FP, SP, and IP into the buffer
+ /// (the frontend does not emit any buffer stores).
+ SETJMP,
+
/// OUTCHAIN = EH_SJLJ_LONGJMP(INCHAIN, buffer)
/// This corresponds to the eh.sjlj.longjmp intrinsic.
/// It takes an input chain and a pointer to the jump buffer as inputs
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 4469ff155b854..5b309751fc517 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1571,6 +1571,8 @@ def int_eh_sjlj_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>;
def int_eh_sjlj_longjmp : Intrinsic<[], [llvm_ptr_ty], [IntrNoReturn]>;
def int_eh_sjlj_setup_dispatch : Intrinsic<[], []>;
+def int_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>;
+
//===---------------- Generic Variable Attribute Intrinsics----------------===//
//
def int_var_annotation : DefaultAttrsIntrinsic<
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 5e54343f7f146..7b35825ba995c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -1116,6 +1116,7 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
case ISD::FRAME_TO_ARGS_OFFSET:
case ISD::EH_DWARF_CFA:
case ISD::EH_SJLJ_SETJMP:
+ case ISD::SETJMP:
case ISD::EH_SJLJ_LONGJMP:
case ISD::EH_SJLJ_SETUP_DISPATCH:
// These operations lie about being legal: when they claim to be legal,
@@ -3311,6 +3312,7 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
Results.push_back(Node->getOperand(0));
break;
case ISD::EH_SJLJ_SETJMP:
+ case ISD::SETJMP:
// If the target didn't expand this, just return 'zero' and preserve the
// chain.
Results.push_back(DAG.getConstant(0, dl, MVT::i32));
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index eb55a68eaba84..4c72ecb8bd6c4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -6863,6 +6863,16 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
MFI.setFunctionContextIndex(FI);
return;
}
+ case Intrinsic::setjmp: {
+ SDValue Ops[2];
+ Ops[0] = getRoot();
+ Ops[1] = getValue(I.getArgOperand(0));
+ SDValue Op =
+ DAG.getNode(ISD::SETJMP, sdl, DAG.getVTList(MVT::i32, MVT::Other), Ops);
+ setValue(&I, Op.getValue(0));
+ DAG.setRoot(Op.getValue(1));
+ return;
+ }
case Intrinsic::eh_sjlj_setjmp: {
SDValue Ops[2];
Ops[0] = getRoot();
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 7161dd299f830..890545c756351 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -160,6 +160,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::EH_DWARF_CFA: return "EH_DWARF_CFA";
case ISD::EH_RETURN: return "EH_RETURN";
case ISD::EH_SJLJ_SETJMP: return "EH_SJLJ_SETJMP";
+ case ISD::SETJMP: return "SETJMP";
case ISD::EH_SJLJ_LONGJMP: return "EH_SJLJ_LONGJMP";
case ISD::EH_SJLJ_SETUP_DISPATCH: return "EH_SJLJ_SETUP_DISPATCH";
case ISD::ConstantPool: return "ConstantPool";
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 970c962197ac0..7b81a4825d4fe 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1195,6 +1195,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM_,
// We want to custom lower some of our intrinsics.
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
+ setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom);
@@ -3776,6 +3777,33 @@ ARMTargetLowering::LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const {
Op.getOperand(1), Val);
}
+SDValue ARMTargetLowering::LowerSETJMP(SDValue Op, SelectionDAG &DAG) const {
+ SDLoc dl(Op);
+ SDValue Chain = Op.getOperand(0);
+ SDValue Buf = Op.getOperand(1);
+
+ MachineFunction &MF = DAG.getMachineFunction();
+ EVT PtrVT = getPointerTy(DAG.getDataLayout());
+
+ // Store FP into buf[0].
+ const ARMBaseRegisterInfo &ARI =
+ *static_cast<const ARMBaseRegisterInfo *>(Subtarget->getRegisterInfo());
+ Register FrameReg = ARI.getFrameRegister(MF);
+ SDValue FP = DAG.getCopyFromReg(Chain, dl, FrameReg, PtrVT);
+ Chain = DAG.getStore(FP.getValue(1), dl, FP, Buf, MachinePointerInfo());
+
+ // Store SP into buf[2] (offset 8).
+ SDValue SP = DAG.getCopyFromReg(Chain, dl, ARM::SP, PtrVT);
+ SDValue SPAddr =
+ DAG.getNode(ISD::ADD, dl, PtrVT, Buf, DAG.getConstant(8, dl, PtrVT));
+ Chain = DAG.getStore(SP.getValue(1), dl, SP, SPAddr, MachinePointerInfo());
+
+ // Delegate to EH_SJLJ_SETJMP for IP store + return value.
+ SDValue Val = DAG.getConstant(0, dl, MVT::i32);
+ return DAG.getNode(ARMISD::EH_SJLJ_SETJMP, dl,
+ DAG.getVTList(MVT::i32, MVT::Other), Chain, Buf, Val);
+}
+
SDValue
ARMTargetLowering::LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const {
SDLoc dl(Op);
@@ -10434,7 +10462,10 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG);
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
- case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG);
+ case ISD::EH_SJLJ_SETJMP:
+ return LowerEH_SJLJ_SETJMP(Op, DAG);
+ case ISD::SETJMP:
+ return LowerSETJMP(Op, DAG);
case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::EH_SJLJ_SETUP_DISPATCH: return LowerEH_SJLJ_SETUP_DISPATCH(Op, DAG);
case ISD::INTRINSIC_VOID: return LowerINTRINSIC_VOID(Op, DAG, Subtarget);
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index e58d872c548e4..c4710adf6a6eb 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -546,6 +546,7 @@ class VectorType;
SDValue Dst,
ISD::ArgFlagsTy Flags) const;
SDValue LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerSETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_SJLJ_SETUP_DISPATCH(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG,
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 1515ff2e13b85..c2f09544209be 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -601,6 +601,7 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
// your own exception handling based on them.
// LLVM/Clang supports zero-cost DWARF exception handling.
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
+ setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
// We want to legalize GlobalAddress and ConstantPool nodes into the
@@ -7985,6 +7986,12 @@ SDValue PPCTargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
Op.getOperand(0), Op.getOperand(1));
}
+SDValue PPCTargetLowering::lowerSETJMP(SDValue Op, SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ return DAG.getNode(PPCISD::SETJMP, DL, DAG.getVTList(MVT::i32, MVT::Other),
+ Op.getOperand(0), Op.getOperand(1));
+}
+
SDValue PPCTargetLowering::lowerEH_SJLJ_LONGJMP(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
@@ -12744,7 +12751,10 @@ SDValue PPCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
// Exception handling lowering.
case ISD::EH_DWARF_CFA: return LowerEH_DWARF_CFA(Op, DAG);
- case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG);
+ case ISD::EH_SJLJ_SETJMP:
+ return lowerEH_SJLJ_SETJMP(Op, DAG);
+ case ISD::SETJMP:
+ return lowerSETJMP(Op, DAG);
case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::LOAD: return LowerLOAD(Op, DAG);
@@ -13577,6 +13587,151 @@ PPCTargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
return sinkMBB;
}
+MachineBasicBlock *PPCTargetLowering::emitSetJmp(MachineInstr &MI,
+ MachineBasicBlock *MBB) const {
+ DebugLoc DL = MI.getDebugLoc();
+ const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+ const PPCRegisterInfo *TRI = Subtarget.getRegisterInfo();
+
+ MachineFunction *MF = MBB->getParent();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+
+ const BasicBlock *BB = MBB->getBasicBlock();
+ MachineFunction::iterator I = ++MBB->getIterator();
+
+ Register DstReg = MI.getOperand(0).getReg();
+ const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
+ assert(TRI->isTypeLegalForClass(*RC, MVT::i32) && "Invalid destination!");
+ Register mainDstReg = MRI.createVirtualRegister(RC);
+ Register restoreDstReg = MRI.createVirtualRegister(RC);
+
+ MVT PVT = getPointerTy(MF->getDataLayout());
+ assert((PVT == MVT::i64 || PVT == MVT::i32) && "Invalid Pointer Size!");
+
+ MachineBasicBlock *thisMBB = MBB;
+ MachineBasicBlock *mainMBB = MF->CreateMachineBasicBlock(BB);
+ MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(BB);
+ MF->insert(I, mainMBB);
+ MF->insert(I, sinkMBB);
+
+ MachineInstrBuilder MIB;
+
+ // Transfer the remainder of BB and its successor edges to sinkMBB.
+ sinkMBB->splice(sinkMBB->begin(), MBB,
+ std::next(MachineBasicBlock::iterator(MI)), MBB->end());
+ sinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
+
+ // Buffer layout:
+ // buf[0] = Frame Pointer
+ // buf[1] = IP (return address / LR)
+ // buf[2] = Stack Pointer
+ // buf[3] = TOC pointer (R2, 64-bit ELF only)
+ // buf[4] = Base Pointer
+ const int64_t FPOffset = 0;
+ const int64_t LabelOffset = 1 * PVT.getStoreSize();
+ const int64_t SPOffset = 2 * PVT.getStoreSize();
+ const int64_t TOCOffset = 3 * PVT.getStoreSize();
+ const int64_t BPOffset = 4 * PVT.getStoreSize();
+
+ const TargetRegisterClass *PtrRC = getRegClassFor(PVT);
+ Register LabelReg = MRI.createVirtualRegister(PtrRC);
+ Register BufReg = MI.getOperand(1).getReg();
+
+ unsigned SP = (PVT == MVT::i64) ? PPC::X1 : PPC::R1;
+
+ // Store FP to buf[0] if we have a frame pointer.
+ // Note: hasFP() is unreliable here because it depends on getStackSize()
+ // which isn't known yet during ISel. Use needsFP() instead.
+ auto *TFI =
+ static_cast<const PPCFrameLowering *>(Subtarget.getFrameLowering());
+ if (TFI->needsFP(*MF)) {
+ unsigned FP = (PVT == MVT::i64) ? PPC::X31 : PPC::R31;
+ MIB = BuildMI(*thisMBB, MI, DL,
+ TII->get(Subtarget.isPPC64() ? PPC::STD : PPC::STW))
+ .addReg(FP)
+ .addImm(FPOffset)
+ .addReg(BufReg)
+ .cloneMemRefs(MI);
+ }
+
+ // Store SP to buf[2].
+ MIB = BuildMI(*thisMBB, MI, DL,
+ TII->get(Subtarget.isPPC64() ? PPC::STD : PPC::STW))
+ .addReg(SP)
+ .addImm(SPOffset)
+ .addReg(BufReg)
+ .cloneMemRefs(MI);
+
+ // Store TOC (R2) for 64-bit ELF.
+ if (Subtarget.is64BitELFABI()) {
+ setUsesTOCBasePtr(*MBB->getParent());
+ MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::STD))
+ .addReg(PPC::X2)
+ .addImm(TOCOffset)
+ .addReg(BufReg)
+ .cloneMemRefs(MI);
+ }
+
+ // Store BP.
+ unsigned BaseReg;
+ if (MF->getFunction().hasFnAttribute(Attribute::Naked))
+ BaseReg = Subtarget.isPPC64() ? PPC::X1 : PPC::R1;
+ else
+ BaseReg = Subtarget.isPPC64() ? PPC::BP8 : PPC::BP;
+
+ MIB = BuildMI(*thisMBB, MI, DL,
+ TII->get(Subtarget.isPPC64() ? PPC::STD : PPC::STW))
+ .addReg(BaseReg)
+ .addImm(BPOffset)
+ .addReg(BufReg)
+ .cloneMemRefs(MI);
+
+ // Setup
+ MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::BCLalways)).addMBB(mainMBB);
+ MIB.addRegMask(TRI->getNoPreservedMask());
+
+ BuildMI(*thisMBB, MI, DL, TII->get(PPC::LI), restoreDstReg).addImm(1);
+
+ MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::EH_SjLj_Setup)).addMBB(mainMBB);
+ MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::B)).addMBB(sinkMBB);
+
+ thisMBB->addSuccessor(mainMBB, BranchProbability::getZero());
+ thisMBB->addSuccessor(sinkMBB, BranchProbability::getOne());
+
+ // mainMBB:
+ // mainDstReg = 0
+ MIB =
+ BuildMI(mainMBB, DL,
+ TII->get(Subtarget.isPPC64() ? PPC::MFLR8 : PPC::MFLR), LabelReg);
+
+ // Store IP
+ if (Subtarget.isPPC64()) {
+ MIB = BuildMI(mainMBB, DL, TII->get(PPC::STD))
+ .addReg(LabelReg)
+ .addImm(LabelOffset)
+ .addReg(BufReg);
+ } else {
+ MIB = BuildMI(mainMBB, DL, TII->get(PPC::STW))
+ .addReg(LabelReg)
+ .addImm(LabelOffset)
+ .addReg(BufReg);
+ }
+ MIB.cloneMemRefs(MI);
+
+ BuildMI(mainMBB, DL, TII->get(PPC::LI), mainDstReg).addImm(0);
+ mainMBB->addSuccessor(sinkMBB);
+
+ // sinkMBB:
+ BuildMI(*sinkMBB, sinkMBB->begin(), DL, TII->get(PPC::PHI), DstReg)
+ .addReg(mainDstReg)
+ .addMBB(mainMBB)
+ .addReg(restoreDstReg)
+ .addMBB(thisMBB);
+
+ MI.eraseFromParent();
+ return sinkMBB;
+}
+
MachineBasicBlock *
PPCTargetLowering::emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const {
@@ -13930,6 +14085,9 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
if (MI.getOpcode() == PPC::EH_SjLj_SetJmp32 ||
MI.getOpcode() == PPC::EH_SjLj_SetJmp64) {
return emitEHSjLjSetJmp(MI, BB);
+ } else if (MI.getOpcode() == PPC::SetJmp32 ||
+ MI.getOpcode() == PPC::SetJmp64) {
+ return emitSetJmp(MI, BB);
} else if (MI.getOpcode() == PPC::EH_SjLj_LongJmp32 ||
MI.getOpcode() == PPC::EH_SjLj_LongJmp64) {
return emitEHSjLjLongJmp(MI, BB);
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index cfcc6b5f03edc..b084bed075b73 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -386,6 +386,8 @@ namespace llvm {
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
+ MachineBasicBlock *emitSetJmp(MachineInstr &MI,
+ MachineBasicBlock *MBB) const;
MachineBasicBlock *emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
@@ -858,6 +860,7 @@ namespace llvm {
const CallBase *CB) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
+ SDValue lowerSETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBITCAST(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td
index 2b62654b08986..c4540c132c153 100644
--- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td
+++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td
@@ -506,11 +506,16 @@ def MFCR8 : XFXForm_3<31, 19, (outs g8rc:$RT), (ins),
// While longjmp is a control-flow barrier (fallthrough isn't allowed), setjmp
// is not.
let hasSideEffects = 1 in {
- let Defs = [CTR8] in
+ let Defs = [CTR8] in {
def EH_SjLj_SetJmp64 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins memr:$buf),
"#EH_SJLJ_SETJMP64",
[(set i32:$dst, (PPCeh_sjlj_setjmp addr:$buf))]>,
Requires<[IsPPC64]>;
+ def SetJmp64 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins memr:$buf),
+ "#SETJMP64",
+ [(set i32:$dst, (PPCsetjmp addr:$buf))]>,
+ Requires<[IsPPC64]>;
+ }
}
let hasSideEffects = 1, isBarrier = 1 in {
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
index 3271e4d279f56..ba07e318f6e8e 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
@@ -590,6 +590,10 @@ def PPCeh_sjlj_setjmp : SDNode<"PPCISD::EH_SJLJ_SETJMP",
SDTypeProfile<1, 1, [SDTCisInt<0>,
SDTCisPtrTy<1>]>,
[SDNPHasChain, SDNPSideEffect]>;
+def PPCsetjmp : SDNode<"PPCISD::SETJMP",
+ SDTypeProfile<1, 1, [SDTCisInt<0>,
+ SDTCisPtrTy<1>]>,
+ [SDNPHasChain, SDNPSideEffect]>;
// EH_SJLJ_LONGJMP - SjLj exception handling longjmp.
def PPCeh_sjlj_longjmp : SDNode<"PPCISD::EH_SJLJ_LONGJMP",
@@ -1895,11 +1899,16 @@ def TAILBA : IForm<18, 0, 0, (outs), (ins abscalltarget:$LI),
// While longjmp is a control-flow barrier (fallthrough isn't allowed), setjmp
// is not.
let hasSideEffects = 1 in {
- let Defs = [CTR] in
+ let Defs = [CTR] in {
def EH_SjLj_SetJmp32 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins memr:$buf),
"#EH_SJLJ_SETJMP32",
[(set i32:$dst, (PPCeh_sjlj_setjmp addr:$buf))]>,
Requires<[IsPPC32]>;
+ def SetJmp32 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins memr:$buf),
+ "#SETJMP32",
+ [(set i32:$dst, (PPCsetjmp addr:$buf))]>,
+ Requires<[IsPPC32]>;
+ }
}
let hasSideEffects = 1, isBarrier = 1 in {
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 84d66f88a812d..0a799d53c0619 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -808,6 +808,7 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
// We're not using SJLJ for exception handling, but they're implemented
// solely to support use of __builtin_setjmp / __builtin_longjmp.
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
+ setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
// We want to use MVC in preference to even a single load/store pair.
@@ -1181,6 +1182,14 @@ SystemZTargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
return SinkMBB;
}
+MachineBasicBlock *
+SystemZTargetLowering::emitSetJmp(MachineInstr &MI,
+ MachineBasicBlock *MBB) const {
+ // emitSetJmp is identical to emitEHSjLjSetJmp because the SystemZ
+ // implementation of emitEHSjLjSetJmp already stores FP, SP, and IP
+ return emitEHSjLjSetJmp(MI, MBB);
+}
+
MachineBasicBlock *
SystemZTargetLowering::emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const {
@@ -7298,6 +7307,7 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
case ISD::READCYCLECOUNTER:
return lowerREADCYCLECOUNTER(Op, DAG);
case ISD::EH_SJLJ_SETJMP:
+ case ISD::SETJMP:
case ISD::EH_SJLJ_LONGJMP:
// These operations are legal on our platform, but we cannot actually
// set the operation action to Legal as common code would treat this
@@ -11192,6 +11202,8 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
return emitProbedAlloca(MI, MBB);
case SystemZ::EH_SjLj_SetJmp:
return emitEHSjLjSetJmp(MI, MBB);
+ case SystemZ::SetJmp:
+ return emitSetJmp(MI, MBB);
case SystemZ::EH_SjLj_LongJmp:
return emitEHSjLjLongJmp(MI, MBB);
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index bb3eeba6446d2..9bee8e24ddf71 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -115,6 +115,7 @@ class SystemZTargetLowering : public TargetLowering {
}
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
+ MachineBasicBlock *emitSetJmp(MachineInstr &MI, MachineBasicBlock *MBB) const;
MachineBasicBlock *emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 35a923d070e3e..6755578236b46 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -1920,8 +1920,10 @@ let mayLoad = 1, mayStore = 1, Defs = [CC] in {
//--------------------------------------------------------------------------
let isBarrier = 1, hasNoSchedulingInfo = 1 in {
let hasSideEffects = 1, usesCustomInserter = 1 in {
- def EH_SjLj_SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2),
+ def EH_SjLj_SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2),
[(set GR32:$dst, (z_eh_sjlj_setjmp ADDR64:$R2))]>;
+ def SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2),
+ [(set GR32:$dst, (z_setjmp ADDR64:$R2))]>;
let isTerminator = 1 in {
def EH_SjLj_LongJmp : Pseudo<(outs), (ins ADDR64:$R2),
[(z_eh_sjlj_longjmp ADDR64:$R2)]>;
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index 2a5b0435c1565..36597fb5ecafd 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -414,6 +414,8 @@ def z_tdc : SDNode<"SystemZISD::TDC", SDT_ZTest>;
def z_eh_sjlj_setjmp : SDNode<"ISD::EH_SJLJ_SETJMP", SDT_ZSetJmp,
[SDNPHasChain, SDNPSideEffect]>;
+def z_setjmp : SDNode<"ISD::SETJMP", SDT_ZSetJmp,
+ [SDNPHasChain, SDNPSideEffect]>;
def z_eh_sjlj_longjmp : SDNode<"ISD::EH_SJLJ_LONGJMP", SDT_ZLongJmp,
[SDNPHasChain, SDNPSideEffect]>;
diff --git a/llvm/lib/Target/VE/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp
index 141196c332074..027ad831f74f4 100644
--- a/llvm/lib/Target/VE/VEISelLowering.cpp
+++ b/llvm/lib/Target/VE/VEISelLowering.cpp
@@ -298,6 +298,7 @@ void VETargetLowering::initSPUActions() {
/// SJLJ instructions {
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
+ setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom);
/// } SJLJ instructions
@@ -1663,6 +1664,12 @@ SDValue VETargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
Op.getOperand(1));
}
+SDValue VETargetLowering::lowerSETJMP(SDValue Op, SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ return DAG.getNode(VEISD::SETJMP, DL, DAG.getVTList(MVT::i32, MVT::Other),
+ Op.getOperand(0), Op.getOperand(1));
+}
+
SDValue VETargetLowering::lowerEH_SJLJ_SETUP_DISPATCH(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
@@ -1833,6 +1840,8 @@ SDValue VETargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
return lowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::EH_SJLJ_SETJMP:
return lowerEH_SJLJ_SETJMP(Op, DAG);
+ case ISD::SETJMP:
+ return lowerSETJMP(Op, DAG);
case ISD::EH_SJLJ_SETUP_DISPATCH:
return lowerEH_SJLJ_SETUP_DISPATCH(Op, DAG);
case ISD::FRAMEADDR:
@@ -2246,6 +2255,139 @@ VETargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
return SinkMBB;
}
+MachineBasicBlock *VETargetLowering::emitSetJmp(MachineInstr &MI,
+ MachineBasicBlock *MBB) const {
+ DebugLoc DL = MI.getDebugLoc();
+ MachineFunction *MF = MBB->getParent();
+ const TargetInstrInfo *TII = Subtarget->getInstrInfo();
+ const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+
+ const BasicBlock *BB = MBB->getBasicBlock();
+ MachineFunction::iterator I = ++MBB->getIterator();
+
+ // Memory Reference.
+ SmallVector<MachineMemOperand *, 2> MMOs(MI.memoperands());
+ Register BufReg = MI.getOperand(1).getReg();
+
+ Register DstReg;
+
+ DstReg = MI.getOperand(0).getReg();
+ const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
+ assert(TRI->isTypeLegalForClass(*RC, MVT::i32) && "Invalid destination!");
+ (void)TRI;
+ Register MainDestReg = MRI.createVirtualRegister(RC);
+ Register RestoreDestReg = MRI.createVirtualRegister(RC);
+
+ // Buffer layout:
+ // buf[0] = Frame Pointer (SX9, offset 0)
+ // buf[1] = IP (offset 8)
+ // buf[2] = Stack Pointer (SX11, offset 16)
+ // buf[3] = Base Pointer (SX17, offset 24)
+
+ MachineBasicBlock *ThisMBB = MBB;
+ MachineBasicBlock *MainMBB = MF->CreateMachineBasicBlock(BB);
+ MachineBasicBlock *SinkMBB = MF->CreateMachineBasicBlock(BB);
+ MachineBasicBlock *RestoreMBB = MF->CreateMachineBasicBlock(BB);
+ MF->insert(I, MainMBB);
+ MF->insert(I, SinkMBB);
+ MF->push_back(RestoreMBB);
+ RestoreMBB->setMachineBlockAddressTaken();
+
+ // Transfer the remainder of BB and its successor edges to SinkMBB.
+ SinkMBB->splice(SinkMBB->begin(), MBB,
+ std::next(MachineBasicBlock::iterator(MI)), MBB->end());
+ SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
+
+ // ThisMBB:
+ Register LabelReg =
+ prepareMBB(*MBB, MachineBasicBlock::iterator(MI), RestoreMBB, DL);
+
+ // Store FP (SX9) to buf[0].
+ const VEFrameLowering *TFI = Subtarget->getFrameLowering();
+ if (TFI->hasFP(*MF)) {
+ MachineInstrBuilder MIB = BuildMI(*MBB, MI, DL, TII->get(VE::STrii));
+ MIB.addReg(BufReg);
+ MIB.addImm(0);
+ MIB.addImm(0);
+ MIB.addReg(VE::SX9);
+ MIB.setMemRefs(MMOs);
+ }
+
+ // Store SP (SX11) to buf[2].
+ {
+ MachineInstrBuilder MIB = BuildMI(*MBB, MI, DL, TII->get(VE::STrii));
+ MIB.addReg(BufReg);
+ MIB.addImm(0);
+ MIB.addImm(16);
+ MIB.addReg(VE::SX11);
+ MIB.setMemRefs(MMOs);
+ }
+
+ // Store BP in buf[3] iff this function is using BP.
+ if (TFI->hasBP(*MF)) {
+ MachineInstrBuilder MIB = BuildMI(*MBB, MI, DL, TII->get(VE::STrii));
+ MIB.addReg(BufReg);
+ MIB.addImm(0);
+ MIB.addImm(24);
+ MIB.addReg(VE::SX17);
+ MIB.setMemRefs(MMOs);
+ }
+
+ // Store IP in buf[1].
+ MachineInstrBuilder MIB = BuildMI(*MBB, MI, DL, TII->get(VE::STrii));
+ MIB.add(MI.getOperand(1)); // we can preserve the kill flags here.
+ MIB.addImm(0);
+ MIB.addImm(8);
+ MIB.addReg(LabelReg, getKillRegState(true));
+ MIB.setMemRefs(MMOs);
+
+ // Insert setup.
+ MIB =
+ BuildMI(*ThisMBB, MI, DL, TII->get(VE::EH_SjLj_Setup)).addMBB(RestoreMBB);
+
+ const VERegisterInfo *RegInfo = Subtarget->getRegisterInfo();
+ MIB.addRegMask(RegInfo->getNoPreservedMask());
+ ThisMBB->addSuccessor(MainMBB);
+ ThisMBB->addSuccessor(RestoreMBB);
+
+ // MainMBB:
+ BuildMI(MainMBB, DL, TII->get(VE::LEAzii), MainDestReg)
+ .addImm(0)
+ .addImm(0)
+ .addImm(0);
+ MainMBB->addSuccessor(SinkMBB);
+
+ // SinkMBB:
+ BuildMI(*SinkMBB, SinkMBB->begin(), DL, TII->get(VE::PHI), DstReg)
+ .addReg(MainDestReg)
+ .addMBB(MainMBB)
+ .addReg(RestoreDestReg)
+ .addMBB(RestoreMBB);
+
+ // RestoreMBB:
+ // Restore BP from buf[3] iff this function is using BP. The address of
+ // buf is in SX10.
+ // FIXME: Better to not use SX10 here
+ if (TFI->hasBP(*MF)) {
+ MachineInstrBuilder MIB =
+ BuildMI(RestoreMBB, DL, TII->get(VE::LDrii), VE::SX17);
+ MIB.addReg(VE::SX10);
+ MIB.addImm(0);
+ MIB.addImm(24);
+ MIB.setMemRefs(MMOs);
+ }
+ BuildMI(RestoreMBB, DL, TII->get(VE::LEAzii), RestoreDestReg)
+ .addImm(0)
+ .addImm(0)
+ .addImm(1);
+ BuildMI(RestoreMBB, DL, TII->get(VE::BRCFLa_t)).addMBB(SinkMBB);
+ RestoreMBB->addSuccessor(SinkMBB);
+
+ MI.eraseFromParent();
+ return SinkMBB;
+}
+
MachineBasicBlock *
VETargetLowering::emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const {
@@ -2626,6 +2768,8 @@ VETargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
return emitEHSjLjLongJmp(MI, BB);
case VE::EH_SjLj_SetJmp:
return emitEHSjLjSetJmp(MI, BB);
+ case VE::SetJmp:
+ return emitSetJmp(MI, BB);
case VE::EH_SjLj_Setup_Dispatch:
return emitSjLjDispatchBlock(MI, BB);
}
diff --git a/llvm/lib/Target/VE/VEISelLowering.h b/llvm/lib/Target/VE/VEISelLowering.h
index 487804194757e..9d410b8c2be84 100644
--- a/llvm/lib/Target/VE/VEISelLowering.h
+++ b/llvm/lib/Target/VE/VEISelLowering.h
@@ -190,6 +190,7 @@ class VETargetLowering : public TargetLowering {
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETUP_DISPATCH(SDValue Op, SelectionDAG &DAG) const;
+ SDValue lowerSETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
@@ -219,6 +220,7 @@ class VETargetLowering : public TargetLowering {
MachineBasicBlock *MBB) const;
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
+ MachineBasicBlock *emitSetJmp(MachineInstr &MI, MachineBasicBlock *MBB) const;
MachineBasicBlock *emitSjLjDispatchBlock(MachineInstr &MI,
MachineBasicBlock *BB) const;
diff --git a/llvm/lib/Target/VE/VEInstrInfo.td b/llvm/lib/Target/VE/VEInstrInfo.td
index 9869f95ae5661..fdffa9a434201 100644
--- a/llvm/lib/Target/VE/VEInstrInfo.td
+++ b/llvm/lib/Target/VE/VEInstrInfo.td
@@ -465,6 +465,10 @@ def VEeh_sjlj_setjmp: SDNode<"VEISD::EH_SJLJ_SETJMP",
SDTypeProfile<1, 1, [SDTCisInt<0>,
SDTCisPtrTy<1>]>,
[SDNPHasChain, SDNPSideEffect]>;
+def VEsetjmp: SDNode<"VEISD::SETJMP",
+ SDTypeProfile<1, 1, [SDTCisInt<0>,
+ SDTCisPtrTy<1>]>,
+ [SDNPHasChain, SDNPSideEffect]>;
def VEeh_sjlj_longjmp: SDNode<"VEISD::EH_SJLJ_LONGJMP",
SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>,
[SDNPHasChain, SDNPSideEffect]>;
@@ -1917,6 +1921,9 @@ let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
def EH_SjLj_SetJmp : Pseudo<(outs I32:$dst), (ins I64:$buf),
"# EH_SJLJ_SETJMP",
[(set I32:$dst, (VEeh_sjlj_setjmp I64:$buf))]>;
+ def SetJmp : Pseudo<(outs I32:$dst), (ins I64:$buf),
+ "# SETJMP",
+ [(set I32:$dst, (VEsetjmp I64:$buf))]>;
def EH_SjLj_Setup_Dispatch : Pseudo<(outs), (ins), "# EH_SJLJ_SETUP_DISPATCH",
[(VEeh_sjlj_setup_dispatch)]>;
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index be95168f2de00..b0c73ab38c49f 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -3030,11 +3030,12 @@ bool X86DAGToDAGISel::selectAddr(SDNode *Parent, SDValue N, SDValue &Base,
// This list of opcodes are all the nodes that have an "addr:$ptr" operand
// that are not a MemSDNode, and thus don't have proper addrspace info.
Parent->getOpcode() != ISD::INTRINSIC_W_CHAIN && // unaligned loads, fixme
- Parent->getOpcode() != ISD::INTRINSIC_VOID && // nontemporal stores
- Parent->getOpcode() != X86ISD::TLSCALL && // Fixme
- Parent->getOpcode() != X86ISD::ENQCMD && // Fixme
- Parent->getOpcode() != X86ISD::ENQCMDS && // Fixme
+ Parent->getOpcode() != ISD::INTRINSIC_VOID && // nontemporal stores
+ Parent->getOpcode() != X86ISD::TLSCALL && // Fixme
+ Parent->getOpcode() != X86ISD::ENQCMD && // Fixme
+ Parent->getOpcode() != X86ISD::ENQCMDS && // Fixme
Parent->getOpcode() != X86ISD::EH_SJLJ_SETJMP && // setjmp
+ Parent->getOpcode() != X86ISD::SETJMP && // setjmp
Parent->getOpcode() != X86ISD::EH_SJLJ_LONGJMP) { // longjmp
unsigned AddrSpace =
cast<MemSDNode>(Parent)->getPointerInfo().getAddrSpace();
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index f0e3bd3cebd66..f83c2bd870e9e 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -510,6 +510,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
// NOTE: EH_SJLJ_SETJMP/_LONGJMP are not recommended, since
// LLVM/Clang supports zero-cost DWARF and SEH exception handling.
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
+ setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom);
@@ -28913,6 +28914,16 @@ SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
Op.getOperand(0), Op.getOperand(1));
}
+SDValue X86TargetLowering::lowerSETJMP(SDValue Op, SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ if (!Subtarget.is64Bit()) {
+ const X86InstrInfo *TII = Subtarget.getInstrInfo();
+ (void)TII->getGlobalBaseReg(&DAG.getMachineFunction());
+ }
+ return DAG.getNode(X86ISD::SETJMP, DL, DAG.getVTList(MVT::i32, MVT::Other),
+ Op.getOperand(0), Op.getOperand(1));
+}
+
SDValue X86TargetLowering::lowerEH_SJLJ_LONGJMP(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
@@ -34209,6 +34220,7 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG);
+ case ISD::SETJMP: return lowerSETJMP(Op, DAG);
case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::EH_SJLJ_SETUP_DISPATCH:
return lowerEH_SJLJ_SETUP_DISPATCH(Op, DAG);
@@ -37578,6 +37590,8 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
MIB.addMBB(restoreMBB);
MIB.setMemRefs(MMOs);
+ const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
+
if (MF->getFunction().getParent()->getModuleFlag("cf-protection-return")) {
emitSetJmpShadowStackFix(MI, thisMBB);
}
@@ -37586,7 +37600,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);
@@ -37623,6 +37636,164 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
return sinkMBB;
}
+// Expand @llvm.setjmp pseudo. Like emitEHSjLjSetJmp but the backend is
+// responsible for storing FP and SP into the buffer (the frontend does not
+// emit @llvm.frameaddress / @llvm.stacksave stores).
+MachineBasicBlock *X86TargetLowering::emitSetJmp(MachineInstr &MI,
+ MachineBasicBlock *MBB) const {
+ const MIMetadata MIMD(MI);
+ MachineFunction *MF = MBB->getParent();
+ const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+ const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+
+ const BasicBlock *BB = MBB->getBasicBlock();
+ MachineFunction::iterator I = ++MBB->getIterator();
+
+ SmallVector<MachineMemOperand *, 2> MMOs(MI.memoperands());
+
+ unsigned MemOpndSlot = 0;
+ unsigned CurOp = 0;
+
+ Register DstReg = MI.getOperand(CurOp++).getReg();
+ const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
+ assert(TRI->isTypeLegalForClass(*RC, MVT::i32) && "Invalid destination!");
+ (void)TRI;
+ Register mainDstReg = MRI.createVirtualRegister(RC);
+ Register restoreDstReg = MRI.createVirtualRegister(RC);
+
+ MemOpndSlot = CurOp;
+
+ MVT PVT = getPointerTy(MF->getDataLayout());
+ assert((PVT == MVT::i64 || PVT == MVT::i32) && "Invalid Pointer Size!");
+
+ MachineBasicBlock *thisMBB = MBB;
+ MachineBasicBlock *mainMBB = MF->CreateMachineBasicBlock(BB);
+ MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(BB);
+ MachineBasicBlock *restoreMBB = MF->CreateMachineBasicBlock(BB);
+ MF->insert(I, mainMBB);
+ MF->insert(I, sinkMBB);
+ MF->push_back(restoreMBB);
+ restoreMBB->setMachineBlockAddressTaken();
+
+ MachineInstrBuilder MIB;
+
+ sinkMBB->splice(sinkMBB->begin(), MBB,
+ std::next(MachineBasicBlock::iterator(MI)), MBB->end());
+ sinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
+
+ // thisMBB:
+ unsigned PtrStoreOpc = 0;
+ Register LabelReg;
+ const int64_t LabelOffset = 1 * PVT.getStoreSize();
+ bool UseImmLabel = (MF->getTarget().getCodeModel() == CodeModel::Small) &&
+ !isPositionIndependent();
+
+ // Prepare IP either in reg or imm.
+ if (!UseImmLabel) {
+ PtrStoreOpc = (PVT == MVT::i64) ? X86::MOV64mr : X86::MOV32mr;
+ const TargetRegisterClass *PtrRC = getRegClassFor(PVT);
+ LabelReg = MRI.createVirtualRegister(PtrRC);
+ if (Subtarget.is64Bit()) {
+ MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(X86::LEA64r), LabelReg)
+ .addReg(X86::RIP)
+ .addImm(0)
+ .addReg(0)
+ .addMBB(restoreMBB)
+ .addReg(0);
+ } else {
+ const X86InstrInfo *XII = static_cast<const X86InstrInfo *>(TII);
+ MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(X86::LEA32r), LabelReg)
+ .addReg(XII->getGlobalBaseReg(MF))
+ .addImm(0)
+ .addReg(0)
+ .addMBB(restoreMBB, Subtarget.classifyBlockAddressReference())
+ .addReg(0);
+ }
+ } else
+ PtrStoreOpc = (PVT == MVT::i64) ? X86::MOV64mi32 : X86::MOV32mi;
+
+ // Store IP to buf[1].
+ MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(PtrStoreOpc));
+ for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
+ if (i == X86::AddrDisp)
+ MIB.addDisp(MI.getOperand(MemOpndSlot + i), LabelOffset);
+ else
+ MIB.add(MI.getOperand(MemOpndSlot + i));
+ }
+ if (!UseImmLabel)
+ MIB.addReg(LabelReg);
+ else
+ MIB.addMBB(restoreMBB);
+ MIB.setMemRefs(MMOs);
+
+ // Store FP to buf[0] and SP to buf[2].
+ const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
+ unsigned RegStoreOpc = (PVT == MVT::i64) ? X86::MOV64mr : X86::MOV32mr;
+
+ bool HasFP = Subtarget.getFrameLowering()->hasFP(*MF);
+ if (HasFP) {
+ 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);
+ }
+
+ const int64_t SPOffset = 2 * PVT.getStoreSize();
+ MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(RegStoreOpc));
+ for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
+ if (i == X86::AddrDisp)
+ MIB.addDisp(MI.getOperand(MemOpndSlot + i), SPOffset);
+ else
+ MIB.add(MI.getOperand(MemOpndSlot + i));
+ }
+ MIB.addReg(RegInfo->getStackRegister());
+ MIB.setMemRefs(MMOs);
+
+ if (MF->getFunction().getParent()->getModuleFlag("cf-protection-return")) {
+ emitSetJmpShadowStackFix(MI, thisMBB);
+ }
+
+ // Setup
+ MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(X86::EH_SjLj_Setup))
+ .addMBB(restoreMBB);
+
+ MIB.addRegMask(RegInfo->getNoPreservedMask());
+ thisMBB->addSuccessor(mainMBB);
+ thisMBB->addSuccessor(restoreMBB);
+
+ // mainMBB:
+ BuildMI(mainMBB, MIMD, TII->get(X86::MOV32r0), mainDstReg);
+ mainMBB->addSuccessor(sinkMBB);
+
+ // sinkMBB:
+ BuildMI(*sinkMBB, sinkMBB->begin(), MIMD, TII->get(X86::PHI), DstReg)
+ .addReg(mainDstReg)
+ .addMBB(mainMBB)
+ .addReg(restoreDstReg)
+ .addMBB(restoreMBB);
+
+ // restoreMBB:
+ if (RegInfo->hasBasePointer(*MF)) {
+ const bool Uses64BitFramePtr = Subtarget.isTarget64BitLP64();
+ X86MachineFunctionInfo *X86FI = MF->getInfo<X86MachineFunctionInfo>();
+ X86FI->setRestoreBasePointer(MF);
+ Register FramePtr = RegInfo->getFrameRegister(*MF);
+ Register BasePtr = RegInfo->getBaseRegister();
+ unsigned Opm = Uses64BitFramePtr ? X86::MOV64rm : X86::MOV32rm;
+ addRegOffset(BuildMI(restoreMBB, MIMD, TII->get(Opm), BasePtr), FramePtr,
+ true, X86FI->getRestoreBasePointerOffset())
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
+ BuildMI(restoreMBB, MIMD, TII->get(X86::MOV32ri), restoreDstReg).addImm(1);
+ BuildMI(restoreMBB, MIMD, TII->get(X86::JMP_1)).addMBB(sinkMBB);
+ restoreMBB->addSuccessor(sinkMBB);
+
+ MI.eraseFromParent();
+ return sinkMBB;
+}
+
/// Fix the shadow stack using the previously saved SSP pointer.
/// \sa emitSetJmpShadowStackFix
/// \param [in] MI The temporary Machine Instruction for the builtin.
@@ -38408,6 +38579,10 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case X86::EH_SjLj_SetJmp64:
return emitEHSjLjSetJmp(MI, BB);
+ case X86::SetJmp32:
+ case X86::SetJmp64:
+ return emitSetJmp(MI, BB);
+
case X86::EH_SjLj_LongJmp32:
case X86::EH_SjLj_LongJmp64:
return emitEHSjLjLongJmp(MI, BB);
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index 5c7c54cacd239..1274089fea7da 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -823,6 +823,7 @@ namespace llvm {
ISD::ArgFlagsTy Flags) const;
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
+ SDValue lowerSETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETUP_DISPATCH(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
@@ -928,6 +929,8 @@ namespace llvm {
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
+ MachineBasicBlock *emitSetJmp(MachineInstr &MI,
+ MachineBasicBlock *MBB) const;
void emitSetJmpShadowStackFix(MachineInstr &MI,
MachineBasicBlock *MBB) const;
diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index bc05dae7351bb..847d141d1ce90 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -214,6 +214,14 @@ let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
"#EH_SJLJ_SETJMP64",
[(set GR32:$dst, (X86eh_sjlj_setjmp addr:$buf))]>,
Requires<[In64BitMode]>;
+ def SetJmp32 : I<0, Pseudo, (outs GR32:$dst), (ins i32mem:$buf),
+ "#SETJMP32",
+ [(set GR32:$dst, (X86setjmp addr:$buf))]>,
+ Requires<[Not64BitMode]>;
+ def SetJmp64 : I<0, Pseudo, (outs GR32:$dst), (ins i64mem:$buf),
+ "#SETJMP64",
+ [(set GR32:$dst, (X86setjmp addr:$buf))]>,
+ Requires<[In64BitMode]>;
let isTerminator = 1 in {
def EH_SjLj_LongJmp32 : I<0, Pseudo, (outs), (ins i32mem:$buf),
"#EH_SJLJ_LONGJMP32",
diff --git a/llvm/lib/Target/X86/X86InstrFragments.td b/llvm/lib/Target/X86/X86InstrFragments.td
index 3cd05ab0351bd..fe59fbfc6201b 100644
--- a/llvm/lib/Target/X86/X86InstrFragments.td
+++ b/llvm/lib/Target/X86/X86InstrFragments.td
@@ -352,6 +352,10 @@ def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP",
SDTypeProfile<1, 1, [SDTCisInt<0>,
SDTCisPtrTy<1>]>,
[SDNPHasChain, SDNPSideEffect]>;
+def X86setjmp : SDNode<"X86ISD::SETJMP",
+ SDTypeProfile<1, 1, [SDTCisInt<0>,
+ SDTCisPtrTy<1>]>,
+ [SDNPHasChain, SDNPSideEffect]>;
// SjLj exception handling longjmp.
def X86eh_sjlj_longjmp : SDNode<"X86ISD::EH_SJLJ_LONGJMP",
diff --git a/llvm/test/CodeGen/ARM/setjmp.ll b/llvm/test/CodeGen/ARM/setjmp.ll
new file mode 100644
index 0000000000000..e322bbe4d5d12
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/setjmp.ll
@@ -0,0 +1,47 @@
+; RUN: llc < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=ARM %s
+; RUN: llc < %s -mtriple=thumbv7-apple-ios | FileCheck --check-prefix=THUMB2 %s
+
+; Verify that @llvm.setjmp produces the same FP/SP stores as the old pattern
+; of @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
+
+ at buf = internal global [5 x ptr] zeroinitializer
+
+; --- Old pattern (frameaddress + stacksave + stores + eh.sjlj.setjmp) ---
+
+declare ptr @llvm.frameaddress(i32) nounwind readnone
+declare ptr @llvm.stacksave() nounwind
+declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
+
+define i32 @old_setjmp() nounwind "frame-pointer"="all" {
+ %fp = call ptr @llvm.frameaddress(i32 0)
+ store ptr %fp, ptr @buf, align 16
+ %sp = call ptr @llvm.stacksave()
+ store ptr %sp, ptr getelementptr inbounds ([5 x ptr], ptr @buf, i64 0, i64 2), align 16
+ %r = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
+ ret i32 %r
+}
+
+; --- New pattern (@llvm.setjmp) ---
+
+declare i32 @llvm.setjmp(ptr) nounwind
+
+define i32 @new_setjmp() nounwind "frame-pointer"="all" {
+ %r = call i32 @llvm.setjmp(ptr @buf)
+ ret i32 %r
+}
+
+; Both functions should store FP (r7) to buf[0] and SP to buf[2].
+
+; ARM-LABEL: _old_setjmp:
+; ARM: str r7, [r0]
+; ARM: str sp, [r0, #8]
+; ARM-LABEL: _new_setjmp:
+; ARM: str r7, [r0]
+; ARM: str sp, [r0, #8]
+
+; THUMB2-LABEL: _old_setjmp:
+; THUMB2: str r7, [r0]
+; THUMB2: str.w sp, [r0, #8]
+; THUMB2-LABEL: _new_setjmp:
+; THUMB2: str r7, [r0]
+; THUMB2: str.w sp, [r0, #8]
diff --git a/llvm/test/CodeGen/PowerPC/setjmp.ll b/llvm/test/CodeGen/PowerPC/setjmp.ll
new file mode 100644
index 0000000000000..f0b86a790c488
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/setjmp.ll
@@ -0,0 +1,39 @@
+; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 -verify-machineinstrs | FileCheck %s
+
+; Verify that @llvm.setjmp produces the same FP/SP stores as the old pattern
+; of @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
+
+ at buf = internal global [5 x ptr] zeroinitializer, align 8
+
+; --- Old pattern (frameaddress + stacksave + stores + eh.sjlj.setjmp) ---
+
+declare ptr @llvm.frameaddress(i32) nounwind readnone
+declare ptr @llvm.stacksave() nounwind
+declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
+
+define i32 @old_setjmp() nounwind "frame-pointer"="all" {
+ %fp = call ptr @llvm.frameaddress(i32 0)
+ store ptr %fp, ptr @buf, align 8
+ %sp = call ptr @llvm.stacksave()
+ store ptr %sp, ptr getelementptr inbounds (ptr, ptr @buf, i64 2), align 8
+ %r = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
+ ret i32 %r
+}
+
+; --- New pattern (@llvm.setjmp) ---
+
+declare i32 @llvm.setjmp(ptr) nounwind
+
+define i32 @new_setjmp() nounwind "frame-pointer"="all" {
+ %r = call i32 @llvm.setjmp(ptr @buf)
+ ret i32 %r
+}
+
+; Both functions should store FP (r31) to buf[0] and SP (r1) to buf[2] (offset 16).
+
+; CHECK-LABEL: old_setjmp:
+; CHECK: std 31, buf at toc@l(
+; CHECK: std 1, 16(
+; CHECK-LABEL: new_setjmp:
+; CHECK: std 31, 0(
+; CHECK: std 1, 16(
diff --git a/llvm/test/CodeGen/SystemZ/setjmp.ll b/llvm/test/CodeGen/SystemZ/setjmp.ll
new file mode 100644
index 0000000000000..01c78e58aff2d
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/setjmp.ll
@@ -0,0 +1,35 @@
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+
+; Verify that @llvm.setjmp produces the same IP/SP stores as the old pattern
+; of @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
+; SystemZ's eh.sjlj.setjmp already stores IP and SP internally, so
+; the old and new patterns should produce identical output.
+
+ at buf = global [20 x ptr] zeroinitializer, align 8
+
+; --- Old pattern (eh.sjlj.setjmp, which already stores IP+SP on SystemZ) ---
+
+declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
+
+define void @old_setjmp() nounwind {
+ %r = tail call i32 @llvm.eh.sjlj.setjmp(ptr nonnull @buf)
+ ret void
+}
+
+; --- New pattern (@llvm.setjmp) ---
+
+declare i32 @llvm.setjmp(ptr) nounwind
+
+define void @new_setjmp() nounwind {
+ %r = tail call i32 @llvm.setjmp(ptr nonnull @buf)
+ ret void
+}
+
+; Both should store IP to buf[1] (offset 8) and SP to buf[3] (offset 24).
+
+; CHECK-LABEL: old_setjmp:
+; CHECK: stg %r0, 8(%r1)
+; CHECK: stg %r15, 24(%r1)
+; CHECK-LABEL: new_setjmp:
+; CHECK: stg %r0, 8(%r1)
+; CHECK: stg %r15, 24(%r1)
diff --git a/llvm/test/CodeGen/VE/Scalar/setjmp.ll b/llvm/test/CodeGen/VE/Scalar/setjmp.ll
new file mode 100644
index 0000000000000..24747bacbbfea
--- /dev/null
+++ b/llvm/test/CodeGen/VE/Scalar/setjmp.ll
@@ -0,0 +1,39 @@
+; RUN: llc < %s -mtriple=ve | FileCheck %s
+
+; Verify that @llvm.setjmp produces the same FP/SP stores as the old pattern
+; of @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
+
+ at buf = common global [1 x [25 x i64]] zeroinitializer, align 8
+
+; --- Old pattern (frameaddress + stacksave + stores + eh.sjlj.setjmp) ---
+
+declare ptr @llvm.frameaddress(i32) nounwind readnone
+declare ptr @llvm.stacksave() nounwind
+declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
+
+define i32 @old_setjmp() nounwind "frame-pointer"="all" {
+ %fp = call ptr @llvm.frameaddress(i32 0)
+ store ptr %fp, ptr @buf, align 8
+ %sp = call ptr @llvm.stacksave()
+ store ptr %sp, ptr getelementptr inbounds (ptr, ptr @buf, i64 2), align 8
+ %r = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
+ ret i32 %r
+}
+
+; --- New pattern (@llvm.setjmp) ---
+
+declare i32 @llvm.setjmp(ptr) nounwind
+
+define i32 @new_setjmp() nounwind "frame-pointer"="all" {
+ %r = call i32 @llvm.setjmp(ptr @buf)
+ ret i32 %r
+}
+
+; Both functions should store FP (s9) to buf[0] and SP (s11) to buf[2].
+
+; CHECK-LABEL: old_setjmp:
+; CHECK: st %s9, (, %s0)
+; CHECK: st %s11, 16(, %s0)
+; CHECK-LABEL: new_setjmp:
+; CHECK: st %s9, (, %s0)
+; CHECK: st %s11, 16(, %s0)
diff --git a/llvm/test/CodeGen/X86/setjmp.ll b/llvm/test/CodeGen/X86/setjmp.ll
new file mode 100644
index 0000000000000..1e4b195949576
--- /dev/null
+++ b/llvm/test/CodeGen/X86/setjmp.ll
@@ -0,0 +1,55 @@
+; RUN: llc < %s -mtriple=i386-pc-linux | FileCheck --check-prefix=X86 %s
+; RUN: llc < %s -mtriple=x86_64-pc-linux | FileCheck --check-prefix=X64 %s
+; RUN: llc < %s -mtriple=x86_64-windows-gnu | FileCheck --check-prefix=WIN64 %s
+
+; Verify that @llvm.setjmp produces the same output as the old pattern of
+; @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
+
+ at buf = internal global [5 x ptr] zeroinitializer
+
+; --- Old pattern (frameaddress + stacksave + stores + eh.sjlj.setjmp) ---
+
+declare ptr @llvm.frameaddress(i32) nounwind readnone
+declare ptr @llvm.stacksave() nounwind
+declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
+
+define i32 @old_setjmp() nounwind "frame-pointer"="all" {
+ %fp = tail call ptr @llvm.frameaddress(i32 0)
+ store ptr %fp, ptr @buf, align 16
+ %sp = tail call ptr @llvm.stacksave()
+ store ptr %sp, ptr getelementptr inbounds ([5 x ptr], ptr @buf, i64 0, i64 2), align 16
+ %r = tail call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
+ ret i32 %r
+}
+
+; --- New pattern (@llvm.setjmp) ---
+
+declare i32 @llvm.setjmp(ptr) nounwind
+
+define i32 @new_setjmp() nounwind "frame-pointer"="all" {
+ %r = tail call i32 @llvm.setjmp(ptr @buf)
+ ret i32 %r
+}
+
+; Both functions should store FP to buf[0], SP to buf[2], IP to buf[1].
+
+; X86-LABEL: old_setjmp:
+; X86: movl %ebp, buf
+; X86: movl %esp, buf+8
+; X86-LABEL: new_setjmp:
+; X86: movl %ebp, buf
+; X86: movl %esp, buf+8
+
+; X64-LABEL: old_setjmp:
+; X64: movq %rbp, buf(%rip)
+; X64: movq %rsp, buf+16(%rip)
+; X64-LABEL: new_setjmp:
+; X64: movq %rbp, buf(%rip)
+; X64: movq %rsp, buf+16(%rip)
+
+; On WIN64, the old pattern stores an adjusted address from @llvm.frameaddress
+; (which is wrong on WindowsCFI targets). The new @llvm.setjmp stores %rbp
+; directly, which is the correct fix.
+; WIN64-LABEL: new_setjmp:
+; WIN64: movq %rbp, buf(%rip)
+; WIN64: movq %rsp, buf+16(%rip)
>From 3463b3c5088c9c772370ce352a2456644fb7559a Mon Sep 17 00:00:00 2001
From: pkova <pyry at urbit.org>
Date: Tue, 24 Mar 2026 18:12:42 +0200
Subject: [PATCH 2/6] Store FP, SP and IP on backend in @llvm.eh.sjlj.setjmp
---
clang/lib/CodeGen/CGBuiltin.cpp | 5 +-
.../CodeGen/SystemZ/builtin-setjmp-logjmp.c | 2 +-
clang/test/Sema/builtin-longjmp.c | 2 +-
llvm/include/llvm/CodeGen/ISDOpcodes.h | 6 -
llvm/include/llvm/IR/Intrinsics.td | 2 -
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 2 -
.../SelectionDAG/SelectionDAGBuilder.cpp | 10 -
.../SelectionDAG/SelectionDAGDumper.cpp | 1 -
llvm/lib/Target/ARM/ARMISelLowering.cpp | 16 +-
llvm/lib/Target/ARM/ARMISelLowering.h | 1 -
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 178 +++---------------
llvm/lib/Target/PowerPC/PPCISelLowering.h | 3 -
llvm/lib/Target/PowerPC/PPCInstr64Bit.td | 7 +-
llvm/lib/Target/PowerPC/PPCInstrInfo.td | 11 +-
.../Target/SystemZ/SystemZISelLowering.cpp | 12 --
llvm/lib/Target/SystemZ/SystemZISelLowering.h | 1 -
llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 2 -
llvm/lib/Target/SystemZ/SystemZOperators.td | 2 -
llvm/lib/Target/VE/VEISelLowering.cpp | 126 -------------
llvm/lib/Target/VE/VEISelLowering.h | 2 -
llvm/lib/Target/VE/VEInstrInfo.td | 7 -
llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 1 -
llvm/lib/Target/X86/X86ISelLowering.cpp | 161 +---------------
llvm/lib/Target/X86/X86ISelLowering.h | 3 -
llvm/lib/Target/X86/X86InstrCompiler.td | 8 -
llvm/lib/Target/X86/X86InstrFragments.td | 4 -
llvm/test/CodeGen/ARM/setjmp.ll | 34 +---
llvm/test/CodeGen/PowerPC/setjmp.ll | 29 +--
llvm/test/CodeGen/SystemZ/setjmp.ll | 25 +--
llvm/test/CodeGen/VE/Scalar/setjmp.ll | 29 +--
llvm/test/CodeGen/X86/setjmp.ll | 40 +---
31 files changed, 55 insertions(+), 677 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 34aedc111ee4c..0c7e2d6c11499 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4918,8 +4918,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_setjmp: {
Address Buf = EmitPointerWithAlignment(E->getArg(0));
- // The backend handles all buffer stores (FP, SP, IP) via @llvm.setjmp.
- Function *F = CGM.getIntrinsic(Intrinsic::setjmp);
+ // The backend handles all buffer stores (FP, SP, IP) via
+ // @llvm.eh.sjlj.setjmp.
+ Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp);
return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this)));
}
case Builtin::BI__builtin_longjmp: {
diff --git a/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c b/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
index d2522c6bab7df..898891fa182ea 100644
--- a/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
+++ b/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
@@ -6,7 +6,7 @@ void *buf[20];
// CHECK-LABEL: define dso_local void @foo(
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.setjmp(ptr @buf)
+// CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
// CHECK-NEXT: ret void
//
void foo()
diff --git a/clang/test/Sema/builtin-longjmp.c b/clang/test/Sema/builtin-longjmp.c
index b320ec0b6a2d2..99463cf3385a1 100644
--- a/clang/test/Sema/builtin-longjmp.c
+++ b/clang/test/Sema/builtin-longjmp.c
@@ -21,7 +21,7 @@ jmp_buf buf;
// CHECK: call{{.*}} void @llvm.eh.sjlj.longjmp
// CHECK: define{{.*}} void @do_setjmp()
-// CHECK: call{{.*}} i32 @llvm.setjmp
+// CHECK: call{{.*}} i32 @llvm.eh.sjlj.setjmp
void do_jump(void) {
__builtin_longjmp(buf, 1); // expected-error {{__builtin_longjmp is not supported for the current target}}
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 2a49f30210b2c..fa578f733d4e8 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -161,12 +161,6 @@ enum NodeType {
/// and returns an outchain.
EH_SJLJ_SETJMP,
- /// RESULT, OUTCHAIN = SETJMP(INCHAIN, buffer)
- /// This corresponds to the setjmp intrinsic. Like EH_SJLJ_SETJMP but the
- /// backend is responsible for storing all of FP, SP, and IP into the buffer
- /// (the frontend does not emit any buffer stores).
- SETJMP,
-
/// OUTCHAIN = EH_SJLJ_LONGJMP(INCHAIN, buffer)
/// This corresponds to the eh.sjlj.longjmp intrinsic.
/// It takes an input chain and a pointer to the jump buffer as inputs
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 5b309751fc517..4469ff155b854 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1571,8 +1571,6 @@ def int_eh_sjlj_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>;
def int_eh_sjlj_longjmp : Intrinsic<[], [llvm_ptr_ty], [IntrNoReturn]>;
def int_eh_sjlj_setup_dispatch : Intrinsic<[], []>;
-def int_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>;
-
//===---------------- Generic Variable Attribute Intrinsics----------------===//
//
def int_var_annotation : DefaultAttrsIntrinsic<
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 7b35825ba995c..5e54343f7f146 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -1116,7 +1116,6 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
case ISD::FRAME_TO_ARGS_OFFSET:
case ISD::EH_DWARF_CFA:
case ISD::EH_SJLJ_SETJMP:
- case ISD::SETJMP:
case ISD::EH_SJLJ_LONGJMP:
case ISD::EH_SJLJ_SETUP_DISPATCH:
// These operations lie about being legal: when they claim to be legal,
@@ -3312,7 +3311,6 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
Results.push_back(Node->getOperand(0));
break;
case ISD::EH_SJLJ_SETJMP:
- case ISD::SETJMP:
// If the target didn't expand this, just return 'zero' and preserve the
// chain.
Results.push_back(DAG.getConstant(0, dl, MVT::i32));
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 4c72ecb8bd6c4..eb55a68eaba84 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -6863,16 +6863,6 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
MFI.setFunctionContextIndex(FI);
return;
}
- case Intrinsic::setjmp: {
- SDValue Ops[2];
- Ops[0] = getRoot();
- Ops[1] = getValue(I.getArgOperand(0));
- SDValue Op =
- DAG.getNode(ISD::SETJMP, sdl, DAG.getVTList(MVT::i32, MVT::Other), Ops);
- setValue(&I, Op.getValue(0));
- DAG.setRoot(Op.getValue(1));
- return;
- }
case Intrinsic::eh_sjlj_setjmp: {
SDValue Ops[2];
Ops[0] = getRoot();
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 890545c756351..7161dd299f830 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -160,7 +160,6 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::EH_DWARF_CFA: return "EH_DWARF_CFA";
case ISD::EH_RETURN: return "EH_RETURN";
case ISD::EH_SJLJ_SETJMP: return "EH_SJLJ_SETJMP";
- case ISD::SETJMP: return "SETJMP";
case ISD::EH_SJLJ_LONGJMP: return "EH_SJLJ_LONGJMP";
case ISD::EH_SJLJ_SETUP_DISPATCH: return "EH_SJLJ_SETUP_DISPATCH";
case ISD::ConstantPool: return "ConstantPool";
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 7b81a4825d4fe..27a45a1bf5b92 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1195,7 +1195,6 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM_,
// We want to custom lower some of our intrinsics.
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
- setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom);
@@ -3770,14 +3769,6 @@ SDValue ARMTargetLowering::LowerGlobalAddressWindows(SDValue Op,
SDValue
ARMTargetLowering::LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const {
- SDLoc dl(Op);
- SDValue Val = DAG.getConstant(0, dl, MVT::i32);
- return DAG.getNode(ARMISD::EH_SJLJ_SETJMP, dl,
- DAG.getVTList(MVT::i32, MVT::Other), Op.getOperand(0),
- Op.getOperand(1), Val);
-}
-
-SDValue ARMTargetLowering::LowerSETJMP(SDValue Op, SelectionDAG &DAG) const {
SDLoc dl(Op);
SDValue Chain = Op.getOperand(0);
SDValue Buf = Op.getOperand(1);
@@ -3798,7 +3789,7 @@ SDValue ARMTargetLowering::LowerSETJMP(SDValue Op, SelectionDAG &DAG) const {
DAG.getNode(ISD::ADD, dl, PtrVT, Buf, DAG.getConstant(8, dl, PtrVT));
Chain = DAG.getStore(SP.getValue(1), dl, SP, SPAddr, MachinePointerInfo());
- // Delegate to EH_SJLJ_SETJMP for IP store + return value.
+ // Delegate to ARMISD::EH_SJLJ_SETJMP for IP store + return value.
SDValue Val = DAG.getConstant(0, dl, MVT::i32);
return DAG.getNode(ARMISD::EH_SJLJ_SETJMP, dl,
DAG.getVTList(MVT::i32, MVT::Other), Chain, Buf, Val);
@@ -10462,10 +10453,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG);
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
- case ISD::EH_SJLJ_SETJMP:
- return LowerEH_SJLJ_SETJMP(Op, DAG);
- case ISD::SETJMP:
- return LowerSETJMP(Op, DAG);
+ case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG);
case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::EH_SJLJ_SETUP_DISPATCH: return LowerEH_SJLJ_SETUP_DISPATCH(Op, DAG);
case ISD::INTRINSIC_VOID: return LowerINTRINSIC_VOID(Op, DAG, Subtarget);
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index c4710adf6a6eb..e58d872c548e4 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -546,7 +546,6 @@ class VectorType;
SDValue Dst,
ISD::ArgFlagsTy Flags) const;
SDValue LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
- SDValue LowerSETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_SJLJ_SETUP_DISPATCH(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG,
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index c2f09544209be..d3a80e7784ceb 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -601,7 +601,6 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
// your own exception handling based on them.
// LLVM/Clang supports zero-cost DWARF exception handling.
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
- setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
// We want to legalize GlobalAddress and ConstantPool nodes into the
@@ -7986,12 +7985,6 @@ SDValue PPCTargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
Op.getOperand(0), Op.getOperand(1));
}
-SDValue PPCTargetLowering::lowerSETJMP(SDValue Op, SelectionDAG &DAG) const {
- SDLoc DL(Op);
- return DAG.getNode(PPCISD::SETJMP, DL, DAG.getVTList(MVT::i32, MVT::Other),
- Op.getOperand(0), Op.getOperand(1));
-}
-
SDValue PPCTargetLowering::lowerEH_SJLJ_LONGJMP(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
@@ -12751,10 +12744,7 @@ SDValue PPCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
// Exception handling lowering.
case ISD::EH_DWARF_CFA: return LowerEH_DWARF_CFA(Op, DAG);
- case ISD::EH_SJLJ_SETJMP:
- return lowerEH_SJLJ_SETJMP(Op, DAG);
- case ISD::SETJMP:
- return lowerSETJMP(Op, DAG);
+ case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG);
case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::LOAD: return LowerLOAD(Op, DAG);
@@ -13496,143 +13486,21 @@ PPCTargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
std::next(MachineBasicBlock::iterator(MI)), MBB->end());
sinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
- // Note that the structure of the jmp_buf used here is not compatible
- // with that used by libc, and is not designed to be. Specifically, it
- // stores only those 'reserved' registers that LLVM does not otherwise
- // understand how to spill. Also, by convention, by the time this
- // intrinsic is called, Clang has already stored the frame address in the
- // first slot of the buffer and stack address in the third. Following the
- // X86 target code, we'll store the jump address in the second slot. We also
- // need to save the TOC pointer (R2) to handle jumps between shared
- // libraries, and that will be stored in the fourth slot. The thread
- // identifier (R13) is not affected.
-
- // thisMBB:
- const int64_t LabelOffset = 1 * PVT.getStoreSize();
- const int64_t TOCOffset = 3 * PVT.getStoreSize();
- const int64_t BPOffset = 4 * PVT.getStoreSize();
-
- // Prepare IP either in reg.
- const TargetRegisterClass *PtrRC = getRegClassFor(PVT);
- Register LabelReg = MRI.createVirtualRegister(PtrRC);
- Register BufReg = MI.getOperand(1).getReg();
-
- if (Subtarget.is64BitELFABI()) {
- setUsesTOCBasePtr(*MBB->getParent());
- MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::STD))
- .addReg(PPC::X2)
- .addImm(TOCOffset)
- .addReg(BufReg)
- .cloneMemRefs(MI);
- }
-
- // Naked functions never have a base pointer, and so we use r1. For all
- // other functions, this decision must be delayed until during PEI.
- unsigned BaseReg;
- if (MF->getFunction().hasFnAttribute(Attribute::Naked))
- BaseReg = Subtarget.isPPC64() ? PPC::X1 : PPC::R1;
- else
- BaseReg = Subtarget.isPPC64() ? PPC::BP8 : PPC::BP;
-
- MIB = BuildMI(*thisMBB, MI, DL,
- TII->get(Subtarget.isPPC64() ? PPC::STD : PPC::STW))
- .addReg(BaseReg)
- .addImm(BPOffset)
- .addReg(BufReg)
- .cloneMemRefs(MI);
-
- // Setup
- MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::BCLalways)).addMBB(mainMBB);
- MIB.addRegMask(TRI->getNoPreservedMask());
-
- BuildMI(*thisMBB, MI, DL, TII->get(PPC::LI), restoreDstReg).addImm(1);
-
- MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::EH_SjLj_Setup))
- .addMBB(mainMBB);
- MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::B)).addMBB(sinkMBB);
-
- thisMBB->addSuccessor(mainMBB, BranchProbability::getZero());
- thisMBB->addSuccessor(sinkMBB, BranchProbability::getOne());
-
- // mainMBB:
- // mainDstReg = 0
- MIB =
- BuildMI(mainMBB, DL,
- TII->get(Subtarget.isPPC64() ? PPC::MFLR8 : PPC::MFLR), LabelReg);
-
- // Store IP
- if (Subtarget.isPPC64()) {
- MIB = BuildMI(mainMBB, DL, TII->get(PPC::STD))
- .addReg(LabelReg)
- .addImm(LabelOffset)
- .addReg(BufReg);
- } else {
- MIB = BuildMI(mainMBB, DL, TII->get(PPC::STW))
- .addReg(LabelReg)
- .addImm(LabelOffset)
- .addReg(BufReg);
- }
- MIB.cloneMemRefs(MI);
-
- BuildMI(mainMBB, DL, TII->get(PPC::LI), mainDstReg).addImm(0);
- mainMBB->addSuccessor(sinkMBB);
-
- // sinkMBB:
- BuildMI(*sinkMBB, sinkMBB->begin(), DL,
- TII->get(PPC::PHI), DstReg)
- .addReg(mainDstReg).addMBB(mainMBB)
- .addReg(restoreDstReg).addMBB(thisMBB);
-
- MI.eraseFromParent();
- return sinkMBB;
-}
-
-MachineBasicBlock *PPCTargetLowering::emitSetJmp(MachineInstr &MI,
- MachineBasicBlock *MBB) const {
- DebugLoc DL = MI.getDebugLoc();
- const TargetInstrInfo *TII = Subtarget.getInstrInfo();
- const PPCRegisterInfo *TRI = Subtarget.getRegisterInfo();
-
- MachineFunction *MF = MBB->getParent();
- MachineRegisterInfo &MRI = MF->getRegInfo();
-
- const BasicBlock *BB = MBB->getBasicBlock();
- MachineFunction::iterator I = ++MBB->getIterator();
-
- Register DstReg = MI.getOperand(0).getReg();
- const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
- assert(TRI->isTypeLegalForClass(*RC, MVT::i32) && "Invalid destination!");
- Register mainDstReg = MRI.createVirtualRegister(RC);
- Register restoreDstReg = MRI.createVirtualRegister(RC);
-
- MVT PVT = getPointerTy(MF->getDataLayout());
- assert((PVT == MVT::i64 || PVT == MVT::i32) && "Invalid Pointer Size!");
-
- MachineBasicBlock *thisMBB = MBB;
- MachineBasicBlock *mainMBB = MF->CreateMachineBasicBlock(BB);
- MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(BB);
- MF->insert(I, mainMBB);
- MF->insert(I, sinkMBB);
-
- MachineInstrBuilder MIB;
-
- // Transfer the remainder of BB and its successor edges to sinkMBB.
- sinkMBB->splice(sinkMBB->begin(), MBB,
- std::next(MachineBasicBlock::iterator(MI)), MBB->end());
- sinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
-
// Buffer layout:
// buf[0] = Frame Pointer
// buf[1] = IP (return address / LR)
// buf[2] = Stack Pointer
// buf[3] = TOC pointer (R2, 64-bit ELF only)
// buf[4] = Base Pointer
- const int64_t FPOffset = 0;
+
+ // thisMBB:
+ const int64_t FPOffset = 0;
const int64_t LabelOffset = 1 * PVT.getStoreSize();
- const int64_t SPOffset = 2 * PVT.getStoreSize();
- const int64_t TOCOffset = 3 * PVT.getStoreSize();
- const int64_t BPOffset = 4 * PVT.getStoreSize();
+ const int64_t SPOffset = 2 * PVT.getStoreSize();
+ const int64_t TOCOffset = 3 * PVT.getStoreSize();
+ const int64_t BPOffset = 4 * PVT.getStoreSize();
+ // Prepare IP either in reg.
const TargetRegisterClass *PtrRC = getRegClassFor(PVT);
Register LabelReg = MRI.createVirtualRegister(PtrRC);
Register BufReg = MI.getOperand(1).getReg();
@@ -13672,7 +13540,8 @@ MachineBasicBlock *PPCTargetLowering::emitSetJmp(MachineInstr &MI,
.cloneMemRefs(MI);
}
- // Store BP.
+ // Naked functions never have a base pointer, and so we use r1. For all
+ // other functions, this decision must be delayed until during PEI.
unsigned BaseReg;
if (MF->getFunction().hasFnAttribute(Attribute::Naked))
BaseReg = Subtarget.isPPC64() ? PPC::X1 : PPC::R1;
@@ -13692,7 +13561,8 @@ MachineBasicBlock *PPCTargetLowering::emitSetJmp(MachineInstr &MI,
BuildMI(*thisMBB, MI, DL, TII->get(PPC::LI), restoreDstReg).addImm(1);
- MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::EH_SjLj_Setup)).addMBB(mainMBB);
+ MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::EH_SjLj_Setup))
+ .addMBB(mainMBB);
MIB = BuildMI(*thisMBB, MI, DL, TII->get(PPC::B)).addMBB(sinkMBB);
thisMBB->addSuccessor(mainMBB, BranchProbability::getZero());
@@ -13707,14 +13577,14 @@ MachineBasicBlock *PPCTargetLowering::emitSetJmp(MachineInstr &MI,
// Store IP
if (Subtarget.isPPC64()) {
MIB = BuildMI(mainMBB, DL, TII->get(PPC::STD))
- .addReg(LabelReg)
- .addImm(LabelOffset)
- .addReg(BufReg);
+ .addReg(LabelReg)
+ .addImm(LabelOffset)
+ .addReg(BufReg);
} else {
MIB = BuildMI(mainMBB, DL, TII->get(PPC::STW))
- .addReg(LabelReg)
- .addImm(LabelOffset)
- .addReg(BufReg);
+ .addReg(LabelReg)
+ .addImm(LabelOffset)
+ .addReg(BufReg);
}
MIB.cloneMemRefs(MI);
@@ -13722,11 +13592,10 @@ MachineBasicBlock *PPCTargetLowering::emitSetJmp(MachineInstr &MI,
mainMBB->addSuccessor(sinkMBB);
// sinkMBB:
- BuildMI(*sinkMBB, sinkMBB->begin(), DL, TII->get(PPC::PHI), DstReg)
- .addReg(mainDstReg)
- .addMBB(mainMBB)
- .addReg(restoreDstReg)
- .addMBB(thisMBB);
+ BuildMI(*sinkMBB, sinkMBB->begin(), DL,
+ TII->get(PPC::PHI), DstReg)
+ .addReg(mainDstReg).addMBB(mainMBB)
+ .addReg(restoreDstReg).addMBB(thisMBB);
MI.eraseFromParent();
return sinkMBB;
@@ -14085,9 +13954,6 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
if (MI.getOpcode() == PPC::EH_SjLj_SetJmp32 ||
MI.getOpcode() == PPC::EH_SjLj_SetJmp64) {
return emitEHSjLjSetJmp(MI, BB);
- } else if (MI.getOpcode() == PPC::SetJmp32 ||
- MI.getOpcode() == PPC::SetJmp64) {
- return emitSetJmp(MI, BB);
} else if (MI.getOpcode() == PPC::EH_SjLj_LongJmp32 ||
MI.getOpcode() == PPC::EH_SjLj_LongJmp64) {
return emitEHSjLjLongJmp(MI, BB);
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index b084bed075b73..cfcc6b5f03edc 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -386,8 +386,6 @@ namespace llvm {
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
- MachineBasicBlock *emitSetJmp(MachineInstr &MI,
- MachineBasicBlock *MBB) const;
MachineBasicBlock *emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
@@ -860,7 +858,6 @@ namespace llvm {
const CallBase *CB) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
- SDValue lowerSETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBITCAST(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td
index c4540c132c153..2b62654b08986 100644
--- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td
+++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td
@@ -506,16 +506,11 @@ def MFCR8 : XFXForm_3<31, 19, (outs g8rc:$RT), (ins),
// While longjmp is a control-flow barrier (fallthrough isn't allowed), setjmp
// is not.
let hasSideEffects = 1 in {
- let Defs = [CTR8] in {
+ let Defs = [CTR8] in
def EH_SjLj_SetJmp64 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins memr:$buf),
"#EH_SJLJ_SETJMP64",
[(set i32:$dst, (PPCeh_sjlj_setjmp addr:$buf))]>,
Requires<[IsPPC64]>;
- def SetJmp64 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins memr:$buf),
- "#SETJMP64",
- [(set i32:$dst, (PPCsetjmp addr:$buf))]>,
- Requires<[IsPPC64]>;
- }
}
let hasSideEffects = 1, isBarrier = 1 in {
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
index ba07e318f6e8e..3271e4d279f56 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
@@ -590,10 +590,6 @@ def PPCeh_sjlj_setjmp : SDNode<"PPCISD::EH_SJLJ_SETJMP",
SDTypeProfile<1, 1, [SDTCisInt<0>,
SDTCisPtrTy<1>]>,
[SDNPHasChain, SDNPSideEffect]>;
-def PPCsetjmp : SDNode<"PPCISD::SETJMP",
- SDTypeProfile<1, 1, [SDTCisInt<0>,
- SDTCisPtrTy<1>]>,
- [SDNPHasChain, SDNPSideEffect]>;
// EH_SJLJ_LONGJMP - SjLj exception handling longjmp.
def PPCeh_sjlj_longjmp : SDNode<"PPCISD::EH_SJLJ_LONGJMP",
@@ -1899,16 +1895,11 @@ def TAILBA : IForm<18, 0, 0, (outs), (ins abscalltarget:$LI),
// While longjmp is a control-flow barrier (fallthrough isn't allowed), setjmp
// is not.
let hasSideEffects = 1 in {
- let Defs = [CTR] in {
+ let Defs = [CTR] in
def EH_SjLj_SetJmp32 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins memr:$buf),
"#EH_SJLJ_SETJMP32",
[(set i32:$dst, (PPCeh_sjlj_setjmp addr:$buf))]>,
Requires<[IsPPC32]>;
- def SetJmp32 : PPCCustomInserterPseudo<(outs gprc:$dst), (ins memr:$buf),
- "#SETJMP32",
- [(set i32:$dst, (PPCsetjmp addr:$buf))]>,
- Requires<[IsPPC32]>;
- }
}
let hasSideEffects = 1, isBarrier = 1 in {
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 0a799d53c0619..84d66f88a812d 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -808,7 +808,6 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
// We're not using SJLJ for exception handling, but they're implemented
// solely to support use of __builtin_setjmp / __builtin_longjmp.
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
- setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
// We want to use MVC in preference to even a single load/store pair.
@@ -1182,14 +1181,6 @@ SystemZTargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
return SinkMBB;
}
-MachineBasicBlock *
-SystemZTargetLowering::emitSetJmp(MachineInstr &MI,
- MachineBasicBlock *MBB) const {
- // emitSetJmp is identical to emitEHSjLjSetJmp because the SystemZ
- // implementation of emitEHSjLjSetJmp already stores FP, SP, and IP
- return emitEHSjLjSetJmp(MI, MBB);
-}
-
MachineBasicBlock *
SystemZTargetLowering::emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const {
@@ -7307,7 +7298,6 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
case ISD::READCYCLECOUNTER:
return lowerREADCYCLECOUNTER(Op, DAG);
case ISD::EH_SJLJ_SETJMP:
- case ISD::SETJMP:
case ISD::EH_SJLJ_LONGJMP:
// These operations are legal on our platform, but we cannot actually
// set the operation action to Legal as common code would treat this
@@ -11202,8 +11192,6 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
return emitProbedAlloca(MI, MBB);
case SystemZ::EH_SjLj_SetJmp:
return emitEHSjLjSetJmp(MI, MBB);
- case SystemZ::SetJmp:
- return emitSetJmp(MI, MBB);
case SystemZ::EH_SjLj_LongJmp:
return emitEHSjLjLongJmp(MI, MBB);
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index 9bee8e24ddf71..bb3eeba6446d2 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -115,7 +115,6 @@ class SystemZTargetLowering : public TargetLowering {
}
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
- MachineBasicBlock *emitSetJmp(MachineInstr &MI, MachineBasicBlock *MBB) const;
MachineBasicBlock *emitEHSjLjLongJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 6755578236b46..e80fde06e7373 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -1922,8 +1922,6 @@ let isBarrier = 1, hasNoSchedulingInfo = 1 in {
let hasSideEffects = 1, usesCustomInserter = 1 in {
def EH_SjLj_SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2),
[(set GR32:$dst, (z_eh_sjlj_setjmp ADDR64:$R2))]>;
- def SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2),
- [(set GR32:$dst, (z_setjmp ADDR64:$R2))]>;
let isTerminator = 1 in {
def EH_SjLj_LongJmp : Pseudo<(outs), (ins ADDR64:$R2),
[(z_eh_sjlj_longjmp ADDR64:$R2)]>;
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index 36597fb5ecafd..2a5b0435c1565 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -414,8 +414,6 @@ def z_tdc : SDNode<"SystemZISD::TDC", SDT_ZTest>;
def z_eh_sjlj_setjmp : SDNode<"ISD::EH_SJLJ_SETJMP", SDT_ZSetJmp,
[SDNPHasChain, SDNPSideEffect]>;
-def z_setjmp : SDNode<"ISD::SETJMP", SDT_ZSetJmp,
- [SDNPHasChain, SDNPSideEffect]>;
def z_eh_sjlj_longjmp : SDNode<"ISD::EH_SJLJ_LONGJMP", SDT_ZLongJmp,
[SDNPHasChain, SDNPSideEffect]>;
diff --git a/llvm/lib/Target/VE/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp
index 027ad831f74f4..9111364e7b56a 100644
--- a/llvm/lib/Target/VE/VEISelLowering.cpp
+++ b/llvm/lib/Target/VE/VEISelLowering.cpp
@@ -298,7 +298,6 @@ void VETargetLowering::initSPUActions() {
/// SJLJ instructions {
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
- setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom);
/// } SJLJ instructions
@@ -1664,12 +1663,6 @@ SDValue VETargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
Op.getOperand(1));
}
-SDValue VETargetLowering::lowerSETJMP(SDValue Op, SelectionDAG &DAG) const {
- SDLoc DL(Op);
- return DAG.getNode(VEISD::SETJMP, DL, DAG.getVTList(MVT::i32, MVT::Other),
- Op.getOperand(0), Op.getOperand(1));
-}
-
SDValue VETargetLowering::lowerEH_SJLJ_SETUP_DISPATCH(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
@@ -1840,8 +1833,6 @@ SDValue VETargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
return lowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::EH_SJLJ_SETJMP:
return lowerEH_SJLJ_SETJMP(Op, DAG);
- case ISD::SETJMP:
- return lowerSETJMP(Op, DAG);
case ISD::EH_SJLJ_SETUP_DISPATCH:
return lowerEH_SJLJ_SETUP_DISPATCH(Op, DAG);
case ISD::FRAMEADDR:
@@ -2184,121 +2175,6 @@ VETargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
std::next(MachineBasicBlock::iterator(MI)), MBB->end());
SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
- // ThisMBB:
- Register LabelReg =
- prepareMBB(*MBB, MachineBasicBlock::iterator(MI), RestoreMBB, DL);
-
- // Store BP in buf[3] iff this function is using BP.
- const VEFrameLowering *TFI = Subtarget->getFrameLowering();
- if (TFI->hasBP(*MF)) {
- MachineInstrBuilder MIB = BuildMI(*MBB, MI, DL, TII->get(VE::STrii));
- MIB.addReg(BufReg);
- MIB.addImm(0);
- MIB.addImm(24);
- MIB.addReg(VE::SX17);
- MIB.setMemRefs(MMOs);
- }
-
- // Store IP in buf[1].
- MachineInstrBuilder MIB = BuildMI(*MBB, MI, DL, TII->get(VE::STrii));
- MIB.add(MI.getOperand(1)); // we can preserve the kill flags here.
- MIB.addImm(0);
- MIB.addImm(8);
- MIB.addReg(LabelReg, getKillRegState(true));
- MIB.setMemRefs(MMOs);
-
- // SP/FP are already stored in jmpbuf before `llvm.eh.sjlj.setjmp`.
-
- // Insert setup.
- MIB =
- BuildMI(*ThisMBB, MI, DL, TII->get(VE::EH_SjLj_Setup)).addMBB(RestoreMBB);
-
- const VERegisterInfo *RegInfo = Subtarget->getRegisterInfo();
- MIB.addRegMask(RegInfo->getNoPreservedMask());
- ThisMBB->addSuccessor(MainMBB);
- ThisMBB->addSuccessor(RestoreMBB);
-
- // MainMBB:
- BuildMI(MainMBB, DL, TII->get(VE::LEAzii), MainDestReg)
- .addImm(0)
- .addImm(0)
- .addImm(0);
- MainMBB->addSuccessor(SinkMBB);
-
- // SinkMBB:
- BuildMI(*SinkMBB, SinkMBB->begin(), DL, TII->get(VE::PHI), DstReg)
- .addReg(MainDestReg)
- .addMBB(MainMBB)
- .addReg(RestoreDestReg)
- .addMBB(RestoreMBB);
-
- // RestoreMBB:
- // Restore BP from buf[3] iff this function is using BP. The address of
- // buf is in SX10.
- // FIXME: Better to not use SX10 here
- if (TFI->hasBP(*MF)) {
- MachineInstrBuilder MIB =
- BuildMI(RestoreMBB, DL, TII->get(VE::LDrii), VE::SX17);
- MIB.addReg(VE::SX10);
- MIB.addImm(0);
- MIB.addImm(24);
- MIB.setMemRefs(MMOs);
- }
- BuildMI(RestoreMBB, DL, TII->get(VE::LEAzii), RestoreDestReg)
- .addImm(0)
- .addImm(0)
- .addImm(1);
- BuildMI(RestoreMBB, DL, TII->get(VE::BRCFLa_t)).addMBB(SinkMBB);
- RestoreMBB->addSuccessor(SinkMBB);
-
- MI.eraseFromParent();
- return SinkMBB;
-}
-
-MachineBasicBlock *VETargetLowering::emitSetJmp(MachineInstr &MI,
- MachineBasicBlock *MBB) const {
- DebugLoc DL = MI.getDebugLoc();
- MachineFunction *MF = MBB->getParent();
- const TargetInstrInfo *TII = Subtarget->getInstrInfo();
- const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo();
- MachineRegisterInfo &MRI = MF->getRegInfo();
-
- const BasicBlock *BB = MBB->getBasicBlock();
- MachineFunction::iterator I = ++MBB->getIterator();
-
- // Memory Reference.
- SmallVector<MachineMemOperand *, 2> MMOs(MI.memoperands());
- Register BufReg = MI.getOperand(1).getReg();
-
- Register DstReg;
-
- DstReg = MI.getOperand(0).getReg();
- const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
- assert(TRI->isTypeLegalForClass(*RC, MVT::i32) && "Invalid destination!");
- (void)TRI;
- Register MainDestReg = MRI.createVirtualRegister(RC);
- Register RestoreDestReg = MRI.createVirtualRegister(RC);
-
- // Buffer layout:
- // buf[0] = Frame Pointer (SX9, offset 0)
- // buf[1] = IP (offset 8)
- // buf[2] = Stack Pointer (SX11, offset 16)
- // buf[3] = Base Pointer (SX17, offset 24)
-
- MachineBasicBlock *ThisMBB = MBB;
- MachineBasicBlock *MainMBB = MF->CreateMachineBasicBlock(BB);
- MachineBasicBlock *SinkMBB = MF->CreateMachineBasicBlock(BB);
- MachineBasicBlock *RestoreMBB = MF->CreateMachineBasicBlock(BB);
- MF->insert(I, MainMBB);
- MF->insert(I, SinkMBB);
- MF->push_back(RestoreMBB);
- RestoreMBB->setMachineBlockAddressTaken();
-
- // Transfer the remainder of BB and its successor edges to SinkMBB.
- SinkMBB->splice(SinkMBB->begin(), MBB,
- std::next(MachineBasicBlock::iterator(MI)), MBB->end());
- SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
-
// ThisMBB:
Register LabelReg =
prepareMBB(*MBB, MachineBasicBlock::iterator(MI), RestoreMBB, DL);
@@ -2768,8 +2644,6 @@ VETargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
return emitEHSjLjLongJmp(MI, BB);
case VE::EH_SjLj_SetJmp:
return emitEHSjLjSetJmp(MI, BB);
- case VE::SetJmp:
- return emitSetJmp(MI, BB);
case VE::EH_SjLj_Setup_Dispatch:
return emitSjLjDispatchBlock(MI, BB);
}
diff --git a/llvm/lib/Target/VE/VEISelLowering.h b/llvm/lib/Target/VE/VEISelLowering.h
index 9d410b8c2be84..487804194757e 100644
--- a/llvm/lib/Target/VE/VEISelLowering.h
+++ b/llvm/lib/Target/VE/VEISelLowering.h
@@ -190,7 +190,6 @@ class VETargetLowering : public TargetLowering {
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETUP_DISPATCH(SDValue Op, SelectionDAG &DAG) const;
- SDValue lowerSETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
@@ -220,7 +219,6 @@ class VETargetLowering : public TargetLowering {
MachineBasicBlock *MBB) const;
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
- MachineBasicBlock *emitSetJmp(MachineInstr &MI, MachineBasicBlock *MBB) const;
MachineBasicBlock *emitSjLjDispatchBlock(MachineInstr &MI,
MachineBasicBlock *BB) const;
diff --git a/llvm/lib/Target/VE/VEInstrInfo.td b/llvm/lib/Target/VE/VEInstrInfo.td
index fdffa9a434201..9869f95ae5661 100644
--- a/llvm/lib/Target/VE/VEInstrInfo.td
+++ b/llvm/lib/Target/VE/VEInstrInfo.td
@@ -465,10 +465,6 @@ def VEeh_sjlj_setjmp: SDNode<"VEISD::EH_SJLJ_SETJMP",
SDTypeProfile<1, 1, [SDTCisInt<0>,
SDTCisPtrTy<1>]>,
[SDNPHasChain, SDNPSideEffect]>;
-def VEsetjmp: SDNode<"VEISD::SETJMP",
- SDTypeProfile<1, 1, [SDTCisInt<0>,
- SDTCisPtrTy<1>]>,
- [SDNPHasChain, SDNPSideEffect]>;
def VEeh_sjlj_longjmp: SDNode<"VEISD::EH_SJLJ_LONGJMP",
SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>,
[SDNPHasChain, SDNPSideEffect]>;
@@ -1921,9 +1917,6 @@ let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
def EH_SjLj_SetJmp : Pseudo<(outs I32:$dst), (ins I64:$buf),
"# EH_SJLJ_SETJMP",
[(set I32:$dst, (VEeh_sjlj_setjmp I64:$buf))]>;
- def SetJmp : Pseudo<(outs I32:$dst), (ins I64:$buf),
- "# SETJMP",
- [(set I32:$dst, (VEsetjmp I64:$buf))]>;
def EH_SjLj_Setup_Dispatch : Pseudo<(outs), (ins), "# EH_SJLJ_SETUP_DISPATCH",
[(VEeh_sjlj_setup_dispatch)]>;
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index b0c73ab38c49f..5fdad92c5ba12 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -3035,7 +3035,6 @@ bool X86DAGToDAGISel::selectAddr(SDNode *Parent, SDValue N, SDValue &Base,
Parent->getOpcode() != X86ISD::ENQCMD && // Fixme
Parent->getOpcode() != X86ISD::ENQCMDS && // Fixme
Parent->getOpcode() != X86ISD::EH_SJLJ_SETJMP && // setjmp
- Parent->getOpcode() != X86ISD::SETJMP && // setjmp
Parent->getOpcode() != X86ISD::EH_SJLJ_LONGJMP) { // longjmp
unsigned AddrSpace =
cast<MemSDNode>(Parent)->getPointerInfo().getAddrSpace();
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index f83c2bd870e9e..5e5ce34e685e5 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -510,7 +510,6 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
// NOTE: EH_SJLJ_SETJMP/_LONGJMP are not recommended, since
// LLVM/Clang supports zero-cost DWARF and SEH exception handling.
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
- setOperationAction(ISD::SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom);
@@ -28914,16 +28913,6 @@ SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
Op.getOperand(0), Op.getOperand(1));
}
-SDValue X86TargetLowering::lowerSETJMP(SDValue Op, SelectionDAG &DAG) const {
- SDLoc DL(Op);
- if (!Subtarget.is64Bit()) {
- const X86InstrInfo *TII = Subtarget.getInstrInfo();
- (void)TII->getGlobalBaseReg(&DAG.getMachineFunction());
- }
- return DAG.getNode(X86ISD::SETJMP, DL, DAG.getVTList(MVT::i32, MVT::Other),
- Op.getOperand(0), Op.getOperand(1));
-}
-
SDValue X86TargetLowering::lowerEH_SJLJ_LONGJMP(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
@@ -34220,7 +34209,6 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG);
- case ISD::SETJMP: return lowerSETJMP(Op, DAG);
case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
case ISD::EH_SJLJ_SETUP_DISPATCH:
return lowerEH_SJLJ_SETUP_DISPATCH(Op, DAG);
@@ -37592,143 +37580,7 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
- if (MF->getFunction().getParent()->getModuleFlag("cf-protection-return")) {
- emitSetJmpShadowStackFix(MI, thisMBB);
- }
-
- // Setup
- MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(X86::EH_SjLj_Setup))
- .addMBB(restoreMBB);
-
- MIB.addRegMask(RegInfo->getNoPreservedMask());
- thisMBB->addSuccessor(mainMBB);
- thisMBB->addSuccessor(restoreMBB);
-
- // mainMBB:
- // EAX = 0
- BuildMI(mainMBB, MIMD, TII->get(X86::MOV32r0), mainDstReg);
- mainMBB->addSuccessor(sinkMBB);
-
- // sinkMBB:
- BuildMI(*sinkMBB, sinkMBB->begin(), MIMD, TII->get(X86::PHI), DstReg)
- .addReg(mainDstReg)
- .addMBB(mainMBB)
- .addReg(restoreDstReg)
- .addMBB(restoreMBB);
-
- // restoreMBB:
- if (RegInfo->hasBasePointer(*MF)) {
- const bool Uses64BitFramePtr = Subtarget.isTarget64BitLP64();
- X86MachineFunctionInfo *X86FI = MF->getInfo<X86MachineFunctionInfo>();
- X86FI->setRestoreBasePointer(MF);
- Register FramePtr = RegInfo->getFrameRegister(*MF);
- Register BasePtr = RegInfo->getBaseRegister();
- unsigned Opm = Uses64BitFramePtr ? X86::MOV64rm : X86::MOV32rm;
- addRegOffset(BuildMI(restoreMBB, MIMD, TII->get(Opm), BasePtr),
- FramePtr, true, X86FI->getRestoreBasePointerOffset())
- .setMIFlag(MachineInstr::FrameSetup);
- }
- BuildMI(restoreMBB, MIMD, TII->get(X86::MOV32ri), restoreDstReg).addImm(1);
- BuildMI(restoreMBB, MIMD, TII->get(X86::JMP_1)).addMBB(sinkMBB);
- restoreMBB->addSuccessor(sinkMBB);
-
- MI.eraseFromParent();
- return sinkMBB;
-}
-
-// Expand @llvm.setjmp pseudo. Like emitEHSjLjSetJmp but the backend is
-// responsible for storing FP and SP into the buffer (the frontend does not
-// emit @llvm.frameaddress / @llvm.stacksave stores).
-MachineBasicBlock *X86TargetLowering::emitSetJmp(MachineInstr &MI,
- MachineBasicBlock *MBB) const {
- const MIMetadata MIMD(MI);
- MachineFunction *MF = MBB->getParent();
- const TargetInstrInfo *TII = Subtarget.getInstrInfo();
- const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
- MachineRegisterInfo &MRI = MF->getRegInfo();
-
- const BasicBlock *BB = MBB->getBasicBlock();
- MachineFunction::iterator I = ++MBB->getIterator();
-
- SmallVector<MachineMemOperand *, 2> MMOs(MI.memoperands());
-
- unsigned MemOpndSlot = 0;
- unsigned CurOp = 0;
-
- Register DstReg = MI.getOperand(CurOp++).getReg();
- const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
- assert(TRI->isTypeLegalForClass(*RC, MVT::i32) && "Invalid destination!");
- (void)TRI;
- Register mainDstReg = MRI.createVirtualRegister(RC);
- Register restoreDstReg = MRI.createVirtualRegister(RC);
-
- MemOpndSlot = CurOp;
-
- MVT PVT = getPointerTy(MF->getDataLayout());
- assert((PVT == MVT::i64 || PVT == MVT::i32) && "Invalid Pointer Size!");
-
- MachineBasicBlock *thisMBB = MBB;
- MachineBasicBlock *mainMBB = MF->CreateMachineBasicBlock(BB);
- MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(BB);
- MachineBasicBlock *restoreMBB = MF->CreateMachineBasicBlock(BB);
- MF->insert(I, mainMBB);
- MF->insert(I, sinkMBB);
- MF->push_back(restoreMBB);
- restoreMBB->setMachineBlockAddressTaken();
-
- MachineInstrBuilder MIB;
-
- sinkMBB->splice(sinkMBB->begin(), MBB,
- std::next(MachineBasicBlock::iterator(MI)), MBB->end());
- sinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
-
- // thisMBB:
- unsigned PtrStoreOpc = 0;
- Register LabelReg;
- const int64_t LabelOffset = 1 * PVT.getStoreSize();
- bool UseImmLabel = (MF->getTarget().getCodeModel() == CodeModel::Small) &&
- !isPositionIndependent();
-
- // Prepare IP either in reg or imm.
- if (!UseImmLabel) {
- PtrStoreOpc = (PVT == MVT::i64) ? X86::MOV64mr : X86::MOV32mr;
- const TargetRegisterClass *PtrRC = getRegClassFor(PVT);
- LabelReg = MRI.createVirtualRegister(PtrRC);
- if (Subtarget.is64Bit()) {
- MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(X86::LEA64r), LabelReg)
- .addReg(X86::RIP)
- .addImm(0)
- .addReg(0)
- .addMBB(restoreMBB)
- .addReg(0);
- } else {
- const X86InstrInfo *XII = static_cast<const X86InstrInfo *>(TII);
- MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(X86::LEA32r), LabelReg)
- .addReg(XII->getGlobalBaseReg(MF))
- .addImm(0)
- .addReg(0)
- .addMBB(restoreMBB, Subtarget.classifyBlockAddressReference())
- .addReg(0);
- }
- } else
- PtrStoreOpc = (PVT == MVT::i64) ? X86::MOV64mi32 : X86::MOV32mi;
-
- // Store IP to buf[1].
- MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(PtrStoreOpc));
- for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
- if (i == X86::AddrDisp)
- MIB.addDisp(MI.getOperand(MemOpndSlot + i), LabelOffset);
- else
- MIB.add(MI.getOperand(MemOpndSlot + i));
- }
- if (!UseImmLabel)
- MIB.addReg(LabelReg);
- else
- MIB.addMBB(restoreMBB);
- MIB.setMemRefs(MMOs);
-
// Store FP to buf[0] and SP to buf[2].
- const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
unsigned RegStoreOpc = (PVT == MVT::i64) ? X86::MOV64mr : X86::MOV32mr;
bool HasFP = Subtarget.getFrameLowering()->hasFP(*MF);
@@ -37757,13 +37609,14 @@ MachineBasicBlock *X86TargetLowering::emitSetJmp(MachineInstr &MI,
// Setup
MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(X86::EH_SjLj_Setup))
- .addMBB(restoreMBB);
+ .addMBB(restoreMBB);
MIB.addRegMask(RegInfo->getNoPreservedMask());
thisMBB->addSuccessor(mainMBB);
thisMBB->addSuccessor(restoreMBB);
// mainMBB:
+ // EAX = 0
BuildMI(mainMBB, MIMD, TII->get(X86::MOV32r0), mainDstReg);
mainMBB->addSuccessor(sinkMBB);
@@ -37782,9 +37635,9 @@ MachineBasicBlock *X86TargetLowering::emitSetJmp(MachineInstr &MI,
Register FramePtr = RegInfo->getFrameRegister(*MF);
Register BasePtr = RegInfo->getBaseRegister();
unsigned Opm = Uses64BitFramePtr ? X86::MOV64rm : X86::MOV32rm;
- addRegOffset(BuildMI(restoreMBB, MIMD, TII->get(Opm), BasePtr), FramePtr,
- true, X86FI->getRestoreBasePointerOffset())
- .setMIFlag(MachineInstr::FrameSetup);
+ addRegOffset(BuildMI(restoreMBB, MIMD, TII->get(Opm), BasePtr),
+ FramePtr, true, X86FI->getRestoreBasePointerOffset())
+ .setMIFlag(MachineInstr::FrameSetup);
}
BuildMI(restoreMBB, MIMD, TII->get(X86::MOV32ri), restoreDstReg).addImm(1);
BuildMI(restoreMBB, MIMD, TII->get(X86::JMP_1)).addMBB(sinkMBB);
@@ -38579,10 +38432,6 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case X86::EH_SjLj_SetJmp64:
return emitEHSjLjSetJmp(MI, BB);
- case X86::SetJmp32:
- case X86::SetJmp64:
- return emitSetJmp(MI, BB);
-
case X86::EH_SjLj_LongJmp32:
case X86::EH_SjLj_LongJmp64:
return emitEHSjLjLongJmp(MI, BB);
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index 1274089fea7da..5c7c54cacd239 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -823,7 +823,6 @@ namespace llvm {
ISD::ArgFlagsTy Flags) const;
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
- SDValue lowerSETJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_SJLJ_SETUP_DISPATCH(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
@@ -929,8 +928,6 @@ namespace llvm {
MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
MachineBasicBlock *MBB) const;
- MachineBasicBlock *emitSetJmp(MachineInstr &MI,
- MachineBasicBlock *MBB) const;
void emitSetJmpShadowStackFix(MachineInstr &MI,
MachineBasicBlock *MBB) const;
diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index 847d141d1ce90..bc05dae7351bb 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -214,14 +214,6 @@ let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
"#EH_SJLJ_SETJMP64",
[(set GR32:$dst, (X86eh_sjlj_setjmp addr:$buf))]>,
Requires<[In64BitMode]>;
- def SetJmp32 : I<0, Pseudo, (outs GR32:$dst), (ins i32mem:$buf),
- "#SETJMP32",
- [(set GR32:$dst, (X86setjmp addr:$buf))]>,
- Requires<[Not64BitMode]>;
- def SetJmp64 : I<0, Pseudo, (outs GR32:$dst), (ins i64mem:$buf),
- "#SETJMP64",
- [(set GR32:$dst, (X86setjmp addr:$buf))]>,
- Requires<[In64BitMode]>;
let isTerminator = 1 in {
def EH_SjLj_LongJmp32 : I<0, Pseudo, (outs), (ins i32mem:$buf),
"#EH_SJLJ_LONGJMP32",
diff --git a/llvm/lib/Target/X86/X86InstrFragments.td b/llvm/lib/Target/X86/X86InstrFragments.td
index fe59fbfc6201b..3cd05ab0351bd 100644
--- a/llvm/lib/Target/X86/X86InstrFragments.td
+++ b/llvm/lib/Target/X86/X86InstrFragments.td
@@ -352,10 +352,6 @@ def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP",
SDTypeProfile<1, 1, [SDTCisInt<0>,
SDTCisPtrTy<1>]>,
[SDNPHasChain, SDNPSideEffect]>;
-def X86setjmp : SDNode<"X86ISD::SETJMP",
- SDTypeProfile<1, 1, [SDTCisInt<0>,
- SDTCisPtrTy<1>]>,
- [SDNPHasChain, SDNPSideEffect]>;
// SjLj exception handling longjmp.
def X86eh_sjlj_longjmp : SDNode<"X86ISD::EH_SJLJ_LONGJMP",
diff --git a/llvm/test/CodeGen/ARM/setjmp.ll b/llvm/test/CodeGen/ARM/setjmp.ll
index e322bbe4d5d12..27561a6a86516 100644
--- a/llvm/test/CodeGen/ARM/setjmp.ll
+++ b/llvm/test/CodeGen/ARM/setjmp.ll
@@ -1,47 +1,21 @@
; RUN: llc < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=ARM %s
; RUN: llc < %s -mtriple=thumbv7-apple-ios | FileCheck --check-prefix=THUMB2 %s
-; Verify that @llvm.setjmp produces the same FP/SP stores as the old pattern
-; of @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
+; Verify that @llvm.eh.sjlj.setjmp stores FP and SP into the buffer.
@buf = internal global [5 x ptr] zeroinitializer
-; --- Old pattern (frameaddress + stacksave + stores + eh.sjlj.setjmp) ---
-
-declare ptr @llvm.frameaddress(i32) nounwind readnone
-declare ptr @llvm.stacksave() nounwind
declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
-define i32 @old_setjmp() nounwind "frame-pointer"="all" {
- %fp = call ptr @llvm.frameaddress(i32 0)
- store ptr %fp, ptr @buf, align 16
- %sp = call ptr @llvm.stacksave()
- store ptr %sp, ptr getelementptr inbounds ([5 x ptr], ptr @buf, i64 0, i64 2), align 16
+define i32 @setjmp_test() nounwind "frame-pointer"="all" {
%r = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
ret i32 %r
}
-; --- New pattern (@llvm.setjmp) ---
-
-declare i32 @llvm.setjmp(ptr) nounwind
-
-define i32 @new_setjmp() nounwind "frame-pointer"="all" {
- %r = call i32 @llvm.setjmp(ptr @buf)
- ret i32 %r
-}
-
-; Both functions should store FP (r7) to buf[0] and SP to buf[2].
-
-; ARM-LABEL: _old_setjmp:
-; ARM: str r7, [r0]
-; ARM: str sp, [r0, #8]
-; ARM-LABEL: _new_setjmp:
+; ARM-LABEL: _setjmp_test:
; ARM: str r7, [r0]
; ARM: str sp, [r0, #8]
-; THUMB2-LABEL: _old_setjmp:
-; THUMB2: str r7, [r0]
-; THUMB2: str.w sp, [r0, #8]
-; THUMB2-LABEL: _new_setjmp:
+; THUMB2-LABEL: _setjmp_test:
; THUMB2: str r7, [r0]
; THUMB2: str.w sp, [r0, #8]
diff --git a/llvm/test/CodeGen/PowerPC/setjmp.ll b/llvm/test/CodeGen/PowerPC/setjmp.ll
index f0b86a790c488..c0ba66ca78dc8 100644
--- a/llvm/test/CodeGen/PowerPC/setjmp.ll
+++ b/llvm/test/CodeGen/PowerPC/setjmp.ll
@@ -1,39 +1,16 @@
; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 -verify-machineinstrs | FileCheck %s
-; Verify that @llvm.setjmp produces the same FP/SP stores as the old pattern
-; of @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
+; Verify that @llvm.eh.sjlj.setjmp stores FP and SP into the buffer.
@buf = internal global [5 x ptr] zeroinitializer, align 8
-; --- Old pattern (frameaddress + stacksave + stores + eh.sjlj.setjmp) ---
-
-declare ptr @llvm.frameaddress(i32) nounwind readnone
-declare ptr @llvm.stacksave() nounwind
declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
-define i32 @old_setjmp() nounwind "frame-pointer"="all" {
- %fp = call ptr @llvm.frameaddress(i32 0)
- store ptr %fp, ptr @buf, align 8
- %sp = call ptr @llvm.stacksave()
- store ptr %sp, ptr getelementptr inbounds (ptr, ptr @buf, i64 2), align 8
+define i32 @setjmp_test() nounwind "frame-pointer"="all" {
%r = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
ret i32 %r
}
-; --- New pattern (@llvm.setjmp) ---
-
-declare i32 @llvm.setjmp(ptr) nounwind
-
-define i32 @new_setjmp() nounwind "frame-pointer"="all" {
- %r = call i32 @llvm.setjmp(ptr @buf)
- ret i32 %r
-}
-
-; Both functions should store FP (r31) to buf[0] and SP (r1) to buf[2] (offset 16).
-
-; CHECK-LABEL: old_setjmp:
-; CHECK: std 31, buf at toc@l(
-; CHECK: std 1, 16(
-; CHECK-LABEL: new_setjmp:
+; CHECK-LABEL: setjmp_test:
; CHECK: std 31, 0(
; CHECK: std 1, 16(
diff --git a/llvm/test/CodeGen/SystemZ/setjmp.ll b/llvm/test/CodeGen/SystemZ/setjmp.ll
index 01c78e58aff2d..ca5fe12186132 100644
--- a/llvm/test/CodeGen/SystemZ/setjmp.ll
+++ b/llvm/test/CodeGen/SystemZ/setjmp.ll
@@ -1,35 +1,16 @@
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
-; Verify that @llvm.setjmp produces the same IP/SP stores as the old pattern
-; of @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
-; SystemZ's eh.sjlj.setjmp already stores IP and SP internally, so
-; the old and new patterns should produce identical output.
+; Verify that @llvm.eh.sjlj.setjmp stores IP, SP, and FP into the buffer.
@buf = global [20 x ptr] zeroinitializer, align 8
-; --- Old pattern (eh.sjlj.setjmp, which already stores IP+SP on SystemZ) ---
-
declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
-define void @old_setjmp() nounwind {
+define void @setjmp_test() nounwind {
%r = tail call i32 @llvm.eh.sjlj.setjmp(ptr nonnull @buf)
ret void
}
-; --- New pattern (@llvm.setjmp) ---
-
-declare i32 @llvm.setjmp(ptr) nounwind
-
-define void @new_setjmp() nounwind {
- %r = tail call i32 @llvm.setjmp(ptr nonnull @buf)
- ret void
-}
-
-; Both should store IP to buf[1] (offset 8) and SP to buf[3] (offset 24).
-
-; CHECK-LABEL: old_setjmp:
-; CHECK: stg %r0, 8(%r1)
-; CHECK: stg %r15, 24(%r1)
-; CHECK-LABEL: new_setjmp:
+; CHECK-LABEL: setjmp_test:
; CHECK: stg %r0, 8(%r1)
; CHECK: stg %r15, 24(%r1)
diff --git a/llvm/test/CodeGen/VE/Scalar/setjmp.ll b/llvm/test/CodeGen/VE/Scalar/setjmp.ll
index 24747bacbbfea..c9b81993d0e4c 100644
--- a/llvm/test/CodeGen/VE/Scalar/setjmp.ll
+++ b/llvm/test/CodeGen/VE/Scalar/setjmp.ll
@@ -1,39 +1,16 @@
; RUN: llc < %s -mtriple=ve | FileCheck %s
-; Verify that @llvm.setjmp produces the same FP/SP stores as the old pattern
-; of @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
+; Verify that @llvm.eh.sjlj.setjmp stores FP and SP into the buffer.
@buf = common global [1 x [25 x i64]] zeroinitializer, align 8
-; --- Old pattern (frameaddress + stacksave + stores + eh.sjlj.setjmp) ---
-
-declare ptr @llvm.frameaddress(i32) nounwind readnone
-declare ptr @llvm.stacksave() nounwind
declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
-define i32 @old_setjmp() nounwind "frame-pointer"="all" {
- %fp = call ptr @llvm.frameaddress(i32 0)
- store ptr %fp, ptr @buf, align 8
- %sp = call ptr @llvm.stacksave()
- store ptr %sp, ptr getelementptr inbounds (ptr, ptr @buf, i64 2), align 8
+define i32 @setjmp_test() nounwind "frame-pointer"="all" {
%r = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
ret i32 %r
}
-; --- New pattern (@llvm.setjmp) ---
-
-declare i32 @llvm.setjmp(ptr) nounwind
-
-define i32 @new_setjmp() nounwind "frame-pointer"="all" {
- %r = call i32 @llvm.setjmp(ptr @buf)
- ret i32 %r
-}
-
-; Both functions should store FP (s9) to buf[0] and SP (s11) to buf[2].
-
-; CHECK-LABEL: old_setjmp:
-; CHECK: st %s9, (, %s0)
-; CHECK: st %s11, 16(, %s0)
-; CHECK-LABEL: new_setjmp:
+; CHECK-LABEL: setjmp_test:
; CHECK: st %s9, (, %s0)
; CHECK: st %s11, 16(, %s0)
diff --git a/llvm/test/CodeGen/X86/setjmp.ll b/llvm/test/CodeGen/X86/setjmp.ll
index 1e4b195949576..202af115427b3 100644
--- a/llvm/test/CodeGen/X86/setjmp.ll
+++ b/llvm/test/CodeGen/X86/setjmp.ll
@@ -2,54 +2,26 @@
; RUN: llc < %s -mtriple=x86_64-pc-linux | FileCheck --check-prefix=X64 %s
; RUN: llc < %s -mtriple=x86_64-windows-gnu | FileCheck --check-prefix=WIN64 %s
-; Verify that @llvm.setjmp produces the same output as the old pattern of
-; @llvm.frameaddress + @llvm.stacksave + stores + @llvm.eh.sjlj.setjmp.
+; Verify that @llvm.eh.sjlj.setjmp stores FP and SP into the buffer
+; (in addition to IP), so the frontend doesn't need to do it separately.
@buf = internal global [5 x ptr] zeroinitializer
-; --- Old pattern (frameaddress + stacksave + stores + eh.sjlj.setjmp) ---
-
-declare ptr @llvm.frameaddress(i32) nounwind readnone
-declare ptr @llvm.stacksave() nounwind
declare i32 @llvm.eh.sjlj.setjmp(ptr) nounwind
-define i32 @old_setjmp() nounwind "frame-pointer"="all" {
- %fp = tail call ptr @llvm.frameaddress(i32 0)
- store ptr %fp, ptr @buf, align 16
- %sp = tail call ptr @llvm.stacksave()
- store ptr %sp, ptr getelementptr inbounds ([5 x ptr], ptr @buf, i64 0, i64 2), align 16
+define i32 @setjmp_test() nounwind "frame-pointer"="all" {
%r = tail call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
ret i32 %r
}
-; --- New pattern (@llvm.setjmp) ---
-
-declare i32 @llvm.setjmp(ptr) nounwind
-
-define i32 @new_setjmp() nounwind "frame-pointer"="all" {
- %r = tail call i32 @llvm.setjmp(ptr @buf)
- ret i32 %r
-}
-
-; Both functions should store FP to buf[0], SP to buf[2], IP to buf[1].
-
-; X86-LABEL: old_setjmp:
-; X86: movl %ebp, buf
-; X86: movl %esp, buf+8
-; X86-LABEL: new_setjmp:
+; X86-LABEL: setjmp_test:
; X86: movl %ebp, buf
; X86: movl %esp, buf+8
-; X64-LABEL: old_setjmp:
-; X64: movq %rbp, buf(%rip)
-; X64: movq %rsp, buf+16(%rip)
-; X64-LABEL: new_setjmp:
+; X64-LABEL: setjmp_test:
; X64: movq %rbp, buf(%rip)
; X64: movq %rsp, buf+16(%rip)
-; On WIN64, the old pattern stores an adjusted address from @llvm.frameaddress
-; (which is wrong on WindowsCFI targets). The new @llvm.setjmp stores %rbp
-; directly, which is the correct fix.
-; WIN64-LABEL: new_setjmp:
+; WIN64-LABEL: setjmp_test:
; WIN64: movq %rbp, buf(%rip)
; WIN64: movq %rsp, buf+16(%rip)
>From 08bb29057f6812b6ffbced871c65f32f8e84a84f Mon Sep 17 00:00:00 2001
From: pkova <pyry at urbit.org>
Date: Thu, 26 Mar 2026 19:15:09 +0200
Subject: [PATCH 3/6] Document @llvm.eh.sjlj.setjmp changes and
__builtin_setjmp/longjmp
---
clang/docs/LanguageExtensions.rst | 50 ++++++++++++++++++++++++++++++
clang/docs/ReleaseNotes.rst | 1 +
llvm/docs/ExceptionHandling.rst | 7 ++---
llvm/docs/ReleaseNotes.md | 16 ++++++++++
llvm/docs/ReleaseNotesTemplate.txt | 6 ++++
5 files changed, 75 insertions(+), 5 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index a3e487f910725..3c7866eb99b5c 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3619,6 +3619,56 @@ Query for this feature with ``__has_builtin(__builtin_readcyclecounter)``. Note
that even if present, its use may depend on run-time privilege or other OS
controlled state.
+
+``__builtin_setjmp`` and ``__builtin_longjmp``
+----------------------------------------------
+``__builtin_setjmp`` and ``__builtin_longjmp`` are used to implement non-local control flow.
+
+**Syntax**:
+
+.. code-block:: c
+
+ __builtin_setjmp(void* jmpbuf)
+ __builtin_longjmp(void* jmpbuf, 1)
+
+**Example of Use**:
+
+.. code-block:: c
+
+ #include "stdio.h"
+
+ void* buf[5];
+
+ void foo() {
+ __builtin_longjmp(buf, 1);
+ }
+
+ int main() {
+ if (!__builtin_setjmp(buf)) {
+ printf("Hello before longjmp\n");
+ foo();
+ return 1;
+ }
+ printf("Hello after longjmp\n");
+ return 0;
+ }
+
+**Description**:
+
+``__builtin_setjmp`` saves register state that gets restored when
+``__builtin_longjmp`` is called from the same function or any function
+transitively called from it. ``__builtin_setjmp`` returns 0 when called directly
+and returns 1 after jumping from a ``__builtin_longjmp``. Calling
+``__builtin_longjmp`` after the function that called ``__builtin_setjmp`` has
+returned is undefined behavior. The second argument to ``__builtin_longjmp``
+should always be 1.
+
+The semantics of ``__builtin_setjmp`` and ``__builtin_longjmp`` are identical to
+the libc provided ``setjmp`` and ``longjmp`` functions but they are not
+compatible and should not be intermingled. The builtins can be faster on some
+targets because they are legible to the compiler and therefore do not need to
+store all registers for correctness.
+
``__builtin_readsteadycounter``
-------------------------------
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3dabf951661e5..ae84dffbf5552 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -335,6 +335,7 @@ Bug Fixes in This Version
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed a crash when calling `__builtin_allow_sanitize_check` with no arguments. (#GH183927)
+- Fixed a `__builtin_setjmp` miscompilation on Windows x64. (#GH186843)
Bug Fixes to Attribute Support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/llvm/docs/ExceptionHandling.rst b/llvm/docs/ExceptionHandling.rst
index 48974861b2a10..c2c919c8d3dfc 100644
--- a/llvm/docs/ExceptionHandling.rst
+++ b/llvm/docs/ExceptionHandling.rst
@@ -375,11 +375,8 @@ to interoperate.
The single parameter is a pointer to a five word buffer in which the calling
context is saved. The format and contents of the buffer are target-specific.
-On certain targets (ARM, PowerPC, VE, X86), the front end places the
-frame pointer in the first word and the stack pointer in the third word,
-while the target implementation of this intrinsic fills in the remaining
-words. On other targets (SystemZ), saving the calling context to the buffer
-is left completely to the target implementation.
+Saving the context to the buffer is delegated to the implementation on all
+supported targets.
.. _llvm.eh.sjlj.longjmp:
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index e685660195bcd..7088ede0e1236 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -119,6 +119,8 @@ Changes to the ARM Backend
* The `r14` register can now be used as an alias for the link register `lr`
in inline assembly. Clang always canonicalizes the name to `lr`, but other
frontends may not.
+* The backend now stores the frame pointer and stack pointer into the jump buffer
+ when lowering `@llvm.eh.sjlj.setjmp`. This was previously handled by the frontend.
Changes to the AVR Backend
--------------------------
@@ -148,6 +150,9 @@ Changes to the NVPTX Backend
Changes to the PowerPC Backend
------------------------------
+* The backend now stores the frame pointer and stack pointer into the jump buffer
+ when lowering `@llvm.eh.sjlj.setjmp`. This was previously handled by the frontend.
+
Changes to the RISC-V Backend
-----------------------------
@@ -168,6 +173,15 @@ Changes to the RISC-V Backend
Reordering Structured Data) extension.
* `-mcpu=sifive-x160` and `-mcpu=sifive-x180` were added.
+Changes to the SystemZ Backend
+-----------------------------
+
+Changes to the VE Backend
+-----------------------------
+
+* The backend now stores the frame pointer and stack pointer into the jump buffer
+ when lowering `@llvm.eh.sjlj.setjmp`. This was previously handled by the frontend.
+
Changes to the WebAssembly Backend
----------------------------------
@@ -183,6 +197,8 @@ Changes to the X86 Backend
* `.att_syntax` directive is now emitted for assembly files when AT&T syntax is
in use. This matches the behaviour of Intel syntax and aids with
compatibility when changing the default Clang syntax to the Intel syntax.
+* The backend now stores the frame pointer and stack pointer into the jump buffer
+ when lowering `@llvm.eh.sjlj.setjmp`. This was previously handled by the frontend.
Changes to the OCaml bindings
-----------------------------
diff --git a/llvm/docs/ReleaseNotesTemplate.txt b/llvm/docs/ReleaseNotesTemplate.txt
index ea1e4906fbe2e..a9d8f683165b5 100644
--- a/llvm/docs/ReleaseNotesTemplate.txt
+++ b/llvm/docs/ReleaseNotesTemplate.txt
@@ -104,6 +104,12 @@ Changes to the PowerPC Backend
Changes to the RISC-V Backend
-----------------------------
+Changes to the SystemZ Backend
+-----------------------------
+
+Changes to the VE Backend
+-----------------------------
+
Changes to the WebAssembly Backend
----------------------------------
>From 71860e273fc043f7c4234ffc72db340b5798c070 Mon Sep 17 00:00:00 2001
From: pkova <pyry at urbit.org>
Date: Mon, 30 Mar 2026 15:36:17 +0300
Subject: [PATCH 4/6] Store FP, SP before IP in x86 setjmp lowering and strip
kill flags
My previous commit 3463b3c was storing the IP and killing the buffer pointer but
then reusing it to store the FP and SP. This caused caused the
i386-setjmp-pic.ll test to blow up in the machine verifier.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 62 ++++++++++++++-----------
1 file changed, 36 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 5e5ce34e685e5..72f3486e6b6ad 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -37541,6 +37541,41 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
bool UseImmLabel = (MF->getTarget().getCodeModel() == CodeModel::Small) &&
!isPositionIndependent();
+ const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
+
+ // Store FP to buf[0] and SP to buf[2] before the IP store.
+ // These come first so the IP store can be the last user of the address
+ // operands (preserving kill flags there). Kill flags are stripped here.
+ unsigned RegStoreOpc = (PVT == MVT::i64) ? X86::MOV64mr : X86::MOV32mr;
+
+ bool HasFP = Subtarget.getFrameLowering()->hasFP(*MF);
+ if (HasFP) {
+ MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(RegStoreOpc));
+ for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
+ const MachineOperand &MO = MI.getOperand(MemOpndSlot + i);
+ if (MO.isReg())
+ MIB.addReg(MO.getReg()); // strip kill flags
+ else
+ MIB.add(MO);
+ }
+ MIB.addReg(RegInfo->getFrameRegister(*MF));
+ MIB.setMemRefs(MMOs);
+ }
+
+ const int64_t SPOffset = 2 * PVT.getStoreSize();
+ MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(RegStoreOpc));
+ for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
+ const MachineOperand &MO = MI.getOperand(MemOpndSlot + i);
+ if (i == X86::AddrDisp)
+ MIB.addDisp(MO, SPOffset);
+ else if (MO.isReg())
+ MIB.addReg(MO.getReg()); // strip kill flags
+ else
+ MIB.add(MO);
+ }
+ MIB.addReg(RegInfo->getStackRegister());
+ MIB.setMemRefs(MMOs);
+
// Prepare IP either in reg or imm.
if (!UseImmLabel) {
PtrStoreOpc = (PVT == MVT::i64) ? X86::MOV64mr : X86::MOV32mr;
@@ -37564,7 +37599,7 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
}
} else
PtrStoreOpc = (PVT == MVT::i64) ? X86::MOV64mi32 : X86::MOV32mi;
- // Store IP
+ // Store IP (last user of address operands — kill flags preserved).
MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(PtrStoreOpc));
for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
if (i == X86::AddrDisp)
@@ -37578,31 +37613,6 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
MIB.addMBB(restoreMBB);
MIB.setMemRefs(MMOs);
- const X86RegisterInfo *RegInfo = Subtarget.getRegisterInfo();
-
- // Store FP to buf[0] and SP to buf[2].
- unsigned RegStoreOpc = (PVT == MVT::i64) ? X86::MOV64mr : X86::MOV32mr;
-
- bool HasFP = Subtarget.getFrameLowering()->hasFP(*MF);
- if (HasFP) {
- 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);
- }
-
- const int64_t SPOffset = 2 * PVT.getStoreSize();
- MIB = BuildMI(*thisMBB, MI, MIMD, TII->get(RegStoreOpc));
- for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
- if (i == X86::AddrDisp)
- MIB.addDisp(MI.getOperand(MemOpndSlot + i), SPOffset);
- else
- MIB.add(MI.getOperand(MemOpndSlot + i));
- }
- MIB.addReg(RegInfo->getStackRegister());
- MIB.setMemRefs(MMOs);
-
if (MF->getFunction().getParent()->getModuleFlag("cf-protection-return")) {
emitSetJmpShadowStackFix(MI, thisMBB);
}
>From 98f7014a7d4596cfd2fc03a918c39f1158d64112 Mon Sep 17 00:00:00 2001
From: pkova <pyry at urbit.org>
Date: Mon, 30 Mar 2026 15:41:06 +0300
Subject: [PATCH 5/6] Modify pre-existing setjmp longjmp tests to the new
backend regime
---
llvm/test/CodeGen/Thumb2/setjmp_longjmp.ll | 25 ++++++-------------
llvm/test/CodeGen/VE/Scalar/builtin_sjlj.ll | 25 ++++++-------------
.../test/CodeGen/VE/Scalar/builtin_sjlj_bp.ll | 2 ++
llvm/test/CodeGen/X86/shadow-stack.ll | 17 ++++---------
4 files changed, 21 insertions(+), 48 deletions(-)
diff --git a/llvm/test/CodeGen/Thumb2/setjmp_longjmp.ll b/llvm/test/CodeGen/Thumb2/setjmp_longjmp.ll
index e260286fb692a..a12a923c5706a 100644
--- a/llvm/test/CodeGen/Thumb2/setjmp_longjmp.ll
+++ b/llvm/test/CodeGen/Thumb2/setjmp_longjmp.ll
@@ -4,15 +4,14 @@ target triple = "thumbv7-apple-ios"
declare i32 @llvm.eh.sjlj.setjmp(ptr)
declare void @llvm.eh.sjlj.longjmp(ptr)
-declare ptr @llvm.frameaddress(i32)
-declare ptr @llvm.stacksave()
@g = external global i32
-define void @double_foobar() {
+define void @double_foobar() "frame-pointer"="all" {
; CHECK-LABEL: double_foobar:
; CHECK: @ %bb.0: @ %entry
-; CHECK-NEXT: push.w {r4, r5, r6, r7, r8, r10, r11, lr}
-; CHECK-NEXT: add r7, sp, #24
+; CHECK-NEXT: push {r4, r5, r6, r7, lr}
+; CHECK-NEXT: add r7, sp, #12
+; CHECK-NEXT: push.w {r8, r10, r11}
; CHECK-NEXT: sub sp, #24
; CHECK-NEXT: movs r1, #0
; CHECK-NEXT: add r0, sp, #4
@@ -52,8 +51,9 @@ define void @double_foobar() {
; CHECK-NEXT: ldrne r1, [sp] @ 4-byte Reload
; CHECK-NEXT: strne r0, [r1]
; CHECK-NEXT: addne sp, #24
-; CHECK-NEXT: it ne
-; CHECK-NEXT: popne.w {r4, r5, r6, r7, r8, r10, r11, pc}
+; CHECK-NEXT: itt ne
+; CHECK-NEXT: popne.w {r8, r10, r11}
+; CHECK-NEXT: popne {r4, r5, r6, r7, pc}
; CHECK-NEXT: LBB0_2: @ %if2.else
; CHECK-NEXT: ldr r1, [sp] @ 4-byte Reload
; CHECK-NEXT: movs r0, #2
@@ -82,12 +82,6 @@ define void @double_foobar() {
entry:
%buf = alloca [5 x ptr], align 4
- %fa = tail call ptr @llvm.frameaddress(i32 0)
- store ptr %fa, ptr %buf, align 4
- %ss = tail call ptr @llvm.stacksave()
- %ssgep = getelementptr [5 x ptr], ptr %buf, i32 0, i32 2
- store ptr %ss, ptr %ssgep, align 4
-
%setjmpres = call i32 @llvm.eh.sjlj.setjmp(ptr %buf)
%tobool = icmp ne i32 %setjmpres, 0
br i1 %tobool, label %if.then, label %if.else
@@ -102,11 +96,6 @@ if.else:
unreachable
if.end:
- %fa2 = tail call ptr @llvm.frameaddress(i32 0)
- store ptr %fa2, ptr %buf, align 4
- %ss2 = tail call ptr @llvm.stacksave()
- store ptr %ss2, ptr %ssgep, align 4
-
%setjmpres2 = call i32 @llvm.eh.sjlj.setjmp(ptr %buf)
%tobool2 = icmp ne i32 %setjmpres2, 0
br i1 %tobool2, label %if2.then, label %if2.else
diff --git a/llvm/test/CodeGen/VE/Scalar/builtin_sjlj.ll b/llvm/test/CodeGen/VE/Scalar/builtin_sjlj.ll
index 2713d61d16c2f..6d3a5dc504c44 100644
--- a/llvm/test/CodeGen/VE/Scalar/builtin_sjlj.ll
+++ b/llvm/test/CodeGen/VE/Scalar/builtin_sjlj.ll
@@ -7,7 +7,7 @@
@buf = common global [1 x %struct.__jmp_buf_tag] zeroinitializer, align 8
; Function Attrs: noinline nounwind optnone
-define signext i32 @t_setjmp() {
+define signext i32 @t_setjmp() "frame-pointer"="all" {
; CHECK-LABEL: t_setjmp:
; CHECK: .LBB{{[0-9]+}}_5:
; CHECK-NEXT: st %s18, 48(, %s9) # 8-byte Folded Spill
@@ -29,11 +29,11 @@ define signext i32 @t_setjmp() {
; CHECK-NEXT: lea %s0, buf at lo
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: lea.sl %s0, buf at hi(, %s0)
-; CHECK-NEXT: st %s9, (, %s0)
-; CHECK-NEXT: st %s11, 16(, %s0)
; CHECK-NEXT: lea %s1, .LBB{{[0-9]+}}_3 at lo
; CHECK-NEXT: and %s1, %s1, (32)0
; CHECK-NEXT: lea.sl %s1, .LBB{{[0-9]+}}_3 at hi(, %s1)
+; CHECK-NEXT: st %s9, (, %s0)
+; CHECK-NEXT: st %s11, 16(, %s0)
; CHECK-NEXT: st %s1, 8(, %s0)
; CHECK-NEXT: # EH_SJlJ_SETUP .LBB{{[0-9]+}}_3
; CHECK-NEXT: # %bb.1:
@@ -104,11 +104,11 @@ define signext i32 @t_setjmp() {
; PIC-NEXT: and %s0, %s0, (32)0
; PIC-NEXT: lea.sl %s0, buf at got_hi(, %s0)
; PIC-NEXT: ld %s0, (%s0, %s15)
-; PIC-NEXT: st %s9, (, %s0)
-; PIC-NEXT: st %s11, 16(, %s0)
; PIC-NEXT: lea %s1, .LBB0_3 at gotoff_lo
; PIC-NEXT: and %s1, %s1, (32)0
; PIC-NEXT: lea.sl %s1, .LBB0_3 at gotoff_hi(%s1, %s15)
+; PIC-NEXT: st %s9, (, %s0)
+; PIC-NEXT: st %s11, 16(, %s0)
; PIC-NEXT: st %s1, 8(, %s0)
; PIC-NEXT: # EH_SJlJ_SETUP .LBB0_3
; PIC-NEXT: # %bb.1:
@@ -140,20 +140,10 @@ define signext i32 @t_setjmp() {
; PIC-NEXT: ld %s10, 8(, %s11)
; PIC-NEXT: ld %s9, (, %s11)
; PIC-NEXT: b.l.t (, %s10)
- %1 = call ptr @llvm.frameaddress(i32 0)
- store ptr %1, ptr @buf, align 8
- %2 = call ptr @llvm.stacksave()
- store ptr %2, ptr getelementptr inbounds (ptr, ptr @buf, i64 2), align 8
- %3 = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
- ret i32 %3
+ %1 = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
+ ret i32 %1
}
-; Function Attrs: nounwind readnone
-declare ptr @llvm.frameaddress(i32)
-
-; Function Attrs: nounwind
-declare ptr @llvm.stacksave()
-
; Function Attrs: nounwind
declare i32 @llvm.eh.sjlj.setjmp(ptr)
@@ -210,4 +200,3 @@ define void @t_longjmp() {
; Function Attrs: noreturn nounwind
declare void @llvm.eh.sjlj.longjmp(ptr)
-
diff --git a/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_bp.ll b/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_bp.ll
index 6fdf71da75c4a..7b3b5f5d821ef 100644
--- a/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_bp.ll
+++ b/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_bp.ll
@@ -37,6 +37,8 @@ define i32 @t_setjmp(i64 %n, ptr byval(%Foo) nocapture readnone align 8 %f) {
; CHECK-NEXT: lea %s0, .LBB{{[0-9]+}}_3 at lo
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: lea.sl %s0, .LBB{{[0-9]+}}_3 at hi(, %s0)
+; CHECK-NEXT: st %s9, (, %s1)
+; CHECK-NEXT: st %s11, 16(, %s1)
; CHECK-NEXT: st %s17, 24(, %s1)
; CHECK-NEXT: st %s1, 296(, %s17) # 8-byte Folded Spill
; CHECK-NEXT: st %s0, 8(, %s1)
diff --git a/llvm/test/CodeGen/X86/shadow-stack.ll b/llvm/test/CodeGen/X86/shadow-stack.ll
index bf0a00732b88a..a6891d92ce1ef 100644
--- a/llvm/test/CodeGen/X86/shadow-stack.ll
+++ b/llvm/test/CodeGen/X86/shadow-stack.ll
@@ -2,7 +2,7 @@
; RUN: llc -mtriple x86_64-apple-macosx10.13.0 < %s | FileCheck %s --check-prefix=X86_64
; RUN: llc -mtriple i386-apple-macosx10.13.0 < %s | FileCheck %s --check-prefix=X86
-; The MacOS tripples are used to get trapping behavior on the "unreachable" IR
+; The MacOS triples are used to get trapping behavior on the "unreachable" IR
; instruction, so that the placement of the ud2 instruction could be verified.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -108,7 +108,7 @@ declare void @llvm.eh.sjlj.longjmp(ptr)
; Functions that call SetJmp should save the current ShadowStackPointer for
; future fixing of the Shadow Stack.
-define i32 @foo(i32 %i) local_unnamed_addr {
+define i32 @foo(i32 %i) local_unnamed_addr "frame-pointer"="all" {
; X86_64-LABEL: foo:
; X86_64: ## %bb.0: ## %entry
; X86_64-NEXT: pushq %rbp
@@ -181,7 +181,7 @@ define i32 @foo(i32 %i) local_unnamed_addr {
; X86-NEXT: movl L_buf$non_lazy_ptr, %eax
; X86-NEXT: movl (%eax), %eax
; X86-NEXT: movl %ebp, (%eax)
-; X86-NEXT: movl %esp, 16(%eax)
+; X86-NEXT: movl %esp, 8(%eax)
; X86-NEXT: movl $LBB1_4, 4(%eax)
; X86-NEXT: xorl %ecx, %ecx
; X86-NEXT: rdsspd %ecx
@@ -211,13 +211,8 @@ define i32 @foo(i32 %i) local_unnamed_addr {
; X86-NEXT: ud2
entry:
%0 = load ptr, ptr @buf, align 8
- %1 = tail call ptr @llvm.frameaddress(i32 0)
- store ptr %1, ptr %0, align 8
- %2 = tail call ptr @llvm.stacksave()
- %3 = getelementptr inbounds i8, ptr %0, i64 16
- store ptr %2, ptr %3, align 8
- %4 = tail call i32 @llvm.eh.sjlj.setjmp(ptr %0)
- %tobool = icmp eq i32 %4, 0
+ %1 = tail call i32 @llvm.eh.sjlj.setjmp(ptr %0)
+ %tobool = icmp eq i32 %1, 0
br i1 %tobool, label %if.then, label %if.end
if.then: ; preds = %entry
@@ -229,8 +224,6 @@ if.end: ; preds = %entry
ret i32 %add2
}
-declare ptr @llvm.frameaddress(i32)
-declare ptr @llvm.stacksave()
declare i32 @llvm.eh.sjlj.setjmp(ptr)
!llvm.module.flags = !{!0}
>From 19ad48212bfd1b2427927cacff75fc9d1b796f89 Mon Sep 17 00:00:00 2001
From: pkova <pyry at urbit.org>
Date: Mon, 30 Mar 2026 16:04:31 +0300
Subject: [PATCH 6/6] Revert unintentional whitespace changes
---
llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 2 +-
llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index e80fde06e7373..35a923d070e3e 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -1920,7 +1920,7 @@ let mayLoad = 1, mayStore = 1, Defs = [CC] in {
//--------------------------------------------------------------------------
let isBarrier = 1, hasNoSchedulingInfo = 1 in {
let hasSideEffects = 1, usesCustomInserter = 1 in {
- def EH_SjLj_SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2),
+ def EH_SjLj_SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2),
[(set GR32:$dst, (z_eh_sjlj_setjmp ADDR64:$R2))]>;
let isTerminator = 1 in {
def EH_SjLj_LongJmp : Pseudo<(outs), (ins ADDR64:$R2),
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index 5fdad92c5ba12..be95168f2de00 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -3030,10 +3030,10 @@ bool X86DAGToDAGISel::selectAddr(SDNode *Parent, SDValue N, SDValue &Base,
// This list of opcodes are all the nodes that have an "addr:$ptr" operand
// that are not a MemSDNode, and thus don't have proper addrspace info.
Parent->getOpcode() != ISD::INTRINSIC_W_CHAIN && // unaligned loads, fixme
- Parent->getOpcode() != ISD::INTRINSIC_VOID && // nontemporal stores
- Parent->getOpcode() != X86ISD::TLSCALL && // Fixme
- Parent->getOpcode() != X86ISD::ENQCMD && // Fixme
- Parent->getOpcode() != X86ISD::ENQCMDS && // Fixme
+ Parent->getOpcode() != ISD::INTRINSIC_VOID && // nontemporal stores
+ Parent->getOpcode() != X86ISD::TLSCALL && // Fixme
+ Parent->getOpcode() != X86ISD::ENQCMD && // Fixme
+ Parent->getOpcode() != X86ISD::ENQCMDS && // Fixme
Parent->getOpcode() != X86ISD::EH_SJLJ_SETJMP && // setjmp
Parent->getOpcode() != X86ISD::EH_SJLJ_LONGJMP) { // longjmp
unsigned AddrSpace =
More information about the llvm-commits
mailing list