[clang] [llvm] [SystemZ] Global Stackprotector and associated location section (PR #169317)

Dominik Steenken via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 9 04:42:42 PDT 2026


https://github.com/dominik-steenken updated https://github.com/llvm/llvm-project/pull/169317

>From f717bae2ff6a3c4aeb7536b54697383c4994bf8d Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Wed, 16 Jul 2025 10:48:55 +0200
Subject: [PATCH 01/29] [SystemZ] Global Stackprotector and associated location
 section

This commit allows `-mstack-protector-guard=global` for `s390x`.

It also adds a new arch-specific option `-mstack-protector-guard-record`,
analogous to `-mrecord-mcount`, which will cause `clang` to emit a
`__stack_protector_loc` section containing all the locations in the output
binary that load the stack guard address, for the purposes of later rewriting
of those loads by the kernel. This new option only works together with the
`global` stack protector.

In order to minimize exposure of the stack guard, both the storing of the
stack guard onto the stack, and the later comparison of that value against
the reference value, are handled via direct mem-to-mem instructions, those
being `mvc` and `clc`.

This is achieved by introducing two new pseudo instructions, `MOVE_STACK_GUARD`
and `COMPARE_STACK_GUARD`, which are inserted by the DAGCombiner after
SelectionDAG construction. These pseudos stick around throughout the entire
backend pipeline, and are lowered only in the AsmPrinter.

This commit also adds tests for both kinds of stack protectors (tls and global),
for the proper insertion of the pseudos, the proper emission of the,
`__stack_protector_loc` section, as well as the option compatibility checks
for the new options.
---
 clang/include/clang/Basic/CodeGenOptions.def  |   1 +
 clang/include/clang/Options/Options.td        |   8 +
 clang/lib/CodeGen/CodeGenFunction.cpp         |   8 +
 clang/lib/Driver/ToolChains/Clang.cpp         |  40 +++--
 .../CodeGen/SystemZ/stack-guard-pseudos.c     |  16 ++
 clang/test/Driver/stack-protector-guard.c     |  18 ++
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 127 ++++++++++++++
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |   2 +
 .../Target/SystemZ/SystemZISelDAGToDAG.cpp    |   9 +-
 .../Target/SystemZ/SystemZISelLowering.cpp    | 114 ++++++++++++-
 llvm/lib/Target/SystemZ/SystemZISelLowering.h |   3 -
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  |  59 +++----
 llvm/lib/Target/SystemZ/SystemZInstrInfo.h    |   1 -
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td   |  14 ++
 .../SystemZ/stack-guard-global-nopic.ll       | 157 +++++++++++++++++
 .../CodeGen/SystemZ/stack-guard-global-pic.ll | 159 ++++++++++++++++++
 llvm/test/CodeGen/SystemZ/stack-guard-tls.ll  | 135 +++++++++++++++
 llvm/test/CodeGen/SystemZ/stack-guard.ll      |  33 ----
 18 files changed, 816 insertions(+), 88 deletions(-)
 create mode 100644 clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
 create mode 100644 llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
 create mode 100644 llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
 create mode 100644 llvm/test/CodeGen/SystemZ/stack-guard-tls.ll
 delete mode 100644 llvm/test/CodeGen/SystemZ/stack-guard.ll

diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 3d8db87a185b4..b0906ff7b0b70 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -161,6 +161,7 @@ CODEGENOPT(InstrumentForProfiling , 1, 0, Benign) ///< Set when -pg is enabled.
 CODEGENOPT(CallFEntry , 1, 0, Benign) ///< Set when -mfentry is enabled.
 CODEGENOPT(MNopMCount , 1, 0, Benign) ///< Set when -mnop-mcount is enabled.
 CODEGENOPT(RecordMCount , 1, 0, Benign) ///< Set when -mrecord-mcount is enabled.
+CODEGENOPT(StackProtectorGuardRecord, 1, 0, Benign) ///< Set when -mstack-protector-guard-record is enabled.
 CODEGENOPT(PackedStack , 1, 0, Benign) ///< Set when -mpacked-stack is enabled.
 CODEGENOPT(LessPreciseFPMAD  , 1, 0, Benign) ///< Enable less precise MAD instructions to
                                              ///< be generated.
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 1021d95e4005b..7d7213130fec9 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5979,6 +5979,14 @@ def mstack_protector_guard_reg_EQ : Joined<["-"], "mstack-protector-guard-reg=">
   Visibility<[ClangOption, CC1Option]>,
   HelpText<"Use the given reg for addressing the stack-protector guard">,
   MarshallingInfoString<CodeGenOpts<"StackProtectorGuardReg">>;
+def mstackprotector_guard_record
+    : Flag<["-"], "mstack-protector-guard-record">,
+      HelpText<
+          "Generate a __stack_protector_loc section entry for each load of "
+          "the stackguard address.">,
+      Visibility<[ClangOption, CC1Option]>,
+      Group<m_Group>,
+      MarshallingInfoFlag<CodeGenOpts<"StackProtectorGuardRecord">>;
 def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86/SystemZ only)">,
   Visibility<[ClangOption, CC1Option]>, Group<m_Group>,
   MarshallingInfoFlag<CodeGenOpts<"CallFEntry">>;
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index b14d9d7e8d060..8870149e030be 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1195,6 +1195,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
     }
   }
 
+  if (CGM.getCodeGenOpts().StackProtectorGuardRecord) {
+    if (CGM.getCodeGenOpts().StackProtectorGuard != "global")
+      CGM.getDiags().Report(diag::err_opt_not_valid_without_opt)
+          << "-mstack-protector-guard-record"
+          << "-mstack-protector-guard=global";
+    Fn->addFnAttr("mstackprotector-guard-record");
+  }
+
   if (CGM.getCodeGenOpts().PackedStack) {
     if (getContext().getTargetInfo().getTriple().getArch() !=
         llvm::Triple::systemz)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 7e544bd1042ea..c6506e1b20dcb 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3495,22 +3495,24 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
   }
 
   const std::string &TripleStr = EffectiveTriple.getTriple();
+  StringRef GuardValue;
   if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_EQ)) {
-    StringRef Value = A->getValue();
+    GuardValue = A->getValue();
     if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() &&
         !EffectiveTriple.isARM() && !EffectiveTriple.isThumb() &&
-        !EffectiveTriple.isRISCV() && !EffectiveTriple.isPPC())
+        !EffectiveTriple.isRISCV() && !EffectiveTriple.isPPC() &&
+        !EffectiveTriple.isSystemZ())
       D.Diag(diag::err_drv_unsupported_opt_for_target)
           << A->getAsString(Args) << TripleStr;
     if ((EffectiveTriple.isX86() || EffectiveTriple.isARM() ||
-         EffectiveTriple.isThumb()) &&
-        Value != "tls" && Value != "global") {
+         EffectiveTriple.isThumb() || EffectiveTriple.isSystemZ()) &&
+        GuardValue != "tls" && GuardValue != "global") {
       D.Diag(diag::err_drv_invalid_value_with_suggestion)
-          << A->getOption().getName() << Value << "tls global";
+          << A->getOption().getName() << GuardValue << "tls global";
       return;
     }
     if ((EffectiveTriple.isARM() || EffectiveTriple.isThumb()) &&
-        Value == "tls") {
+        GuardValue == "tls") {
       if (!Args.hasArg(options::OPT_mstack_protector_guard_offset_EQ)) {
         D.Diag(diag::err_drv_ssp_missing_offset_argument)
             << A->getAsString(Args);
@@ -3534,18 +3536,19 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
       CmdArgs.push_back("-target-feature");
       CmdArgs.push_back("+read-tp-tpidruro");
     }
-    if (EffectiveTriple.isAArch64() && Value != "sysreg" && Value != "global") {
+    if (EffectiveTriple.isAArch64() && GuardValue != "sysreg" &&
+        GuardValue != "global") {
       D.Diag(diag::err_drv_invalid_value_with_suggestion)
-          << A->getOption().getName() << Value << "sysreg global";
+          << A->getOption().getName() << GuardValue << "sysreg global";
       return;
     }
     if (EffectiveTriple.isRISCV() || EffectiveTriple.isPPC()) {
-      if (Value != "tls" && Value != "global") {
+      if (GuardValue != "tls" && GuardValue != "global") {
         D.Diag(diag::err_drv_invalid_value_with_suggestion)
-            << A->getOption().getName() << Value << "tls global";
+            << A->getOption().getName() << GuardValue << "tls global";
         return;
       }
-      if (Value == "tls") {
+      if (GuardValue == "tls") {
         if (!Args.hasArg(options::OPT_mstack_protector_guard_offset_EQ)) {
           D.Diag(diag::err_drv_ssp_missing_offset_argument)
               << A->getAsString(Args);
@@ -3619,6 +3622,21 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
     }
     A->render(Args, CmdArgs);
   }
+
+  if (Arg *A = Args.getLastArg(options::OPT_mstackprotector_guard_record)) {
+    if (!EffectiveTriple.isSystemZ()) {
+      D.Diag(diag::err_drv_unsupported_opt_for_target)
+          << A->getAsString(Args) << TripleStr;
+      return;
+    }
+    if (GuardValue != "global") {
+      D.Diag(diag::err_drv_argument_only_allowed_with)
+          << "-mstack-protector-guard-record"
+          << "-mstack-protector-guard=global";
+      return;
+    }
+    A->render(Args, CmdArgs);
+  }
 }
 
 static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args,
diff --git a/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c b/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
new file mode 100644
index 0000000000000..b364aa4028ec7
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -S -mllvm -stop-after=systemz-isel -stack-protector 1 -triple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-PSEUDOS %s
+// RUN: not %clang_cc1 -S -stack-protector 1 -mstack-protector-guard-record -triple=s390x-ibm-linux < %s -o - 2>&1 | FileCheck -check-prefix=CHECK-OPTS %s 
+// CHECK-PSEUDOS:   bb.0.entry:
+// CHECK-PSEUDOS:     %3:addr64bit = LOAD_STACK_GUARD_ADDRESS
+// CHECK-PSEUDOS:     MOVE_STACK_GUARD %stack.0.StackGuardSlot, 0, %3
+// CHECK-PSEUDOS:     COMPARE_STACK_GUARD %stack.0.StackGuardSlot, 0, %3, implicit-def $cc
+
+extern char *strcpy (char * D, const char * S);
+int main(int argc, char *argv[])
+{
+    char Buffer[8] = {0};
+    strcpy(Buffer, argv[1]);
+    return 0;
+}
+
+// CHECK-OPTS: error: option '-mstack-protector-guard-record' cannot be specified without '-mstack-protector-guard=global'
diff --git a/clang/test/Driver/stack-protector-guard.c b/clang/test/Driver/stack-protector-guard.c
index 666c83079e519..8c8aacfa574c7 100644
--- a/clang/test/Driver/stack-protector-guard.c
+++ b/clang/test/Driver/stack-protector-guard.c
@@ -155,3 +155,21 @@
 
 // CHECK-TLS-POWERPC32: "-cc1" {{.*}}"-mstack-protector-guard=tls" "-mstack-protector-guard-offset=24" "-mstack-protector-guard-reg=r2"
 // INVALID-REG-POWERPC32: error: invalid value 'r3' in 'mstack-protector-guard-reg=', expected one of: r2
+
+// RUN: %clang -### -target systemz-unknown-elf -mstack-protector-guard=tls %s 2>&1 | \
+// RUN:  FileCheck -check-prefix=CHECK_TLS_SYSTEMZ %s
+// CHECK_TLS_SYSTEMZ: "-cc1" {{.*}}"-mstack-protector-guard=tls"
+
+// RUN: %clang -### -target systemz-unknown-elf -mstack-protector-guard=global %s 2>&1 | \
+// RUN:  FileCheck -check-prefix=CHECK_GLOBAL_SYSTEMZ %s
+// CHECK_GLOBAL_SYSTEMZ: "-cc1" {{.*}}"-mstack-protector-guard=global"
+
+// RUN: %clang -### -target systemz-unknown-elf -mstack-protector-guard=global \
+// RUN:  -mstack-protector-guard-record %s 2>&1 | \
+// RUN:  FileCheck -check-prefix=CHECK_GLOBAL_RECORD_SYSTEMZ %s
+// CHECK_GLOBAL_RECORD_SYSTEMZ: "-cc1" {{.*}}"-mstack-protector-guard=global" "-mstack-protector-guard-record"
+
+// RUN: not %clang -target systemz-unknown-elf -mstack-protector-guard=tls \
+// RUN:  -mstack-protector-guard-record %s 2>&1 | \
+// RUN:  FileCheck -check-prefix=INVALID_TLS_RECORD_SYSTEMZ %s
+// INVALID_TLS_RECORD_SYSTEMZ: error: invalid argument '-mstack-protector-guard-record' only allowed with '-mstack-protector-guard=global'
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index cb451a1ca4f55..fb1c83b968ac2 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -24,10 +24,12 @@
 #include "llvm/BinaryFormat/GOFF.h"
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Mangler.h"
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCDirectives.h"
 #include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCStreamer.h"
@@ -245,6 +247,16 @@ SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MachineOperand MO) {
   return insert(Sym, ADAslotType);
 }
 
+namespace {
+unsigned long getStackGuardOffset(const MachineBasicBlock *MBB) {
+  // In the TLS (default) case, AddrReg will contain the thread pointer, so we
+  // need to add 40 bytes to get the actual address of the stack guard.
+  StringRef GuardType =
+      MBB->getParent()->getFunction().getParent()->getStackProtectorGuard();
+  return (GuardType == "global") ? 0 : 40;
+}
+} // namespace
+
 void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   SystemZ_MC::verifyInstructionPredicates(MI->getOpcode(),
                                           getSubtargetInfo().getFeatureBits());
@@ -773,6 +785,42 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   case SystemZ::EH_SjLj_Setup:
     return;
 
+  case SystemZ::LOAD_STACK_GUARD: {
+    // If requested, record address of stack guard address load
+    if (MF->getFunction().hasFnAttribute("mstackprotector-guard-record"))
+      emitStackProtectorLocEntry();
+    Register AddrReg = emitLoadStackGuardAddress(MI);
+    LoweredMI = MCInstBuilder(SystemZ::LG)
+                    .addReg(AddrReg)
+                    .addImm(getStackGuardOffset(MI->getParent()))
+                    .addReg(0);
+  } break;
+
+  case SystemZ::LOAD_STACK_GUARD_ADDRESS:
+    // If requested, record address of stack guard address load
+    if (MF->getFunction().hasFnAttribute("mstackprotector-guard-record"))
+      emitStackProtectorLocEntry();
+    emitLoadStackGuardAddress(MI);
+    return;
+
+  case SystemZ::COMPARE_STACK_GUARD:
+    LoweredMI = MCInstBuilder(SystemZ::CLC)
+                    .addReg(MI->getOperand(0).getReg())
+                    .addImm(MI->getOperand(1).getImm())
+                    .addImm(8)
+                    .addReg(MI->getOperand(2).getReg())
+                    .addImm(getStackGuardOffset(MI->getParent()));
+    break;
+
+  case SystemZ::MOVE_STACK_GUARD:
+    LoweredMI = MCInstBuilder(SystemZ::MVC)
+                    .addReg(MI->getOperand(0).getReg())
+                    .addImm(MI->getOperand(1).getImm())
+                    .addImm(8)
+                    .addReg(MI->getOperand(2).getReg())
+                    .addImm(getStackGuardOffset(MI->getParent()));
+    break;
+
   default:
     Lower.lower(MI, LoweredMI);
     break;
@@ -780,6 +828,85 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   EmitToStreamer(*OutStreamer, LoweredMI);
 }
 
+void SystemZAsmPrinter::emitStackProtectorLocEntry() {
+  MCSymbol *Sym = OutContext.createTempSymbol();
+  OutStreamer->pushSection();
+  OutStreamer->switchSection(OutContext.getELFSection(
+      "__stack_protector_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC));
+  OutStreamer->emitSymbolValue(Sym, getDataLayout().getPointerSize());
+  OutStreamer->popSection();
+  OutStreamer->emitLabel(Sym);
+}
+
+// Emit the stack guard address load, depending on guard type.
+// Return the register the stack guard address was loaded into.
+Register SystemZAsmPrinter::emitLoadStackGuardAddress(const MachineInstr *MI) {
+  const MachineBasicBlock *MBB = MI->getParent();
+  const MachineFunction &MF = *MBB->getParent();
+  const Register AddrReg = MI->getOperand(0).getReg();
+  const MCRegisterInfo &MRI = *TM.getMCRegisterInfo();
+  const Register Reg32 = MRI.getSubReg(AddrReg, SystemZ::subreg_l32);
+
+  const Module *M = MF.getFunction().getParent();
+  StringRef GuardType = M->getStackProtectorGuard();
+
+  if (GuardType.empty() || (GuardType == "tls")) {
+    // EAR can only load the low subregister so use a shift for %a0 to produce
+    // the GR containing %a0 and %a1.
+
+    // ear <reg>, %a0
+    MCInst EAR1 = MCInstBuilder(SystemZ::EAR)
+                      .addReg(Reg32)
+                      .addReg(SystemZ::A0)
+                      .addReg(AddrReg);
+
+    // sllg <reg>, <reg>, 32
+    MCInst SLLG = MCInstBuilder(SystemZ::SLLG)
+                      .addReg(AddrReg)
+                      .addReg(AddrReg)
+                      .addReg(0)
+                      .addImm(32);
+
+    // ear <reg>, %a1
+    MCInst EAR2 = MCInstBuilder(SystemZ::EAR)
+                      .addReg(Reg32)
+                      .addReg(SystemZ::A1)
+                      .addReg(AddrReg);
+
+    EmitToStreamer(*OutStreamer, EAR1);
+    EmitToStreamer(*OutStreamer, SLLG);
+    EmitToStreamer(*OutStreamer, EAR2);
+  } else if (GuardType == "global") {
+    // Obtain the global value.
+    const auto *GV = M->getGlobalVariable(
+        "__stack_chk_guard", PointerType::getUnqual(M->getContext()));
+    assert(GV &&
+           "could not create reference to global variable __stack_chk_guard");
+    auto *Sym = TM.getSymbol(GV);
+    // Ref->
+    // Emit the address load.
+    MCInst Load;
+    if (M->getPICLevel() == PICLevel::NotPIC) {
+      Load = MCInstBuilder(SystemZ::LARL)
+                 .addReg(AddrReg)
+                 .addExpr(MCSymbolRefExpr::create(Sym, OutContext));
+    } else {
+      Load =
+          MCInstBuilder(SystemZ::LGRL)
+              .addReg(AddrReg)
+              .addExpr(MCSymbolRefExpr::create(Sym, SystemZ::S_GOT, OutContext))
+              .addExpr(getGlobalOffsetTable(OutContext));
+    }
+    EmitToStreamer(*OutStreamer, Load);
+  } else {
+    llvm_unreachable(
+        (Twine("Unknown stack protector type \"") + GuardType + "\"")
+            .str()
+            .c_str());
+  }
+  return AddrReg;
+}
+
 // Emit the largest nop instruction smaller than or equal to NumBytes
 // bytes.  Return the size of nop emitted.
 static unsigned EmitNop(MCContext &OutContext, MCStreamer &OutStreamer,
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 0f87eb0307911..129144867530f 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -148,6 +148,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
                                      SystemZMCInstLower &Lower);
   void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
+  Register emitLoadStackGuardAddress(const MachineInstr *MI);
+  void emitStackProtectorLocEntry();
   void emitAttributes(Module &M);
 };
 } // end namespace llvm
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index a05fdc74e6366..fa1daa8bf8c54 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -10,10 +10,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "SystemZTargetMachine.h"
 #include "SystemZISelLowering.h"
+#include "SystemZTargetMachine.h"
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/KnownBits.h"
 #include "llvm/Support/raw_ostream.h"
@@ -369,7 +370,11 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
       if (F.hasFnAttribute("mrecord-mcount"))
         report_fatal_error("mrecord-mcount only supported with fentry-call");
     }
-
+    if (F.getParent()->getStackProtectorGuard() != "global") {
+      if (F.hasFnAttribute("mstack-protector-guard-record"))
+        report_fatal_error("mstack-protector-guard-record only supported with "
+                           "mstack-protector-guard=global");
+    }
     Subtarget = &MF.getSubtarget<SystemZSubtarget>();
     return SelectionDAGISel::runOnMachineFunction(MF);
   }
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index eacaaddc5e4d4..150277656b2a8 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -14,12 +14,12 @@
 #include "SystemZCallingConv.h"
 #include "SystemZConstantPoolValue.h"
 #include "SystemZMachineFunctionInfo.h"
+#include "SystemZRegisterInfo.h"
 #include "SystemZTargetMachine.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/CodeGen/CallingConvLower.h"
 #include "llvm/CodeGen/ISDOpcodes.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
 #include "llvm/IR/GlobalAlias.h"
 #include "llvm/IR/IntrinsicInst.h"
@@ -8129,6 +8129,25 @@ SDValue SystemZTargetLowering::combineSTORE(
                                SN->getMemOperand());
     }
   }
+
+  // combine STORE (LOAD_STACK_GUARD) into MOVE_STACK_GUARD
+  if (Op1->isMachineOpcode() &&
+      (Op1->getMachineOpcode() == SystemZ::LOAD_STACK_GUARD)) {
+    // If so, create a MOVE_STACK_GUARD node to replace the store,
+    // and a LOAD_STACK_GUARD_ADDRESS to replace the LOAD_STACK_GUARD
+    MachineSDNode *LoadAddr = DAG.getMachineNode(
+        SystemZ::LOAD_STACK_GUARD_ADDRESS, SDLoc(SN), MVT::i64);
+    int FI = cast<FrameIndexSDNode>(SN->getOperand(2))->getIndex();
+    // FrameIndex, Dummy Displacement
+    SDValue Ops[] = {DAG.getTargetFrameIndex(FI, MVT::i64),
+                     DAG.getTargetConstant(0, SDLoc(SN), MVT::i64),
+                     SDValue(LoadAddr, 0), SN->getChain()};
+    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOVE_STACK_GUARD,
+                                             SDLoc(SN), MVT::Other, Ops);
+
+    return SDValue(Move, 0);
+  }
+
   // Combine STORE (BSWAP) into STRVH/STRV/STRVG/VSTBR
   if (!SN->isTruncatingStore() &&
       Op1.getOpcode() == ISD::BSWAP &&
@@ -8948,20 +8967,66 @@ SystemZTargetLowering::getJumpConditionMergingParams(Instruction::BinaryOps Opc,
   return {-1, -1, -1};
 }
 
+namespace {
+bool isStackGuardCheck(SDNode const *N, int &FI, SDValue &InChain,
+                       SDValue &OutChain, SDValue &StackGuardLoad,
+                       SystemZTargetLowering::DAGCombinerInfo &DCI) {
+  auto Comp = N->getOperand(4);
+  if (Comp->getOpcode() != SystemZISD::ICMP)
+    return false;
+
+  if (!Comp->hasOneUse())
+    return false;
+
+  SDValue LHS = Comp->getOperand(0);
+  SDValue RHS = Comp->getOperand(1);
+  LoadSDNode *FILoad;
+
+  if (LHS.isMachineOpcode() &&
+      LHS.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
+      ISD::isNormalLoad(RHS.getNode()) &&
+      dyn_cast<FrameIndexSDNode>(RHS.getOperand(1))) {
+    StackGuardLoad = LHS;
+    FILoad = cast<LoadSDNode>(RHS);
+  } else if ((RHS.isMachineOpcode() &&
+              RHS.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
+              ISD::isNormalLoad(LHS.getNode()) &&
+              dyn_cast<FrameIndexSDNode>(LHS.getOperand(1)))) {
+    StackGuardLoad = RHS;
+    FILoad = cast<LoadSDNode>(LHS);
+  } else
+    return false;
+
+  // Assert that the values of the loads are not used elsewhere.
+  // Bail for now. TODO: What is the proper response here?
+  assert(
+      SDValue(FILoad, 0).hasOneUse() &&
+      "Value of stackguard loaded from stack must be used for compare only!");
+  assert(StackGuardLoad.hasOneUse() &&
+         "Value of reference stackguard must be used for compare only!");
+
+  FI = cast<FrameIndexSDNode>(FILoad->getOperand(1))->getIndex();
+  InChain = FILoad->getChain();
+  OutChain = SDValue(FILoad, 1);
+  DCI.AddToWorklist(FILoad);
+  DCI.AddToWorklist(Comp.getNode());
+  return true;
+}
+} // namespace
+
 SDValue SystemZTargetLowering::combineBR_CCMASK(SDNode *N,
                                                 DAGCombinerInfo &DCI) const {
   SelectionDAG &DAG = DCI.DAG;
 
-  // Combine BR_CCMASK (ICMP (SELECT_CCMASK)) into a single BR_CCMASK.
   auto *CCValid = dyn_cast<ConstantSDNode>(N->getOperand(1));
   auto *CCMask = dyn_cast<ConstantSDNode>(N->getOperand(2));
   if (!CCValid || !CCMask)
     return SDValue();
-
   int CCValidVal = CCValid->getZExtValue();
   int CCMaskVal = CCMask->getZExtValue();
   SDValue Chain = N->getOperand(0);
   SDValue CCReg = N->getOperand(4);
+
   // If combineCMask was able to merge or simplify ccvalid or ccmask, re-emit
   // the modified BR_CCMASK with the new values.
   // In order to avoid conditional branches with full or empty cc masks, do not
@@ -8973,6 +9038,47 @@ SDValue SystemZTargetLowering::combineBR_CCMASK(SDNode *N,
                        DAG.getTargetConstant(CCValidVal, SDLoc(N), MVT::i32),
                        DAG.getTargetConstant(CCMaskVal, SDLoc(N), MVT::i32),
                        N->getOperand(3), CCReg);
+
+  SDLoc DL(N);
+
+  // Combine BR_CCMASK (ICMP (Load FI, Load StackGuard)) into BRC
+  // (COMPARE_STACK_GUARD)
+  int FI = 0;
+  SDValue InChain, OutChain, StackGuardLoad;
+  if (isStackGuardCheck(N, FI, InChain, OutChain, StackGuardLoad, DCI)) {
+    // Sanity Checks
+    assert(CCMaskVal == SystemZ::CCMASK_CMP_NE &&
+           "Unexpected branch condition in stack guard check");
+    // Handle the load's chain if necessary
+    DAG.ReplaceAllUsesOfValueWith(OutChain, InChain);
+
+    // Construct the LOAD_STACK_GUARD_ADDRESS node to replace LOAD_STACK_GUARD
+    auto *LoadAddress =
+        DAG.getMachineNode(SystemZ::LOAD_STACK_GUARD_ADDRESS, DL, MVT::i64);
+
+    // Construct the COMPARE_STACK_GUARD node
+    SDVTList CmpVTs = DAG.getVTList(MVT::Other, MVT::Glue);
+    auto CompOps = {DAG.getTargetFrameIndex(FI, MVT::i64),
+                    DAG.getTargetConstant(0, DL, MVT::i64),
+                    SDValue(LoadAddress, 0), InChain};
+    auto *Compare =
+        DAG.getMachineNode(SystemZ::COMPARE_STACK_GUARD, DL, CmpVTs, CompOps);
+    // Construct the BRC node using COMPARE_STACK_GUARD's CC result
+    auto BranchOps = {DAG.getTargetConstant(CCValidVal, DL, MVT::i32),
+                      DAG.getTargetConstant(CCMaskVal, DL, MVT::i32),
+                      N->getOperand(3), SDValue(Compare, 0),
+                      SDValue(Compare, 1)};
+    return SDValue(DAG.getMachineNode(SystemZ::BRC, DL, MVT::Other, BranchOps),
+                   0);
+  }
+
+  // Combine BR_CCMASK (ICMP (SELECT_CCMASK)) into a single BR_CCMASK.
+  if (combineCCMask(CCReg, CCValidVal, CCMaskVal, DAG))
+    return DAG.getNode(SystemZISD::BR_CCMASK, DL, N->getValueType(0), Chain,
+                       DAG.getTargetConstant(CCValidVal, DL, MVT::i32),
+                       DAG.getTargetConstant(CCMaskVal, DL, MVT::i32),
+                       N->getOperand(3), CCReg);
+
   return SDValue();
 }
 
@@ -9385,6 +9491,8 @@ SDValue SystemZTargetLowering::PerformDAGCombine(SDNode *N,
   case SystemZISD::BR_CCMASK:   return combineBR_CCMASK(N, DCI);
   case SystemZISD::SELECT_CCMASK: return combineSELECT_CCMASK(N, DCI);
   case SystemZISD::GET_CCMASK:  return combineGET_CCMASK(N, DCI);
+  // case SystemZISD::ICMP:
+  //   return combineICMP(N, DCI);
   case ISD::SRL:
   case ISD::SRA:                return combineShiftToMulAddHigh(N, DCI);
   case ISD::MUL:                return combineMUL(N, DCI);
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index bb3eeba6446d2..db793ae096937 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -227,9 +227,6 @@ class SystemZTargetLowering : public TargetLowering {
 
   /// Override to support customized stack guard loading.
   bool useLoadStackGuardNode(const Module &M) const override { return true; }
-  void
-  insertSSPDeclarations(Module &M,
-                        const LibcallLoweringInfo &Libcalls) const override {}
 
   MachineBasicBlock *
   EmitInstrWithCustomInserter(MachineInstr &MI,
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index b1fbea1c7cb64..e6751e99bd11a 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -34,6 +34,7 @@
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/CodeGen/VirtRegMap.h"
 #include "llvm/MC/MCInstBuilder.h"
+#include "llvm/IR/Module.h"
 #include "llvm/MC/MCInstrDesc.h"
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/Support/BranchProbability.h"
@@ -229,35 +230,6 @@ void SystemZInstrInfo::expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode,
   MI.eraseFromParent();
 }
 
-void SystemZInstrInfo::expandLoadStackGuard(MachineInstr *MI) const {
-  MachineBasicBlock *MBB = MI->getParent();
-  MachineFunction &MF = *MBB->getParent();
-  const Register Reg64 = MI->getOperand(0).getReg();
-  const Register Reg32 = RI.getSubReg(Reg64, SystemZ::subreg_l32);
-
-  // EAR can only load the low subregister so us a shift for %a0 to produce
-  // the GR containing %a0 and %a1.
-
-  // ear <reg>, %a0
-  BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32)
-    .addReg(SystemZ::A0)
-    .addReg(Reg64, RegState::ImplicitDefine);
-
-  // sllg <reg>, <reg>, 32
-  BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::SLLG), Reg64)
-    .addReg(Reg64)
-    .addReg(0)
-    .addImm(32);
-
-  // ear <reg>, %a1
-  BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32)
-    .addReg(SystemZ::A1);
-
-  // lg <reg>, 40(<reg>)
-  MI->setDesc(get(SystemZ::LG));
-  MachineInstrBuilder(MF, MI).addReg(Reg64).addImm(40).addReg(0);
-}
-
 // Emit a zero-extending move from 32-bit GPR SrcReg to 32-bit GPR
 // DestReg before MBBI in MBB.  Use LowLowOpcode when both DestReg and SrcReg
 // are low registers, otherwise use RISB[LH]G.  Size is the number of bits
@@ -1059,8 +1031,7 @@ void SystemZInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
 // and no index.  Flag is SimpleBDXLoad for loads and SimpleBDXStore for stores.
 static bool isSimpleBD12Move(const MachineInstr *MI, unsigned Flag) {
   const MCInstrDesc &MCID = MI->getDesc();
-  return ((MCID.TSFlags & Flag) &&
-          isUInt<12>(MI->getOperand(2).getImm()) &&
+  return ((MCID.TSFlags & Flag) && isUInt<12>(MI->getOperand(2).getImm()) &&
           MI->getOperand(3).getReg() == 0);
 }
 
@@ -1806,10 +1777,6 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     splitAdjDynAlloc(MI);
     return true;
 
-  case TargetOpcode::LOAD_STACK_GUARD:
-    expandLoadStackGuard(&MI);
-    return true;
-
   default:
     return false;
   }
@@ -1831,6 +1798,28 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     return 18;
   if (MI.getOpcode() == TargetOpcode::PATCHABLE_RET)
     return 18 + (MI.getOperand(0).getImm() == SystemZ::CondReturn ? 4 : 0);
