[llvm] [SystemZ] Split SystemZAsmPrinter into 2 classes - ELF and XPLink (PR #214343)

Yusra Syeda via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 25 07:10:47 PDT 2026


https://github.com/ysyeda updated https://github.com/llvm/llvm-project/pull/214343

>From d4b158f81d79b3e6297e947774b50f31f4156a6e Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Wed, 5 Aug 2026 17:19:53 -0400
Subject: [PATCH 1/5] split systemzasmprinter into 2 classes for elf and xplink

---
 llvm/lib/Target/SystemZ/CMakeLists.txt        |    2 +
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp | 1291 +----------------
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |  103 +-
 .../Target/SystemZ/SystemZELFAsmPrinter.cpp   |  478 ++++++
 .../lib/Target/SystemZ/SystemZELFAsmPrinter.h |   54 +
 .../SystemZ/SystemZXPLINKAsmPrinter.cpp       |  864 +++++++++++
 .../Target/SystemZ/SystemZXPLINKAsmPrinter.h  |  127 ++
 7 files changed, 1545 insertions(+), 1374 deletions(-)
 create mode 100644 llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
 create mode 100644 llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.h
 create mode 100644 llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
 create mode 100644 llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.h

diff --git a/llvm/lib/Target/SystemZ/CMakeLists.txt b/llvm/lib/Target/SystemZ/CMakeLists.txt
index 6d94a755322df..1dd74c3ff8d5c 100644
--- a/llvm/lib/Target/SystemZ/CMakeLists.txt
+++ b/llvm/lib/Target/SystemZ/CMakeLists.txt
@@ -18,6 +18,8 @@ add_public_tablegen_target(SystemZCommonTableGen)
 
 add_llvm_target(SystemZCodeGen
   SystemZAsmPrinter.cpp
+  SystemZELFAsmPrinter.cpp
+  SystemZXPLINKAsmPrinter.cpp
   SystemZCallingConv.cpp
   SystemZConstantPoolValue.cpp
   SystemZCopyPhysRegs.cpp
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 235d8eea84ec5..d4c274bb6bd14 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -12,32 +12,21 @@
 //===----------------------------------------------------------------------===//
 
 #include "SystemZAsmPrinter.h"
+#include "SystemZELFAsmPrinter.h"
+#include "SystemZXPLINKAsmPrinter.h"
 #include "MCTargetDesc/SystemZGNUInstPrinter.h"
 #include "MCTargetDesc/SystemZHLASMInstPrinter.h"
 #include "MCTargetDesc/SystemZMCAsmInfo.h"
 #include "MCTargetDesc/SystemZMCTargetDesc.h"
-#include "SystemZConstantPoolValue.h"
 #include "SystemZMCInstLower.h"
+#include "SystemZSubtarget.h"
 #include "TargetInfo/SystemZTargetInfo.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/BinaryFormat/GOFF.h"
-#include "llvm/CodeGen/MachineModuleInfoImpls.h"
-#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
-#include "llvm/IR/GlobalVariable.h"
-#include "llvm/IR/Mangler.h"
-#include "llvm/IR/Module.h"
-#include "llvm/MC/MCDirectives.h"
+#include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInstBuilder.h"
-#include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSymbolGOFF.h"
 #include "llvm/MC/TargetRegistry.h"
-#include "llvm/Support/Chrono.h"
 #include "llvm/Support/Compiler.h"
-#include "llvm/Support/ConvertEBCDIC.h"
-#include "llvm/Support/FormatVariadic.h"
 
 using namespace llvm;
 
@@ -81,18 +70,6 @@ static MCInst lowerRIEfLow(const MachineInstr *MI, unsigned Opcode) {
     .addImm(MI->getOperand(5).getImm());
 }
 
-static const MCSymbolRefExpr *getTLSGetOffset(MCContext &Context) {
-  StringRef Name = "__tls_get_offset";
-  return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name),
-                                 SystemZ::S_PLT, Context);
-}
-
-static const MCSymbolRefExpr *getGlobalOffsetTable(MCContext &Context) {
-  StringRef Name = "_GLOBAL_OFFSET_TABLE_";
-  return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name),
-                                 Context);
-}
-
 // MI is an instruction that accepts an optional alignment hint,
 // and which was already lowered to LoweredMI.  If the alignment
 // of the original memory operand is known, update LoweredMI to
@@ -103,10 +80,9 @@ static void lowerAlignmentHint(const MachineInstr *MI, MCInst &LoweredMI,
     return;
 
   Align Alignment = Align(16);
-  for (MachineInstr::mmo_iterator MMOI = MI->memoperands_begin(),
-         EE = MI->memoperands_end(); MMOI != EE; ++MMOI)
-    if ((*MMOI)->getAlign() < Alignment)
-      Alignment = (*MMOI)->getAlign();
+  for (const MachineMemOperand *MMO : MI->memoperands())
+    if (MMO->getAlign() < Alignment)
+      Alignment = MMO->getAlign();
 
   unsigned AlignmentHint = 0;
   if (Alignment >= Align(16))
@@ -160,92 +136,6 @@ static MCInst lowerVecEltInsertion(const MachineInstr *MI, unsigned Opcode) {
       .addImm(0);
 }
 
-bool SystemZAsmPrinter::doInitialization(Module &M) {
-  SM.reset();
-
-  // In HLASM, the only way to represent aliases is to use the
-  // extra-label-at-definition strategy. This is similar to the AIX
-  // implementation with the additional caveat that all symbol attributes must
-  // be emitted before the label is emitted.
-  if (TM.getTargetTriple().isOSzOS()) {
-    // Construct an aliasing list for each GlobalObject.
-    for (const auto &Alias : M.aliases()) {
-      const GlobalObject *Aliasee = Alias.getAliaseeObject();
-      if (!Aliasee)
-        OutContext.reportError(
-            {}, "Alias without a base object is not yet supported on z/OS.");
-
-      bool IsFunc = isa<Function>(Aliasee->stripPointerCasts());
-      if (IsFunc) {
-        if (Alias.hasWeakLinkage() || Alias.hasLinkOnceLinkage())
-          OutContext.reportError({},
-                                 "Weak alias/reference not supported on z/OS");
-
-        GOAliasMap[Aliasee].push_back(&Alias);
-      } else
-        OutContext.reportError(
-            {}, "Only aliases to functions is supported in GOFF.");
-    }
-  }
-  return AsmPrinter::doInitialization(M);
-}
-
-// The XPLINK ABI requires that a no-op encoding the call type is emitted after
-// each call to a subroutine. This information can be used by the called
-// function to determine its entry point, e.g. for generating a backtrace. The
-// call type is encoded as a register number in the bcr instruction. See
-// enumeration CallType for the possible values.
-void SystemZAsmPrinter::emitCallInformation(CallType CT) {
-  EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::BCRAsm)
-                     .addImm(0)
-                     .addReg(SystemZMC::GR64Regs[static_cast<unsigned>(CT)]));
-}
-
-uint32_t SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MCSymbol *Sym,
-                                                            unsigned SlotKind) {
-  auto Key = std::make_pair(Sym, SlotKind);
-  auto It = Displacements.find(Key);
-
-  if (It != Displacements.end())
-    return (*It).second;
-
-  // Determine length of descriptor.
-  uint32_t Length;
-  switch (SlotKind) {
-  case SystemZII::MO_ADA_DIRECT_FUNC_DESC:
-    Length = 2 * PointerSize;
-    break;
-  default:
-    Length = PointerSize;
-    break;
-  }
-
-  uint32_t Displacement = NextDisplacement;
-  Displacements[std::make_pair(Sym, SlotKind)] = NextDisplacement;
-  NextDisplacement += Length;
-
-  return Displacement;
-}
-
-uint32_t
-SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MachineOperand MO) {
-  MCSymbol *Sym;
-  if (MO.getType() == MachineOperand::MO_GlobalAddress) {
-    const GlobalValue *GV = MO.getGlobal();
-    Sym = MO.getParent()->getMF()->getTarget().getSymbol(GV);
-    assert(Sym && "No symbol");
-  } else if (MO.getType() == MachineOperand::MO_ExternalSymbol) {
-    const char *SymName = MO.getSymbolName();
-    Sym = MO.getParent()->getMF()->getContext().getOrCreateSymbol(SymName);
-    assert(Sym && "No symbol");
-  } else
-    llvm_unreachable("Unexpected operand type");
-
-  unsigned ADAslotType = MO.getTargetFlags();
-  return insert(Sym, ADAslotType);
-}
-
 void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   SystemZ_MC::verifyInstructionPredicates(MI->getOpcode(),
                                           getSubtargetInfo().getFeatureBits());
@@ -258,13 +148,6 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
       .addReg(SystemZ::R14D);
     break;
 
-  case SystemZ::Return_XPLINK:
-    LoweredMI = MCInstBuilder(SystemZ::B)
-      .addReg(SystemZ::R7D)
-      .addImm(2)
-      .addReg(0);
-    break;
-
   case SystemZ::CondReturn:
     LoweredMI = MCInstBuilder(SystemZ::BCR)
       .addImm(MI->getOperand(0).getImm())
@@ -272,15 +155,6 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
       .addReg(SystemZ::R14D);
     break;
 
-  case SystemZ::CondReturn_XPLINK:
-    LoweredMI = MCInstBuilder(SystemZ::BC)
-      .addImm(MI->getOperand(0).getImm())
-      .addImm(MI->getOperand(1).getImm())
-      .addReg(SystemZ::R7D)
-      .addImm(2)
-      .addReg(0);
-    break;
-
   case SystemZ::CRBReturn:
     LoweredMI = MCInstBuilder(SystemZ::CRB)
       .addReg(MI->getOperand(0).getReg())
@@ -353,90 +227,6 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
       .addImm(0);
     break;
 
-  case SystemZ::CallBRASL_XPLINK64:
-    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
-                                     .addReg(SystemZ::R7D)
-                                     .addExpr(Lower.getExpr(MI->getOperand(0),
-                                                            SystemZ::S_None)));
-    emitCallInformation(CallType::BRASL7);
-    return;
-
-  case SystemZ::CallBASR_XPLINK64:
-    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
-                                     .addReg(SystemZ::R7D)
-                                     .addReg(MI->getOperand(0).getReg()));
-    emitCallInformation(CallType::BASR76);
-    return;
-
-  case SystemZ::CallBASR_STACKEXT:
-    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
-                                     .addReg(SystemZ::R3D)
-                                     .addReg(MI->getOperand(0).getReg()));
-    emitCallInformation(CallType::BASR33);
-    return;
-
-  case SystemZ::ADA_ENTRY_VALUE:
-  case SystemZ::ADA_ENTRY: {
-    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
-    const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
-    uint32_t Disp = ADATable.insert(MI->getOperand(1));
-    Register TargetReg = MI->getOperand(0).getReg();
-
-    Register ADAReg = MI->getOperand(2).getReg();
-    Disp += MI->getOperand(3).getImm();
-    bool LoadAddr = MI->getOpcode() == SystemZ::ADA_ENTRY;
-
-    unsigned Op0 = LoadAddr ? SystemZ::LA : SystemZ::LG;
-    unsigned Op = TII->getOpcodeForOffset(Op0, Disp);
-
-    Register IndexReg = 0;
-    if (!Op) {
-      if (TargetReg != ADAReg) {
-        IndexReg = TargetReg;
-        // Use TargetReg to store displacement.
-        EmitToStreamer(
-            *OutStreamer,
-            MCInstBuilder(SystemZ::LLILF).addReg(TargetReg).addImm(Disp));
-      } else
-        EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::ALGFI)
-                                         .addReg(TargetReg)
-                                         .addReg(TargetReg)
-                                         .addImm(Disp));
-      Disp = 0;
-      Op = Op0;
-    }
-    EmitToStreamer(*OutStreamer, MCInstBuilder(Op)
-                                     .addReg(TargetReg)
-                                     .addReg(ADAReg)
-                                     .addImm(Disp)
-                                     .addReg(IndexReg));
-
-    return;
-  }
-  case SystemZ::CallBRASL:
-    LoweredMI = MCInstBuilder(SystemZ::BRASL)
-                    .addReg(SystemZ::R14D)
-                    .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_PLT));
-    break;
-
-  case SystemZ::CallBASR:
-    LoweredMI = MCInstBuilder(SystemZ::BASR)
-      .addReg(SystemZ::R14D)
-      .addReg(MI->getOperand(0).getReg());
-    break;
-
-  case SystemZ::CallJG:
-    LoweredMI = MCInstBuilder(SystemZ::JG)
-                    .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_PLT));
-    break;
-
-  case SystemZ::CallBRCL:
-    LoweredMI = MCInstBuilder(SystemZ::BRCL)
-                    .addImm(MI->getOperand(0).getImm())
-                    .addImm(MI->getOperand(1).getImm())
-                    .addExpr(Lower.getExpr(MI->getOperand(2), SystemZ::S_PLT));
-    break;
-
   case SystemZ::CallBR:
     LoweredMI = MCInstBuilder(SystemZ::BR)
       .addReg(MI->getOperand(0).getReg());
@@ -521,28 +311,6 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
       .addImm(0);
     break;
 
-  case SystemZ::TLS_GDCALL:
-    LoweredMI =
-        MCInstBuilder(SystemZ::BRASL)
-            .addReg(SystemZ::R14D)
-            .addExpr(getTLSGetOffset(MF->getContext()))
-            .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_TLSGD));
-    break;
-
-  case SystemZ::TLS_LDCALL:
-    LoweredMI =
-        MCInstBuilder(SystemZ::BRASL)
-            .addReg(SystemZ::R14D)
-            .addExpr(getTLSGetOffset(MF->getContext()))
-            .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_TLSLDM));
-    break;
-
-  case SystemZ::GOT:
-    LoweredMI = MCInstBuilder(SystemZ::LARL)
-      .addReg(MI->getOperand(0).getReg())
-      .addExpr(getGlobalOffsetTable(MF->getContext()));
-    break;
-
   case SystemZ::IILF64:
     LoweredMI = MCInstBuilder(SystemZ::IILF)
       .addReg(SystemZMC::getRegAsGR32(MI->getOperand(0).getReg()))
@@ -713,26 +481,6 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
     }
     break;
 
-  case TargetOpcode::FENTRY_CALL:
-    LowerFENTRY_CALL(*MI, Lower);
-    return;
-
-  case TargetOpcode::STACKMAP:
-    LowerSTACKMAP(*MI);
-    return;
-
-  case TargetOpcode::PATCHPOINT:
-    LowerPATCHPOINT(*MI, Lower);
-    return;
-
-  case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
-    LowerPATCHABLE_FUNCTION_ENTER(*MI, Lower);
-    return;
-
-  case TargetOpcode::PATCHABLE_RET:
-    LowerPATCHABLE_RET(*MI, Lower);
-    return;
-
   case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
     llvm_unreachable("PATCHABLE_FUNCTION_EXIT should never be emitted");
 
@@ -778,13 +526,6 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   case SystemZ::EH_SjLj_Setup:
     return;
 
-  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);
     break;
@@ -792,411 +533,6 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) {
   EmitToStreamer(*OutStreamer, LoweredMI);
 }
 
