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

Dominik Steenken via cfe-commits cfe-commits at lists.llvm.org
Mon May 18 04:47:04 PDT 2026


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

>From c02a05b15e3e8976a447161601eb1d6c617eab9a 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 1/4] [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         |  37 ++--
 .../CodeGen/SystemZ/stack-guard-pseudos.c     |  16 ++
 clang/test/Driver/stack-protector-guard.c     |  18 ++
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 126 ++++++++++++++
 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, 812 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 aa36de6edecbf..6cce4ada1dfd1 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -167,6 +167,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 753e3ac1b74a5..6377f7bb189f2 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -6099,6 +6099,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 b920266b59808..2b600e90ab480 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 2b415e60d5331..5d5100aed00db 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3503,22 +3503,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);
@@ -3542,18 +3544,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);
@@ -3649,6 +3652,18 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
     if (Width != 4 && Width != 8) {
       D.Diag(diag::err_drv_invalid_int_value)
           << A->getOption().getName() << Value;
+    }
+  }
+  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);
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 a31eeefa36ddd..46e09d6581867 100644
--- a/clang/test/Driver/stack-protector-guard.c
+++ b/clang/test/Driver/stack-protector-guard.c
@@ -160,3 +160,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 c9c080eb1453a..c4f5058830706 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -29,6 +29,7 @@
 #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"
@@ -246,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());
@@ -774,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;
@@ -781,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 e9d765f81a0cb..045cc73ea8b13 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -170,6 +170,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 26cc921b6b169..92e6ec3c9f87d 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"
@@ -8119,6 +8119,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 &&
@@ -8943,20 +8962,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
@@ -8968,6 +9033,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();
 }
 
@@ -9380,6 +9486,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 65197bbf0ee1d..59df2c952f79f 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 397989ff5087d..e96ca9444aefa 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);
 }
 
@@ -1808,10 +1779,6 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     splitAdjDynAlloc(MI);
     return true;
 
-  case TargetOpcode::LOAD_STACK_GUARD:
-    expandLoadStackGuard(&MI);
-    return true;
-
   default:
     return false;
   }
@@ -1835,6 +1802,28 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     return 18 + (MI.getOperand(0).getImm() == SystemZ::CondReturn ? 4 : 0);
   if (MI.getOpcode() == TargetOpcode::BUNDLE)
     return getInstBundleSize(MI);
+  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 fdf349ae41049..33f9e22567727 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 49cface4adf3eefe95a63fbe50d12e434b22d0fd 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 2/4] 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 c4f5058830706..ff9826a394e8c 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 92e6ec3c9f87d..07fec897d6249 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"
@@ -8123,16 +8124,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);
@@ -9047,17 +9046,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),
@@ -11155,6 +11150,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()) {
@@ -11312,6 +11335,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 59df2c952f79f..83f485e195ef0 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 e96ca9444aefa..0bf38c2270905 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1779,11 +1779,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();
@@ -1803,27 +1896,24 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
   if (MI.getOpcode() == TargetOpcode::BUNDLE)
     return getInstBundleSize(MI);
   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 33f9e22567727..910e215da1162 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 84555bd4b5f44e95257b000212bbeaf3f5b8b725 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 3/4] Implement Reviewer's Comments

This includes code formatting updates, general cleanup,
rremoving unnecessary asserts, refactoring functions for
clarity and brevity, turning `stack-protector-guard-record`
from a function attribute into a module flag, and moving
to an ISD Node approach instead of DAG combining.

