[clang] 030bbc9 - [SystemZ] Add support for __builtin_setjmp and __builtin_longjmp (#116642)

via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 6 14:33:36 PST 2024


Author: anoopkg6
Date: 2024-12-06T23:33:33+01:00
New Revision: 030bbc92a705758f1131fb29cab5be6d6a27dd1f

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

LOG: [SystemZ] Add support for __builtin_setjmp and __builtin_longjmp (#116642)

Implementation for __builtin_setjmp and __builtin_longjmp for SystemZ.

Added: 
    clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
    llvm/test/CodeGen/SystemZ/builtin-longjmp.ll
    llvm/test/CodeGen/SystemZ/builtin-setjmp-alloca.ll
    llvm/test/CodeGen/SystemZ/builtin-setjmp-spills.ll
    llvm/test/CodeGen/SystemZ/builtin-setjmp.ll

Modified: 
    clang/lib/Basic/Targets/SystemZ.h
    clang/lib/CodeGen/CGBuiltin.cpp
    llvm/docs/ExceptionHandling.rst
    llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
    llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
    llvm/lib/Target/SystemZ/SystemZISelLowering.h
    llvm/lib/Target/SystemZ/SystemZInstrInfo.td
    llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
    llvm/lib/Target/SystemZ/SystemZOperators.td
    llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
    llvm/lib/Target/SystemZ/SystemZRegisterInfo.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index ef9a07033a6e4f..e6405f174f660f 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -247,6 +247,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
     return RegNo < 4 ? 6 + RegNo : -1;
   }
 
+  bool hasSjLjLowering() const override { return true; }
+
   std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
     return std::make_pair(256, 256);
   }

diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 41c632ead6aa3c..656e6748e1e103 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4860,6 +4860,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     // 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),

diff  --git a/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c b/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
new file mode 100644
index 00000000000000..f2d1659eb87692
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
@@ -0,0 +1,25 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang --target=s390x-linux -S -emit-llvm -o - %s | FileCheck %s
+
+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:    ret void
+//
+void foo()
+{
+  __builtin_setjmp (buf);
+}
+
+// CHECK-LABEL: define dso_local void @foo1(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    call void @llvm.eh.sjlj.longjmp(ptr @buf)
+// CHECK-NEXT:    unreachable
+//
+void foo1()
+{
+  __builtin_longjmp (buf, 1);
+}

diff  --git a/llvm/docs/ExceptionHandling.rst b/llvm/docs/ExceptionHandling.rst
index c2afb25c6ccd47..52cc512cc13abc 100644
--- a/llvm/docs/ExceptionHandling.rst
+++ b/llvm/docs/ExceptionHandling.rst
@@ -374,10 +374,11 @@ overall functioning of this intrinsic is compatible with the GCC
 to interoperate.
 
 The single parameter is a pointer to a five word buffer in which the calling
-context is saved. The front end places the frame pointer in the first word, and
-the target implementation of this intrinsic should place the destination address
-for a `llvm.eh.sjlj.longjmp`_ in the second word. The following three words are
-available for use in a target-specific manner.
+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. 
 
 .. _llvm.eh.sjlj.longjmp:
 

diff  --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 59154431877a88..d307c73a87fc90 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -705,6 +705,11 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
     return;
   }
 
+  // EH_SjLj_Setup is a dummy terminator instruction of size 0.
+  // It is used to handle the clobber register for builtin setjmp.
+  case SystemZ::EH_SjLj_Setup:
+    return;
+
   default:
     Lower.lower(MI, LoweredMI);
     break;

diff  --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 975a0f5050d166..67abc714287e2c 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -751,6 +751,11 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
   setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
 
+  // 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::EH_SJLJ_LONGJMP, MVT::Other, Custom);
+
   // We want to use MVC in preference to even a single load/store pair.
   MaxStoresPerMemcpy = Subtarget.hasVector() ? 2 : 0;
   MaxStoresPerMemcpyOptSize = 0;
@@ -940,6 +945,240 @@ bool SystemZTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
   return SystemZVectorConstantInfo(Imm).isVectorConstantLegal(Subtarget);
 }
 