-// 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,
-                        unsigned NumBytes, const MCSubtargetInfo &STI) {
-  if (NumBytes < 2) {
-    llvm_unreachable("Zero nops?");
-    return 0;
-  }
-  else if (NumBytes < 4) {
-    OutStreamer.emitInstruction(
-        MCInstBuilder(SystemZ::BCRAsm).addImm(0).addReg(SystemZ::R0D), STI);
-    return 2;
-  }
-  else if (NumBytes < 6) {
-    OutStreamer.emitInstruction(
-        MCInstBuilder(SystemZ::BCAsm).addImm(0).addReg(0).addImm(0).addReg(0),
-        STI);
-    return 4;
-  }
-  else {
-    MCSymbol *DotSym = OutContext.createTempSymbol();
-    const MCSymbolRefExpr *Dot = MCSymbolRefExpr::create(DotSym, OutContext);
-    OutStreamer.emitLabel(DotSym);
-    OutStreamer.emitInstruction(
-        MCInstBuilder(SystemZ::BRCLAsm).addImm(0).addExpr(Dot), STI);
-    return 6;
-  }
-}
-
-void SystemZAsmPrinter::LowerFENTRY_CALL(const MachineInstr &MI,
-                                         SystemZMCInstLower &Lower) {
-  MCContext &Ctx = MF->getContext();
-  if (MF->getFunction().hasFnAttribute("mrecord-mcount")) {
-    MCSymbol *DotSym = OutContext.createTempSymbol();
-    OutStreamer->pushSection();
-    OutStreamer->switchSection(
-        Ctx.getELFSection("__mcount_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC));
-    OutStreamer->emitSymbolValue(DotSym, 8);
-    OutStreamer->popSection();
-    OutStreamer->emitLabel(DotSym);
-  }
-
-  if (MF->getFunction().hasFnAttribute("mnop-mcount")) {
-    EmitNop(Ctx, *OutStreamer, 6, getSubtargetInfo());
-    return;
-  }
-
-  MCSymbol *fentry = Ctx.getOrCreateSymbol("__fentry__");
-  const MCSymbolRefExpr *Op =
-      MCSymbolRefExpr::create(fentry, SystemZ::S_PLT, Ctx);
-  OutStreamer->emitInstruction(
-      MCInstBuilder(SystemZ::BRASL).addReg(SystemZ::R0D).addExpr(Op),
-      getSubtargetInfo());
-}
-
-void SystemZAsmPrinter::LowerSTACKMAP(const MachineInstr &MI) {
-  auto *TII = MF->getSubtarget<SystemZSubtarget>().getInstrInfo();
-
-  unsigned NumNOPBytes = MI.getOperand(1).getImm();
-
-  auto &Ctx = OutStreamer->getContext();
-  MCSymbol *MILabel = Ctx.createTempSymbol();
-  OutStreamer->emitLabel(MILabel);
-  
-  SM.recordStackMap(*MILabel, MI);
-  assert(NumNOPBytes % 2 == 0 && "Invalid number of NOP bytes requested!");
-
-  // Scan ahead to trim the shadow.
-  unsigned ShadowBytes = 0;
-  const MachineBasicBlock &MBB = *MI.getParent();
-  MachineBasicBlock::const_iterator MII(MI);
-  ++MII;
-  while (ShadowBytes < NumNOPBytes) {
-    if (MII == MBB.end() ||
-        MII->getOpcode() == TargetOpcode::PATCHPOINT ||
-        MII->getOpcode() == TargetOpcode::STACKMAP)
-      break;
-    ShadowBytes += TII->getInstSizeInBytes(*MII);
-    if (MII->isCall())
-      break;
-    ++MII;
-  }
-
-  // Emit nops.
-  while (ShadowBytes < NumNOPBytes)
-    ShadowBytes += EmitNop(OutContext, *OutStreamer, NumNOPBytes - ShadowBytes,
-                           getSubtargetInfo());
-}
-
-// Lower a patchpoint of the form:
-// [<def>], <id>, <numBytes>, <target>, <numArgs>
-void SystemZAsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
-                                        SystemZMCInstLower &Lower) {
-  auto &Ctx = OutStreamer->getContext();
-  MCSymbol *MILabel = Ctx.createTempSymbol();
-  OutStreamer->emitLabel(MILabel);
-
-  SM.recordPatchPoint(*MILabel, MI);
-  PatchPointOpers Opers(&MI);
-
-  unsigned EncodedBytes = 0;
-  const MachineOperand &CalleeMO = Opers.getCallTarget();
-
-  if (CalleeMO.isImm()) {
-    uint64_t CallTarget = CalleeMO.getImm();
-    if (CallTarget) {
-      unsigned ScratchIdx = -1;
-      unsigned ScratchReg = 0;
-      do {
-        ScratchIdx = Opers.getNextScratchIdx(ScratchIdx + 1);
-        ScratchReg = MI.getOperand(ScratchIdx).getReg();
-      } while (ScratchReg == SystemZ::R0D);
-
-      // Materialize the call target address
-      EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LLILF)
-                                      .addReg(ScratchReg)
-                                      .addImm(CallTarget & 0xFFFFFFFF));
-      EncodedBytes += 6;
-      if (CallTarget >> 32) {
-        EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::IIHF)
-                                        .addReg(ScratchReg)
-                                        .addImm(CallTarget >> 32));
-        EncodedBytes += 6;
-      }
-
-      EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
-                                     .addReg(SystemZ::R14D)
-                                     .addReg(ScratchReg));
-      EncodedBytes += 2;
-    }
-  } else if (CalleeMO.isGlobal()) {
-    const MCExpr *Expr = Lower.getExpr(CalleeMO, SystemZ::S_PLT);
-    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
-                                   .addReg(SystemZ::R14D)
-                                   .addExpr(Expr));
-    EncodedBytes += 6;
-  }
-
-  // Emit padding.
-  unsigned NumBytes = Opers.getNumPatchBytes();
-  assert(NumBytes >= EncodedBytes &&
-         "Patchpoint can't request size less than the length of a call.");
-  assert((NumBytes - EncodedBytes) % 2 == 0 &&
-         "Invalid number of NOP bytes requested!");
-  while (EncodedBytes < NumBytes)
-    EncodedBytes += EmitNop(OutContext, *OutStreamer, NumBytes - EncodedBytes,
-                            getSubtargetInfo());
-}
-
-void SystemZAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
-    const MachineInstr &MI, SystemZMCInstLower &Lower) {
-
-  const MachineFunction &MF = *(MI.getParent()->getParent());
-  const Function &F = MF.getFunction();
-
-  // If patchable-function-entry is set, emit in-function nops here.
-  if (F.hasFnAttribute("patchable-function-entry")) {
-    // get M-N from function attribute (CodeGenFunction subtracts N
-    // from M to yield the correct patchable-function-entry).
-    unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
-    // Emit M-N 2-byte nops. Use getNop() here instead of emitNops()
-    // to keep it aligned with the common code implementation emitting
-    // the prefix nops.
-    for (unsigned I = 0; I < Num; ++I)
-      EmitToStreamer(*OutStreamer, MF.getSubtarget().getInstrInfo()->getNop());
-    return;
-  }
-  // Otherwise, emit xray sled.
-  // .begin:
-  //   j .end    # -> stmg    %r2, %r15, 16(%r15)
-  //   nop
-  //   llilf   %2, FuncID
-  //   brasl   %r14, __xray_FunctionEntry at GOT
-  // .end:
-  //
-  // Update compiler-rt/lib/xray/xray_s390x.cpp accordingly when number
-  // of instructions change.
-  bool HasVectorFeature =
-      TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureVector) &&
-      !TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureSoftFloat);
-  MCSymbol *FuncEntry = OutContext.getOrCreateSymbol(
-      HasVectorFeature ? "__xray_FunctionEntryVec" : "__xray_FunctionEntry");
-  MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_", true);
-  MCSymbol *EndOfSled = OutContext.createTempSymbol();
-  OutStreamer->emitLabel(BeginOfSled);
-  EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::J)
-                     .addExpr(MCSymbolRefExpr::create(EndOfSled, OutContext)));
-  EmitNop(OutContext, *OutStreamer, 2, getSubtargetInfo());
-  EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
-  EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
-                                   .addReg(SystemZ::R14D)
-                                   .addExpr(MCSymbolRefExpr::create(
-                                       FuncEntry, SystemZ::S_PLT, OutContext)));
-  OutStreamer->emitLabel(EndOfSled);
-  recordSled(BeginOfSled, MI, SledKind::FUNCTION_ENTER, 2);
-}
-
-void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
-                                           SystemZMCInstLower &Lower) {
-  unsigned OpCode = MI.getOperand(0).getImm();
-  MCSymbol *FallthroughLabel = nullptr;
-  if (OpCode == SystemZ::CondReturn) {
-    FallthroughLabel = OutContext.createTempSymbol();
-    int64_t Cond0 = MI.getOperand(1).getImm();
-    int64_t Cond1 = MI.getOperand(2).getImm();
-    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRC)
-                                     .addImm(Cond0)
-                                     .addImm(Cond1 ^ Cond0)
-                                     .addExpr(MCSymbolRefExpr::create(
-                                         FallthroughLabel, OutContext)));
-  }
-  // .begin:
-  //   br %r14    # -> stmg    %r2, %r15, 24(%r15)
-  //   nop
-  //   nop
-  //   llilf   %2,FuncID
-  //   j       __xray_FunctionExit at GOT
-  //
-  // Update compiler-rt/lib/xray/xray_s390x.cpp accordingly when number
-  // of instructions change.
-  bool HasVectorFeature =
-      TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureVector) &&
-      !TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureSoftFloat);
-  MCSymbol *FuncExit = OutContext.getOrCreateSymbol(
-      HasVectorFeature ? "__xray_FunctionExitVec" : "__xray_FunctionExit");
-  MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_", true);
-  OutStreamer->emitLabel(BeginOfSled);
-  EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::BR).addReg(SystemZ::R14D));
-  EmitNop(OutContext, *OutStreamer, 4, getSubtargetInfo());
-  EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
-  EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::J)
-                                   .addExpr(MCSymbolRefExpr::create(
-                                       FuncExit, SystemZ::S_PLT, OutContext)));
-  if (FallthroughLabel)
-    OutStreamer->emitLabel(FallthroughLabel);
-  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.
-void SystemZAsmPrinter::emitAttributes(Module &M) {
-  if (M.getModuleFlag("s390x-visible-vector-ABI")) {
-    bool HasVectorFeature =
-        TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureVector);
-    OutStreamer->emitGNUAttribute(8, HasVectorFeature ? 2 : 1);
-  }
-}
-
-// Convert a SystemZ-specific constant pool modifier into the associated
-// specifier.
-static uint8_t getSpecifierFromModifier(SystemZCP::SystemZCPModifier Modifier) {
-  switch (Modifier) {
-  case SystemZCP::TLSGD:
-    return SystemZ::S_TLSGD;
-  case SystemZCP::TLSLDM:
-    return SystemZ::S_TLSLDM;
-  case SystemZCP::DTPOFF:
-    return SystemZ::S_DTPOFF;
-  case SystemZCP::NTPOFF:
-    return SystemZ::S_NTPOFF;
-  }
-  llvm_unreachable("Invalid SystemCPModifier!");
-}
-
-void SystemZAsmPrinter::emitMachineConstantPoolValue(
-    MachineConstantPoolValue *MCPV) {
-  auto *ZCPV = static_cast<SystemZConstantPoolValue*>(MCPV);
-
-  const MCExpr *Expr = MCSymbolRefExpr::create(
-      getSymbol(ZCPV->getGlobalValue()),
-      getSpecifierFromModifier(ZCPV->getModifier()), OutContext);
-  uint64_t Size = getDataLayout().getTypeAllocSize(ZCPV->getType());
-
-  OutStreamer->emitValue(Expr, Size);
-}
-
-// Emit the ctor or dtor list taking into account the init priority.
-void SystemZAsmPrinter::emitXXStructorList(const DataLayout &DL,
-                                           const Constant *List, bool IsCtor) {
-  if (!TM.getTargetTriple().isOSBinFormatGOFF())
-    return AsmPrinter::emitXXStructorList(DL, List, IsCtor);
-
-  SmallVector<Structor, 8> Structors;
-  preprocessXXStructorList(DL, List, Structors);
-  if (Structors.empty())
-    return;
-
-  const Align Align = llvm::Align(4);
-  const TargetLoweringObjectFileGOFF &Obj =
-      static_cast<const TargetLoweringObjectFileGOFF &>(getObjFileLowering());
-  for (Structor &S : Structors) {
-    MCSectionGOFF *Section =
-        static_cast<MCSectionGOFF *>(Obj.getStaticXtorSection(S.Priority));
-    OutStreamer->switchSection(Section);
-    if (OutStreamer->getCurrentSection() != OutStreamer->getPreviousSection())
-      emitAlignment(Align);
-
-    // The priority is provided as an input to getStaticXtorSection(), and is
-    // recalculated within that function as `Prio` going to going into the
-    // PR section.
-    // This priority retrieved via the `SortKey` below is the recalculated
-    // Priority.
-    uint32_t XtorPriority = Section->getPRAttributes().SortKey;
-
-    const GlobalValue *GV = dyn_cast<GlobalValue>(S.Func->stripPointerCasts());
-    assert(GV && "C++ xxtor pointer was not a GlobalValue!");
-    MCSymbolGOFF *Symbol = static_cast<MCSymbolGOFF *>(getSymbol(GV));
-
-    // @@SQINIT entry: { unsigned prio; void (*ctor)();  void (*dtor)(); }
-
-    unsigned PointerSizeInBytes = DL.getPointerSize();
-
-    auto &Ctx = OutStreamer->getContext();
-    const MCExpr *ADAFuncRefExpr;
-    unsigned SlotKind = SystemZII::MO_ADA_DIRECT_FUNC_DESC;
-
-    MCSectionGOFF *ADASection =
-        static_cast<MCSectionGOFF *>(Obj.getADASection());
-    assert(ADASection && "ADA section must exist for GOFF targets!");
-    const MCSymbol *ADASym = ADASection->getBeginSymbol();
-    assert(ADASym && "ADA symbol should already be set!");
-
-    ADAFuncRefExpr = MCBinaryExpr::createAdd(
-        MCSpecifierExpr::create(MCSymbolRefExpr::create(ADASym, OutContext),
-                                SystemZ::S_QCon, OutContext),
-        MCConstantExpr::create(ADATable.insert(Symbol, SlotKind), Ctx), Ctx);
-
-    emitInt32(XtorPriority);
-    if (IsCtor) {
-      OutStreamer->emitValue(ADAFuncRefExpr, PointerSizeInBytes);
-      OutStreamer->emitIntValue(0, PointerSizeInBytes);
-    } else {
-      OutStreamer->emitIntValue(0, PointerSizeInBytes);
-      OutStreamer->emitValue(ADAFuncRefExpr, PointerSizeInBytes);
-    }
-  }
-}
-
 static void printFormattedRegName(const MCAsmInfo *MAI, unsigned RegNo,
                                   raw_ostream &OS) {
   const char *RegName;
@@ -1293,616 +629,21 @@ bool SystemZAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
   return false;
 }
 