For the last part, we introduce new SystemZISD nodes, CMP_STACKGUARD
and MOV_STACKGUARD, which can be inserted into the dag during isel.
These are then lowered to CMP_STACKGUARD_DAG and MOV_STACKGUARD_DAG,
then custom-inserted into their namesakes in the SystemZ namespace,
and then finally expanded post-RA to a CLC / MVC.
---
 clang/include/clang/Options/Options.td        |   2 +-
 clang/lib/CodeGen/CodeGenFunction.cpp         |   8 -
 clang/lib/CodeGen/CodeGenModule.cpp           |   8 +
 ...-pseudos.c => stack-guard-global-option.c} |   6 -
 llvm/include/llvm/IR/Module.h                 |   4 +
 llvm/lib/IR/Module.cpp                        |  11 +
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 105 ++++++----
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |   6 +-
 .../Target/SystemZ/SystemZISelDAGToDAG.cpp    |   2 +-
 .../Target/SystemZ/SystemZISelLowering.cpp    | 192 +++++++-----------
 llvm/lib/Target/SystemZ/SystemZISelLowering.h |  13 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  | 126 ++++--------
 llvm/lib/Target/SystemZ/SystemZInstrInfo.h    |   7 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td   |  51 +++--
 llvm/lib/Target/SystemZ/SystemZOperators.td   |  14 ++
 .../SystemZ/stack-guard-global-nopic.ll       |   9 +-
 .../CodeGen/SystemZ/stack-guard-global-pic.ll |  27 +--
 .../CodeGen/SystemZ/stack-guard-pseudos.ll    |  23 +++
 18 files changed, 301 insertions(+), 313 deletions(-)
 rename clang/test/CodeGen/SystemZ/{stack-guard-pseudos.c => stack-guard-global-option.c} (51%)
 create mode 100644 llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll

diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 6377f7bb189f2..098e3ecf66e65 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -6103,7 +6103,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">>;
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 2b600e90ab480..b920266b59808 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 236738e9975d3..a522c0641dab7 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1719,6 +1719,14 @@ void CodeGenModule::Release() {
   if (getCodeGenOpts().StackProtectorGuardValueWidth != UINT_MAX)
     getModule().setStackProtectorGuardValueWidth(
         getCodeGenOpts().StackProtectorGuardValueWidth);
+  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/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c b/clang/test/CodeGen/SystemZ/stack-guard-global-option.c
similarity index 51%
rename from clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
rename to clang/test/CodeGen/SystemZ/stack-guard-global-option.c
index b364aa4028ec7..c81c37b1c89eb 100644
--- a/clang/test/CodeGen/SystemZ/stack-guard-pseudos.c
+++ b/clang/test/CodeGen/SystemZ/stack-guard-global-option.c
@@ -1,10 +1,4 @@
-// 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[])
 {
diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index 3a5166d92d89d..1ee4c1a886621 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -1012,6 +1012,10 @@ class LLVM_ABI Module {
   /// Get/set the width in memory of the stack protector guard value.
   std::optional<unsigned> getStackProtectorGuardValueWidth() const;
   void setStackProtectorGuardValueWidth(unsigned Width);
+  
+  // 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;
diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp
index 07edccbaf75d6..faa0fbd3ab81c 100644
--- a/llvm/lib/IR/Module.cpp
+++ b/llvm/lib/IR/Module.cpp
@@ -760,6 +760,17 @@ 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 ff9826a394e8c..40bfaa55da17f 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -29,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"
@@ -247,16 +246,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());
@@ -785,21 +774,12 @@ 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_STACK_GUARD:
-  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_BLOCK_ADDR:
+    lowerLOAD_TLS_BLOCK_ADDR(*MI, Lower);
+    return;
+  case SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR:
+    lowerLOAD_GLOBAL_STACKGUARD_ADDR(*MI, Lower);
+    return;
 
   default:
     Lower.lower(MI, LoweredMI);
@@ -808,17 +788,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,
@@ -1061,6 +1030,68 @@ void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
   recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2);
 }
 
+void SystemZAsmPrinter::lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
+                                                 SystemZMCInstLower &Lower) {
+  Register AddrReg = MI.getOperand(0).getReg();
+  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));
+}
+
+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();
+  const TargetLowering *TLI = MF.getSubtarget().getTargetLowering();
+
+  // 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);
+  }
+  // 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)));
+  }
+}
+
 // 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 045cc73ea8b13..f3703b783f7ec 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -170,8 +170,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);
-  Register emitLoadStackGuardAddress(const MachineInstr *MI);
-  void emitStackProtectorLocEntry();
+  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 fa1daa8bf8c54..025969a81f6b7 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/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 07fec897d6249..b597d6adbd01c 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"
@@ -26,10 +23,12 @@
 #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"
 #include "llvm/Support/KnownBits.h"
