https://github.com/pkova updated https://github.com/llvm/llvm-project/pull/186843
>From e3ca0fbfb3dc2c2327aa974f6024a94c6f2fdc67 Mon Sep 17 00:00:00 2001 From: pkova <[email protected]> Date: Thu, 19 Mar 2026 18:06:29 +0200 Subject: [PATCH] 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. + +@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. + +@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@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. + +@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. + +@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. + +@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) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