-void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) {
-  auto TT = OutContext.getTargetTriple();
-  if (TT.isOSzOS()) {
-    auto *ZOS = static_cast<SystemZTargetzOSStreamer *>(getTargetStreamer());
-    emitADASection();
-    emitIDRLSection(M);
-    // On z/OS, we need to associate an external data reference with an ED
-    // symbol, for which we use the the ED of the ADA. We also need to mark the
-    // reference as being to data, otherwise we cannot bind with code generated
-    // by XL.
-    for (auto &GO : M.global_objects()) {
-      if (auto *GV = dyn_cast<GlobalVariable>(&GO)) {
-        if (!GV->hasInitializer()) {
-          MCSymbol *Sym = getSymbol(GV);
-          ZOS->emitADA(Sym, OutContext.getObjectFileInfo()->getADASection());
-          OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeObject);
-        }
-      }
-    }
-  }
-  emitAttributes(M);
-}
-
-void SystemZAsmPrinter::emitADASection() {
-  OutStreamer->pushSection();
-
-  const unsigned PointerSize = getDataLayout().getPointerSize();
-  OutStreamer->switchSection(getObjFileLowering().getADASection());
-
-  auto *ZOS = static_cast<SystemZTargetzOSStreamer *>(getTargetStreamer());
-  unsigned EmittedBytes = 0;
-  for (auto &Entry : ADATable.getTable()) {
-    const MCSymbol *Sym;
-    unsigned SlotKind;
-    std::tie(Sym, SlotKind) = Entry.first;
-    unsigned Offset = Entry.second;
-    assert(Offset == EmittedBytes && "Offset not as expected");
-    (void)EmittedBytes;
-#define EMIT_COMMENT(Str)                                                      \
-  OutStreamer->AddComment(Twine("Offset ")                                     \
-                              .concat(utostr(Offset))                          \
-                              .concat(" " Str " ")                             \
-                              .concat(Sym->getName()));
-    switch (SlotKind) {
-    case SystemZII::MO_ADA_DIRECT_FUNC_DESC:
-      // Language Environment DLL logic requires function descriptors, for
-      // imported functions, that are placed in the ADA to be 8 byte aligned.
-      EMIT_COMMENT("function descriptor of");
-      OutStreamer->emitValue(
-          MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
-                                  SystemZ::S_RCon, OutContext),
-          PointerSize);
-      OutStreamer->emitValue(
-          MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
-                                  SystemZ::S_VCon, OutContext),
-          PointerSize);
-      EmittedBytes += PointerSize * 2;
-      break;
-    case SystemZII::MO_ADA_DATA_SYMBOL_ADDR:
-      EMIT_COMMENT("pointer to data symbol");
-      OutStreamer->emitValue(
-          MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
-                                  SystemZ::S_None, OutContext),
-          PointerSize);
-      EmittedBytes += PointerSize;
-      break;
-    case SystemZII::MO_ADA_INDIRECT_FUNC_DESC: {
-      MCSymbol *Alias = OutContext.getOrCreateSymbol(
-          Twine(Sym->getName()).concat("@indirect"));
-      OutStreamer->emitSymbolAttribute(Alias, MCSA_IndirectSymbol);
-      OutStreamer->emitSymbolAttribute(Alias, MCSA_ELF_TypeFunction);
-      OutStreamer->emitSymbolAttribute(Alias, MCSA_Global);
-      OutStreamer->emitSymbolAttribute(Alias, MCSA_Extern);
-      MCSymbolGOFF *GOFFSym =
-          static_cast<llvm::MCSymbolGOFF *>(const_cast<llvm::MCSymbol *>(Sym));
-      ZOS->emitExternalName(Alias, GOFFSym->getExternalName());
-      EMIT_COMMENT("pointer to function descriptor");
-      OutStreamer->emitValue(
-          MCSpecifierExpr::create(MCSymbolRefExpr::create(Alias, OutContext),
-                                  SystemZ::S_VCon, OutContext),
-          PointerSize);
-      EmittedBytes += PointerSize;
-      break;
-    }
-    default:
-      llvm_unreachable("Unexpected slot kind");
-    }
-#undef EMIT_COMMENT
-  }
-  OutStreamer->popSection();
-}
-
-static std::string getProductID(Module &M) {
-  std::string ProductID;
-  if (auto *MD = M.getModuleFlag("zos_product_id"))
-    ProductID = cast<MDString>(MD)->getString().str();
-  if (ProductID.empty())
-    ProductID = "LLVM";
-  return ProductID;
-}
-
-static uint32_t getProductVersion(Module &M) {
-  if (auto *VersionVal = mdconst::extract_or_null<ConstantInt>(
-          M.getModuleFlag("zos_product_major_version")))
-    return VersionVal->getZExtValue();
-  return LLVM_VERSION_MAJOR;
-}
-
-static uint32_t getProductRelease(Module &M) {
-  if (auto *ReleaseVal = mdconst::extract_or_null<ConstantInt>(
-          M.getModuleFlag("zos_product_minor_version")))
-    return ReleaseVal->getZExtValue();
-  return LLVM_VERSION_MINOR;
-}
-
-static uint32_t getProductPatch(Module &M) {
-  if (auto *PatchVal = mdconst::extract_or_null<ConstantInt>(
-          M.getModuleFlag("zos_product_patchlevel")))
-    return PatchVal->getZExtValue();
-  return LLVM_VERSION_PATCH;
-}
-
-static time_t getTranslationTime(Module &M) {
-  std::time_t Time = 0;
-  if (auto *Val = mdconst::extract_or_null<ConstantInt>(
-          M.getModuleFlag("zos_translation_time"))) {
-    long SecondsSinceEpoch = Val->getSExtValue();
-    Time = static_cast<time_t>(SecondsSinceEpoch);
-  }
-  return Time;
-}
-
-void SystemZAsmPrinter::emitIDRLSection(Module &M) {
-  OutStreamer->pushSection();
-  OutStreamer->switchSection(getObjFileLowering().getIDRLSection());
-  constexpr unsigned IDRLDataLength = 30;
-  std::time_t Time = getTranslationTime(M);
-
-  uint32_t ProductVersion = getProductVersion(M);
-  uint32_t ProductRelease = getProductRelease(M);
-
-  std::string ProductID = getProductID(M);
-
-  SmallString<IDRLDataLength + 1> TempStr;
-  raw_svector_ostream O(TempStr);
-  O << formatv("{0,-10}{1,0-2:d}{2,0-2:d}{3:%Y%m%d%H%M%S}{4,0-2}",
-               ProductID.substr(0, 10).c_str(), ProductVersion, ProductRelease,
-               llvm::sys::toUtcTime(Time), "0");
-  SmallString<IDRLDataLength> Data;
-  ConverterEBCDIC::convertToEBCDIC(TempStr, Data);
-
-  OutStreamer->emitInt8(0);               // Reserved.
-  OutStreamer->emitInt8(3);               // Format.
-  OutStreamer->emitInt16(IDRLDataLength); // Length.
-  OutStreamer->emitBytes(Data.str());
-  OutStreamer->popSection();
-}
-
-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.
-    auto *ZOS = static_cast<SystemZTargetzOSStreamer *>(getTargetStreamer());
-    OutStreamer->emitLabel(ZOS->DeferredPPA1.back().FnEnd);
-  }
-}
-
-// Determine the end of the prolog and the instructions which updates the stack
-// register, and attach symbols to those instructions.
-static void determinePrologueStackUpdateSym(MachineFunction *MF,
-                                            MCSymbol *&EndOfPrologSym,
-                                            MCSymbol *&StackUpdateSym) {
-  EndOfPrologSym = nullptr;
-  StackUpdateSym = nullptr;
-
-  // Scan the basic block for the FENCE instruction which marks the end
-  // of the prologue. We know
-  // the prologue is spread at most across the first 3 basic blocks. Also record
-  // the first instruction updating the stack pointer.
-  const SystemZSubtarget &STI = MF->getSubtarget<SystemZSubtarget>();
-  auto &Regs = STI.getSpecialRegisters<SystemZXPLINK64Registers>();
-  MachineInstr *EndOfPrologMI = nullptr;
-  MachineInstr *StackUpdateMI = nullptr;
-  unsigned BBCount = 1;
-
-  for (auto &MBB : *MF) {
-    for (auto &I : MBB) {
-      if (I.getOpcode() == SystemZ::FENCE)
-        EndOfPrologMI = &I;
-      else if (!StackUpdateMI) {
-        unsigned Opcode = I.getOpcode();
-        // TODO: We can instead emit a pseudo instruction in
-        // SystemZFrameLowering to represent a stack adjustment instruction, and
-        // check for that here, instead of having to check for multiple
-        // instructions.
-        if ((Opcode == SystemZ::AGHI || Opcode == SystemZ::AGFI) &&
-            I.getOperand(0).getReg() == Regs.getStackPointerRegister())
-          StackUpdateMI = &I;
-      }
-    }
-
-    // Prologue can be a max of 3 BBs if we need to call stack extension code
-    if (EndOfPrologMI || BBCount == 3)
-      break;
-
-    ++BBCount;
-  }
-
-  // Leaf functions do not have a prologue.
-  if (EndOfPrologMI == nullptr)
-    return;
-
-#ifdef EXPENSIVE_CHECKS
-  // Check that the prolog length is valid.
-  auto *TII = STI.getInstrInfo();
-  size_t Size = 0;
-
-  for (auto &MBB : *MF) {
-    bool TerminateLoop = false;
-    for (auto &I : MBB) {
-      Size += TII->getInstSizeInBytes(I);
-      if (&I == EndOfPrologMI) {
-        TerminateLoop = true;
-        break;
-      }
-    }
-    if (TerminateLoop)
-      break;
-  }
-  if (Size > 128)
-    report_fatal_error(
-        Twine(MF->getName()).concat(": Prolog exceeds 128 bytes"));
-#endif
-
-  // Attach a temporary symbol to mark the end of the prolog.
-  EndOfPrologSym = MF->getContext().createTempSymbol("end_of_prologue");
-  EndOfPrologMI->setPostInstrSymbol(*MF, EndOfPrologSym);
-
-  if (StackUpdateMI) {
-    StackUpdateSym = MF->getContext().createTempSymbol("stack_update");
-    StackUpdateMI->setPreInstrSymbol(*MF, StackUpdateSym);
-  }
-}
-
-void SystemZAsmPrinter::calculatePPA1() {
-  auto *ZOS = static_cast<SystemZTargetzOSStreamer *>(getTargetStreamer());
-  assert(ZOS->PPA2Sym != nullptr && "PPA2 Symbol not defined");
-
-  SystemZTargetzOSStreamer::PPA1Info Info;
-
-  const TargetRegisterInfo *TRI = MF->getRegInfo().getTargetRegisterInfo();
-  const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
-
-  const SystemZMachineFunctionInfo *ZFI =
-      MF->getInfo<SystemZMachineFunctionInfo>();
-  const auto *ZFL = static_cast<const SystemZXPLINKFrameLowering *>(
-      Subtarget.getFrameLowering());
-  const MachineFrameInfo &MFFrame = MF->getFrameInfo();
-
-  // Get saved GPR/FPR/VPR masks.
-  const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo();
-  uint16_t SavedGPRMask = 0;
-  uint16_t SavedFPRMask = 0;
-  uint8_t SavedVRMask = 0;
-  int64_t OffsetFPR = 0;
-  int64_t OffsetVR = 0;
-  const int64_t TopOfStack =
-      MFFrame.getOffsetAdjustment() + MFFrame.getStackSize();
-
-  // Loop over the spilled registers. The CalleeSavedInfo can't be used because
-  // it does not contain all spilled registers.
-  for (unsigned I = ZFI->getSpillGPRRegs().LowGPR,
-                E = ZFI->getSpillGPRRegs().HighGPR;
-       I && E && I <= E; ++I) {
-    unsigned V = TRI->getEncodingValue((Register)I);
-    assert(V < 16 && "GPR index out of range");
-    SavedGPRMask |= 1 << (15 - V);
-  }
-
-  for (auto &CS : CSI) {
-    unsigned Reg = CS.getReg();
-    unsigned I = TRI->getEncodingValue(Reg);
-
-    if (SystemZ::FP64BitRegClass.contains(Reg)) {
-      assert(I < 16 && "FPR index out of range");
-      SavedFPRMask |= 1 << (15 - I);
-      int64_t Temp = MFFrame.getObjectOffset(CS.getFrameIdx());
-      if (Temp < OffsetFPR)
-        OffsetFPR = Temp;
-    } else if (SystemZ::VR128BitRegClass.contains(Reg)) {
-      assert(I >= 16 && I <= 23 && "VPR index out of range");
-      unsigned BitNum = I - 16;
-      SavedVRMask |= 1 << (7 - BitNum);
-      int64_t Temp = MFFrame.getObjectOffset(CS.getFrameIdx());
-      if (Temp < OffsetVR)
-        OffsetVR = Temp;
-    }
-  }
-
-  // Adjust the offset.
-  OffsetFPR += (OffsetFPR < 0) ? TopOfStack : 0;
-  OffsetVR += (OffsetVR < 0) ? TopOfStack : 0;
-
-  // Get alloca register.
-  uint8_t FrameReg = TRI->getEncodingValue(TRI->getFrameRegister(*MF));
-  uint8_t AllocaReg = ZFL->hasFP(*MF) ? FrameReg : 0;
-  assert(AllocaReg < 16 && "Can't have alloca register larger than 15");
-
-  MCSymbol *PersonalityRoutine = nullptr;
-  MCSymbol *GCCEH = nullptr;
-  uint64_t PersonalityADADisp = 0;
-  uint64_t GCCEHADADisp = 0;
-  if (!MF->getLandingPads().empty()) {
-    const Function *Per = dyn_cast<Function>(
-        MF->getFunction().getPersonalityFn()->stripPointerCasts());
-    PersonalityRoutine = Per ? MF->getTarget().getSymbol(Per) : nullptr;
-    if (PersonalityRoutine) {
-      GCCEH = MF->getContext().getOrCreateSymbol(
-          Twine("GCC_except_table") + Twine(MF->getFunctionNumber()));
-      PersonalityADADisp = ADATable.insert(
-          PersonalityRoutine, SystemZII::MO_ADA_INDIRECT_FUNC_DESC);
-      GCCEHADADisp = ADATable.insert(GCCEH, SystemZII::MO_ADA_DATA_SYMBOL_ADDR);
-    }
-  }
-
-  // Get the name of the function, with suffix _.
-  std::string N(MF->getFunction().hasName()
-                    ? Twine(MF->getFunction().getName()).concat("_").str()
-                    : "");
-
-  // Calculate the lables for the prolog size and the stack update symbol.
-  MCSymbol *EndOfPrologSym;
-  MCSymbol *StackUpdateSym;
-  determinePrologueStackUpdateSym(MF, EndOfPrologSym, StackUpdateSym);
-
-  // Save the calculated values.
-  if (MF->getFunction().hasFnAttribute("zos-ppa1-name"))
-    Info.Name =
-        MF->getFunction().getFnAttribute("zos-ppa1-name").getValueAsString();
-  else if (MF->getFunction().hasName())
-    Info.Name = MF->getFunction().getName();
-
-  Info.PPA1 = OutContext.createTempSymbol(Twine("PPA1_").concat(N), true);
-  Info.EPMarker = OutContext.createTempSymbol(Twine("EPM_").concat(N), true);
-  Info.FnEnd = OutContext.createTempSymbol(Twine(N).concat("end_"));
-  Info.Fn = CurrentFnSym;
-  Info.EndOfProlog = EndOfPrologSym;
-  Info.StackUpdate = StackUpdateSym;
-  Info.PersonalityADADisp = PersonalityADADisp;
-  Info.GCCEHADADisp = GCCEHADADisp;
-  Info.OffsetFPR = OffsetFPR;
-  Info.OffsetVR = OffsetVR;
-  Info.CallFrameSize = MFFrame.getMaxCallFrameSize();
-  Info.SizeOfFnParams = ZFI->getSizeOfFnParams();
-  Info.SavedGPRMask = SavedGPRMask;
-  Info.SavedFPRMask = SavedFPRMask;
-  Info.SavedVRMask = SavedVRMask;
-  Info.FrameReg = FrameReg;
-  Info.AllocaReg = AllocaReg;
-  Info.IsVarArg = MF->getFunction().isVarArg();
-  Info.HasStackProtector = MFFrame.hasStackProtectorIndex();
-
-  ZOS->DeferredPPA1.push_back(Info);
-}
-
-void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) {
-  if (TM.getTargetTriple().isOSzOS())
-    emitPPA2(M);
-  AsmPrinter::emitStartOfAsmFile(M);
-}
-
-void SystemZAsmPrinter::emitPPA2(Module &M) {
-  auto *ZOS = static_cast<SystemZTargetzOSStreamer *>(getTargetStreamer());
-  OutStreamer->pushSection();
-  OutStreamer->switchSection(getObjFileLowering().getTextSection());
-  MCContext &OutContext = OutStreamer->getContext();
-  // Make CELQSTRT symbol.
-  const char *StartSymbolName = "CELQSTRT";
-  MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(StartSymbolName);
-  OutStreamer->emitSymbolAttribute(CELQSTRT, MCSA_OSLinkage);
-  OutStreamer->emitSymbolAttribute(CELQSTRT, MCSA_Global);
-
-  // Create symbol and assign to streamer field for use in PPA1.
-  ZOS->PPA2Sym = OutContext.createTempSymbol("PPA2", false);
-  MCSymbol *PPA2Sym = ZOS->PPA2Sym;
-  MCSymbol *DateVersionSym = OutContext.createTempSymbol("DVS", false);
-
-  std::time_t Time = getTranslationTime(M);
-  SmallString<14> CompilationTimeEBCDIC, CompilationTime;
-  CompilationTime = formatv("{0:%Y%m%d%H%M%S}", llvm::sys::toUtcTime(Time));
-
-  uint32_t ProductVersion = getProductVersion(M),
-           ProductRelease = getProductRelease(M),
-           ProductPatch = getProductPatch(M);
-
-  SmallString<6> VersionEBCDIC, Version;
-  Version = formatv("{0,0-2:d}{1,0-2:d}{2,0-2:d}", ProductVersion,
-                    ProductRelease, ProductPatch);
-
-  ConverterEBCDIC::convertToEBCDIC(CompilationTime, CompilationTimeEBCDIC);
-  ConverterEBCDIC::convertToEBCDIC(Version, VersionEBCDIC);
-
-  enum class PPA2MemberId : uint8_t {
-    // See z/OS Language Environment Vendor Interfaces v2r5, p.23, for
-    // complete list. Only the C runtime is supported by this backend.
-    LE_C_Runtime = 3,
-  };
-  enum class PPA2MemberSubId : uint8_t {
-    // List of languages using the LE C runtime implementation.
-    C = 0x00,
-    CXX = 0x01,
-    Swift = 0x03,
-    Go = 0x60,
-    LLVMBasedLang = 0xe7,
-  };
-  // PPA2 Flags
-  enum class PPA2Flags : uint8_t {
-    CompileForBinaryFloatingPoint = 0x80,
-    CompiledWithXPLink = 0x01,
-    CompiledUnitASCII = 0x04,
-    HasServiceInfo = 0x20,
-  };
-
-  PPA2MemberSubId MemberSubId = PPA2MemberSubId::LLVMBasedLang;
-  if (auto *MD = M.getModuleFlag("zos_cu_language")) {
-    StringRef Language = cast<MDString>(MD)->getString();
-    MemberSubId = StringSwitch<PPA2MemberSubId>(Language)
-                      .Case("C", PPA2MemberSubId::C)
-                      .Case("C++", PPA2MemberSubId::CXX)
-                      .Case("Swift", PPA2MemberSubId::Swift)
-                      .Case("Go", PPA2MemberSubId::Go)
-                      .Default(PPA2MemberSubId::LLVMBasedLang);
-  }
-
-  // Emit PPA2 section.
-  OutStreamer->emitLabel(PPA2Sym);
-  OutStreamer->emitInt8(static_cast<uint8_t>(PPA2MemberId::LE_C_Runtime));
-  OutStreamer->emitInt8(static_cast<uint8_t>(MemberSubId));
-  OutStreamer->emitInt8(0x22); // Member defined, c370_plist+c370_env
-  OutStreamer->emitInt8(0x04); // Control level 4 (XPLink)
-  OutStreamer->emitAbsoluteSymbolDiff(CELQSTRT, PPA2Sym, 4);
-  OutStreamer->emitInt32(0x00000000);
-  OutStreamer->emitAbsoluteSymbolDiff(DateVersionSym, PPA2Sym, 4);
-  OutStreamer->emitInt32(
-      0x00000000); // Offset to main entry point, always 0 (so says TR).
-  uint8_t Flgs = static_cast<uint8_t>(PPA2Flags::CompileForBinaryFloatingPoint);
-  Flgs |= static_cast<uint8_t>(PPA2Flags::CompiledWithXPLink);
-
-  bool IsASCII = true;
-  if (auto *MD = M.getModuleFlag("zos_le_char_mode")) {
-    const StringRef &CharMode = cast<MDString>(MD)->getString();
-    if (CharMode == "ebcdic")
-      IsASCII = false;
-    else if (CharMode != "ascii")
-      OutContext.reportError(
-          {}, "Only ascii or ebcdic are allowed for zos_le_char_mode");
-  }
-  if (IsASCII)
-    Flgs |= static_cast<uint8_t>(
-        PPA2Flags::CompiledUnitASCII); // Setting bit for ASCII char. mode.
-
-  OutStreamer->emitInt8(Flgs);
-  OutStreamer->emitInt8(0x00);    // Reserved.
-                                  // No MD5 signature before timestamp.
-                                  // No FLOAT(AFP(VOLATILE)).
-                                  // Remaining 5 flag bits reserved.
-  OutStreamer->emitInt16(0x0000); // 16 Reserved flag bits.
-
-  // Emit date and version section.
-  OutStreamer->emitLabel(DateVersionSym);
-  OutStreamer->emitBytes(CompilationTimeEBCDIC.str());
-  OutStreamer->emitBytes(VersionEBCDIC.str());
-
-  OutStreamer->emitInt16(0x0000); // Service level string length.
-
-  // The binder requires that the offset to the PPA2 be emitted in a different,
-  // specially-named section.
-  OutStreamer->switchSection(getObjFileLowering().getPPA2ListSection());
-  // Emit 8 byte alignment.
-  // Emit pointer to PPA2 label.
-  OutStreamer->AddComment("A(PPA2-CELQSTRT)");
-  OutStreamer->emitAbsoluteSymbolDiff(PPA2Sym, CELQSTRT, 8);
-  OutStreamer->popSection();
-}
-
-void SystemZAsmPrinter::emitGlobalAlias(const Module &M,
-                                        const GlobalAlias &GA) {
-  if (!TM.getTargetTriple().isOSzOS())
-    return AsmPrinter::emitGlobalAlias(M, GA);
-
-  // Aliased function labels have already been emitted for z/OS
-}
-
-const MCExpr *SystemZAsmPrinter::lowerConstant(const Constant *CV,
-                                               const Constant *BaseCV,
-                                               uint64_t Offset) {
-  const Triple &TargetTriple = TM.getTargetTriple();
-
-  if (TargetTriple.isOSzOS()) {
-    const GlobalAlias *GA = dyn_cast<GlobalAlias>(CV);
-    const GlobalVariable *GV = dyn_cast<GlobalVariable>(CV);
-    const Function *FV = dyn_cast<Function>(CV);
-    bool IsFunc = !GV && (FV || (GA && isa<Function>(GA->getAliaseeObject())));
-
-    MCSymbol *Sym = NULL;
-
-    if (GA)
-      Sym = getSymbol(GA);
-    else if (IsFunc)
-      Sym = getSymbol(FV);
-    else if (GV)
-      Sym = getSymbol(GV);
-
-    if (IsFunc) {
-      OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
-      if (FV->hasExternalLinkage())
-        return MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
-                                       SystemZ::S_VCon, OutContext);
-      // Trigger creation of function descriptor in ADA for internal
-      // functions.
-      unsigned Disp = ADATable.insert(Sym, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
-      return MCBinaryExpr::createAdd(
-          MCSpecifierExpr::create(
-              MCSymbolRefExpr::create(
-                  getObjFileLowering().getADASection()->getBeginSymbol(),
-                  OutContext),
-              SystemZ::S_None, OutContext),
-          MCConstantExpr::create(Disp, OutContext), OutContext);
-    }
-    if (Sym) {
-      OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeObject);
-      return MCSymbolRefExpr::create(Sym, OutContext);
-    }
-  }
-  return AsmPrinter::lowerConstant(CV);
-}
-
-void SystemZAsmPrinter::emitFunctionEntryLabel() {
-  const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
-
-  if (Subtarget.getTargetTriple().isOSzOS()) {
-    auto *ZOS = static_cast<SystemZTargetzOSStreamer *>(getTargetStreamer());
-    calculatePPA1();
-
-    // EntryPoint Marker
-    const MachineFrameInfo &MFFrame = MF->getFrameInfo();
-    bool IsUsingAlloca = MFFrame.hasVarSizedObjects();
-    uint32_t DSASize = MFFrame.getStackSize();
-    bool IsLeaf = DSASize == 0 && MFFrame.getCalleeSavedInfo().empty();
-
-    // Set Flags.
-    uint8_t Flags = 0;
-    if (IsLeaf)
-      Flags |= 0x08;
-    if (IsUsingAlloca)
-      Flags |= 0x04;
-
-    // Combine into top 27 bits of DSASize and bottom 5 bits of Flags.
-    uint32_t DSAAndFlags = DSASize & 0xFFFFFFE0; // (x/32) << 5
-    DSAAndFlags |= Flags;
-
-    // Emit entry point marker section.
-    OutStreamer->AddComment("XPLINK Routine Layout Entry");
-    OutStreamer->emitLabel(ZOS->DeferredPPA1.back().EPMarker);
-    OutStreamer->AddComment("Eyecatcher 0x00C300C500C500");
-    OutStreamer->emitIntValueInHex(0x00C300C500C500, 7); // Eyecatcher.
-    OutStreamer->AddComment("Mark Type C'1'");
-    OutStreamer->emitInt8(0xF1); // Mark Type.
-    OutStreamer->AddComment("Offset to PPA1");
-    OutStreamer->emitAbsoluteSymbolDiff(ZOS->DeferredPPA1.back().PPA1,
-                                        ZOS->DeferredPPA1.back().EPMarker, 4);
-    if (OutStreamer->isVerboseAsm()) {
-      OutStreamer->AddComment("DSA Size 0x" + Twine::utohexstr(DSASize));
-      OutStreamer->AddComment("Entry Flags");
-      if (Flags & 0x08)
-        OutStreamer->AddComment("  Bit 1: 1 = Leaf function");
-      else
-        OutStreamer->AddComment("  Bit 1: 0 = Non-leaf function");
-      if (Flags & 0x04)
-        OutStreamer->AddComment("  Bit 2: 1 = Uses alloca");
-      else
-        OutStreamer->AddComment("  Bit 2: 0 = Does not use alloca");
-    }
-    OutStreamer->emitInt32(DSAAndFlags);
-
-    ZOS->emitADA(CurrentFnSym, getObjFileLowering().getADASection());
-  }
-
-  AsmPrinter::emitFunctionEntryLabel();
-
-  if (Subtarget.getTargetTriple().isOSzOS()) {
-    const Function *F = &MF->getFunction();
-    // Emit aliasing label for function entry point label.
-    for (const GlobalAlias *Alias : GOAliasMap[F]) {
-      MCSymbol *Sym = getSymbol(Alias);
-      OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
-      emitVisibility(Sym, Alias->getVisibility());
-      emitLinkage(Alias, Sym);
-      OutStreamer->emitLabel(Sym);
-    }
-  }
-}
-
 char SystemZAsmPrinter::ID = 0;
 
 INITIALIZE_PASS(SystemZAsmPrinter, "systemz-asm-printer",
                 "SystemZ Assembly Printer", false, false)
 