+MachineBasicBlock *
+SystemZTargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
+                                        MachineBasicBlock *MBB) const {
+  DebugLoc DL = MI.getDebugLoc();
+  const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+  const SystemZRegisterInfo *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!");
+  // For v = setjmp(buf), we generate.
+  // Algorithm:
+  //
+  //                 ---------
+  //                | thisMBB |
+  //                 ---------
+  //                     |
+  //         ------------------------
+  //        |                        |
+  //     ----------           ---------------
+  //    |  mainMBB |         | restoreMBB    |
+  //    |   v = 0  |         |  v = 1        |
+  //     ----------           ---------------
+  //        |                        |
+  //         -------------------------
+  //                     |
+  //           -----------------------------
+  //          |       sinkMBB               |
+  //          | phi(v_mainMBB,v_restoreMBB) |
+  //           -----------------------------
+  // thisMBB:
+  //  buf[FPOffset] = Frame Pointer if hasFP.
+  //  buf[LabelOffset] = restoreMBB <-- takes address of restoreMBB.
+  //  buf[BCOffset] = Backchain value if building with -mbackchain.
+  //  buf[SPOffset] = Stack Pointer.
+  //  buf[LPOffset] = We never write this slot with  R13, gcc stores R13 always.
+  //  SjLjSetup restoreMBB
+  // mainMBB:
+  //  v_main = 0
+  // sinkMBB:
+  //  v = phi(v_main, v_restore)
+  // restoreMBB:
+  //  v_restore = 1
+
+  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;
+
+  // 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:
+  const int64_t FPOffset = 0;                         // Slot 1.
+  const int64_t LabelOffset = 1 * PVT.getStoreSize(); // Slot 2.
+  const int64_t BCOffset = 2 * PVT.getStoreSize();    // Slot 3.
+  const int64_t SPOffset = 3 * PVT.getStoreSize();    // Slot 4.
+
+  // Buf address.
+  Register BufReg = MI.getOperand(1).getReg();
+
+  const TargetRegisterClass *PtrRC = getRegClassFor(PVT);
+  unsigned LabelReg = MRI.createVirtualRegister(PtrRC);
+
+  // Prepare IP for longjmp.
+  BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::LARL), LabelReg)
+      .addMBB(restoreMBB);
+  // Store IP for return from jmp, slot 2, offset = 1.
+  BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
+      .addReg(LabelReg)
+      .addReg(BufReg)
+      .addImm(LabelOffset)
+      .addReg(0);
+
+  auto *SpecialRegs = Subtarget.getSpecialRegisters();
+  bool HasFP = Subtarget.getFrameLowering()->hasFP(*MF);
+  if (HasFP) {
+    BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
+        .addReg(SpecialRegs->getFramePointerRegister())
+        .addReg(BufReg)
+        .addImm(FPOffset)
+        .addReg(0);
+  }
+
+  // Store SP.
+  BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
+      .addReg(SpecialRegs->getStackPointerRegister())
+      .addReg(BufReg)
+      .addImm(SPOffset)
+      .addReg(0);
+
+  // Slot 3(Offset = 2) Backchain value (if building with -mbackchain).
+  bool BackChain = MF->getSubtarget<SystemZSubtarget>().hasBackChain();
+  if (BackChain) {
+    Register BCReg = MRI.createVirtualRegister(RC);
+    auto *TFL = Subtarget.getFrameLowering<SystemZFrameLowering>();
+    MIB = BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::LG), BCReg)
+              .addReg(SpecialRegs->getStackPointerRegister())
+              .addImm(TFL->getBackchainOffset(*MF))
+              .addReg(0);
+
+    BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
+        .addReg(BCReg)
+        .addReg(BufReg)
+        .addImm(BCOffset)
+        .addReg(0);
+  }
+
+  // Setup.
+  MIB = BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::EH_SjLj_Setup))
+            .addMBB(restoreMBB);
+
+  const SystemZRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
+  MIB.addRegMask(RegInfo->getNoPreservedMask());
+
+  thisMBB->addSuccessor(mainMBB);
+  thisMBB->addSuccessor(restoreMBB);
+
+  // mainMBB:
+  BuildMI(mainMBB, DL, TII->get(SystemZ::LHI), mainDstReg).addImm(0);
+  mainMBB->addSuccessor(sinkMBB);
+
+  // sinkMBB:
+  BuildMI(*sinkMBB, sinkMBB->begin(), DL, TII->get(SystemZ::PHI), DstReg)
+      .addReg(mainDstReg)
+      .addMBB(mainMBB)
+      .addReg(restoreDstReg)
+      .addMBB(restoreMBB);
+
+  // restoreMBB.
+  BuildMI(restoreMBB, DL, TII->get(SystemZ::LHI), restoreDstReg).addImm(1);
+  BuildMI(restoreMBB, DL, TII->get(SystemZ::J)).addMBB(sinkMBB);
+  restoreMBB->addSuccessor(sinkMBB);
+
+  MI.eraseFromParent();
+
+  return sinkMBB;
+}
+
+MachineBasicBlock *
+SystemZTargetLowering::emitEHSjLjLongJmp(MachineInstr &MI,
+                                         MachineBasicBlock *MBB) const {
+
+  DebugLoc DL = MI.getDebugLoc();
+  const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+
+  MachineFunction *MF = MBB->getParent();
+  MachineRegisterInfo &MRI = MF->getRegInfo();
+
+  MVT PVT = getPointerTy(MF->getDataLayout());
+  assert((PVT == MVT::i64 || PVT == MVT::i32) && "Invalid Pointer Size!");
+  Register BufReg = MI.getOperand(0).getReg();
+  const TargetRegisterClass *RC = MRI.getRegClass(BufReg);
+  auto *SpecialRegs = Subtarget.getSpecialRegisters();
+
+  Register Tmp = MRI.createVirtualRegister(RC);
+  Register BCReg = MRI.createVirtualRegister(RC);
+
+  MachineInstrBuilder MIB;
+
+  const int64_t FPOffset = 0;
+  const int64_t LabelOffset = 1 * PVT.getStoreSize();
+  const int64_t BCOffset = 2 * PVT.getStoreSize();
+  const int64_t SPOffset = 3 * PVT.getStoreSize();
+  const int64_t LPOffset = 4 * PVT.getStoreSize();
+
+  MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG), Tmp)
+            .addReg(BufReg)
+            .addImm(LabelOffset)
+            .addReg(0);
+
+  MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG),
+                SpecialRegs->getFramePointerRegister())
+            .addReg(BufReg)
+            .addImm(FPOffset)
+            .addReg(0);
+
+  // We are restoring R13 even though we never stored in setjmp from llvm,
+  // as gcc always stores R13 in builtin_setjmp. We could have mixed code
+  // gcc setjmp and llvm longjmp.
+  MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG), SystemZ::R13D)
+            .addReg(BufReg)
+            .addImm(LPOffset)
+            .addReg(0);
+
+  bool BackChain = MF->getSubtarget<SystemZSubtarget>().hasBackChain();
+  if (BackChain) {
+    MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG), BCReg)
+              .addReg(BufReg)
+              .addImm(BCOffset)
+              .addReg(0);
+  }
+
+  MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::LG),
+                SpecialRegs->getStackPointerRegister())
+            .addReg(BufReg)
+            .addImm(SPOffset)
+            .addReg(0);
+
+  if (BackChain) {
+    auto *TFL = Subtarget.getFrameLowering<SystemZFrameLowering>();
+    BuildMI(*MBB, MI, DL, TII->get(SystemZ::STG))
+        .addReg(BCReg)
+        .addReg(SpecialRegs->getStackPointerRegister())
+        .addImm(TFL->getBackchainOffset(*MF))
+        .addReg(0);
+  }
+
+  MIB = BuildMI(*MBB, MI, DL, TII->get(SystemZ::BR)).addReg(Tmp);
+
+  MI.eraseFromParent();
+  return MBB;
+}
+
 /// Returns true if stack probing through inline assembly is requested.
 bool SystemZTargetLowering::hasInlineStackProbe(const MachineFunction &MF) const {
   // If the function specifically requests inline stack probes, emit them.
@@ -6292,6 +6531,14 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
     return lowerGET_ROUNDING(Op, DAG);
   case ISD::READCYCLECOUNTER:
     return lowerREADCYCLECOUNTER(Op, DAG);
+  case ISD::EH_SJLJ_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
+    // as equivalent to Expand. Instead, we keep the operation action to
+    // Custom and just leave them unchanged here.
+    return Op;
+
   default:
     llvm_unreachable("Unexpected node to lower");
   }