+  if ((MI.getOpcode() == SystemZ::MOVE_STACK_GUARD) ||
+      (MI.getOpcode() == SystemZ::COMPARE_STACK_GUARD))
+    return 6;
+  if ((MI.getOpcode() == SystemZ::LOAD_STACK_GUARD_ADDRESS) ||
+      (MI.getOpcode() == TargetOpcode::LOAD_STACK_GUARD)) {
+    StringRef GuardType = MI.getParent()
+                              ->getParent()
+                              ->getFunction()
+                              .getParent()
+                              ->getStackProtectorGuard();
+    unsigned Size = (MI.getOpcode() == TargetOpcode::LOAD_STACK_GUARD)
+                        ? 6 // lg to load value
+                        : 0;
+    if (GuardType == "global")
+      return Size + 6; // larl/lgrl
+    if (GuardType.empty() || GuardType == "tls")
+      return Size + 14; // ear,sllg,ear
+    llvm_unreachable(
+        (Twine("Unknown stack protector type \"") + GuardType + "\"")
+            .str()
+            .c_str());
+  }
 
   return MI.getDesc().getSize();
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
index bf832154ad717..4f0d12cd939ae 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
@@ -193,7 +193,6 @@ class SystemZInstrInfo : public SystemZGenInstrInfo {
                        unsigned HighOpcode) const;
   void expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode,
                         unsigned Size) const;
-  void expandLoadStackGuard(MachineInstr *MI) const;
 
   MachineInstrBuilder
   emitGRX32Move(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 35a923d070e3e..c9d0e0f7bc5e6 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -522,6 +522,20 @@ let SimpleBDXStore = 1, mayStore = 1 in {
                        [(store GR128:$src, bdxaddr20only128:$dst)]>;
   }
 }
+
+let hasNoSchedulingInfo = 1, hasSideEffects = 1 in {
+  // LOAD_STACK_GUARD_ADDRESS may not Load, because it has no (official)
+  // operands.
+  let isReMaterializable = 1 in
+    def LOAD_STACK_GUARD_ADDRESS : Pseudo<(outs ADDR64:$grdaddr), (ins), []>;
+  let mayLoad = 1 in {
+    let mayStore = 1 in def MOVE_STACK_GUARD
+        : Pseudo<(outs), (ins bdaddr12only:$grdloc, ADDR64:$grdaddr), []>;
+    let Defs = [CC] in def COMPARE_STACK_GUARD
+        : Pseudo<(outs), (ins bdaddr12only:$grdloc, ADDR64:$grdaddr), []>;
+  }
+}
+
 def STRL  : StoreRILPC<"strl", 0xC4F, aligned_store, GR32>;
 def STGRL : StoreRILPC<"stgrl", 0xC4B, aligned_store, GR64>;
 
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
new file mode 100644
index 0000000000000..d1d98537c1df2
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
@@ -0,0 +1,157 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs | FileCheck %s
+
+define i32 @test_global_stack_guard() #0 {
+; CHECK-LABEL: test_global_stack_guard:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -1192
+; CHECK-NEXT:    .cfi_def_cfa_offset 1352
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp0
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp0:
+; CHECK-NEXT:    larl %r1, __stack_chk_guard
+; CHECK-NEXT:    mvc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    la %r2, 160(%r15)
+; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp1
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp1:
+; CHECK-NEXT:    larl %r1, __stack_chk_guard
+; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    jlh .LBB0_2
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lmg %r14, %r15, 1304(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB0_2: # %entry
+; CHECK-NEXT:    brasl %r14, __stack_chk_fail at PLT
+entry:
+  %a1 = alloca [256 x i32], align 4
+  call void @foo3(ptr %a1)
+  ret i32 0
+}
+
+define i32 @test_global_stack_guard_branch(i32 %in) #0 {
+; CHECK-LABEL: test_global_stack_guard_branch:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r13, %r15, 104(%r15)
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -1192
+; CHECK-NEXT:    .cfi_def_cfa_offset 1352
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp2
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp2:
+; CHECK-NEXT:    larl %r1, __stack_chk_guard
+; CHECK-NEXT:    mvc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    lr %r13, %r2
+; CHECK-NEXT:    la %r2, 160(%r15)
+; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    cije %r13, 1, .LBB1_4
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:    cijlh %r13, 0, .LBB1_6
+; CHECK-NEXT:  # %bb.2: # %foo
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp3
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp3:
+; CHECK-NEXT:    larl %r1, __stack_chk_guard
+; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    jlh .LBB1_8
+; CHECK-NEXT:  # %bb.3: # %foo
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lmg %r13, %r15, 1296(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB1_4: # %bar
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp4
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp4:
+; CHECK-NEXT:    larl %r1, __stack_chk_guard
+; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    jlh .LBB1_8
+; CHECK-NEXT:  # %bb.5: # %bar
+; CHECK-NEXT:    lhi %r2, 1
+; CHECK-NEXT:    lmg %r13, %r15, 1296(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB1_6: # %else
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp5
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp5:
+; CHECK-NEXT:    larl %r1, __stack_chk_guard
+; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    jlh .LBB1_8
+; CHECK-NEXT:  # %bb.7: # %else
+; CHECK-NEXT:    lhi %r2, 2
+; CHECK-NEXT:    lmg %r13, %r15, 1296(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB1_8: # %bar
+; CHECK-NEXT:    brasl %r14, __stack_chk_fail at PLT
+entry:
+  %a1 = alloca [256 x i32], align 4
+  call void @foo3(ptr %a1)
+  switch i32 %in, label %else [
+    i32 0, label %foo
+    i32 1, label %bar
+  ]
+foo:
+  ret i32 0
+bar:
+  ret i32 1
+else:
+  ret i32 2
+}
+
+define i32 @test_global_stack_guard_large() #0 {
+; CHECK-LABEL: test_global_stack_guard_large:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -8376
+; CHECK-NEXT:    .cfi_def_cfa_offset 8536
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp6
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp6:
+; CHECK-NEXT:    larl %r1, __stack_chk_guard
+; CHECK-NEXT:    lay %r2, 8192(%r15)
+; CHECK-NEXT:    mvc 176(8,%r2), 0(%r1)
+; CHECK-NEXT:    la %r2, 176(%r15)
+; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp7
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp7:
+; CHECK-NEXT:    larl %r1, __stack_chk_guard
+; CHECK-NEXT:    lay %r2, 8192(%r15)
+; CHECK-NEXT:    clc 176(8,%r2), 0(%r1)
+; CHECK-NEXT:    jlh .LBB2_2
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lmg %r14, %r15, 8488(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB2_2: # %entry
+; CHECK-NEXT:    brasl %r14, __stack_chk_fail at PLT
+entry:
+  %a1 = alloca [2048 x i32], align 4
+  call void @foo3(ptr %a1)
+  ret i32 0
+}
+
+
+declare void @foo3(ptr)
+
+attributes #0 = { sspstrong "mstackprotector-guard-record" }
+
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"stack-protector-guard", !"global"}
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll b/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
new file mode 100644
index 0000000000000..fe8b6a7e4214d
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
@@ -0,0 +1,159 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs | FileCheck %s
+
+define i32 @test_global_stack_guard() #0 {
+; CHECK-LABEL: test_global_stack_guard:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -1192
+; CHECK-NEXT:    .cfi_def_cfa_offset 1352
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp0
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp0:
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    mvc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    la %r2, 160(%r15)
+; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp1
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp1:
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    jlh .LBB0_2
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lmg %r14, %r15, 1304(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB0_2: # %entry
+; CHECK-NEXT:    brasl %r14, __stack_chk_fail at PLT
+entry:
+  %a1 = alloca [256 x i32], align 4
+  call void @foo3(ptr %a1)
+  ret i32 0
+}
+
+define i32 @test_global_stack_guard_branch(i32 %in) #0 {
+; CHECK-LABEL: test_global_stack_guard_branch:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r13, %r15, 104(%r15)
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -1192
+; CHECK-NEXT:    .cfi_def_cfa_offset 1352
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp2
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp2:
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    mvc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    lr %r13, %r2
+; CHECK-NEXT:    la %r2, 160(%r15)
+; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    cije %r13, 1, .LBB1_4
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:    cijlh %r13, 0, .LBB1_6
+; CHECK-NEXT:  # %bb.2: # %foo
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp3
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp3:
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    jlh .LBB1_8
+; CHECK-NEXT:  # %bb.3: # %foo
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lmg %r13, %r15, 1296(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB1_4: # %bar
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp4
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp4:
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    jlh .LBB1_8
+; CHECK-NEXT:  # %bb.5: # %bar
+; CHECK-NEXT:    lhi %r2, 1
+; CHECK-NEXT:    lmg %r13, %r15, 1296(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB1_6: # %else
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp5
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp5:
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
+; CHECK-NEXT:    jlh .LBB1_8
+; CHECK-NEXT:  # %bb.7: # %else
+; CHECK-NEXT:    lhi %r2, 2
+; CHECK-NEXT:    lmg %r13, %r15, 1296(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB1_8: # %bar
+; CHECK-NEXT:    brasl %r14, __stack_chk_fail at PLT
+entry:
+  %a1 = alloca [256 x i32], align 4
+  call void @foo3(ptr %a1)
+  switch i32 %in, label %else [
+    i32 0, label %foo
+    i32 1, label %bar
+  ]
+foo:
+  ret i32 0
+bar:
+  ret i32 1
+else:
+  ret i32 2
+}
+
+
+define i32 @test_global_stack_guard_large() #0 {
+; CHECK-LABEL: test_global_stack_guard_large:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -8376
+; CHECK-NEXT:    .cfi_def_cfa_offset 8536
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp6
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp6:
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    lay %r2, 8192(%r15)
+; CHECK-NEXT:    mvc 176(8,%r2), 0(%r1)
+; CHECK-NEXT:    la %r2, 176(%r15)
+; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
+; CHECK-NEXT:    .quad .Ltmp7
+; CHECK-NEXT:    .text
+; CHECK-NEXT:  .Ltmp7:
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    lay %r2, 8192(%r15)
+; CHECK-NEXT:    clc 176(8,%r2), 0(%r1)
+; CHECK-NEXT:    jlh .LBB2_2
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lmg %r14, %r15, 8488(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB2_2: # %entry
+; CHECK-NEXT:    brasl %r14, __stack_chk_fail at PLT
+entry:
+  %a1 = alloca [2048 x i32], align 4
+  call void @foo3(ptr %a1)
+  ret i32 0
+}
+
+declare void @foo3(ptr)
+
+attributes #0 = { sspstrong "mstackprotector-guard-record" }
+
+
+!llvm.module.flags = !{!0, !1, !2}
+!0 = !{i32 1, !"stack-protector-guard", !"global"}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-tls.ll b/llvm/test/CodeGen/SystemZ/stack-guard-tls.ll
new file mode 100644
index 0000000000000..ea5ad0d5429cb
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-tls.ll
@@ -0,0 +1,135 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs | FileCheck %s
+
+define i32 @test_tls_stack_guard() #0 {
+; CHECK-LABEL: test_tls_stack_guard:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -1192
+; CHECK-NEXT:    .cfi_def_cfa_offset 1352
+; CHECK-NEXT:    ear %r1, %a0
+; CHECK-NEXT:    sllg %r1, %r1, 32
+; CHECK-NEXT:    ear %r1, %a1
+; CHECK-NEXT:    mvc 1184(8,%r15), 40(%r1)
+; CHECK-NEXT:    la %r2, 160(%r15)
+; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    ear %r1, %a0
+; CHECK-NEXT:    sllg %r1, %r1, 32
+; CHECK-NEXT:    ear %r1, %a1
+; CHECK-NEXT:    clc 1184(8,%r15), 40(%r1)
+; CHECK-NEXT:    jlh .LBB0_2
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lmg %r14, %r15, 1304(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB0_2: # %entry
+; CHECK-NEXT:    brasl %r14, __stack_chk_fail at PLT
+entry:
+  %a1 = alloca [256 x i32], align 4
+  call void @foo3(ptr %a1)
+  ret i32 0
+}
+
+
+define i32 @test_global_stack_guard_branch(i32 %in) #0 {
+; CHECK-LABEL: test_global_stack_guard_branch:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r13, %r15, 104(%r15)
+; CHECK-NEXT:    .cfi_offset %r13, -56
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -1192
+; CHECK-NEXT:    .cfi_def_cfa_offset 1352
+; CHECK-NEXT:    ear %r1, %a0
+; CHECK-NEXT:    sllg %r1, %r1, 32
+; CHECK-NEXT:    ear %r1, %a1
+; CHECK-NEXT:    mvc 1184(8,%r15), 40(%r1)
+; CHECK-NEXT:    lr %r13, %r2
+; CHECK-NEXT:    la %r2, 160(%r15)
+; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    cije %r13, 1, .LBB1_4
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:    cijlh %r13, 0, .LBB1_6
+; CHECK-NEXT:  # %bb.2: # %foo
+; CHECK-NEXT:    ear %r1, %a0
+; CHECK-NEXT:    sllg %r1, %r1, 32
+; CHECK-NEXT:    ear %r1, %a1
+; CHECK-NEXT:    clc 1184(8,%r15), 40(%r1)
+; CHECK-NEXT:    jlh .LBB1_8
+; CHECK-NEXT:  # %bb.3: # %foo
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lmg %r13, %r15, 1296(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB1_4: # %bar
+; CHECK-NEXT:    ear %r1, %a0
+; CHECK-NEXT:    sllg %r1, %r1, 32
+; CHECK-NEXT:    ear %r1, %a1
+; CHECK-NEXT:    clc 1184(8,%r15), 40(%r1)
+; CHECK-NEXT:    jlh .LBB1_8
+; CHECK-NEXT:  # %bb.5: # %bar
+; CHECK-NEXT:    lhi %r2, 1
+; CHECK-NEXT:    lmg %r13, %r15, 1296(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB1_6: # %else
+; CHECK-NEXT:    ear %r1, %a0
+; CHECK-NEXT:    sllg %r1, %r1, 32
+; CHECK-NEXT:    ear %r1, %a1
+; CHECK-NEXT:    clc 1184(8,%r15), 40(%r1)
+; CHECK-NEXT:    jlh .LBB1_8
+; CHECK-NEXT:  # %bb.7: # %else
+; CHECK-NEXT:    lhi %r2, 2
+; CHECK-NEXT:    lmg %r13, %r15, 1296(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB1_8: # %bar
+; CHECK-NEXT:    brasl %r14, __stack_chk_fail at PLT
+entry:
+  %a1 = alloca [256 x i32], align 4
+  call void @foo3(ptr %a1)
+  switch i32 %in, label %else [
+    i32 0, label %foo
+    i32 1, label %bar
+  ]
+foo:
+  ret i32 0
+bar:
+  ret i32 1
+else:
+  ret i32 2
+}
+
+define i32 @test_tls_stack_guard_large() #0 {
+; CHECK-LABEL: test_tls_stack_guard_large:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    stmg %r14, %r15, 112(%r15)
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -1192
+; CHECK-NEXT:    .cfi_def_cfa_offset 1352
+; CHECK-NEXT:    ear %r1, %a0
+; CHECK-NEXT:    sllg %r1, %r1, 32
+; CHECK-NEXT:    ear %r1, %a1
+; CHECK-NEXT:    mvc 1184(8,%r15), 40(%r1)
+; CHECK-NEXT:    la %r2, 160(%r15)
+; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    ear %r1, %a0
+; CHECK-NEXT:    sllg %r1, %r1, 32
+; CHECK-NEXT:    ear %r1, %a1
+; CHECK-NEXT:    clc 1184(8,%r15), 40(%r1)
+; CHECK-NEXT:    jlh .LBB2_2
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lmg %r14, %r15, 1304(%r15)
+; CHECK-NEXT:    br %r14
+; CHECK-NEXT:  .LBB2_2: # %entry
+; CHECK-NEXT:    brasl %r14, __stack_chk_fail at PLT
+entry:
+  %a1 = alloca [256 x i32], align 4
+  call void @foo3(ptr %a1)
+  ret i32 0
+}
+
+declare void @foo3(ptr)
+
+attributes #0 = { sspstrong }
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard.ll b/llvm/test/CodeGen/SystemZ/stack-guard.ll
deleted file mode 100644
index 04a87b4632dd2..0000000000000
--- a/llvm/test/CodeGen/SystemZ/stack-guard.ll
+++ /dev/null
@@ -1,33 +0,0 @@
-; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
-
-; CHECK-LABEL: @test_stack_guard
-; CHECK: ear [[REG1:%r[1-9][0-9]?]], %a0
-; CHECK: sllg [[REG1]], [[REG1]], 32
-; CHECK: ear [[REG1]], %a1
-; CHECK: lg [[REG1]], 40([[REG1]])
-; CHECK: stg [[REG1]], {{[0-9]*}}(%r15)
-; CHECK: brasl %r14, foo3 at PLT
-; CHECK: ear [[REG2:%r[1-9][0-9]?]], %a0
-; CHECK: sllg [[REG2]], [[REG2]], 32
-; CHECK: ear [[REG2]], %a1
-; CHECK: lg [[REG2]], 40([[REG2]])
-; CHECK: cg [[REG2]], {{[0-9]*}}(%r15)
-
-define i32 @test_stack_guard() #0 {
-entry:
-  %a1 = alloca [256 x i32], align 4
-  call void @llvm.lifetime.start.p0(i64 1024, ptr %a1)
-  call void @foo3(ptr %a1)
-  call void @llvm.lifetime.end.p0(i64 1024, ptr %a1)
-  ret i32 0
-}
-
-; Function Attrs: nounwind
-declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
-
-declare void @foo3(ptr)
-
-; Function Attrs: nounwind
-declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
-
-attributes #0 = { sspstrong }

>From db819d59d2cb2df9514c53cdb648b25606bcfb6b Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Thu, 11 Dec 2025 09:35:53 +0100
Subject: [PATCH 02/29] Double up the StackGuard Pseudos to introduce dead
 defreg

The intent here is to add two pseudos with a _DAG suffix which can be slotted
into the Selection DAG in places where the instruction they are replacing does
not define a register. Then, in the custom inserter, these pseudos are replaced
with the "real" pseudos which do define an early-clobber register, which will
be assigned a physical register by regalloc, which can then be used in
ExpandPostRAPseudos to store the stack guard's address without fear that the
register might end up spilled.
---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 110 ++-------------
 .../Target/SystemZ/SystemZISelLowering.cpp    |  59 ++++++--
 llvm/lib/Target/SystemZ/SystemZISelLowering.h |   5 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  | 128 +++++++++++++++---
 llvm/lib/Target/SystemZ/SystemZInstrInfo.h    |   7 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td   |  23 ++--
 6 files changed, 189 insertions(+), 143 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index fb1c83b968ac2..7d9f7c429fa87 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -785,41 +785,21 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   case SystemZ::EH_SjLj_Setup:
     return;
 
-  case SystemZ::LOAD_STACK_GUARD: {
-    // If requested, record address of stack guard address load
-    if (MF->getFunction().hasFnAttribute("mstackprotector-guard-record"))
-      emitStackProtectorLocEntry();
-    Register AddrReg = emitLoadStackGuardAddress(MI);
-    LoweredMI = MCInstBuilder(SystemZ::LG)
-                    .addReg(AddrReg)
-                    .addImm(getStackGuardOffset(MI->getParent()))
-                    .addReg(0);
-  } break;
-
-  case SystemZ::LOAD_STACK_GUARD_ADDRESS:
-    // If requested, record address of stack guard address load
-    if (MF->getFunction().hasFnAttribute("mstackprotector-guard-record"))
-      emitStackProtectorLocEntry();
-    emitLoadStackGuardAddress(MI);
-    return;
+  case SystemZ::LOAD_STACK_GUARD:
+    llvm_unreachable("LOAD_STACK_GUARD should have been eliminated by the DAG Combiner.");
 
+  case SystemZ::MOVE_STACK_GUARD:
   case SystemZ::COMPARE_STACK_GUARD:
-    LoweredMI = MCInstBuilder(SystemZ::CLC)
-                    .addReg(MI->getOperand(0).getReg())
-                    .addImm(MI->getOperand(1).getImm())
-                    .addImm(8)
-                    .addReg(MI->getOperand(2).getReg())
-                    .addImm(getStackGuardOffset(MI->getParent()));
-    break;
+    llvm_unreachable("MOVE_STACK_GUARD and COMPARE_STACK_GUARD should have been expanded by ExpandPostRAPseudo.");
 
-  case SystemZ::MOVE_STACK_GUARD:
-    LoweredMI = MCInstBuilder(SystemZ::MVC)
-                    .addReg(MI->getOperand(0).getReg())
-                    .addImm(MI->getOperand(1).getImm())
-                    .addImm(8)
-                    .addReg(MI->getOperand(2).getReg())
-                    .addImm(getStackGuardOffset(MI->getParent()));
+  case SystemZ::LARL:
+  case SystemZ::LGRL: {
+    auto & Op = MI->getOperand(1);
+    if (Op.isGlobal() && (Op.getGlobal()->getName() == "__stack_chk_guard"))
+      emitStackProtectorLocEntry();
+    Lower.lower(MI, LoweredMI);
     break;
+  }
 
   default:
     Lower.lower(MI, LoweredMI);
@@ -838,74 +818,6 @@ void SystemZAsmPrinter::emitStackProtectorLocEntry() {
   OutStreamer->emitLabel(Sym);
 }
 
-// Emit the stack guard address load, depending on guard type.
-// Return the register the stack guard address was loaded into.
-Register SystemZAsmPrinter::emitLoadStackGuardAddress(const MachineInstr *MI) {
-  const MachineBasicBlock *MBB = MI->getParent();
-  const MachineFunction &MF = *MBB->getParent();
-  const Register AddrReg = MI->getOperand(0).getReg();
-  const MCRegisterInfo &MRI = *TM.getMCRegisterInfo();
-  const Register Reg32 = MRI.getSubReg(AddrReg, SystemZ::subreg_l32);
-
-  const Module *M = MF.getFunction().getParent();
-  StringRef GuardType = M->getStackProtectorGuard();
-
-  if (GuardType.empty() || (GuardType == "tls")) {
-    // EAR can only load the low subregister so use a shift for %a0 to produce
-    // the GR containing %a0 and %a1.
-
-    // ear <reg>, %a0
-    MCInst EAR1 = MCInstBuilder(SystemZ::EAR)
-                      .addReg(Reg32)
-                      .addReg(SystemZ::A0)
-                      .addReg(AddrReg);
-
-    // sllg <reg>, <reg>, 32
-    MCInst SLLG = MCInstBuilder(SystemZ::SLLG)
-                      .addReg(AddrReg)
-                      .addReg(AddrReg)
-                      .addReg(0)
-                      .addImm(32);
-
-    // ear <reg>, %a1
-    MCInst EAR2 = MCInstBuilder(SystemZ::EAR)
-                      .addReg(Reg32)
-                      .addReg(SystemZ::A1)
-                      .addReg(AddrReg);
-
-    EmitToStreamer(*OutStreamer, EAR1);
-    EmitToStreamer(*OutStreamer, SLLG);
-    EmitToStreamer(*OutStreamer, EAR2);
-  } else if (GuardType == "global") {
-    // Obtain the global value.
-    const auto *GV = M->getGlobalVariable(
-        "__stack_chk_guard", PointerType::getUnqual(M->getContext()));
-    assert(GV &&
-           "could not create reference to global variable __stack_chk_guard");
-    auto *Sym = TM.getSymbol(GV);
-    // Ref->
-    // Emit the address load.
-    MCInst Load;
-    if (M->getPICLevel() == PICLevel::NotPIC) {
-      Load = MCInstBuilder(SystemZ::LARL)
-                 .addReg(AddrReg)
-                 .addExpr(MCSymbolRefExpr::create(Sym, OutContext));
-    } else {
-      Load =
-          MCInstBuilder(SystemZ::LGRL)
-              .addReg(AddrReg)
-              .addExpr(MCSymbolRefExpr::create(Sym, SystemZ::S_GOT, OutContext))
-              .addExpr(getGlobalOffsetTable(OutContext));
-    }
-    EmitToStreamer(*OutStreamer, Load);
-  } else {
-    llvm_unreachable(
-        (Twine("Unknown stack protector type \"") + GuardType + "\"")
-            .str()
-            .c_str());
-  }
-  return AddrReg;
-}
 
 // Emit the largest nop instruction smaller than or equal to NumBytes
 // bytes.  Return the size of nop emitted.
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 150277656b2a8..5dbf1175bed7f 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SystemZISelLowering.h"
+#include "MCTargetDesc/SystemZMCTargetDesc.h"
 #include "SystemZCallingConv.h"
 #include "SystemZConstantPoolValue.h"
 #include "SystemZMachineFunctionInfo.h"
@@ -8133,16 +8134,14 @@ SDValue SystemZTargetLowering::combineSTORE(
   // combine STORE (LOAD_STACK_GUARD) into MOVE_STACK_GUARD
   if (Op1->isMachineOpcode() &&
       (Op1->getMachineOpcode() == SystemZ::LOAD_STACK_GUARD)) {
-    // If so, create a MOVE_STACK_GUARD node to replace the store,
-    // and a LOAD_STACK_GUARD_ADDRESS to replace the LOAD_STACK_GUARD
-    MachineSDNode *LoadAddr = DAG.getMachineNode(
-        SystemZ::LOAD_STACK_GUARD_ADDRESS, SDLoc(SN), MVT::i64);
+    // If so, create a MOVE_STACK_GUARD_DAG node to replace the store,
+    // as well as the LOAD_STACK_GUARD.
     int FI = cast<FrameIndexSDNode>(SN->getOperand(2))->getIndex();
     // FrameIndex, Dummy Displacement
     SDValue Ops[] = {DAG.getTargetFrameIndex(FI, MVT::i64),
                      DAG.getTargetConstant(0, SDLoc(SN), MVT::i64),
-                     SDValue(LoadAddr, 0), SN->getChain()};
-    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOVE_STACK_GUARD,
+                     SN->getChain()};
+    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOVE_STACK_GUARD_DAG,
                                              SDLoc(SN), MVT::Other, Ops);
 
     return SDValue(Move, 0);
@@ -9052,17 +9051,13 @@ SDValue SystemZTargetLowering::combineBR_CCMASK(SDNode *N,
     // Handle the load's chain if necessary
     DAG.ReplaceAllUsesOfValueWith(OutChain, InChain);
 
-    // Construct the LOAD_STACK_GUARD_ADDRESS node to replace LOAD_STACK_GUARD
-    auto *LoadAddress =
-        DAG.getMachineNode(SystemZ::LOAD_STACK_GUARD_ADDRESS, DL, MVT::i64);
-
-    // Construct the COMPARE_STACK_GUARD node
+    // Construct the COMPARE_STACK_GUARD_DAG to replace the icmp and
+    // LOAD_STACK_GUARD nodes.
     SDVTList CmpVTs = DAG.getVTList(MVT::Other, MVT::Glue);
     auto CompOps = {DAG.getTargetFrameIndex(FI, MVT::i64),
-                    DAG.getTargetConstant(0, DL, MVT::i64),
-                    SDValue(LoadAddress, 0), InChain};
-    auto *Compare =
-        DAG.getMachineNode(SystemZ::COMPARE_STACK_GUARD, DL, CmpVTs, CompOps);
+                    DAG.getTargetConstant(0, DL, MVT::i64), InChain};
+    auto *Compare = DAG.getMachineNode(SystemZ::COMPARE_STACK_GUARD_DAG, DL,
+                                       CmpVTs, CompOps);
     // Construct the BRC node using COMPARE_STACK_GUARD's CC result
     auto BranchOps = {DAG.getTargetConstant(CCValidVal, DL, MVT::i32),
                       DAG.getTargetConstant(CCMaskVal, DL, MVT::i32),
@@ -11161,6 +11156,34 @@ getBackchainAddress(SDValue SP, SelectionDAG &DAG) const {
                      DAG.getIntPtrConstant(TFL->getBackchainOffset(MF), DL));
 }
 
+MachineBasicBlock *
+SystemZTargetLowering::emitMSGPseudo(MachineInstr &MI,
+                                     MachineBasicBlock *MBB) const {
+  MachineRegisterInfo *MRI = &MBB->getParent()->getRegInfo();
+  const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
+  DebugLoc DL = MI.getDebugLoc();
+  Register AddrReg = MRI->createVirtualRegister(&SystemZ::ADDR64BitRegClass);
+  BuildMI(*MBB, MI, DL, TII->get(SystemZ::MOVE_STACK_GUARD), AddrReg)
+      .addFrameIndex(MI.getOperand(0).getIndex())
+      .addImm(MI.getOperand(1).getImm());
+  MI.eraseFromParent();
+  return MBB;
+}
+
+MachineBasicBlock *
+SystemZTargetLowering::emitCSGPseudo(MachineInstr &MI,
+                                     MachineBasicBlock *MBB) const {
+  MachineRegisterInfo *MRI = &MBB->getParent()->getRegInfo();
+  const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
+  DebugLoc DL = MI.getDebugLoc();
+  Register AddrReg = MRI->createVirtualRegister(&SystemZ::ADDR64BitRegClass);
+  BuildMI(*MBB, MI, DL, TII->get(SystemZ::COMPARE_STACK_GUARD), AddrReg)
+      .addFrameIndex(MI.getOperand(0).getIndex())
+      .addImm(MI.getOperand(1).getImm());
+  MI.eraseFromParent();
+  return MBB;
+}
+
 MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
     MachineInstr &MI, MachineBasicBlock *MBB) const {
   switch (MI.getOpcode()) {
@@ -11318,6 +11341,12 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
   case TargetOpcode::PATCHPOINT:
     return emitPatchPoint(MI, MBB);
 
+  case SystemZ::MOVE_STACK_GUARD_DAG:
+    return emitMSGPseudo(MI, MBB);
+
+  case SystemZ::COMPARE_STACK_GUARD_DAG:
+    return emitCSGPseudo(MI, MBB);
+
   default:
     llvm_unreachable("Unexpected instr type to insert");
   }
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index db793ae096937..efab825b70e94 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -470,7 +470,10 @@ class SystemZTargetLowering : public TargetLowering {
                                          unsigned Opcode) const;
   MachineBasicBlock *emitProbedAlloca(MachineInstr &MI,
                                       MachineBasicBlock *MBB) const;
-
+  MachineBasicBlock *emitMSGPseudo(MachineInstr &MI,
+                                   MachineBasicBlock *MBB) const;
+  MachineBasicBlock *emitCSGPseudo(MachineInstr &MI,
+                                   MachineBasicBlock *MBB) const;
   SDValue getBackchainAddress(SDValue SP, SelectionDAG &DAG) const;
 
   MachineMemOperand::Flags
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index e6751e99bd11a..3deb9b312e027 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1777,11 +1777,104 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     splitAdjDynAlloc(MI);
     return true;
 
+  case SystemZ::MOVE_STACK_GUARD:
+    expandMSGPseudo(MI);
+    return true;
+
+  case SystemZ::COMPARE_STACK_GUARD:
+    expandCSGPseudo(MI);
+    return true;
+
   default:
     return false;
   }
 }
 
+namespace {
+unsigned long getStackGuardOffset(const MachineBasicBlock &MBB) {
+  // In the TLS (default) case, AddrReg will contain the thread pointer, so we
+  // need to add 40 bytes to get the actual address of the stack guard.
+  StringRef GuardType =
+      MBB.getParent()->getFunction().getParent()->getStackProtectorGuard();
+  return (GuardType == "global") ? 0 : 40;
+}
+} // namespace
+
+// Emit the stack guard address load, depending on guard type.
+// Return the register the stack guard address was loaded into.
+void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI) const {
+  MachineBasicBlock &MBB = *(MI.getParent());
+  const MachineFunction &MF = *(MBB.getParent());
+  const Register AddrReg = MI.getOperand(0).getReg();
+  const MachineRegisterInfo &MRI = MF.getRegInfo();
+  const Register Reg32 =
+      MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
+  const auto DL = MI.getDebugLoc();
+
+  const Module *M = MF.getFunction().getParent();
+  StringRef GuardType = M->getStackProtectorGuard();
+
+  if (GuardType.empty() || (GuardType == "tls")) {
+    // EAR can only load the low subregister so use a shift for %a0 to produce
+    // the GR containing %a0 and %a1.
+
+    // ear <reg>, %a0
+    BuildMI(MBB, MI, DL, get(SystemZ::EAR), Reg32)
+        .addReg(SystemZ::A0);
+
+    // sllg <reg>, <reg>, 32
+    BuildMI(MBB, MI, DL, get(SystemZ::SLLG), AddrReg)
+        .addReg(AddrReg)
+        .addReg(0)
+        .addImm(32);
+
+    // ear <reg>, %a1
+    BuildMI(MBB, MI, DL, get(SystemZ::EAR), Reg32)
+        .addReg(SystemZ::A1);
+
+  } else if (GuardType == "global") {
+    // Obtain the global value.
+    const auto *GV = M->getNamedGlobal("__stack_chk_guard");
+    assert(GV &&
+           "could not create reference to global variable __stack_chk_guard");
+    // Ref->
+    // Emit the address load.
+    if (M->getPICLevel() == PICLevel::NotPIC) {
+      BuildMI(MBB, MI, DL, get(SystemZ::LARL), AddrReg).addGlobalAddress(GV);
+    } else {
+      BuildMI(MBB, MI, DL, get(SystemZ::LGRL), AddrReg)
+          .addGlobalAddress(GV, 0, SystemZII::MO_GOT);
+    }
+
+  } else {
+    llvm_unreachable(
+        (Twine("Unknown stack protector type \"") + GuardType + "\"")
+            .str()
+            .c_str());
+  }
+}
+
+void SystemZInstrInfo::expandMSGPseudo(MachineInstr &MI) const {
+  emitLoadStackGuardAddress(MI);
+  BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(SystemZ::MVC))
+      .addReg(MI.getOperand(1).getReg())
+      .addImm(MI.getOperand(2).getImm())
+      .addImm(8)
+      .addReg(MI.getOperand(0).getReg())
+      .addImm(getStackGuardOffset(*(MI.getParent())));
+  MI.removeFromParent();
+}
+void SystemZInstrInfo::expandCSGPseudo(MachineInstr &MI) const {
+  emitLoadStackGuardAddress(MI);
+  BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(SystemZ::CLC))
+      .addReg(MI.getOperand(1).getReg())
+      .addImm(MI.getOperand(2).getImm())
+      .addImm(8)
+      .addReg(MI.getOperand(0).getReg())
+      .addImm(getStackGuardOffset(*(MI.getParent())));
+  MI.removeFromParent();
+}
+
 unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
   if (MI.isInlineAsm()) {
     const MachineFunction *MF = MI.getParent()->getParent();
@@ -1799,27 +1892,24 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
   if (MI.getOpcode() == TargetOpcode::PATCHABLE_RET)
     return 18 + (MI.getOperand(0).getImm() == SystemZ::CondReturn ? 4 : 0);
   if ((MI.getOpcode() == SystemZ::MOVE_STACK_GUARD) ||
-      (MI.getOpcode() == SystemZ::COMPARE_STACK_GUARD))
-    return 6;
-  if ((MI.getOpcode() == SystemZ::LOAD_STACK_GUARD_ADDRESS) ||
-      (MI.getOpcode() == TargetOpcode::LOAD_STACK_GUARD)) {
-    StringRef GuardType = MI.getParent()
-                              ->getParent()
-                              ->getFunction()
-                              .getParent()
-                              ->getStackProtectorGuard();
-    unsigned Size = (MI.getOpcode() == TargetOpcode::LOAD_STACK_GUARD)
-                        ? 6 // lg to load value
-                        : 0;
-    if (GuardType == "global")
-      return Size + 6; // larl/lgrl
-    if (GuardType.empty() || GuardType == "tls")
-      return Size + 14; // ear,sllg,ear
-    llvm_unreachable(
-        (Twine("Unknown stack protector type \"") + GuardType + "\"")
+      (MI.getOpcode() == SystemZ::COMPARE_STACK_GUARD)) {
+      StringRef GuardType = MI.getParent()
+      ->getParent()
+      ->getFunction()
+      .getParent()
+      ->getStackProtectorGuard();
+      unsigned Size = 6;  // mvc,clc
+      if (GuardType == "global")
+        Size += 6; // larl/lgrl
+      else if (GuardType.empty() || GuardType == "tls")
+        Size += 14; // ear,sllg,ear
+      else
+        llvm_unreachable(
+          (Twine("Unknown stack protector type \"") + GuardType + "\"")
             .str()
             .c_str());
-  }
+      return Size;
+    }
 
   return MI.getDesc().getSize();
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
index 4f0d12cd939ae..3b1fc9d1b77d2 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
@@ -193,7 +193,8 @@ class SystemZInstrInfo : public SystemZGenInstrInfo {
                        unsigned HighOpcode) const;
   void expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode,
                         unsigned Size) const;
