Skip to content

[SystemZ] Add support for __builtin_setjmp and __builtin_longjmp #116642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Dec 6, 2024

Conversation

anoopkg6
Copy link
Contributor

Implementation for __builtin_setjmp and __builtin_longjmp for SystemZ.

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:SystemZ clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. labels Nov 18, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 18, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-backend-systemz

Author: None (anoopkg6)

Changes

Implementation for __builtin_setjmp and __builtin_longjmp for SystemZ.


Patch is 665.11 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/116642.diff

76 Files Affected:

  • (modified) clang/lib/Basic/Targets/SystemZ.h (+2)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+6)
  • (modified) llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp (+4)
  • (modified) llvm/lib/Target/SystemZ/SystemZISelLowering.cpp (+252-1)
  • (modified) llvm/lib/Target/SystemZ/SystemZISelLowering.h (+7)
  • (modified) llvm/lib/Target/SystemZ/SystemZInstrInfo.td (+14)
  • (modified) llvm/lib/Target/SystemZ/SystemZLongBranch.cpp (+4-1)
  • (modified) llvm/lib/Target/SystemZ/SystemZOperators.td (+12)
  • (modified) llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp (+5)
  • (modified) llvm/lib/Target/SystemZ/SystemZRegisterInfo.h (+1)
  • (added) llvm/test/CodeGen/SystemZ/builtin-longjmp-01.ll (+44)
  • (added) llvm/test/CodeGen/SystemZ/builtin-longjmp-backchain-01.ll (+46)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-01.ll (+60)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-backchain-01.ll (+65)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-01.ll (+72)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-02.ll (+101)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-03.ll (+87)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-04-o0.ll (+94)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-04-o2.ll (+93)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-00-o0.ll (+284)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-00-o2.ll (+170)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-00.ll (+170)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-01.ll (+343)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-02.ll (+329)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-03.ll (+1037)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-04-o0.ll (+149)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-04-o2.ll (+157)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-04.ll (+157)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-00-o0.ll (+286)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-00-o2.ll (+170)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-01.ll (+343)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-02.ll (+330)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-03.ll (+1038)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-04-o0.ll (+150)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-04-o2.ll (+133)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-01.ll (+73)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-02.ll (+82)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-03.ll (+88)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-04-o0.ll (+95)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-04-o2.ll (+95)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-00.ll (+94)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-01.ll (+203)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-02.ll (+276)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-03.ll (+291)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-04.ll (+264)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-00.ll (+94)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-01.ll (+175)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-02.ll (+277)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-03.ll (+290)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-04.ll (+264)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-global-02-o2.ll (+133)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-global-0l-o2.ll (+109)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-global-backchain-02-o2.ll (+135)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-global-backchain-0l-o2.ll (+111)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-01-o0.ll (+105)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-02-o0.ll (+147)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-03.ll (+393)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-backchain-01-o0.ll (+106)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-backchain-02-o0.ll (+147)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-backchain-03.ll (+393)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-volatile-01-o2.ll (+104)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-volatile-02-o2.ll (+122)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-volatile-backchain-01-o2.ll (+105)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-volatile-backchain-02-o2.ll (+124)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-01.ll (+245)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-02.ll (+152)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-03.ll (+223)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-backchain-01.ll (+246)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-backchain-02.ll (+153)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-backchain-03.ll (+225)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-01.ll (+243)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-02.ll (+151)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-03.ll (+222)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-backchain-01.ll (+241)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-backchain-02.ll (+155)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-backchain-03.ll (+227)
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 e2d03eff8ab4a0..1de6aded302ceb 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4619,6 +4619,12 @@ 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) {
+      // Call LLVM's EH setjmp, which is lightweight.
+      Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp);
+      return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this)));
+    }
+
     // Store the frame pointer to the setjmp buffer.
     Value *FrameAddr = Builder.CreateCall(
         CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy),
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 050a482c69d528..a75dac5b91ceca 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -687,6 +687,10 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
         MCInstBuilder(SystemZ::EXRL).addReg(LenMinus1Reg).addExpr(Dot));
     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);
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 3e05f3b0180a78..f498f9eab865f1 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -751,6 +751,13 @@ 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,7 +947,242 @@ bool SystemZTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
   return SystemZVectorConstantInfo(Imm).isVectorConstantLegal(Subtarget);
 }
 
-/// Returns true if stack probing through inline assembly is requested.
+
+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[0] = 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 LabelOffset = 1 * PVT.getStoreSize(); // Slot 2.
+  const int64_t SPOffset = 3 * PVT.getStoreSize(); // Slot 4.
+
+  // Buf address.
+  Register BufReg = MI.getOperand(1).getReg();
+
+  unsigned LabelReg = 0;
+  const TargetRegisterClass *PtrRC = getRegClassFor(PVT);
+  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);
+
+  bool HasFP =  Subtarget.getFrameLowering()->hasFP(*MF);
+  if (HasFP) {
+     const int64_t FPOffset = 0; 
+     BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
+          .addReg(SystemZ::R11D)
+          .addReg(BufReg)
+          .addImm(FPOffset)
+          .addReg(0);
+  }
+  
+  // store SP.
+  BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
+          .addReg(SystemZ::R15D)
+          .addReg(BufReg)
+          .addImm(SPOffset)
+          .addReg(0);
+
+  // Slot 3(Offset = 2) Backchain value (if building with -mbackchain).
+  bool BackChain = MF->getSubtarget<SystemZSubtarget>().hasBackChain();
+  if (BackChain) {
+     const int64_t BCOffset    = 2 * PVT.getStoreSize();
+     Register BCReg = MRI.createVirtualRegister(RC);
+     MIB = BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::LG), BCReg)
+             .addReg(SystemZ::R15D)
+             .addImm(0)
+             .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);
+
+  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 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), SystemZ::R11D)
+             .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) {
+     const int64_t BCOffset    = 2 * PVT.getStoreSize();
+     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), SystemZ::R15D)
+             .addReg(BufReg)
+             .addImm(SPOffset)
+             .addReg(0);
+
+  if (BackChain) {
+     BuildMI(*MBB, MI, DL, TII->get(SystemZ::STG))
+          .addReg(BCReg)
+          .addReg(SystemZ::R15D)
+          .addImm(0)
+          .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.
   if (MF.getFunction().hasFnAttribute("probe-stack"))
@@ -6292,6 +6534,10 @@ 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:
+    return Op;
+
   default:
     llvm_unreachable("Unexpected node to lower");
   }