@@ -9733,6 +9980,10 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
 
   case SystemZ::PROBED_ALLOCA:
     return emitProbedAlloca(MI, MBB);
+  case SystemZ::EH_SjLj_SetJmp:
+    return emitEHSjLjSetJmp(MI, MBB);
+  case SystemZ::EH_SjLj_LongJmp:
+    return emitEHSjLjLongJmp(MI, MBB);
 
   case TargetOpcode::STACKMAP:
   case TargetOpcode::PATCHPOINT:

diff  --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index 3c06c1fdf2b1bc..0a899e861c73bf 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -476,6 +476,12 @@ class SystemZTargetLowering : public TargetLowering {
     // LD, and having the full constant in memory enables reg/mem opcodes.
     return VT != MVT::f64;
   }
+  MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI,
+                                      MachineBasicBlock *MBB) const;
+
+  MachineBasicBlock *emitEHSjLjLongJmp(MachineInstr &MI,
+                                       MachineBasicBlock *MBB) const;
+
   bool hasInlineStackProbe(const MachineFunction &MF) const override;
   AtomicExpansionKind shouldCastAtomicLoadInIR(LoadInst *LI) const override;
   AtomicExpansionKind shouldCastAtomicStoreInIR(StoreInst *SI) const override;

diff  --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 5cbba0d9c5edd3..d6cddeb8b6c303 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -1862,6 +1862,23 @@ let mayLoad = 1, mayStore = 1, Defs = [CC] in {
   }
 }
 
+//--------------------------------------------------------------------------
+// Setjmp/Longjmp.
+//--------------------------------------------------------------------------
+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))]>;
+    let isTerminator = 1 in {
+      def EH_SjLj_LongJmp : Pseudo<(outs), (ins ADDR64:$R2), 
+                           [(z_eh_sjlj_longjmp  ADDR64:$R2)]>;
+    }
+  }
+  let isTerminator = 1, isCodeGenOnly = 1, Size = 0 in {
+    def EH_SjLj_Setup : Pseudo<(outs), (ins brtarget32:$dst), []>;
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Message-security assist
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
index 632218cc61eefe..36d76235398edd 100644
--- a/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
@@ -220,7 +220,10 @@ static unsigned getInstSizeInBytes(const MachineInstr &MI,
           MI.isImplicitDef() || MI.getOpcode() == TargetOpcode::MEMBARRIER ||
           // These have a size that may be zero:
           MI.isInlineAsm() || MI.getOpcode() == SystemZ::STACKMAP ||
-          MI.getOpcode() == SystemZ::PATCHPOINT) &&
+          MI.getOpcode() == SystemZ::PATCHPOINT ||
+          // EH_SjLj_Setup is a dummy terminator instruction of size 0,
+          // It is used to handle the clobber register for builtin setjmp.
+          MI.getOpcode() == SystemZ::EH_SjLj_Setup) &&
          "Missing size value for instruction.");
   return Size;
 }

diff  --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index 6cb89ccff85e68..90fb4e5f370dab 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -238,6 +238,12 @@ def SDT_ZTest               : SDTypeProfile<1, 2,
                                             [SDTCisVT<0, i32>,
                                              SDTCisVT<2, i64>]>;
 
+def SDT_ZSetJmp             : SDTypeProfile<1, 1,
+                                            [SDTCisInt<0>,
+                                             SDTCisPtrTy<1>]>;
+def SDT_ZLongJmp            : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
+
+
 //===----------------------------------------------------------------------===//
 // Node definitions
 //===----------------------------------------------------------------------===//