+static AsmPrinter *createSystemZAsmPrinter(TargetMachine &TM,
+                                           std::unique_ptr<MCStreamer> &&Streamer) {
+  if (TM.getTargetTriple().isOSzOS())
+    return new SystemZXPLINKAsmPrinter(TM, std::move(Streamer));
+  return new SystemZELFAsmPrinter(TM, std::move(Streamer));
+}
+
 // Force static initialization.
 extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
 LLVMInitializeSystemZAsmPrinter() {
-  RegisterAsmPrinter<SystemZAsmPrinter> X(getTheSystemZTarget());
+  TargetRegistry::RegisterAsmPrinter(getTheSystemZTarget(),
+                                     createSystemZAsmPrinter);
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
index fa111fa43eed7..a3bc050110d26 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -19,100 +19,28 @@
 #include "llvm/Support/Compiler.h"
 
 namespace llvm {
+class MCExpr;
 class MCStreamer;
 class MachineInstr;
 class Module;
 class raw_ostream;
 
 class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
-public:
-  static char ID;
-
-private:
   SystemZTargetStreamer *getTargetStreamer() {
     MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
     assert(TS && "do not have a target streamer");
     return static_cast<SystemZTargetStreamer *>(TS);
   }
 
-  /// Call type information for XPLINK.
-  enum class CallType {
-    BASR76 = 0,   // b'x000' == BASR  r7,r6
-    BRAS7 = 1,    // b'x001' == BRAS  r7,ep
-    RESVD_2 = 2,  // b'x010'
-    BRASL7 = 3,   // b'x011' == BRASL r7,ep
-    RESVD_4 = 4,  // b'x100'
-    RESVD_5 = 5,  // b'x101'
-    BALR1415 = 6, // b'x110' == BALR  r14,r15
-    BASR33 = 7,   // b'x111' == BASR  r3,r3
-  };
-
-  // The Associated Data Area (ADA) contains descriptors which help locating
-  // external symbols. For each symbol and type, the displacement into the ADA
-  // is stored.
-  class AssociatedDataAreaTable {
-  public:
-    using DisplacementTable =
-        MapVector<std::pair<const MCSymbol *, unsigned>, uint32_t>;
-
-  private:
-    const uint64_t PointerSize;
-
-    /// The mapping of name/slot type pairs to displacements.
-    DisplacementTable Displacements;
-
-    /// The next available displacement value. Incremented when new entries into
-    /// the ADA are created.
-    uint32_t NextDisplacement = 0;
-
-  public:
-    AssociatedDataAreaTable(uint64_t PointerSize) : PointerSize(PointerSize) {}
-
-    /// @brief Add a function descriptor to the ADA.
-    /// @param MI Pointer to an ADA_ENTRY instruction.
-    /// @return The displacement of the descriptor into the ADA.
-    uint32_t insert(const MachineOperand MO);
-
-    /// @brief Get the displacement into associated data area (ADA) for a name.
-    /// If no  displacement is already associated with the name, assign one and
-    /// return it.
-    /// @param Sym The symbol for which the displacement should be returned.
-    /// @param SlotKind The ADA type.
-    /// @return The displacement of the descriptor into the ADA.
-    uint32_t insert(const MCSymbol *Sym, unsigned SlotKind);
-
-    /// Get the table of GOFF displacements.  This is 'const' since it should
-    /// never be modified by anything except the APIs on this class.
-    const DisplacementTable &getTable() const { return Displacements; }
-
-    uint32_t getNextDisplacement() const { return NextDisplacement; }
-  };
-
-  AssociatedDataAreaTable ADATable;
-
-  // Record a list of GlobalAlias associated with a GlobalObject.
-  // This is used for z/OS's extra-label-at-definition aliasing strategy.
-  // This is similar to what is done for AIX.
-  DenseMap<const GlobalObject *, SmallVector<const GlobalAlias *, 1>>
-      GOAliasMap;
-
-  void calculatePPA1();
-  void emitPPA2(Module &M);
-  void emitADASection();
-  void emitIDRLSection(Module &M);
-
 public:
+  static char ID;
+
   SystemZAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
-      : AsmPrinter(TM, std::move(Streamer), ID),
-        ADATable(TM.getPointerSize(0)) {}
+      : AsmPrinter(TM, std::move(Streamer), ID) {}
 
   // Override AsmPrinter.
   StringRef getPassName() const override { return "SystemZ Assembly Printer"; }
   void emitInstruction(const MachineInstr *MI) override;
-  void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
-  void emitXXStructorList(const DataLayout &DL, const Constant *List,
-                          bool IsCtor) override;
-  void emitEndOfAsmFile(Module &M) override;
   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                        const char *ExtraCode, raw_ostream &OS) override;
   bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
@@ -126,29 +54,6 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter {
 
     return false;
   }
-
-  bool doInitialization(Module &M) override;
-  void emitFunctionEntryLabel() override;
-  void emitFunctionBodyEnd() override;
-  void emitStartOfAsmFile(Module &M) override;
-  void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override;
-  const MCExpr *lowerConstant(const Constant *CV,
-                              const Constant *BaseCV = nullptr,
-                              uint64_t Offset = 0) override;
-
-private:
-  void emitCallInformation(CallType CT);
-  void LowerFENTRY_CALL(const MachineInstr &MI, SystemZMCInstLower &MCIL);
-  void LowerSTACKMAP(const MachineInstr &MI);
-  void LowerPATCHPOINT(const MachineInstr &MI, SystemZMCInstLower &Lower);
-  void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
-                                     SystemZMCInstLower &Lower);
-  void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
-  void lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
-                                SystemZMCInstLower &Lower);
-  void lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI,
-                                        SystemZMCInstLower &Lower);
-  void emitAttributes(Module &M);
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
new file mode 100644
index 0000000000000..d7f12674ea244
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
@@ -0,0 +1,478 @@
+//===-- SystemZELFAsmPrinter.cpp - SystemZ ELF asm printer ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SystemZELFAsmPrinter class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemZELFAsmPrinter.h"
+#include "MCTargetDesc/SystemZMCTargetDesc.h"
+#include "SystemZConstantPoolValue.h"
+#include "SystemZMCInstLower.h"
+#include "SystemZSubtarget.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/StackMaps.h"
+#include "llvm/IR/Module.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCStreamer.h"
+
+using namespace llvm;
+
+// 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,
+                        unsigned NumBytes, const MCSubtargetInfo &STI) {
+  if (NumBytes < 2) {
+    llvm_unreachable("Zero nops?");
+    return 0;
+  }
+  else if (NumBytes < 4) {
+    OutStreamer.emitInstruction(
+        MCInstBuilder(SystemZ::BCRAsm).addImm(0).addReg(SystemZ::R0D), STI);
+    return 2;
+  }
+  else if (NumBytes < 6) {
+    OutStreamer.emitInstruction(
+        MCInstBuilder(SystemZ::BCAsm).addImm(0).addReg(0).addImm(0).addReg(0),
+        STI);
+    return 4;
+  }
+  else {
+    MCSymbol *DotSym = OutContext.createTempSymbol();
+    const MCSymbolRefExpr *Dot = MCSymbolRefExpr::create(DotSym, OutContext);
+    OutStreamer.emitLabel(DotSym);
+    OutStreamer.emitInstruction(
+        MCInstBuilder(SystemZ::BRCLAsm).addImm(0).addExpr(Dot), STI);
+    return 6;
+  }
+}
+
+static const MCSymbolRefExpr *getTLSGetOffset(MCContext &Context) {
+  StringRef Name = "__tls_get_offset";
+  return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name),
+                                 SystemZ::S_PLT, Context);
+}
+
+static const MCSymbolRefExpr *getGlobalOffsetTable(MCContext &Context) {
+  StringRef Name = "_GLOBAL_OFFSET_TABLE_";
+  return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name),
+                                 Context);
+}
+
+SystemZELFAsmPrinter::SystemZELFAsmPrinter(
+    TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
+    : SystemZAsmPrinter(TM, std::move(Streamer)) {}
+
+void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
+  SystemZMCInstLower Lower(MF->getContext(), *this);
+
+  switch (MI->getOpcode()) {
+  case TargetOpcode::FENTRY_CALL:
+    LowerFENTRY_CALL(*MI, Lower);
+    return;
+  case TargetOpcode::STACKMAP:
+    LowerSTACKMAP(*MI);
+    return;
+  case TargetOpcode::PATCHPOINT:
+    LowerPATCHPOINT(*MI, Lower);
+    return;
+  case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
+    LowerPATCHABLE_FUNCTION_ENTER(*MI, Lower);
+    return;
+  case TargetOpcode::PATCHABLE_RET:
+    LowerPATCHABLE_RET(*MI, Lower);
+    return;
+  case SystemZ::CallBASR: {
+    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
+    SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BASR)
+                       .addReg(Regs->getReturnFunctionAddressRegister())
+                       .addReg(MI->getOperand(0).getReg()));
+    return;
+  }
+  case SystemZ::CallBRASL: {
+    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
+    SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BRASL)
+                       .addReg(Regs->getReturnFunctionAddressRegister())
+                       .addExpr(Lower.getExpr(MI->getOperand(0),
+                                              SystemZ::S_PLT)));
+    return;
+  }
+  case SystemZ::CallJG:
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::JG).addExpr(
+                       Lower.getExpr(MI->getOperand(0), SystemZ::S_PLT)));
+    return;
+  case SystemZ::CallBRCL:
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BRCL)
+                       .addImm(MI->getOperand(0).getImm())
+                       .addImm(MI->getOperand(1).getImm())
+                       .addExpr(Lower.getExpr(MI->getOperand(2),
+                                              SystemZ::S_PLT)));
+    return;
+  case SystemZ::TLS_GDCALL: {
+    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
+    SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BRASL)
+                       .addReg(Regs->getReturnFunctionAddressRegister())
+                       .addExpr(getTLSGetOffset(MF->getContext()))
+                       .addExpr(Lower.getExpr(MI->getOperand(0),
+                                              SystemZ::S_TLSGD)));
+    return;
+  }
+  case SystemZ::TLS_LDCALL: {
+    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
+    SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BRASL)
+                       .addReg(Regs->getReturnFunctionAddressRegister())
+                       .addExpr(getTLSGetOffset(MF->getContext()))
+                       .addExpr(Lower.getExpr(MI->getOperand(0),
+                                              SystemZ::S_TLSLDM)));
+    return;
+  }
+  case SystemZ::GOT:
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::LARL)
+                       .addReg(MI->getOperand(0).getReg())
+                       .addExpr(getGlobalOffsetTable(MF->getContext())));
+    return;
+  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:
+    SystemZAsmPrinter::emitInstruction(MI);
+    return;
+  }
+}
+
+void SystemZELFAsmPrinter::LowerFENTRY_CALL(const MachineInstr &MI,
+                                             SystemZMCInstLower &Lower) {
+  MCContext &Ctx = MF->getContext();
+  if (MF->getFunction().hasFnAttribute("mrecord-mcount")) {
+    MCSymbol *DotSym = OutContext.createTempSymbol();
+    OutStreamer->pushSection();
+    OutStreamer->switchSection(
+        Ctx.getELFSection("__mcount_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC));
+    OutStreamer->emitSymbolValue(DotSym, 8);
+    OutStreamer->popSection();
+    OutStreamer->emitLabel(DotSym);
+  }
+
+  if (MF->getFunction().hasFnAttribute("mnop-mcount")) {
+    EmitNop(Ctx, *OutStreamer, 6, getSubtargetInfo());
+    return;
+  }
+
+  MCSymbol *fentry = Ctx.getOrCreateSymbol("__fentry__");
+  const MCSymbolRefExpr *Op =
+      MCSymbolRefExpr::create(fentry, SystemZ::S_PLT, Ctx);
+  OutStreamer->emitInstruction(
+      MCInstBuilder(SystemZ::BRASL).addReg(SystemZ::R0D).addExpr(Op),
+      getSubtargetInfo());
+}
+
+void SystemZELFAsmPrinter::LowerSTACKMAP(const MachineInstr &MI) {
+  auto *TII = MF->getSubtarget<SystemZSubtarget>().getInstrInfo();
+
+  unsigned NumNOPBytes = MI.getOperand(1).getImm();
+
+  auto &Ctx = OutStreamer->getContext();
+  MCSymbol *MILabel = Ctx.createTempSymbol();
+  OutStreamer->emitLabel(MILabel);
+
+  SM.recordStackMap(*MILabel, MI);
+  assert(NumNOPBytes % 2 == 0 && "Invalid number of NOP bytes requested!");
+
+  // Scan ahead to trim the shadow.
+  unsigned ShadowBytes = 0;
+  const MachineBasicBlock &MBB = *MI.getParent();
+  MachineBasicBlock::const_iterator MII(MI);
+  ++MII;
+  while (ShadowBytes < NumNOPBytes) {
+    if (MII == MBB.end() ||
+        MII->getOpcode() == TargetOpcode::PATCHPOINT ||
+        MII->getOpcode() == TargetOpcode::STACKMAP)
+      break;
+    ShadowBytes += TII->getInstSizeInBytes(*MII);
+    if (MII->isCall())
+      break;
+    ++MII;
+  }
+
+  // Emit nops.
+  while (ShadowBytes < NumNOPBytes)
+    ShadowBytes += EmitNop(OutContext, *OutStreamer, NumNOPBytes - ShadowBytes,
+                           getSubtargetInfo());
+}
+
+// Lower a patchpoint of the form:
+// [<def>], <id>, <numBytes>, <target>, <numArgs>
+void SystemZELFAsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
+                                            SystemZMCInstLower &Lower) {
+  auto &Ctx = OutStreamer->getContext();
+  MCSymbol *MILabel = Ctx.createTempSymbol();
+  OutStreamer->emitLabel(MILabel);
+
+  SM.recordPatchPoint(*MILabel, MI);
+  PatchPointOpers Opers(&MI);
+
+  unsigned EncodedBytes = 0;
+  const MachineOperand &CalleeMO = Opers.getCallTarget();
+
+  if (CalleeMO.isImm()) {
+    uint64_t CallTarget = CalleeMO.getImm();
+    if (CallTarget) {
+      unsigned ScratchIdx = -1;
+      unsigned ScratchReg = 0;
+      do {
+        ScratchIdx = Opers.getNextScratchIdx(ScratchIdx + 1);
+        ScratchReg = MI.getOperand(ScratchIdx).getReg();
+      } while (ScratchReg == SystemZ::R0D);
+
+      // Materialize the call target address
+      EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LLILF)
+                                      .addReg(ScratchReg)
+                                      .addImm(CallTarget & 0xFFFFFFFF));
+      EncodedBytes += 6;
+      if (CallTarget >> 32) {
+        EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::IIHF)
+                                        .addReg(ScratchReg)
+                                        .addImm(CallTarget >> 32));
+        EncodedBytes += 6;
+      }
+
+      EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
+                                     .addReg(SystemZ::R14D)
+                                     .addReg(ScratchReg));
+      EncodedBytes += 2;
+    }
+  } else if (CalleeMO.isGlobal()) {
+    const MCExpr *Expr = Lower.getExpr(CalleeMO, SystemZ::S_PLT);
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
+                                   .addReg(SystemZ::R14D)
+                                   .addExpr(Expr));
+    EncodedBytes += 6;
+  }
+
+  // Emit padding.
+  unsigned NumBytes = Opers.getNumPatchBytes();
+  assert(NumBytes >= EncodedBytes &&
+         "Patchpoint can't request size less than the length of a call.");
+  assert((NumBytes - EncodedBytes) % 2 == 0 &&
+         "Invalid number of NOP bytes requested!");
+  while (EncodedBytes < NumBytes)
+    EncodedBytes += EmitNop(OutContext, *OutStreamer, NumBytes - EncodedBytes,
+                            getSubtargetInfo());
+}
+
+void SystemZELFAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
+    const MachineInstr &MI, SystemZMCInstLower &Lower) {
+  const MachineFunction &MF = *(MI.getParent()->getParent());
+  const Function &F = MF.getFunction();
+
+  // If patchable-function-entry is set, emit in-function nops here.
+  if (F.hasFnAttribute("patchable-function-entry")) {
+    unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
+    for (unsigned I = 0; I < Num; ++I)
+      EmitToStreamer(*OutStreamer, MF.getSubtarget().getInstrInfo()->getNop());
+    return;
+  }
+  // Otherwise, emit xray sled.
+  // .begin:
+  //   j .end    # -> stmg    %r2, %r15, 16(%r15)
+  //   nop
+  //   llilf   %2, FuncID
+  //   brasl   %r14, __xray_FunctionEntry at GOT
+  // .end:
+  //
+  // Update compiler-rt/lib/xray/xray_s390x.cpp accordingly when number
+  // of instructions change.
+  bool HasVectorFeature =
+      TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureVector) &&
+      !TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureSoftFloat);
+  MCSymbol *FuncEntry = OutContext.getOrCreateSymbol(
+      HasVectorFeature ? "__xray_FunctionEntryVec" : "__xray_FunctionEntry");
+  MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_", true);
+  MCSymbol *EndOfSled = OutContext.createTempSymbol();
+  OutStreamer->emitLabel(BeginOfSled);
+  EmitToStreamer(*OutStreamer,
+                 MCInstBuilder(SystemZ::J).addExpr(
+                     MCSymbolRefExpr::create(EndOfSled, OutContext)));
+  EmitNop(OutContext, *OutStreamer, 2, getSubtargetInfo());
+  EmitToStreamer(*OutStreamer,
+                 MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
+  EmitToStreamer(*OutStreamer,
+                 MCInstBuilder(SystemZ::BRASL)
+                     .addReg(SystemZ::R14D)
+                     .addExpr(MCSymbolRefExpr::create(
+                         FuncEntry, SystemZ::S_PLT, OutContext)));
+  OutStreamer->emitLabel(EndOfSled);
+  recordSled(BeginOfSled, MI, SledKind::FUNCTION_ENTER, 2);
+}
+
+void SystemZELFAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
+                                               SystemZMCInstLower &Lower) {
+  unsigned OpCode = MI.getOperand(0).getImm();
+  MCSymbol *FallthroughLabel = nullptr;
+  if (OpCode == SystemZ::CondReturn) {
+    FallthroughLabel = OutContext.createTempSymbol();
+    int64_t Cond0 = MI.getOperand(1).getImm();
+    int64_t Cond1 = MI.getOperand(2).getImm();
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BRC)
+                       .addImm(Cond0)
+                       .addImm(Cond1 ^ Cond0)
+                       .addExpr(MCSymbolRefExpr::create(FallthroughLabel,
+                                                        OutContext)));
+  }
+  // .begin:
+  //   br %r14    # -> stmg    %r2, %r15, 24(%r15)
+  //   nop
+  //   nop
+  //   llilf   %2,FuncID
+  //   j       __xray_FunctionExit at GOT
+  //
+  // Update compiler-rt/lib/xray/xray_s390x.cpp accordingly when number
+  // of instructions change.
+  bool HasVectorFeature =
+      TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureVector) &&
+      !TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureSoftFloat);
+  MCSymbol *FuncExit = OutContext.getOrCreateSymbol(
+      HasVectorFeature ? "__xray_FunctionExitVec" : "__xray_FunctionExit");
+  MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_", true);
+  OutStreamer->emitLabel(BeginOfSled);
+  EmitToStreamer(*OutStreamer,
+                 MCInstBuilder(SystemZ::BR).addReg(SystemZ::R14D));
+  EmitNop(OutContext, *OutStreamer, 4, getSubtargetInfo());
+  EmitToStreamer(*OutStreamer,
+                 MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
+  EmitToStreamer(*OutStreamer,
+                 MCInstBuilder(SystemZ::J).addExpr(MCSymbolRefExpr::create(
+                     FuncExit, SystemZ::S_PLT, OutContext)));
+  if (FallthroughLabel)
+    OutStreamer->emitLabel(FallthroughLabel);
+  recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2);
+}
+
+void SystemZELFAsmPrinter::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 SystemZELFAsmPrinter::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 there is an externally visible use of a
+// vector type in the module it should be annotated with an attribute.
+void SystemZELFAsmPrinter::emitAttributes(Module &M) {
+  if (M.getModuleFlag("s390x-visible-vector-ABI")) {
+    bool HasVectorFeature =
+        TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureVector);
+    OutStreamer->emitGNUAttribute(8, HasVectorFeature ? 2 : 1);
+  }
+}
+
+// Convert a SystemZ-specific constant pool modifier into the associated
+// specifier.
+static uint8_t getSpecifierFromModifier(SystemZCP::SystemZCPModifier Modifier) {
+  switch (Modifier) {
+  case SystemZCP::TLSGD:
+    return SystemZ::S_TLSGD;
+  case SystemZCP::TLSLDM:
+    return SystemZ::S_TLSLDM;
+  case SystemZCP::DTPOFF:
+    return SystemZ::S_DTPOFF;
+  case SystemZCP::NTPOFF:
+    return SystemZ::S_NTPOFF;
+  }
+  llvm_unreachable("Invalid SystemCPModifier!");
+}
+
+void SystemZELFAsmPrinter::emitMachineConstantPoolValue(
+    MachineConstantPoolValue *MCPV) {
+  auto *ZCPV = static_cast<SystemZConstantPoolValue*>(MCPV);
+
+  const MCExpr *Expr = MCSymbolRefExpr::create(
+      getSymbol(ZCPV->getGlobalValue()),
+      getSpecifierFromModifier(ZCPV->getModifier()), OutContext);
+  uint64_t Size = getDataLayout().getTypeAllocSize(ZCPV->getType());
+
+  OutStreamer->emitValue(Expr, Size);
+}
+
+void SystemZELFAsmPrinter::emitEndOfAsmFile(Module &M) {
+  emitAttributes(M);
+}
diff --git a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.h
new file mode 100644
index 0000000000000..2e7916840583b
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.h
@@ -0,0 +1,54 @@
+//===-- SystemZELFAsmPrinter.h - SystemZ ELF asm printer --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the SystemZELFAsmPrinter class, which owns ELF-specific
+// asm printer behaviour: ELF instruction lowering, fentry/stackmap/patchpoint,
+// TLS block address, stack-guard address, and the ELF vector-ABI attribute.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZELFASMPRINTER_H
+#define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZELFASMPRINTER_H
+
+#include "MCTargetDesc/SystemZTargetStreamer.h"
+#include "SystemZAsmPrinter.h"
+#include "SystemZMCInstLower.h"
+
+namespace llvm {
+
+class LLVM_LIBRARY_VISIBILITY SystemZELFAsmPrinter : public SystemZAsmPrinter {
+  SystemZTargetStreamer *getTargetStreamer() {
+    MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
+    assert(TS && "do not have a target streamer");
+    return static_cast<SystemZTargetStreamer *>(TS);
+  }
+
+public:
+  SystemZELFAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
+
+  void emitInstruction(const MachineInstr *MI) override;
+  void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
+  void emitEndOfAsmFile(Module &M) override;
+
+private:
+  void LowerFENTRY_CALL(const MachineInstr &MI, SystemZMCInstLower &Lower);
+  void LowerSTACKMAP(const MachineInstr &MI);
+  void LowerPATCHPOINT(const MachineInstr &MI, SystemZMCInstLower &Lower);
+  void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI,
+                                     SystemZMCInstLower &Lower);
+  void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
+  void lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
+                                 SystemZMCInstLower &Lower);
+  void lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI,
+                                        SystemZMCInstLower &Lower);
+  void emitAttributes(Module &M);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZELFASMPRINTER_H
diff --git a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
new file mode 100644
index 0000000000000..72cd1ee222788
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
@@ -0,0 +1,864 @@
+//===-- SystemZXPLINKAsmPrinter.cpp - SystemZ XPLINK asm printer ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SystemZXPLINKAsmPrinter class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemZXPLINKAsmPrinter.h"
+#include "MCTargetDesc/SystemZMCTargetDesc.h"
+#include "MCTargetDesc/SystemZTargetStreamer.h"
+#include "SystemZFrameLowering.h"
+#include "SystemZInstrInfo.h"
+#include "SystemZMCInstLower.h"
+#include "SystemZMachineFunctionInfo.h"
+#include "SystemZSubtarget.h"
+#include "SystemZTargetObjectFile.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalAlias.h"
+#include "llvm/IR/GlobalObject.h"
+#include "llvm/IR/Module.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCSymbolGOFF.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/ConvertEBCDIC.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+
+SystemZXPLINKAsmPrinter::SystemZXPLINKAsmPrinter(
+    TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
+    : SystemZAsmPrinter(TM, std::move(Streamer)),
+      ADATable(TM.getPointerSize(0)) {}
+
+bool SystemZXPLINKAsmPrinter::doInitialization(Module &M) {
+  SM.reset();
+
+  // In HLASM, the only way to represent aliases is to use the
+  // extra-label-at-definition strategy. This is similar to the AIX
+  // implementation with the additional caveat that all symbol attributes must
+  // be emitted before the label is emitted.
+  // Construct an aliasing list for each GlobalObject.
+  for (const auto &Alias : M.aliases()) {
+    const GlobalObject *Aliasee = Alias.getAliaseeObject();
+    if (!Aliasee)
+      OutContext.reportError(
+          {}, "Alias without a base object is not yet supported on z/OS.");
+
+    bool IsFunc = isa<Function>(Aliasee->stripPointerCasts());
+    if (IsFunc) {
+      if (Alias.hasWeakLinkage() || Alias.hasLinkOnceLinkage())
+        OutContext.reportError({},
+                                "Weak alias/reference not supported on z/OS");
+
+      GOAliasMap[Aliasee].push_back(&Alias);
+    } else
+      OutContext.reportError(
+          {}, "Only aliases to functions is supported in GOFF.");
+  }
+  return AsmPrinter::doInitialization(M);
+}
+
+// The XPLINK ABI requires that a no-op encoding the call type is emitted after
+// each call to a subroutine. This information can be used by the called
+// function to determine its entry point, e.g. for generating a backtrace. The
+// call type is encoded as a register number in the bcr instruction. See
+// enumeration CallType for the possible values.
+void SystemZXPLINKAsmPrinter::emitCallInformation(CallType CT) {
+  EmitToStreamer(*OutStreamer,
+                 MCInstBuilder(SystemZ::BCRAsm)
+                     .addImm(0)
+                     .addReg(SystemZMC::GR64Regs[static_cast<unsigned>(CT)]));
+}
+
+uint32_t SystemZXPLINKAsmPrinter::AssociatedDataAreaTable::insert(
+    const MCSymbol *Sym, unsigned SlotKind) {
+  auto Key = std::make_pair(Sym, SlotKind);
+  auto It = Displacements.find(Key);
+
+  if (It != Displacements.end())
+    return (*It).second;
+
+  // Determine length of descriptor.
+  uint32_t Length;
+  switch (SlotKind) {
+  case SystemZII::MO_ADA_DIRECT_FUNC_DESC:
+    Length = 2 * PointerSize;
+    break;
+  default:
+    Length = PointerSize;
+    break;
+  }
+
+  uint32_t Displacement = NextDisplacement;
+  Displacements[std::make_pair(Sym, SlotKind)] = NextDisplacement;
+  NextDisplacement += Length;
+
+  return Displacement;
+}
+
+uint32_t SystemZXPLINKAsmPrinter::AssociatedDataAreaTable::insert(
+    const MachineOperand MO) {
+  MCSymbol *Sym;
+  if (MO.getType() == MachineOperand::MO_GlobalAddress) {
+    const GlobalValue *GV = MO.getGlobal();
+    Sym = MO.getParent()->getMF()->getTarget().getSymbol(GV);
+    assert(Sym && "No symbol");
+  } else if (MO.getType() == MachineOperand::MO_ExternalSymbol) {
+    const char *SymName = MO.getSymbolName();
+    Sym = MO.getParent()->getMF()->getContext().getOrCreateSymbol(SymName);
+    assert(Sym && "No symbol");
+  } else
+    llvm_unreachable("Unexpected operand type");
+
+  unsigned ADAslotType = MO.getTargetFlags();
+  return insert(Sym, ADAslotType);
+}
+
+void SystemZXPLINKAsmPrinter::emitInstruction(const MachineInstr *MI) {
+  SystemZMCInstLower Lower(MF->getContext(), *this);
+  MCInst LoweredMI;
+
+  switch (MI->getOpcode()) {
+  case SystemZ::CallBRASL_XPLINK64:
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BRASL)
+                       .addReg(SystemZ::R7D)
+                       .addExpr(Lower.getExpr(MI->getOperand(0),
+                                              SystemZ::S_None)));
+    emitCallInformation(CallType::BRASL7);
+    return;
+
+  case SystemZ::CallBASR_XPLINK64:
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BASR)
+                       .addReg(SystemZ::R7D)
+                       .addReg(MI->getOperand(0).getReg()));
+    emitCallInformation(CallType::BASR76);
+    return;
+
+  case SystemZ::Return_XPLINK:
+    LoweredMI = MCInstBuilder(SystemZ::B)
+                    .addReg(SystemZ::R7D)
+                    .addImm(2)
+                    .addReg(0);
+    break;
+
+  case SystemZ::CondReturn_XPLINK:
+    LoweredMI = MCInstBuilder(SystemZ::BC)
+                    .addImm(MI->getOperand(0).getImm())
+                    .addImm(MI->getOperand(1).getImm())
+                    .addReg(SystemZ::R7D)
+                    .addImm(2)
+                    .addReg(0);
+    break;
+
+  case SystemZ::CallBASR_STACKEXT:
+    EmitToStreamer(*OutStreamer,
+                   MCInstBuilder(SystemZ::BASR)
+                       .addReg(SystemZ::R3D)
+                       .addReg(MI->getOperand(0).getReg()));
+    emitCallInformation(CallType::BASR33);
+    return;
+
+  case SystemZ::ADA_ENTRY_VALUE:
+  case SystemZ::ADA_ENTRY: {
+    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
+    const SystemZInstrInfo *TII = Subtarget.getInstrInfo();
+    uint32_t Disp = ADATable.insert(MI->getOperand(1));
+    Register TargetReg = MI->getOperand(0).getReg();
+
+    Register ADAReg = MI->getOperand(2).getReg();
+    Disp += MI->getOperand(3).getImm();
+    bool LoadAddr = MI->getOpcode() == SystemZ::ADA_ENTRY;
+
+    unsigned Op0 = LoadAddr ? SystemZ::LA : SystemZ::LG;
+    unsigned Op = TII->getOpcodeForOffset(Op0, Disp);
+
+    Register IndexReg = 0;
+    if (!Op) {
+      if (TargetReg != ADAReg) {
+        IndexReg = TargetReg;
+        // Use TargetReg to store displacement.
+        EmitToStreamer(
+            *OutStreamer,
+            MCInstBuilder(SystemZ::LLILF).addReg(TargetReg).addImm(Disp));
+      } else
+        EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::ALGFI)
+                                        .addReg(TargetReg)
+                                        .addReg(TargetReg)
+                                        .addImm(Disp));
+      Disp = 0;
+      Op = Op0;
+    }
+    EmitToStreamer(*OutStreamer, MCInstBuilder(Op)
+                                    .addReg(TargetReg)
+                                    .addReg(ADAReg)
+                                    .addImm(Disp)
+                                    .addReg(IndexReg));
+    return;
+  }
+
+  default:
+    SystemZAsmPrinter::emitInstruction(MI);
+    return;
+  }
+  EmitToStreamer(*OutStreamer, LoweredMI);
+}
+
+void SystemZXPLINKAsmPrinter::emitXXStructorList(const DataLayout &DL,
+                                                  const Constant *List,
+                                                  bool IsCtor) {
+  assert(TM.getTargetTriple().isOSBinFormatGOFF() && "Only GOFF supported");
+
+  SmallVector<Structor, 8> Structors;
+  preprocessXXStructorList(DL, List, Structors);
+  if (Structors.empty())
+    return;
+
+  const Align Align = llvm::Align(4);
+  const TargetLoweringObjectFileGOFF &Obj =
+      static_cast<const TargetLoweringObjectFileGOFF &>(getObjFileLowering());
+  for (Structor &S : Structors) {
+    MCSectionGOFF *Section =
+        static_cast<MCSectionGOFF *>(Obj.getStaticXtorSection(S.Priority));
+    OutStreamer->switchSection(Section);
+    if (OutStreamer->getCurrentSection() != OutStreamer->getPreviousSection())
+      emitAlignment(Align);
+
+    // The priority is provided as an input to getStaticXtorSection(), and is
+    // recalculated within that function as `Prio` going to going into the
+    // PR section.
+    // This priority retrieved via the `SortKey` below is the recalculated
+    // Priority.
+    uint32_t XtorPriority = Section->getPRAttributes().SortKey;
+
+    const GlobalValue *GV = dyn_cast<GlobalValue>(S.Func->stripPointerCasts());
+    assert(GV && "C++ xxtor pointer was not a GlobalValue!");
+    MCSymbolGOFF *Symbol = static_cast<MCSymbolGOFF *>(getSymbol(GV));
+
+    // @@SQINIT entry: { unsigned prio; void (*ctor)();  void (*dtor)(); }
+
+    unsigned PointerSizeInBytes = DL.getPointerSize();
+
+    auto &Ctx = OutStreamer->getContext();
+    const MCExpr *ADAFuncRefExpr;
+    unsigned SlotKind = SystemZII::MO_ADA_DIRECT_FUNC_DESC;
+
+    MCSectionGOFF *ADASection =
+        static_cast<MCSectionGOFF *>(Obj.getADASection());
+    assert(ADASection && "ADA section must exist for GOFF targets!");
+    const MCSymbol *ADASym = ADASection->getBeginSymbol();
+    assert(ADASym && "ADA symbol should already be set!");
+
+    ADAFuncRefExpr = MCBinaryExpr::createAdd(
+        MCSpecifierExpr::create(MCSymbolRefExpr::create(ADASym, OutContext),
+                                SystemZ::S_QCon, OutContext),
+        MCConstantExpr::create(ADATable.insert(Symbol, SlotKind), Ctx), Ctx);
+
+    emitInt32(XtorPriority);
+    if (IsCtor) {
+      OutStreamer->emitValue(ADAFuncRefExpr, PointerSizeInBytes);
+      OutStreamer->emitIntValue(0, PointerSizeInBytes);
+    } else {
+      OutStreamer->emitIntValue(0, PointerSizeInBytes);
+      OutStreamer->emitValue(ADAFuncRefExpr, PointerSizeInBytes);
+    }
+  }
+}
+
+void SystemZXPLINKAsmPrinter::emitEndOfAsmFile(Module &M) {
+  auto *ZOS = getTargetStreamer();
+  emitADASection();
+  emitIDRLSection(M);
+  // On z/OS, we need to associate an external data reference with an ED
+  // symbol, for which we use the the ED of the ADA. We also need to mark the
+  // reference as being to data, otherwise we cannot bind with code generated
+  // by XL.
+  for (auto &GO : M.global_objects()) {
+    if (auto *GV = dyn_cast<GlobalVariable>(&GO)) {
+      if (!GV->hasInitializer()) {
+        MCSymbol *Sym = getSymbol(GV);
+        ZOS->emitADA(Sym, OutContext.getObjectFileInfo()->getADASection());
+        OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeObject);
+      }
+    }
+  }
+}
+
+void SystemZXPLINKAsmPrinter::emitADASection() {
+  OutStreamer->pushSection();
+
+  const unsigned PointerSize = getDataLayout().getPointerSize();
+  OutStreamer->switchSection(getObjFileLowering().getADASection());
+
+  auto *ZOS = getTargetStreamer();
+  unsigned EmittedBytes = 0;
+  for (auto &Entry : ADATable.getTable()) {
+    const MCSymbol *Sym;
+    unsigned SlotKind;
+    std::tie(Sym, SlotKind) = Entry.first;
+    unsigned Offset = Entry.second;
+    assert(Offset == EmittedBytes && "Offset not as expected");
+    (void)EmittedBytes;
+#define EMIT_COMMENT(Str)                                                      \
+  OutStreamer->AddComment(Twine("Offset ")                                     \
+                              .concat(utostr(Offset))                          \
+                              .concat(" " Str " ")                             \
+                              .concat(Sym->getName()));
+    switch (SlotKind) {
+    case SystemZII::MO_ADA_DIRECT_FUNC_DESC:
+      // Language Environment DLL logic requires function descriptors, for
+      // imported functions, that are placed in the ADA to be 8 byte aligned.
+      EMIT_COMMENT("function descriptor of");
+      OutStreamer->emitValue(
+          MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
+                                  SystemZ::S_RCon, OutContext),
+          PointerSize);
+      OutStreamer->emitValue(
+          MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
+                                  SystemZ::S_VCon, OutContext),
+          PointerSize);
+      EmittedBytes += PointerSize * 2;
+      break;
+    case SystemZII::MO_ADA_DATA_SYMBOL_ADDR:
+      EMIT_COMMENT("pointer to data symbol");
+      OutStreamer->emitValue(
+          MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
+                                  SystemZ::S_None, OutContext),
+          PointerSize);
+      EmittedBytes += PointerSize;
+      break;
+    case SystemZII::MO_ADA_INDIRECT_FUNC_DESC: {
+      MCSymbol *Alias = OutContext.getOrCreateSymbol(
+          Twine(Sym->getName()).concat("@indirect"));
+      OutStreamer->emitSymbolAttribute(Alias, MCSA_IndirectSymbol);
+      OutStreamer->emitSymbolAttribute(Alias, MCSA_ELF_TypeFunction);
+      OutStreamer->emitSymbolAttribute(Alias, MCSA_Global);
+      OutStreamer->emitSymbolAttribute(Alias, MCSA_Extern);
+      MCSymbolGOFF *GOFFSym =
+          static_cast<llvm::MCSymbolGOFF *>(const_cast<llvm::MCSymbol *>(Sym));
+      ZOS->emitExternalName(Alias, GOFFSym->getExternalName());
+      EMIT_COMMENT("pointer to function descriptor");
+      OutStreamer->emitValue(
+          MCSpecifierExpr::create(MCSymbolRefExpr::create(Alias, OutContext),
+                                  SystemZ::S_VCon, OutContext),
+          PointerSize);
+      EmittedBytes += PointerSize;
+      break;
+    }
+    default:
+      llvm_unreachable("Unexpected slot kind");
+    }
+#undef EMIT_COMMENT
+  }
+  OutStreamer->popSection();
+}
+
+static std::string getProductID(Module &M) {
+  std::string ProductID;
+  if (auto *MD = M.getModuleFlag("zos_product_id"))
+    ProductID = cast<MDString>(MD)->getString().str();
+  if (ProductID.empty())
+    ProductID = "LLVM";
+  return ProductID;
+}
+
+static uint32_t getProductVersion(Module &M) {
+  if (auto *VersionVal = mdconst::extract_or_null<ConstantInt>(
+          M.getModuleFlag("zos_product_major_version")))
+    return VersionVal->getZExtValue();
+  return LLVM_VERSION_MAJOR;
+}
+
+static uint32_t getProductRelease(Module &M) {
+  if (auto *ReleaseVal = mdconst::extract_or_null<ConstantInt>(
+          M.getModuleFlag("zos_product_minor_version")))
+    return ReleaseVal->getZExtValue();
+  return LLVM_VERSION_MINOR;
+}
+
+static uint32_t getProductPatch(Module &M) {
+  if (auto *PatchVal = mdconst::extract_or_null<ConstantInt>(
+          M.getModuleFlag("zos_product_patchlevel")))
+    return PatchVal->getZExtValue();
+  return LLVM_VERSION_PATCH;
+}
+
+static time_t getTranslationTime(Module &M) {
+  std::time_t Time = 0;
+  if (auto *Val = mdconst::extract_or_null<ConstantInt>(
+          M.getModuleFlag("zos_translation_time"))) {
+    long SecondsSinceEpoch = Val->getSExtValue();
+    Time = static_cast<time_t>(SecondsSinceEpoch);
+  }
+  return Time;
+}
+
+void SystemZXPLINKAsmPrinter::emitIDRLSection(Module &M) {
+  OutStreamer->pushSection();
+  OutStreamer->switchSection(getObjFileLowering().getIDRLSection());
+  constexpr unsigned IDRLDataLength = 30;
+  std::time_t Time = getTranslationTime(M);
+
+  uint32_t ProductVersion = getProductVersion(M);
+  uint32_t ProductRelease = getProductRelease(M);
+
+  std::string ProductID = getProductID(M);
+
+  SmallString<IDRLDataLength + 1> TempStr;
+  raw_svector_ostream O(TempStr);
+  O << formatv("{0,-10}{1,0-2:d}{2,0-2:d}{3:%Y%m%d%H%M%S}{4,0-2}",
+               ProductID.substr(0, 10).c_str(), ProductVersion, ProductRelease,
+               llvm::sys::toUtcTime(Time), "0");
+  SmallString<IDRLDataLength> Data;
+  ConverterEBCDIC::convertToEBCDIC(TempStr, Data);
+
+  OutStreamer->emitInt8(0);               // Reserved.
+  OutStreamer->emitInt8(3);               // Format.
+  OutStreamer->emitInt16(IDRLDataLength); // Length.
+  OutStreamer->emitBytes(Data.str());
+  OutStreamer->popSection();
+}
+
+void SystemZXPLINKAsmPrinter::emitFunctionBodyEnd() {
+  // 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.
+  auto *ZOS = getTargetStreamer();
+  OutStreamer->emitLabel(ZOS->DeferredPPA1.back().FnEnd);
+}
+
+// Determine the end of the prolog and the instructions which updates the stack
+// register, and attach symbols to those instructions.
+static void determinePrologueStackUpdateSym(MachineFunction *MF,
+                                            MCSymbol *&EndOfPrologSym,
+                                            MCSymbol *&StackUpdateSym) {
+  EndOfPrologSym = nullptr;
+  StackUpdateSym = nullptr;
+
+  // Scan the basic block for the FENCE instruction which marks the end
+  // of the prologue. We know
+  // the prologue is spread at most across the first 3 basic blocks. Also record
+  // the first instruction updating the stack pointer.
+  const SystemZSubtarget &STI = MF->getSubtarget<SystemZSubtarget>();
+  auto &Regs = STI.getSpecialRegisters<SystemZXPLINK64Registers>();
+  MachineInstr *EndOfPrologMI = nullptr;
+  MachineInstr *StackUpdateMI = nullptr;
+  unsigned BBCount = 1;
+
+  for (auto &MBB : *MF) {
+    for (auto &I : MBB) {
+      if (I.getOpcode() == SystemZ::FENCE)
+        EndOfPrologMI = &I;
+      else if (!StackUpdateMI) {
+        unsigned Opcode = I.getOpcode();
+        // TODO: We can instead emit a pseudo instruction in
+        // SystemZFrameLowering to represent a stack adjustment instruction, and
+        // check for that here, instead of having to check for multiple
+        // instructions.
+        if ((Opcode == SystemZ::AGHI || Opcode == SystemZ::AGFI) &&
+            I.getOperand(0).getReg() == Regs.getStackPointerRegister())
+          StackUpdateMI = &I;
+      }
+    }
+
+    // Prologue can be a max of 3 BBs if we need to call stack extension code
+    if (EndOfPrologMI || BBCount == 3)
+      break;
+
+    ++BBCount;
+  }
+
+  // Leaf functions do not have a prologue.
+  if (EndOfPrologMI == nullptr)
+    return;
+
+#ifdef EXPENSIVE_CHECKS
+  // Check that the prolog length is valid.
+  auto *TII = STI.getInstrInfo();
+  size_t Size = 0;
+
+  for (auto &MBB : *MF) {
+    bool TerminateLoop = false;
+    for (auto &I : MBB) {
+      Size += TII->getInstSizeInBytes(I);
+      if (&I == EndOfPrologMI) {
+        TerminateLoop = true;
+        break;
+      }
+    }
+    if (TerminateLoop)
+      break;
+  }
+  if (Size > 128)
+    report_fatal_error(
+        Twine(MF->getName()).concat(": Prolog exceeds 128 bytes"));
+#endif
+
+  // Attach a temporary symbol to mark the end of the prolog.
+  EndOfPrologSym = MF->getContext().createTempSymbol("end_of_prologue");
+  EndOfPrologMI->setPostInstrSymbol(*MF, EndOfPrologSym);
+
+  if (StackUpdateMI) {
+    StackUpdateSym = MF->getContext().createTempSymbol("stack_update");
+    StackUpdateMI->setPreInstrSymbol(*MF, StackUpdateSym);
+  }
+}
+
+void SystemZXPLINKAsmPrinter::calculatePPA1() {
+  auto *ZOS = getTargetStreamer();
+  assert(ZOS->PPA2Sym != nullptr && "PPA2 Symbol not defined");
+
+  SystemZTargetzOSStreamer::PPA1Info Info;
+
+  const TargetRegisterInfo *TRI = MF->getRegInfo().getTargetRegisterInfo();
+  const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
+
+  const SystemZMachineFunctionInfo *ZFI =
+      MF->getInfo<SystemZMachineFunctionInfo>();
+  const auto *ZFL = static_cast<const SystemZXPLINKFrameLowering *>(
+      Subtarget.getFrameLowering());
+  const MachineFrameInfo &MFFrame = MF->getFrameInfo();
+
+  // Get saved GPR/FPR/VPR masks.
+  const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo();
+  uint16_t SavedGPRMask = 0;
+  uint16_t SavedFPRMask = 0;
+  uint8_t SavedVRMask = 0;
+  int64_t OffsetFPR = 0;
+  int64_t OffsetVR = 0;
+  const int64_t TopOfStack =
+      MFFrame.getOffsetAdjustment() + MFFrame.getStackSize();
+
+  // Loop over the spilled registers. The CalleeSavedInfo can't be used because
+  // it does not contain all spilled registers.
+  for (unsigned I = ZFI->getSpillGPRRegs().LowGPR,
+                E = ZFI->getSpillGPRRegs().HighGPR;
+       I && E && I <= E; ++I) {
+    unsigned V = TRI->getEncodingValue((Register)I);
+    assert(V < 16 && "GPR index out of range");
+    SavedGPRMask |= 1 << (15 - V);
+  }
+
+  for (auto &CS : CSI) {
+    unsigned Reg = CS.getReg();
+    unsigned I = TRI->getEncodingValue(Reg);
+
+    if (SystemZ::FP64BitRegClass.contains(Reg)) {
+      assert(I < 16 && "FPR index out of range");
+      SavedFPRMask |= 1 << (15 - I);
+      int64_t Temp = MFFrame.getObjectOffset(CS.getFrameIdx());
+      if (Temp < OffsetFPR)
+        OffsetFPR = Temp;
+    } else if (SystemZ::VR128BitRegClass.contains(Reg)) {
+      assert(I >= 16 && I <= 23 && "VPR index out of range");
+      unsigned BitNum = I - 16;
+      SavedVRMask |= 1 << (7 - BitNum);
+      int64_t Temp = MFFrame.getObjectOffset(CS.getFrameIdx());
+      if (Temp < OffsetVR)
+        OffsetVR = Temp;
+    }
+  }
+
+  // Adjust the offset.
+  OffsetFPR += (OffsetFPR < 0) ? TopOfStack : 0;
+  OffsetVR += (OffsetVR < 0) ? TopOfStack : 0;
+
+  // Get alloca register.
+  uint8_t FrameReg = TRI->getEncodingValue(TRI->getFrameRegister(*MF));
+  uint8_t AllocaReg = ZFL->hasFP(*MF) ? FrameReg : 0;
+  assert(AllocaReg < 16 && "Can't have alloca register larger than 15");
+
+  MCSymbol *PersonalityRoutine = nullptr;
+  MCSymbol *GCCEH = nullptr;
+  uint64_t PersonalityADADisp = 0;
+  uint64_t GCCEHADADisp = 0;
+  if (!MF->getLandingPads().empty()) {
+    const Function *Per = dyn_cast<Function>(
+        MF->getFunction().getPersonalityFn()->stripPointerCasts());
+    PersonalityRoutine = Per ? MF->getTarget().getSymbol(Per) : nullptr;
+    if (PersonalityRoutine) {
+      GCCEH = MF->getContext().getOrCreateSymbol(
+          Twine("GCC_except_table") + Twine(MF->getFunctionNumber()));
+      PersonalityADADisp = ADATable.insert(
+          PersonalityRoutine, SystemZII::MO_ADA_INDIRECT_FUNC_DESC);
+      GCCEHADADisp = ADATable.insert(GCCEH, SystemZII::MO_ADA_DATA_SYMBOL_ADDR);
+    }
+  }
+
+  // Get the name of the function, with suffix _.
+  std::string N(MF->getFunction().hasName()
+                    ? Twine(MF->getFunction().getName()).concat("_").str()
+                    : "");
+
+  // Calculate the lables for the prolog size and the stack update symbol.
+  MCSymbol *EndOfPrologSym;
+  MCSymbol *StackUpdateSym;
+  determinePrologueStackUpdateSym(MF, EndOfPrologSym, StackUpdateSym);
+
+  // Save the calculated values.
+  if (MF->getFunction().hasFnAttribute("zos-ppa1-name"))
+    Info.Name =
+        MF->getFunction().getFnAttribute("zos-ppa1-name").getValueAsString();
+  else if (MF->getFunction().hasName())
+    Info.Name = MF->getFunction().getName();
+
+  Info.PPA1 = OutContext.createTempSymbol(Twine("PPA1_").concat(N), true);
+  Info.EPMarker = OutContext.createTempSymbol(Twine("EPM_").concat(N), true);
+  Info.FnEnd = OutContext.createTempSymbol(Twine(N).concat("end_"));
+  Info.Fn = CurrentFnSym;
+  Info.EndOfProlog = EndOfPrologSym;
+  Info.StackUpdate = StackUpdateSym;
+  Info.PersonalityADADisp = PersonalityADADisp;
+  Info.GCCEHADADisp = GCCEHADADisp;
+  Info.OffsetFPR = OffsetFPR;
+  Info.OffsetVR = OffsetVR;
+  Info.CallFrameSize = MFFrame.getMaxCallFrameSize();
+  Info.SizeOfFnParams = ZFI->getSizeOfFnParams();
+  Info.SavedGPRMask = SavedGPRMask;
+  Info.SavedFPRMask = SavedFPRMask;
+  Info.SavedVRMask = SavedVRMask;
+  Info.FrameReg = FrameReg;
+  Info.AllocaReg = AllocaReg;
+  Info.IsVarArg = MF->getFunction().isVarArg();
+  Info.HasStackProtector = MFFrame.hasStackProtectorIndex();
+
+  ZOS->DeferredPPA1.push_back(Info);
+}
+
+void SystemZXPLINKAsmPrinter::emitStartOfAsmFile(Module &M) {
+  emitPPA2(M);
+  AsmPrinter::emitStartOfAsmFile(M);
+}
+
+void SystemZXPLINKAsmPrinter::emitPPA2(Module &M) {
+  auto *ZOS = getTargetStreamer();
+  OutStreamer->pushSection();
+  OutStreamer->switchSection(getObjFileLowering().getTextSection());
+  MCContext &OutContext = OutStreamer->getContext();
+  // Make CELQSTRT symbol.
+  const char *StartSymbolName = "CELQSTRT";
+  MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(StartSymbolName);
+  OutStreamer->emitSymbolAttribute(CELQSTRT, MCSA_OSLinkage);
+  OutStreamer->emitSymbolAttribute(CELQSTRT, MCSA_Global);
+
+  // Create symbol and assign to streamer field for use in PPA1.
+  ZOS->PPA2Sym = OutContext.createTempSymbol("PPA2", false);
+  MCSymbol *PPA2Sym = ZOS->PPA2Sym;
+  MCSymbol *DateVersionSym = OutContext.createTempSymbol("DVS", false);
+
+  std::time_t Time = getTranslationTime(M);
+  SmallString<14> CompilationTimeEBCDIC, CompilationTime;
+  CompilationTime = formatv("{0:%Y%m%d%H%M%S}", llvm::sys::toUtcTime(Time));
+
+  uint32_t ProductVersion = getProductVersion(M),
+           ProductRelease = getProductRelease(M),
+           ProductPatch = getProductPatch(M);
+
+  SmallString<6> VersionEBCDIC, Version;
+  Version = formatv("{0,0-2:d}{1,0-2:d}{2,0-2:d}", ProductVersion,
+                    ProductRelease, ProductPatch);
+
+  ConverterEBCDIC::convertToEBCDIC(CompilationTime, CompilationTimeEBCDIC);
+  ConverterEBCDIC::convertToEBCDIC(Version, VersionEBCDIC);
+
+  enum class PPA2MemberId : uint8_t {
+    // See z/OS Language Environment Vendor Interfaces v2r5, p.23, for
+    // complete list. Only the C runtime is supported by this backend.
+    LE_C_Runtime = 3,
+  };
+  enum class PPA2MemberSubId : uint8_t {
+    // List of languages using the LE C runtime implementation.
+    C = 0x00,
+    CXX = 0x01,
+    Swift = 0x03,
+    Go = 0x60,
+    LLVMBasedLang = 0xe7,
+  };
+  // PPA2 Flags
+  enum class PPA2Flags : uint8_t {
+    CompileForBinaryFloatingPoint = 0x80,
+    CompiledWithXPLink = 0x01,
+    CompiledUnitASCII = 0x04,
+    HasServiceInfo = 0x20,
+  };
+
+  PPA2MemberSubId MemberSubId = PPA2MemberSubId::LLVMBasedLang;
+  if (auto *MD = M.getModuleFlag("zos_cu_language")) {
+    StringRef Language = cast<MDString>(MD)->getString();
+    MemberSubId = StringSwitch<PPA2MemberSubId>(Language)
+                      .Case("C", PPA2MemberSubId::C)
+                      .Case("C++", PPA2MemberSubId::CXX)
+                      .Case("Swift", PPA2MemberSubId::Swift)
+                      .Case("Go", PPA2MemberSubId::Go)
+                      .Default(PPA2MemberSubId::LLVMBasedLang);
+  }
+
+  // Emit PPA2 section.
+  OutStreamer->emitLabel(PPA2Sym);
+  OutStreamer->emitInt8(static_cast<uint8_t>(PPA2MemberId::LE_C_Runtime));
+  OutStreamer->emitInt8(static_cast<uint8_t>(MemberSubId));
+  OutStreamer->emitInt8(0x22); // Member defined, c370_plist+c370_env
+  OutStreamer->emitInt8(0x04); // Control level 4 (XPLink)
+  OutStreamer->emitAbsoluteSymbolDiff(CELQSTRT, PPA2Sym, 4);
+  OutStreamer->emitInt32(0x00000000);
+  OutStreamer->emitAbsoluteSymbolDiff(DateVersionSym, PPA2Sym, 4);
+  OutStreamer->emitInt32(
+      0x00000000); // Offset to main entry point, always 0 (so says TR).
+  uint8_t Flgs = static_cast<uint8_t>(PPA2Flags::CompileForBinaryFloatingPoint);
+  Flgs |= static_cast<uint8_t>(PPA2Flags::CompiledWithXPLink);
+
+  bool IsASCII = true;
+  if (auto *MD = M.getModuleFlag("zos_le_char_mode")) {
+    const StringRef &CharMode = cast<MDString>(MD)->getString();
+    if (CharMode == "ebcdic")
+      IsASCII = false;
+    else if (CharMode != "ascii")
+      OutContext.reportError(
+          {}, "Only ascii or ebcdic are allowed for zos_le_char_mode");
+  }
+  if (IsASCII)
+    Flgs |= static_cast<uint8_t>(
+        PPA2Flags::CompiledUnitASCII); // Setting bit for ASCII char. mode.
+
+  OutStreamer->emitInt8(Flgs);
+  OutStreamer->emitInt8(0x00);    // Reserved.
+                                  // No MD5 signature before timestamp.
+                                  // No FLOAT(AFP(VOLATILE)).
+                                  // Remaining 5 flag bits reserved.
+  OutStreamer->emitInt16(0x0000); // 16 Reserved flag bits.
+
+  // Emit date and version section.
+  OutStreamer->emitLabel(DateVersionSym);
+  OutStreamer->emitBytes(CompilationTimeEBCDIC.str());
+  OutStreamer->emitBytes(VersionEBCDIC.str());
+
+  OutStreamer->emitInt16(0x0000); // Service level string length.
+
+  // The binder requires that the offset to the PPA2 be emitted in a different,
+  // specially-named section.
+  OutStreamer->switchSection(getObjFileLowering().getPPA2ListSection());
+  // Emit 8 byte alignment.
+  // Emit pointer to PPA2 label.
+  OutStreamer->AddComment("A(PPA2-CELQSTRT)");
+  OutStreamer->emitAbsoluteSymbolDiff(PPA2Sym, CELQSTRT, 8);
+  OutStreamer->popSection();
+}
+
+void SystemZXPLINKAsmPrinter::emitGlobalAlias(const Module &M,
+                                               const GlobalAlias &GA) {
+  if (!TM.getTargetTriple().isOSzOS())
+    return AsmPrinter::emitGlobalAlias(M, GA);
+
+  // Aliased function labels have already been emitted for z/OS
+}
+
+const MCExpr *SystemZXPLINKAsmPrinter::lowerConstant(const Constant *CV,
+                                                      const Constant *BaseCV,
+                                                      uint64_t Offset) {
+  const GlobalAlias *GA = dyn_cast<GlobalAlias>(CV);
+  const GlobalVariable *GV = dyn_cast<GlobalVariable>(CV);
+  const Function *FV = dyn_cast<Function>(CV);
+  bool IsFunc = !GV && (FV || (GA && isa<Function>(GA->getAliaseeObject())));
+
+  MCSymbol *Sym = NULL;
+
+  if (GA)
+    Sym = getSymbol(GA);
+  else if (IsFunc)
+    Sym = getSymbol(FV);
+  else if (GV)
+    Sym = getSymbol(GV);
+
+  if (IsFunc) {
+    OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
+    if (FV->hasExternalLinkage())
+      return MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
+                                      SystemZ::S_VCon, OutContext);
+    // Trigger creation of function descriptor in ADA for internal
+    // functions.
+    unsigned Disp = ADATable.insert(Sym, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
+    return MCBinaryExpr::createAdd(
+        MCSpecifierExpr::create(
+            MCSymbolRefExpr::create(
+                getObjFileLowering().getADASection()->getBeginSymbol(),
+                OutContext),
+            SystemZ::S_None, OutContext),
+        MCConstantExpr::create(Disp, OutContext), OutContext);
+  }
+  if (Sym) {
+    OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeObject);
+    return MCSymbolRefExpr::create(Sym, OutContext);
+  }
+  return AsmPrinter::lowerConstant(CV);
+}
+
+void SystemZXPLINKAsmPrinter::emitFunctionEntryLabel() {
+  auto *ZOS = getTargetStreamer();
+  calculatePPA1();
+
+  // EntryPoint Marker
+  const MachineFrameInfo &MFFrame = MF->getFrameInfo();
+  bool IsUsingAlloca = MFFrame.hasVarSizedObjects();
+  uint32_t DSASize = MFFrame.getStackSize();
+  bool IsLeaf = DSASize == 0 && MFFrame.getCalleeSavedInfo().empty();
+
+  // Set Flags.
+  uint8_t Flags = 0;
+  if (IsLeaf)
+    Flags |= 0x08;
+  if (IsUsingAlloca)
+    Flags |= 0x04;
+
+  // Combine into top 27 bits of DSASize and bottom 5 bits of Flags.
+  uint32_t DSAAndFlags = DSASize & 0xFFFFFFE0; // (x/32) << 5
+  DSAAndFlags |= Flags;
+
+  // Emit entry point marker section.
+  OutStreamer->AddComment("XPLINK Routine Layout Entry");
+  OutStreamer->emitLabel(ZOS->DeferredPPA1.back().EPMarker);
+  OutStreamer->AddComment("Eyecatcher 0x00C300C500C500");
+  OutStreamer->emitIntValueInHex(0x00C300C500C500, 7); // Eyecatcher.
+  OutStreamer->AddComment("Mark Type C'1'");
+  OutStreamer->emitInt8(0xF1); // Mark Type.
+  OutStreamer->AddComment("Offset to PPA1");
+  OutStreamer->emitAbsoluteSymbolDiff(ZOS->DeferredPPA1.back().PPA1,
+                                      ZOS->DeferredPPA1.back().EPMarker, 4);
+  if (OutStreamer->isVerboseAsm()) {
+    OutStreamer->AddComment("DSA Size 0x" + Twine::utohexstr(DSASize));
+    OutStreamer->AddComment("Entry Flags");
+    if (Flags & 0x08)
+      OutStreamer->AddComment("  Bit 1: 1 = Leaf function");
+    else
+      OutStreamer->AddComment("  Bit 1: 0 = Non-leaf function");
+    if (Flags & 0x04)
+      OutStreamer->AddComment("  Bit 2: 1 = Uses alloca");
+    else
+      OutStreamer->AddComment("  Bit 2: 0 = Does not use alloca");
+  }
+  OutStreamer->emitInt32(DSAAndFlags);
+
+  ZOS->emitADA(CurrentFnSym, getObjFileLowering().getADASection());
+
+  AsmPrinter::emitFunctionEntryLabel();
+
+  const Function *F = &MF->getFunction();
+  // Emit aliasing label for function entry point label.
+  for (const GlobalAlias *Alias : GOAliasMap[F]) {
+    MCSymbol *Sym = getSymbol(Alias);
+    OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
+    emitVisibility(Sym, Alias->getVisibility());
+    emitLinkage(Alias, Sym);
+    OutStreamer->emitLabel(Sym);
+  }
+}
diff --git a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.h
new file mode 100644
index 0000000000000..4d480db06b2db
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.h
@@ -0,0 +1,127 @@
+//===-- SystemZXPLINKAsmPrinter.h - SystemZ XPLINK asm printer --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the SystemZXPLINKAsmPrinter class, which owns all
+// z/OS XPLINK-specific asm printer behaviour: ADA table management, PPA1/PPA2,
+// IDRL, entry-point markers, and XPLINK call/return instruction lowering.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZXPLINKASMPRINTER_H
+#define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZXPLINKASMPRINTER_H
+
+#include "MCTargetDesc/SystemZTargetStreamer.h"
+#include "SystemZAsmPrinter.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
+
+namespace llvm {
+class MCStreamer;
+class MCSymbolGOFF;
+class MachineInstr;
+class Module;
+class raw_ostream;
+
+class LLVM_LIBRARY_VISIBILITY SystemZXPLINKAsmPrinter
+    : public SystemZAsmPrinter {
+
+  /// Call type information for XPLINK.
+  enum class CallType {
+    BASR76 = 0,   // b'x000' == BASR  r7,r6
+    BRAS7 = 1,    // b'x001' == BRAS  r7,ep
+    RESVD_2 = 2,  // b'x010'
+    BRASL7 = 3,   // b'x011' == BRASL r7,ep
+    RESVD_4 = 4,  // b'x100'
+    RESVD_5 = 5,  // b'x101'
+    BALR1415 = 6, // b'x110' == BALR  r14,r15
+    BASR33 = 7,   // b'x111' == BASR  r3,r3
+  };
+
+  // The Associated Data Area (ADA) contains descriptors which help locating
+  // external symbols. For each symbol and type, the displacement into the ADA
+  // is stored.
+  class AssociatedDataAreaTable {
+  public:
+    using DisplacementTable =
+        MapVector<std::pair<const MCSymbol *, unsigned>, uint32_t>;
+
+  private:
+    const uint64_t PointerSize;
+
+    /// The mapping of name/slot type pairs to displacements.
+    DisplacementTable Displacements;
+
+    /// The next available displacement value. Incremented when new entries into
+    /// the ADA are created.
+    uint32_t NextDisplacement = 0;
+
+  public:
+    AssociatedDataAreaTable(uint64_t PointerSize) : PointerSize(PointerSize) {}
+
+    /// @brief Add a function descriptor to the ADA.
+    /// @param MI Pointer to an ADA_ENTRY instruction.
+    /// @return The displacement of the descriptor into the ADA.
+    uint32_t insert(const MachineOperand MO);
+
+    /// @brief Get the displacement into associated data area (ADA) for a name.
+    /// If no displacement is already associated with the name, assign one and
+    /// return it.
+    /// @param Sym The symbol for which the displacement should be returned.
+    /// @param SlotKind The ADA type.
+    /// @return The displacement of the descriptor into the ADA.
+    uint32_t insert(const MCSymbol *Sym, unsigned SlotKind);
+
+    /// Get the table of GOFF displacements.  This is 'const' since it should
+    /// never be modified by anything except the APIs on this class.
+    const DisplacementTable &getTable() const { return Displacements; }
+
+    uint32_t getNextDisplacement() const { return NextDisplacement; }
+  };
+
+  AssociatedDataAreaTable ADATable;
+
+  // Record a list of GlobalAlias associated with a GlobalObject.
+  // This is used for z/OS's extra-label-at-definition aliasing strategy.
+  // This is similar to what is done for AIX.
+  DenseMap<const GlobalObject *, SmallVector<const GlobalAlias *, 1>>
+      GOAliasMap;
+
+  void calculatePPA1();
+  void emitPPA2(Module &M);
+  void emitADASection();
+  void emitIDRLSection(Module &M);
+  void emitCallInformation(CallType CT);
+
+  SystemZTargetzOSStreamer *getTargetStreamer() {
+    MCTargetStreamer *TS = OutStreamer->getTargetStreamer();
+    assert(TS && "do not have a target streamer");
+    return static_cast<SystemZTargetzOSStreamer *>(TS);
+  }
+
+public:
+  SystemZXPLINKAsmPrinter(TargetMachine &TM,
+                           std::unique_ptr<MCStreamer> Streamer);
+
+  // Override AsmPrinter.
+  void emitInstruction(const MachineInstr *MI) override;
+  void emitXXStructorList(const DataLayout &DL, const Constant *List,
+                          bool IsCtor) override;
+  void emitEndOfAsmFile(Module &M) override;
+  bool doInitialization(Module &M) override;
+  void emitFunctionEntryLabel() override;
+  void emitFunctionBodyEnd() override;
+  void emitStartOfAsmFile(Module &M) override;
+  void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override;
+  const MCExpr *lowerConstant(const Constant *CV,
+                              const Constant *BaseCV = nullptr,
+                              uint64_t Offset = 0) override;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZXPLINKASMPRINTER_H

>From b60efa3efd2318451ac8e465075e05394e045355 Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Tue, 11 Aug 2026 10:36:32 -0400
Subject: [PATCH 2/5] fix formatting

---
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp |   9 +-
 .../Target/SystemZ/SystemZELFAsmPrinter.cpp   | 143 ++++++++----------
 .../lib/Target/SystemZ/SystemZELFAsmPrinter.h |   2 +-
 .../SystemZ/SystemZXPLINKAsmPrinter.cpp       |  67 ++++----
 .../Target/SystemZ/SystemZXPLINKAsmPrinter.h  |   2 +-
 5 files changed, 104 insertions(+), 119 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index d4c274bb6bd14..78f4ee79aa414 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -12,14 +12,14 @@
 //===----------------------------------------------------------------------===//
 
 #include "SystemZAsmPrinter.h"
-#include "SystemZELFAsmPrinter.h"
-#include "SystemZXPLINKAsmPrinter.h"
 #include "MCTargetDesc/SystemZGNUInstPrinter.h"
 #include "MCTargetDesc/SystemZHLASMInstPrinter.h"
 #include "MCTargetDesc/SystemZMCAsmInfo.h"
 #include "MCTargetDesc/SystemZMCTargetDesc.h"
+#include "SystemZELFAsmPrinter.h"
 #include "SystemZMCInstLower.h"
 #include "SystemZSubtarget.h"
+#include "SystemZXPLINKAsmPrinter.h"
 #include "TargetInfo/SystemZTargetInfo.h"
 #include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/MC/MCExpr.h"
@@ -634,8 +634,9 @@ char SystemZAsmPrinter::ID = 0;
 INITIALIZE_PASS(SystemZAsmPrinter, "systemz-asm-printer",
                 "SystemZ Assembly Printer", false, false)
 
-static AsmPrinter *createSystemZAsmPrinter(TargetMachine &TM,
-                                           std::unique_ptr<MCStreamer> &&Streamer) {
+static AsmPrinter *
+createSystemZAsmPrinter(TargetMachine &TM,
+                        std::unique_ptr<MCStreamer> &&Streamer) {
   if (TM.getTargetTriple().isOSzOS())
     return new SystemZXPLINKAsmPrinter(TM, std::move(Streamer));
   return new SystemZELFAsmPrinter(TM, std::move(Streamer));
diff --git a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
index d7f12674ea244..c7aaca973e4f6 100644
--- a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
@@ -33,19 +33,16 @@ static unsigned EmitNop(MCContext &OutContext, MCStreamer &OutStreamer,
   if (NumBytes < 2) {
     llvm_unreachable("Zero nops?");
     return 0;
-  }
-  else if (NumBytes < 4) {
+  } else if (NumBytes < 4) {
     OutStreamer.emitInstruction(
         MCInstBuilder(SystemZ::BCRAsm).addImm(0).addReg(SystemZ::R0D), STI);
     return 2;
-  }
-  else if (NumBytes < 6) {
+  } else if (NumBytes < 6) {
     OutStreamer.emitInstruction(
         MCInstBuilder(SystemZ::BCAsm).addImm(0).addReg(0).addImm(0).addReg(0),
         STI);
     return 4;
-  }
-  else {
+  } else {
     MCSymbol *DotSym = OutContext.createTempSymbol();
     const MCSymbolRefExpr *Dot = MCSymbolRefExpr::create(DotSym, OutContext);
     OutStreamer.emitLabel(DotSym);
@@ -63,12 +60,11 @@ static const MCSymbolRefExpr *getTLSGetOffset(MCContext &Context) {
 
 static const MCSymbolRefExpr *getGlobalOffsetTable(MCContext &Context) {
   StringRef Name = "_GLOBAL_OFFSET_TABLE_";
-  return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name),
-                                 Context);
+  return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name), Context);
 }
 
-SystemZELFAsmPrinter::SystemZELFAsmPrinter(
-    TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
+SystemZELFAsmPrinter::SystemZELFAsmPrinter(TargetMachine &TM,
+                                           std::unique_ptr<MCStreamer> Streamer)
     : SystemZAsmPrinter(TM, std::move(Streamer)) {}
 
 void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
@@ -102,46 +98,45 @@ void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
   case SystemZ::CallBRASL: {
     const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
     SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::BRASL)
-                       .addReg(Regs->getReturnFunctionAddressRegister())
-                       .addExpr(Lower.getExpr(MI->getOperand(0),
-                                              SystemZ::S_PLT)));
+    EmitToStreamer(
+        *OutStreamer,
+        MCInstBuilder(SystemZ::BRASL)
+            .addReg(Regs->getReturnFunctionAddressRegister())
+            .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_PLT)));
     return;
   }
   case SystemZ::CallJG:
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::JG).addExpr(
-                       Lower.getExpr(MI->getOperand(0), SystemZ::S_PLT)));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::JG)
+                                     .addExpr(Lower.getExpr(MI->getOperand(0),
+                                                            SystemZ::S_PLT)));
     return;
   case SystemZ::CallBRCL:
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::BRCL)
-                       .addImm(MI->getOperand(0).getImm())
-                       .addImm(MI->getOperand(1).getImm())
-                       .addExpr(Lower.getExpr(MI->getOperand(2),
-                                              SystemZ::S_PLT)));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRCL)
+                                     .addImm(MI->getOperand(0).getImm())
+                                     .addImm(MI->getOperand(1).getImm())
+                                     .addExpr(Lower.getExpr(MI->getOperand(2),
+                                                            SystemZ::S_PLT)));
     return;
   case SystemZ::TLS_GDCALL: {
     const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
     SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::BRASL)