-
+  void expandMSGPseudo(MachineInstr &MI) const;
+  void expandCSGPseudo(MachineInstr &MI) const;
   MachineInstrBuilder
   emitGRX32Move(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
                 const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
@@ -218,6 +219,10 @@ class SystemZInstrInfo : public SystemZGenInstrInfo {
                                        unsigned CommuteOpIdx1,
                                        unsigned CommuteOpIdx2) const override;
 
+  // Emits a load of the stack guard's address, using the DestReg
+  // of the given MI as the target.
+  void emitLoadStackGuardAddress(MachineInstr &MI) const;
+
 public:
   explicit SystemZInstrInfo(const SystemZSubtarget &STI);
 
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index c9d0e0f7bc5e6..cf81c4bdd7ed0 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -524,15 +524,22 @@ let SimpleBDXStore = 1, mayStore = 1 in {
 }
 
 let hasNoSchedulingInfo = 1, hasSideEffects = 1 in {
-  // LOAD_STACK_GUARD_ADDRESS may not Load, because it has no (official)
-  // operands.
-  let isReMaterializable = 1 in
-    def LOAD_STACK_GUARD_ADDRESS : Pseudo<(outs ADDR64:$grdaddr), (ins), []>;
   let mayLoad = 1 in {
-    let mayStore = 1 in def MOVE_STACK_GUARD
-        : Pseudo<(outs), (ins bdaddr12only:$grdloc, ADDR64:$grdaddr), []>;
-    let Defs = [CC] in def COMPARE_STACK_GUARD
-        : Pseudo<(outs), (ins bdaddr12only:$grdloc, ADDR64:$grdaddr), []>;
+    let mayStore = 1 in {
+      // load the stack guard's address, and move the stack guard to the stack.
+      let usesCustomInserter = 1 in def MOVE_STACK_GUARD_DAG
+          : Pseudo<(outs), (ins bdaddr12only:$grdloc), []>;
+      let Constraints = "@earlyclobber $grdaddr" in def MOVE_STACK_GUARD
+          : Pseudo<(outs ADDR64:$grdaddr), (ins bdaddr12only:$grdloc), []>;
+    }
+    let Defs = [CC] in {
+      // load the stack guard's address, and compare the stack guard against
+      // the one on the stack.
+      let usesCustomInserter = 1 in def COMPARE_STACK_GUARD_DAG
+          : Pseudo<(outs), (ins bdaddr12only:$grdloc), []>;
+      let Constraints = "@earlyclobber $grdaddr" in def COMPARE_STACK_GUARD
+          : Pseudo<(outs ADDR64:$grdaddr), (ins bdaddr12only:$grdloc), []>;
+    }
   }
 }
 

>From d241f8765c6b517f89c8a5d7578a8812b5db1ae0 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Fri, 19 Dec 2025 10:51:19 +0100
Subject: [PATCH 03/29] Introduce RegScavenging Fallback

RegScavenger has a bug (https://github.com/llvm/llvm-project/issues/172511)
that makes it so that the early-clobber flag on the def reg associated with
`MOVE_STACK_GUARD` and `COMPARE_STACK_GUARD` gets ignored when frame index
elimination has to insert additional VRegs post RA in order to facilitate
materializing a workable base address from which to reach the stack guard
on a particularly large stack frame.
That bug leads to the early-clobber def reg, which is intended to be used
as a scratch register to hold the address of the stack guard, being assigned
to the same physical register as the one that is used to materialize the
stack base address.
In this workaround, that case is detected and RegScavenger is called again
to scavenge a different register for this use. This is not 100% guaranteed
to work, as extremely register-constrained, and large stack frames may not
have a register or emergency spill slot available, but this is all we can
do as a workaround until the underlying RegScavenger issue is fixed.
---
 .../CodeGen/SystemZ/stack-guard-pseudos.c     | 15 +++--
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 10 ----
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  | 59 +++++++++++++++----
 llvm/lib/Target/SystemZ/SystemZInstrInfo.h    |  6 +-
 .../SystemZ/stack-guard-global-nopic.ll       | 12 ++--
 .../CodeGen/SystemZ/stack-guard-global-pic.ll | 12 ++--
 6 files changed, 73 insertions(+), 41 deletions(-)

diff --git a/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c b/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
index b364aa4028ec7..ad7b8b177e106 100644
--- a/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
+++ b/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
@@ -1,10 +1,13 @@
-// RUN: %clang_cc1 -S -mllvm -stop-after=systemz-isel -stack-protector 1 -triple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-PSEUDOS %s
+// RUN: %clang_cc1 -S -mllvm -stop-after=systemz-isel -stack-protector 1 -triple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-DAGCOMBINE %s
+// RUN: %clang_cc1 -S -mllvm -stop-after=finalize-isel -stack-protector 1 -triple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-CUSTOMINSERT %s
 // RUN: not %clang_cc1 -S -stack-protector 1 -mstack-protector-guard-record -triple=s390x-ibm-linux < %s -o - 2>&1 | FileCheck -check-prefix=CHECK-OPTS %s 
-// CHECK-PSEUDOS:   bb.0.entry:
-// CHECK-PSEUDOS:     %3:addr64bit = LOAD_STACK_GUARD_ADDRESS
-// CHECK-PSEUDOS:     MOVE_STACK_GUARD %stack.0.StackGuardSlot, 0, %3
-// CHECK-PSEUDOS:     COMPARE_STACK_GUARD %stack.0.StackGuardSlot, 0, %3, implicit-def $cc
-
+// CHECK-DAGCOMBINE:   bb.0.entry:
+// CHECK-DAGCOMBINE:     MOVE_STACK_GUARD_DAG %stack.0.StackGuardSlot, 0
+// CHECK-DAGCOMBINE:     COMPARE_STACK_GUARD_DAG %stack.0.StackGuardSlot, 0, implicit-def $cc
+// CHECK-CUSTOMINSERT: bb.0.entry
+// CHECK-CUSTOMINSERT:   early-clobber %10:addr64bit = MOVE_STACK_GUARD %stack.0.StackGuardSlot, 0
+// CHECK_CUSTOMINSERT: bb.3.entry
+// CHECK-CUSTOMINSERT: early-clobber %14:addr64bit = COMPARE_STACK_GUARD %stack.0.StackGuardSlot, 0, implicit-def $cc
 extern char *strcpy (char * D, const char * S);
 int main(int argc, char *argv[])
 {
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 7d9f7c429fa87..2eee99c4ce65f 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -247,16 +247,6 @@ SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MachineOperand MO) {
   return insert(Sym, ADAslotType);
 }
 
-namespace {
-unsigned long getStackGuardOffset(const MachineBasicBlock *MBB) {
-  // In the TLS (default) case, AddrReg will contain the thread pointer, so we
-  // need to add 40 bytes to get the actual address of the stack guard.
-  StringRef GuardType =
-      MBB->getParent()->getFunction().getParent()->getStackProtectorGuard();
-  return (GuardType == "global") ? 0 : 40;
-}
-} // namespace
-
 void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   SystemZ_MC::verifyInstructionPredicates(MI->getOpcode(),
                                           getSubtargetInfo().getFeatureBits());
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 3deb9b312e027..8aaea18a8cc29 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -27,6 +27,7 @@
 #include "llvm/CodeGen/MachineMemOperand.h"
 #include "llvm/CodeGen/MachineOperand.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
 #include "llvm/CodeGen/SlotIndexes.h"
 #include "llvm/CodeGen/StackMaps.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
@@ -1791,21 +1792,55 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
 }
 
 namespace {
-unsigned long getStackGuardOffset(const MachineBasicBlock &MBB) {
+    Register scavengeAddrReg(MachineInstr& MI, MachineBasicBlock* MBB) {
+    // create fresh RegScavanger instance.
+    RegScavenger RS;
+    // initialize RegScavenger to correct location
+    RS.enterBasicBlockEnd(*MBB);
+    RS.backward(MI);
+
+    // Attempt to find a free register.
+    Register Scratch = RS.FindUnusedReg(&SystemZ::ADDR64BitRegClass);
+    // If not found, scavenge one, i.e. evict something to a stack spill slot.
+    if (!Scratch) {
+      Scratch = RS.scavengeRegisterBackwards(
+          SystemZ::ADDR64BitRegClass,
+          MI,              // Scavenge back to this position.
+          true,  // Will need Scratch Reg after MI.
+          0,            
+          true     // Spills are allowed.
+      );
+    }
+    return Scratch;
+  }
+unsigned long getStackGuardOffset(const MachineBasicBlock *MBB) {
   // In the TLS (default) case, AddrReg will contain the thread pointer, so we
   // need to add 40 bytes to get the actual address of the stack guard.
   StringRef GuardType =
-      MBB.getParent()->getFunction().getParent()->getStackProtectorGuard();
+      MBB->getParent()->getFunction().getParent()->getStackProtectorGuard();
   return (GuardType == "global") ? 0 : 40;
 }
+// Check MI (which should be either MOVE_STACK_GUARD or COMPARE_STACK_GUARD)
+// to see if the early-clobber flag on the def reg was honored. If so,
+// return that register. If not, scavenge a new register and return that.
+// This is a workaround for https://github.com/llvm/llvm-project/issues/172511
+// and should be removed once that issue is resolved.
+Register chooseAddrReg(MachineInstr& MI, MachineBasicBlock *MBB) {
+  Register DefReg = MI.getOperand(0).getReg();
+  Register OpReg = MI.getOperand(1).getReg();
+  // if we can use DefReg, return it
+  if (DefReg != OpReg)
+    return DefReg;
+  // otherwise, scavenge
+  return scavengeAddrReg(MI, MBB);
+}
 } // namespace
 
 // Emit the stack guard address load, depending on guard type.
 // Return the register the stack guard address was loaded into.
-void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI) const {
+void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI, Register AddrReg) const {
   MachineBasicBlock &MBB = *(MI.getParent());
   const MachineFunction &MF = *(MBB.getParent());
-  const Register AddrReg = MI.getOperand(0).getReg();
   const MachineRegisterInfo &MRI = MF.getRegInfo();
   const Register Reg32 =
       MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
@@ -1855,23 +1890,27 @@ void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI) const {
 }
 
 void SystemZInstrInfo::expandMSGPseudo(MachineInstr &MI) const {
-  emitLoadStackGuardAddress(MI);
+  MachineBasicBlock* MBB = MI.getParent();
+  Register AddrReg = chooseAddrReg(MI, MBB);
+  emitLoadStackGuardAddress(MI, AddrReg);
   BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(SystemZ::MVC))
       .addReg(MI.getOperand(1).getReg())
       .addImm(MI.getOperand(2).getImm())
       .addImm(8)
-      .addReg(MI.getOperand(0).getReg())
-      .addImm(getStackGuardOffset(*(MI.getParent())));
+      .addReg(AddrReg)
+      .addImm(getStackGuardOffset(MBB));
   MI.removeFromParent();
 }
 void SystemZInstrInfo::expandCSGPseudo(MachineInstr &MI) const {
-  emitLoadStackGuardAddress(MI);
+  MachineBasicBlock* MBB = MI.getParent();
+  Register AddrReg = chooseAddrReg(MI, MBB);
+  emitLoadStackGuardAddress(MI, AddrReg);
   BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(SystemZ::CLC))
       .addReg(MI.getOperand(1).getReg())
       .addImm(MI.getOperand(2).getImm())
       .addImm(8)
-      .addReg(MI.getOperand(0).getReg())
-      .addImm(getStackGuardOffset(*(MI.getParent())));
+      .addReg(AddrReg)
+      .addImm(getStackGuardOffset(MBB));
   MI.removeFromParent();
 }
 
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
index 3b1fc9d1b77d2..a12848d3b2136 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
@@ -219,9 +219,9 @@ class SystemZInstrInfo : public SystemZGenInstrInfo {
                                        unsigned CommuteOpIdx1,
                                        unsigned CommuteOpIdx2) const override;
 
-  // Emits a load of the stack guard's address, using the DestReg
-  // of the given MI as the target.
-  void emitLoadStackGuardAddress(MachineInstr &MI) const;
+  // Emits a load of the stack guard's address, using the given
+  // AddrReg as the target.
+  void emitLoadStackGuardAddress(MachineInstr &MI, Register AddrReg) const;
 
 public:
   explicit SystemZInstrInfo(const SystemZSubtarget &STI);
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
index d1d98537c1df2..2ce8c12826e09 100644
--- a/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
@@ -118,22 +118,22 @@ define i32 @test_global_stack_guard_large() #0 {
 ; CHECK-NEXT:    .cfi_offset %r15, -40
 ; CHECK-NEXT:    aghi %r15, -8376
 ; CHECK-NEXT:    .cfi_def_cfa_offset 8536
+; CHECK-NEXT:    lay %r1, 8192(%r15)
 ; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
 ; CHECK-NEXT:    .quad .Ltmp6
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp6:
-; CHECK-NEXT:    larl %r1, __stack_chk_guard
-; CHECK-NEXT:    lay %r2, 8192(%r15)
-; CHECK-NEXT:    mvc 176(8,%r2), 0(%r1)
+; CHECK-NEXT:    larl %r2, __stack_chk_guard
+; CHECK-NEXT:    mvc 176(8,%r1), 0(%r2)
 ; CHECK-NEXT:    la %r2, 176(%r15)
 ; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    lay %r1, 8192(%r15)
 ; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
 ; CHECK-NEXT:    .quad .Ltmp7
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp7:
-; CHECK-NEXT:    larl %r1, __stack_chk_guard
-; CHECK-NEXT:    lay %r2, 8192(%r15)
-; CHECK-NEXT:    clc 176(8,%r2), 0(%r1)
+; CHECK-NEXT:    larl %r2, __stack_chk_guard
+; CHECK-NEXT:    clc 176(8,%r1), 0(%r2)
 ; CHECK-NEXT:    jlh .LBB2_2
 ; CHECK-NEXT:  # %bb.1: # %entry
 ; CHECK-NEXT:    lhi %r2, 0
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll b/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
index fe8b6a7e4214d..2ea7e4bc22202 100644
--- a/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
@@ -119,22 +119,22 @@ define i32 @test_global_stack_guard_large() #0 {
 ; CHECK-NEXT:    .cfi_offset %r15, -40
 ; CHECK-NEXT:    aghi %r15, -8376
 ; CHECK-NEXT:    .cfi_def_cfa_offset 8536
+; CHECK-NEXT:    lay %r1, 8192(%r15)
 ; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
 ; CHECK-NEXT:    .quad .Ltmp6
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp6:
-; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
-; CHECK-NEXT:    lay %r2, 8192(%r15)
-; CHECK-NEXT:    mvc 176(8,%r2), 0(%r1)
+; CHECK-NEXT:    lgrl %r2, __stack_chk_guard at GOT
+; CHECK-NEXT:    mvc 176(8,%r1), 0(%r2)
 ; CHECK-NEXT:    la %r2, 176(%r15)
 ; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    lay %r1, 8192(%r15)
 ; CHECK-NEXT:    .section __stack_protector_loc,"a", at progbits
 ; CHECK-NEXT:    .quad .Ltmp7
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp7:
-; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
-; CHECK-NEXT:    lay %r2, 8192(%r15)
-; CHECK-NEXT:    clc 176(8,%r2), 0(%r1)
+; CHECK-NEXT:    lgrl %r2, __stack_chk_guard at GOT
+; CHECK-NEXT:    clc 176(8,%r1), 0(%r2)
 ; CHECK-NEXT:    jlh .LBB2_2
 ; CHECK-NEXT:  # %bb.1: # %entry
 ; CHECK-NEXT:    lhi %r2, 0

>From 9a62ace7f35541c4f22ab1d1556e0c2ea9de72a2 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Wed, 7 Jan 2026 10:07:53 +0100
Subject: [PATCH 04/29] code formatting updates

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp |  9 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  | 89 +++++++++----------
 2 files changed, 49 insertions(+), 49 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 2eee99c4ce65f..b236ead9f1587 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -776,15 +776,17 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
     return;
 
   case SystemZ::LOAD_STACK_GUARD:
-    llvm_unreachable("LOAD_STACK_GUARD should have been eliminated by the DAG Combiner.");
+    llvm_unreachable(
+        "LOAD_STACK_GUARD should have been eliminated by the DAG Combiner.");
 
   case SystemZ::MOVE_STACK_GUARD:
   case SystemZ::COMPARE_STACK_GUARD:
-    llvm_unreachable("MOVE_STACK_GUARD and COMPARE_STACK_GUARD should have been expanded by ExpandPostRAPseudo.");
+    llvm_unreachable("MOVE_STACK_GUARD and COMPARE_STACK_GUARD should have "
+                     "been expanded by ExpandPostRAPseudo.");
 
   case SystemZ::LARL:
   case SystemZ::LGRL: {
-    auto & Op = MI->getOperand(1);
+    auto &Op = MI->getOperand(1);
     if (Op.isGlobal() && (Op.getGlobal()->getName() == "__stack_chk_guard"))
       emitStackProtectorLocEntry();
     Lower.lower(MI, LoweredMI);
@@ -808,7 +810,6 @@ void SystemZAsmPrinter::emitStackProtectorLocEntry() {
   OutStreamer->emitLabel(Sym);
 }
 
-
 // Emit the largest nop instruction smaller than or equal to NumBytes
 // bytes.  Return the size of nop emitted.
 static unsigned EmitNop(MCContext &OutContext, MCStreamer &OutStreamer,
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 8aaea18a8cc29..34939e35ffafa 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1792,27 +1792,27 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
 }
 
 namespace {
-    Register scavengeAddrReg(MachineInstr& MI, MachineBasicBlock* MBB) {
-    // create fresh RegScavanger instance.
-    RegScavenger RS;
-    // initialize RegScavenger to correct location
-    RS.enterBasicBlockEnd(*MBB);
-    RS.backward(MI);
-
-    // Attempt to find a free register.
-    Register Scratch = RS.FindUnusedReg(&SystemZ::ADDR64BitRegClass);
-    // If not found, scavenge one, i.e. evict something to a stack spill slot.
-    if (!Scratch) {
-      Scratch = RS.scavengeRegisterBackwards(
-          SystemZ::ADDR64BitRegClass,
-          MI,              // Scavenge back to this position.
-          true,  // Will need Scratch Reg after MI.
-          0,            
-          true     // Spills are allowed.
-      );
-    }
-    return Scratch;
-  }
+Register scavengeAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
+  // create fresh RegScavanger instance.
+  RegScavenger RS;
+  // initialize RegScavenger to correct location
+  RS.enterBasicBlockEnd(*MBB);
+  RS.backward(MI);
+
+  // Attempt to find a free register.
+  Register Scratch = RS.FindUnusedReg(&SystemZ::ADDR64BitRegClass);
+  // If not found, scavenge one, i.e. evict something to a stack spill slot.
+  if (!Scratch) {
+    Scratch =
+        RS.scavengeRegisterBackwards(SystemZ::ADDR64BitRegClass,
+                                     MI,   // Scavenge back to this position.
+                                     true, // Will need Scratch Reg after MI.
+                                     0,
+                                     true // Spills are allowed.
+        );
+  }
+  return Scratch;
+}
 unsigned long getStackGuardOffset(const MachineBasicBlock *MBB) {
   // In the TLS (default) case, AddrReg will contain the thread pointer, so we
   // need to add 40 bytes to get the actual address of the stack guard.
@@ -1825,7 +1825,7 @@ unsigned long getStackGuardOffset(const MachineBasicBlock *MBB) {
 // return that register. If not, scavenge a new register and return that.
 // This is a workaround for https://github.com/llvm/llvm-project/issues/172511
 // and should be removed once that issue is resolved.
-Register chooseAddrReg(MachineInstr& MI, MachineBasicBlock *MBB) {
+Register chooseAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
   Register DefReg = MI.getOperand(0).getReg();
   Register OpReg = MI.getOperand(1).getReg();
   // if we can use DefReg, return it
@@ -1838,7 +1838,8 @@ Register chooseAddrReg(MachineInstr& MI, MachineBasicBlock *MBB) {
 
 // Emit the stack guard address load, depending on guard type.
 // Return the register the stack guard address was loaded into.
-void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI, Register AddrReg) const {
+void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI,
+                                                 Register AddrReg) const {
   MachineBasicBlock &MBB = *(MI.getParent());
   const MachineFunction &MF = *(MBB.getParent());
   const MachineRegisterInfo &MRI = MF.getRegInfo();
@@ -1854,8 +1855,7 @@ void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI, Register Addr
     // the GR containing %a0 and %a1.
 
     // ear <reg>, %a0
-    BuildMI(MBB, MI, DL, get(SystemZ::EAR), Reg32)
-        .addReg(SystemZ::A0);
+    BuildMI(MBB, MI, DL, get(SystemZ::EAR), Reg32).addReg(SystemZ::A0);
 
     // sllg <reg>, <reg>, 32
     BuildMI(MBB, MI, DL, get(SystemZ::SLLG), AddrReg)
@@ -1864,8 +1864,7 @@ void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI, Register Addr
         .addImm(32);
 
     // ear <reg>, %a1
-    BuildMI(MBB, MI, DL, get(SystemZ::EAR), Reg32)
-        .addReg(SystemZ::A1);
+    BuildMI(MBB, MI, DL, get(SystemZ::EAR), Reg32).addReg(SystemZ::A1);
 
   } else if (GuardType == "global") {
     // Obtain the global value.
@@ -1890,7 +1889,7 @@ void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI, Register Addr
 }
 
 void SystemZInstrInfo::expandMSGPseudo(MachineInstr &MI) const {
-  MachineBasicBlock* MBB = MI.getParent();
+  MachineBasicBlock *MBB = MI.getParent();
   Register AddrReg = chooseAddrReg(MI, MBB);
   emitLoadStackGuardAddress(MI, AddrReg);
   BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(SystemZ::MVC))
@@ -1902,7 +1901,7 @@ void SystemZInstrInfo::expandMSGPseudo(MachineInstr &MI) const {
   MI.removeFromParent();
 }
 void SystemZInstrInfo::expandCSGPseudo(MachineInstr &MI) const {
-  MachineBasicBlock* MBB = MI.getParent();
+  MachineBasicBlock *MBB = MI.getParent();
   Register AddrReg = chooseAddrReg(MI, MBB);
   emitLoadStackGuardAddress(MI, AddrReg);
   BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(SystemZ::CLC))
@@ -1932,23 +1931,23 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     return 18 + (MI.getOperand(0).getImm() == SystemZ::CondReturn ? 4 : 0);
   if ((MI.getOpcode() == SystemZ::MOVE_STACK_GUARD) ||
       (MI.getOpcode() == SystemZ::COMPARE_STACK_GUARD)) {
-      StringRef GuardType = MI.getParent()
-      ->getParent()
-      ->getFunction()
-      .getParent()
-      ->getStackProtectorGuard();
-      unsigned Size = 6;  // mvc,clc
-      if (GuardType == "global")
-        Size += 6; // larl/lgrl
-      else if (GuardType.empty() || GuardType == "tls")
-        Size += 14; // ear,sllg,ear
-      else
-        llvm_unreachable(
+    StringRef GuardType = MI.getParent()
+                              ->getParent()
+                              ->getFunction()
+                              .getParent()
+                              ->getStackProtectorGuard();
+    unsigned Size = 6; // mvc,clc
+    if (GuardType == "global")
+      Size += 6; // larl/lgrl
+    else if (GuardType.empty() || GuardType == "tls")
+      Size += 14; // ear,sllg,ear
+    else
+      llvm_unreachable(
           (Twine("Unknown stack protector type \"") + GuardType + "\"")
-            .str()
-            .c_str());
-      return Size;
-    }
+              .str()
+              .c_str());
+    return Size;
+  }
 
   return MI.getDesc().getSize();
 }

>From 5e8fc337625d9d5011c70ad6f453b7df91048c42 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 12 Jan 2026 09:30:24 +0100
Subject: [PATCH 05/29] Cleanup, Comments, Formatting

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |  1 -
 .../Target/SystemZ/SystemZISelLowering.cpp    | 25 ++++++++++++++-----
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  |  9 ++++---
 3 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 129144867530f..39c792e7bccab 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -148,7 +148,6 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
                                      SystemZMCInstLower &Lower);
   void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
-  Register emitLoadStackGuardAddress(const MachineInstr *MI);
   void emitStackProtectorLocEntry();
   void emitAttributes(Module &M);
 };
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 5dbf1175bed7f..86f87d1563e23 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -8131,13 +8131,12 @@ SDValue SystemZTargetLowering::combineSTORE(
     }
   }
 