@@ -314,6 +320,12 @@ def z_stckf            : SDNode<"SystemZISD::STCKF", SDT_ZStoreInherent,
 
 def z_tdc               : SDNode<"SystemZISD::TDC", SDT_ZTest>;
 
+def z_eh_sjlj_setjmp    : SDNode<"ISD::EH_SJLJ_SETJMP", SDT_ZSetJmp,
+                                 [SDNPHasChain, SDNPSideEffect]>;
+def z_eh_sjlj_longjmp   : SDNode<"ISD::EH_SJLJ_LONGJMP", SDT_ZLongJmp,
+                                 [SDNPHasChain, SDNPSideEffect]>;
+
+
 // Defined because the index is an i32 rather than a pointer.
 def z_vector_insert     : SDNode<"ISD::INSERT_VECTOR_ELT",
                                  SDT_ZInsertVectorElt>;

diff  --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
index d246d3f3c5bd11..0df2a15753cf3e 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
@@ -254,6 +254,10 @@ SystemZRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
   return Regs->getCallPreservedMask(MF, CC);
 }
 
+const uint32_t *SystemZRegisterInfo::getNoPreservedMask() const {
+  return CSR_SystemZ_NoRegs_RegMask;
+}
+
 BitVector
 SystemZRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
   BitVector Reserved(getNumRegs());