-                       .addReg(Regs->getReturnFunctionAddressRegister())
-                       .addExpr(getTLSGetOffset(MF->getContext()))
-                       .addExpr(Lower.getExpr(MI->getOperand(0),
-                                              SystemZ::S_TLSGD)));
+    EmitToStreamer(
+        *OutStreamer,
+        MCInstBuilder(SystemZ::BRASL)
+            .addReg(Regs->getReturnFunctionAddressRegister())
+            .addExpr(getTLSGetOffset(MF->getContext()))
+            .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_TLSGD)));
     return;
   }
   case SystemZ::TLS_LDCALL: {
     const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
     SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::BRASL)
-                       .addReg(Regs->getReturnFunctionAddressRegister())
-                       .addExpr(getTLSGetOffset(MF->getContext()))
-                       .addExpr(Lower.getExpr(MI->getOperand(0),
-                                              SystemZ::S_TLSLDM)));
+    EmitToStreamer(
+        *OutStreamer,
+        MCInstBuilder(SystemZ::BRASL)
+            .addReg(Regs->getReturnFunctionAddressRegister())
+            .addExpr(getTLSGetOffset(MF->getContext()))
+            .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_TLSLDM)));
     return;
   }
   case SystemZ::GOT:
@@ -163,7 +158,7 @@ void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
 }
 
 void SystemZELFAsmPrinter::LowerFENTRY_CALL(const MachineInstr &MI,
-                                             SystemZMCInstLower &Lower) {
+                                            SystemZMCInstLower &Lower) {
   MCContext &Ctx = MF->getContext();
   if (MF->getFunction().hasFnAttribute("mrecord-mcount")) {
     MCSymbol *DotSym = OutContext.createTempSymbol();
@@ -206,8 +201,7 @@ void SystemZELFAsmPrinter::LowerSTACKMAP(const MachineInstr &MI) {
   MachineBasicBlock::const_iterator MII(MI);
   ++MII;
   while (ShadowBytes < NumNOPBytes) {
-    if (MII == MBB.end() ||
-        MII->getOpcode() == TargetOpcode::PATCHPOINT ||
+    if (MII == MBB.end() || MII->getOpcode() == TargetOpcode::PATCHPOINT ||
         MII->getOpcode() == TargetOpcode::STACKMAP)
       break;
     ShadowBytes += TII->getInstSizeInBytes(*MII);
@@ -225,7 +219,7 @@ void SystemZELFAsmPrinter::LowerSTACKMAP(const MachineInstr &MI) {
 // Lower a patchpoint of the form:
 // [<def>], <id>, <numBytes>, <target>, <numArgs>
 void SystemZELFAsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
-                                            SystemZMCInstLower &Lower) {
+                                           SystemZMCInstLower &Lower) {
   auto &Ctx = OutStreamer->getContext();
   MCSymbol *MILabel = Ctx.createTempSymbol();
   OutStreamer->emitLabel(MILabel);
@@ -248,26 +242,26 @@ void SystemZELFAsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
 
       // Materialize the call target address
       EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LLILF)
-                                      .addReg(ScratchReg)
-                                      .addImm(CallTarget & 0xFFFFFFFF));
+                                       .addReg(ScratchReg)
+                                       .addImm(CallTarget & 0xFFFFFFFF));
       EncodedBytes += 6;
       if (CallTarget >> 32) {
         EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::IIHF)
-                                        .addReg(ScratchReg)
-                                        .addImm(CallTarget >> 32));
+                                         .addReg(ScratchReg)
+                                         .addImm(CallTarget >> 32));
         EncodedBytes += 6;
       }
 
       EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