@@ -9724,6 +9970,11 @@ 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..92ac938c903b68 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;
@@ -723,6 +729,7 @@ class SystemZTargetLowering : public TargetLowering {
   SDValue lowerGET_ROUNDING(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerREADCYCLECOUNTER(SDValue Op, SelectionDAG &DAG) const;
 
+
   bool canTreatAsByteVector(EVT VT) const;
   SDValue combineExtract(const SDLoc &DL, EVT ElemVT, EVT VecVT, SDValue OrigOp,
                          unsigned Index, DAGCombinerInfo &DCI,
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index f3baf896658de5..ad7ee522a8c6f7 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -1871,6 +1871,20 @@ let mayLoad = 1, mayStore = 1, Defs = [CC] in {
   }
 }
 
+//--------------------------------------------------------------------------
+// Setjmp/Longjmp.
+//--------------------------------------------------------------------------
+let isTerminator = 1, isBarrier = 1, isCodeGenOnly = 1,  hasNoSchedulingInfo = 1, Size = 0 in {
+  def EH_SjLj_Setup : Pseudo<(outs), (ins brtarget32:$dst), []>;
+}
+
+let hasSideEffects = 1, isBarrier = 1, usesCustomInserter = 1, hasNoSchedulingInfo = 1 in {
+  def EH_SjLj_SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2), [(set GR32:$dst, (z_eh_sjlj_setjmp ADDR64:$R2))]>;
+}
+
+let hasSideEffects = 1, isTerminator = 1, isBarrier = 1, usesCustomInserter = 1, hasNoSchedulingInfo = 1 in {
+  def EH_SjLj_LongJmp : Pseudo<(outs), (ins ADDR64:$R2), [(z_eh_sjlj_longjmp  ADDR64:$R2)]>;
+}
 //===----------------------------------------------------------------------===//
 // Message-security assist
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
index 632218cc61eefe..8267d398c50ed6 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..6d3e542c1b4e81 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
@@ -254,6 +254,11 @@ 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-01.ll b/llvm/test/CodeGen/SystemZ/builtin-longjmp-01.ll
new file mode 100644
index 00000000000000..413b651acb64a7
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/builtin-longjmp-01.ll
@@ -0,0 +1,44 @@
+;Test  longjmp load from jmp_buf.
+; Frame pointer from Slot 1.
+; Jump address from Slot 2.
+; Stack Pointer from Slot 4.
+; Literal Pool Pointer from Slot 5.
+
+; RUN: llc -O2 < %s | FileCheck %s
+
+
+; ModuleID = 'longjmp.c'
+source_filename = "longjmp.c"
+target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
+target triple = "s390x-unknown-linux-gnu"
+
+@buf = dso_local global [20 x ptr] zeroinitializer, align 8
+
+; Function Attrs: noreturn nounwind
+define dso_local void @foo() local_unnamed_addr #0 {
+entry:
+; CHECK:        stmg    %r11, %r15, 88(%r15)
+; CHECK:        larl    %r1, buf
+; CHECK:        lg      %r2, 8(%r1)
+; CHECK:        lg      %r11, 0(%r1)
+; CHECK:        lg      %r13, 32(%r1)
+; CHECK:        lg      %r15, 24(%r1)
+; CHECK:        br      %r2
+
+  tail call void @llvm.eh.sjlj.longjmp(ptr nonnull @buf)
+  unreachable
+}
+
+; Function Attrs: noreturn nounwind
+declare void @llvm.eh.sjlj.longjmp(ptr) #1
+
+attributes #0 = { noreturn nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="z10" }
+attributes #1 = { noreturn nounwind }
+
+!llvm.module.flags = !{!0, !1, !2}
+!llvm.ident = !{!3}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
+!3 = !{!"clang version 20.0.0git (https://github.com/llvm/llvm-project.git 79880371396d6e486bf6bacd6c4087ebdac591f8)"}
diff --git a/llvm/test/CodeGen/SystemZ/builtin-longjmp-backchain-01.ll b/llvm/test/CodeGen/SystemZ/builtin-longjmp-backchain-01.ll
new file mode 100644
index 00000000000000..39ee483c27cbd5
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/builtin-longjmp-backchain-01.ll
@@ -0,0 +1,46 @@
+;Test -mba...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Nov 18, 2024

@llvm/pr-subscribers-clang-codegen

Author: None (anoopkg6)

Changes

Implementation for __builtin_setjmp and __builtin_longjmp for SystemZ.


Patch is 665.11 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/116642.diff