-  // combine STORE (LOAD_STACK_GUARD) into MOVE_STACK_GUARD
+  // combine STORE (LOAD_STACK_GUARD) into MOVE_STACK_GUARD_DAG (MSGD)
   if (Op1->isMachineOpcode() &&
       (Op1->getMachineOpcode() == SystemZ::LOAD_STACK_GUARD)) {
-    // If so, create a MOVE_STACK_GUARD_DAG node to replace the store,
-    // as well as the LOAD_STACK_GUARD.
+    // Obtain the frame index the store was targeting.
     int FI = cast<FrameIndexSDNode>(SN->getOperand(2))->getIndex();
-    // FrameIndex, Dummy Displacement
+    // Prepare operands of MSGD - FrameIndex, Dummy Displacement.
     SDValue Ops[] = {DAG.getTargetFrameIndex(FI, MVT::i64),
                      DAG.getTargetConstant(0, SDLoc(SN), MVT::i64),
                      SN->getChain()};
@@ -8967,6 +8966,13 @@ SystemZTargetLowering::getJumpConditionMergingParams(Instruction::BinaryOps Opc,
 }
 
 namespace {
+// Check if a given ICMP N node implements a check of the stack guard
+// against a stack guard instance on the stack. Specifically, this checks if:
+// - N is ICMP
+// - N has a single use
+// - N's operands are a load of the stack guard, and a load from a stack slot
+// - Those operand values are not used elsewhere <-- asserts if this is not
+// true!
 bool isStackGuardCheck(SDNode const *N, int &FI, SDValue &InChain,
                        SDValue &OutChain, SDValue &StackGuardLoad,
                        SystemZTargetLowering::DAGCombinerInfo &DCI) {
@@ -9004,9 +9010,12 @@ bool isStackGuardCheck(SDNode const *N, int &FI, SDValue &InChain,
   assert(StackGuardLoad.hasOneUse() &&
          "Value of reference stackguard must be used for compare only!");
 
+  // Update arguments passed by reference.
   FI = cast<FrameIndexSDNode>(FILoad->getOperand(1))->getIndex();
   InChain = FILoad->getChain();
   OutChain = SDValue(FILoad, 1);
+  // At this point, it's clear these nodes will be combined.
+  // Add them to the work list.
   DCI.AddToWorklist(FILoad);
   DCI.AddToWorklist(Comp.getNode());
   return true;
@@ -9486,8 +9495,6 @@ SDValue SystemZTargetLowering::PerformDAGCombine(SDNode *N,
   case SystemZISD::BR_CCMASK:   return combineBR_CCMASK(N, DCI);
   case SystemZISD::SELECT_CCMASK: return combineSELECT_CCMASK(N, DCI);
   case SystemZISD::GET_CCMASK:  return combineGET_CCMASK(N, DCI);
-  // case SystemZISD::ICMP:
-  //   return combineICMP(N, DCI);
   case ISD::SRL:
   case ISD::SRA:                return combineShiftToMulAddHigh(N, DCI);
   case ISD::MUL:                return combineMUL(N, DCI);
@@ -11156,6 +11163,9 @@ getBackchainAddress(SDValue SP, SelectionDAG &DAG) const {
                      DAG.getIntPtrConstant(TFL->getBackchainOffset(MF), DL));
 }
 
+// Turn MOVE_STACK_GUARD_DAG into MOVE_STACK_GUARD, adding
+// a dead def-reg that will be used as a scratch register
+// when this pseudo is expanded.
 MachineBasicBlock *
 SystemZTargetLowering::emitMSGPseudo(MachineInstr &MI,
                                      MachineBasicBlock *MBB) const {
@@ -11170,6 +11180,9 @@ SystemZTargetLowering::emitMSGPseudo(MachineInstr &MI,
   return MBB;
 }
 
+// Turn COMPARE_STACK_GUARD_DAG into COMPARE_STACK_GUARD, adding
+// a dead def-reg that will be used as a scratch register
+// when this pseudo is expanded.
 MachineBasicBlock *
 SystemZTargetLowering::emitCSGPseudo(MachineInstr &MI,
                                      MachineBasicBlock *MBB) const {
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 34939e35ffafa..54525d25dd87b 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1032,7 +1032,8 @@ void SystemZInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
 // and no index.  Flag is SimpleBDXLoad for loads and SimpleBDXStore for stores.
 static bool isSimpleBD12Move(const MachineInstr *MI, unsigned Flag) {
   const MCInstrDesc &MCID = MI->getDesc();
-  return ((MCID.TSFlags & Flag) && isUInt<12>(MI->getOperand(2).getImm()) &&
+  return ((MCID.TSFlags & Flag) &&
+          isUInt<12>(MI->getOperand(2).getImm()) &&
           MI->getOperand(3).getReg() == 0);
 }
 
@@ -1806,7 +1807,7 @@ Register scavengeAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
     Scratch =
         RS.scavengeRegisterBackwards(SystemZ::ADDR64BitRegClass,
                                      MI,   // Scavenge back to this position.
-                                     true, // Will need Scratch Reg after MI.
+                                     true, // Scope must include MI.
                                      0,
                                      true // Spills are allowed.
         );
@@ -1843,8 +1844,6 @@ void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI,
   MachineBasicBlock &MBB = *(MI.getParent());
   const MachineFunction &MF = *(MBB.getParent());
   const MachineRegisterInfo &MRI = MF.getRegInfo();
-  const Register Reg32 =
-      MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
   const auto DL = MI.getDebugLoc();
 
   const Module *M = MF.getFunction().getParent();
@@ -1853,6 +1852,8 @@ void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI,
   if (GuardType.empty() || (GuardType == "tls")) {
     // EAR can only load the low subregister so use a shift for %a0 to produce
     // the GR containing %a0 and %a1.
+    const Register Reg32 =
+        MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
 
     // ear <reg>, %a0
     BuildMI(MBB, MI, DL, get(SystemZ::EAR), Reg32).addReg(SystemZ::A0);

>From aab59c0dfc8d84b476ea2d84bcef2186affefcac Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Thu, 22 Jan 2026 08:58:39 +0100
Subject: [PATCH 06/29] Apply review comments

---
 ...-pseudos.c => stack-guard-global-option.c} |   7 --
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp |  81 +++++++++++--
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |   1 +
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  | 113 +++++-------------
 llvm/lib/Target/SystemZ/SystemZInstrInfo.h    |   8 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td   |  45 ++++---
 .../CodeGen/SystemZ/stack-guard-pseudos.ll    |  23 ++++
 7 files changed, 159 insertions(+), 119 deletions(-)
 rename clang/test/CodeGen/SystemZ/{stack-guard-pseudos.c => stack-guard-global-option.c} (60%)
 create mode 100644 llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll

diff --git a/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c b/clang/test/CodeGen/SystemZ/stack-guard-global-option.c
similarity index 60%
rename from clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
rename to clang/test/CodeGen/SystemZ/stack-guard-global-option.c
index ad7b8b177e106..b21d918ef72c8 100644
--- a/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
+++ b/clang/test/CodeGen/SystemZ/stack-guard-global-option.c
@@ -1,13 +1,6 @@
 // RUN: %clang_cc1 -S -mllvm -stop-after=systemz-isel -stack-protector 1 -triple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-DAGCOMBINE %s
 // RUN: %clang_cc1 -S -mllvm -stop-after=finalize-isel -stack-protector 1 -triple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-CUSTOMINSERT %s
 // RUN: not %clang_cc1 -S -stack-protector 1 -mstack-protector-guard-record -triple=s390x-ibm-linux < %s -o - 2>&1 | FileCheck -check-prefix=CHECK-OPTS %s 
-// CHECK-DAGCOMBINE:   bb.0.entry:
-// CHECK-DAGCOMBINE:     MOVE_STACK_GUARD_DAG %stack.0.StackGuardSlot, 0
-// CHECK-DAGCOMBINE:     COMPARE_STACK_GUARD_DAG %stack.0.StackGuardSlot, 0, implicit-def $cc
-// CHECK-CUSTOMINSERT: bb.0.entry
-// CHECK-CUSTOMINSERT:   early-clobber %10:addr64bit = MOVE_STACK_GUARD %stack.0.StackGuardSlot, 0
-// CHECK_CUSTOMINSERT: bb.3.entry
-// CHECK-CUSTOMINSERT: early-clobber %14:addr64bit = COMPARE_STACK_GUARD %stack.0.StackGuardSlot, 0, implicit-def $cc
 extern char *strcpy (char * D, const char * S);
 int main(int argc, char *argv[])
 {
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index b236ead9f1587..c5a5a1cab59a9 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -22,6 +22,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
 #include "llvm/IR/GlobalVariable.h"
@@ -783,15 +784,11 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   case SystemZ::COMPARE_STACK_GUARD:
     llvm_unreachable("MOVE_STACK_GUARD and COMPARE_STACK_GUARD should have "
                      "been expanded by ExpandPostRAPseudo.");
-
-  case SystemZ::LARL:
-  case SystemZ::LGRL: {
-    auto &Op = MI->getOperand(1);
-    if (Op.isGlobal() && (Op.getGlobal()->getName() == "__stack_chk_guard"))
-      emitStackProtectorLocEntry();
-    Lower.lower(MI, LoweredMI);
-    break;
-  }
+  
+  case SystemZ::LOAD_TLS_STACK_GUARD_ADDRESS:
+  case SystemZ::LOAD_GLOBAL_STACK_GUARD_ADDRESS:
+      lowerLOAD_STACK_GUARD_ADDRESS(*MI, Lower);
+      return;
 
   default:
     Lower.lower(MI, LoweredMI);
@@ -1056,6 +1053,72 @@ void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
   recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2);
 }
 
+void SystemZAsmPrinter::lowerLOAD_STACK_GUARD_ADDRESS(const MachineInstr& MI, SystemZMCInstLower& Lower) {
+  Register AddrReg = MI.getOperand(0).getReg();
+  const MachineBasicBlock &MBB = *(MI.getParent());
+  const MachineFunction &MF = *(MBB.getParent());
+  const MachineRegisterInfo &MRI = MF.getRegInfo();
+  const Module* M = MF.getFunction().getParent();
+
+  if (MI.getOpcode() == SystemZ::LOAD_TLS_STACK_GUARD_ADDRESS) {
+    // EAR can only load the low subregister so use a shift for %a0 to produce
+    // the GR containing %a0 and %a1.
+    const Register Reg32 =
+        MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
+
+    // ear <reg>, %a0
+    EmitToStreamer(*OutStreamer, 
+      MCInstBuilder(SystemZ::EAR)
+      .addReg(Reg32)
+      .addReg(SystemZ::A0)
+    );
+    
+    // sllg <reg>, <reg>, 32
+    EmitToStreamer(*OutStreamer, 
+      MCInstBuilder(SystemZ::SLLG)
+      .addReg(AddrReg)
+      .addReg(AddrReg)
+      .addReg(0)
+      .addImm(32)
+    );
+    
+    // ear <reg>, %a1
+    EmitToStreamer(*OutStreamer, 
+      MCInstBuilder(SystemZ::EAR)
+      .addReg(Reg32)
+      .addReg(SystemZ::A1)
+    );
+    return;
+  }
+  if (MI.getOpcode() == SystemZ::LOAD_GLOBAL_STACK_GUARD_ADDRESS) {
+    // Obtain the global value (assert if stack guard variable can't be found).
+    const TargetLowering* TLI = MF.getSubtarget().getTargetLowering();
+    const GlobalVariable* GV = cast<GlobalVariable>(TLI->getSDagStackGuard(*M));
+    // If configured, emit the `__stack_protector_loc` entry
+    if (MF.getFunction().hasFnAttribute("mstackprotector-guard-record"))
+      emitStackProtectorLocEntry();
+    // Emit the address load.
+    if (M->getPICLevel() == PICLevel::NotPIC) {
+      EmitToStreamer(*OutStreamer, 
+        MCInstBuilder(SystemZ::LARL)
+        .addReg(AddrReg)
+        .addExpr(MCSymbolRefExpr::create(getSymbol(GV), OutContext))
+      );
+    } else {
+      EmitToStreamer(*OutStreamer, 
+        MCInstBuilder(SystemZ::LGRL)
+        .addReg(AddrReg)
+        .addExpr(MCSymbolRefExpr::create(getSymbol(GV),
+                                            SystemZ::S_GOTENT,
+                                            OutContext))
+      );
+    }
+    return;
+  }
+
+}
+
+
 // The *alignment* of 128-bit vector types is different between the software
 // and hardware vector ABIs. If the there is an externally visible use of a
 // vector type in the module it should be annotated with an attribute.
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 39c792e7bccab..9a75019209074 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -149,6 +149,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
                                      SystemZMCInstLower &Lower);
   void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
   void emitStackProtectorLocEntry();
+  void lowerLOAD_STACK_GUARD_ADDRESS(const MachineInstr& MI, SystemZMCInstLower &Lower);
   void emitAttributes(Module &M);
 };
 } // end namespace llvm
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 54525d25dd87b..23f239212273a 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -35,6 +35,7 @@
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/CodeGen/VirtRegMap.h"
 #include "llvm/MC/MCInstBuilder.h"
+#include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCInstrDesc.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -1780,11 +1781,11 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     return true;
 
   case SystemZ::MOVE_STACK_GUARD:
-    expandMSGPseudo(MI);
+    expandStackGuardPseudo(MI, SystemZ::MVC);
     return true;
 
   case SystemZ::COMPARE_STACK_GUARD:
-    expandCSGPseudo(MI);
+    expandStackGuardPseudo(MI, SystemZ::CLC);
     return true;
 
   default:
@@ -1814,13 +1815,7 @@ Register scavengeAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
   }
   return Scratch;
 }
-unsigned long getStackGuardOffset(const MachineBasicBlock *MBB) {
-  // In the TLS (default) case, AddrReg will contain the thread pointer, so we
-  // need to add 40 bytes to get the actual address of the stack guard.
-  StringRef GuardType =
-      MBB->getParent()->getFunction().getParent()->getStackProtectorGuard();
-  return (GuardType == "global") ? 0 : 40;
-}
+
 // Check MI (which should be either MOVE_STACK_GUARD or COMPARE_STACK_GUARD)
 // to see if the early-clobber flag on the def reg was honored. If so,
 // return that register. If not, scavenge a new register and return that.
@@ -1839,78 +1834,44 @@ Register chooseAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
 
 // Emit the stack guard address load, depending on guard type.
 // Return the register the stack guard address was loaded into.
-void SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI,
+unsigned SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI,
                                                  Register AddrReg) const {
   MachineBasicBlock &MBB = *(MI.getParent());
   const MachineFunction &MF = *(MBB.getParent());
-  const MachineRegisterInfo &MRI = MF.getRegInfo();
   const auto DL = MI.getDebugLoc();
-
+  
   const Module *M = MF.getFunction().getParent();
   StringRef GuardType = M->getStackProtectorGuard();
 
   if (GuardType.empty() || (GuardType == "tls")) {
-    // EAR can only load the low subregister so use a shift for %a0 to produce
-    // the GR containing %a0 and %a1.
-    const Register Reg32 =
-        MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
-
-    // ear <reg>, %a0
-    BuildMI(MBB, MI, DL, get(SystemZ::EAR), Reg32).addReg(SystemZ::A0);
-
-    // sllg <reg>, <reg>, 32
-    BuildMI(MBB, MI, DL, get(SystemZ::SLLG), AddrReg)
-        .addReg(AddrReg)
-        .addReg(0)
-        .addImm(32);
-
-    // ear <reg>, %a1
-    BuildMI(MBB, MI, DL, get(SystemZ::EAR), Reg32).addReg(SystemZ::A1);
-
-  } else if (GuardType == "global") {
-    // Obtain the global value.
-    const auto *GV = M->getNamedGlobal("__stack_chk_guard");
-    assert(GV &&
-           "could not create reference to global variable __stack_chk_guard");
-    // Ref->
-    // Emit the address load.
-    if (M->getPICLevel() == PICLevel::NotPIC) {
-      BuildMI(MBB, MI, DL, get(SystemZ::LARL), AddrReg).addGlobalAddress(GV);
-    } else {
-      BuildMI(MBB, MI, DL, get(SystemZ::LGRL), AddrReg)
-          .addGlobalAddress(GV, 0, SystemZII::MO_GOT);
-    }
-
-  } else {
-    llvm_unreachable(
-        (Twine("Unknown stack protector type \"") + GuardType + "\"")
-            .str()
-            .c_str());
+    // emit a load of the TLS stack guard's address
+    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_TLS_STACK_GUARD_ADDRESS), AddrReg);
+    // return the appropriate stack guard offset (40 in the tls case).
+    return 40;
+  }
+  if (GuardType == "global") {
+    // emit a load of the global stack guard's address
+    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_GLOBAL_STACK_GUARD_ADDRESS), AddrReg);
+    // return the appropriate stack guard offset (0 in the global case).
+    return 0;
   }
-}
 
-void SystemZInstrInfo::expandMSGPseudo(MachineInstr &MI) const {
-  MachineBasicBlock *MBB = MI.getParent();
-  Register AddrReg = chooseAddrReg(MI, MBB);
-  emitLoadStackGuardAddress(MI, AddrReg);
-  BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(SystemZ::MVC))
-      .addReg(MI.getOperand(1).getReg())
-      .addImm(MI.getOperand(2).getImm())
-      .addImm(8)
-      .addReg(AddrReg)
-      .addImm(getStackGuardOffset(MBB));
-  MI.removeFromParent();
+  llvm_unreachable(
+      (Twine("Unknown stack protector type \"") + GuardType + "\"")
+          .str()
+          .c_str());
 }
-void SystemZInstrInfo::expandCSGPseudo(MachineInstr &MI) const {
+
+void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI, unsigned Opcode) const {
   MachineBasicBlock *MBB = MI.getParent();
   Register AddrReg = chooseAddrReg(MI, MBB);
-  emitLoadStackGuardAddress(MI, AddrReg);
-  BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(SystemZ::CLC))
+  unsigned Offset = emitLoadStackGuardAddress(MI, AddrReg);
+  BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(Opcode))
       .addReg(MI.getOperand(1).getReg())
       .addImm(MI.getOperand(2).getImm())
       .addImm(8)
       .addReg(AddrReg)
-      .addImm(getStackGuardOffset(MBB));
+      .addImm(Offset);
   MI.removeFromParent();
 }
 
@@ -1930,24 +1891,12 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     return 18;
   if (MI.getOpcode() == TargetOpcode::PATCHABLE_RET)
     return 18 + (MI.getOperand(0).getImm() == SystemZ::CondReturn ? 4 : 0);
-  if ((MI.getOpcode() == SystemZ::MOVE_STACK_GUARD) ||
-      (MI.getOpcode() == SystemZ::COMPARE_STACK_GUARD)) {
-    StringRef GuardType = MI.getParent()
-                              ->getParent()
-                              ->getFunction()
-                              .getParent()
-                              ->getStackProtectorGuard();
-    unsigned Size = 6; // mvc,clc
-    if (GuardType == "global")
-      Size += 6; // larl/lgrl
-    else if (GuardType.empty() || GuardType == "tls")
-      Size += 14; // ear,sllg,ear
-    else
-      llvm_unreachable(
-          (Twine("Unknown stack protector type \"") + GuardType + "\"")
-              .str()
-              .c_str());
-    return Size;
+  if (MI.getOpcode() == SystemZ::LOAD_TLS_STACK_GUARD_ADDRESS)
+    // ear (4), sllg (6), ear (4) = 14 bytes
+    return 14;
+  if (MI.getOpcode() == SystemZ::LOAD_GLOBAL_STACK_GUARD_ADDRESS) {
+    // both larl and lgrl are 6 bytes long.
+    return 6;
   }
 
   return MI.getDesc().getSize();
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
index a12848d3b2136..a9fc5b566c0fa 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
@@ -193,8 +193,7 @@ class SystemZInstrInfo : public SystemZGenInstrInfo {
                        unsigned HighOpcode) const;
   void expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode,
                         unsigned Size) const;
-  void expandMSGPseudo(MachineInstr &MI) const;
-  void expandCSGPseudo(MachineInstr &MI) const;
+  void expandStackGuardPseudo(MachineInstr &MI, unsigned Opcode) const;
   MachineInstrBuilder
   emitGRX32Move(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
                 const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
@@ -220,8 +219,9 @@ class SystemZInstrInfo : public SystemZGenInstrInfo {
                                        unsigned CommuteOpIdx2) const override;
 
   // Emits a load of the stack guard's address, using the given
-  // AddrReg as the target.
-  void emitLoadStackGuardAddress(MachineInstr &MI, Register AddrReg) const;
+  // AddrReg as the target. Returns the appropriate offset to load
+  // the stack guard from that address.
+  unsigned emitLoadStackGuardAddress(MachineInstr &MI, Register AddrReg) const;
 
 public:
   explicit SystemZInstrInfo(const SystemZSubtarget &STI);
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index cf81c4bdd7ed0..fe87a5a6e7d33 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -523,23 +523,34 @@ let SimpleBDXStore = 1, mayStore = 1 in {
   }
 }
 
-let hasNoSchedulingInfo = 1, hasSideEffects = 1 in {
-  let mayLoad = 1 in {
-    let mayStore = 1 in {
-      // load the stack guard's address, and move the stack guard to the stack.
-      let usesCustomInserter = 1 in def MOVE_STACK_GUARD_DAG
-          : Pseudo<(outs), (ins bdaddr12only:$grdloc), []>;
-      let Constraints = "@earlyclobber $grdaddr" in def MOVE_STACK_GUARD
-          : Pseudo<(outs ADDR64:$grdaddr), (ins bdaddr12only:$grdloc), []>;
-    }
-    let Defs = [CC] in {
-      // load the stack guard's address, and compare the stack guard against
-      // the one on the stack.
-      let usesCustomInserter = 1 in def COMPARE_STACK_GUARD_DAG
-          : Pseudo<(outs), (ins bdaddr12only:$grdloc), []>;
-      let Constraints = "@earlyclobber $grdaddr" in def COMPARE_STACK_GUARD
-          : Pseudo<(outs ADDR64:$grdaddr), (ins bdaddr12only:$grdloc), []>;
-    }
+let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
+  // load the stack guard's address
+  def LOAD_TLS_STACK_GUARD_ADDRESS : Pseudo<(outs ADDR64:$grdaddr),
+                                            (ins), []>;
+  def LOAD_GLOBAL_STACK_GUARD_ADDRESS : Pseudo<(outs ADDR64:$grdaddr),
+                                               (ins), []>;
+
+  let mayStore = 1 in {
+    // load the stack guard's address
+    // (via LOAD_[TLS|GLOBAL]STACK_GUARD_ADDRESS),
+    // and move the stack guard to the stack.
+    let usesCustomInserter = 1 in
+      def MOVE_STACK_GUARD_DAG : Pseudo<(outs),
+                                        (ins bdaddr12only:$grdloc), []>;
+    let Constraints = "@earlyclobber $grdaddr" in
+      def MOVE_STACK_GUARD : Pseudo<(outs ADDR64:$grdaddr),
+                                    (ins bdaddr12only:$grdloc), []>;
+  }
+  let Defs = [CC] in {
+    // load the stack guard's address
+    // (via LOAD_[TLS|GLOBAL]_STACK_GUARD_ADDRESS),
+    // and compare the stack guard against the one on the stack.
+    let usesCustomInserter = 1 in
+      def COMPARE_STACK_GUARD_DAG : Pseudo<(outs),
+                                           (ins bdaddr12only:$grdloc), []>;
+    let Constraints = "@earlyclobber $grdaddr" in
+      def COMPARE_STACK_GUARD : Pseudo<(outs ADDR64:$grdaddr),
+                                       (ins bdaddr12only:$grdloc), []>;
   }
 }
 
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
new file mode 100644
index 0000000000000..6a9b501cf727e
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
@@ -0,0 +1,23 @@
+; RUN: llc -stop-after=systemz-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-DAGCOMBINE %s
+; RUN: llc -stop-after=finalize-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-CUSTOMINSERT %s
+; CHECK-DAGCOMBINE:   bb.0.entry:
+; CHECK-DAGCOMBINE:     MOVE_STACK_GUARD_DAG %stack.0.StackGuardSlot, 0
+; CHECK-DAGCOMBINE:     COMPARE_STACK_GUARD_DAG %stack.0.StackGuardSlot, 0, implicit-def $cc
+; CHECK-CUSTOMINSERT: bb.0.entry
+; CHECK-CUSTOMINSERT:   early-clobber %6:addr64bit = MOVE_STACK_GUARD %stack.0.StackGuardSlot, 0
+; CHECK_CUSTOMINSERT: bb.3.entry
+; CHECK-CUSTOMINSERT: early-clobber %10:addr64bit = COMPARE_STACK_GUARD %stack.0.StackGuardSlot, 0, implicit-def $cc
+
+define dso_local signext i32 @stack_guard_pseudo_check(i32 %argc, ptr %argv) #0 {
+entry:
+  %Buffer = alloca [8 x i8], align 1
+  call void @llvm.memset.p0.i64(ptr align 1 %Buffer, i8 0, i64 8, i1 false)
+  %arraydecay = getelementptr inbounds [8 x i8], ptr %Buffer, i64 0, i64 0
+  %call = call ptr @strcpy(ptr noundef %arraydecay, ptr noundef %argv)
+  ret i32 0
+}
+
+declare void @llvm.memset.p0.i64(ptr writeonly captures(none), i8, i64, i1 immarg)
+declare ptr @strcpy(ptr noundef, ptr noundef)
+
+attributes #0 = { ssp }

>From 519f48b39240ae7e50ca9217ef5951554120d3e4 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 26 Jan 2026 13:02:05 +0100
Subject: [PATCH 07/29] Drop the DAG combine approach for
 `COMPARE_STACK_GUARD`. Instead introduce a new SystemZISD node, which
 `getCmp` can return if it decides that the comparison it is looking at is the
 one that goes into the conditional branch nto the stack guard safety block.
 To keep the names of the pseudos a bot shorter, introduce shorthand names
 (mostly using `SG` for `STACK_GUARD`. The new dag node is called
 `SystemZISD::COMPARE_SG_DAG`. This is then lowered into
 `SystemZ::COMPARE_SG_DAG`, which is then custom inserted as
 `SystemZ::COMPARE_SG`, and then finally expanded post-RA to a CLC.

---
 .../SystemZ/stack-guard-global-option.c       |   2 -
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp |  20 +--
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |   2 +-
 .../Target/SystemZ/SystemZISelDAGToDAG.cpp    |  10 ++
 .../Target/SystemZ/SystemZISelLowering.cpp    | 150 +++++++-----------
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  |  14 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td   |  12 +-
 llvm/lib/Target/SystemZ/SystemZOperators.td   |   8 +
 .../CodeGen/SystemZ/stack-guard-pseudos.ll    |   8 +-
 9 files changed, 103 insertions(+), 123 deletions(-)

diff --git a/clang/test/CodeGen/SystemZ/stack-guard-global-option.c b/clang/test/CodeGen/SystemZ/stack-guard-global-option.c
index b21d918ef72c8..c81c37b1c89eb 100644
--- a/clang/test/CodeGen/SystemZ/stack-guard-global-option.c
+++ b/clang/test/CodeGen/SystemZ/stack-guard-global-option.c
@@ -1,5 +1,3 @@
-// RUN: %clang_cc1 -S -mllvm -stop-after=systemz-isel -stack-protector 1 -triple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-DAGCOMBINE %s
-// RUN: %clang_cc1 -S -mllvm -stop-after=finalize-isel -stack-protector 1 -triple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-CUSTOMINSERT %s
 // RUN: not %clang_cc1 -S -stack-protector 1 -mstack-protector-guard-record -triple=s390x-ibm-linux < %s -o - 2>&1 | FileCheck -check-prefix=CHECK-OPTS %s 
 extern char *strcpy (char * D, const char * S);
 int main(int argc, char *argv[])
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index c5a5a1cab59a9..be21d5072bbee 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -780,14 +780,14 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
     llvm_unreachable(
         "LOAD_STACK_GUARD should have been eliminated by the DAG Combiner.");
 
-  case SystemZ::MOVE_STACK_GUARD:
-  case SystemZ::COMPARE_STACK_GUARD:
-    llvm_unreachable("MOVE_STACK_GUARD and COMPARE_STACK_GUARD should have "
+  case SystemZ::MOVE_SG:
+  case SystemZ::COMPARE_SG:
+    llvm_unreachable("MOVE_SG and COMPARE_SG should have "
                      "been expanded by ExpandPostRAPseudo.");
   
-  case SystemZ::LOAD_TLS_STACK_GUARD_ADDRESS:
-  case SystemZ::LOAD_GLOBAL_STACK_GUARD_ADDRESS:
-      lowerLOAD_STACK_GUARD_ADDRESS(*MI, Lower);
+  case SystemZ::LOAD_TSGA:
+  case SystemZ::LOAD_GSGA:
+      lowerLOAD_SGA(*MI, Lower);
       return;
 
   default:
@@ -1053,14 +1053,14 @@ void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
   recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2);
 }
 
-void SystemZAsmPrinter::lowerLOAD_STACK_GUARD_ADDRESS(const MachineInstr& MI, SystemZMCInstLower& Lower) {
+void SystemZAsmPrinter::lowerLOAD_SGA(const MachineInstr& MI, SystemZMCInstLower& Lower) {
   Register AddrReg = MI.getOperand(0).getReg();
   const MachineBasicBlock &MBB = *(MI.getParent());
   const MachineFunction &MF = *(MBB.getParent());
   const MachineRegisterInfo &MRI = MF.getRegInfo();
   const Module* M = MF.getFunction().getParent();
 
-  if (MI.getOpcode() == SystemZ::LOAD_TLS_STACK_GUARD_ADDRESS) {
+  if (MI.getOpcode() == SystemZ::LOAD_TSGA) {
     // EAR can only load the low subregister so use a shift for %a0 to produce
     // the GR containing %a0 and %a1.
     const Register Reg32 =
@@ -1090,10 +1090,10 @@ void SystemZAsmPrinter::lowerLOAD_STACK_GUARD_ADDRESS(const MachineInstr& MI, Sy
     );
     return;
   }
-  if (MI.getOpcode() == SystemZ::LOAD_GLOBAL_STACK_GUARD_ADDRESS) {
+  if (MI.getOpcode() == SystemZ::LOAD_GSGA) {
     // Obtain the global value (assert if stack guard variable can't be found).
     const TargetLowering* TLI = MF.getSubtarget().getTargetLowering();
-    const GlobalVariable* GV = cast<GlobalVariable>(TLI->getSDagStackGuard(*M));
+    const GlobalVariable* GV = cast<GlobalVariable>(TLI->getSDagStackGuard(*M, TLI->getLibcallLoweringInfo()));
     // If configured, emit the `__stack_protector_loc` entry
     if (MF.getFunction().hasFnAttribute("mstackprotector-guard-record"))
       emitStackProtectorLocEntry();
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 9a75019209074..62e405663a1de 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -149,7 +149,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
                                      SystemZMCInstLower &Lower);
   void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
   void emitStackProtectorLocEntry();
-  void lowerLOAD_STACK_GUARD_ADDRESS(const MachineInstr& MI, SystemZMCInstLower &Lower);
+  void lowerLOAD_SGA(const MachineInstr& MI, SystemZMCInstLower &Lower);
   void emitAttributes(Module &M);
 };
 } // end namespace llvm
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index fa1daa8bf8c54..9f54156ee90da 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -1806,6 +1806,16 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
     SelectCode(St);
     return;
   }
+  case SystemZISD::COMPARE_SG_DAG:
+    auto * FINode = cast<FrameIndexSDNode>(Node->getOperand(0)->getOperand(1));
+    assert (FINode && "Operand of COMPARE_SG_DAG was not load of stack slot");
+    int FI = FINode->getIndex();
+    auto DL = SDLoc(Node);
+    auto CompOps = {CurDAG->getTargetFrameIndex(FI, MVT::i64),
+                    CurDAG->getTargetConstant(0, DL, MVT::i64)};
+    MachineSDNode* Pseudo = CurDAG->getMachineNode(SystemZ::COMPARE_SG_BRIDGE, SDLoc(Node), MVT::i32, CompOps);
+    ReplaceNode(Node, Pseudo);
+    return;
   }
 
   SelectCode(Node);
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 86f87d1563e23..9fd44a986afc6 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -3546,6 +3546,45 @@ static Comparison getIntrinsicCmp(SelectionDAG &DAG, unsigned Opcode,
   return C;
 }
 
+namespace {
+  // Check if a given Compare is a check of the stack guard against a stack
+  // guard instance on the stack. Specifically, this checks if:
+  // - The operands are a load of the stack guard, and a load from a stack slot
+  // - Those operand values are not used elsewhere <-- asserts if this is not
+  //   true!
+  // This function sets ShouldSwap to true, iff a swap would put the load from
+  // the stack slot in the position 0.
+  bool isStackGuardCompare(SDValue CmpOp0, SDValue CmpOp1, bool &ShouldSwap) {
+    SDValue StackGuardLoad;
+    LoadSDNode *FILoad;
+
+    if (CmpOp0.isMachineOpcode() &&
+        CmpOp0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
+        ISD::isNormalLoad(CmpOp1.getNode()) &&
+        dyn_cast<FrameIndexSDNode>(CmpOp1.getOperand(1))) {
+      StackGuardLoad = CmpOp0;
+      FILoad = cast<LoadSDNode>(CmpOp1);
+      ShouldSwap = true;
+    } else if ((CmpOp1.isMachineOpcode() &&
+                CmpOp1.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
+                ISD::isNormalLoad(CmpOp0.getNode()) &&
+                dyn_cast<FrameIndexSDNode>(CmpOp0.getOperand(1)))) {
+      StackGuardLoad = CmpOp1;
+      FILoad = cast<LoadSDNode>(CmpOp0);
+    } else {
+      return false;
+    }
+    // Assert that the values of the loads are not used elsewhere.
+    // Bail for now. TODO: What is the proper response here?
+    assert(
+        SDValue(FILoad, 0).hasOneUse() &&
+        "Value of stackguard loaded from stack must be used for compare only!");
+    assert(StackGuardLoad.hasOneUse() &&
+          "Value of reference stackguard must be used for compare only!");
+    return true;
+  }
+} // namespace
+
 // Decide how to implement a comparison of type Cond between CmpOp0 with CmpOp1.
 static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
                          ISD::CondCode Cond, const SDLoc &DL,
@@ -3566,6 +3605,7 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
                              CmpOp1->getAsZExtVal(), Cond);
   }
   Comparison C(CmpOp0, CmpOp1, Chain);