-                                     .addReg(SystemZ::R14D)
-                                     .addReg(ScratchReg));
+                                       .addReg(SystemZ::R14D)
+                                       .addReg(ScratchReg));
       EncodedBytes += 2;
     }
   } else if (CalleeMO.isGlobal()) {
     const MCExpr *Expr = Lower.getExpr(CalleeMO, SystemZ::S_PLT);
-    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
-                                   .addReg(SystemZ::R14D)
-                                   .addExpr(Expr));
+    EmitToStreamer(
+        *OutStreamer,
+        MCInstBuilder(SystemZ::BRASL).addReg(SystemZ::R14D).addExpr(Expr));
     EncodedBytes += 6;
   }
 
@@ -313,34 +307,32 @@ void SystemZELFAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
   MCSymbol *EndOfSled = OutContext.createTempSymbol();
   OutStreamer->emitLabel(BeginOfSled);
   EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::J).addExpr(
-                     MCSymbolRefExpr::create(EndOfSled, OutContext)));
+                 MCInstBuilder(SystemZ::J)
+                     .addExpr(MCSymbolRefExpr::create(EndOfSled, OutContext)));
   EmitNop(OutContext, *OutStreamer, 2, getSubtargetInfo());
   EmitToStreamer(*OutStreamer,
                  MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
-  EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::BRASL)
-                     .addReg(SystemZ::R14D)
-                     .addExpr(MCSymbolRefExpr::create(
-                         FuncEntry, SystemZ::S_PLT, OutContext)));
+  EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
+                                   .addReg(SystemZ::R14D)
+                                   .addExpr(MCSymbolRefExpr::create(
+                                       FuncEntry, SystemZ::S_PLT, OutContext)));
   OutStreamer->emitLabel(EndOfSled);
   recordSled(BeginOfSled, MI, SledKind::FUNCTION_ENTER, 2);
 }
 
 void SystemZELFAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