76 Files Affected:

  • (modified) clang/lib/Basic/Targets/SystemZ.h (+2)
  • (modified) clang/lib/CodeGen/CGBuiltin.cpp (+6)
  • (modified) llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp (+4)
  • (modified) llvm/lib/Target/SystemZ/SystemZISelLowering.cpp (+252-1)
  • (modified) llvm/lib/Target/SystemZ/SystemZISelLowering.h (+7)
  • (modified) llvm/lib/Target/SystemZ/SystemZInstrInfo.td (+14)
  • (modified) llvm/lib/Target/SystemZ/SystemZLongBranch.cpp (+4-1)
  • (modified) llvm/lib/Target/SystemZ/SystemZOperators.td (+12)
  • (modified) llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp (+5)
  • (modified) llvm/lib/Target/SystemZ/SystemZRegisterInfo.h (+1)
  • (added) llvm/test/CodeGen/SystemZ/builtin-longjmp-01.ll (+44)
  • (added) llvm/test/CodeGen/SystemZ/builtin-longjmp-backchain-01.ll (+46)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-01.ll (+60)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-backchain-01.ll (+65)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-01.ll (+72)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-02.ll (+101)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-03.ll (+87)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-04-o0.ll (+94)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-04-o2.ll (+93)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-00-o0.ll (+284)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-00-o2.ll (+170)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-00.ll (+170)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-01.ll (+343)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-02.ll (+329)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-03.ll (+1037)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-04-o0.ll (+149)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-04-o2.ll (+157)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-04.ll (+157)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-00-o0.ll (+286)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-00-o2.ll (+170)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-01.ll (+343)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-02.ll (+330)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-03.ll (+1038)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-04-o0.ll (+150)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-alloca-backchain-04-o2.ll (+133)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-01.ll (+73)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-02.ll (+82)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-03.ll (+88)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-04-o0.ll (+95)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-backchain-04-o2.ll (+95)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-00.ll (+94)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-01.ll (+203)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-02.ll (+276)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-03.ll (+291)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-04.ll (+264)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-00.ll (+94)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-01.ll (+175)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-02.ll (+277)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-03.ll (+290)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-literal-pool-backchain-04.ll (+264)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-global-02-o2.ll (+133)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-global-0l-o2.ll (+109)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-global-backchain-02-o2.ll (+135)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-global-backchain-0l-o2.ll (+111)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-01-o0.ll (+105)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-02-o0.ll (+147)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-03.ll (+393)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-backchain-01-o0.ll (+106)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-backchain-02-o0.ll (+147)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-local-backchain-03.ll (+393)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-volatile-01-o2.ll (+104)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-volatile-02-o2.ll (+122)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-volatile-backchain-01-o2.ll (+105)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-longjmp-malloc-volatile-backchain-02-o2.ll (+124)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-01.ll (+245)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-02.ll (+152)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-03.ll (+223)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-backchain-01.ll (+246)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-backchain-02.ll (+153)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-double-backchain-03.ll (+225)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-01.ll (+243)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-02.ll (+151)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-03.ll (+222)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-backchain-01.ll (+241)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-backchain-02.ll (+155)
  • (added) llvm/test/CodeGen/SystemZ/builtin-setjmp-spills-int-backchain-03.ll (+227)
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 e2d03eff8ab4a0..1de6aded302ceb 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4619,6 +4619,12 @@ 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) {
+      // Call LLVM's EH setjmp, which is lightweight.
+      Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp);
+      return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this)));
+    }
+
     // Store the frame pointer to the setjmp buffer.
     Value *FrameAddr = Builder.CreateCall(
         CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy),
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 050a482c69d528..a75dac5b91ceca 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -687,6 +687,10 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
         MCInstBuilder(SystemZ::EXRL).addReg(LenMinus1Reg).addExpr(Dot));
     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);
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 3e05f3b0180a78..f498f9eab865f1 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -751,6 +751,13 @@ 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,7 +947,242 @@ bool SystemZTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
   return SystemZVectorConstantInfo(Imm).isVectorConstantLegal(Subtarget);
 }
 
-/// Returns true if stack probing through inline assembly is requested.
+
+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[0] = 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 LabelOffset = 1 * PVT.getStoreSize(); // Slot 2.
+  const int64_t SPOffset = 3 * PVT.getStoreSize(); // Slot 4.
+
+  // Buf address.
+  Register BufReg = MI.getOperand(1).getReg();
+
+  unsigned LabelReg = 0;
+  const TargetRegisterClass *PtrRC = getRegClassFor(PVT);
+  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);
+
+  bool HasFP =  Subtarget.getFrameLowering()->hasFP(*MF);
+  if (HasFP) {
+     const int64_t FPOffset = 0; 
+     BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
+          .addReg(SystemZ::R11D)
+          .addReg(BufReg)
+          .addImm(FPOffset)
+          .addReg(0);
+  }
+  
+  // store SP.
+  BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::STG))
+          .addReg(SystemZ::R15D)
+          .addReg(BufReg)
+          .addImm(SPOffset)
+          .addReg(0);
+
+  // Slot 3(Offset = 2) Backchain value (if building with -mbackchain).
+  bool BackChain = MF->getSubtarget<SystemZSubtarget>().hasBackChain();
+  if (BackChain) {
+     const int64_t BCOffset    = 2 * PVT.getStoreSize();
+     Register BCReg = MRI.createVirtualRegister(RC);
+     MIB = BuildMI(*thisMBB, MI, DL, TII->get(SystemZ::LG), BCReg)
+             .addReg(SystemZ::R15D)
+             .addImm(0)
+             .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);
+
+  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 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), SystemZ::R11D)
+             .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) {
+     const int64_t BCOffset    = 2 * PVT.getStoreSize();
+     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), SystemZ::R15D)
+             .addReg(BufReg)
+             .addImm(SPOffset)
+             .addReg(0);
+
+  if (BackChain) {
+     BuildMI(*MBB, MI, DL, TII->get(SystemZ::STG))
+          .addReg(BCReg)
+          .addReg(SystemZ::R15D)
+          .addImm(0)
+          .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.
   if (MF.getFunction().hasFnAttribute("probe-stack"))
@@ -6292,6 +6534,10 @@ 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:
+    return Op;
+
   default:
     llvm_unreachable("Unexpected node to lower");
   }