+  bool MustSwap = false;
   C.CCMask = CCMaskForCondCode(Cond);
   if (C.Op0.getValueType().isFloatingPoint()) {
     C.CCValid = SystemZ::CCMASK_FCMP;
@@ -3576,6 +3616,11 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
     else
       C.Opcode = SystemZISD::STRICT_FCMPS;
     adjustForFNeg(C);
+  } else if (isStackGuardCompare(CmpOp0, CmpOp1, MustSwap)) {
+    // emit COMPARE_SG_DAG instead
+      C.Opcode = SystemZISD::COMPARE_SG_DAG;
+      C.CCValid = SystemZ::CCMASK_ICMP;
+      C.ICmpType = SystemZICMP::Any;
   } else {
     assert(!C.Chain);
     C.CCValid = SystemZ::CCMASK_ICMP;
@@ -3602,7 +3647,7 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
     adjustICmpTruncate(DAG, DL, C);
   }
 
-  if (shouldSwapCmpOperands(C)) {
+  if (MustSwap || shouldSwapCmpOperands(C)) {
     std::swap(C.Op0, C.Op1);
     C.CCMask = SystemZ::reverseCCMask(C.CCMask);
   }
@@ -3630,6 +3675,9 @@ static SDValue emitCmp(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) {
   if (C.Opcode == SystemZISD::ICMP)
     return DAG.getNode(SystemZISD::ICMP, DL, MVT::i32, C.Op0, C.Op1,
                        DAG.getTargetConstant(C.ICmpType, DL, MVT::i32));
+  if (C.Opcode == SystemZISD::COMPARE_SG_DAG)
+    return DAG.getNode(SystemZISD::COMPARE_SG_DAG, DL, MVT::i32, C.Op0,
+                       DAG.getTargetConstant(C.ICmpType, DL, MVT::i32));
   if (C.Opcode == SystemZISD::TM) {
     bool RegisterOnly = (bool(C.CCMask & SystemZ::CCMASK_TM_MIXED_MSB_0) !=
                          bool(C.CCMask & SystemZ::CCMASK_TM_MIXED_MSB_1));
@@ -8131,7 +8179,7 @@ SDValue SystemZTargetLowering::combineSTORE(
     }
   }
 
-  // combine STORE (LOAD_STACK_GUARD) into MOVE_STACK_GUARD_DAG (MSGD)
+  // combine STORE (LOAD_STACK_GUARD) into MOVE_SG_DAG
   if (Op1->isMachineOpcode() &&
       (Op1->getMachineOpcode() == SystemZ::LOAD_STACK_GUARD)) {
     // Obtain the frame index the store was targeting.
@@ -8140,7 +8188,7 @@ SDValue SystemZTargetLowering::combineSTORE(
     SDValue Ops[] = {DAG.getTargetFrameIndex(FI, MVT::i64),
                      DAG.getTargetConstant(0, SDLoc(SN), MVT::i64),
                      SN->getChain()};
-    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOVE_STACK_GUARD_DAG,
+    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOVE_SG_DAG,
                                              SDLoc(SN), MVT::Other, Ops);
 
     return SDValue(Move, 0);
@@ -8965,63 +9013,6 @@ SystemZTargetLowering::getJumpConditionMergingParams(Instruction::BinaryOps Opc,
   return {-1, -1, -1};
 }
 
-namespace {
-// Check if a given ICMP N node implements a check of the stack guard
-// against a stack guard instance on the stack. Specifically, this checks if:
-// - N is ICMP
-// - N has a single use
-// - N's operands are a load of the stack guard, and a load from a stack slot
-// - Those operand values are not used elsewhere <-- asserts if this is not
-// true!
-bool isStackGuardCheck(SDNode const *N, int &FI, SDValue &InChain,
-                       SDValue &OutChain, SDValue &StackGuardLoad,
-                       SystemZTargetLowering::DAGCombinerInfo &DCI) {
-  auto Comp = N->getOperand(4);
-  if (Comp->getOpcode() != SystemZISD::ICMP)
-    return false;
-
-  if (!Comp->hasOneUse())
-    return false;
-
-  SDValue LHS = Comp->getOperand(0);
-  SDValue RHS = Comp->getOperand(1);
-  LoadSDNode *FILoad;
-
-  if (LHS.isMachineOpcode() &&
-      LHS.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
-      ISD::isNormalLoad(RHS.getNode()) &&
-      dyn_cast<FrameIndexSDNode>(RHS.getOperand(1))) {
-    StackGuardLoad = LHS;
-    FILoad = cast<LoadSDNode>(RHS);
-  } else if ((RHS.isMachineOpcode() &&
-              RHS.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
-              ISD::isNormalLoad(LHS.getNode()) &&
-              dyn_cast<FrameIndexSDNode>(LHS.getOperand(1)))) {
-    StackGuardLoad = RHS;
-    FILoad = cast<LoadSDNode>(LHS);
-  } else
-    return false;
-
-  // Assert that the values of the loads are not used elsewhere.
-  // Bail for now. TODO: What is the proper response here?
-  assert(
-      SDValue(FILoad, 0).hasOneUse() &&
-      "Value of stackguard loaded from stack must be used for compare only!");
-  assert(StackGuardLoad.hasOneUse() &&
-         "Value of reference stackguard must be used for compare only!");
-
-  // Update arguments passed by reference.
-  FI = cast<FrameIndexSDNode>(FILoad->getOperand(1))->getIndex();
-  InChain = FILoad->getChain();
-  OutChain = SDValue(FILoad, 1);
-  // At this point, it's clear these nodes will be combined.
-  // Add them to the work list.
-  DCI.AddToWorklist(FILoad);
-  DCI.AddToWorklist(Comp.getNode());
-  return true;
-}
-} // namespace
-
 SDValue SystemZTargetLowering::combineBR_CCMASK(SDNode *N,
                                                 DAGCombinerInfo &DCI) const {
   SelectionDAG &DAG = DCI.DAG;
@@ -9049,33 +9040,6 @@ SDValue SystemZTargetLowering::combineBR_CCMASK(SDNode *N,
 
   SDLoc DL(N);
 
-  // Combine BR_CCMASK (ICMP (Load FI, Load StackGuard)) into BRC
-  // (COMPARE_STACK_GUARD)
-  int FI = 0;
-  SDValue InChain, OutChain, StackGuardLoad;
-  if (isStackGuardCheck(N, FI, InChain, OutChain, StackGuardLoad, DCI)) {
-    // Sanity Checks
-    assert(CCMaskVal == SystemZ::CCMASK_CMP_NE &&
-           "Unexpected branch condition in stack guard check");
-    // Handle the load's chain if necessary
-    DAG.ReplaceAllUsesOfValueWith(OutChain, InChain);
-
-    // Construct the COMPARE_STACK_GUARD_DAG to replace the icmp and
-    // LOAD_STACK_GUARD nodes.
-    SDVTList CmpVTs = DAG.getVTList(MVT::Other, MVT::Glue);
-    auto CompOps = {DAG.getTargetFrameIndex(FI, MVT::i64),
-                    DAG.getTargetConstant(0, DL, MVT::i64), InChain};
-    auto *Compare = DAG.getMachineNode(SystemZ::COMPARE_STACK_GUARD_DAG, DL,
-                                       CmpVTs, CompOps);
-    // Construct the BRC node using COMPARE_STACK_GUARD's CC result
-    auto BranchOps = {DAG.getTargetConstant(CCValidVal, DL, MVT::i32),
-                      DAG.getTargetConstant(CCMaskVal, DL, MVT::i32),
-                      N->getOperand(3), SDValue(Compare, 0),
-                      SDValue(Compare, 1)};
-    return SDValue(DAG.getMachineNode(SystemZ::BRC, DL, MVT::Other, BranchOps),
-                   0);
-  }
-
   // Combine BR_CCMASK (ICMP (SELECT_CCMASK)) into a single BR_CCMASK.
   if (combineCCMask(CCReg, CCValidVal, CCMaskVal, DAG))
     return DAG.getNode(SystemZISD::BR_CCMASK, DL, N->getValueType(0), Chain,
@@ -11163,7 +11127,7 @@ getBackchainAddress(SDValue SP, SelectionDAG &DAG) const {
                      DAG.getIntPtrConstant(TFL->getBackchainOffset(MF), DL));
 }
 
-// Turn MOVE_STACK_GUARD_DAG into MOVE_STACK_GUARD, adding
+// Turn MOVE_SG_DAG into MOVE_SG, adding
 // a dead def-reg that will be used as a scratch register
 // when this pseudo is expanded.
 MachineBasicBlock *
@@ -11173,14 +11137,14 @@ SystemZTargetLowering::emitMSGPseudo(MachineInstr &MI,
   const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
   DebugLoc DL = MI.getDebugLoc();
   Register AddrReg = MRI->createVirtualRegister(&SystemZ::ADDR64BitRegClass);
-  BuildMI(*MBB, MI, DL, TII->get(SystemZ::MOVE_STACK_GUARD), AddrReg)
+  BuildMI(*MBB, MI, DL, TII->get(SystemZ::MOVE_SG), AddrReg)
       .addFrameIndex(MI.getOperand(0).getIndex())
       .addImm(MI.getOperand(1).getImm());
   MI.eraseFromParent();
   return MBB;
 }
 
-// Turn COMPARE_STACK_GUARD_DAG into COMPARE_STACK_GUARD, adding
+// Turn COMPARE_SG_BRIDGE into COMPARE_SG, adding
 // a dead def-reg that will be used as a scratch register
 // when this pseudo is expanded.
 MachineBasicBlock *
@@ -11190,7 +11154,7 @@ SystemZTargetLowering::emitCSGPseudo(MachineInstr &MI,
   const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
   DebugLoc DL = MI.getDebugLoc();
   Register AddrReg = MRI->createVirtualRegister(&SystemZ::ADDR64BitRegClass);
-  BuildMI(*MBB, MI, DL, TII->get(SystemZ::COMPARE_STACK_GUARD), AddrReg)
+  BuildMI(*MBB, MI, DL, TII->get(SystemZ::COMPARE_SG), AddrReg)
       .addFrameIndex(MI.getOperand(0).getIndex())
       .addImm(MI.getOperand(1).getImm());
   MI.eraseFromParent();
@@ -11354,10 +11318,10 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
   case TargetOpcode::PATCHPOINT:
     return emitPatchPoint(MI, MBB);
 
-  case SystemZ::MOVE_STACK_GUARD_DAG:
+  case SystemZ::MOVE_SG_DAG:
     return emitMSGPseudo(MI, MBB);
 
-  case SystemZ::COMPARE_STACK_GUARD_DAG:
+  case SystemZ::COMPARE_SG_BRIDGE:
     return emitCSGPseudo(MI, MBB);
 
   default:
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 23f239212273a..0f0ffdf983f4e 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1780,11 +1780,11 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     splitAdjDynAlloc(MI);
     return true;
 
-  case SystemZ::MOVE_STACK_GUARD:
+  case SystemZ::MOVE_SG:
     expandStackGuardPseudo(MI, SystemZ::MVC);
     return true;
 
-  case SystemZ::COMPARE_STACK_GUARD:
+  case SystemZ::COMPARE_SG:
     expandStackGuardPseudo(MI, SystemZ::CLC);
     return true;
 
@@ -1816,7 +1816,7 @@ Register scavengeAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
   return Scratch;
 }
 
-// Check MI (which should be either MOVE_STACK_GUARD or COMPARE_STACK_GUARD)
+// Check MI (which should be either MOVE_SG or COMPARE_SG)
 // to see if the early-clobber flag on the def reg was honored. If so,
 // return that register. If not, scavenge a new register and return that.
 // This is a workaround for https://github.com/llvm/llvm-project/issues/172511
@@ -1845,13 +1845,13 @@ unsigned SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI,
 
   if (GuardType.empty() || (GuardType == "tls")) {
     // emit a load of the TLS stack guard's address
-    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_TLS_STACK_GUARD_ADDRESS), AddrReg);
+    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_TSGA), AddrReg);
     // return the appropriate stack guard offset (40 in the tls case).
     return 40;
   }
   if (GuardType == "global") {
     // emit a load of the global stack guard's address
-    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_GLOBAL_STACK_GUARD_ADDRESS), AddrReg);
+    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_GSGA), AddrReg);
     // return the appropriate stack guard offset (0 in the global case).
     return 0;
   }
@@ -1891,10 +1891,10 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     return 18;
   if (MI.getOpcode() == TargetOpcode::PATCHABLE_RET)
     return 18 + (MI.getOperand(0).getImm() == SystemZ::CondReturn ? 4 : 0);
-  if (MI.getOpcode() == SystemZ::LOAD_TLS_STACK_GUARD_ADDRESS)
+  if (MI.getOpcode() == SystemZ::LOAD_TSGA)
     // ear (4), sllg (6), ear (4) = 14 bytes
     return 14;
-  if (MI.getOpcode() == SystemZ::LOAD_GLOBAL_STACK_GUARD_ADDRESS) {
+  if (MI.getOpcode() == SystemZ::LOAD_GSGA) {
     // both larl and lgrl are 6 bytes long.
     return 6;
   }
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index fe87a5a6e7d33..e2d0c9576d44e 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -525,9 +525,9 @@ let SimpleBDXStore = 1, mayStore = 1 in {
 
 let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
   // load the stack guard's address
-  def LOAD_TLS_STACK_GUARD_ADDRESS : Pseudo<(outs ADDR64:$grdaddr),
+  def LOAD_TSGA : Pseudo<(outs ADDR64:$grdaddr),
                                             (ins), []>;
-  def LOAD_GLOBAL_STACK_GUARD_ADDRESS : Pseudo<(outs ADDR64:$grdaddr),
+  def LOAD_GSGA : Pseudo<(outs ADDR64:$grdaddr),
                                                (ins), []>;
 
   let mayStore = 1 in {
@@ -535,10 +535,10 @@ let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
     // (via LOAD_[TLS|GLOBAL]STACK_GUARD_ADDRESS),
     // and move the stack guard to the stack.
     let usesCustomInserter = 1 in
-      def MOVE_STACK_GUARD_DAG : Pseudo<(outs),
+      def MOVE_SG_DAG : Pseudo<(outs),
                                         (ins bdaddr12only:$grdloc), []>;
     let Constraints = "@earlyclobber $grdaddr" in
-      def MOVE_STACK_GUARD : Pseudo<(outs ADDR64:$grdaddr),
+      def MOVE_SG : Pseudo<(outs ADDR64:$grdaddr),
                                     (ins bdaddr12only:$grdloc), []>;
   }
   let Defs = [CC] in {
@@ -546,10 +546,10 @@ let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
     // (via LOAD_[TLS|GLOBAL]_STACK_GUARD_ADDRESS),
     // and compare the stack guard against the one on the stack.
     let usesCustomInserter = 1 in
-      def COMPARE_STACK_GUARD_DAG : Pseudo<(outs),
+      def COMPARE_SG_BRIDGE : Pseudo<(outs),
                                            (ins bdaddr12only:$grdloc), []>;
     let Constraints = "@earlyclobber $grdaddr" in
-      def COMPARE_STACK_GUARD : Pseudo<(outs ADDR64:$grdaddr),
+      def COMPARE_SG : Pseudo<(outs ADDR64:$grdaddr),
                                        (ins bdaddr12only:$grdloc), []>;
   }
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index 2a5b0435c1565..a01c696cb3d29 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -21,6 +21,10 @@ def SDT_ZICmp               : SDTypeProfile<1, 3,
                                             [SDTCisVT<0, i32>,
                                              SDTCisSameAs<1, 2>,
                                              SDTCisVT<3, i32>]>;
+def SDT_ZCSG                : SDTypeProfile<1, 2,
+                                            [SDTCisVT<0, i32>,
+                                             SDTCisPtrTy<1>,
+                                             SDTCisVT<2, i32>]>;
 def SDT_ZBRCCMask           : SDTypeProfile<0, 4,
                                             [SDTCisVT<0, i32>,
                                              SDTCisVT<1, i32>,
@@ -303,6 +307,10 @@ def z_pcrel_offset      : SDNode<"SystemZISD::PCREL_OFFSET",
 // to compare, and an integer of type SystemZICMP.
 def z_icmp              : SDNode<"SystemZISD::ICMP", SDT_ZICmp>;
 
+// A special form of icmp dedicated to comparing a stack protector value
+// to a stack slot. Kept separate to enable custom lowering.
+def z_csg              : SDNode<"SystemZISD::COMPARE_SG_DAG", SDT_ZCSG>;
+
 // Floating-point comparisons.  The two operands are the values to compare.
 def z_fcmp              : SDNode<"SystemZISD::FCMP", SDT_ZCmp>;
 
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
index 6a9b501cf727e..9e366f319af46 100644
--- a/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
@@ -1,12 +1,12 @@
 ; RUN: llc -stop-after=systemz-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-DAGCOMBINE %s
 ; RUN: llc -stop-after=finalize-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-CUSTOMINSERT %s
 ; CHECK-DAGCOMBINE:   bb.0.entry:
-; CHECK-DAGCOMBINE:     MOVE_STACK_GUARD_DAG %stack.0.StackGuardSlot, 0
-; CHECK-DAGCOMBINE:     COMPARE_STACK_GUARD_DAG %stack.0.StackGuardSlot, 0, implicit-def $cc
+; CHECK-DAGCOMBINE:     MOVE_SG_DAG %stack.0.StackGuardSlot, 0
+; CHECK-DAGCOMBINE:     COMPARE_SG_BRIDGE %stack.0.StackGuardSlot, 0, implicit-def $cc
 ; CHECK-CUSTOMINSERT: bb.0.entry
-; CHECK-CUSTOMINSERT:   early-clobber %6:addr64bit = MOVE_STACK_GUARD %stack.0.StackGuardSlot, 0
+; CHECK-CUSTOMINSERT:   early-clobber %6:addr64bit = MOVE_SG %stack.0.StackGuardSlot, 0
 ; CHECK_CUSTOMINSERT: bb.3.entry
-; CHECK-CUSTOMINSERT: early-clobber %10:addr64bit = COMPARE_STACK_GUARD %stack.0.StackGuardSlot, 0, implicit-def $cc
+; CHECK-CUSTOMINSERT: early-clobber %10:addr64bit = COMPARE_SG %stack.0.StackGuardSlot, 0, implicit-def $cc
 
 define dso_local signext i32 @stack_guard_pseudo_check(i32 %argc, ptr %argv) #0 {
 entry:

>From 37aa9121bc178e6079656bfd2cc8e84295041263 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 2 Feb 2026 15:59:37 +0100
Subject: [PATCH 08/29] Clean up Formatting

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 71 +++++++---------
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |  2 +-
 .../Target/SystemZ/SystemZISelDAGToDAG.cpp    |  7 +-
 .../Target/SystemZ/SystemZISelLowering.cpp    | 80 +++++++++----------
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  | 16 ++--
 5 files changed, 84 insertions(+), 92 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index be21d5072bbee..9c69779a08595 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -784,11 +784,11 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   case SystemZ::COMPARE_SG:
     llvm_unreachable("MOVE_SG and COMPARE_SG should have "
                      "been expanded by ExpandPostRAPseudo.");
-  
+
   case SystemZ::LOAD_TSGA:
   case SystemZ::LOAD_GSGA:
-      lowerLOAD_SGA(*MI, Lower);
-      return;
+    lowerLOAD_SGA(*MI, Lower);
+    return;
 
   default:
     Lower.lower(MI, LoweredMI);
@@ -1053,12 +1053,13 @@ void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
   recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2);
 }
 
-void SystemZAsmPrinter::lowerLOAD_SGA(const MachineInstr& MI, SystemZMCInstLower& Lower) {
+void SystemZAsmPrinter::lowerLOAD_SGA(const MachineInstr &MI,
+                                      SystemZMCInstLower &Lower) {
   Register AddrReg = MI.getOperand(0).getReg();
   const MachineBasicBlock &MBB = *(MI.getParent());
   const MachineFunction &MF = *(MBB.getParent());
   const MachineRegisterInfo &MRI = MF.getRegInfo();
-  const Module* M = MF.getFunction().getParent();
+  const Module *M = MF.getFunction().getParent();
 
   if (MI.getOpcode() == SystemZ::LOAD_TSGA) {
     // EAR can only load the low subregister so use a shift for %a0 to produce
@@ -1067,58 +1068,48 @@ void SystemZAsmPrinter::lowerLOAD_SGA(const MachineInstr& MI, SystemZMCInstLower
         MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
 
     // ear <reg>, %a0
-    EmitToStreamer(*OutStreamer, 
-      MCInstBuilder(SystemZ::EAR)
-      .addReg(Reg32)
-      .addReg(SystemZ::A0)
-    );
-    
+    EmitToStreamer(
+        *OutStreamer,
+        MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A0));
+
     // sllg <reg>, <reg>, 32
-    EmitToStreamer(*OutStreamer, 
-      MCInstBuilder(SystemZ::SLLG)
-      .addReg(AddrReg)
-      .addReg(AddrReg)
-      .addReg(0)
-      .addImm(32)
-    );
-    
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::SLLG)
+                                     .addReg(AddrReg)
+                                     .addReg(AddrReg)
+                                     .addReg(0)
+                                     .addImm(32));
+
     // ear <reg>, %a1
-    EmitToStreamer(*OutStreamer, 
-      MCInstBuilder(SystemZ::EAR)
-      .addReg(Reg32)
-      .addReg(SystemZ::A1)
-    );
+    EmitToStreamer(
+        *OutStreamer,
+        MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A1));
     return;
   }
   if (MI.getOpcode() == SystemZ::LOAD_GSGA) {
     // Obtain the global value (assert if stack guard variable can't be found).
-    const TargetLowering* TLI = MF.getSubtarget().getTargetLowering();
-    const GlobalVariable* GV = cast<GlobalVariable>(TLI->getSDagStackGuard(*M, TLI->getLibcallLoweringInfo()));
+    const TargetLowering *TLI = MF.getSubtarget().getTargetLowering();
+    const GlobalVariable *GV = cast<GlobalVariable>(
+        TLI->getSDagStackGuard(*M, TLI->getLibcallLoweringInfo()));
     // If configured, emit the `__stack_protector_loc` entry
     if (MF.getFunction().hasFnAttribute("mstackprotector-guard-record"))
       emitStackProtectorLocEntry();
     // Emit the address load.
     if (M->getPICLevel() == PICLevel::NotPIC) {
-      EmitToStreamer(*OutStreamer, 
-        MCInstBuilder(SystemZ::LARL)
-        .addReg(AddrReg)
-        .addExpr(MCSymbolRefExpr::create(getSymbol(GV), OutContext))
-      );
+      EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LARL)
+                                       .addReg(AddrReg)
+                                       .addExpr(MCSymbolRefExpr::create(
+                                           getSymbol(GV), OutContext)));
     } else {
-      EmitToStreamer(*OutStreamer, 
-        MCInstBuilder(SystemZ::LGRL)
-        .addReg(AddrReg)
-        .addExpr(MCSymbolRefExpr::create(getSymbol(GV),
-                                            SystemZ::S_GOTENT,
-                                            OutContext))
-      );
+      EmitToStreamer(*OutStreamer,
+                     MCInstBuilder(SystemZ::LGRL)
+                         .addReg(AddrReg)
+                         .addExpr(MCSymbolRefExpr::create(
+                             getSymbol(GV), SystemZ::S_GOTENT, OutContext)));
     }
     return;
   }
-
 }
 
-
 // The *alignment* of 128-bit vector types is different between the software
 // and hardware vector ABIs. If the there is an externally visible use of a
 // vector type in the module it should be annotated with an attribute.
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 62e405663a1de..0e4ac2a09aa65 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -149,7 +149,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
                                      SystemZMCInstLower &Lower);
   void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
   void emitStackProtectorLocEntry();
-  void lowerLOAD_SGA(const MachineInstr& MI, SystemZMCInstLower &Lower);
+  void lowerLOAD_SGA(const MachineInstr &MI, SystemZMCInstLower &Lower);
   void emitAttributes(Module &M);
 };
 } // end namespace llvm
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 9f54156ee90da..3100a2ab9881f 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -1807,13 +1807,14 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
     return;
   }
   case SystemZISD::COMPARE_SG_DAG:
-    auto * FINode = cast<FrameIndexSDNode>(Node->getOperand(0)->getOperand(1));
-    assert (FINode && "Operand of COMPARE_SG_DAG was not load of stack slot");
+    auto *FINode = cast<FrameIndexSDNode>(Node->getOperand(0)->getOperand(1));
+    assert(FINode && "Operand of COMPARE_SG_DAG was not load of stack slot");
     int FI = FINode->getIndex();
     auto DL = SDLoc(Node);
     auto CompOps = {CurDAG->getTargetFrameIndex(FI, MVT::i64),
                     CurDAG->getTargetConstant(0, DL, MVT::i64)};
-    MachineSDNode* Pseudo = CurDAG->getMachineNode(SystemZ::COMPARE_SG_BRIDGE, SDLoc(Node), MVT::i32, CompOps);
+    MachineSDNode *Pseudo = CurDAG->getMachineNode(
+        SystemZ::COMPARE_SG_BRIDGE, SDLoc(Node), MVT::i32, CompOps);
     ReplaceNode(Node, Pseudo);
     return;
   }
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 9fd44a986afc6..7cde7b320aa2d 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -3547,42 +3547,42 @@ static Comparison getIntrinsicCmp(SelectionDAG &DAG, unsigned Opcode,
 }
 
 namespace {
-  // Check if a given Compare is a check of the stack guard against a stack
-  // guard instance on the stack. Specifically, this checks if:
-  // - The operands are a load of the stack guard, and a load from a stack slot
-  // - Those operand values are not used elsewhere <-- asserts if this is not
-  //   true!
-  // This function sets ShouldSwap to true, iff a swap would put the load from
-  // the stack slot in the position 0.
-  bool isStackGuardCompare(SDValue CmpOp0, SDValue CmpOp1, bool &ShouldSwap) {
-    SDValue StackGuardLoad;
-    LoadSDNode *FILoad;
-
-    if (CmpOp0.isMachineOpcode() &&
-        CmpOp0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
-        ISD::isNormalLoad(CmpOp1.getNode()) &&
-        dyn_cast<FrameIndexSDNode>(CmpOp1.getOperand(1))) {
-      StackGuardLoad = CmpOp0;
-      FILoad = cast<LoadSDNode>(CmpOp1);
-      ShouldSwap = true;
-    } else if ((CmpOp1.isMachineOpcode() &&
-                CmpOp1.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
-                ISD::isNormalLoad(CmpOp0.getNode()) &&
-                dyn_cast<FrameIndexSDNode>(CmpOp0.getOperand(1)))) {
-      StackGuardLoad = CmpOp1;
-      FILoad = cast<LoadSDNode>(CmpOp0);
-    } else {
-      return false;
-    }
-    // Assert that the values of the loads are not used elsewhere.
-    // Bail for now. TODO: What is the proper response here?
-    assert(
-        SDValue(FILoad, 0).hasOneUse() &&
-        "Value of stackguard loaded from stack must be used for compare only!");
-    assert(StackGuardLoad.hasOneUse() &&
-          "Value of reference stackguard must be used for compare only!");
-    return true;
+// Check if a given Compare is a check of the stack guard against a stack
+// guard instance on the stack. Specifically, this checks if:
+// - The operands are a load of the stack guard, and a load from a stack slot
+// - Those operand values are not used elsewhere <-- asserts if this is not
+//   true!
+// This function sets ShouldSwap to true, iff a swap would put the load from
+// the stack slot in the position 0.
+bool isStackGuardCompare(SDValue CmpOp0, SDValue CmpOp1, bool &ShouldSwap) {
+  SDValue StackGuardLoad;
+  LoadSDNode *FILoad;
+
+  if (CmpOp0.isMachineOpcode() &&
+      CmpOp0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
+      ISD::isNormalLoad(CmpOp1.getNode()) &&
+      dyn_cast<FrameIndexSDNode>(CmpOp1.getOperand(1))) {
+    StackGuardLoad = CmpOp0;
+    FILoad = cast<LoadSDNode>(CmpOp1);
+    ShouldSwap = true;
+  } else if ((CmpOp1.isMachineOpcode() &&
+              CmpOp1.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
+              ISD::isNormalLoad(CmpOp0.getNode()) &&
+              dyn_cast<FrameIndexSDNode>(CmpOp0.getOperand(1)))) {
+    StackGuardLoad = CmpOp1;
+    FILoad = cast<LoadSDNode>(CmpOp0);
+  } else {
+    return false;
   }
+  // Assert that the values of the loads are not used elsewhere.
+  // Bail for now. TODO: What is the proper response here?
+  assert(
+      SDValue(FILoad, 0).hasOneUse() &&
+      "Value of stackguard loaded from stack must be used for compare only!");
+  assert(StackGuardLoad.hasOneUse() &&
+         "Value of reference stackguard must be used for compare only!");
+  return true;
+}
 } // namespace
 
 // Decide how to implement a comparison of type Cond between CmpOp0 with CmpOp1.
@@ -3618,9 +3618,9 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
     adjustForFNeg(C);
   } else if (isStackGuardCompare(CmpOp0, CmpOp1, MustSwap)) {
     // emit COMPARE_SG_DAG instead
-      C.Opcode = SystemZISD::COMPARE_SG_DAG;
-      C.CCValid = SystemZ::CCMASK_ICMP;
-      C.ICmpType = SystemZICMP::Any;
+    C.Opcode = SystemZISD::COMPARE_SG_DAG;
+    C.CCValid = SystemZ::CCMASK_ICMP;
+    C.ICmpType = SystemZICMP::Any;
   } else {
     assert(!C.Chain);
     C.CCValid = SystemZ::CCMASK_ICMP;
@@ -8188,8 +8188,8 @@ SDValue SystemZTargetLowering::combineSTORE(
     SDValue Ops[] = {DAG.getTargetFrameIndex(FI, MVT::i64),
                      DAG.getTargetConstant(0, SDLoc(SN), MVT::i64),
                      SN->getChain()};
-    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOVE_SG_DAG,
-                                             SDLoc(SN), MVT::Other, Ops);
+    MachineSDNode *Move =
+        DAG.getMachineNode(SystemZ::MOVE_SG_DAG, SDLoc(SN), MVT::Other, Ops);
 
     return SDValue(Move, 0);
   }
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 0f0ffdf983f4e..200d866b613fc 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -34,9 +34,9 @@
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/CodeGen/VirtRegMap.h"
-#include "llvm/MC/MCInstBuilder.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Module.h"
+#include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCInstrDesc.h"
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/Support/BranchProbability.h"
@@ -1835,11 +1835,11 @@ Register chooseAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
 // Emit the stack guard address load, depending on guard type.
 // Return the register the stack guard address was loaded into.
 unsigned SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI,
-                                                 Register AddrReg) const {
+                                                     Register AddrReg) const {
   MachineBasicBlock &MBB = *(MI.getParent());
   const MachineFunction &MF = *(MBB.getParent());
   const auto DL = MI.getDebugLoc();
-  
+
   const Module *M = MF.getFunction().getParent();
   StringRef GuardType = M->getStackProtectorGuard();
 
@@ -1856,13 +1856,13 @@ unsigned SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI,
     return 0;
   }
 
-  llvm_unreachable(
-      (Twine("Unknown stack protector type \"") + GuardType + "\"")
-          .str()
-          .c_str());
+  llvm_unreachable((Twine("Unknown stack protector type \"") + GuardType + "\"")
+                       .str()
+                       .c_str());
 }
 