+#include "llvm/Target/TargetMachine.h"
 #include <cctype>
 #include <optional>
 
@@ -3032,6 +3031,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) {
+  // 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;
+
   // Leave i128 and f128 comparisons alone, since they have no memory forms.
   if (C.Op0.getValueType() == MVT::i128)
     return false;
@@ -3180,6 +3185,35 @@ 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
+// - The original opcode is ICMP
+// - ICMPType is compatible with unsigned comparison.
+static void adjustForStackGuardCompare(SelectionDAG &DAG, const SDLoc &DL,
+                                       Comparison &C) {
+
+  // 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;
+
+  // 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.Op1 = SDValue();
+}
+
 // 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) {
@@ -3601,12 +3635,15 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1,
 
   adjustForTestUnderMask(DAG, DL, C);
   adjustICmp128(DAG, DL, C);
+  adjustForStackGuardCompare(DAG, DL, C);
   return C;
 }
 
 // Emit the comparison instruction described by C.
 static SDValue emitCmp(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) {
   if (!C.Op1.getNode()) {
+    if (C.Opcode == SystemZISD::CMP_STACKGUARD)
+      return DAG.getNode(SystemZISD::CMP_STACKGUARD, DL, MVT::i32, C.Op0);
     SDNode *Node;
     switch (C.Op0.getOpcode()) {
     case ISD::INTRINSIC_W_CHAIN:
@@ -8121,20 +8158,14 @@ SDValue SystemZTargetLowering::combineSTORE(
     }
   }
 
-  // combine STORE (LOAD_STACK_GUARD) into MOVE_STACK_GUARD
+  // combine STORE (LOAD_STACK_GUARD) into MOV_STACKGUARD_DAG
   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
-    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,
-                                             SDLoc(SN), MVT::Other, Ops);
-
-    return SDValue(Move, 0);
+    // 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);
   }
 
   // Combine STORE (BSWAP) into STRVH/STRV/STRVG/VSTBR
@@ -8961,66 +8992,20 @@ 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
@@ -9032,43 +9017,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 (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,
-                       DAG.getTargetConstant(CCValidVal, DL, MVT::i32),
-                       DAG.getTargetConstant(CCMaskVal, DL, MVT::i32),
-                       N->getOperand(3), CCReg);
-
   return SDValue();
 }
 
@@ -9481,8 +9429,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);
@@ -11150,28 +11096,16 @@ 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 {
+// 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();
   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(PseudoOp), AddrReg)
       .addFrameIndex(MI.getOperand(0).getIndex())
       .addImm(MI.getOperand(1).getImm());
   MI.eraseFromParent();
@@ -11335,11 +11269,11 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter(
   case TargetOpcode::PATCHPOINT:
     return emitPatchPoint(MI, MBB);
 
-  case SystemZ::MOVE_STACK_GUARD_DAG:
-    return emitMSGPseudo(MI, MBB);
+  case SystemZ::MOV_STACKGUARD_DAG:
+    return emitStackGuardPseudo(MI, MBB, SystemZ::MOV_STACKGUARD);
 
-  case SystemZ::COMPARE_STACK_GUARD_DAG:
-    return emitCSGPseudo(MI, MBB);
+  case SystemZ::CMP_STACKGUARD_DAG:
+    return emitStackGuardPseudo(MI, MBB, SystemZ::CMP_STACKGUARD);
 
   default:
     llvm_unreachable("Unexpected instr type to insert");
@@ -11527,3 +11461,15 @@ 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 83f485e195ef0..7facd3a27d97c 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;
@@ -470,10 +474,9 @@ 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
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 0bf38c2270905..31c15c25ae3d8 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -33,8 +33,8 @@
 #include "llvm/CodeGen/TargetOpcodes.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/CodeGen/VirtRegMap.h"
-#include "llvm/MC/MCInstBuilder.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"
@@ -1031,7 +1031,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);
 }
 
@@ -1779,12 +1780,12 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
     splitAdjDynAlloc(MI);
     return true;
 
-  case SystemZ::MOVE_STACK_GUARD:
-    expandMSGPseudo(MI);
+  case SystemZ::MOV_STACKGUARD:
+    expandStackGuardPseudo(MI, SystemZ::MVC);
     return true;
 