-                                               SystemZMCInstLower &Lower) {
+                                              SystemZMCInstLower &Lower) {
   unsigned OpCode = MI.getOperand(0).getImm();
   MCSymbol *FallthroughLabel = nullptr;
   if (OpCode == SystemZ::CondReturn) {
     FallthroughLabel = OutContext.createTempSymbol();
     int64_t Cond0 = MI.getOperand(1).getImm();
     int64_t Cond1 = MI.getOperand(2).getImm();
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::BRC)
-                       .addImm(Cond0)
-                       .addImm(Cond1 ^ Cond0)
-                       .addExpr(MCSymbolRefExpr::create(FallthroughLabel,
-                                                        OutContext)));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRC)
+                                     .addImm(Cond0)
+                                     .addImm(Cond1 ^ Cond0)
+                                     .addExpr(MCSymbolRefExpr::create(
+                                         FallthroughLabel, OutContext)));
   }
   // .begin:
   //   br %r14    # -> stmg    %r2, %r15, 24(%r15)
@@ -363,16 +355,16 @@ void SystemZELFAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
   EmitNop(OutContext, *OutStreamer, 4, getSubtargetInfo());
   EmitToStreamer(*OutStreamer,
                  MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
-  EmitToStreamer(*OutStreamer,
-                 MCInstBuilder(SystemZ::J).addExpr(MCSymbolRefExpr::create(
-                     FuncExit, SystemZ::S_PLT, OutContext)));
+  EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::J)
+                                   .addExpr(MCSymbolRefExpr::create(
+                                       FuncExit, SystemZ::S_PLT, OutContext)));
   if (FallthroughLabel)
     OutStreamer->emitLabel(FallthroughLabel);
   recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2);
 }
 