-void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI, unsigned Opcode) const {
+void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
+                                              unsigned Opcode) const {
   MachineBasicBlock *MBB = MI.getParent();
   Register AddrReg = chooseAddrReg(MI, MBB);
   unsigned Offset = emitLoadStackGuardAddress(MI, AddrReg);

>From 4d10a26a9846c8e87a6d039283cc6f108a2af377 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Thu, 5 Feb 2026 13:06:22 +0100
Subject: [PATCH 09/29] Clarify help text

---
 clang/include/clang/Options/Options.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 7d7213130fec9..d1d0302a9d232 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5983,7 +5983,7 @@ def mstackprotector_guard_record
     : Flag<["-"], "mstack-protector-guard-record">,
       HelpText<
           "Generate a __stack_protector_loc section entry for each load of "
-          "the stackguard address.">,
+          "the stack-protector guard address.">,
       Visibility<[ClangOption, CC1Option]>,
       Group<m_Group>,
       MarshallingInfoFlag<CodeGenOpts<"StackProtectorGuardRecord">>;

>From b21f2e15025ee7687496c9d7cc1639d1fe2eb718 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Thu, 5 Feb 2026 13:09:32 +0100
Subject: [PATCH 10/29] Remove unnecessary ASMPrrinter asserts

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 9c69779a08595..6f12f3050701b 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -776,15 +776,6 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   case SystemZ::EH_SjLj_Setup:
     return;
 
-  case SystemZ::LOAD_STACK_GUARD:
-    llvm_unreachable(
-        "LOAD_STACK_GUARD should have been eliminated by the DAG Combiner.");
-
-  case SystemZ::MOVE_SG:
-  case SystemZ::COMPARE_SG:
-    llvm_unreachable("MOVE_SG and COMPARE_SG should have "
-                     "been expanded by ExpandPostRAPseudo.");
-
   case SystemZ::LOAD_TSGA:
   case SystemZ::LOAD_GSGA:
     lowerLOAD_SGA(*MI, Lower);

>From 5fdac68dc8c1e57283f02773f570d516a1c2daa7 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Thu, 5 Feb 2026 15:09:10 +0100
Subject: [PATCH 11/29] Turn stack-protector-guard-record into a module flag

---
 clang/lib/CodeGen/CodeGenFunction.cpp                 | 8 --------
 clang/lib/CodeGen/CodeGenModule.cpp                   | 8 ++++++++
 llvm/include/llvm/IR/Module.h                         | 4 ++++
 llvm/lib/IR/Module.cpp                                | 9 +++++++++
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp         | 2 +-
 llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp       | 2 +-
 llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll | 5 +++--
 llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll   | 7 ++++---
 8 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 8870149e030be..b14d9d7e8d060 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1195,14 +1195,6 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
     }
   }
 
-  if (CGM.getCodeGenOpts().StackProtectorGuardRecord) {
-    if (CGM.getCodeGenOpts().StackProtectorGuard != "global")
-      CGM.getDiags().Report(diag::err_opt_not_valid_without_opt)
-          << "-mstack-protector-guard-record"
-          << "-mstack-protector-guard=global";
-    Fn->addFnAttr("mstackprotector-guard-record");
-  }
-
   if (CGM.getCodeGenOpts().PackedStack) {
     if (getContext().getTargetInfo().getTriple().getArch() !=
         llvm::Triple::systemz)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index c31bcabe49016..546bb475195ac 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1605,6 +1605,14 @@ void CodeGenModule::Release() {
   if (getCodeGenOpts().StackProtectorGuardOffset != INT_MAX)
     getModule().setStackProtectorGuardOffset(
         getCodeGenOpts().StackProtectorGuardOffset);
+  if (getCodeGenOpts().StackProtectorGuardRecord) {
+    if (getModule().getStackProtectorGuard() != "global") {
+        Diags.Report(diag::err_opt_not_valid_without_opt)
+          << "-mstack-protector-guard-record"
+          << "-mstack-protector-guard=global";
+    }
+    getModule().setStackProtectorGuardRecord(true);
+  }
   if (getCodeGenOpts().StackAlignment)
     getModule().setOverrideStackAlignment(getCodeGenOpts().StackAlignment);
   if (getCodeGenOpts().SkipRaxSetup)
diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index 7156a83c9f3cc..d198246d36335 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -1007,6 +1007,10 @@ class LLVM_ABI Module {
   int getStackProtectorGuardOffset() const;
   void setStackProtectorGuardOffset(int Offset);
 
+  // Get/set flag indicating whether to emit a __stack_protector_loc section.
+  bool hasStackProtectorGuardRecord() const;
+  void setStackProtectorGuardRecord(bool Flag);
+
   /// Get/set the stack alignment overridden from the default.
   unsigned getOverrideStackAlignment() const;
   void setOverrideStackAlignment(unsigned Align);
diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp
index 11dc68e0e4751..da55298ba8bba 100644
--- a/llvm/lib/IR/Module.cpp
+++ b/llvm/lib/IR/Module.cpp
@@ -760,6 +760,15 @@ void Module::setFramePointer(FramePointerKind Kind) {
   addModuleFlag(ModFlagBehavior::Max, "frame-pointer", static_cast<int>(Kind));
 }
 
+bool Module::hasStackProtectorGuardRecord() const {
+  auto *Val = cast_or_null<ConstantAsMetadata>(getModuleFlag("stack-protector-guard-record"));
+  return Val && cast<ConstantInt>(Val->getValue())->isOne();
+}
+
+void Module::setStackProtectorGuardRecord(bool Flag) {
+  addModuleFlag(ModFlagBehavior::Max, "stack-protector-guard-record", Flag ? 1 : 0);
+}
+
 StringRef Module::getStackProtectorGuard() const {
   Metadata *MD = getModuleFlag("stack-protector-guard");
   if (auto *MDS = dyn_cast_or_null<MDString>(MD))
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 6f12f3050701b..0ca9b671bdacf 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1082,7 +1082,7 @@ void SystemZAsmPrinter::lowerLOAD_SGA(const MachineInstr &MI,
     const GlobalVariable *GV = cast<GlobalVariable>(
         TLI->getSDagStackGuard(*M, TLI->getLibcallLoweringInfo()));
     // If configured, emit the `__stack_protector_loc` entry
-    if (MF.getFunction().hasFnAttribute("mstackprotector-guard-record"))
+    if (M->hasStackProtectorGuardRecord())
       emitStackProtectorLocEntry();
     // Emit the address load.
     if (M->getPICLevel() == PICLevel::NotPIC) {
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 3100a2ab9881f..71cf3b356c60d 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -371,7 +371,7 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
         report_fatal_error("mrecord-mcount only supported with fentry-call");
     }
     if (F.getParent()->getStackProtectorGuard() != "global") {
-      if (F.hasFnAttribute("mstack-protector-guard-record"))
+      if (F.getParent()->hasStackProtectorGuardRecord())
         report_fatal_error("mstack-protector-guard-record only supported with "
                            "mstack-protector-guard=global");
     }
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
index 2ce8c12826e09..be9fb71ead55b 100644
--- a/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
@@ -150,8 +150,9 @@ entry:
 
 declare void @foo3(ptr)
 
-attributes #0 = { sspstrong "mstackprotector-guard-record" }
+attributes #0 = { sspstrong }
 
 
-!llvm.module.flags = !{!0}
+!llvm.module.flags = !{!0, !1}
 !0 = !{i32 1, !"stack-protector-guard", !"global"}
+!1 = !{i32 7, !"stack-protector-guard-record", i32 1}
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll b/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
index 2ea7e4bc22202..3d503b6e91e29 100644
--- a/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
@@ -153,7 +153,8 @@ declare void @foo3(ptr)
 attributes #0 = { sspstrong "mstackprotector-guard-record" }
 
 
-!llvm.module.flags = !{!0, !1, !2}
+!llvm.module.flags = !{!0, !1, !2, !3}
 !0 = !{i32 1, !"stack-protector-guard", !"global"}
-!1 = !{i32 8, !"PIC Level", i32 2}
-!2 = !{i32 7, !"PIE Level", i32 2}
+!1 = !{i32 7, !"stack-protector-guard-record", i32 1}
+!2 = !{i32 8, !"PIC Level", i32 2}
+!3 = !{i32 7, !"PIE Level", i32 2}

>From 11c6b0a7a6f8ed60a0a7563f251063a81580c785 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 9 Feb 2026 15:34:55 +0100
Subject: [PATCH 12/29] Split lowering functions for TSGA and GSGA

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 121 +++++++++---------
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |   4 +-
 2 files changed, 63 insertions(+), 62 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 0ca9b671bdacf..9ae56864da700 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -777,8 +777,10 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
     return;
 
   case SystemZ::LOAD_TSGA:
+    lowerLOAD_TSGA(*MI, Lower);
+    return;
   case SystemZ::LOAD_GSGA:
-    lowerLOAD_SGA(*MI, Lower);
+    lowerLOAD_GSGA(*MI, Lower);
     return;
 
   default:
@@ -788,16 +790,6 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   EmitToStreamer(*OutStreamer, LoweredMI);
 }
 
-void SystemZAsmPrinter::emitStackProtectorLocEntry() {
-  MCSymbol *Sym = OutContext.createTempSymbol();
-  OutStreamer->pushSection();
-  OutStreamer->switchSection(OutContext.getELFSection(
-      "__stack_protector_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC));
-  OutStreamer->emitSymbolValue(Sym, getDataLayout().getPointerSize());
-  OutStreamer->popSection();
-  OutStreamer->emitLabel(Sym);
-}
-
 // Emit the largest nop instruction smaller than or equal to NumBytes
 // bytes.  Return the size of nop emitted.
 static unsigned EmitNop(MCContext &OutContext, MCStreamer &OutStreamer,
@@ -1044,61 +1036,70 @@ void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
   recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2);
 }
 
-void SystemZAsmPrinter::lowerLOAD_SGA(const MachineInstr &MI,
+void SystemZAsmPrinter::lowerLOAD_TSGA(const MachineInstr &MI,
                                       SystemZMCInstLower &Lower) {
   Register AddrReg = MI.getOperand(0).getReg();
-  const MachineBasicBlock &MBB = *(MI.getParent());
-  const MachineFunction &MF = *(MBB.getParent());
-  const MachineRegisterInfo &MRI = MF.getRegInfo();
-  const Module *M = MF.getFunction().getParent();
-
-  if (MI.getOpcode() == SystemZ::LOAD_TSGA) {
-    // EAR can only load the low subregister so use a shift for %a0 to produce
-    // the GR containing %a0 and %a1.
-    const Register Reg32 =
-        MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
-
-    // ear <reg>, %a0
-    EmitToStreamer(
-        *OutStreamer,
-        MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A0));
+  const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
+
+  // EAR can only load the low subregister so use a shift for %a0 to produce
+  // the GR containing %a0 and %a1.
+  const Register Reg32 =
+      MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
+
+  // ear <reg>, %a0
+  EmitToStreamer(
+      *OutStreamer,
+      MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A0));
+
+  // sllg <reg>, <reg>, 32
+  EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::SLLG)
+                                    .addReg(AddrReg)
+                                    .addReg(AddrReg)
+                                    .addReg(0)
+                                    .addImm(32));
+
+  // ear <reg>, %a1
+  EmitToStreamer(
+      *OutStreamer,
+      MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A1));
+  return;
+}
 
-    // sllg <reg>, <reg>, 32
-    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::SLLG)
-                                     .addReg(AddrReg)
-                                     .addReg(AddrReg)
-                                     .addReg(0)
-                                     .addImm(32));
+void SystemZAsmPrinter::lowerLOAD_GSGA(const MachineInstr &MI,
+                                      SystemZMCInstLower &Lower) {
+  Register AddrReg = MI.getOperand(0).getReg();
+  const MachineFunction &MF = *(MI.getParent()->getParent());
+  const Module *M = MF.getFunction().getParent();
+  const TargetLowering *TLI = MF.getSubtarget().getTargetLowering();
 
-    // ear <reg>, %a1
-    EmitToStreamer(
-        *OutStreamer,
-        MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A1));
-    return;
+  // Obtain the global value (assert if stack guard variable can't be found).
+  const GlobalVariable *GV = cast<GlobalVariable>(
+      TLI->getSDagStackGuard(*M, TLI->getLibcallLoweringInfo()));
+  
+  // If configured, emit the `__stack_protector_loc` entry
+  if (M->hasStackProtectorGuardRecord()) {
+    MCSymbol *Sym = OutContext.createTempSymbol();
+    OutStreamer->pushSection();
+    OutStreamer->switchSection(OutContext.getELFSection(
+        "__stack_protector_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC));
+    OutStreamer->emitSymbolValue(Sym, getDataLayout().getPointerSize());
+    OutStreamer->popSection();
+    OutStreamer->emitLabel(Sym);
   }
-  if (MI.getOpcode() == SystemZ::LOAD_GSGA) {
-    // Obtain the global value (assert if stack guard variable can't be found).
-    const TargetLowering *TLI = MF.getSubtarget().getTargetLowering();
-    const GlobalVariable *GV = cast<GlobalVariable>(
-        TLI->getSDagStackGuard(*M, TLI->getLibcallLoweringInfo()));
-    // If configured, emit the `__stack_protector_loc` entry
-    if (M->hasStackProtectorGuardRecord())
-      emitStackProtectorLocEntry();
-    // Emit the address load.
-    if (M->getPICLevel() == PICLevel::NotPIC) {
-      EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LARL)
-                                       .addReg(AddrReg)
-                                       .addExpr(MCSymbolRefExpr::create(
-                                           getSymbol(GV), OutContext)));
-    } else {
-      EmitToStreamer(*OutStreamer,
-                     MCInstBuilder(SystemZ::LGRL)
-                         .addReg(AddrReg)
-                         .addExpr(MCSymbolRefExpr::create(
-                             getSymbol(GV), SystemZ::S_GOTENT, OutContext)));
-    }
-    return;
+  // Emit the address load.
+  if (M->getPICLevel() == PICLevel::NotPIC) {
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LARL)
+                                      .addReg(AddrReg)
+                                      .addExpr(MCSymbolRefExpr::create(
+                                          getSymbol(GV), OutContext)));
+  } else {
+    EmitToStreamer(*OutStreamer,
+                    MCInstBuilder(SystemZ::LGRL)
+                        .addReg(AddrReg)
+                        .addExpr(MCSymbolRefExpr::create(
+                            getSymbol(GV), SystemZ::S_GOTENT, OutContext)));
   }
+  return;
 }
 
 // The *alignment* of 128-bit vector types is different between the software
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 0e4ac2a09aa65..26b2f0b152ddc 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -148,8 +148,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
                                      SystemZMCInstLower &Lower);
   void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
-  void emitStackProtectorLocEntry();
-  void lowerLOAD_SGA(const MachineInstr &MI, SystemZMCInstLower &Lower);
+  void lowerLOAD_TSGA(const MachineInstr &MI, SystemZMCInstLower &Lower);
+  void lowerLOAD_GSGA(const MachineInstr &MI, SystemZMCInstLower &Lower);
   void emitAttributes(Module &M);
 };
 } // end namespace llvm

>From b91fb89b73d7764b22c8d7d48bc3073235574975 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 9 Feb 2026 15:35:32 +0100
Subject: [PATCH 13/29] inline chooseAddrReg and emitLoadStackGuardAddress

---
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp | 64 +++++++++-----------
 1 file changed, 29 insertions(+), 35 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 200d866b613fc..f18a1d6fea493 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1794,6 +1794,8 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
 }
 
 namespace {
+// This is a workaround for https://github.com/llvm/llvm-project/issues/172511
+// and should be removed once that issue is resolved.
 Register scavengeAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
   // create fresh RegScavanger instance.
   RegScavenger RS;
@@ -1815,63 +1817,55 @@ Register scavengeAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
   }
   return Scratch;
 }
-
-// Check MI (which should be either MOVE_SG or COMPARE_SG)
-// to see if the early-clobber flag on the def reg was honored. If so,
-// return that register. If not, scavenge a new register and return that.
-// This is a workaround for https://github.com/llvm/llvm-project/issues/172511
-// and should be removed once that issue is resolved.
-Register chooseAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
-  Register DefReg = MI.getOperand(0).getReg();
-  Register OpReg = MI.getOperand(1).getReg();
-  // if we can use DefReg, return it
-  if (DefReg != OpReg)
-    return DefReg;
-  // otherwise, scavenge
-  return scavengeAddrReg(MI, MBB);
-}
 } // namespace
 
-// Emit the stack guard address load, depending on guard type.
-// Return the register the stack guard address was loaded into.
-unsigned SystemZInstrInfo::emitLoadStackGuardAddress(MachineInstr &MI,
-                                                     Register AddrReg) const {
+void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
+                                              unsigned Opcode) const {
   MachineBasicBlock &MBB = *(MI.getParent());
   const MachineFunction &MF = *(MBB.getParent());
   const auto DL = MI.getDebugLoc();
-
   const Module *M = MF.getFunction().getParent();
   StringRef GuardType = M->getStackProtectorGuard();
+  unsigned int Offset = 0;
+
+  // Check MI (which should be either MOVE_SG or COMPARE_SG)
+  // to see if the early-clobber flag on the def reg was honored. If so,
+  // return that register. If not, scavenge a new register and return that.
+  // This is a workaround for https://github.com/llvm/llvm-project/issues/172511
+  // and should be removed once that issue is resolved.
+  // After this, AddrReg is set to a usable scratch register.
+  Register AddrReg = MI.getOperand(0).getReg();
+  Register OpReg = MI.getOperand(1).getReg();
+  // if we can't use AddrReg, scavenge a new one.
+  if (AddrReg == OpReg)
+    AddrReg = scavengeAddrReg(MI, &MBB);
 
+  // emit an appropriate pseudo for the guard type, which loads the address of said
+  // guard into the scratch register AddrReg.
   if (GuardType.empty() || (GuardType == "tls")) {
     // emit a load of the TLS stack guard's address
     BuildMI(MBB, MI, DL, get(SystemZ::LOAD_TSGA), AddrReg);
-    // return the appropriate stack guard offset (40 in the tls case).
-    return 40;
+    // record the appropriate stack guard offset (40 in the tls case).
+    Offset = 40;
   }
-  if (GuardType == "global") {
+  else if (GuardType == "global") {
     // emit a load of the global stack guard's address
     BuildMI(MBB, MI, DL, get(SystemZ::LOAD_GSGA), AddrReg);
-    // return the appropriate stack guard offset (0 in the global case).
-    return 0;
+  } else {
+    llvm_unreachable((Twine("Unknown stack protector type \"") + GuardType + "\"")
+                      .str()
+                      .c_str());
   }
 
-  llvm_unreachable((Twine("Unknown stack protector type \"") + GuardType + "\"")
-                       .str()
-                       .c_str());
-}
-
-void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
-                                              unsigned Opcode) const {
-  MachineBasicBlock *MBB = MI.getParent();
-  Register AddrReg = chooseAddrReg(MI, MBB);
-  unsigned Offset = emitLoadStackGuardAddress(MI, AddrReg);
+  // Construct the appropriate move or compare instruction using the
+  // scratch register.
   BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(Opcode))
       .addReg(MI.getOperand(1).getReg())
       .addImm(MI.getOperand(2).getImm())
       .addImm(8)
       .addReg(AddrReg)
       .addImm(Offset);
+
   MI.removeFromParent();
 }
 

>From 05b5270946d3aec9a090328f7616520932ec5ce1 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Wed, 11 Feb 2026 10:52:39 +0100
Subject: [PATCH 14/29] merge emitMSGPseudo and emitCSGPSeudo

---
 .../Target/SystemZ/SystemZISelLowering.cpp    | 33 ++++---------------
 llvm/lib/Target/SystemZ/SystemZISelLowering.h |  6 ++--
 2 files changed, 9 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 7cde7b320aa2d..6c22598e7ea3b 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -11127,34 +11127,15 @@ getBackchainAddress(SDValue SP, SelectionDAG &DAG) const {
                      DAG.getIntPtrConstant(TFL->getBackchainOffset(MF), DL));
 }
 
-// Turn MOVE_SG_DAG into MOVE_SG, adding
-// a dead def-reg that will be used as a scratch register
-// when this pseudo is expanded.
-MachineBasicBlock *
-SystemZTargetLowering::emitMSGPseudo(MachineInstr &MI,
-                                     MachineBasicBlock *MBB) const {
-  MachineRegisterInfo *MRI = &MBB->getParent()->getRegInfo();
-  const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
-  DebugLoc DL = MI.getDebugLoc();
-  Register AddrReg = MRI->createVirtualRegister(&SystemZ::ADDR64BitRegClass);
-  BuildMI(*MBB, MI, DL, TII->get(SystemZ::MOVE_SG), AddrReg)
-      .addFrameIndex(MI.getOperand(0).getIndex())
-      .addImm(MI.getOperand(1).getImm());
-  MI.eraseFromParent();
-  return MBB;
-}
-
-// Turn COMPARE_SG_BRIDGE into COMPARE_SG, adding
-// a dead def-reg that will be used as a scratch register
-// when this pseudo is expanded.
-MachineBasicBlock *
-SystemZTargetLowering::emitCSGPseudo(MachineInstr &MI,
-                                     MachineBasicBlock *MBB) const {
+// Replace a _SG_DAG pseudo with a _SG pseudo, adding
+// a dead early-clobber def reg that will be used as a
+// scratch register when the pseudo is expanded.
+MachineBasicBlock* SystemZTargetLowering::emitStackGuardPseudo(MachineInstr &MI, MachineBasicBlock* MBB, unsigned PseudoOp) const {
   MachineRegisterInfo *MRI = &MBB->getParent()->getRegInfo();
   const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
   DebugLoc DL = MI.getDebugLoc();
   Register AddrReg = MRI->createVirtualRegister(&SystemZ::ADDR64BitRegClass);
-  BuildMI(*MBB, MI, DL, TII->get(SystemZ::COMPARE_SG), AddrReg)
+  BuildMI(*MBB, MI, DL, TII->get(PseudoOp), AddrReg)
       .addFrameIndex(MI.getOperand(0).getIndex())
       .addImm(MI.getOperand(1).getImm());
   MI.eraseFromParent();
@@ -11319,10 +11300,10 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
     return emitPatchPoint(MI, MBB);
 
   case SystemZ::MOVE_SG_DAG:
-    return emitMSGPseudo(MI, MBB);
+    return emitStackGuardPseudo(MI, MBB, SystemZ::MOVE_SG);
 
   case SystemZ::COMPARE_SG_BRIDGE:
-    return emitCSGPseudo(MI, MBB);
+    return emitStackGuardPseudo(MI, MBB, SystemZ::COMPARE_SG);
 
   default:
     llvm_unreachable("Unexpected instr type to insert");
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index efab825b70e94..02e40067d6d1b 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -470,10 +470,8 @@ class SystemZTargetLowering : public TargetLowering {
                                          unsigned Opcode) const;
   MachineBasicBlock *emitProbedAlloca(MachineInstr &MI,
                                       MachineBasicBlock *MBB) const;
-  MachineBasicBlock *emitMSGPseudo(MachineInstr &MI,
-                                   MachineBasicBlock *MBB) const;
-  MachineBasicBlock *emitCSGPseudo(MachineInstr &MI,
-                                   MachineBasicBlock *MBB) const;
+  MachineBasicBlock *emitStackGuardPseudo(MachineInstr &MI,
+                                   MachineBasicBlock *MBB, unsigned PseudoOp) const;
   SDValue getBackchainAddress(SDValue SP, SelectionDAG &DAG) const;
 
   MachineMemOperand::Flags

>From 940d5eb751bd240289e02d1f68c67f63be00f75d Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Thu, 12 Feb 2026 14:11:25 +0100
Subject: [PATCH 15/29] rename pseudos to revert to longer names

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 12 +++++-----
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |  4 ++--
 .../Target/SystemZ/SystemZISelDAGToDAG.cpp    |  6 ++---
 .../Target/SystemZ/SystemZISelLowering.cpp    | 22 +++++++++----------
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  | 14 ++++++------
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td   | 16 +++++++-------
 llvm/lib/Target/SystemZ/SystemZOperators.td   |  2 +-
 .../CodeGen/SystemZ/stack-guard-pseudos.ll    |  8 +++----
 8 files changed, 42 insertions(+), 42 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 9ae56864da700..35db07ccb28ff 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -776,11 +776,11 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   case SystemZ::EH_SjLj_Setup:
     return;
 
-  case SystemZ::LOAD_TSGA:
-    lowerLOAD_TSGA(*MI, Lower);
+  case SystemZ::LOAD_TLS_BLOCK_ADDR:
+    lowerLOAD_TLS_BLOCK_ADDR(*MI, Lower);
     return;
-  case SystemZ::LOAD_GSGA:
-    lowerLOAD_GSGA(*MI, Lower);
+  case SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR:
+    lowerLOAD_GLOBAL_STACKGUARD_ADDR(*MI, Lower);
     return;
 
   default:
@@ -1036,7 +1036,7 @@ void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
   recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2);
 }
 
-void SystemZAsmPrinter::lowerLOAD_TSGA(const MachineInstr &MI,
+void SystemZAsmPrinter::lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
                                       SystemZMCInstLower &Lower) {
   Register AddrReg = MI.getOperand(0).getReg();
   const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
@@ -1065,7 +1065,7 @@ void SystemZAsmPrinter::lowerLOAD_TSGA(const MachineInstr &MI,
   return;
 }
 
-void SystemZAsmPrinter::lowerLOAD_GSGA(const MachineInstr &MI,
+void SystemZAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI,
                                       SystemZMCInstLower &Lower) {
   Register AddrReg = MI.getOperand(0).getReg();
   const MachineFunction &MF = *(MI.getParent()->getParent());
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 26b2f0b152ddc..e85426185119a 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -148,8 +148,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
                                      SystemZMCInstLower &Lower);
   void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
-  void lowerLOAD_TSGA(const MachineInstr &MI, SystemZMCInstLower &Lower);
-  void lowerLOAD_GSGA(const MachineInstr &MI, SystemZMCInstLower &Lower);
+  void lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI, SystemZMCInstLower &Lower);
+  void lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI, SystemZMCInstLower &Lower);
   void emitAttributes(Module &M);
 };
 } // end namespace llvm
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 71cf3b356c60d..a50492e5b57d9 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -1806,15 +1806,15 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
     SelectCode(St);
     return;
   }
-  case SystemZISD::COMPARE_SG_DAG:
+  case SystemZISD::COMPARE_STACKGUARD:
     auto *FINode = cast<FrameIndexSDNode>(Node->getOperand(0)->getOperand(1));
