[llvm] [SystemZ][z/OS] Remove use of subsections. (PR #184167)

Kai Nacke via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 10 09:10:20 PDT 2026


https://github.com/redstar updated https://github.com/llvm/llvm-project/pull/184167

>From 5a7b1d95e29eb81a85239e01aa1fe2c069632c34 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Tue, 10 Feb 2026 16:40:07 -0500
Subject: [PATCH 1/4] [SystemZ][z/OS] Remove use of subsections.

HLASM has no notion of subsections. There are several possible solutions
how to deal with this. However,

- using a different section introduces a lot of relocations, which slows
  down the binder later
- emitting the PPA1 after the code changes the location which may break
  existing tools

The choosen solution is to record the PPA1 data, and emit them at the
end of the assembly into the code section. This solves both issues,
at the expense of having to do some bookkeeping.

This change moves the position of the PPA2, too, but this is less
critical.
---
 llvm/include/llvm/BinaryFormat/GOFF.h         |   6 -
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 232 ++++++++++--------
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |  27 +-
 llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll    |  22 +-
 llvm/test/CodeGen/SystemZ/zos-landingpad.ll   |  12 +-
 llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll |  39 +--
 llvm/test/CodeGen/SystemZ/zos-ppa1.ll         |   2 -
 .../CodeGen/SystemZ/zos-prologue-epilog.ll    |  46 ++--
 llvm/test/CodeGen/SystemZ/zos-section-1.ll    |  44 ++--
 llvm/test/CodeGen/SystemZ/zos-simple-test.ll  |  12 +-
 llvm/test/CodeGen/SystemZ/zos-symbol-2.ll     |   2 +-
 11 files changed, 244 insertions(+), 200 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h
index f54d8cd19c86b..67e58b50b7229 100644
--- a/llvm/include/llvm/BinaryFormat/GOFF.h
+++ b/llvm/include/llvm/BinaryFormat/GOFF.h
@@ -187,12 +187,6 @@ enum ENDEntryPointRequest : uint8_t {
   END_EPR_Reserved = 3,
 };
 
-// \brief Subsections of the primary C_CODE section in the object file.
-enum SubsectionKind : uint8_t {
-  SK_PPA1 = 2,
-  SK_PPA2 = 4,
-};
-
 // The standard System/390 convention is to name the high-order (leftmost) bit
 // in a byte as bit zero. The Flags type helps to set bits in byte according
 // to this numeration order.
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 8be75196f0482..786476dab16f0 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1226,6 +1226,9 @@ bool SystemZAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
 void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) {
   auto TT = OutContext.getTargetTriple();
   if (TT.isOSzOS()) {
+    OutStreamer->switchSection(getObjFileLowering().getTextSection());
+    for (auto &Info : DeferredPPA1)
+      emitPPA1(Info);
     emitADASection();
     emitIDRLSection(M);
   }
@@ -1372,12 +1375,7 @@ void SystemZAsmPrinter::emitFunctionBodyEnd() {
     // is used. This is needed to calculate the size of the function.
     MCSymbol *FnEndSym = createTempSymbol("func_end");
     OutStreamer->emitLabel(FnEndSym);
-
-    OutStreamer->pushSection();
-    OutStreamer->switchSection(getObjFileLowering().getTextSection(),
-                               GOFF::SK_PPA1);
-    emitPPA1(FnEndSym);
-    OutStreamer->popSection();
+    calculatePPA1(FnEndSym);
 
     CurrentFnPPA1Sym = nullptr;
     CurrentFnEPMarkerSym = nullptr;
@@ -1503,9 +1501,100 @@ static void emitPPA1Name(std::unique_ptr<MCStreamer> &OutStreamer,
   OutStreamer->emitZeros(ExtraZeros);
 }
 
-void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
+void SystemZAsmPrinter::emitPPA1(PPA1Info &Info) {
   assert(PPA2Sym != nullptr && "PPA2 Symbol not defined");
 
+  // Emit PPA1 section.
+  OutStreamer->AddComment("PPA1");
+  OutStreamer->emitLabel(Info.PPA1);
+  OutStreamer->AddComment("Version");
+  OutStreamer->emitInt8(0x02); // Version.
+  OutStreamer->AddComment("LE Signature X'CE'");
+  OutStreamer->emitInt8(0xCE); // CEL signature.
+  OutStreamer->AddComment("Saved GPR Mask");
+  OutStreamer->emitInt16(Info.SavedGPRMask);
+  OutStreamer->AddComment("Offset to PPA2");
+  OutStreamer->emitAbsoluteSymbolDiff(PPA2Sym, Info.PPA1, 4);
+
+  emitPPA1Flags(OutStreamer, Info.IsVarArg, Info.HasStackProtector,
+                Info.SavedFPRMask != 0, Info.SavedVRMask != 0,
+                Info.PersonalityRoutine != nullptr, Info.HasArgAreaLength,
+                Info.Name.size() > 0);
+
+  OutStreamer->AddComment("Length/4 of Parms");
+  OutStreamer->emitInt16(
+      static_cast<uint16_t>(Info.SizeOfFnParams / 4)); // Parms/4.
+  OutStreamer->AddComment("Length of Code");
+  OutStreamer->emitAbsoluteSymbolDiff(Info.FnEnd, Info.EPMarker, 4);
+
+  if (Info.HasArgAreaLength) {
+    OutStreamer->AddComment("Argument Area Length");
+    OutStreamer->emitInt32(Info.CallFrameSize);
+  }
+
+  // Emit saved FPR mask and offset to FPR save area (0x20 of flags 3).
+  if (Info.SavedFPRMask) {
+    OutStreamer->AddComment("FPR mask");
+    OutStreamer->emitInt16(Info.SavedFPRMask);
+    OutStreamer->AddComment("AR mask");
+    OutStreamer->emitInt16(0); // AR Mask, unused currently.
+    OutStreamer->AddComment("FPR Save Area Locator");
+    OutStreamer->AddComment(Twine("  Bit 0-3: Register R")
+                                .concat(utostr(Info.FrameAndFPROffset >> 28))
+                                .str());
+    OutStreamer->AddComment(
+        Twine("  Bit 4-31: Offset ")
+            .concat(utostr(Info.FrameAndFPROffset & 0x0FFFFFFF))
+            .str());
+    OutStreamer->emitInt32(Info.FrameAndFPROffset); // Offset to FPR save area
+                                                    // with register to add
+                                                    // value to (alloca reg).
+  }
+
+  // Emit saved VR mask to VR save area.
+  if (Info.SavedVRMask) {
+    OutStreamer->AddComment("VR mask");
+    OutStreamer->emitInt8(Info.SavedVRMask);
+    OutStreamer->emitInt8(0);  // Reserved.
+    OutStreamer->emitInt16(0); // Also reserved.
+    OutStreamer->AddComment("VR Save Area Locator");
+    OutStreamer->AddComment(Twine("  Bit 0-3: Register R")
+                                .concat(utostr(Info.FrameAndVROffset >> 28))
+                                .str());
+    OutStreamer->AddComment(
+        Twine("  Bit 4-31: Offset ")
+            .concat(utostr(Info.FrameAndVROffset & 0x0FFFFFFF))
+            .str());
+    OutStreamer->emitInt32(Info.FrameAndVROffset);
+  }
+
+  // Emit C++ EH information block.
+  if (Info.PersonalityRoutine) {
+    OutStreamer->AddComment("Version");
+    OutStreamer->emitInt32(1);
+    OutStreamer->AddComment("Flags");
+    OutStreamer->emitInt32(0); // LSDA field is a WAS offset
+    OutStreamer->AddComment("Personality routine");
+    OutStreamer->emitInt64(ADATable.insert(
+        Info.PersonalityRoutine, SystemZII::MO_ADA_INDIRECT_FUNC_DESC));
+    OutStreamer->AddComment("LSDA location");
+    OutStreamer->emitInt64(
+        ADATable.insert(Info.GCCEH, SystemZII::MO_ADA_DATA_SYMBOL_ADDR));
+  }
+
+  // Emit name length and name optional section (0x01 of flags 4)
+  if (Info.Name.size())
+    emitPPA1Name(OutStreamer, Info.Name);
+
+  // Emit offset to entry point optional section (0x80 of flags 4).
+  OutStreamer->emitAbsoluteSymbolDiff(Info.EPMarker, Info.PPA1, 4);
+}
+
+void SystemZAsmPrinter::calculatePPA1(MCSymbol *FnEndSym) {
+  assert(PPA2Sym != nullptr && "PPA2 Symbol not defined");
+
+  PPA1Info Info;
+
   const TargetRegisterInfo *TRI = MF->getRegInfo().getTargetRegisterInfo();
   const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
   const auto TargetHasVector = Subtarget.hasVector();
@@ -1586,19 +1675,35 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
     FrameAndVROffset |= FrameReg << 28;               // Put into top 4 bits.
   }
 
-  // Emit PPA1 section.
-  OutStreamer->AddComment("PPA1");
-  OutStreamer->emitLabel(CurrentFnPPA1Sym);
-  OutStreamer->AddComment("Version");
-  OutStreamer->emitInt8(0x02); // Version.
-  OutStreamer->AddComment("LE Signature X'CE'");
-  OutStreamer->emitInt8(0xCE); // CEL signature.
-  OutStreamer->AddComment("Saved GPR Mask");
-  OutStreamer->emitInt16(SavedGPRMask);
-  OutStreamer->AddComment("Offset to PPA2");
-  OutStreamer->emitAbsoluteSymbolDiff(PPA2Sym, CurrentFnPPA1Sym, 4);
+  MCSymbol *PersonalityRoutine = nullptr;
+  MCSymbol *GCCEH = nullptr;
+  if (!MF->getLandingPads().empty()) {
+    const Function *Per = dyn_cast<Function>(
+        MF->getFunction().getPersonalityFn()->stripPointerCasts());
+    PersonalityRoutine = Per ? MF->getTarget().getSymbol(Per) : nullptr;
+    assert(PersonalityRoutine && "Missing personality routine");
+
+    GCCEH = MF->getContext().getOrCreateSymbol(Twine("GCC_except_table") +
+                                               Twine(MF->getFunctionNumber()));
+  }
 
-  bool NeedEmitEHBlock = !MF->getLandingPads().empty();
+  // Save the calculated values.
+  if (MF->getFunction().hasName())
+    Info.Name = MF->getFunction().getName();
+  Info.PPA1 = CurrentFnPPA1Sym;
+  Info.EPMarker = CurrentFnEPMarkerSym;
+  Info.FnEnd = FnEndSym;
+  Info.PersonalityRoutine = PersonalityRoutine;
+  Info.GCCEH = GCCEH;
+  Info.CallFrameSize = MFFrame.getMaxCallFrameSize();
+  Info.SizeOfFnParams = ZFI->getSizeOfFnParams();
+  Info.FrameAndFPROffset = FrameAndFPROffset;
+  Info.FrameAndVROffset = FrameAndVROffset;
+  Info.SavedGPRMask = SavedGPRMask;
+  Info.SavedFPRMask = SavedFPRMask;
+  Info.SavedVRMask = SavedVRMask;
+  Info.IsVarArg = MF->getFunction().isVarArg();
+  Info.HasStackProtector = MFFrame.hasStackProtectorIndex();
 
   // Optional Argument Area Length.
   // Note: This represents the length of the argument area that we reserve
@@ -1610,92 +1715,10 @@ void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) {
   //       extension.  This optional field is also created if the
   //       routine has alloca(). This may reduce stack space
   //       if alloca() call causes a stack extension.
-  bool HasArgAreaLength =
+  Info.HasArgAreaLength =
       (AllocaReg != 0) || (MFFrame.getMaxCallFrameSize() > 128);
 
-  bool HasName =
-      MF->getFunction().hasName() && MF->getFunction().getName().size() > 0;
-
-  emitPPA1Flags(OutStreamer, MF->getFunction().isVarArg(),
-                MFFrame.hasStackProtectorIndex(), SavedFPRMask != 0,
-                TargetHasVector && SavedVRMask != 0, NeedEmitEHBlock,
-                HasArgAreaLength, HasName);
-
-  OutStreamer->AddComment("Length/4 of Parms");
-  OutStreamer->emitInt16(
-      static_cast<uint16_t>(ZFI->getSizeOfFnParams() / 4)); // Parms/4.
-  OutStreamer->AddComment("Length of Code");
-  OutStreamer->emitAbsoluteSymbolDiff(FnEndSym, CurrentFnEPMarkerSym, 4);
-
-  if (HasArgAreaLength) {
-    OutStreamer->AddComment("Argument Area Length");
-    OutStreamer->emitInt32(MFFrame.getMaxCallFrameSize());
-  }
-
-  // Emit saved FPR mask and offset to FPR save area (0x20 of flags 3).
-  if (SavedFPRMask) {
-    OutStreamer->AddComment("FPR mask");
-    OutStreamer->emitInt16(SavedFPRMask);
-    OutStreamer->AddComment("AR mask");
-    OutStreamer->emitInt16(0); // AR Mask, unused currently.
-    OutStreamer->AddComment("FPR Save Area Locator");
-    OutStreamer->AddComment(Twine("  Bit 0-3: Register R")
-                                .concat(utostr(FrameAndFPROffset >> 28))
-                                .str());
-    OutStreamer->AddComment(Twine("  Bit 4-31: Offset ")
-                                .concat(utostr(FrameAndFPROffset & 0x0FFFFFFF))
-                                .str());
-    OutStreamer->emitInt32(FrameAndFPROffset); // Offset to FPR save area with
-                                               // register to add value to
-                                               // (alloca reg).
-  }
-
-  // Emit saved VR mask to VR save area.
-  if (TargetHasVector && SavedVRMask) {
-    OutStreamer->AddComment("VR mask");
-    OutStreamer->emitInt8(SavedVRMask);
-    OutStreamer->emitInt8(0);  // Reserved.
-    OutStreamer->emitInt16(0); // Also reserved.
-    OutStreamer->AddComment("VR Save Area Locator");
-    OutStreamer->AddComment(Twine("  Bit 0-3: Register R")
-                                .concat(utostr(FrameAndVROffset >> 28))
-                                .str());
-    OutStreamer->AddComment(Twine("  Bit 4-31: Offset ")
-                                .concat(utostr(FrameAndVROffset & 0x0FFFFFFF))
-                                .str());
-    OutStreamer->emitInt32(FrameAndVROffset);
-  }
-
-  // Emit C++ EH information block
-  const Function *Per = nullptr;
-  if (NeedEmitEHBlock) {
-    Per = dyn_cast<Function>(
-        MF->getFunction().getPersonalityFn()->stripPointerCasts());
-    MCSymbol *PersonalityRoutine =
-        Per ? MF->getTarget().getSymbol(Per) : nullptr;
-    assert(PersonalityRoutine && "Missing personality routine");
-
-    OutStreamer->AddComment("Version");
-    OutStreamer->emitInt32(1);
-    OutStreamer->AddComment("Flags");
-    OutStreamer->emitInt32(0); // LSDA field is a WAS offset
-    OutStreamer->AddComment("Personality routine");
-    OutStreamer->emitInt64(ADATable.insert(
-        PersonalityRoutine, SystemZII::MO_ADA_INDIRECT_FUNC_DESC));
-    OutStreamer->AddComment("LSDA location");
-    MCSymbol *GCCEH = MF->getContext().getOrCreateSymbol(
-        Twine("GCC_except_table") + Twine(MF->getFunctionNumber()));
-    OutStreamer->emitInt64(
-        ADATable.insert(GCCEH, SystemZII::MO_ADA_DATA_SYMBOL_ADDR));
-  }
-
-  // Emit name length and name optional section (0x01 of flags 4)
-  if (HasName)
-    emitPPA1Name(OutStreamer, MF->getFunction().getName());
-
-  // Emit offset to entry point optional section (0x80 of flags 4).
-  OutStreamer->emitAbsoluteSymbolDiff(CurrentFnEPMarkerSym, CurrentFnPPA1Sym,
-                                      4);
+  DeferredPPA1.push_back(Info);
 }
 
 void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) {
@@ -1706,8 +1729,7 @@ void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) {
 
 void SystemZAsmPrinter::emitPPA2(Module &M) {
   OutStreamer->pushSection();
-  OutStreamer->switchSection(getObjFileLowering().getTextSection(),
-                             GOFF::SK_PPA2);
+  OutStreamer->switchSection(getObjFileLowering().getTextSection());
   MCContext &OutContext = OutStreamer->getContext();
   // Make CELQSTRT symbol.
   const char *StartSymbolName = "CELQSTRT";
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 0f87eb0307911..0456ccee386b6 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -13,6 +13,7 @@
 #include "SystemZMCInstLower.h"
 #include "SystemZTargetMachine.h"
 #include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/StackMaps.h"
 #include "llvm/MC/MCInstBuilder.h"
 #include "llvm/Support/Compiler.h"
@@ -99,15 +100,35 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   DenseMap<const GlobalObject *, SmallVector<const GlobalAlias *, 1>>
       GOAliasMap;
 
-  void emitPPA1(MCSymbol *FnEndSym);
+  struct PPA1Info {
+    StringRef Name;
+    MCSymbol *FnEnd = nullptr;    // Symbol marking function end.
+    MCSymbol *PPA1 = nullptr;     // Symbol marking PPA1 begin.
+    MCSymbol *EPMarker = nullptr; // Symbol marking entry point.
+    MCSymbol *PersonalityRoutine = nullptr;
+    MCSymbol *GCCEH = nullptr;
+    uint64_t CallFrameSize = 0;
+    unsigned SizeOfFnParams = 0;
+    uint32_t FrameAndFPROffset;
+    uint32_t FrameAndVROffset;
+    uint16_t SavedGPRMask = 0;
+    uint16_t SavedFPRMask = 0;
+    uint8_t SavedVRMask = 0;
+    bool HasArgAreaLength = false;
+    bool IsVarArg = false;
+    bool HasStackProtector = false;
+  };
+  SmallVector<PPA1Info, 0> DeferredPPA1;
+
+  void calculatePPA1(MCSymbol *FnEndSym);
+  void emitPPA1(PPA1Info &Info);
   void emitPPA2(Module &M);
   void emitADASection();
   void emitIDRLSection(Module &M);
 
 public:
   SystemZAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
-      : AsmPrinter(TM, std::move(Streamer), ID), CurrentFnPPA1Sym(nullptr),
-        CurrentFnEPMarkerSym(nullptr), PPA2Sym(nullptr),
+      : AsmPrinter(TM, std::move(Streamer), ID), PPA2Sym(nullptr),
         ADATable(TM.getPointerSize(0)) {}
 
   // Override AsmPrinter.
diff --git a/llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll b/llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll
index a10686b85e810..273ce61e55fc8 100644
--- a/llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll
@@ -1,6 +1,6 @@
 ; Test the HLASM streamer on z/OS to ensure there's no GNU syntax anywhere
 
-; RUN: llc < %s -mtriple=s390x-ibm-zos | FileCheck %s
+; RUN: llc < %s -mtriple=s390x-ibm-zos -asm-verbose=0 | FileCheck %s
 
 @.str = private unnamed_addr constant [10 x i8] c"Hello %s\0A\00", align 2
 @Greeting = global ptr @.str, align 8
@@ -20,7 +20,15 @@ define void @foo() {
 ; CHECK: DC XL1'81'
 ; CHECK: DC XL1'00'
 ; CHECK: DC XL2'0000'
-; CHECK-LABEL: L#PPA1_foo_0 DS 0H
+; CHECK-LABEL: L#.str DS 0H
+; CHECK: DC XL10'48656C6C6F2025730A00'
+; CHECK: Greeting XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(EXPORT)
+; CHECK: DS 0B
+; CHECK: DC AD(L#.str)
+; CHECK: DS 0B
+; CHECK-LABEL: L#.str.1 DS 0H
+; CHECK: DC XL6'576F726C6400'
+; CHECK-LABEL: L#PPA1_foo_0 DS 0H    
 ; CHECK: DC XL1'02'
 ; CHECK: DC XL1'CE'
 ; CHECK: DC XL2'0300'
@@ -34,20 +42,10 @@ define void @foo() {
 ; CHECK: DC XL2'0003'
 ; CHECK: DC XL3'869696'
 ; CHECK: DC AD(L#EPM_foo_0-L#PPA1_foo_0)
-; CHECK-LABEL: L#.str DS 0H
-; CHECK: DC XL10'48656C6C6F2025730A00'
-; CHECK: Greeting XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(EXPORT)
-; CHECK: DS 0B
-; CHECK: DC AD(L#.str)
-; CHECK: DS 0B
-; CHECK-LABEL: L#.str.1 DS 0H
-; CHECK: DC XL6'576F726C6400'
 ; CHECK: C_WSA64 CATTR ALIGN(4),FILL(0),DEFLOAD,NOTEXECUTABLE,RMODE(64),PART(stdi
 ; CHECK:                in#S)
 ; CHECK: stdin#S XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(SECTION)
-; CHECK: * Offset 0 pointer to data symbol Greeting
 ; CHECK:  DC AD(Greeting)
-; CHECK: * Offset 8 function descriptor of outs
 ; CHECK:  DC RD(outs)
 ; CHECK:  DC VD(outs)
 ; CHECK: END
diff --git a/llvm/test/CodeGen/SystemZ/zos-landingpad.ll b/llvm/test/CodeGen/SystemZ/zos-landingpad.ll
index 1ae1751f92634..5c0f1f1d09033 100644
--- a/llvm/test/CodeGen/SystemZ/zos-landingpad.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-landingpad.ll
@@ -30,6 +30,12 @@ lpad:
   unreachable
 }
 
+; Check that the exception table is emitted into .lsda section.
+; CHECK:  stdin#C CSECT
+; CHECK: C_WSA64 CATTR ALIGN(2),FILL(0),NOTEXECUTABLE,RMODE(64),PART(.gcc_excepti
+; CHECK:                ion_table.test1)
+; CHECK: .gcc_exception_table.test1 XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(S
+; CHECK:                SECTION)
 ; Check that offsets to the FD of the personality routine and LSDA are emitted in PPA1
 ; CHECK: * PPA1 Flags 4
 ; CHECK: *   Bit 3: 1 = C++ EH block
@@ -39,9 +45,3 @@ lpad:
 ; CHECK:  DC XL8'0000000000000020'
 ; CHECK: * LSDA location
 ; CHECK:  DC XL8'0000000000000028'
-; Check that the exception table is emitted into .lsda section.
-; CHECK:  stdin#C CSECT
-; CHECK: C_WSA64 CATTR ALIGN(2),FILL(0),NOTEXECUTABLE,RMODE(64),PART(.gcc_excepti
-; CHECK:                ion_table.test1)
-; CHECK: .gcc_exception_table.test1 XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(S
-; CHECK:                SECTION)
diff --git a/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll b/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll
index 32a59e5ba3ea9..610c851798614 100644
--- a/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-ppa1-argarea.ll
@@ -11,9 +11,6 @@ define void @fSmallOutArgArea() {
 ; CHECK: *   Bit 2: 0 = Does not use alloca
 ; CHECK:  DC XL4'00000008'
 ; CHECK: fSmallOutArgArea DS 0H
-; CHECK: L#PPA1_fSmallOutArgArea_0 DS 0H
-; CHECK: * PPA1 Flags 3
-; CHECK:  DC XL1'00'
   ret void
 }
 
@@ -24,12 +21,6 @@ define void @fLargeOutArgArea() {
 ; CHECK: *   Bit 2: 0 = Does not use alloca
 ; CHECK:  DC XL4'00000220'
 ; CHECK: fLargeOutArgArea DS 0H
-; CHECK: L#PPA1_fLargeOutArgArea_0 DS 0H
-; CHECK: * PPA1 Flags 3
-; CHECK: *   Bit 1: 1 = Argument Area Length is in optional area
-; CHECK:  DC XL1'40'
-; CHECK: * Argument Area Length
-; CHECK:  DC XL4'00000140'
   %1 = load [33 x i32], ptr @GlobLargeS, align 4
   call void @fLargeParm([33 x i32] inreg %1)
   ret void
@@ -38,8 +29,6 @@ define void @fLargeOutArgArea() {
 ; === Check that function with parameter does emit PPA1 Length/4 of parms
 define void @fLargeParm([33 x i64] inreg %arr) {
 ; CHECK-LABEL: L#EPM_fLargeParm_0 DS 0H
-; CHECK: * Length/4 of Parms
-; CHECK:  DC XL2'0042'
   %1 = extractvalue [33 x i64] %arr, 1
   call void @foo(i64 %1)
   ret void
@@ -50,12 +39,6 @@ define hidden void @fHasAlloca() {
 ; CHECK-LABEL: L#EPM_fHasAlloca_0 DS 0H
 ; CHECK: *   Bit 2: 1 = Uses alloca
 ; CHECK: fHasAlloca DS 0H
-; CHECK: L#PPA1_fHasAlloca_0 DS 0H
-; CHECK: * PPA1 Flags 3
-; CHECK: *   Bit 1: 1 = Argument Area Length is in optional area
-; CHECK:  DC XL1'40'
-; CHECK: * Argument Area Length
-; CHECK:  DC XL4'00000040'
   %p = alloca ptr, align 4
   %1 = load i32, ptr @GlobInt, align 4
   %2 = alloca i8, i32 %1, align 8
@@ -64,3 +47,25 @@ define hidden void @fHasAlloca() {
 }
 
 declare void @foo(i64)
+
+; CHECK-LABEL: L#PPA1_fSmallOutArgArea_0 DS 0H
+; CHECK: * PPA1 Flags 3
+; CHECK:  DC XL1'00'
+
+; CHECK-LABEL: L#PPA1_fLargeOutArgArea_0 DS 0H
+; CHECK: * PPA1 Flags 3
+; CHECK: *   Bit 1: 1 = Argument Area Length is in optional area
+; CHECK:  DC XL1'40'
+; CHECK: * Argument Area Length
+; CHECK:  DC XL4'00000140'
+
+; CHECK-LABEL: L#PPA1_fLargeParm_0 DS 0H
+; CHECK: * Length/4 of Parms
+; CHECK:  DC XL2'0042'
+
+; CHECK-LABEL: L#PPA1_fHasAlloca_0 DS 0H
+; CHECK: * PPA1 Flags 3
+; CHECK: *   Bit 1: 1 = Argument Area Length is in optional area
+; CHECK:  DC XL1'40'
+; CHECK: * Argument Area Length
+; CHECK:  DC XL4'00000040'
diff --git a/llvm/test/CodeGen/SystemZ/zos-ppa1.ll b/llvm/test/CodeGen/SystemZ/zos-ppa1.ll
index f73edfc6ba42e..5c03260656630 100644
--- a/llvm/test/CodeGen/SystemZ/zos-ppa1.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-ppa1.ll
@@ -15,8 +15,6 @@
 ; CHECK:  DC XL4'00000008'
 ; CHECK:  ENTRY void_test
 ; CHECK: L#func_end0 DS 0H
-; CHECK: stdin#C CSECT
-; CHECK: C_CODE64 CATTR
 ; CHECK: * PPA1
 ; CHECK: L#PPA1_void_test_0 DS 0H
 ; CHECK: * Version
diff --git a/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll b/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
index 2b52701b141a1..46fea4016f76f 100644
--- a/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
@@ -15,9 +15,6 @@
 ; CHECK64: aghi  4,192
 ; CHECK64: b 2(7)
 
-; CHECK64: L#PPA1_func0_0 DS 0H
-; CHECK64: * Length/4 of Parms
-; CHECK64:  DC XL2'0000'
 define void @func0() {
   call i64 (i64) @fun(i64 10) 
   ret void
@@ -32,9 +29,6 @@ define void @func0() {
 ; CHECK64: aghi  4,160
 ; CHECK64: b 2(7)
 
-; CHECK64: L#PPA1_func1_0 DS 0H
-; CHECK64: * Length/4 of Parms
-; CHECK64:  DC XL2'0002'
 define void @func1(ptr %ptr) {
   %l01 = load volatile i64, ptr %ptr
   %l02 = load volatile i64, ptr %ptr
@@ -366,9 +360,6 @@ define void @large_stack0() {
 ; CHECK64: stmg  6,7,2064(4)
 ; CHECK64: lgr 3,0
 
-; CHECK64: L#PPA1_large_stack1_0 DS 0H
-; CHECK64: * Length/4 of Parms
-; CHECK64:  DC XL2'0006'
 define void @large_stack1(i64 %n1, i64 %n2, i64 %n3) {
   %arr = alloca [131072 x i64], align 8
   call i64 (ptr, i64, i64, i64) @fun3(ptr %arr,
@@ -426,6 +417,7 @@ define void @large_stack3() {
 ; CHECK: aghik	3,1,-4
 ; CHECK-NOT: aghi  4,
 ; CHECK-NOT: lmg
+; CHECK-LABEL: L#func_end20 DS 0H
 define i64 @leaf_func0(i64 %a, i64 %b, i64 %c) {
   %n = add i64 %a, %b
   %m = mul i64 %n, %c
@@ -433,22 +425,11 @@ define i64 @leaf_func0(i64 %a, i64 %b, i64 %c) {
   ret i64 %o
 }
 
-
-; =============================
-;     Tests for PPA1 Fields
-; =============================
-; CHECK-LABEL: named_func DS 0H
-; CHECK:      * PPA1 Flags 4
-; CHECK-NEXT: *   Bit 7: 1 = Name Length and Name
-; CHECK-NEXT:  DC XL1'81'
 define i64 @named_func(i64 %arg) {
   %sum = add i64 1, %arg
   ret i64 %sum
 }
 
-; CHECK-LABEL: __unnamed_1 DS 0H
-; CHECK:      * PPA1 Flags 4
-; CHECK-NEXT:  DC XL1'80'
 define void @""(ptr %p) {
   call i64 (ptr) @fun1(ptr %p)
   ret void
@@ -460,3 +441,28 @@ declare i64 @fun1(ptr %ptr)
 declare i64 @fun2(i64 %n, ptr %arr0, ptr %arr1)
 declare i64 @fun3(ptr %ptr, i64 %n1, i64 %n2, i64 %n3)
 declare i64 @fun4(ptr %ptr0, ptr %ptr1, i64 %n1, i64 %n2, i64 %n3)
+
+; =============================
+;     Tests for PPA1 Fields
+; =============================
+
+; CHECK64: L#PPA1_func0_0 DS 0H
+; CHECK64: * Length/4 of Parms
+; CHECK64:  DC XL2'0000'
+
+; CHECK64: L#PPA1_func1_0 DS 0H
+; CHECK64: * Length/4 of Parms
+; CHECK64:  DC XL2'0002'
+
+; CHECK64: L#PPA1_large_stack1_0 DS 0H
+; CHECK64: * Length/4 of Parms
+; CHECK64:  DC XL2'0006'
+
+; CHECK-LABEL: L#PPA1_named_func_0 DS 0H
+; CHECK:      * PPA1 Flags 4
+; CHECK-NEXT: *   Bit 7: 1 = Name Length and Name
+; CHECK-NEXT:  DC XL1'81'
+
+; CHECK-LABEL: L#PPA1_0 DS 0H
+; CHECK:      * PPA1 Flags 4
+; CHECK-NEXT:  DC XL1'80'
diff --git a/llvm/test/CodeGen/SystemZ/zos-section-1.ll b/llvm/test/CodeGen/SystemZ/zos-section-1.ll
index ac9b6fc362c36..c5020fcb9f24a 100644
--- a/llvm/test/CodeGen/SystemZ/zos-section-1.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-section-1.ll
@@ -115,7 +115,7 @@ entry:
 ; ESD record, type LD.
 ; The name is me.
 ; CHECK-NEXT: 000370 03 00 00 02 [[ME:00 00 00 0a]] [[C_CODE64]] 00 00 00 00
-; CHECK-NEXT: 000380 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000380 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00
 ; CHECK-NEXT: 000390 00 00 00 00 00 00 00 00 01 00 00 00 [[TESTS]]
 ; CHECK-NEXT: 0003a0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 02
 ; CHECK-NEXT: 0003b0 00 04 20 00 00 00 00 02 94 85 00 00 00 00 00 00
@@ -131,36 +131,36 @@ entry:
 ; Text record for the code section C_CODE64.
 ; The regular expression matches the lower byte of the length.
 ; CHECK-NEXT: 000410 03 11 00 00 [[C_CODE64]] 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000420 00 00 00 00 00 00 00 {{..}} 00 c3 00 c5 00 c5 00 f1
+; CHECK-NEXT: 000420 00 00 00 00 00 00 00 {{..}} 03 e7 22 04 00 00 00 00
 
 ; Text record for the section .&ppa2.
-; CHECK:      0004b0 03 10 00 00 [[PPA2]] 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 0004c0 00 00 00 00 00 00 00 {{..}} {{.*}}
+; CHECK:      000500 03 10 00 00 [[PPA2]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000510 00 00 00 00 00 00 00 {{..}} {{.*}}
 
 ; Text record for the ADA section test#S.
-; CHECK:      000500 03 10 00 00 [[TESTS]] 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000510 00 00 00 00 00 00 00 {{..}} {{.*}}
+; CHECK:      000550 03 10 00 00 [[TESTS]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000560 00 00 00 00 00 00 00 {{..}} {{.*}}
 
 ; Text record for the section B_IDRL.
-; CHECK:      000550 03 10 00 01 [[BIDRL]] 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000560 00 00 00 00 00 00 00 {{..}} {{.*}}
+; CHECK:      0005a0 03 10 00 01 [[BIDRL]] 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0005b0 00 00 00 00 00 00 00 {{..}} {{.*}}
 
 ; The relocation data directory.
-; CHECK:      0005a0 03 21 00 00 00 5c 00 00 02 00 04 00 00 00 00 00
-; CHECK-NEXT: 0005b0 00 08 00 00 00 02 00 00 00 5a 60 00 00 00 04 00
-; CHECK-NEXT: 0005c0 00 00 00 00 00 09 00 00 00 00 08 00 00 00 00 00
-; CHECK-NEXT: 0005d0 00 08 00 00 00 04 00 00 00 00 60 00 02 00 08 00
-; CHECK-NEXT: 0005e0 00 00 00 00 00 09 20 70 01 00 08 00 00 00 00 00
+; CHECK:      0005f0 03 21 00 00 00 5c 00 00 02 00 04 00 00 00 00 00
+; CHECK-NEXT: 000600 00 08 00 00 00 02 00 00 00 04 60 00 00 00 04 00
+; CHECK-NEXT: 000610 00 00 00 00 00 09 00 00 00 00 08 00 00 00 00 00
+; CHECK-NEXT: 000620 00 08 00 00 00 04 00 00 00 00 60 00 02 00 08 00
+; CHECK-NEXT: 000630 00 00 00 00 00 09 20 70 01 00 08 00 00 00 00 00
 ; Continuation of the relocation data directory.
-; CHECK-NEXT: 0005f0 03 22 00 00 0b 00 00 00 06 c0 00 01 00 08 00 00
-; CHECK-NEXT: 000600 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000610 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000620 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000630 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-
-; End record.
-; CHECK:      000640 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-; CHECK-NEXT: 000650 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 000640 03 22 00 00 0b 00 00 00 06 c0 00 01 00 08 00 00
+; CHECK-NEXT: 000650 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00
 ; CHECK-NEXT: 000660 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ; CHECK-NEXT: 000670 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ; CHECK-NEXT: 000680 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+; End record.
+; CHECK:      000690 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0006a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0006b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0006c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+; CHECK-NEXT: 0006d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
diff --git a/llvm/test/CodeGen/SystemZ/zos-simple-test.ll b/llvm/test/CodeGen/SystemZ/zos-simple-test.ll
index a185fc7016a07..381d058e8d82e 100644
--- a/llvm/test/CodeGen/SystemZ/zos-simple-test.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-simple-test.ll
@@ -5,12 +5,12 @@
 @a = global i32 0, align 4
 
 define signext i32 @main() {
-; CHECK: stdin#C CSECT
-; CHECK: C_CODE64 CATTR ALIGN(3),FILL(0),READONLY,RMODE(64)
-; CHECK: main DS 0H
-; CHECK: stdin#C CSECT
-; CHECK: C_WSA64 CATTR ALIGN(2),FILL(0),DEFLOAD,NOTEXECUTABLE,RMODE(64),PART(a)
-; CHECK: a XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(EXPORT)
+; CHECK:      stdin#C CSECT
+; CHECK-NEXT: C_CODE64 CATTR ALIGN(3),FILL(0),READONLY,RMODE(64)
+; CHECK:      main DS 0H
+; CHECK:      a CSECT
+; CHECK-NEXT: C_WSA64 CATTR ALIGN(2),FILL(0),DEFLOAD,NOTEXECUTABLE,RMODE(64),PART(a)
+; CHECK-NEXT: a XATTR LINKAGE(XPLINK),REFERENCE(DATA),SCOPE(EXPORT)
 entry:
   ret i32 0
 }
diff --git a/llvm/test/CodeGen/SystemZ/zos-symbol-2.ll b/llvm/test/CodeGen/SystemZ/zos-symbol-2.ll
index bccbe7c672be7..7df5c8dc4b9c9 100644
--- a/llvm/test/CodeGen/SystemZ/zos-symbol-2.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-symbol-2.ll
@@ -37,7 +37,7 @@ entry:
 ;  .1 is flag (record is continued)
 ;  00 is version
 ; CHECKREL:      000690 03 21 00 00 00 60 00 00 02 00 04 00 00 00 00 00
-; CHECKREL-NEXT: 0006a0 00 0b 00 00 00 02 00 00 00 4e 60 00 00 00 04 00
+; CHECKREL-NEXT: 0006a0 00 0b 00 00 00 02 00 00 00 04 60 00 00 00 04 00
 ; CHECKREL-NEXT: 0006b0 00 00 00 00 00 0c 00 00 00 00 08 00 00 00 00 00
 ; CHECKREL-NEXT: 0006c0 00 0b 00 00 00 04 00 00 00 00 60 00 02 00 08 00
 ; CHECKREL-NEXT: 0006d0 00 00 00 00 00 0c 20 00 00 00 08 00 00 00 00 00

>From a64ab2449cda1cda8f00a7e70b0d3b9491ee5225 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Tue, 10 Mar 2026 14:49:54 -0400
Subject: [PATCH 2/4] Reorder code to avoid globals

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 14 ++++++--------
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |  5 ++---
 2 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 786476dab16f0..ca4486df64a15 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1375,10 +1375,7 @@ void SystemZAsmPrinter::emitFunctionBodyEnd() {
     // is used. This is needed to calculate the size of the function.
     MCSymbol *FnEndSym = createTempSymbol("func_end");
     OutStreamer->emitLabel(FnEndSym);
-    calculatePPA1(FnEndSym);
-
-    CurrentFnPPA1Sym = nullptr;
-    CurrentFnEPMarkerSym = nullptr;
+    DeferredPPA1.back().FnEnd = FnEndSym;
   }
 }
 
@@ -1590,7 +1587,7 @@ void SystemZAsmPrinter::emitPPA1(PPA1Info &Info) {
   OutStreamer->emitAbsoluteSymbolDiff(Info.EPMarker, Info.PPA1, 4);
 }
 
-void SystemZAsmPrinter::calculatePPA1(MCSymbol *FnEndSym) {
+void SystemZAsmPrinter::calculatePPA1(MCSymbol *CurrentFnPPA1Sym, MCSymbol *CurrentFnEPMarkerSym) {
   assert(PPA2Sym != nullptr && "PPA2 Symbol not defined");
 
   PPA1Info Info;
@@ -1692,7 +1689,7 @@ void SystemZAsmPrinter::calculatePPA1(MCSymbol *FnEndSym) {
     Info.Name = MF->getFunction().getName();
   Info.PPA1 = CurrentFnPPA1Sym;
   Info.EPMarker = CurrentFnEPMarkerSym;
-  Info.FnEnd = FnEndSym;
+  Info.FnEnd = nullptr; // Filled later.
   Info.PersonalityRoutine = PersonalityRoutine;
   Info.GCCEH = GCCEH;
   Info.CallFrameSize = MFFrame.getMaxCallFrameSize();
@@ -1902,10 +1899,11 @@ void SystemZAsmPrinter::emitFunctionEntryLabel() {
                       ? Twine(MF->getFunction().getName()).concat("_").str()
                       : "");
 
-    CurrentFnEPMarkerSym =
+    MCSymbol *CurrentFnEPMarkerSym =
         OutContext.createTempSymbol(Twine("EPM_").concat(N).str(), true);
-    CurrentFnPPA1Sym =
+    MCSymbol *CurrentFnPPA1Sym =
         OutContext.createTempSymbol(Twine("PPA1_").concat(N).str(), true);
+    calculatePPA1(CurrentFnPPA1Sym, CurrentFnEPMarkerSym);
 
     // EntryPoint Marker
     const MachineFrameInfo &MFFrame = MF->getFrameInfo();
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index 0456ccee386b6..e551d39a5a953 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -29,8 +29,6 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   static char ID;
 
 private:
-  MCSymbol *CurrentFnPPA1Sym;     // PPA1 Symbol.
-  MCSymbol *CurrentFnEPMarkerSym; // Entry Point Marker.
   MCSymbol *PPA2Sym;
 
   SystemZTargetStreamer *getTargetStreamer() {
@@ -120,7 +118,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
   };
   SmallVector<PPA1Info, 0> DeferredPPA1;
 
-  void calculatePPA1(MCSymbol *FnEndSym);
+  void calculatePPA1(MCSymbol *CurrentFnPPA1Sym,
+                     MCSymbol *CurrentFnEPMarkerSym);
   void emitPPA1(PPA1Info &Info);
   void emitPPA2(Module &M);
   void emitADASection();

>From 69c14a39cbbb1d23d5ab91a2d132a74185abd5ca Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Fri, 10 Apr 2026 11:38:13 -0400
Subject: [PATCH 3/4] Move place where the function end symbol is generated.

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index ca4486df64a15..a4ba80f95fc96 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1373,9 +1373,7 @@ void SystemZAsmPrinter::emitFunctionBodyEnd() {
   if (TM.getTargetTriple().isOSzOS()) {
     // Emit symbol for the end of function if the z/OS target streamer
     // is used. This is needed to calculate the size of the function.
-    MCSymbol *FnEndSym = createTempSymbol("func_end");
-    OutStreamer->emitLabel(FnEndSym);
-    DeferredPPA1.back().FnEnd = FnEndSym;
+    OutStreamer->emitLabel(DeferredPPA1.back().FnEnd);
   }
 }
 
@@ -1689,7 +1687,7 @@ void SystemZAsmPrinter::calculatePPA1(MCSymbol *CurrentFnPPA1Sym, MCSymbol *Curr
     Info.Name = MF->getFunction().getName();
   Info.PPA1 = CurrentFnPPA1Sym;
   Info.EPMarker = CurrentFnEPMarkerSym;
-  Info.FnEnd = nullptr; // Filled later.
+  Info.FnEnd = createTempSymbol("func_end");
   Info.PersonalityRoutine = PersonalityRoutine;
   Info.GCCEH = GCCEH;
   Info.CallFrameSize = MFFrame.getMaxCallFrameSize();

>From 906cab4956f270fb6d86e701313660529d4eab38 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Fri, 10 Apr 2026 12:09:35 -0400
Subject: [PATCH 4/4] Break up OffsetFPR, OffsetVR, and FrameReg.

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 61 +++++++------------
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |  3 +
 .../CodeGen/SystemZ/zos-prologue-epilog.ll    |  2 +-
 3 files changed, 26 insertions(+), 40 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index a4ba80f95fc96..ee31213618ce7 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -1534,16 +1534,18 @@ void SystemZAsmPrinter::emitPPA1(PPA1Info &Info) {
     OutStreamer->AddComment("AR mask");
     OutStreamer->emitInt16(0); // AR Mask, unused currently.
     OutStreamer->AddComment("FPR Save Area Locator");
-    OutStreamer->AddComment(Twine("  Bit 0-3: Register R")
-                                .concat(utostr(Info.FrameAndFPROffset >> 28))
-                                .str());
+    uint64_t FPRSaveAreaOffset = Info.OffsetFPR;
+    assert(FPRSaveAreaOffset < 0x10000000 && "Offset out of range");
+    FPRSaveAreaOffset &= 0x0FFFFFFF; // Lose top 4 bits.
     OutStreamer->AddComment(
-        Twine("  Bit 4-31: Offset ")
-            .concat(utostr(Info.FrameAndFPROffset & 0x0FFFFFFF))
-            .str());
-    OutStreamer->emitInt32(Info.FrameAndFPROffset); // Offset to FPR save area
-                                                    // with register to add
-                                                    // value to (alloca reg).
+        Twine("  Bit 0-3: Register R").concat(utostr(Info.FrameReg)).str());
+    OutStreamer->AddComment(Twine("  Bit 4-31: Offset ")
+                                .concat(utostr(FPRSaveAreaOffset))
+                                .str());
+    OutStreamer->emitInt32(FPRSaveAreaOffset |
+                           (Info.FrameReg << 28)); // Offset to FPR save area
+                                                   // with register to add
+                                                   // value to (alloca reg).
   }
 
   // Emit saved VR mask to VR save area.
@@ -1552,15 +1554,15 @@ void SystemZAsmPrinter::emitPPA1(PPA1Info &Info) {
     OutStreamer->emitInt8(Info.SavedVRMask);
     OutStreamer->emitInt8(0);  // Reserved.
     OutStreamer->emitInt16(0); // Also reserved.
+    uint64_t VRSaveAreaOffset = Info.OffsetVR;
+    assert(VRSaveAreaOffset < 0x10000000 && "Offset out of range");
+    VRSaveAreaOffset &= 0x0FFFFFFF; // Lose top 4 bits.
     OutStreamer->AddComment("VR Save Area Locator");
-    OutStreamer->AddComment(Twine("  Bit 0-3: Register R")
-                                .concat(utostr(Info.FrameAndVROffset >> 28))
-                                .str());
     OutStreamer->AddComment(
-        Twine("  Bit 4-31: Offset ")
-            .concat(utostr(Info.FrameAndVROffset & 0x0FFFFFFF))
-            .str());
-    OutStreamer->emitInt32(Info.FrameAndVROffset);
+        Twine("  Bit 0-3: Register R").concat(utostr(Info.FrameReg)).str());
+    OutStreamer->AddComment(
+        Twine("  Bit 4-31: Offset ").concat(utostr(VRSaveAreaOffset)).str());
+    OutStreamer->emitInt32(VRSaveAreaOffset | (Info.FrameReg << 28));
   }
 
   // Emit C++ EH information block.
@@ -1592,7 +1594,7 @@ void SystemZAsmPrinter::calculatePPA1(MCSymbol *CurrentFnPPA1Sym, MCSymbol *Curr
 
   const TargetRegisterInfo *TRI = MF->getRegInfo().getTargetRegisterInfo();
   const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
-  const auto TargetHasVector = Subtarget.hasVector();
+  //const auto TargetHasVector = Subtarget.hasVector();
 
   const SystemZMachineFunctionInfo *ZFI =
       MF->getInfo<SystemZMachineFunctionInfo>();
@@ -1650,26 +1652,6 @@ void SystemZAsmPrinter::calculatePPA1(MCSymbol *CurrentFnPPA1Sym, MCSymbol *Curr
   assert(AllocaReg < 16 && "Can't have alloca register larger than 15");
   (void)AllocaReg;
 
-  // Build FPR save area offset.
-  uint32_t FrameAndFPROffset = 0;
-  if (SavedFPRMask) {
-    uint64_t FPRSaveAreaOffset = OffsetFPR;
-    assert(FPRSaveAreaOffset < 0x10000000 && "Offset out of range");
-
-    FrameAndFPROffset = FPRSaveAreaOffset & 0x0FFFFFFF; // Lose top 4 bits.
-    FrameAndFPROffset |= FrameReg << 28;                // Put into top 4 bits.
-  }
-
-  // Build VR save area offset.
-  uint32_t FrameAndVROffset = 0;
-  if (TargetHasVector && SavedVRMask) {
-    uint64_t VRSaveAreaOffset = OffsetVR;
-    assert(VRSaveAreaOffset < 0x10000000 && "Offset out of range");
-
-    FrameAndVROffset = VRSaveAreaOffset & 0x0FFFFFFF; // Lose top 4 bits.
-    FrameAndVROffset |= FrameReg << 28;               // Put into top 4 bits.
-  }
-
   MCSymbol *PersonalityRoutine = nullptr;
   MCSymbol *GCCEH = nullptr;
   if (!MF->getLandingPads().empty()) {
@@ -1690,13 +1672,14 @@ void SystemZAsmPrinter::calculatePPA1(MCSymbol *CurrentFnPPA1Sym, MCSymbol *Curr
   Info.FnEnd = createTempSymbol("func_end");
   Info.PersonalityRoutine = PersonalityRoutine;
   Info.GCCEH = GCCEH;
+  Info.OffsetFPR = OffsetFPR;
+  Info.OffsetVR = OffsetVR;
   Info.CallFrameSize = MFFrame.getMaxCallFrameSize();
   Info.SizeOfFnParams = ZFI->getSizeOfFnParams();
-  Info.FrameAndFPROffset = FrameAndFPROffset;
-  Info.FrameAndVROffset = FrameAndVROffset;
   Info.SavedGPRMask = SavedGPRMask;
   Info.SavedFPRMask = SavedFPRMask;
   Info.SavedVRMask = SavedVRMask;
+  Info.FrameReg = FrameReg;
   Info.IsVarArg = MF->getFunction().isVarArg();
   Info.HasStackProtector = MFFrame.hasStackProtectorIndex();
 
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index e551d39a5a953..bcc608c09dabd 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -105,6 +105,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
     MCSymbol *EPMarker = nullptr; // Symbol marking entry point.
     MCSymbol *PersonalityRoutine = nullptr;
     MCSymbol *GCCEH = nullptr;
+    int64_t OffsetFPR = 0;
+    int64_t OffsetVR = 0;
     uint64_t CallFrameSize = 0;
     unsigned SizeOfFnParams = 0;
     uint32_t FrameAndFPROffset;
@@ -112,6 +114,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
     uint16_t SavedGPRMask = 0;
     uint16_t SavedFPRMask = 0;
     uint8_t SavedVRMask = 0;
+    uint8_t FrameReg = 0;
     bool HasArgAreaLength = false;
     bool IsVarArg = false;
     bool HasStackProtector = false;
diff --git a/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll b/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
index 46fea4016f76f..29be921a6935b 100644
--- a/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
+++ b/llvm/test/CodeGen/SystemZ/zos-prologue-epilog.ll
@@ -417,7 +417,7 @@ define void @large_stack3() {
 ; CHECK: aghik	3,1,-4
 ; CHECK-NOT: aghi  4,
 ; CHECK-NOT: lmg
-; CHECK-LABEL: L#func_end20 DS 0H
+; CHECK-LABEL: L#func_end22 DS 0H
 define i64 @leaf_func0(i64 %a, i64 %b, i64 %c) {
   %n = add i64 %a, %b
   %m = mul i64 %n, %c



More information about the llvm-commits mailing list