-  case SystemZ::COMPARE_STACK_GUARD:
-    expandCSGPseudo(MI);
+  case SystemZ::CMP_STACKGUARD:
+    expandStackGuardPseudo(MI, SystemZ::CLC);
     return true;
 
   default:
@@ -1792,88 +1793,46 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
   }
 }
 
-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 {
+void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
+                                              unsigned Opcode) 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();
+  unsigned int Offset = 0;
 
-  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);
+  Register AddrReg = MI.getOperand(0).getReg();
+  Register OpReg = MI.getOperand(1).getReg();
 
-    // 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);
+  assert (AddrReg != OpReg && "Scratch register for stack guard address blocked by operand register.");
 
+  // 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 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).
+    Offset = 40;
   } 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);
-    }
-
+    // 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());
   }
-}
 
-void SystemZInstrInfo::expandMSGPseudo(MachineInstr &MI) const {
-  emitLoadStackGuardAddress(MI);
-  BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(SystemZ::MVC))
+  // 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(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())));
+      .addReg(AddrReg)
+      .addImm(Offset);
+
   MI.removeFromParent();
 }
 
@@ -1895,25 +1854,12 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
     return 18 + (MI.getOperand(0).getImm() == SystemZ::CondReturn ? 4 : 0);
   if (MI.getOpcode() == TargetOpcode::BUNDLE)
     return getInstBundleSize(MI);