-    assert(FINode && "Operand of COMPARE_SG_DAG was not load of stack slot");
+    assert(FINode && "Operand of COMPARE_STACKGUARD_DAG was not load of stack slot");
     int FI = FINode->getIndex();
     auto DL = SDLoc(Node);
     auto CompOps = {CurDAG->getTargetFrameIndex(FI, MVT::i64),
                     CurDAG->getTargetConstant(0, DL, MVT::i64)};
     MachineSDNode *Pseudo = CurDAG->getMachineNode(
-        SystemZ::COMPARE_SG_BRIDGE, SDLoc(Node), MVT::i32, CompOps);
+        SystemZ::COMPARE_STACKGUARD_DAG, SDLoc(Node), MVT::i32, CompOps);
     ReplaceNode(Node, Pseudo);
     return;
   }
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 6c22598e7ea3b..48ce8b383f070 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -3617,8 +3617,8 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
       C.Opcode = SystemZISD::STRICT_FCMPS;
     adjustForFNeg(C);
   } else if (isStackGuardCompare(CmpOp0, CmpOp1, MustSwap)) {
-    // emit COMPARE_SG_DAG instead
-    C.Opcode = SystemZISD::COMPARE_SG_DAG;
+    // emit COMPARE_STACKGUARD_DAG instead
+    C.Opcode = SystemZISD::COMPARE_STACKGUARD;
     C.CCValid = SystemZ::CCMASK_ICMP;
     C.ICmpType = SystemZICMP::Any;
   } else {
@@ -3675,8 +3675,8 @@ static SDValue emitCmp(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) {
   if (C.Opcode == SystemZISD::ICMP)
     return DAG.getNode(SystemZISD::ICMP, DL, MVT::i32, C.Op0, C.Op1,
                        DAG.getTargetConstant(C.ICmpType, DL, MVT::i32));
-  if (C.Opcode == SystemZISD::COMPARE_SG_DAG)
-    return DAG.getNode(SystemZISD::COMPARE_SG_DAG, DL, MVT::i32, C.Op0,
+  if (C.Opcode == SystemZISD::COMPARE_STACKGUARD)
+    return DAG.getNode(SystemZISD::COMPARE_STACKGUARD, DL, MVT::i32, C.Op0,
                        DAG.getTargetConstant(C.ICmpType, DL, MVT::i32));
   if (C.Opcode == SystemZISD::TM) {
     bool RegisterOnly = (bool(C.CCMask & SystemZ::CCMASK_TM_MIXED_MSB_0) !=
@@ -8179,7 +8179,7 @@ SDValue SystemZTargetLowering::combineSTORE(
     }
   }
 
-  // combine STORE (LOAD_STACK_GUARD) into MOVE_SG_DAG
+  // combine STORE (LOAD_STACK_GUARD) into MOVE_STACKGUARD_DAG
   if (Op1->isMachineOpcode() &&
       (Op1->getMachineOpcode() == SystemZ::LOAD_STACK_GUARD)) {
     // Obtain the frame index the store was targeting.
@@ -8189,7 +8189,7 @@ SDValue SystemZTargetLowering::combineSTORE(
                      DAG.getTargetConstant(0, SDLoc(SN), MVT::i64),
                      SN->getChain()};
     MachineSDNode *Move =
-        DAG.getMachineNode(SystemZ::MOVE_SG_DAG, SDLoc(SN), MVT::Other, Ops);
+        DAG.getMachineNode(SystemZ::MOVE_STACKGUARD_DAG, SDLoc(SN), MVT::Other, Ops);
 
     return SDValue(Move, 0);
   }
@@ -11127,7 +11127,7 @@ getBackchainAddress(SDValue SP, SelectionDAG &DAG) const {
                      DAG.getIntPtrConstant(TFL->getBackchainOffset(MF), DL));
 }
 
-// Replace a _SG_DAG pseudo with a _SG pseudo, adding
+// Replace a _STACKGUARD_DAG pseudo with a _SG pseudo, adding
 // a dead early-clobber def reg that will be used as a
 // scratch register when the pseudo is expanded.
 MachineBasicBlock* SystemZTargetLowering::emitStackGuardPseudo(MachineInstr &MI, MachineBasicBlock* MBB, unsigned PseudoOp) const {
@@ -11299,11 +11299,11 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
   case TargetOpcode::PATCHPOINT:
     return emitPatchPoint(MI, MBB);
 
-  case SystemZ::MOVE_SG_DAG:
-    return emitStackGuardPseudo(MI, MBB, SystemZ::MOVE_SG);
+  case SystemZ::MOVE_STACKGUARD_DAG:
+    return emitStackGuardPseudo(MI, MBB, SystemZ::MOVE_STACKGUARD);
 
-  case SystemZ::COMPARE_SG_BRIDGE:
-    return emitStackGuardPseudo(MI, MBB, SystemZ::COMPARE_SG);
+  case SystemZ::COMPARE_STACKGUARD_DAG:
+    return emitStackGuardPseudo(MI, MBB, SystemZ::COMPARE_STACKGUARD);
 
   default:
     llvm_unreachable("Unexpected instr type to insert");
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index f18a1d6fea493..62283d0decbf7 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1780,11 +1780,11 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     splitAdjDynAlloc(MI);
     return true;
 
-  case SystemZ::MOVE_SG:
+  case SystemZ::MOVE_STACKGUARD:
     expandStackGuardPseudo(MI, SystemZ::MVC);
     return true;
 
-  case SystemZ::COMPARE_SG:
+  case SystemZ::COMPARE_STACKGUARD:
     expandStackGuardPseudo(MI, SystemZ::CLC);
     return true;
 
@@ -1828,7 +1828,7 @@ void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   StringRef GuardType = M->getStackProtectorGuard();
   unsigned int Offset = 0;
 
-  // Check MI (which should be either MOVE_SG or COMPARE_SG)
+  // Check MI (which should be either MOVE_STACKGUARD or COMPARE_STACKGUARD)
   // to see if the early-clobber flag on the def reg was honored. If so,
   // return that register. If not, scavenge a new register and return that.
   // This is a workaround for https://github.com/llvm/llvm-project/issues/172511
@@ -1844,13 +1844,13 @@ void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   // guard into the scratch register AddrReg.
   if (GuardType.empty() || (GuardType == "tls")) {
     // emit a load of the TLS stack guard's address
-    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_TSGA), AddrReg);
+    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_TLS_BLOCK_ADDR), AddrReg);
     // record the appropriate stack guard offset (40 in the tls case).
     Offset = 40;
   }
   else if (GuardType == "global") {
     // emit a load of the global stack guard's address
-    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_GSGA), AddrReg);
+    BuildMI(MBB, MI, DL, get(SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR), AddrReg);
   } else {
     llvm_unreachable((Twine("Unknown stack protector type \"") + GuardType + "\"")
                       .str()
@@ -1885,10 +1885,10 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     return 18;
   if (MI.getOpcode() == TargetOpcode::PATCHABLE_RET)
     return 18 + (MI.getOperand(0).getImm() == SystemZ::CondReturn ? 4 : 0);
-  if (MI.getOpcode() == SystemZ::LOAD_TSGA)
+  if (MI.getOpcode() == SystemZ::LOAD_TLS_BLOCK_ADDR)
     // ear (4), sllg (6), ear (4) = 14 bytes
     return 14;
-  if (MI.getOpcode() == SystemZ::LOAD_GSGA) {
+  if (MI.getOpcode() == SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR) {
     // both larl and lgrl are 6 bytes long.
     return 6;
   }
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index e2d0c9576d44e..5b4b90bc6625d 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -525,31 +525,31 @@ let SimpleBDXStore = 1, mayStore = 1 in {
 
 let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
   // load the stack guard's address
-  def LOAD_TSGA : Pseudo<(outs ADDR64:$grdaddr),
+  def LOAD_TLS_BLOCK_ADDR : Pseudo<(outs ADDR64:$grdaddr),
                                             (ins), []>;
-  def LOAD_GSGA : Pseudo<(outs ADDR64:$grdaddr),
+  def LOAD_GLOBAL_STACKGUARD_ADDR : Pseudo<(outs ADDR64:$grdaddr),
                                                (ins), []>;
 
   let mayStore = 1 in {
     // load the stack guard's address
-    // (via LOAD_[TLS|GLOBAL]STACK_GUARD_ADDRESS),
+    // (via LOAD_[TLS|GLOBAL]_STACKGUARD_ADDR),
     // and move the stack guard to the stack.
     let usesCustomInserter = 1 in
-      def MOVE_SG_DAG : Pseudo<(outs),
+      def MOVE_STACKGUARD_DAG : Pseudo<(outs),
                                         (ins bdaddr12only:$grdloc), []>;
     let Constraints = "@earlyclobber $grdaddr" in
-      def MOVE_SG : Pseudo<(outs ADDR64:$grdaddr),
+      def MOVE_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr),
                                     (ins bdaddr12only:$grdloc), []>;
   }
   let Defs = [CC] in {
     // load the stack guard's address
-    // (via LOAD_[TLS|GLOBAL]_STACK_GUARD_ADDRESS),
+    // (via LOAD_[TLS|GLOBAL]_STACKGUARD_ADDR),
     // and compare the stack guard against the one on the stack.
     let usesCustomInserter = 1 in
-      def COMPARE_SG_BRIDGE : Pseudo<(outs),
+      def COMPARE_STACKGUARD_DAG : Pseudo<(outs),
                                            (ins bdaddr12only:$grdloc), []>;
     let Constraints = "@earlyclobber $grdaddr" in
-      def COMPARE_SG : Pseudo<(outs ADDR64:$grdaddr),
+      def COMPARE_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr),
                                        (ins bdaddr12only:$grdloc), []>;
   }
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index a01c696cb3d29..a3044da1c4e19 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -309,7 +309,7 @@ def z_icmp              : SDNode<"SystemZISD::ICMP", SDT_ZICmp>;
 
 // A special form of icmp dedicated to comparing a stack protector value
 // to a stack slot. Kept separate to enable custom lowering.
-def z_csg              : SDNode<"SystemZISD::COMPARE_SG_DAG", SDT_ZCSG>;
+def z_csg              : SDNode<"SystemZISD::COMPARE_STACKGUARD", SDT_ZCSG>;
 
 // Floating-point comparisons.  The two operands are the values to compare.
 def z_fcmp              : SDNode<"SystemZISD::FCMP", SDT_ZCmp>;
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
index 9e366f319af46..e885e5a4d067b 100644
--- a/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
@@ -1,12 +1,12 @@
 ; RUN: llc -stop-after=systemz-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-DAGCOMBINE %s
 ; RUN: llc -stop-after=finalize-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-CUSTOMINSERT %s
 ; CHECK-DAGCOMBINE:   bb.0.entry:
-; CHECK-DAGCOMBINE:     MOVE_SG_DAG %stack.0.StackGuardSlot, 0
-; CHECK-DAGCOMBINE:     COMPARE_SG_BRIDGE %stack.0.StackGuardSlot, 0, implicit-def $cc
+; CHECK-DAGCOMBINE:     MOVE_STACKGUARD_DAG %stack.0.StackGuardSlot, 0
+; CHECK-DAGCOMBINE:     COMPARE_STACKGUARD_DAG %stack.0.StackGuardSlot, 0, implicit-def $cc
 ; CHECK-CUSTOMINSERT: bb.0.entry
-; CHECK-CUSTOMINSERT:   early-clobber %6:addr64bit = MOVE_SG %stack.0.StackGuardSlot, 0
+; CHECK-CUSTOMINSERT:   early-clobber %6:addr64bit = MOVE_STACKGUARD %stack.0.StackGuardSlot, 0
 ; CHECK_CUSTOMINSERT: bb.3.entry
-; CHECK-CUSTOMINSERT: early-clobber %10:addr64bit = COMPARE_SG %stack.0.StackGuardSlot, 0, implicit-def $cc
+; CHECK-CUSTOMINSERT: early-clobber %10:addr64bit = COMPARE_STACKGUARD %stack.0.StackGuardSlot, 0, implicit-def $cc
 
 define dso_local signext i32 @stack_guard_pseudo_check(i32 %argc, ptr %argv) #0 {
 entry:

>From 7e6171a7b9f1155d0d3b70a8f016694063ffd3b5 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Wed, 25 Feb 2026 13:34:03 +0100
Subject: [PATCH 16/29] use a pattern to select COMPARE_STACKGUARD_DAG

---
 llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp | 11 -----------
 llvm/lib/Target/SystemZ/SystemZISelLowering.cpp |  3 +--
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td     |  7 ++++++-
 llvm/lib/Target/SystemZ/SystemZOperators.td     |  5 ++---
 4 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index a50492e5b57d9..025969a81f6b7 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -1806,17 +1806,6 @@ void SystemZDAGToDAGISel::Select(SDNode *Node) {
     SelectCode(St);
     return;
   }
-  case SystemZISD::COMPARE_STACKGUARD:
-    auto *FINode = cast<FrameIndexSDNode>(Node->getOperand(0)->getOperand(1));
-    assert(FINode && "Operand of COMPARE_STACKGUARD_DAG was not load of stack slot");
-    int FI = FINode->getIndex();
-    auto DL = SDLoc(Node);
-    auto CompOps = {CurDAG->getTargetFrameIndex(FI, MVT::i64),
-                    CurDAG->getTargetConstant(0, DL, MVT::i64)};
-    MachineSDNode *Pseudo = CurDAG->getMachineNode(
-        SystemZ::COMPARE_STACKGUARD_DAG, SDLoc(Node), MVT::i32, CompOps);
-    ReplaceNode(Node, Pseudo);
-    return;
   }
 
   SelectCode(Node);
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 48ce8b383f070..f18fd829cd512 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -3676,8 +3676,7 @@ static SDValue emitCmp(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) {
     return DAG.getNode(SystemZISD::ICMP, DL, MVT::i32, C.Op0, C.Op1,
                        DAG.getTargetConstant(C.ICmpType, DL, MVT::i32));
   if (C.Opcode == SystemZISD::COMPARE_STACKGUARD)
-    return DAG.getNode(SystemZISD::COMPARE_STACKGUARD, DL, MVT::i32, C.Op0,
-                       DAG.getTargetConstant(C.ICmpType, DL, MVT::i32));
+    return DAG.getNode(SystemZISD::COMPARE_STACKGUARD, DL, MVT::i32, C.Op0);
   if (C.Opcode == SystemZISD::TM) {
     bool RegisterOnly = (bool(C.CCMask & SystemZ::CCMASK_TM_MIXED_MSB_0) !=
                          bool(C.CCMask & SystemZ::CCMASK_TM_MIXED_MSB_1));
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 5b4b90bc6625d..236ce9b1cd481 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -547,7 +547,12 @@ let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
     // and compare the stack guard against the one on the stack.
     let usesCustomInserter = 1 in
       def COMPARE_STACKGUARD_DAG : Pseudo<(outs),
-                                           (ins bdaddr12only:$grdloc), []>;
+                                           (ins bdaddr12only:$grdloc), 
+                                           [(set CC, 
+                                             (z_csg
+                                              (load bdaddr12only:$grdloc)
+                                             )
+                                            )]>;
     let Constraints = "@earlyclobber $grdaddr" in
       def COMPARE_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr),
                                        (ins bdaddr12only:$grdloc), []>;
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index a3044da1c4e19..57811563f2b6b 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -21,10 +21,9 @@ def SDT_ZICmp               : SDTypeProfile<1, 3,
                                             [SDTCisVT<0, i32>,
                                              SDTCisSameAs<1, 2>,
                                              SDTCisVT<3, i32>]>;
-def SDT_ZCSG                : SDTypeProfile<1, 2,
+def SDT_ZCSG                : SDTypeProfile<1, 1,
                                             [SDTCisVT<0, i32>,
-                                             SDTCisPtrTy<1>,
-                                             SDTCisVT<2, i32>]>;
+                                             SDTCisPtrTy<1>]>;
 def SDT_ZBRCCMask           : SDTypeProfile<0, 4,
                                             [SDTCisVT<0, i32>,
                                              SDTCisVT<1, i32>,

>From 3182eb0b708eed3c6832757a6912ee4a618fe892 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Wed, 25 Feb 2026 13:36:44 +0100
Subject: [PATCH 17/29] remove combineBR_CCMASK changes

---
 llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index f18fd829cd512..70863c2191982 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -9016,15 +9016,16 @@ SDValue SystemZTargetLowering::combineBR_CCMASK(SDNode *N,
                                                 DAGCombinerInfo &DCI) const {
   SelectionDAG &DAG = DCI.DAG;
 
+  // Combine BR_CCMASK (ICMP (SELECT_CCMASK)) into a single BR_CCMASK.
   auto *CCValid = dyn_cast<ConstantSDNode>(N->getOperand(1));
   auto *CCMask = dyn_cast<ConstantSDNode>(N->getOperand(2));
   if (!CCValid || !CCMask)
     return SDValue();
+
   int CCValidVal = CCValid->getZExtValue();
   int CCMaskVal = CCMask->getZExtValue();
   SDValue Chain = N->getOperand(0);
   SDValue CCReg = N->getOperand(4);
-
   // If combineCMask was able to merge or simplify ccvalid or ccmask, re-emit
   // the modified BR_CCMASK with the new values.
   // In order to avoid conditional branches with full or empty cc masks, do not
@@ -9036,16 +9037,6 @@ SDValue SystemZTargetLowering::combineBR_CCMASK(SDNode *N,
                        DAG.getTargetConstant(CCValidVal, SDLoc(N), MVT::i32),
                        DAG.getTargetConstant(CCMaskVal, SDLoc(N), MVT::i32),
                        N->getOperand(3), CCReg);
-
-  SDLoc DL(N);
-
-  // Combine BR_CCMASK (ICMP (SELECT_CCMASK)) into a single BR_CCMASK.
-  if (combineCCMask(CCReg, CCValidVal, CCMaskVal, DAG))
-    return DAG.getNode(SystemZISD::BR_CCMASK, DL, N->getValueType(0), Chain,
-                       DAG.getTargetConstant(CCValidVal, DL, MVT::i32),
-                       DAG.getTargetConstant(CCMaskVal, DL, MVT::i32),
-                       N->getOperand(3), CCReg);
-
   return SDValue();
 }
 

>From 99d985ab13f341e5ab551ff2d8c6ee849e5b6db9 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Wed, 25 Feb 2026 13:38:32 +0100
Subject: [PATCH 18/29] rename SDT_ZCSG

---
 llvm/lib/Target/SystemZ/SystemZOperators.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index 57811563f2b6b..9221230680f29 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -21,7 +21,7 @@ def SDT_ZICmp               : SDTypeProfile<1, 3,
                                             [SDTCisVT<0, i32>,
                                              SDTCisSameAs<1, 2>,
                                              SDTCisVT<3, i32>]>;
-def SDT_ZCSG                : SDTypeProfile<1, 1,
+def SDT_ZIcmpSG                : SDTypeProfile<1, 1,
                                             [SDTCisVT<0, i32>,
                                              SDTCisPtrTy<1>]>;
 def SDT_ZBRCCMask           : SDTypeProfile<0, 4,
@@ -308,7 +308,7 @@ def z_icmp              : SDNode<"SystemZISD::ICMP", SDT_ZICmp>;
 
 // A special form of icmp dedicated to comparing a stack protector value
 // to a stack slot. Kept separate to enable custom lowering.
-def z_csg              : SDNode<"SystemZISD::COMPARE_STACKGUARD", SDT_ZCSG>;
+def z_csg              : SDNode<"SystemZISD::COMPARE_STACKGUARD", SDT_ZIcmpSG>;
 
 // Floating-point comparisons.  The two operands are the values to compare.
 def z_fcmp              : SDNode<"SystemZISD::FCMP", SDT_ZCmp>;

>From 9555ee5753c78cfa378e45178887e3d6023ea017 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Wed, 25 Feb 2026 14:26:43 +0100
Subject: [PATCH 19/29] refactored isStackGuardCompare into
 adjustForStackGuardCompare and shouldSwapCmpOperands

---
 .../Target/SystemZ/SystemZISelLowering.cpp    | 92 +++++++++----------
 1 file changed, 46 insertions(+), 46 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 70863c2191982..31311c0cb1169 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -3040,6 +3040,12 @@ static bool isNaturalMemoryOperand(SDValue Op, unsigned ICmpType) {
 
 // Return true if it is better to swap the operands of C.
 static bool shouldSwapCmpOperands(const Comparison &C) {
+  // swap operands of COMPARE_STACK_GUARD if loading the reference value
+  // is Op0.
+  if ((C.Opcode == SystemZISD::COMPARE_STACKGUARD) && C.Op0.isMachineOpcode() &&
+      (C.Op0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD))
+      return true;
+
   // Leave i128 and f128 comparisons alone, since they have no memory forms.
   if (C.Op0.getValueType() == MVT::i128)
     return false;
@@ -3188,6 +3194,44 @@ static void adjustICmpTruncate(SelectionDAG &DAG, const SDLoc &DL,
   }
 }
 
+// Adjust if a given Compare is a check of the stack guard against a stack
+// guard instance on the stack. Specifically, this checks if:
+// - The operands are a load of the stack guard, and a load from a stack slot
+// - Those operand values are not used elsewhere <-- asserts if this is not
+//   true!
+static void adjustForStackGuardCompare(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) {
+  SDValue StackGuardLoad;
+  LoadSDNode *FILoad;
+
+  if (C.Op0.isMachineOpcode() &&
+      C.Op0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
+      ISD::isNormalLoad(C.Op1.getNode()) &&
+      dyn_cast<FrameIndexSDNode>(C.Op1.getOperand(1))) {
+    StackGuardLoad = C.Op0;
+    FILoad = cast<LoadSDNode>(C.Op1);
+  } else if ((C.Op1.isMachineOpcode() &&
+              C.Op1.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
+              ISD::isNormalLoad(C.Op0.getNode()) &&
+              dyn_cast<FrameIndexSDNode>(C.Op0.getOperand(1)))) {
+    StackGuardLoad = C.Op1;
+    FILoad = cast<LoadSDNode>(C.Op0);
+  } else {
+    return;
+  }
+  // Assert that the values of the loads are not used elsewhere.
+  // Bail for now. TODO: What is the proper response here?
+  assert(
+      SDValue(FILoad, 0).hasOneUse() &&
+      "Value of stackguard loaded from stack must be used for compare only!");
+  assert(StackGuardLoad.hasOneUse() &&
+         "Value of reference stackguard must be used for compare only!");
+
+  // At this point we are sure that this is a proper compare_stack_guard
+  // case, update the opcode to reflect this.
+  C.Opcode = SystemZISD::COMPARE_STACKGUARD;
+  C.CCValid = SystemZ::CCMASK_ICMP;
+}
+
 // Return true if shift operation N has an in-range constant shift value.
 // Store it in ShiftVal if so.
 static bool isSimpleShift(SDValue N, unsigned &ShiftVal) {
@@ -3546,45 +3590,6 @@ static Comparison getIntrinsicCmp(SelectionDAG &DAG, unsigned Opcode,
   return C;
 }
 
-namespace {
-// Check if a given Compare is a check of the stack guard against a stack
-// guard instance on the stack. Specifically, this checks if:
-// - The operands are a load of the stack guard, and a load from a stack slot
-// - Those operand values are not used elsewhere <-- asserts if this is not
-//   true!
-// This function sets ShouldSwap to true, iff a swap would put the load from
-// the stack slot in the position 0.
-bool isStackGuardCompare(SDValue CmpOp0, SDValue CmpOp1, bool &ShouldSwap) {
-  SDValue StackGuardLoad;
-  LoadSDNode *FILoad;
-
-  if (CmpOp0.isMachineOpcode() &&
-      CmpOp0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
-      ISD::isNormalLoad(CmpOp1.getNode()) &&
-      dyn_cast<FrameIndexSDNode>(CmpOp1.getOperand(1))) {
-    StackGuardLoad = CmpOp0;
-    FILoad = cast<LoadSDNode>(CmpOp1);
-    ShouldSwap = true;
-  } else if ((CmpOp1.isMachineOpcode() &&
-              CmpOp1.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
-              ISD::isNormalLoad(CmpOp0.getNode()) &&
-              dyn_cast<FrameIndexSDNode>(CmpOp0.getOperand(1)))) {
-    StackGuardLoad = CmpOp1;
-    FILoad = cast<LoadSDNode>(CmpOp0);
-  } else {
-    return false;
-  }
-  // Assert that the values of the loads are not used elsewhere.
-  // Bail for now. TODO: What is the proper response here?
-  assert(
-      SDValue(FILoad, 0).hasOneUse() &&
-      "Value of stackguard loaded from stack must be used for compare only!");
-  assert(StackGuardLoad.hasOneUse() &&
-         "Value of reference stackguard must be used for compare only!");
-  return true;
-}
-} // namespace
-
 // Decide how to implement a comparison of type Cond between CmpOp0 with CmpOp1.
 static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
                          ISD::CondCode Cond, const SDLoc &DL,
@@ -3605,7 +3610,6 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
                              CmpOp1->getAsZExtVal(), Cond);
   }
   Comparison C(CmpOp0, CmpOp1, Chain);
-  bool MustSwap = false;
   C.CCMask = CCMaskForCondCode(Cond);
   if (C.Op0.getValueType().isFloatingPoint()) {
     C.CCValid = SystemZ::CCMASK_FCMP;
@@ -3616,11 +3620,6 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
     else
       C.Opcode = SystemZISD::STRICT_FCMPS;
     adjustForFNeg(C);
-  } else if (isStackGuardCompare(CmpOp0, CmpOp1, MustSwap)) {
-    // emit COMPARE_STACKGUARD_DAG instead
-    C.Opcode = SystemZISD::COMPARE_STACKGUARD;
-    C.CCValid = SystemZ::CCMASK_ICMP;
-    C.ICmpType = SystemZICMP::Any;
   } else {
     assert(!C.Chain);
     C.CCValid = SystemZ::CCMASK_ICMP;
@@ -3639,6 +3638,7 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
     else
       C.ICmpType = SystemZICMP::SignedOnly;
     C.CCMask &= ~SystemZ::CCMASK_CMP_UO;
+    adjustForStackGuardCompare(DAG, DL, C);
     adjustForRedundantAnd(DAG, DL, C);
     adjustZeroCmp(DAG, DL, C);
     adjustSubwordCmp(DAG, DL, C);
@@ -3647,7 +3647,7 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
     adjustICmpTruncate(DAG, DL, C);
   }
 
-  if (MustSwap || shouldSwapCmpOperands(C)) {
+  if (shouldSwapCmpOperands(C)) {
     std::swap(C.Op0, C.Op1);
     C.CCMask = SystemZ::reverseCCMask(C.CCMask);
   }

>From 27ec9dfa1144270d91ef27334067c20bc9789053 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Wed, 25 Feb 2026 14:30:36 +0100
Subject: [PATCH 20/29] formatting updates

---
 clang/lib/CodeGen/CodeGenModule.cpp           |  2 +-
 llvm/lib/IR/Module.cpp                        |  6 ++-
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 40 +++++++++----------
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |  6 ++-
 .../Target/SystemZ/SystemZISelLowering.cpp    | 12 +++---
 llvm/lib/Target/SystemZ/SystemZISelLowering.h |  3 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  | 14 +++----
 7 files changed, 44 insertions(+), 39 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 546bb475195ac..ce9df1f9bb76b 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1607,7 +1607,7 @@ void CodeGenModule::Release() {
         getCodeGenOpts().StackProtectorGuardOffset);
   if (getCodeGenOpts().StackProtectorGuardRecord) {
     if (getModule().getStackProtectorGuard() != "global") {
-        Diags.Report(diag::err_opt_not_valid_without_opt)
+      Diags.Report(diag::err_opt_not_valid_without_opt)
           << "-mstack-protector-guard-record"
           << "-mstack-protector-guard=global";
     }
diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp
index da55298ba8bba..d9822bcb98a8f 100644
--- a/llvm/lib/IR/Module.cpp
+++ b/llvm/lib/IR/Module.cpp
@@ -761,12 +761,14 @@ void Module::setFramePointer(FramePointerKind Kind) {
 }
 
 bool Module::hasStackProtectorGuardRecord() const {
-  auto *Val = cast_or_null<ConstantAsMetadata>(getModuleFlag("stack-protector-guard-record"));
+  auto *Val = cast_or_null<ConstantAsMetadata>(
+      getModuleFlag("stack-protector-guard-record"));
   return Val && cast<ConstantInt>(Val->getValue())->isOne();
 }
 
 void Module::setStackProtectorGuardRecord(bool Flag) {
-  addModuleFlag(ModFlagBehavior::Max, "stack-protector-guard-record", Flag ? 1 : 0);
+  addModuleFlag(ModFlagBehavior::Max, "stack-protector-guard-record",
+                Flag ? 1 : 0);
 }
 
 StringRef Module::getStackProtectorGuard() const {
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 35db07ccb28ff..62d1e9027c587 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1037,7 +1037,7 @@ void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
 }
 
 void SystemZAsmPrinter::lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
-                                      SystemZMCInstLower &Lower) {
+                                                 SystemZMCInstLower &Lower) {
   Register AddrReg = MI.getOperand(0).getReg();
   const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
 
@@ -1047,26 +1047,24 @@ void SystemZAsmPrinter::lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
       MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
 
   // ear <reg>, %a0
-  EmitToStreamer(
-      *OutStreamer,
-      MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A0));
+  EmitToStreamer(*OutStreamer,
+                 MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A0));
 
   // sllg <reg>, <reg>, 32
   EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::SLLG)
-                                    .addReg(AddrReg)
-                                    .addReg(AddrReg)
-                                    .addReg(0)
-                                    .addImm(32));
+                                   .addReg(AddrReg)
+                                   .addReg(AddrReg)
+                                   .addReg(0)
+                                   .addImm(32));
 
   // ear <reg>, %a1
-  EmitToStreamer(
-      *OutStreamer,
-      MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A1));
+  EmitToStreamer(*OutStreamer,
+                 MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A1));
   return;
 }
 
-void SystemZAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI,
-                                      SystemZMCInstLower &Lower) {
+void SystemZAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(
+    const MachineInstr &MI, SystemZMCInstLower &Lower) {
   Register AddrReg = MI.getOperand(0).getReg();
   const MachineFunction &MF = *(MI.getParent()->getParent());
   const Module *M = MF.getFunction().getParent();
@@ -1075,7 +1073,7 @@ void SystemZAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI,
   // Obtain the global value (assert if stack guard variable can't be found).
   const GlobalVariable *GV = cast<GlobalVariable>(
       TLI->getSDagStackGuard(*M, TLI->getLibcallLoweringInfo()));
-  
+
   // If configured, emit the `__stack_protector_loc` entry
   if (M->hasStackProtectorGuardRecord()) {
     MCSymbol *Sym = OutContext.createTempSymbol();
@@ -1089,15 +1087,15 @@ void SystemZAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI,
   // Emit the address load.
   if (M->getPICLevel() == PICLevel::NotPIC) {
     EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LARL)
-                                      .addReg(AddrReg)
-                                      .addExpr(MCSymbolRefExpr::create(
-                                          getSymbol(GV), OutContext)));
+                                     .addReg(AddrReg)
+                                     .addExpr(MCSymbolRefExpr::create(
+                                         getSymbol(GV), OutContext)));
   } else {
     EmitToStreamer(*OutStreamer,
-                    MCInstBuilder(SystemZ::LGRL)
-                        .addReg(AddrReg)
-                        .addExpr(MCSymbolRefExpr::create(
-                            getSymbol(GV), SystemZ::S_GOTENT, OutContext)));
+                   MCInstBuilder(SystemZ::LGRL)
+                       .addReg(AddrReg)
+                       .addExpr(MCSymbolRefExpr::create(
+                           getSymbol(GV), SystemZ::S_GOTENT, OutContext)));
   }
   return;
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index e85426185119a..5123c176ea075 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -148,8 +148,10 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
                                      SystemZMCInstLower &Lower);
   void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