diff  --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
index cbc02c73f1ac70..4f497f8d23d29a 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.h
@@ -161,6 +161,7 @@ struct SystemZRegisterInfo : public SystemZGenRegisterInfo {
   const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
   const uint32_t *getCallPreservedMask(const MachineFunction &MF,
                                        CallingConv::ID CC) const override;
+  const uint32_t *getNoPreservedMask() const override;
   BitVector getReservedRegs(const MachineFunction &MF) const override;
   bool eliminateFrameIndex(MachineBasicBlock::iterator MI,
                            int SPAdj, unsigned FIOperandNum,

diff  --git a/llvm/test/CodeGen/SystemZ/builtin-longjmp.ll b/llvm/test/CodeGen/SystemZ/builtin-longjmp.ll
new file mode 100644
index 00000000000000..e10f8f82064b44
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/builtin-longjmp.ll
@@ -0,0 +1,49 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; Test longjmp load from jmp_buf.
+; Frame pointer from Slot 1.
+; Jump address from Slot 2.
+; Backchain Value from Slot 3.
+; Stack Pointer from Slot 4.
+; Literal Pool Pointer from Slot 5.
+
+; RUN: llc < %s -mtriple=s390x-linux-gnu -O2 | FileCheck %s
+
+ at buf = global [20 x ptr] zeroinitializer, align 8
+
+define void @foo() {
+; CHECK-LABEL: foo:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r11, %r15, 88(%r15)
+; CHECK-NEXT:    .cfi_offset %r11, -72
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    lgrl %r1, buf at GOT
+; CHECK-NEXT:    lg %r2, 8(%r1)
+; CHECK-NEXT:    lg %r11, 0(%r1)
+; CHECK-NEXT:    lg %r13, 32(%r1)
+; CHECK-NEXT:    lg %r15, 24(%r1)
+; CHECK-NEXT:    br %r2
+entry:
+  tail call void @llvm.eh.sjlj.longjmp(ptr nonnull @buf)
+  unreachable
+}
+
+define void @bar()  "backchain" {
+; CHECK-LABEL: bar:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r11, %r15, 88(%r15)
+; CHECK-NEXT:    .cfi_offset %r11, -72
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    lgrl %r1, buf at GOT
+; CHECK-NEXT:    lg %r2, 8(%r1)
+; CHECK-NEXT:    lg %r11, 0(%r1)
+; CHECK-NEXT:    lg %r13, 32(%r1)
+; CHECK-NEXT:    lg %r3, 16(%r1)
+; CHECK-NEXT:    lg %r15, 24(%r1)
+; CHECK-NEXT:    stg %r3, 0(%r15)
+; CHECK-NEXT:    br %r2
+entry:
+  tail call void @llvm.eh.sjlj.longjmp(ptr nonnull @buf)
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/SystemZ/builtin-setjmp-alloca.ll b/llvm/test/CodeGen/SystemZ/builtin-setjmp-alloca.ll
new file mode 100644
index 00000000000000..cc7d9c33c02c5b
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/builtin-setjmp-alloca.ll
@@ -0,0 +1,156 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; Test setjmp  store to jmp_buf when frame pointer is used and saved
+; because of variable size alloca.
+; Frame Pointer is stored in slot 1.
+; Return address in slot 2.
+; Backchain value is stored in slot 3 for -mbackchain option.
+; Stack Pointer in slot 4.
+; Clobber %r6-%r15, %f8-%f15.
+
+; RUN: llc < %s -mtriple=s390x-linux-gnu -O2 | FileCheck %s
+
+declare i32 @llvm.eh.sjlj.setjmp(ptr)
+ at buf = global [20 x ptr] zeroinitializer, align 8
+
+define signext i32 @foo() "frame-pointer"="all" {
+; CHECK-LABEL: foo:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r6, %r15, 48(%r15)
+; CHECK-NEXT:    .cfi_offset %r6, -112
+; CHECK-NEXT:    .cfi_offset %r7, -104
+; CHECK-NEXT:    .cfi_offset %r8, -96
+; CHECK-NEXT:    .cfi_offset %r9, -88
+; CHECK-NEXT:    .cfi_offset %r10, -80
+; CHECK-NEXT:    .cfi_offset %r11, -72
+; CHECK-NEXT:    .cfi_offset %r12, -64
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -240
+; CHECK-NEXT:    .cfi_def_cfa_offset 400
+; CHECK-NEXT:    lgr %r11, %r15
+; CHECK-NEXT:    .cfi_def_cfa_register %r11
+; CHECK-NEXT:    std %f8, 232(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f9, 224(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f10, 216(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f11, 208(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f12, 200(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f13, 192(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f14, 184(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f15, 176(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset %f8, -168
+; CHECK-NEXT:    .cfi_offset %f9, -176
+; CHECK-NEXT:    .cfi_offset %f10, -184
+; CHECK-NEXT:    .cfi_offset %f11, -192
+; CHECK-NEXT:    .cfi_offset %f12, -200
+; CHECK-NEXT:    .cfi_offset %f13, -208
+; CHECK-NEXT:    .cfi_offset %f14, -216
+; CHECK-NEXT:    .cfi_offset %f15, -224
+; CHECK-NEXT:    la %r0, 160(%r11)
+; CHECK-NEXT:    lgrl %r1, buf at GOT
+; CHECK-NEXT:    stg %r0, 168(%r11)
+; CHECK-NEXT:    mvhi 160(%r11), 10
+; CHECK-NEXT:    larl %r0, .LBB0_1
+; CHECK-NEXT:    stg %r0, 8(%r1)
+; CHECK-NEXT:    stg %r11, 0(%r1)
+; CHECK-NEXT:    stg %r15, 24(%r1)
+; CHECK-NEXT:  .LBB0_1: # Block address taken
+; CHECK-NEXT:    # %entry
+; CHECK-NEXT:  .LBB0_2: # %entry
+; CHECK-NEXT:    lg %r1, 168(%r11)
+; CHECK-NEXT:    lgf %r2, 0(%r1)
+; CHECK-NEXT:    ld %f8, 232(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f9, 224(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f10, 216(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f11, 208(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f12, 200(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f13, 192(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f14, 184(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f15, 176(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    lmg %r6, %r15, 288(%r11)
+; CHECK-NEXT:    br %r14
+entry:
+  %val = alloca ptr, align 8
+  %0 = alloca i8, i64 4, align 8
+  store ptr %0, ptr %val, align 8
+  %1 = load ptr, ptr %val, align 8
+  store volatile i32 10, ptr %1, align 4
+  %2 = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
+  %3 = load ptr, ptr %val, align 8
+  %4 = load volatile i32, ptr %3, align 4
+  ret i32 %4
+}
+
+define signext i32 @foo1() "backchain" "frame-pointer"="all" {
+; CHECK-LABEL: foo1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r6, %r15, 48(%r15)
+; CHECK-NEXT:    .cfi_offset %r6, -112
+; CHECK-NEXT:    .cfi_offset %r7, -104
+; CHECK-NEXT:    .cfi_offset %r8, -96
+; CHECK-NEXT:    .cfi_offset %r9, -88
+; CHECK-NEXT:    .cfi_offset %r10, -80
+; CHECK-NEXT:    .cfi_offset %r11, -72
+; CHECK-NEXT:    .cfi_offset %r12, -64
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    lgr %r1, %r15
+; CHECK-NEXT:    aghi %r15, -240
+; CHECK-NEXT:    .cfi_def_cfa_offset 400
+; CHECK-NEXT:    stg %r1, 0(%r15)
+; CHECK-NEXT:    lgr %r11, %r15
+; CHECK-NEXT:    .cfi_def_cfa_register %r11
+; CHECK-NEXT:    std %f8, 232(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f9, 224(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f10, 216(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f11, 208(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f12, 200(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f13, 192(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f14, 184(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f15, 176(%r11) # 8-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset %f8, -168
+; CHECK-NEXT:    .cfi_offset %f9, -176
+; CHECK-NEXT:    .cfi_offset %f10, -184
+; CHECK-NEXT:    .cfi_offset %f11, -192
+; CHECK-NEXT:    .cfi_offset %f12, -200
+; CHECK-NEXT:    .cfi_offset %f13, -208
+; CHECK-NEXT:    .cfi_offset %f14, -216
+; CHECK-NEXT:    .cfi_offset %f15, -224
+; CHECK-NEXT:    la %r0, 160(%r11)
+; CHECK-NEXT:    lgrl %r1, buf at GOT
+; CHECK-NEXT:    stg %r0, 168(%r11)
+; CHECK-NEXT:    mvhi 160(%r11), 10
+; CHECK-NEXT:    larl %r0, .LBB1_1
+; CHECK-NEXT:    stg %r0, 8(%r1)
+; CHECK-NEXT:    stg %r11, 0(%r1)
+; CHECK-NEXT:    stg %r15, 24(%r1)
+; CHECK-NEXT:    lg %r0, 0(%r15)
+; CHECK-NEXT:    stg %r0, 16(%r1)
+; CHECK-NEXT:  .LBB1_1: # Block address taken
+; CHECK-NEXT:    # %entry
+; CHECK-NEXT:  .LBB1_2: # %entry
+; CHECK-NEXT:    lg %r1, 168(%r11)
+; CHECK-NEXT:    lgf %r2, 0(%r1)
+; CHECK-NEXT:    ld %f8, 232(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f9, 224(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f10, 216(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f11, 208(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f12, 200(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f13, 192(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f14, 184(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f15, 176(%r11) # 8-byte Folded Reload
+; CHECK-NEXT:    lmg %r6, %r15, 288(%r11)
+; CHECK-NEXT:    br %r14
+entry:
+  %val = alloca ptr, align 8
+  %0 = alloca i8, i64 4, align 8
+  store ptr %0, ptr %val, align 8
+  %1 = load ptr, ptr %val, align 8
+  store volatile i32 10, ptr %1, align 4
+  %2 = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
+  %3 = load ptr, ptr %val, align 8
+  %4 = load volatile i32, ptr %3, align 4
+  ret i32 %4
+}
+

diff  --git a/llvm/test/CodeGen/SystemZ/builtin-setjmp-spills.ll b/llvm/test/CodeGen/SystemZ/builtin-setjmp-spills.ll
new file mode 100644
index 00000000000000..08871b342a3bd0
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/builtin-setjmp-spills.ll
@@ -0,0 +1,254 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; Simulate register pressure around setjmp call and check all virtual registers
+; are saved to stack before setjmp call and restored from stack after the call.
+; And these registers are not live across the setjmp call.
+; setjmp storing to jmp_buf.
+; Return address in slot 2.
+; Stack Pointer in slot 4.
+; Clobber %r6-%r15, %f8-%f15.
+
+; RUN: llc < %s -mtriple=s390x-linux-gnu -O3 | FileCheck %s
+
+declare i32 @llvm.eh.sjlj.setjmp(ptr)
+
+ at t = global i32 0, align 4
+ at s = global i32 0, align 4
+ at r = global i32 0, align 4
+ at q = global i32 0, align 4
+ at p = global i32 0, align 4
+ at o = global i32 0, align 4
+ at n = global i32 0, align 4
+ at m = global i32 0, align 4
+ at l = global i32 0, align 4
+ at k = global i32 0, align 4
+ at j = global i32 0, align 4
+ at i = global i32 0, align 4
+ at h = global i32 0, align 4
+ at g = global i32 0, align 4
+ at f = global i32 0, align 4
+ at e = global i32 0, align 4
+ at d = global i32 0, align 4
+ at c = global i32 0, align 4
+ at b = global i32 0, align 4
+ at a = global i32 0, align 4
+ at buf = global [10 x ptr] zeroinitializer, align 8
+
+define signext i32 @func() {
+; CHECK-LABEL: func:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r6, %r15, 48(%r15)
+; CHECK-NEXT:    .cfi_offset %r6, -112
+; CHECK-NEXT:    .cfi_offset %r7, -104
+; CHECK-NEXT:    .cfi_offset %r8, -96
+; CHECK-NEXT:    .cfi_offset %r9, -88
+; CHECK-NEXT:    .cfi_offset %r10, -80
+; CHECK-NEXT:    .cfi_offset %r11, -72
+; CHECK-NEXT:    .cfi_offset %r12, -64
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -384
+; CHECK-NEXT:    .cfi_def_cfa_offset 544
+; CHECK-NEXT:    std %f8, 376(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f9, 368(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f10, 360(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f11, 352(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f12, 344(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f13, 336(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f14, 328(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f15, 320(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset %f8, -168
+; CHECK-NEXT:    .cfi_offset %f9, -176
+; CHECK-NEXT:    .cfi_offset %f10, -184
+; CHECK-NEXT:    .cfi_offset %f11, -192
+; CHECK-NEXT:    .cfi_offset %f12, -200
+; CHECK-NEXT:    .cfi_offset %f13, -208
+; CHECK-NEXT:    .cfi_offset %f14, -216
+; CHECK-NEXT:    .cfi_offset %f15, -224
+; CHECK-NEXT:    lgrl %r1, t at GOT
+; CHECK-NEXT:    lgrl %r2, s at GOT
+; CHECK-NEXT:    stg %r1, 312(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r1), 1
+; CHECK-NEXT:    lgrl %r1, r at GOT
+; CHECK-NEXT:    lgrl %r3, q at GOT
+; CHECK-NEXT:    stg %r2, 304(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r2), 1
+; CHECK-NEXT:    lgrl %r2, p at GOT
+; CHECK-NEXT:    stg %r1, 296(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r1), 1
+; CHECK-NEXT:    stg %r3, 288(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r3), 1
+; CHECK-NEXT:    lgrl %r1, o at GOT
+; CHECK-NEXT:    stg %r2, 280(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r2), 1
+; CHECK-NEXT:    lgrl %r2, n at GOT
+; CHECK-NEXT:    lgrl %r3, m at GOT
+; CHECK-NEXT:    stg %r1, 272(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r1), 1
+; CHECK-NEXT:    lgrl %r1, l at GOT
+; CHECK-NEXT:    stg %r2, 264(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r2), 1
+; CHECK-NEXT:    stg %r3, 256(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r3), 1
+; CHECK-NEXT:    lgrl %r2, k at GOT
+; CHECK-NEXT:    stg %r1, 248(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r1), 1
+; CHECK-NEXT:    lgrl %r1, j at GOT
+; CHECK-NEXT:    lgrl %r3, i at GOT
+; CHECK-NEXT:    stg %r2, 240(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r2), 1
+; CHECK-NEXT:    lgrl %r2, h at GOT
+; CHECK-NEXT:    stg %r1, 232(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r1), 1
+; CHECK-NEXT:    stg %r3, 224(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r3), 1
+; CHECK-NEXT:    lgrl %r1, g at GOT
+; CHECK-NEXT:    stg %r2, 216(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r2), 1
+; CHECK-NEXT:    lgrl %r2, f at GOT
+; CHECK-NEXT:    lgrl %r3, e at GOT
+; CHECK-NEXT:    stg %r1, 208(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r1), 1
+; CHECK-NEXT:    lgrl %r1, d at GOT
+; CHECK-NEXT:    stg %r2, 200(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r2), 1
+; CHECK-NEXT:    stg %r3, 192(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r3), 1
+; CHECK-NEXT:    lgrl %r2, c at GOT
+; CHECK-NEXT:    stg %r1, 184(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r1), 1
+; CHECK-NEXT:    lgrl %r3, b at GOT
+; CHECK-NEXT:    lgrl %r4, a at GOT
+; CHECK-NEXT:    stg %r2, 176(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r2), 1
+; CHECK-NEXT:    lgrl %r1, buf at GOT
+; CHECK-NEXT:    stg %r3, 168(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r3), 1
+; CHECK-NEXT:    stg %r4, 160(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    mvhi 0(%r4), 1
+; CHECK-NEXT:    larl %r0, .LBB0_2
+; CHECK-NEXT:    stg %r0, 8(%r1)
+; CHECK-NEXT:    stg %r15, 24(%r1)
+; CHECK-NEXT:  .LBB0_1: # %entry
+; CHECK-NEXT:    lhi %r0, 0
+; CHECK-NEXT:    j .LBB0_3
+; CHECK-NEXT:  .LBB0_2: # Block address taken
+; CHECK-NEXT:    # %entry
+; CHECK-NEXT:    lhi %r0, 1
+; CHECK-NEXT:  .LBB0_3: # %entry
+; CHECK-NEXT:    lg %r1, 160(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 168(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 176(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 184(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 192(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 200(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 208(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 216(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 224(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 232(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 240(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 248(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 256(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 264(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 272(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 280(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 288(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 296(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 304(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lg %r1, 312(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    a %r0, 0(%r1)
+; CHECK-NEXT:    lgfr %r2, %r0
+; CHECK-NEXT:    ld %f8, 376(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f9, 368(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f10, 360(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f11, 352(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f12, 344(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f13, 336(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f14, 328(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f15, 320(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    lmg %r6, %r15, 432(%r15)
+; CHECK-NEXT:    br %r14
+entry:
+  store i32 1, ptr @t, align 4
+  store i32 1, ptr @s, align 4
+  store i32 1, ptr @r, align 4
+  store i32 1, ptr @q, align 4
+  store i32 1, ptr @p, align 4
+  store i32 1, ptr @o, align 4
+  store i32 1, ptr @n, align 4
+  store i32 1, ptr @m, align 4
+  store i32 1, ptr @l, align 4
+  store i32 1, ptr @k, align 4
+  store i32 1, ptr @j, align 4
+  store i32 1, ptr @i, align 4
+  store i32 1, ptr @h, align 4
+  store i32 1, ptr @g, align 4
+  store i32 1, ptr @f, align 4
+  store i32 1, ptr @e, align 4
+  store i32 1, ptr @d, align 4
+  store i32 1, ptr @c, align 4
+  store i32 1, ptr @b, align 4
+  store i32 1, ptr @a, align 4
+  %0 = tail call i32 @llvm.eh.sjlj.setjmp(ptr nonnull @buf)
+  %1 = load i32, ptr @a, align 4
+  %2 = load i32, ptr @b, align 4
+  %3 = load i32, ptr @c, align 4
+  %4 = load i32, ptr @d, align 4
+  %5 = load i32, ptr @e, align 4
+  %6 = load i32, ptr @f, align 4
+  %7 = load i32, ptr @g, align 4
+  %8 = load i32, ptr @h, align 4
+  %9 = load i32, ptr @i, align 4
+  %10 = load i32, ptr @j, align 4
+  %11 = load i32, ptr @k, align 4
+  %12 = load i32, ptr @l, align 4
+  %13 = load i32, ptr @m, align 4
+  %14 = load i32, ptr @n, align 4
+  %15 = load i32, ptr @o, align 4
+  %16 = load i32, ptr @p, align 4
+  %17 = load i32, ptr @q, align 4
+  %18 = load i32, ptr @r, align 4
+  %19 = load i32, ptr @s, align 4
+  %20 = load i32, ptr @t, align 4
+  %add = add i32 %1, %0
+  %add1 = add i32 %add, %2
+  %add2 = add i32 %add1, %3
+  %add3 = add i32 %add2, %4
+  %add4 = add i32 %add3, %5
+  %add5 = add i32 %add4, %6
+  %add6 = add i32 %add5, %7
+  %add7 = add i32 %add6, %8
+  %add8 = add i32 %add7, %9
+  %add9 = add i32 %add8, %10
+  %add10 = add i32 %add9, %11
+  %add11 = add i32 %add10, %12
+  %add12 = add i32 %add11, %13
+  %add13 = add i32 %add12, %14
+  %add14 = add i32 %add13, %15
+  %add15 = add i32 %add14, %16
+  %add16 = add i32 %add15, %17
+  %add17 = add i32 %add16, %18
+  %add18 = add i32 %add17, %19
+  %add19 = add i32 %add18, %20
+  ret i32 %add19
+}
+

diff  --git a/llvm/test/CodeGen/SystemZ/builtin-setjmp.ll b/llvm/test/CodeGen/SystemZ/builtin-setjmp.ll
new file mode 100644
index 00000000000000..f381b875ae3a98
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/builtin-setjmp.ll
@@ -0,0 +1,124 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; Test setjmp store jmp_buf
+; Return address in slot 2.
+; Backchain value is stored in slot 3 for -mbackchain option.
+; Stack Pointer in slot 4.
+; Clobber %r6-%r15, %f8-%f15.
+
+; RUN: llc < %s -mtriple=s390x-linux-gnu -O2 | FileCheck %s
+
+declare i32 @llvm.eh.sjlj.setjmp(ptr)
+ at buf = global [20 x ptr] zeroinitializer, align 8
+
+define void @foo() {
+; CHECK-LABEL: foo:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r6, %r15, 48(%r15)
+; CHECK-NEXT:    .cfi_offset %r6, -112
+; CHECK-NEXT:    .cfi_offset %r7, -104
+; CHECK-NEXT:    .cfi_offset %r8, -96
+; CHECK-NEXT:    .cfi_offset %r9, -88
+; CHECK-NEXT:    .cfi_offset %r10, -80
+; CHECK-NEXT:    .cfi_offset %r11, -72
+; CHECK-NEXT:    .cfi_offset %r12, -64
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -64
+; CHECK-NEXT:    .cfi_def_cfa_offset 224
+; CHECK-NEXT:    std %f8, 56(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f9, 48(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f10, 40(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f11, 32(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f12, 24(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f13, 16(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f14, 8(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f15, 0(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset %f8, -168
+; CHECK-NEXT:    .cfi_offset %f9, -176
+; CHECK-NEXT:    .cfi_offset %f10, -184
+; CHECK-NEXT:    .cfi_offset %f11, -192
+; CHECK-NEXT:    .cfi_offset %f12, -200
+; CHECK-NEXT:    .cfi_offset %f13, -208
+; CHECK-NEXT:    .cfi_offset %f14, -216
+; CHECK-NEXT:    .cfi_offset %f15, -224
+; CHECK-NEXT:    lgrl %r1, buf at GOT
+; CHECK-NEXT:    larl %r0, .LBB0_1
+; CHECK-NEXT:    stg %r0, 8(%r1)
+; CHECK-NEXT:    stg %r15, 24(%r1)
+; CHECK-NEXT:  .LBB0_1: # Block address taken
+; CHECK-NEXT:    # %entry
+; CHECK-NEXT:  .LBB0_2: # %entry
+; CHECK-NEXT:    ld %f8, 56(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f9, 48(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f10, 40(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f11, 32(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f12, 24(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f13, 16(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f14, 8(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f15, 0(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    lmg %r6, %r15, 112(%r15)
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i32 @llvm.eh.sjlj.setjmp(ptr nonnull @buf)
+  ret void
+}
+
+define void @foo1() "backchain" {
+; CHECK-LABEL: foo1:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r6, %r15, 48(%r15)
+; CHECK-NEXT:    .cfi_offset %r6, -112
+; CHECK-NEXT:    .cfi_offset %r7, -104
+; CHECK-NEXT:    .cfi_offset %r8, -96
+; CHECK-NEXT:    .cfi_offset %r9, -88
+; CHECK-NEXT:    .cfi_offset %r10, -80
+; CHECK-NEXT:    .cfi_offset %r11, -72
+; CHECK-NEXT:    .cfi_offset %r12, -64
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    lgr %r1, %r15
+; CHECK-NEXT:    aghi %r15, -64
+; CHECK-NEXT:    .cfi_def_cfa_offset 224
+; CHECK-NEXT:    stg %r1, 0(%r15)
+; CHECK-NEXT:    std %f8, 56(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f9, 48(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f10, 40(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f11, 32(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f12, 24(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f13, 16(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f14, 8(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    std %f15, 0(%r15) # 8-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset %f8, -168
+; CHECK-NEXT:    .cfi_offset %f9, -176
+; CHECK-NEXT:    .cfi_offset %f10, -184
+; CHECK-NEXT:    .cfi_offset %f11, -192
+; CHECK-NEXT:    .cfi_offset %f12, -200
+; CHECK-NEXT:    .cfi_offset %f13, -208
+; CHECK-NEXT:    .cfi_offset %f14, -216
+; CHECK-NEXT:    .cfi_offset %f15, -224
+; CHECK-NEXT:    lgrl %r1, buf at GOT
+; CHECK-NEXT:    larl %r0, .LBB1_1
+; CHECK-NEXT:    stg %r0, 8(%r1)
+; CHECK-NEXT:    stg %r15, 24(%r1)
+; CHECK-NEXT:    lg %r0, 0(%r15)
+; CHECK-NEXT:    stg %r0, 16(%r1)
+; CHECK-NEXT:  .LBB1_1: # Block address taken
+; CHECK-NEXT:    # %entry
+; CHECK-NEXT:  .LBB1_2: # %entry
+; CHECK-NEXT:    ld %f8, 56(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f9, 48(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f10, 40(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f11, 32(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f12, 24(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f13, 16(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f14, 8(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    ld %f15, 0(%r15) # 8-byte Folded Reload
+; CHECK-NEXT:    lmg %r6, %r15, 112(%r15)
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i32 @llvm.eh.sjlj.setjmp(ptr nonnull @buf)
+  ret void
+}
+


        


More information about the cfe-commits mailing list