-  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_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.
+    return 6;
 
   return MI.getDesc().getSize();
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
index 910e215da1162..0bf20bff52622 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,
@@ -219,10 +218,6 @@ 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 cf81c4bdd7ed0..269fa6ffda0b9 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -523,23 +523,40 @@ 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 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 {
+    // Move the stack guard to the stack.
+    let usesCustomInserter = 1 in
+      def MOV_STACKGUARD_DAG : Pseudo<(outs),
+                                        (ins bdaddr12only:$grdloc), [
+                                          (z_mov_stackguard 
+                                            bdaddr12only:$grdloc
+                                          )
+                                     ]>;
+    let Constraints = "@earlyclobber $grdaddr" in
+      def MOV_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr),
+                                    (ins bdaddr12only:$grdloc), []>;
+  }
+  let Defs = [CC] in {
+    // Compare the stack guard against the one on the stack.
+    let usesCustomInserter = 1 in
+      def CMP_STACKGUARD_DAG : Pseudo<(outs),
+                                           (ins bdaddr12only:$grdloc), 
+                                           [(set CC, 
+                                             (z_cmp_stackguard
+                                              (load bdaddr12only:$grdloc)
+                                             )
+                                            )]>;
+    let Constraints = "@earlyclobber $grdaddr" in
+      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 758445e2a566d..b69f84d78aaf1 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -21,6 +21,11 @@ def SDT_ZICmp               : SDTypeProfile<1, 3,
                                             [SDTCisVT<0, i32>,
                                              SDTCisSameAs<1, 2>,
                                              SDTCisVT<3, i32>]>;
+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>,
@@ -303,6 +308,15 @@ 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_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>;
 
diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
index d1d98537c1df2..5e691c8461153 100644
--- a/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll
@@ -118,21 +118,21 @@ 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 %r2, 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:    la %r2, 176(%r15)
 ; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    lay %r2, 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:    jlh .LBB2_2
 ; CHECK-NEXT:  # %bb.1: # %entry
@@ -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 fe8b6a7e4214d..d138dfbdb5c67 100644
--- a/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
+++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll
@@ -13,7 +13,7 @@ define i32 @test_global_stack_guard() #0 {
 ; CHECK-NEXT:    .quad .Ltmp0
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp0:
-; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOTENT
 ; CHECK-NEXT:    mvc 1184(8,%r15), 0(%r1)
 ; CHECK-NEXT:    la %r2, 160(%r15)
 ; CHECK-NEXT:    brasl %r14, foo3 at PLT
@@ -21,7 +21,7 @@ define i32 @test_global_stack_guard() #0 {
 ; CHECK-NEXT:    .quad .Ltmp1
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp1:
-; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOTENT
 ; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
 ; CHECK-NEXT:    jlh .LBB0_2
 ; CHECK-NEXT:  # %bb.1: # %entry
@@ -49,7 +49,7 @@ define i32 @test_global_stack_guard_branch(i32 %in) #0 {
 ; CHECK-NEXT:    .quad .Ltmp2
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp2:
-; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOTENT
 ; CHECK-NEXT:    mvc 1184(8,%r15), 0(%r1)
 ; CHECK-NEXT:    lr %r13, %r2
 ; CHECK-NEXT:    la %r2, 160(%r15)
@@ -62,7 +62,7 @@ define i32 @test_global_stack_guard_branch(i32 %in) #0 {
 ; CHECK-NEXT:    .quad .Ltmp3
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp3:
-; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOTENT
 ; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
 ; CHECK-NEXT:    jlh .LBB1_8
 ; CHECK-NEXT:  # %bb.3: # %foo
@@ -74,7 +74,7 @@ define i32 @test_global_stack_guard_branch(i32 %in) #0 {
 ; CHECK-NEXT:    .quad .Ltmp4
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp4:
-; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOTENT
 ; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
 ; CHECK-NEXT:    jlh .LBB1_8
 ; CHECK-NEXT:  # %bb.5: # %bar
@@ -86,7 +86,7 @@ define i32 @test_global_stack_guard_branch(i32 %in) #0 {
 ; CHECK-NEXT:    .quad .Ltmp5
 ; CHECK-NEXT:    .text
 ; CHECK-NEXT:  .Ltmp5:
-; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOT
+; CHECK-NEXT:    lgrl %r1, __stack_chk_guard at GOTENT
 ; CHECK-NEXT:    clc 1184(8,%r15), 0(%r1)
 ; CHECK-NEXT:    jlh .LBB1_8
 ; CHECK-NEXT:  # %bb.7: # %else
@@ -119,21 +119,21 @@ 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 %r2, 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:    lgrl %r1, __stack_chk_guard at GOTENT
 ; CHECK-NEXT:    mvc 176(8,%r2), 0(%r1)
 ; CHECK-NEXT:    la %r2, 176(%r15)
 ; CHECK-NEXT:    brasl %r14, foo3 at PLT
+; CHECK-NEXT:    lay %r2, 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:    lgrl %r1, __stack_chk_guard at GOTENT
 ; CHECK-NEXT:    clc 176(8,%r2), 0(%r1)
 ; CHECK-NEXT:    jlh .LBB2_2
 ; CHECK-NEXT:  # %bb.1: # %entry
@@ -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}
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..a3b9b938e097a
--- /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:     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 = MOV_STACKGUARD %stack.0.StackGuardSlot, 0
+; CHECK_CUSTOMINSERT: bb.3.entry
+; 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:
+  %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 5d13899e04deb422a7e1e525f03fb9df458ed289 Mon Sep 17 00:00:00 2001
From: Dominik Steenken <dost at de.ibm.com>
Date: Wed, 13 May 2026 11:14:43 +0200
Subject: [PATCH 4/4] apply formatting rules

---
 llvm/include/llvm/IR/Module.h                | 2 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index 1ee4c1a886621..2032c0ceb2088 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -1012,7 +1012,7 @@ class LLVM_ABI Module {
   /// Get/set the width in memory of the stack protector guard value.
   std::optional<unsigned> getStackProtectorGuardValueWidth() const;
   void setStackProtectorGuardValueWidth(unsigned Width);
-  
+
   // Get/set flag indicating whether to emit a __stack_protector_loc section.
   bool hasStackProtectorGuardRecord() const;
   void setStackProtectorGuardRecord(bool Flag);
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 31c15c25ae3d8..e26ae83568f1a 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1805,7 +1805,9 @@ void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   Register AddrReg = MI.getOperand(0).getReg();
   Register OpReg = MI.getOperand(1).getReg();
 
-  assert (AddrReg != OpReg && "Scratch register for stack guard address blocked by operand register.");
+  assert(
+      AddrReg != OpReg &&
+      "Scratch register for stack guard address blocked by operand register.");
 
   // Emit an appropriate pseudo for the guard type, which loads the address of
   // said guard into the scratch register AddrReg.



More information about the cfe-commits mailing list