-  void lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI, SystemZMCInstLower &Lower);
-  void lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI, SystemZMCInstLower &Lower);
+  void lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
+                                SystemZMCInstLower &Lower);
+  void lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI,
+                                        SystemZMCInstLower &Lower);
   void emitAttributes(Module &M);
 };
 } // end namespace llvm
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 31311c0cb1169..997ad7c3a47f1 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -3044,7 +3044,7 @@ static bool shouldSwapCmpOperands(const Comparison &C) {
   // is Op0.
   if ((C.Opcode == SystemZISD::COMPARE_STACKGUARD) && C.Op0.isMachineOpcode() &&
       (C.Op0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD))
-      return true;
+    return true;
 
   // Leave i128 and f128 comparisons alone, since they have no memory forms.
   if (C.Op0.getValueType() == MVT::i128)
@@ -3199,7 +3199,8 @@ static void adjustICmpTruncate(SelectionDAG &DAG, const SDLoc &DL,
 // - The operands are a load of the stack guard, and a load from a stack slot
 // - Those operand values are not used elsewhere <-- asserts if this is not
 //   true!
-static void adjustForStackGuardCompare(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) {
+static void adjustForStackGuardCompare(SelectionDAG &DAG, const SDLoc &DL,
+                                       Comparison &C) {
   SDValue StackGuardLoad;
   LoadSDNode *FILoad;
 
@@ -8187,8 +8188,8 @@ SDValue SystemZTargetLowering::combineSTORE(
     SDValue Ops[] = {DAG.getTargetFrameIndex(FI, MVT::i64),
                      DAG.getTargetConstant(0, SDLoc(SN), MVT::i64),
                      SN->getChain()};
-    MachineSDNode *Move =
-        DAG.getMachineNode(SystemZ::MOVE_STACKGUARD_DAG, SDLoc(SN), MVT::Other, Ops);
+    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOVE_STACKGUARD_DAG,
+                                             SDLoc(SN), MVT::Other, Ops);
 
     return SDValue(Move, 0);
   }
@@ -11120,7 +11121,8 @@ getBackchainAddress(SDValue SP, SelectionDAG &DAG) const {
 // Replace a _STACKGUARD_DAG pseudo with a _SG pseudo, adding
 // a dead early-clobber def reg that will be used as a
 // scratch register when the pseudo is expanded.
-MachineBasicBlock* SystemZTargetLowering::emitStackGuardPseudo(MachineInstr &MI, MachineBasicBlock* MBB, unsigned PseudoOp) const {
+MachineBasicBlock *SystemZTargetLowering::emitStackGuardPseudo(
+    MachineInstr &MI, MachineBasicBlock *MBB, unsigned PseudoOp) const {
   MachineRegisterInfo *MRI = &MBB->getParent()->getRegInfo();
   const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
   DebugLoc DL = MI.getDebugLoc();
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index 02e40067d6d1b..0369fb9942a04 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -471,7 +471,8 @@ class SystemZTargetLowering : public TargetLowering {
   MachineBasicBlock *emitProbedAlloca(MachineInstr &MI,
                                       MachineBasicBlock *MBB) const;
   MachineBasicBlock *emitStackGuardPseudo(MachineInstr &MI,
-                                   MachineBasicBlock *MBB, unsigned PseudoOp) const;
+                                          MachineBasicBlock *MBB,
+                                          unsigned PseudoOp) const;
   SDValue getBackchainAddress(SDValue SP, SelectionDAG &DAG) const;
 
   MachineMemOperand::Flags
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 62283d0decbf7..d564105df3750 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1840,21 +1840,21 @@ void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   if (AddrReg == OpReg)
     AddrReg = scavengeAddrReg(MI, &MBB);
 
-  // emit an appropriate pseudo for the guard type, which loads the address of said
-  // guard into the scratch register AddrReg.
+  // emit an appropriate pseudo for the guard type, which loads the address of
+  // said guard into the scratch register AddrReg.
   if (GuardType.empty() || (GuardType == "tls")) {
     // emit a load of the TLS stack guard's address
     BuildMI(MBB, MI, DL, get(SystemZ::LOAD_TLS_BLOCK_ADDR), AddrReg);
     // record the appropriate stack guard offset (40 in the tls case).
     Offset = 40;
-  }
-  else if (GuardType == "global") {
+  } else if (GuardType == "global") {
     // emit a load of the global stack guard's address
     BuildMI(MBB, MI, DL, get(SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR), AddrReg);
   } else {
-    llvm_unreachable((Twine("Unknown stack protector type \"") + GuardType + "\"")
-                      .str()
-                      .c_str());
+    llvm_unreachable(
+        (Twine("Unknown stack protector type \"") + GuardType + "\"")
+            .str()
+            .c_str());
   }
 
   // Construct the appropriate move or compare instruction using the

>From d63c2c9b2ebacd8d79930bcf28ab4bf157d2005f Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Thu, 26 Feb 2026 16:22:50 +0100
Subject: [PATCH 21/29] add statistics

---
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index d564105df3750..5a0766c0b86dc 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -55,6 +55,8 @@ using namespace llvm;
 
 #define DEBUG_TYPE "systemz-II"
 
+STATISTIC(NumRSWorkaround, "The # of times the RegScavenger workaround for the FIE bug was triggered.");
+
 // Return a mask with Count low bits set.
 static uint64_t allOnes(unsigned int Count) {
   return Count == 0 ? 0 : (uint64_t(1) << (Count - 1) << 1) - 1;
@@ -1797,6 +1799,7 @@ namespace {
 // This is a workaround for https://github.com/llvm/llvm-project/issues/172511
 // and should be removed once that issue is resolved.
 Register scavengeAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
+  NumRSWorkaround++;
   // create fresh RegScavanger instance.
   RegScavenger RS;
   // initialize RegScavenger to correct location

>From 34c52ba991e3606ff906757ead52e6056a3945b1 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 2 Mar 2026 10:39:43 +0100
Subject: [PATCH 22/29] Formatting, nits, and naming issues

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp |  2 --
 .../Target/SystemZ/SystemZISelLowering.cpp    | 22 +++++++++---------
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  | 23 +++++++++----------
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td   | 10 ++++----
 llvm/lib/Target/SystemZ/SystemZOperators.td   |  5 ++--
 .../CodeGen/SystemZ/stack-guard-pseudos.ll    |  8 +++----
 6 files changed, 34 insertions(+), 36 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 62d1e9027c587..ef6b9d3b0e6f0 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1060,7 +1060,6 @@ void SystemZAsmPrinter::lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
   // ear <reg>, %a1
   EmitToStreamer(*OutStreamer,
                  MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A1));
-  return;
 }
 
 void SystemZAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(
@@ -1097,7 +1096,6 @@ void SystemZAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(
                        .addExpr(MCSymbolRefExpr::create(
                            getSymbol(GV), SystemZ::S_GOTENT, OutContext)));
   }
-  return;
 }
 
 // The *alignment* of 128-bit vector types is different between the software
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 997ad7c3a47f1..8d93371b47e34 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -3040,9 +3040,9 @@ static bool isNaturalMemoryOperand(SDValue Op, unsigned ICmpType) {
 
 // Return true if it is better to swap the operands of C.
 static bool shouldSwapCmpOperands(const Comparison &C) {
-  // swap operands of COMPARE_STACK_GUARD if loading the reference value
+  // swap operands of CMP_STACKGUARD_GUARD if loading the reference value
   // is Op0.
-  if ((C.Opcode == SystemZISD::COMPARE_STACKGUARD) && C.Op0.isMachineOpcode() &&
+  if ((C.Opcode == SystemZISD::CMP_STACKGUARD) && C.Op0.isMachineOpcode() &&
       (C.Op0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD))
     return true;
 
@@ -3229,7 +3229,7 @@ static void adjustForStackGuardCompare(SelectionDAG &DAG, const SDLoc &DL,
 
   // At this point we are sure that this is a proper compare_stack_guard
   // case, update the opcode to reflect this.
-  C.Opcode = SystemZISD::COMPARE_STACKGUARD;
+  C.Opcode = SystemZISD::CMP_STACKGUARD;
   C.CCValid = SystemZ::CCMASK_ICMP;
 }
 
@@ -3676,8 +3676,8 @@ static SDValue emitCmp(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) {
   if (C.Opcode == SystemZISD::ICMP)
     return DAG.getNode(SystemZISD::ICMP, DL, MVT::i32, C.Op0, C.Op1,
                        DAG.getTargetConstant(C.ICmpType, DL, MVT::i32));
-  if (C.Opcode == SystemZISD::COMPARE_STACKGUARD)
-    return DAG.getNode(SystemZISD::COMPARE_STACKGUARD, DL, MVT::i32, C.Op0);
+  if (C.Opcode == SystemZISD::CMP_STACKGUARD)
+    return DAG.getNode(SystemZISD::CMP_STACKGUARD, DL, MVT::i32, C.Op0);
   if (C.Opcode == SystemZISD::TM) {
     bool RegisterOnly = (bool(C.CCMask & SystemZ::CCMASK_TM_MIXED_MSB_0) !=
                          bool(C.CCMask & SystemZ::CCMASK_TM_MIXED_MSB_1));
@@ -8179,7 +8179,7 @@ SDValue SystemZTargetLowering::combineSTORE(
     }
   }
 
-  // combine STORE (LOAD_STACK_GUARD) into MOVE_STACKGUARD_DAG
+  // combine STORE (LOAD_STACK_GUARD) into MOV_STACKGUARD_DAG
   if (Op1->isMachineOpcode() &&
       (Op1->getMachineOpcode() == SystemZ::LOAD_STACK_GUARD)) {
     // Obtain the frame index the store was targeting.
@@ -8188,7 +8188,7 @@ SDValue SystemZTargetLowering::combineSTORE(
     SDValue Ops[] = {DAG.getTargetFrameIndex(FI, MVT::i64),
                      DAG.getTargetConstant(0, SDLoc(SN), MVT::i64),
                      SN->getChain()};
-    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOVE_STACKGUARD_DAG,
+    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOV_STACKGUARD_DAG,
                                              SDLoc(SN), MVT::Other, Ops);
 
     return SDValue(Move, 0);
@@ -11291,11 +11291,11 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
   case TargetOpcode::PATCHPOINT:
     return emitPatchPoint(MI, MBB);
 
-  case SystemZ::MOVE_STACKGUARD_DAG:
-    return emitStackGuardPseudo(MI, MBB, SystemZ::MOVE_STACKGUARD);
+  case SystemZ::MOV_STACKGUARD_DAG:
+    return emitStackGuardPseudo(MI, MBB, SystemZ::MOV_STACKGUARD);
 
-  case SystemZ::COMPARE_STACKGUARD_DAG:
-    return emitStackGuardPseudo(MI, MBB, SystemZ::COMPARE_STACKGUARD);
+  case SystemZ::CMP_STACKGUARD_DAG:
+    return emitStackGuardPseudo(MI, MBB, SystemZ::CMP_STACKGUARD);
 
   default:
     llvm_unreachable("Unexpected instr type to insert");
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 5a0766c0b86dc..5a9d107f6bb87 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1782,11 +1782,11 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     splitAdjDynAlloc(MI);
     return true;
 
-  case SystemZ::MOVE_STACKGUARD:
+  case SystemZ::MOV_STACKGUARD:
     expandStackGuardPseudo(MI, SystemZ::MVC);
     return true;
 
-  case SystemZ::COMPARE_STACKGUARD:
+  case SystemZ::CMP_STACKGUARD:
     expandStackGuardPseudo(MI, SystemZ::CLC);
     return true;
 
@@ -1831,7 +1831,7 @@ void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   StringRef GuardType = M->getStackProtectorGuard();
   unsigned int Offset = 0;
 
-  // Check MI (which should be either MOVE_STACKGUARD or COMPARE_STACKGUARD)
+  // Check MI (which should be either MOV_STACKGUARD or CMP_STACKGUARD)
   // to see if the early-clobber flag on the def reg was honored. If so,
   // return that register. If not, scavenge a new register and return that.
   // This is a workaround for https://github.com/llvm/llvm-project/issues/172511
@@ -1843,19 +1843,19 @@ void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   if (AddrReg == OpReg)
     AddrReg = scavengeAddrReg(MI, &MBB);
 
-  // emit an appropriate pseudo for the guard type, which loads the address of
+  // Emit an appropriate pseudo for the guard type, which loads the address of
   // said guard into the scratch register AddrReg.
   if (GuardType.empty() || (GuardType == "tls")) {
-    // emit a load of the TLS stack guard's address
+    // Emit a load of the TLS block's address
     BuildMI(MBB, MI, DL, get(SystemZ::LOAD_TLS_BLOCK_ADDR), AddrReg);
-    // record the appropriate stack guard offset (40 in the tls case).
+    // Record the appropriate stack guard offset (40 in the tls case).
     Offset = 40;
   } else if (GuardType == "global") {
-    // emit a load of the global stack guard's address
+    // Emit a load of the global stack guard's address
     BuildMI(MBB, MI, DL, get(SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR), AddrReg);
   } else {
-    llvm_unreachable(
-        (Twine("Unknown stack protector type \"") + GuardType + "\"")
+    report_fatal_error(
+        (Twine("unknown stack protector type \"") + GuardType + "\".")
             .str()
             .c_str());
   }
@@ -1891,10 +1891,9 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
   if (MI.getOpcode() == SystemZ::LOAD_TLS_BLOCK_ADDR)
     // ear (4), sllg (6), ear (4) = 14 bytes
     return 14;
-  if (MI.getOpcode() == SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR) {
-    // both larl and lgrl are 6 bytes long.
+  if (MI.getOpcode() == SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR)
+    // Both larl and lgrl are 6 bytes long.
     return 6;
-  }
 
   return MI.getDesc().getSize();
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 236ce9b1cd481..9de4427bdca3d 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -535,10 +535,10 @@ let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
     // (via LOAD_[TLS|GLOBAL]_STACKGUARD_ADDR),
     // and move the stack guard to the stack.
     let usesCustomInserter = 1 in
-      def MOVE_STACKGUARD_DAG : Pseudo<(outs),
+      def MOV_STACKGUARD_DAG : Pseudo<(outs),
                                         (ins bdaddr12only:$grdloc), []>;
     let Constraints = "@earlyclobber $grdaddr" in
-      def MOVE_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr),
+      def MOV_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr),
                                     (ins bdaddr12only:$grdloc), []>;
   }
   let Defs = [CC] in {
@@ -546,15 +546,15 @@ let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
     // (via LOAD_[TLS|GLOBAL]_STACKGUARD_ADDR),
     // and compare the stack guard against the one on the stack.
     let usesCustomInserter = 1 in
-      def COMPARE_STACKGUARD_DAG : Pseudo<(outs),
+      def CMP_STACKGUARD_DAG : Pseudo<(outs),
                                            (ins bdaddr12only:$grdloc), 
                                            [(set CC, 
-                                             (z_csg
+                                             (z_cmp_stackguard
                                               (load bdaddr12only:$grdloc)
                                              )
                                             )]>;
     let Constraints = "@earlyclobber $grdaddr" in
-      def COMPARE_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr),
+      def CMP_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr),
                                        (ins bdaddr12only:$grdloc), []>;
   }
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index 9221230680f29..29c83271df640 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -21,7 +21,7 @@ def SDT_ZICmp               : SDTypeProfile<1, 3,
                                             [SDTCisVT<0, i32>,
                                              SDTCisSameAs<1, 2>,
                                              SDTCisVT<3, i32>]>;
-def SDT_ZIcmpSG                : SDTypeProfile<1, 1,
+def SDT_ZICmpSG             : SDTypeProfile<1, 1,
                                             [SDTCisVT<0, i32>,
                                              SDTCisPtrTy<1>]>;
 def SDT_ZBRCCMask           : SDTypeProfile<0, 4,
@@ -308,7 +308,8 @@ def z_icmp              : SDNode<"SystemZISD::ICMP", SDT_ZICmp>;
 
 // A special form of icmp dedicated to comparing a stack protector value
 // to a stack slot. Kept separate to enable custom lowering.
-def z_csg              : SDNode<"SystemZISD::COMPARE_STACKGUARD", SDT_ZIcmpSG>;
+def z_cmp_stackguard    : SDNode<"SystemZISD::CMP_STACKGUARD",
+                                      SDT_ZICmpSG>;
 
 // Floating-point comparisons.  The two operands are the values to compare.
 def z_fcmp              : SDNode<"SystemZISD::FCMP", SDT_ZCmp>;
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
index e885e5a4d067b..a3b9b938e097a 100644
--- a/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll
@@ -1,12 +1,12 @@
 ; RUN: llc -stop-after=systemz-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-DAGCOMBINE %s
 ; RUN: llc -stop-after=finalize-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-CUSTOMINSERT %s
 ; CHECK-DAGCOMBINE:   bb.0.entry:
-; CHECK-DAGCOMBINE:     MOVE_STACKGUARD_DAG %stack.0.StackGuardSlot, 0
-; CHECK-DAGCOMBINE:     COMPARE_STACKGUARD_DAG %stack.0.StackGuardSlot, 0, implicit-def $cc
+; CHECK-DAGCOMBINE:     MOV_STACKGUARD_DAG %stack.0.StackGuardSlot, 0
+; CHECK-DAGCOMBINE:     CMP_STACKGUARD_DAG %stack.0.StackGuardSlot, 0, implicit-def $cc
 ; CHECK-CUSTOMINSERT: bb.0.entry
-; CHECK-CUSTOMINSERT:   early-clobber %6:addr64bit = MOVE_STACKGUARD %stack.0.StackGuardSlot, 0
+; CHECK-CUSTOMINSERT:   early-clobber %6:addr64bit = MOV_STACKGUARD %stack.0.StackGuardSlot, 0
 ; CHECK_CUSTOMINSERT: bb.3.entry
-; CHECK-CUSTOMINSERT: early-clobber %10:addr64bit = COMPARE_STACKGUARD %stack.0.StackGuardSlot, 0, implicit-def $cc
+; CHECK-CUSTOMINSERT: early-clobber %10:addr64bit = CMP_STACKGUARD %stack.0.StackGuardSlot, 0, implicit-def $cc
 
 define dso_local signext i32 @stack_guard_pseudo_check(i32 %argc, ptr %argv) #0 {
 entry:

>From 4d54dbdf382a503b21918be8e36deed2221927df Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 2 Mar 2026 10:59:17 +0100
Subject: [PATCH 23/29] don't insertSSPDeclarations for TLS case

---
 llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 12 ++++++++++++
 llvm/lib/Target/SystemZ/SystemZISelLowering.h   |  6 +++++-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 8d93371b47e34..8e906372fc377 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -26,6 +26,7 @@
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsS390.h"
+#include "llvm/IR/Module.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -11483,3 +11484,14 @@ bool SystemZTargetLowering::verifyNarrowIntegerArgs(
 
   return true;
 }
+
+void SystemZTargetLowering::insertSSPDeclarations(Module &M, const LibcallLoweringInfo &Libcalls) const {
+  StringRef GuardMode = M.getStackProtectorGuard();
+
+  // In the TLS case, no symbol needs to be inserted.
+  if (GuardMode == "tls" || GuardMode.empty())
+    return;
+
+  // Otherwise (in the global case), insert the appropriate global variable.
+  TargetLowering::insertSSPDeclarations(M, Libcalls);
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index 0369fb9942a04..870db4ef0b1ed 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -16,6 +16,7 @@
 
 #include "SystemZ.h"
 #include "SystemZInstrInfo.h"
+#include "llvm/CodeGen/LibcallLoweringInfo.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/SelectionDAG.h"
 #include "llvm/CodeGen/TargetLowering.h"
@@ -227,7 +228,10 @@ class SystemZTargetLowering : public TargetLowering {
 
   /// Override to support customized stack guard loading.
   bool useLoadStackGuardNode(const Module &M) const override { return true; }
-
+  // Insert SSP declaration if global stack protector is used.
+  void
+  insertSSPDeclarations(Module &M,
+                        const LibcallLoweringInfo &Libcalls) const override;
   MachineBasicBlock *
   EmitInstrWithCustomInserter(MachineInstr &MI,
                               MachineBasicBlock *BB) const override;

>From 55fe51cc721ca74e58c829bc07e9e341c36fc0ed Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 2 Mar 2026 11:16:36 +0100
Subject: [PATCH 24/29] fix getCmp implementation

---
 .../Target/SystemZ/SystemZISelLowering.cpp    | 50 ++++++++-----------
 1 file changed, 20 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 8e906372fc377..ecfa9cc6ed621 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -3041,9 +3041,9 @@ static bool isNaturalMemoryOperand(SDValue Op, unsigned ICmpType) {
 
 // Return true if it is better to swap the operands of C.
 static bool shouldSwapCmpOperands(const Comparison &C) {
-  // swap operands of CMP_STACKGUARD_GUARD if loading the reference value
-  // is Op0.
-  if ((C.Opcode == SystemZISD::CMP_STACKGUARD) && C.Op0.isMachineOpcode() &&
+  // If one side of the compare is a load of the stackguard reference value,
+  // then that load should be Op1.
+  if (C.Op0.isMachineOpcode() &&
       (C.Op0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD))
     return true;
 
@@ -3198,37 +3198,27 @@ static void adjustICmpTruncate(SelectionDAG &DAG, const SDLoc &DL,
 // Adjust if a given Compare is a check of the stack guard against a stack
 // guard instance on the stack. Specifically, this checks if:
 // - The operands are a load of the stack guard, and a load from a stack slot
-// - Those operand values are not used elsewhere <-- asserts if this is not
-//   true!
+// - The original opcode is ICMP
+// - ICMPType is compatible with unsigned comparison.
 static void adjustForStackGuardCompare(SelectionDAG &DAG, const SDLoc &DL,
                                        Comparison &C) {
-  SDValue StackGuardLoad;
-  LoadSDNode *FILoad;
 
-  if (C.Op0.isMachineOpcode() &&
-      C.Op0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
-      ISD::isNormalLoad(C.Op1.getNode()) &&
-      dyn_cast<FrameIndexSDNode>(C.Op1.getOperand(1))) {
-    StackGuardLoad = C.Op0;
-    FILoad = cast<LoadSDNode>(C.Op1);
-  } else if ((C.Op1.isMachineOpcode() &&
-              C.Op1.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD &&
-              ISD::isNormalLoad(C.Op0.getNode()) &&
-              dyn_cast<FrameIndexSDNode>(C.Op0.getOperand(1)))) {
-    StackGuardLoad = C.Op1;
-    FILoad = cast<LoadSDNode>(C.Op0);
-  } else {
+  // Opcode must be ICMP.
+  if (C.Opcode != SystemZISD::ICMP)
+    return;
+  // ICmpType must be Unsigned or Any.
+  if (C.ICmpType == SystemZICMP::SignedOnly)
+    return;
+  // Op0 must be FrameIndex Load.
+  if (!(ISD::isNormalLoad(C.Op0.getNode()) &&
+        dyn_cast<FrameIndexSDNode>(C.Op0.getOperand(1))))
+    return;
+  // Op1 must be LOAD_STACK_GUARD.
+  if (!C.Op1.isMachineOpcode() ||
+      C.Op1.getMachineOpcode() != SystemZ::LOAD_STACK_GUARD)
     return;
-  }
-  // Assert that the values of the loads are not used elsewhere.
-  // Bail for now. TODO: What is the proper response here?
-  assert(
-      SDValue(FILoad, 0).hasOneUse() &&
-      "Value of stackguard loaded from stack must be used for compare only!");
-  assert(StackGuardLoad.hasOneUse() &&
-         "Value of reference stackguard must be used for compare only!");
 
-  // At this point we are sure that this is a proper compare_stack_guard
+  // At this point we are sure that this is a proper CMP_STACKGUARD
   // case, update the opcode to reflect this.
   C.Opcode = SystemZISD::CMP_STACKGUARD;
   C.CCValid = SystemZ::CCMASK_ICMP;
@@ -3640,7 +3630,6 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
     else
       C.ICmpType = SystemZICMP::SignedOnly;
     C.CCMask &= ~SystemZ::CCMASK_CMP_UO;
-    adjustForStackGuardCompare(DAG, DL, C);
     adjustForRedundantAnd(DAG, DL, C);
     adjustZeroCmp(DAG, DL, C);
     adjustSubwordCmp(DAG, DL, C);
@@ -3654,6 +3643,7 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
     C.CCMask = SystemZ::reverseCCMask(C.CCMask);
   }
 
+  adjustForStackGuardCompare(DAG, DL, C);
   adjustForTestUnderMask(DAG, DL, C);
   adjustICmp128(DAG, DL, C);
   return C;

>From 61b35e8228743a300af0172cb4242370c0e02dd6 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 2 Mar 2026 14:19:51 +0100
Subject: [PATCH 25/29] Add MOV_STACKGUARD ISD Node

---
 llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 11 ++++-------
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td     |  6 +++++-
 llvm/lib/Target/SystemZ/SystemZOperators.td     | 10 ++++++++--
 3 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index ecfa9cc6ed621..2e4bc83af71d8 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -8176,13 +8176,10 @@ SDValue SystemZTargetLowering::combineSTORE(
     // Obtain the frame index the store was targeting.
     int FI = cast<FrameIndexSDNode>(SN->getOperand(2))->getIndex();
     // Prepare operands of MSGD - FrameIndex, Dummy Displacement.
-    SDValue Ops[] = {DAG.getTargetFrameIndex(FI, MVT::i64),
-                     DAG.getTargetConstant(0, SDLoc(SN), MVT::i64),
-                     SN->getChain()};
-    MachineSDNode *Move = DAG.getMachineNode(SystemZ::MOV_STACKGUARD_DAG,
-                                             SDLoc(SN), MVT::Other, Ops);
-
-    return SDValue(Move, 0);
+    SDValue Ops[] = {SN->getChain(),
+                     DAG.getTargetFrameIndex(FI, MVT::i64)};
+    return DAG.getNode(SystemZISD::MOV_STACKGUARD,
+                               SDLoc(SN), MVT::Other, Ops);
   }
 
   // Combine STORE (BSWAP) into STRVH/STRV/STRVG/VSTBR
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 9de4427bdca3d..73dd0cd7ee325 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -536,7 +536,11 @@ let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
     // and move the stack guard to the stack.
     let usesCustomInserter = 1 in
       def MOV_STACKGUARD_DAG : Pseudo<(outs),
-                                        (ins bdaddr12only:$grdloc), []>;
+                                        (ins bdaddr12only:$grdloc), [
+                                          (z_mov_stackguard 
+                                            bdaddr12only:$grdloc
+                                          )
+                                     ]>;
     let Constraints = "@earlyclobber $grdaddr" in
       def MOV_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr),
                                     (ins bdaddr12only:$grdloc), []>;
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index 29c83271df640..a0365c2eaf0d7 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -24,6 +24,8 @@ def SDT_ZICmp               : SDTypeProfile<1, 3,
 def SDT_ZICmpSG             : SDTypeProfile<1, 1,
                                             [SDTCisVT<0, i32>,
                                              SDTCisPtrTy<1>]>;
+def SDT_ZMovSG              : SDTypeProfile<0, 1,
+                                            [SDTCisPtrTy<0>]>;
 def SDT_ZBRCCMask           : SDTypeProfile<0, 4,
                                             [SDTCisVT<0, i32>,
                                              SDTCisVT<1, i32>,
@@ -308,8 +310,12 @@ def z_icmp              : SDNode<"SystemZISD::ICMP", SDT_ZICmp>;
 
 // A special form of icmp dedicated to comparing a stack protector value
 // to a stack slot. Kept separate to enable custom lowering.
-def z_cmp_stackguard    : SDNode<"SystemZISD::CMP_STACKGUARD",
-                                      SDT_ZICmpSG>;
+def z_cmp_stackguard    : SDNode<"SystemZISD::CMP_STACKGUARD", SDT_ZICmpSG>;
+
+// A special ISD node intended to mirror z_cmp_stackguard, but modeling
+// the moving of the stackguard to the stack instead of the (later) compare.
+def z_mov_stackguard    : SDNode<"SystemZISD::MOV_STACKGUARD", SDT_ZMovSG,
+                                 [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>;
 
 // Floating-point comparisons.  The two operands are the values to compare.
 def z_fcmp              : SDNode<"SystemZISD::FCMP", SDT_ZCmp>;

>From 61177b5e8c3906b3c35a407ddba4e241fd034398 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 2 Mar 2026 14:33:23 +0100
Subject: [PATCH 26/29] Update comments

---
 llvm/lib/Target/SystemZ/SystemZISelLowering.cpp |  8 ++++----
 llvm/lib/Target/SystemZ/SystemZISelLowering.h   |  2 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp    | 10 +++++-----
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td     | 11 ++++-------
 4 files changed, 14 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 2e4bc83af71d8..304e6b38106dc 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -8175,7 +8175,7 @@ SDValue SystemZTargetLowering::combineSTORE(
       (Op1->getMachineOpcode() == SystemZ::LOAD_STACK_GUARD)) {
     // Obtain the frame index the store was targeting.
     int FI = cast<FrameIndexSDNode>(SN->getOperand(2))->getIndex();
-    // Prepare operands of MSGD - FrameIndex, Dummy Displacement.
+    // Prepare operands of the MOV_STACKGUARD ISD Node - Chain and FrameIndex.
     SDValue Ops[] = {SN->getChain(),
                      DAG.getTargetFrameIndex(FI, MVT::i64)};
     return DAG.getNode(SystemZISD::MOV_STACKGUARD,
@@ -11106,9 +11106,9 @@ getBackchainAddress(SDValue SP, SelectionDAG &DAG) const {
                      DAG.getIntPtrConstant(TFL->getBackchainOffset(MF), DL));
 }
 
-// Replace a _STACKGUARD_DAG pseudo with a _SG pseudo, adding
-// a dead early-clobber def reg that will be used as a
-// scratch register when the pseudo is expanded.
+// Replace a _STACKGUARD_DAG pseudo with a _STACKGUARD pseudo, adding
+// a dead early-clobber def reg that will be used as a scratch register
+// when the pseudo is expanded.
 MachineBasicBlock *SystemZTargetLowering::emitStackGuardPseudo(
     MachineInstr &MI, MachineBasicBlock *MBB, unsigned PseudoOp) const {
   MachineRegisterInfo *MRI = &MBB->getParent()->getRegInfo();
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
index 870db4ef0b1ed..ba42f4f3e5539 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h
@@ -228,7 +228,7 @@ class SystemZTargetLowering : public TargetLowering {
 
   /// Override to support customized stack guard loading.
   bool useLoadStackGuardNode(const Module &M) const override { return true; }
-  // Insert SSP declaration if global stack protector is used.
+  /// Insert SSP declaration if global stack protector is used.
   void
   insertSSPDeclarations(Module &M,
                         const LibcallLoweringInfo &Libcalls) const override;
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 5a9d107f6bb87..2edbbe3dfbe5d 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1800,9 +1800,9 @@ namespace {
 // and should be removed once that issue is resolved.
 Register scavengeAddrReg(MachineInstr &MI, MachineBasicBlock *MBB) {
   NumRSWorkaround++;
-  // create fresh RegScavanger instance.
+  // Create fresh RegScavenger instance.
   RegScavenger RS;
-  // initialize RegScavenger to correct location
+  // Initialize RegScavenger to correct location.
   RS.enterBasicBlockEnd(*MBB);
   RS.backward(MI);
 
@@ -1836,12 +1836,12 @@ void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   // return that register. If not, scavenge a new register and return that.
   // This is a workaround for https://github.com/llvm/llvm-project/issues/172511
   // and should be removed once that issue is resolved.
-  // After this, AddrReg is set to a usable scratch register.
   Register AddrReg = MI.getOperand(0).getReg();
   Register OpReg = MI.getOperand(1).getReg();
-  // if we can't use AddrReg, scavenge a new one.
+  // If we can't use AddrReg, scavenge a new one.
   if (AddrReg == OpReg)
-    AddrReg = scavengeAddrReg(MI, &MBB);
+  AddrReg = scavengeAddrReg(MI, &MBB);
+  // At this point, AddrReg should be set to a usable scratch register.
 
   // Emit an appropriate pseudo for the guard type, which loads the address of
   // said guard into the scratch register AddrReg.
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 73dd0cd7ee325..269fa6ffda0b9 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -524,16 +524,15 @@ let SimpleBDXStore = 1, mayStore = 1 in {
 }
 
 let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
-  // load the stack guard's address
+  // Load the TLS block's address for the purpose of loading the stack guard.
   def LOAD_TLS_BLOCK_ADDR : Pseudo<(outs ADDR64:$grdaddr),
                                             (ins), []>;
+  // Load the address of a global variable holding the stack guard.
   def LOAD_GLOBAL_STACKGUARD_ADDR : Pseudo<(outs ADDR64:$grdaddr),
                                                (ins), []>;
 
   let mayStore = 1 in {
-    // load the stack guard's address
-    // (via LOAD_[TLS|GLOBAL]_STACKGUARD_ADDR),
-    // and move the stack guard to the stack.
+    // Move the stack guard to the stack.
     let usesCustomInserter = 1 in
       def MOV_STACKGUARD_DAG : Pseudo<(outs),
                                         (ins bdaddr12only:$grdloc), [
@@ -546,9 +545,7 @@ let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in {
                                     (ins bdaddr12only:$grdloc), []>;
   }
   let Defs = [CC] in {
-    // load the stack guard's address
-    // (via LOAD_[TLS|GLOBAL]_STACKGUARD_ADDR),
-    // and compare the stack guard against the one on the stack.
+    // Compare the stack guard against the one on the stack.
     let usesCustomInserter = 1 in
       def CMP_STACKGUARD_DAG : Pseudo<(outs),
                                            (ins bdaddr12only:$grdloc), 

>From 7955703071db6911eb346f75ed772fe55f913118 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 2 Mar 2026 14:47:53 +0100
Subject: [PATCH 27/29] clean up includes

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp   | 2 --
 llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp | 2 +-
 llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 4 +---
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp    | 1 -
 4 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index ef6b9d3b0e6f0..7f25954bdbc26 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -22,7 +22,6 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/BinaryFormat/GOFF.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
 #include "llvm/IR/GlobalVariable.h"
@@ -30,7 +29,6 @@
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCDirectives.h"
 #include "llvm/MC/MCExpr.h"
-#include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCStreamer.h"
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 025969a81f6b7..65f3820d19f0b 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -10,8 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "SystemZISelLowering.h"
 #include "SystemZTargetMachine.h"
+#include "SystemZISelLowering.h"
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/CodeGen/SelectionDAGISel.h"
 #include "llvm/IR/Module.h"
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 304e6b38106dc..c01256f96e9cf 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -11,12 +11,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "SystemZISelLowering.h"
-#include "MCTargetDesc/SystemZMCTargetDesc.h"
 #include "SystemZCallingConv.h"
 #include "SystemZConstantPoolValue.h"
 #include "SystemZMachineFunctionInfo.h"
-#include "SystemZRegisterInfo.h"
-#include "SystemZTargetMachine.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/CodeGen/CallingConvLower.h"
 #include "llvm/CodeGen/ISDOpcodes.h"
@@ -31,6 +28,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/KnownBits.h"
+#include "llvm/Target/TargetMachine.h"
 #include <cctype>
 #include <optional>
 
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 2edbbe3dfbe5d..b6a0fb715a029 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -34,7 +34,6 @@
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/CodeGen/VirtRegMap.h"
-#include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCInstrDesc.h"

>From bfe7ed0e61bab61498e9e0e5db3d273ab96a559d Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 2 Mar 2026 14:50:09 +0100
Subject: [PATCH 28/29] formatting updates

---
 llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp | 2 +-
 llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 9 ++++-----
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp    | 5 +++--
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index 65f3820d19f0b..025969a81f6b7 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -10,8 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "SystemZTargetMachine.h"
 #include "SystemZISelLowering.h"
+#include "SystemZTargetMachine.h"
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/CodeGen/SelectionDAGISel.h"
 #include "llvm/IR/Module.h"
diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index c01256f96e9cf..f43829255e757 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -8174,10 +8174,8 @@ SDValue SystemZTargetLowering::combineSTORE(
     // Obtain the frame index the store was targeting.
     int FI = cast<FrameIndexSDNode>(SN->getOperand(2))->getIndex();
     // Prepare operands of the MOV_STACKGUARD ISD Node - Chain and FrameIndex.
-    SDValue Ops[] = {SN->getChain(),
-                     DAG.getTargetFrameIndex(FI, MVT::i64)};
-    return DAG.getNode(SystemZISD::MOV_STACKGUARD,
-                               SDLoc(SN), MVT::Other, Ops);
+    SDValue Ops[] = {SN->getChain(), DAG.getTargetFrameIndex(FI, MVT::i64)};
+    return DAG.getNode(SystemZISD::MOV_STACKGUARD, SDLoc(SN), MVT::Other, Ops);
   }
 
   // Combine STORE (BSWAP) into STRVH/STRV/STRVG/VSTBR
@@ -11470,7 +11468,8 @@ bool SystemZTargetLowering::verifyNarrowIntegerArgs(
   return true;
 }
 
-void SystemZTargetLowering::insertSSPDeclarations(Module &M, const LibcallLoweringInfo &Libcalls) const {
+void SystemZTargetLowering::insertSSPDeclarations(
+    Module &M, const LibcallLoweringInfo &Libcalls) const {
   StringRef GuardMode = M.getStackProtectorGuard();
 
   // In the TLS case, no symbol needs to be inserted.
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index b6a0fb715a029..372652d33a610 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -54,7 +54,8 @@ using namespace llvm;
 
 #define DEBUG_TYPE "systemz-II"
 
-STATISTIC(NumRSWorkaround, "The # of times the RegScavenger workaround for the FIE bug was triggered.");
+STATISTIC(NumRSWorkaround, "The # of times the RegScavenger workaround for the "
+                           "FIE bug was triggered.");
 
 // Return a mask with Count low bits set.
 static uint64_t allOnes(unsigned int Count) {
@@ -1839,7 +1840,7 @@ void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   Register OpReg = MI.getOperand(1).getReg();
   // If we can't use AddrReg, scavenge a new one.
   if (AddrReg == OpReg)
-  AddrReg = scavengeAddrReg(MI, &MBB);
+    AddrReg = scavengeAddrReg(MI, &MBB);
   // At this point, AddrReg should be set to a usable scratch register.
 
   // Emit an appropriate pseudo for the guard type, which loads the address of

>From bcc7a8f77aa98dcafacf6810fb7ca660661a0bc3 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Mon, 9 Mar 2026 11:33:06 +0100
Subject: [PATCH 29/29] Do not set CCValid

---
 llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index f43829255e757..ac0f417b17196 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -3219,7 +3219,6 @@ static void adjustForStackGuardCompare(SelectionDAG &DAG, const SDLoc &DL,
   // At this point we are sure that this is a proper CMP_STACKGUARD
   // case, update the opcode to reflect this.
   C.Opcode = SystemZISD::CMP_STACKGUARD;
-  C.CCValid = SystemZ::CCMASK_ICMP;
 }
 
 // Return true if shift operation N has an in-range constant shift value.



More information about the cfe-commits mailing list