-void SystemZELFAsmPrinter::lowerLOAD_TLS_BLOCK_ADDR(
-    const MachineInstr &MI, SystemZMCInstLower &Lower) {
+void SystemZELFAsmPrinter::lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
+                                                    SystemZMCInstLower &Lower) {
   Register AddrReg = MI.getOperand(0).getReg();
   const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
 
@@ -420,11 +412,10 @@ void SystemZELFAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(
   }
   // Emit the address load.
   if (M->getPICLevel() == PICLevel::NotPIC) {
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::LARL)
-                       .addReg(AddrReg)
-                       .addExpr(MCSymbolRefExpr::create(getSymbol(GV),
-                                                        OutContext)));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LARL)
+                                     .addReg(AddrReg)
+                                     .addExpr(MCSymbolRefExpr::create(
+                                         getSymbol(GV), OutContext)));
   } else {
     EmitToStreamer(*OutStreamer,
                    MCInstBuilder(SystemZ::LGRL)
@@ -463,7 +454,7 @@ static uint8_t getSpecifierFromModifier(SystemZCP::SystemZCPModifier Modifier) {
 
 void SystemZELFAsmPrinter::emitMachineConstantPoolValue(
     MachineConstantPoolValue *MCPV) {
-  auto *ZCPV = static_cast<SystemZConstantPoolValue*>(MCPV);
+  auto *ZCPV = static_cast<SystemZConstantPoolValue *>(MCPV);
 
   const MCExpr *Expr = MCSymbolRefExpr::create(
       getSymbol(ZCPV->getGlobalValue()),
@@ -473,6 +464,4 @@ void SystemZELFAsmPrinter::emitMachineConstantPoolValue(
   OutStreamer->emitValue(Expr, Size);
 }
 
-void SystemZELFAsmPrinter::emitEndOfAsmFile(Module &M) {
-  emitAttributes(M);
-}
+void SystemZELFAsmPrinter::emitEndOfAsmFile(Module &M) { emitAttributes(M); }
diff --git a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.h
index 2e7916840583b..796b568b3ff0b 100644
--- a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.h
@@ -43,7 +43,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZELFAsmPrinter : public SystemZAsmPrinter {
                                      SystemZMCInstLower &Lower);
   void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower);
   void lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
-                                 SystemZMCInstLower &Lower);
+                                SystemZMCInstLower &Lower);
   void lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI,
                                         SystemZMCInstLower &Lower);
   void emitAttributes(Module &M);
diff --git a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
index 72cd1ee222788..bb16e3cc2c169 100644
--- a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.cpp
@@ -59,12 +59,12 @@ bool SystemZXPLINKAsmPrinter::doInitialization(Module &M) {
     if (IsFunc) {
       if (Alias.hasWeakLinkage() || Alias.hasLinkOnceLinkage())
         OutContext.reportError({},
-                                "Weak alias/reference not supported on z/OS");
+                               "Weak alias/reference not supported on z/OS");
 
       GOAliasMap[Aliasee].push_back(&Alias);
     } else
-      OutContext.reportError(
-          {}, "Only aliases to functions is supported in GOFF.");
+      OutContext.reportError({},
+                             "Only aliases to functions is supported in GOFF.");
   }
   return AsmPrinter::doInitialization(M);
 }
@@ -81,8 +81,9 @@ void SystemZXPLINKAsmPrinter::emitCallInformation(CallType CT) {
                      .addReg(SystemZMC::GR64Regs[static_cast<unsigned>(CT)]));
 }
 
-uint32_t SystemZXPLINKAsmPrinter::AssociatedDataAreaTable::insert(
-    const MCSymbol *Sym, unsigned SlotKind) {
+uint32_t
+SystemZXPLINKAsmPrinter::AssociatedDataAreaTable::insert(const MCSymbol *Sym,
+                                                         unsigned SlotKind) {
   auto Key = std::make_pair(Sym, SlotKind);
   auto It = Displacements.find(Key);
 
@@ -131,27 +132,23 @@ void SystemZXPLINKAsmPrinter::emitInstruction(const MachineInstr *MI) {
 
   switch (MI->getOpcode()) {
   case SystemZ::CallBRASL_XPLINK64:
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::BRASL)
-                       .addReg(SystemZ::R7D)
-                       .addExpr(Lower.getExpr(MI->getOperand(0),
-                                              SystemZ::S_None)));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
+                                     .addReg(SystemZ::R7D)
+                                     .addExpr(Lower.getExpr(MI->getOperand(0),
+                                                            SystemZ::S_None)));
     emitCallInformation(CallType::BRASL7);
     return;
 
   case SystemZ::CallBASR_XPLINK64:
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::BASR)
-                       .addReg(SystemZ::R7D)
-                       .addReg(MI->getOperand(0).getReg()));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
+                                     .addReg(SystemZ::R7D)
+                                     .addReg(MI->getOperand(0).getReg()));
     emitCallInformation(CallType::BASR76);
     return;
 
   case SystemZ::Return_XPLINK:
-    LoweredMI = MCInstBuilder(SystemZ::B)
-                    .addReg(SystemZ::R7D)
-                    .addImm(2)
-                    .addReg(0);
+    LoweredMI =
+        MCInstBuilder(SystemZ::B).addReg(SystemZ::R7D).addImm(2).addReg(0);
     break;
 
   case SystemZ::CondReturn_XPLINK:
@@ -164,10 +161,9 @@ void SystemZXPLINKAsmPrinter::emitInstruction(const MachineInstr *MI) {
     break;
 
   case SystemZ::CallBASR_STACKEXT:
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::BASR)
-                       .addReg(SystemZ::R3D)
-                       .addReg(MI->getOperand(0).getReg()));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
+                                     .addReg(SystemZ::R3D)
+                                     .addReg(MI->getOperand(0).getReg()));
     emitCallInformation(CallType::BASR33);
     return;
 
@@ -195,17 +191,16 @@ void SystemZXPLINKAsmPrinter::emitInstruction(const MachineInstr *MI) {
             MCInstBuilder(SystemZ::LLILF).addReg(TargetReg).addImm(Disp));
       } else
         EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::ALGFI)
-                                        .addReg(TargetReg)
-                                        .addReg(TargetReg)
-                                        .addImm(Disp));
+                                         .addReg(TargetReg)
+                                         .addReg(TargetReg)
+                                         .addImm(Disp));
       Disp = 0;
       Op = Op0;
     }
-    EmitToStreamer(*OutStreamer, MCInstBuilder(Op)
-                                    .addReg(TargetReg)
-                                    .addReg(ADAReg)
-                                    .addImm(Disp)
-                                    .addReg(IndexReg));
+    EmitToStreamer(
+        *OutStreamer,
+        MCInstBuilder(Op).addReg(TargetReg).addReg(ADAReg).addImm(Disp).addReg(
+            IndexReg));
     return;
   }
 
@@ -217,8 +212,8 @@ void SystemZXPLINKAsmPrinter::emitInstruction(const MachineInstr *MI) {
 }
 
 void SystemZXPLINKAsmPrinter::emitXXStructorList(const DataLayout &DL,
-                                                  const Constant *List,
-                                                  bool IsCtor) {
+                                                 const Constant *List,
+                                                 bool IsCtor) {
   assert(TM.getTargetTriple().isOSBinFormatGOFF() && "Only GOFF supported");
 
   SmallVector<Structor, 8> Structors;
@@ -756,7 +751,7 @@ void SystemZXPLINKAsmPrinter::emitPPA2(Module &M) {
 }
 
 void SystemZXPLINKAsmPrinter::emitGlobalAlias(const Module &M,
-                                               const GlobalAlias &GA) {
+                                              const GlobalAlias &GA) {
   if (!TM.getTargetTriple().isOSzOS())
     return AsmPrinter::emitGlobalAlias(M, GA);
 
@@ -764,8 +759,8 @@ void SystemZXPLINKAsmPrinter::emitGlobalAlias(const Module &M,
 }
 
 const MCExpr *SystemZXPLINKAsmPrinter::lowerConstant(const Constant *CV,
-                                                      const Constant *BaseCV,
-                                                      uint64_t Offset) {
+                                                     const Constant *BaseCV,
+                                                     uint64_t Offset) {
   const GlobalAlias *GA = dyn_cast<GlobalAlias>(CV);
   const GlobalVariable *GV = dyn_cast<GlobalVariable>(CV);
   const Function *FV = dyn_cast<Function>(CV);
@@ -784,7 +779,7 @@ const MCExpr *SystemZXPLINKAsmPrinter::lowerConstant(const Constant *CV,
     OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
     if (FV->hasExternalLinkage())
       return MCSpecifierExpr::create(MCSymbolRefExpr::create(Sym, OutContext),
-                                      SystemZ::S_VCon, OutContext);
+                                     SystemZ::S_VCon, OutContext);
     // Trigger creation of function descriptor in ADA for internal
     // functions.
     unsigned Disp = ADATable.insert(Sym, SystemZII::MO_ADA_DIRECT_FUNC_DESC);
diff --git a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.h
index 4d480db06b2db..5b3b1aa78fa42 100644
--- a/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZXPLINKAsmPrinter.h
@@ -105,7 +105,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZXPLINKAsmPrinter
 
 public:
   SystemZXPLINKAsmPrinter(TargetMachine &TM,
-                           std::unique_ptr<MCStreamer> Streamer);
+                          std::unique_ptr<MCStreamer> Streamer);
 
   // Override AsmPrinter.
   void emitInstruction(const MachineInstr *MI) override;

>From fa05b2f41ff01d0c9398a560a5b91396066a4797 Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Fri, 21 Aug 2026 13:42:06 -0400
Subject: [PATCH 3/5] use r14 directly

---
 llvm/lib/Target/SystemZ/CMakeLists.txt           |  4 ++--
 llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp | 16 ++++------------
 2 files changed, 6 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/CMakeLists.txt b/llvm/lib/Target/SystemZ/CMakeLists.txt
index 1dd74c3ff8d5c..51021b30fd073 100644
--- a/llvm/lib/Target/SystemZ/CMakeLists.txt
+++ b/llvm/lib/Target/SystemZ/CMakeLists.txt
@@ -18,11 +18,10 @@ add_public_tablegen_target(SystemZCommonTableGen)
 
 add_llvm_target(SystemZCodeGen
   SystemZAsmPrinter.cpp
-  SystemZELFAsmPrinter.cpp
-  SystemZXPLINKAsmPrinter.cpp
   SystemZCallingConv.cpp
   SystemZConstantPoolValue.cpp
   SystemZCopyPhysRegs.cpp
+  SystemZELFAsmPrinter.cpp
   SystemZElimCompare.cpp
   SystemZFrameLowering.cpp
   SystemZHazardRecognizer.cpp
@@ -43,6 +42,7 @@ add_llvm_target(SystemZCodeGen
   SystemZTargetObjectFile.cpp
   SystemZTargetTransformInfo.cpp
   SystemZTDC.cpp
+  SystemZXPLINKAsmPrinter.cpp
 
   LINK_COMPONENTS
   Analysis
diff --git a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
index c7aaca973e4f6..6a935cdd91a87 100644
--- a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
@@ -87,21 +87,17 @@ void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
     LowerPATCHABLE_RET(*MI, Lower);
     return;
   case SystemZ::CallBASR: {
-    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
-    SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
     EmitToStreamer(*OutStreamer,
                    MCInstBuilder(SystemZ::BASR)
-                       .addReg(Regs->getReturnFunctionAddressRegister())
+                       .addReg(SystemZ::R14D)
                        .addReg(MI->getOperand(0).getReg()));
     return;
   }
   case SystemZ::CallBRASL: {
-    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
-    SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
     EmitToStreamer(
         *OutStreamer,
         MCInstBuilder(SystemZ::BRASL)
-            .addReg(Regs->getReturnFunctionAddressRegister())
+            .addReg(SystemZ::R14D)
             .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_PLT)));
     return;
   }
@@ -118,23 +114,19 @@ void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
                                                             SystemZ::S_PLT)));
     return;
   case SystemZ::TLS_GDCALL: {
-    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
-    SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
     EmitToStreamer(
         *OutStreamer,
         MCInstBuilder(SystemZ::BRASL)
-            .addReg(Regs->getReturnFunctionAddressRegister())
+            .addReg(SystemZ::R14D)
             .addExpr(getTLSGetOffset(MF->getContext()))
             .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_TLSGD)));
     return;
   }
   case SystemZ::TLS_LDCALL: {
-    const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>();
-    SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters();
     EmitToStreamer(
         *OutStreamer,
         MCInstBuilder(SystemZ::BRASL)
-            .addReg(Regs->getReturnFunctionAddressRegister())
+            .addReg(SystemZ::R14D)
             .addExpr(getTLSGetOffset(MF->getContext()))
             .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_TLSLDM)));
     return;

>From 263d9eb73afc8b975709bf87186d15f9ec2f87b4 Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Mon, 24 Aug 2026 12:45:42 -0400
Subject: [PATCH 4/5] formatting fix

---
 .../Target/SystemZ/SystemZELFAsmPrinter.cpp   | 27 +++++++++----------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
index 6a935cdd91a87..a9d47ab2c5713 100644
--- a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
@@ -87,18 +87,16 @@ void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
     LowerPATCHABLE_RET(*MI, Lower);
     return;
   case SystemZ::CallBASR: {
-    EmitToStreamer(*OutStreamer,
-                   MCInstBuilder(SystemZ::BASR)
-                       .addReg(SystemZ::R14D)
-                       .addReg(MI->getOperand(0).getReg()));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
+                                     .addReg(SystemZ::R14D)
+                                     .addReg(MI->getOperand(0).getReg()));
     return;
   }
   case SystemZ::CallBRASL: {
-    EmitToStreamer(
-        *OutStreamer,
-        MCInstBuilder(SystemZ::BRASL)
-            .addReg(SystemZ::R14D)
-            .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_PLT)));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
+                                     .addReg(SystemZ::R14D)
+                                     .addExpr(Lower.getExpr(MI->getOperand(0),
+                                                            SystemZ::S_PLT)));
     return;
   }
   case SystemZ::CallJG:
@@ -114,12 +112,11 @@ void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
                                                             SystemZ::S_PLT)));
     return;
   case SystemZ::TLS_GDCALL: {
-    EmitToStreamer(
-        *OutStreamer,
-        MCInstBuilder(SystemZ::BRASL)
-            .addReg(SystemZ::R14D)
-            .addExpr(getTLSGetOffset(MF->getContext()))
-            .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_TLSGD)));
+    EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
+                                     .addReg(SystemZ::R14D)
+                                     .addExpr(getTLSGetOffset(MF->getContext()))
+                                     .addExpr(Lower.getExpr(MI->getOperand(0),
+                                                            SystemZ::S_TLSGD)));
     return;
   }
   case SystemZ::TLS_LDCALL: {

>From e6e5216065a68ab50825d6e4bc4bf04cc1154ef5 Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Tue, 25 Aug 2026 10:10:29 -0400
Subject: [PATCH 5/5] remove braces

---
 llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
index a9d47ab2c5713..5bdafa1d1da28 100644
--- a/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZELFAsmPrinter.cpp
@@ -86,19 +86,17 @@ void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
   case TargetOpcode::PATCHABLE_RET:
     LowerPATCHABLE_RET(*MI, Lower);
     return;
-  case SystemZ::CallBASR: {
+  case SystemZ::CallBASR:
     EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
                                      .addReg(SystemZ::R14D)
                                      .addReg(MI->getOperand(0).getReg()));
     return;
-  }
-  case SystemZ::CallBRASL: {
+  case SystemZ::CallBRASL:
     EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
                                      .addReg(SystemZ::R14D)
                                      .addExpr(Lower.getExpr(MI->getOperand(0),
                                                             SystemZ::S_PLT)));
     return;
-  }
   case SystemZ::CallJG:
     EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::JG)
                                      .addExpr(Lower.getExpr(MI->getOperand(0),
@@ -111,15 +109,14 @@ void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
                                      .addExpr(Lower.getExpr(MI->getOperand(2),
                                                             SystemZ::S_PLT)));
     return;
-  case SystemZ::TLS_GDCALL: {
+  case SystemZ::TLS_GDCALL:
     EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
                                      .addReg(SystemZ::R14D)
                                      .addExpr(getTLSGetOffset(MF->getContext()))
                                      .addExpr(Lower.getExpr(MI->getOperand(0),
                                                             SystemZ::S_TLSGD)));
     return;
-  }
-  case SystemZ::TLS_LDCALL: {
+  case SystemZ::TLS_LDCALL:
     EmitToStreamer(
         *OutStreamer,
         MCInstBuilder(SystemZ::BRASL)
@@ -127,7 +124,6 @@ void SystemZELFAsmPrinter::emitInstruction(const MachineInstr *MI) {
             .addExpr(getTLSGetOffset(MF->getContext()))
             .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_TLSLDM)));
     return;
-  }
   case SystemZ::GOT:
     EmitToStreamer(*OutStreamer,
                    MCInstBuilder(SystemZ::LARL)



More information about the llvm-commits mailing list