@@ -9724,6 +9970,11 @@ 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..92ac938c903b68 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;
@@ -723,6 +729,7 @@ class SystemZTargetLowering : public TargetLowering {
   SDValue lowerGET_ROUNDING(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerREADCYCLECOUNTER(SDValue Op, SelectionDAG &DAG) const;
 
+
   bool canTreatAsByteVector(EVT VT) const;
   SDValue combineExtract(const SDLoc &DL, EVT ElemVT, EVT VecVT, SDValue OrigOp,
                          unsigned Index, DAGCombinerInfo &DCI,
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index f3baf896658de5..ad7ee522a8c6f7 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -1871,6 +1871,20 @@ let mayLoad = 1, mayStore = 1, Defs = [CC] in {
   }
 }
 
+//--------------------------------------------------------------------------
+// Setjmp/Longjmp.
+//--------------------------------------------------------------------------
+let isTerminator = 1, isBarrier = 1, isCodeGenOnly = 1,  hasNoSchedulingInfo = 1, Size = 0 in {
+  def EH_SjLj_Setup : Pseudo<(outs), (ins brtarget32:$dst), []>;
+}
+
+let hasSideEffects = 1, isBarrier = 1, usesCustomInserter = 1, hasNoSchedulingInfo = 1 in {
+  def EH_SjLj_SetJmp : Pseudo<(outs GR32:$dst), (ins ADDR64:$R2), [(set GR32:$dst, (z_eh_sjlj_setjmp ADDR64:$R2))]>;
+}
+
+let hasSideEffects = 1, isTerminator = 1, isBarrier = 1, usesCustomInserter = 1, hasNoSchedulingInfo = 1 in {
+  def EH_SjLj_LongJmp : Pseudo<(outs), (ins ADDR64:$R2), [(z_eh_sjlj_longjmp  ADDR64:$R2)]>;
+}
 //===----------------------------------------------------------------------===//
 // Message-security assist
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
index 632218cc61eefe..8267d398c50ed6 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..6d3e542c1b4e81 100644
--- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp
@@ -254,6 +254,11 @@ 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-01.ll b/llvm/test/CodeGen/SystemZ/builtin-longjmp-01.ll
new file mode 100644
index 00000000000000..413b651acb64a7
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/builtin-longjmp-01.ll
@@ -0,0 +1,44 @@
+;Test  longjmp load from jmp_buf.
+; Frame pointer from Slot 1.
+; Jump address from Slot 2.
+; Stack Pointer from Slot 4.
+; Literal Pool Pointer from Slot 5.
+
+; RUN: llc -O2 < %s | FileCheck %s
+
+
+; ModuleID = 'longjmp.c'
+source_filename = "longjmp.c"
+target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
+target triple = "s390x-unknown-linux-gnu"
+
+@buf = dso_local global [20 x ptr] zeroinitializer, align 8
+
+; Function Attrs: noreturn nounwind
+define dso_local void @foo() local_unnamed_addr #0 {
+entry:
+; CHECK:        stmg    %r11, %r15, 88(%r15)
+; CHECK:        larl    %r1, buf
+; CHECK:        lg      %r2, 8(%r1)
+; CHECK:        lg      %r11, 0(%r1)
+; CHECK:        lg      %r13, 32(%r1)
+; CHECK:        lg      %r15, 24(%r1)
+; CHECK:        br      %r2
+
+  tail call void @llvm.eh.sjlj.longjmp(ptr nonnull @buf)
+  unreachable
+}
+
+; Function Attrs: noreturn nounwind
+declare void @llvm.eh.sjlj.longjmp(ptr) #1
+
+attributes #0 = { noreturn nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="z10" }
+attributes #1 = { noreturn nounwind }
+
+!llvm.module.flags = !{!0, !1, !2}
+!llvm.ident = !{!3}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
+!3 = !{!"clang version 20.0.0git (https://github.com/llvm/llvm-project.git 79880371396d6e486bf6bacd6c4087ebdac591f8)"}
diff --git a/llvm/test/CodeGen/SystemZ/builtin-longjmp-backchain-01.ll b/llvm/test/CodeGen/SystemZ/builtin-longjmp-backchain-01.ll
new file mode 100644
index 00000000000000..39ee483c27cbd5
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/builtin-longjmp-backchain-01.ll
@@ -0,0 +1,46 @@
+;Test -mba...
[truncated]

Copy link

github-actions bot commented Nov 18, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@s-barannikov s-barannikov changed the title Support for __builtin_setjmp and __builtin_longjmp [SystemZ] Add support for __builtin_setjmp and __builtin_longjmp Nov 18, 2024
Copy link
Member

@uweigand uweigand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution! Please find a number of comments inline. Also, you should address the issues found by the CI, e.g. about coding style.

@@ -4619,6 +4619,12 @@ 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) {
// Call LLVM's EH setjmp, which is lightweight.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the comment here should explain that we're not filling any fields of the jmp_buf here and leave it all to the back-end.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little concerned about modifying the semantics of the intrinsic like this. I mean, the semantics are inherently a bit platform-specific, but this contradicts the documentation in llvm/docs/ExceptionHandling.rst.

If we need different semantics here for some reason, I'd prefer to use an intrinsic with a different name, to avoid any confusion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underlying problem is that current implementation and documentation of the builtin is somewhat inconsistent with itself. The documentation starts out with:

The buffer format and the overall functioning of this intrinsic is compatible with the GCC __builtin_setjmp implementation allowing code built with the clang and GCC to interoperate.

But in GCC the format of the buffer is completely target-dependent (and actually materially different between targets), while LLVM attempts to impose some constraints on certain fields. (These happen to be OK for the small subset of targets that currently implement these intrinsics in LLVM, but not all other GCC targets.)

Specifically, the LLVM documentation continues with

The front end places the frame pointer in the first word

Now, even in GCC every target places the frame pointer in the first word, but in GCC this means the contents of the target frame pointer register, if any is used. What clang puts into the first word, however, is the result of the frameaddress intrinsic - this value matches the frame pointer register contents on some but not all targets. On SystemZ these values differ, which would cause incompatibilties with GCC.

Finally, the clang front-end also writes the stack pointer into the third slot. Not only is this not even mentioned in the docs, it also does not match GCC behavior on all targets. While indeed all targets have the to save the stack pointer somewhere, they're not all using the third slot. On SystemZ we use the fourth slot.

It is a bit unclear to me what the purpose of writing those two slots in the front end is in the first place. It would seem more straightforward to just leave the writing of the buffer completely to the target back-end.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. That's pretty messy. See also 02269a6 and faa3abb . I think what happened is that the meaning of the intrinsic was adapted to suit sjlj lowering, and nobody really thought about trying to expose a stable interface to frontends.

I still think it's a bit of a hazard to adjust the semantics of the intrinsic at this point without changing the name. But there isn't any existing SystemZ bitcode to break, so it might be enough to just update the documentation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. It seems back in the day the eh.sjlj.setjmp intrinsic was used by both the front-end to implement __builtin_setjmp and by the middle-end (SjLjEHPrepare.cpp) for exception handling. Since these two users apparently require somewhat different information in the buffer, filling this in was left to the user.

However, these days those two users actually emit two different intrinsics. The middle-end now uses eh.sjlj.setup.dispatch (which is apparently only intended for internal usage; it's not documented at all), while only the front-end continues to use eh.sjlj.setjmp. See http://reviews.llvm.org/D9313.

I still think the most straightfoward way would be to have eh.sjlj.setjmp just be completely implemented in the back end, and simply do exactly what is needed to implement __builtin_setjmp on the platform, just like is done with longjmp. This could be done for all targets (probably the cleanest solution, but would require updating the existing targets and might introduce incompatibilities with existing bytecode on those targets), or just for selected targets (I guess this would then need to be documented? And should it be a positive or negative list of targets?).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I don't think there's any benefit to having the frontend to generate explicit stores. I just want to make sure whatever solution we choose, it doesn't silently break code generated by other frontends (or older versions of clang).

setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't add those additional newlines. One empty line is enough.

// Buf address.
Register BufReg = MI.getOperand(1).getReg();

unsigned LabelReg = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need the zero initialization here. Just move the declaration down.


bool HasFP = Subtarget.getFrameLowering()->hasFP(*MF);
if (HasFP) {
const int64_t FPOffset = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be preferable to have all five Offset constant declaration in one place near the top of the function.

@@ -723,6 +729,7 @@ class SystemZTargetLowering : public TargetLowering {
SDValue lowerGET_ROUNDING(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerREADCYCLECOUNTER(SDValue Op, SelectionDAG &DAG) const;


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be here.

//--------------------------------------------------------------------------
// Setjmp/Longjmp.
//--------------------------------------------------------------------------
let isTerminator = 1, isBarrier = 1, isCodeGenOnly = 1, hasNoSchedulingInfo = 1, Size = 0 in {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lines here and below are a bit long and should be broken up - see other statements in the file as examples.

; ModuleID = 'longjmp.c'
source_filename = "longjmp.c"
target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"
target triple = "s390x-unknown-linux-gnu"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you generated the test file via running clang. Usual practice is to try an strip the case down to the essentials, so you wouldn't have the datalayout/triple here, or all the attribute setting at the bottom. Have a look at the other files in the directory to see how this is usually done.

@@ -0,0 +1,72 @@
; Test output of setjmp/longjmp.
; RUN: clang -o %t %s
; RUN: %t | FileCheck %s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. This is a problem. The unit tests here cannot be execution tests; they'll have to run on any host system (e.g. on the automated CI on GitHub). You should try to test the critical codegen parts via compile-only test. If it makes sense to have additional execute test, they'll need to go somewhere else, e.g. the test-suite repository.

@uweigand
Copy link
Member

Hi @anoopkg6 , the tests are still failing in CI because this is hosted on an Intel machine, so when you run just with llc, it will attempt to build the test for Intel ...

To make sure the tests run correctly and always target s390x, you should use something along the following lines - see other tests in this directory for examples:

; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s

Copy link
Member

@uweigand uweigand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some additional comments on the test cases inline.

@buf = dso_local global [20 x ptr] zeroinitializer, align 8

; Function Attrs: noreturn nounwind
define dso_local void @foo() local_unnamed_addr #0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't need most of those annotations here. We do not need the Function Attrs comment, nor the #0 attribute reference (which doesn't even exist in this file!). We also do not need the dso_local or local_unnamed_addr markers.

; CHECK: lg %r15, 24(%r1)
; CHECK: br %r2

tail call void @llvm.eh.sjlj.longjmp(ptr nonnull @buf)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need a declaration of that intrinsic somewhere in this file?

@@ -0,0 +1,24 @@
;Test longjmp load from jmp_buf.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the white spaces. Space after ';', only one space between words.

; CHECK: lg %r11, 0(%r1)
; CHECK: lg %r13, 32(%r1)
; CHECK: lg %r15, 24(%r1)
; CHECK: br %r2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be preferable to auto-generate these checks. This can be done by running the utils/update_llc_test_checks.py script - see many of the other test cases. You'll have to pass the path to the llc binary you built via the --llc= option.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

B.t.w. the same applies to all the following tests as well.

@buf = dso_local global [20 x ptr] zeroinitializer, align 8

; Function Attrs: noreturn nounwind
define dso_local void @foo() local_unnamed_addr #0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above for removing unnecessary annotations. Here, we do need the backchain attribute, but not the others. That attribute can be specified inline rather than as part of an attribute bundle - something alone these lines should work:

define void @foo() "backchain" {

attributes #0 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="z10" }
attributes #1 = { nounwind }
attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="z10" }
attributes #3 = { nofree nounwind }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of those attributes look essential.

attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="z10" }
attributes #3 = { nofree nounwind }

!llvm.module.flags = !{!0, !1, !2}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither any of these module flags.

@@ -0,0 +1,216 @@
; Simulate register pressure around setjmp call for double precision
; arguments and return sum of 20 vaiables. It also prints the variables.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is not an executable test, I don't think the printf code-gen tests anything relevant. The above register pressure test should be sufficient.

@@ -0,0 +1,146 @@
; -mbackchain option.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I don't think we need -mbackchain versions of all of those. We have the simple tests above that verify -mbackchain works, we don't need to repeat this for all other tests.

@@ -0,0 +1,215 @@
; Simulate register pressure around setjmp call for integer arguments and
; return sum of 20 vaiables. It also prints the variables.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above comments on the -double tests.

Copy link
Member

@uweigand uweigand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're getting close now - but I still have a few comments below. Thanks!

// 2. Clang front-end also writes the stack pointer into the third
// slot. Not only is this not even mentioned in the docs, it also does
// not match GCC behavior on all targets. On SystemZ we use the fourth
// slot.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anoopkg6 , we shouldn't add a long comment here why the documentation is wrong - instead, the patch should actually fix the documentation. This particular bit would be in docs/ExceptionHandling.rst. I would change the paragraph that currently reads:

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.

to something like:

The single parameter is a pointer to a five word buffer in which the calling
context is saved.   The format and contents of the buffer are target-specific.
On certain targets, 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, saving the
calling context to the buffer is left completely to the target implementation.

Then can we simply put a short notice in this file, along the lines of
"On this target, the back end fills in the context buffer completely."

@efriedma-quic would this be OK with you?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should specifically call out which targets are which, for reference. No point in being overly generic. Otherwise I guess that's fine.

It's worth pointing out that if the backend completely fills the buffer, it doesn't really matter if the frontend stores to the buffer before calling setjmp.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should specifically call out which targets are which, for reference. No point in being overly generic.

Fair enough.

It's worth pointing out that if the backend completely fills the buffer, it doesn't really matter if the frontend stores to the buffer before calling setjmp.

Understood. It would still seem cleaner to not emit those stores if the back-end is going to overwrite them anyway ...

@@ -0,0 +1,25 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need a -backchain version of the test case here - what's tested here is completely identical as far as the front-end goes. Just the other test should be fine.

// | phi(v_mainMBB,v_restoreMBB) |
// -----------------------------
// thisMBB:
// buf[0] = Frame Pointer if hasFP.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use FPOffset here to be consistent with the code below.

; CHECK-NEXT: lmg %r6, %r15, 496(%r15)
; CHECK-NEXT: br %r14
entry:
%0 = tail call i32 @llvm.eh.sjlj.setjmp(ptr nonnull @buf)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this again, I'm a bit confused what this is supposed to test? There are no registers live across the setjmp anyway ...

I'd have throught a good test would be to make a large number of virtual registers live before the setjmp, and then use all of them after the setjmp. The test would then verify that the compiler doesn't attempt to keep any of these virtual registers alive in call-saved GPRs, but rather saves all of them to the stack.

Copy link
Member

@uweigand uweigand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now looks good to me (see one inline comment). The only part missing is the doc change as discussed above - can you add this to the PR here? Then it should be good to go. Thanks!

@@ -1,4 +1,4 @@
//===-- SystemZISelLowering.cpp - SystemZ DAG lowering implementation -----===//
//===-- systemzisellowering.cpp - systemz dag lowering implementation -----===//
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be some accidental change? Please remove.

Copy link
Member

@uweigand uweigand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last comment, then it looks good to go for me. Thanks!

On certain targets, 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, saving the
calling context to the buffer is left completely to the target implementation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given @efriedma-quic 's comment, we should specify the targets here. Maybe change the first sentence to "On certain targets (ARM, PowerPC, VE, X86), ..." and the second sentence to "On other targets (SystemZ), ..."

Copy link
Member

@uweigand uweigand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now. Thanks for your contribution!

@uweigand uweigand merged commit 030bbc9 into llvm:main Dec 6, 2024
9 checks passed
Copy link

github-actions bot commented Dec 6, 2024

@anoopkg6 Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 6, 2024

LLVM Buildbot has detected a new failure on builder fuchsia-x86_64-linux running on fuchsia-debian-64-us-central1-a-1 while building clang,llvm at step 4 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/11/builds/9334

Here is the relevant piece of the build log for the reference
Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/fuchsia-linux.py ...' (failure)
...
clang++: warning: optimization flag '-ffat-lto-objects' is not supported [-Wignored-optimization-argument]
[824/1353] Running the Clang regression tests
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using clang: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/clang
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find clang-repl in /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin:/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using ld.lld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/ld.lld
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using lld-link: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/lld-link
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using ld64.lld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/ld64.lld
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using wasm-ld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/wasm-ld
-- Testing: 21632 tests, 60 workers --
Testing:  0.. 10.. 20.
FAIL: Clang :: CodeGen/SystemZ/builtin-setjmp-logjmp.c (6030 of 21632)
******************** TEST 'Clang :: CodeGen/SystemZ/builtin-setjmp-logjmp.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 2: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/clang --target=s390x-linux -S -emit-llvm -o - /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
+ /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/clang --target=s390x-linux -S -emit-llvm -o - /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
+ /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c:7:16: error: CHECK-NEXT: is not on the line after the previous match
// CHECK-NEXT: [[ENTRY:.*:]]
               ^
<stdin>:14:1: note: 'next' match was here
; Function Attrs: nounwind
^
<stdin>:9:34: note: previous match ended here
define dso_local void @foo() #0 {
                                 ^
<stdin>:10:1: note: non-matching line after previous match is here
 %1 = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c:18:16: error: CHECK-NEXT: is not on the line after the previous match
// CHECK-NEXT: [[ENTRY:.*:]]
               ^
<stdin>:23:1: note: 'next' match was here
; Function Attrs: noreturn nounwind
^
<stdin>:18:35: note: previous match ended here
define dso_local void @foo1() #0 {
                                  ^
<stdin>:19:1: note: non-matching line after previous match is here
 call void @llvm.eh.sjlj.longjmp(ptr @buf)
^

Input file: <stdin>
Check file: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c

-dump-input=help explains the following input dump.

Step 7 (check) failure: check (failure)
...
clang++: warning: optimization flag '-ffat-lto-objects' is not supported [-Wignored-optimization-argument]
[824/1353] Running the Clang regression tests
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using clang: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/clang
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find clang-repl in /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin:/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using ld.lld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/ld.lld
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using lld-link: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/lld-link
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using ld64.lld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/ld64.lld
llvm-lit: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/llvm/utils/lit/lit/llvm/config.py:506: note: using wasm-ld: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/wasm-ld
-- Testing: 21632 tests, 60 workers --
Testing:  0.. 10.. 20.
FAIL: Clang :: CodeGen/SystemZ/builtin-setjmp-logjmp.c (6030 of 21632)
******************** TEST 'Clang :: CodeGen/SystemZ/builtin-setjmp-logjmp.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 2: /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/clang --target=s390x-linux -S -emit-llvm -o - /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c | /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
+ /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/clang --target=s390x-linux -S -emit-llvm -o - /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
+ /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-tt5pf60t/bin/FileCheck /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c:7:16: error: CHECK-NEXT: is not on the line after the previous match
// CHECK-NEXT: [[ENTRY:.*:]]
               ^
<stdin>:14:1: note: 'next' match was here
; Function Attrs: nounwind
^
<stdin>:9:34: note: previous match ended here
define dso_local void @foo() #0 {
                                 ^
<stdin>:10:1: note: non-matching line after previous match is here
 %1 = call i32 @llvm.eh.sjlj.setjmp(ptr @buf)
^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c:18:16: error: CHECK-NEXT: is not on the line after the previous match
// CHECK-NEXT: [[ENTRY:.*:]]
               ^
<stdin>:23:1: note: 'next' match was here
; Function Attrs: noreturn nounwind
^
<stdin>:18:35: note: previous match ended here
define dso_local void @foo1() #0 {
                                  ^
<stdin>:19:1: note: non-matching line after previous match is here
 call void @llvm.eh.sjlj.longjmp(ptr @buf)
^

Input file: <stdin>
Check file: /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/clang/test/CodeGen/SystemZ/builtin-setjmp-logjmp.c

-dump-input=help explains the following input dump.


@ilovepi
Copy link
Contributor

ilovepi commented Dec 6, 2024

This seems to have broken build bot and Fuchsia's Linux CI https://ci.chromium.org/ui/p/fuchsia/builders/toolchain.ci/clang-host-linux-x64/b8729261510660874657/overview. Would you mind reverting until a fix is ready?

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 6, 2024

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-expensive-checks-debian running on gribozavr4 while building clang,llvm at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/16/builds/10237

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'LLVM :: CodeGen/SystemZ/builtin-setjmp-alloca.ll' FAILED ********************
Exit Code: 2

Command Output (stderr):
--
RUN: at line 10: /b/1/llvm-clang-x86_64-expensive-checks-debian/build/bin/llc < /b/1/llvm-clang-x86_64-expensive-checks-debian/llvm-project/llvm/test/CodeGen/SystemZ/builtin-setjmp-alloca.ll -mtriple=s390x-linux-gnu -O2 | /b/1/llvm-clang-x86_64-expensive-checks-debian/build/bin/FileCheck /b/1/llvm-clang-x86_64-expensive-checks-debian/llvm-project/llvm/test/CodeGen/SystemZ/builtin-setjmp-alloca.ll
+ /b/1/llvm-clang-x86_64-expensive-checks-debian/build/bin/llc -mtriple=s390x-linux-gnu -O2
+ /b/1/llvm-clang-x86_64-expensive-checks-debian/build/bin/FileCheck /b/1/llvm-clang-x86_64-expensive-checks-debian/llvm-project/llvm/test/CodeGen/SystemZ/builtin-setjmp-alloca.ll

# After Instruction Selection
# Machine code for function foo1: IsSSA, TracksLiveness
Frame Objects:
  fi#0: size=8, align=8, at location [SP]
  fi#1: size=4, align=8, at location [SP]

bb.0.entry:
  successors: %bb.1(0x40000000), %bb.3(0x40000000); %bb.1(50.00%), %bb.3(50.00%)

  %0:gr64bit = LA %stack.1, 0, $noreg
  STG killed %0:gr64bit, %stack.0.val, 0, $noreg :: (store (s64) into %ir.val)
  MVHI %stack.1, 0, 10 :: (volatile store (s32) into %ir.1, align 8)
  %1:addr64bit = LGRL target-flags(<unknown>) @buf :: (load (s64) from got)
  %7:gr64bit = LARL %bb.3
  STG %7:gr64bit, %1:addr64bit, 8, $noreg
  STG $r11d, %1:addr64bit, 0, $noreg
  STG $r15d, %1:addr64bit, 24, $noreg
  %8:gr32bit = LG $r15d, 0, $noreg
  STG %8:gr32bit, %1:addr64bit, 16, $noreg
  EH_SjLj_Setup %bb.3, <regmask>

bb.1.entry:
; predecessors: %bb.0
  successors: %bb.2(0x80000000); %bb.2(100.00%)

  %5:gr32bit = LHI 0

bb.2.entry:
; predecessors: %bb.1, %bb.3

  %2:gr32bit = PHI %5:gr32bit, %bb.1, %6:gr32bit, %bb.3
  %3:addr64bit = LG %stack.0.val, 0, $noreg :: (dereferenceable load (s64) from %ir.val)
  %4:gr64bit = LGF killed %3:addr64bit, 0, $noreg :: (volatile load (s32) from %ir.3)
  $r2d = COPY %4:gr64bit
  Return implicit $r2d

bb.3.entry (machine-block-address-taken):
; predecessors: %bb.0
  successors: %bb.2(0x80000000); %bb.2(100.00%)

  %6:gr32bit = LHI 1
...

uweigand added a commit that referenced this pull request Dec 6, 2024
@uweigand
Copy link
Member

uweigand commented Dec 7, 2024

Hi @anoopkg6 , I had to revert this again as it was causing a number of issues:

  • An unused variable warning fixed here: 3c47e63
  • The fuchsia build bot failure - I'm not completely sure what causes this, but it suspect the problem is that you should be using %clang_cc1 instead of %clang (which would be a better idea anyway)
  • The expensive checks build bot failure - this indicated a real bug the generated MI, which you can reproduce by adding -verify-machineinstrs to the test case (it would be a good idea to add this to those tests anyway!)

You'll have to open a new PR with a patch including those fixes.

@ilovepi
Copy link
Contributor

ilovepi commented Dec 7, 2024

@uweigand Thanks for the prompt revert.

For reference the Fuchsia bot is just a normal Linux build configured for building Fuchsia in a debian container. The toolchain isn't novel in anyway, except it normally builds with a recent toolchain, and uses the full runtimes build. The bot will list all the CMAKE options we use, and the DockerFile should be with the zorg build bot configs for other buildbots if you have trouble reproducing.

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 7, 2024

LLVM Buildbot has detected a new failure on builder sanitizer-aarch64-linux running on sanitizer-buildbot8 while building clang,llvm at step 2 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/51/builds/7267

Here is the relevant piece of the build log for the reference
Step 2 (annotate) failure: 'python ../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py' (failure)
...
[182/186] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.aarch64-with-call.o
[183/186] Generating Msan-aarch64-with-call-Test
[184/186] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.aarch64.o
[185/186] Generating Msan-aarch64-Test
[185/186] Running compiler_rt regression tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/discovery.py:276: warning: input '/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/interception/Unit' contained no tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/discovery.py:276: warning: input '/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/Unit' contained no tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/main.py:72: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 5555 tests, 48 workers --
Testing:  0.
FAIL: AddressSanitizer-aarch64-linux :: TestCases/Posix/halt_on_error-signals.c (360 of 5555)
******************** TEST 'AddressSanitizer-aarch64-linux :: TestCases/Posix/halt_on_error-signals.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 3: /home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang  -fsanitize=address -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls -gline-tables-only   -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   -fsanitize-recover=address -pthread /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp
+ /home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang -fsanitize=address -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls -gline-tables-only -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta -fsanitize-recover=address -pthread /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp
In file included from /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c:11:
In file included from /usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include/stdio.h:28:
In file included from /usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include/bits/libc-header-start.h:33:
/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include/features.h:196:3: warning: "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE" [-W#warnings]
  196 | # warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE"
      |   ^
1 warning generated.
RUN: at line 5: env ASAN_OPTIONS=halt_on_error=false:suppress_equal_pcs=false  /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp 100 >/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp.log 2>&1 || true
+ env ASAN_OPTIONS=halt_on_error=false:suppress_equal_pcs=false /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp 100
+ true
RUN: at line 7: FileCheck --check-prefix=CHECK-COLLISION /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c </home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp.log || FileCheck --check-prefix=CHECK-NO-COLLISION /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c </home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp.log
+ FileCheck --check-prefix=CHECK-COLLISION /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c
/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c:29:22: error: CHECK-COLLISION: expected string not found in input
 // CHECK-COLLISION: AddressSanitizer: nested bug in the same thread, aborting
                     ^
<stdin>:1:1: note: scanning from here
=================================================================
^
<stdin>:55:134: note: possible intended match here
/home/b/sanitizer-aarch64-linux/build/build_default/./bin/llvm-symbolizer: error: 'linux-vdso.so.1': AddressSanitizerNo such file or directory: nested bug in the same thread, aborting.
                                                                                                                                     ^

Input file: <stdin>
Check file: /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: ================================================================= 
check:29'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
Step 15 (test compiler-rt default) failure: test compiler-rt default (failure)
...
[182/186] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.aarch64-with-call.o
[183/186] Generating Msan-aarch64-with-call-Test
[184/186] Generating MSAN_INST_TEST_OBJECTS.msan_test.cpp.aarch64.o
[185/186] Generating Msan-aarch64-Test
[185/186] Running compiler_rt regression tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/discovery.py:276: warning: input '/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/interception/Unit' contained no tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/discovery.py:276: warning: input '/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/sanitizer_common/Unit' contained no tests
llvm-lit: /home/b/sanitizer-aarch64-linux/build/llvm-project/llvm/utils/lit/lit/main.py:72: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 5555 tests, 48 workers --
Testing:  0.
FAIL: AddressSanitizer-aarch64-linux :: TestCases/Posix/halt_on_error-signals.c (360 of 5555)
******************** TEST 'AddressSanitizer-aarch64-linux :: TestCases/Posix/halt_on_error-signals.c' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 3: /home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang  -fsanitize=address -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls -gline-tables-only   -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta   -fsanitize-recover=address -pthread /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp
+ /home/b/sanitizer-aarch64-linux/build/build_default/./bin/clang -fsanitize=address -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls -gline-tables-only -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta -fsanitize-recover=address -pthread /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c -o /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp
In file included from /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c:11:
In file included from /usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include/stdio.h:28:
In file included from /usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include/bits/libc-header-start.h:33:
/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include/features.h:196:3: warning: "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE" [-W#warnings]
  196 | # warning "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE"
      |   ^
1 warning generated.
RUN: at line 5: env ASAN_OPTIONS=halt_on_error=false:suppress_equal_pcs=false  /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp 100 >/home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp.log 2>&1 || true
+ env ASAN_OPTIONS=halt_on_error=false:suppress_equal_pcs=false /home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp 100
+ true
RUN: at line 7: FileCheck --check-prefix=CHECK-COLLISION /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c </home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp.log || FileCheck --check-prefix=CHECK-NO-COLLISION /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c </home/b/sanitizer-aarch64-linux/build/build_default/runtimes/runtimes-bins/compiler-rt/test/asan/AARCH64LinuxConfig/TestCases/Posix/Output/halt_on_error-signals.c.tmp.log
+ FileCheck --check-prefix=CHECK-COLLISION /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c
/home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c:29:22: error: CHECK-COLLISION: expected string not found in input
 // CHECK-COLLISION: AddressSanitizer: nested bug in the same thread, aborting
                     ^
<stdin>:1:1: note: scanning from here
=================================================================
^
<stdin>:55:134: note: possible intended match here
/home/b/sanitizer-aarch64-linux/build/build_default/./bin/llvm-symbolizer: error: 'linux-vdso.so.1': AddressSanitizerNo such file or directory: nested bug in the same thread, aborting.
                                                                                                                                     ^

Input file: <stdin>
Check file: /home/b/sanitizer-aarch64-linux/build/llvm-project/compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: ================================================================= 
check:29'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found

uweigand pushed a commit that referenced this pull request Dec 10, 2024
…9257)

This pr includes fixes for original pr##116642.
Implementation for __builtin_setjmp and __builtin_longjmp for SystemZ..
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:SystemZ clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants