[llvm] [MC][SystemZ] Introduce Target Specific HLASM Streamer for z/OS (PR #130535)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Mar 9 18:09:56 PDT 2025
https://github.com/tltao created https://github.com/llvm/llvm-project/pull/130535
A more fleshed out version of a previous PR https://github.com/llvm/llvm-project/pull/107415. The goal is to provide platforms an alternative to the current MCAsmStreamer which only supports the GNU Asm syntax.
Will be accompanied by an RFC.
Also this PR is meant to give an overview of a more "complete" implementation. I would expect it to be broken down to smaller PRs when we are ready to merge.
>From aa189bdcf65fc034f0fc17d09a7c51e203a9cfd5 Mon Sep 17 00:00:00 2001
From: Tony Tao <tonytao at ca.ibm.com>
Date: Sat, 8 Mar 2025 21:19:42 -0500
Subject: [PATCH] Introduce HLASM Streamer for z/OS
---
llvm/include/llvm/MC/MCSectionGOFF.h | 4 +-
llvm/include/llvm/MC/TargetRegistry.h | 17 +-
llvm/lib/MC/TargetRegistry.cpp | 10 +-
.../SystemZ/MCTargetDesc/CMakeLists.txt | 2 +
.../MCTargetDesc/SystemZHLASMAsmStreamer.cpp | 282 ++++++++++++++++++
.../MCTargetDesc/SystemZHLASMAsmStreamer.h | 122 ++++++++
.../MCTargetDesc/SystemZHLASMInstPrinter.cpp | 20 +-
.../MCTargetDesc/SystemZHLASMInstPrinter.h | 6 +
.../MCTargetDesc/SystemZInstPrinterCommon.h | 6 +-
.../MCTargetDesc/SystemZMCTargetDesc.cpp | 37 ++-
.../MCTargetDesc/SystemZTargetStreamer.cpp | 42 +++
.../MCTargetDesc/SystemZTargetStreamer.h | 27 ++
llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll | 51 ++++
13 files changed, 614 insertions(+), 12 deletions(-)
create mode 100644 llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
create mode 100644 llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
create mode 100644 llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp
create mode 100644 llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll
diff --git a/llvm/include/llvm/MC/MCSectionGOFF.h b/llvm/include/llvm/MC/MCSectionGOFF.h
index 11c0f95364037..bad67dbc4af18 100644
--- a/llvm/include/llvm/MC/MCSectionGOFF.h
+++ b/llvm/include/llvm/MC/MCSectionGOFF.h
@@ -37,7 +37,9 @@ class MCSectionGOFF final : public MCSection {
void printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
raw_ostream &OS,
uint32_t /*Subsection*/) const override {
- OS << "\t.section\t\"" << getName() << "\"\n";
+ // TODO: This isn't fully correct HLASM syntax, but we are not
+ // ready to implement the full solution yet.
+ OS << getName() << " CSECT\n";
}
bool useCodeAlign() const override { return false; }
diff --git a/llvm/include/llvm/MC/TargetRegistry.h b/llvm/include/llvm/MC/TargetRegistry.h
index 363fa03f27a70..0851049f465cb 100644
--- a/llvm/include/llvm/MC/TargetRegistry.h
+++ b/llvm/include/llvm/MC/TargetRegistry.h
@@ -208,8 +208,13 @@ class Target {
using AsmTargetStreamerCtorTy =
MCTargetStreamer *(*)(MCStreamer &S, formatted_raw_ostream &OS,
MCInstPrinter *InstPrint);
- using ObjectTargetStreamerCtorTy = MCTargetStreamer *(*)(
- MCStreamer &S, const MCSubtargetInfo &STI);
+ using AsmStreamerCtorTy =
+ MCStreamer *(*)(MCContext & Ctx,
+ std::unique_ptr<formatted_raw_ostream> OS,
+ MCInstPrinter *IP, std::unique_ptr<MCCodeEmitter> CE,
+ std::unique_ptr<MCAsmBackend> TAB);
+ using ObjectTargetStreamerCtorTy =
+ MCTargetStreamer *(*)(MCStreamer & S, const MCSubtargetInfo &STI);
using MCRelocationInfoCtorTy = MCRelocationInfo *(*)(const Triple &TT,
MCContext &Ctx);
using MCSymbolizerCtorTy = MCSymbolizer *(*)(
@@ -316,6 +321,10 @@ class Target {
/// registered (default = nullptr).
AsmTargetStreamerCtorTy AsmTargetStreamerCtorFn = nullptr;
+ /// Construction function for this target's AsmStreamer, if
+ /// registered (default = nullptr).
+ AsmStreamerCtorTy AsmStreamerCtorFn = nullptr;
+
/// Construction function for this target's obj TargetStreamer, if
/// registered (default = nullptr).
ObjectTargetStreamerCtorTy ObjectTargetStreamerCtorFn = nullptr;
@@ -938,6 +947,10 @@ struct TargetRegistry {
T.NullTargetStreamerCtorFn = Fn;
}
+ static void RegisterAsmStreamer(Target &T, Target::AsmStreamerCtorTy Fn) {
+ T.AsmStreamerCtorFn = Fn;
+ }
+
static void RegisterAsmTargetStreamer(Target &T,
Target::AsmTargetStreamerCtorTy Fn) {
T.AsmTargetStreamerCtorFn = Fn;
diff --git a/llvm/lib/MC/TargetRegistry.cpp b/llvm/lib/MC/TargetRegistry.cpp
index 8f253266c4a7c..ec1c5a91d2728 100644
--- a/llvm/lib/MC/TargetRegistry.cpp
+++ b/llvm/lib/MC/TargetRegistry.cpp
@@ -92,8 +92,14 @@ MCStreamer *Target::createAsmStreamer(MCContext &Ctx,
std::unique_ptr<MCCodeEmitter> CE,
std::unique_ptr<MCAsmBackend> TAB) const {
formatted_raw_ostream &OSRef = *OS;
- MCStreamer *S = llvm::createAsmStreamer(Ctx, std::move(OS), IP,
- std::move(CE), std::move(TAB));
+ MCStreamer *S;
+ if (AsmStreamerCtorFn)
+ S = AsmStreamerCtorFn(Ctx, std::move(OS), IP, std::move(CE),
+ std::move(TAB));
+ else
+ S = llvm::createAsmStreamer(Ctx, std::move(OS), IP, std::move(CE),
+ std::move(TAB));
+
createAsmTargetStreamer(*S, OSRef, IP);
return S;
}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
index 9c00706531b88..c95445637d0b2 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
@@ -2,6 +2,7 @@ add_llvm_component_library(LLVMSystemZDesc
SystemZELFObjectWriter.cpp
SystemZGNUInstPrinter.cpp
SystemZGOFFObjectWriter.cpp
+ SystemZHLASMAsmStreamer.cpp
SystemZHLASMInstPrinter.cpp
SystemZInstPrinterCommon.cpp
SystemZMCAsmBackend.cpp
@@ -9,6 +10,7 @@ add_llvm_component_library(LLVMSystemZDesc
SystemZMCCodeEmitter.cpp
SystemZMCExpr.cpp
SystemZMCTargetDesc.cpp
+ SystemZTargetStreamer.cpp
LINK_COMPONENTS
CodeGenTypes
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
new file mode 100644
index 0000000000000..165feec7a7d43
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
@@ -0,0 +1,282 @@
+//===- SystemZHLASMAsmStreamer.cpp - HLASM Assembly Text Output -----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemZHLASMAsmStreamer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Signals.h"
+#include <sstream>
+
+#include <cmath>
+
+void SystemZHLASMAsmStreamer::EmitEOL() {
+ // Comments are emitted on a new line before the instruction.
+ if (IsVerboseAsm)
+ EmitComment();
+
+ std::istringstream Stream(Str);
+ SmallVector<std::string> Lines;
+ std::string Line;
+ while (std::getline(Stream, Line, '\n'))
+ Lines.push_back(Line);
+
+ for (auto S : Lines) {
+ if (LLVM_LIKELY(S.length() < ContIndicatorColumn)) {
+ FOS << S;
+ // Each line in HLASM must fill the full 80 characters.
+ FOS.PadToColumn(InstLimit);
+ FOS << "\n";
+ } else {
+ // If last character before end of the line is not a space
+ // we must insert an additional non-space character that
+ // is not part of the statement coding. We just reuse
+ // the existing character by making the new substring start
+ // 1 character sooner, thus "duplicating" that character
+ // If The last character is a space. We insert an X instead.
+ std::string TmpSubStr = S.substr(0, ContIndicatorColumn);
+ if (!TmpSubStr.compare(ContIndicatorColumn - 1, 1, " "))
+ TmpSubStr.replace(ContIndicatorColumn - 1, 1, "X");
+
+ FOS << TmpSubStr;
+ FOS.PadToColumn(InstLimit);
+ FOS << "\n";
+
+ size_t Emitted = ContIndicatorColumn - 1;
+
+ while (Emitted < S.length()) {
+ if ((S.length() - Emitted) < ContLen)
+ TmpSubStr = S.substr(Emitted, S.length());
+ else {
+ TmpSubStr = S.substr(Emitted, ContLen);
+ if (!TmpSubStr.compare(ContLen - 1, 1, " "))
+ TmpSubStr.replace(ContLen - 1, 1, "X");
+ }
+ FOS.PadToColumn(ContStartColumn);
+ FOS << TmpSubStr;
+ FOS.PadToColumn(InstLimit);
+ FOS << "\n";
+ Emitted += ContLen - 1;
+ }
+ }
+ }
+ Str.clear();
+}
+
+void SystemZHLASMAsmStreamer::changeSection(MCSection *Section,
+ uint32_t Subsection) {
+ Section->printSwitchToSection(*MAI, getContext().getTargetTriple(), OS,
+ Subsection);
+ MCStreamer::changeSection(Section, Subsection);
+}
+
+void SystemZHLASMAsmStreamer::emitAlignmentDS(uint64_t ByteAlignment,
+ std::optional<int64_t> Value,
+ unsigned ValueSize,
+ unsigned MaxBytesToEmit) {
+ if (!isPowerOf2_64(ByteAlignment))
+ report_fatal_error("Only power-of-two alignments are supported ");
+
+ OS << " DS 0";
+ switch (ValueSize) {
+ default:
+ llvm_unreachable("Invalid size for machine code value!");
+ case 1:
+ OS << "B";
+ break;
+ case 2:
+ OS << "H";
+ break;
+ case 4:
+ OS << "F";
+ break;
+ case 8:
+ OS << "D";
+ break;
+ case 16:
+ OS << "Q";
+ break;
+ }
+
+ EmitEOL();
+}
+
+void SystemZHLASMAsmStreamer::AddComment(const Twine &T, bool EOL) {
+ if (!IsVerboseAsm)
+ return;
+
+ T.toVector(CommentToEmit);
+
+ if (EOL)
+ CommentToEmit.push_back('\n'); // Place comment in a new line.
+}
+
+void SystemZHLASMAsmStreamer::EmitComment() {
+ if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0)
+ return;
+
+ StringRef Comments = CommentToEmit;
+
+ assert(Comments.back() == '\n' && "Comment array not newline terminated");
+ do {
+ // Emit a line of comments, but not exceeding 80 characters.
+ size_t Position = std::min(InstLimit - 2, Comments.find('\n'));
+ FOS << MAI->getCommentString() << ' ' << Comments.substr(0, Position)
+ << '\n';
+
+ if (Comments[Position] == '\n')
+ Position++;
+ Comments = Comments.substr(Position);
+ } while (!Comments.empty());
+
+ CommentToEmit.clear();
+}
+
+void SystemZHLASMAsmStreamer::emitValueToAlignment(Align Alignment,
+ int64_t Value,
+ unsigned ValueSize,
+ unsigned MaxBytesToEmit) {
+ emitAlignmentDS(Alignment.value(), Value, ValueSize, MaxBytesToEmit);
+}
+
+void SystemZHLASMAsmStreamer::emitCodeAlignment(Align Alignment,
+ const MCSubtargetInfo *STI,
+ unsigned MaxBytesToEmit) {
+ // Emit with a text fill value.
+ if (MAI->getTextAlignFillValue())
+ emitAlignmentDS(Alignment.value(), MAI->getTextAlignFillValue(), 1,
+ MaxBytesToEmit);
+ else
+ emitAlignmentDS(Alignment.value(), std::nullopt, 1, MaxBytesToEmit);
+}
+
+void SystemZHLASMAsmStreamer::emitBytes(StringRef Data) {
+ assert(getCurrentSectionOnly() &&
+ "Cannot emit contents before setting section!");
+ if (Data.empty())
+ return;
+
+ OS << " DC ";
+ size_t Len = Data.size();
+ SmallVector<uint8_t> Chars;
+ Chars.resize(Len);
+ OS << "XL" << Len;
+ uint32_t Index = 0;
+ for (uint8_t C : Data) {
+ Chars[Index] = C;
+ Index++;
+ }
+
+ OS << '\'' << toHex(Chars) << '\'';
+
+ EmitEOL();
+}
+
+void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+
+ InstPrinter->printInst(&Inst, 0, "", STI, OS);
+ EmitEOL();
+}
+
+void SystemZHLASMAsmStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
+
+ MCStreamer::emitLabel(Symbol, Loc);
+
+ Symbol->print(OS, MAI);
+ // TODO Need to adjust this based on Label type
+ OS << " DS 0H";
+ // TODO Update LabelSuffix in SystemZMCAsmInfoGOFF once tests have been
+ // moved to HLASM syntax.
+ // OS << MAI->getLabelSuffix();
+ EmitEOL();
+}
+
+void SystemZHLASMAsmStreamer::emitRawTextImpl(StringRef String) {
+ String.consume_back("\n");
+ OS << String;
+ EmitEOL();
+}
+
+// Slight duplicate of MCExpr::print due to HLASM only recognizing limited
+// arithmetic operators (+-*/).
+void SystemZHLASMAsmStreamer::emitHLASMValueImpl(const MCExpr *Value,
+ unsigned Size, bool Parens) {
+ switch (Value->getKind()) {
+ case MCExpr::Constant: {
+ OS << "XL" << Size << '\'';
+ Value->print(OS, MAI);
+ OS << '\'';
+ return;
+ }
+ case MCExpr::Binary: {
+ const MCBinaryExpr &BE = cast<MCBinaryExpr>(*Value);
+ int64_t Const;
+ // Or is handled differently.
+ if (BE.getOpcode() == MCBinaryExpr::Or) {
+ emitHLASMValueImpl(BE.getLHS(), Size, true);
+ OS << ',';
+ emitHLASMValueImpl(BE.getRHS(), Size, true);
+ return;
+ }
+
+ if (Parens)
+ OS << "A(";
+ emitHLASMValueImpl(BE.getLHS(), Size);
+
+ switch (BE.getOpcode()) {
+ case MCBinaryExpr::LShr: {
+ Const = cast<MCConstantExpr>(BE.getRHS())->getValue();
+ OS << '/' << (1 << Const);
+ if (Parens)
+ OS << ')';
+ return;
+ }
+ case MCBinaryExpr::Add:
+ OS << '+';
+ break;
+ case MCBinaryExpr::Div:
+ OS << '/';
+ break;
+ case MCBinaryExpr::Mul:
+ OS << '*';
+ break;
+ case MCBinaryExpr::Sub:
+ OS << '-';
+ break;
+ default:
+ getContext().reportError(SMLoc(),
+ "Unrecognized HLASM arithmetic expression!");
+ }
+ emitHLASMValueImpl(BE.getRHS(), Size);
+ if (Parens)
+ OS << ')';
+ return;
+ }
+ case MCExpr::Target:
+ Value->print(OS, MAI);
+ return;
+ default:
+ if (Parens)
+ OS << "A(";
+ Value->print(OS, MAI);
+ if (Parens)
+ OS << ')';
+ return;
+ }
+}
+
+void SystemZHLASMAsmStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
+ SMLoc Loc) {
+ assert(Size <= 8 && "Invalid size");
+ assert(getCurrentSectionOnly() &&
+ "Cannot emit contents before setting section!");
+
+ OS << " DC ";
+ emitHLASMValueImpl(Value, Size, true);
+ EmitEOL();
+}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
new file mode 100644
index 0000000000000..bf04eb850c403
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
@@ -0,0 +1,122 @@
+//===- SystemZHLASMAsmStreamer.h - HLASM Assembly Text Output ---*- 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 SystemZHLASMAsmStreamer class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+
+class SystemZHLASMAsmStreamer final : public MCStreamer {
+ constexpr static size_t InstLimit = 80;
+ constexpr static size_t ContIndicatorColumn = 72;
+ constexpr static size_t ContStartColumn = 15;
+ constexpr static size_t ContLen = ContIndicatorColumn - ContStartColumn;
+ std::unique_ptr<formatted_raw_ostream> FOSOwner;
+ formatted_raw_ostream &FOS;
+ std::string Str;
+ raw_string_ostream OS;
+ const MCAsmInfo *MAI;
+ std::unique_ptr<MCInstPrinter> InstPrinter;
+ std::unique_ptr<MCAssembler> Assembler;
+ SmallString<128> CommentToEmit;
+ raw_svector_ostream CommentStream;
+ raw_null_ostream NullStream;
+ bool IsVerboseAsm = false;
+
+public:
+ SystemZHLASMAsmStreamer(MCContext &Context,
+ std::unique_ptr<formatted_raw_ostream> os,
+ MCInstPrinter *printer,
+ std::unique_ptr<MCCodeEmitter> emitter,
+ std::unique_ptr<MCAsmBackend> asmbackend)
+ : MCStreamer(Context), FOSOwner(std::move(os)), FOS(*FOSOwner), OS(Str),
+ MAI(Context.getAsmInfo()), InstPrinter(printer),
+ Assembler(std::make_unique<MCAssembler>(
+ Context, std::move(asmbackend), std::move(emitter),
+ (asmbackend) ? asmbackend->createObjectWriter(NullStream)
+ : nullptr)),
+ CommentStream(CommentToEmit) {
+ assert(InstPrinter);
+ if (Assembler->getBackendPtr())
+ setAllowAutoPadding(Assembler->getBackend().allowAutoPadding());
+
+ Context.setUseNamesOnTempLabels(true);
+ auto *TO = Context.getTargetOptions();
+ if (!TO)
+ return;
+ IsVerboseAsm = TO->AsmVerbose;
+ if (IsVerboseAsm)
+ InstPrinter->setCommentStream(CommentStream);
+ }
+
+ MCAssembler &getAssembler() { return *Assembler; }
+
+ void EmitEOL();
+ void EmitComment();
+
+ /// Add a comment that can be emitted to the generated .s file to make the
+ /// output of the compiler more readable. This only affects the MCAsmStreamer
+ /// and only when verbose assembly output is enabled.
+ void AddComment(const Twine &T, bool EOL = true) override;
+
+ void emitBytes(StringRef Data) override;
+
+ void emitAlignmentDS(uint64_t ByteAlignment, std::optional<int64_t> Value,
+ unsigned ValueSize, unsigned MaxBytesToEmit);
+ void emitValueToAlignment(Align Alignment, int64_t Value = 0,
+ unsigned ValueSize = 1,
+ unsigned MaxBytesToEmit = 0) override;
+
+ void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
+ unsigned MaxBytesToEmit = 0) override;
+
+ /// Return true if this streamer supports verbose assembly at all.
+ bool isVerboseAsm() const override { return IsVerboseAsm; }
+
+ /// Do we support EmitRawText?
+ bool hasRawTextSupport() const override { return true; }
+
+ /// @name MCStreamer Interface
+ /// @{
+
+ void changeSection(MCSection *Section, uint32_t Subsection) override;
+
+ void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
+ void emitLabel(MCSymbol *Symbol, SMLoc Loc) override;
+ bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
+ return false;
+ }
+
+ void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ Align ByteAlignment) override {}
+
+ void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
+ uint64_t Size = 0, Align ByteAlignment = Align(1),
+ SMLoc Loc = SMLoc()) override {}
+ void emitRawTextImpl(StringRef String) override;
+ void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override;
+
+ void emitHLASMValueImpl(const MCExpr *Value, unsigned Size,
+ bool Parens = false);
+ /// @}
+};
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMInstPrinter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMInstPrinter.cpp
index ef9881932f7c0..1ecfd4ec4640e 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMInstPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMInstPrinter.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "SystemZHLASMInstPrinter.h"
+#include "SystemZInstrInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegister.h"
#include "llvm/Support/raw_ostream.h"
@@ -34,8 +35,8 @@ void SystemZHLASMInstPrinter::printInst(const MCInst *MI, uint64_t Address,
raw_string_ostream RSO(Str);
printInstruction(MI, Address, RSO);
// Eat the first tab character and replace it with a space since it is
- // hardcoded in AsmWriterEmitter::EmitPrintInstruction
- // TODO: introduce a line prefix member to AsmWriter to avoid this problem
+ // hardcoded in AsmWriterEmitter::EmitPrintInstruction.
+ // TODO Introduce a line prefix member to AsmWriter to avoid this problem.
if (!Str.empty() && Str.front() == '\t')
O << " " << Str.substr(1, Str.length());
else
@@ -43,3 +44,18 @@ void SystemZHLASMInstPrinter::printInst(const MCInst *MI, uint64_t Address,
printAnnotation(O, Annot);
}
+
+void SystemZHLASMInstPrinter::printPCRelOperand(const MCInst *MI, int OpNum,
+ raw_ostream &O) {
+ const MCOperand &MO = MI->getOperand(OpNum);
+ if (MO.isImm()) {
+ WithMarkup M = markup(O, Markup::Immediate);
+ O << "0x";
+ O.write_hex(MO.getImm());
+ } else {
+ // Don't print @PLT.
+ // TODO May need to do something more here.
+ const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*(MO.getExpr()));
+ O << SRE.getSymbol().getName();
+ }
+}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMInstPrinter.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMInstPrinter.h
index 2732986dbca7d..8cd3c004f4035 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMInstPrinter.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMInstPrinter.h
@@ -36,6 +36,12 @@ class SystemZHLASMInstPrinter : public SystemZInstPrinterCommon {
void printInst(const MCInst *MI, uint64_t Address, StringRef Annot,
const MCSubtargetInfo &STI, raw_ostream &O) override;
+ void printPCRelOperand(const MCInst *MI, int OpNum, raw_ostream &O) override;
+ void printPCRelOperand(const MCInst *MI, uint64_t /*Address*/, int OpNum,
+ raw_ostream &O) override {
+ printPCRelOperand(MI, OpNum, O);
+ }
+
private:
void printFormattedRegName(const MCAsmInfo *MAI, MCRegister Reg,
raw_ostream &O) override;
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinterCommon.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinterCommon.h
index 304aa03d988dc..78a291a427d85 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinterCommon.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinterCommon.h
@@ -71,9 +71,9 @@ class SystemZInstPrinterCommon : public MCInstPrinter {
void printS32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printU32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
void printU48ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
- void printPCRelOperand(const MCInst *MI, int OpNum, raw_ostream &O);
- void printPCRelOperand(const MCInst *MI, uint64_t /*Address*/, int OpNum,
- raw_ostream &O) {
+ virtual void printPCRelOperand(const MCInst *MI, int OpNum, raw_ostream &O);
+ virtual void printPCRelOperand(const MCInst *MI, uint64_t /*Address*/,
+ int OpNum, raw_ostream &O) {
printPCRelOperand(MI, OpNum, O);
}
void printPCRelTLSOperand(const MCInst *MI, uint64_t Address, int OpNum,
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp
index e84368c769e29..35bc9c8a510cd 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp
@@ -8,6 +8,7 @@
#include "SystemZMCTargetDesc.h"
#include "SystemZGNUInstPrinter.h"
+#include "SystemZHLASMAsmStreamer.h"
#include "SystemZHLASMInstPrinter.h"
#include "SystemZMCAsmInfo.h"
#include "SystemZTargetStreamer.h"
@@ -21,6 +22,7 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/CommandLine.h"
using namespace llvm;
@@ -34,6 +36,12 @@ using namespace llvm;
#define GET_REGINFO_MC_DESC
#include "SystemZGenRegisterInfo.inc"
+// Temporary option to assist with the migration to a new HLASMAsmStreamer on
+// z/OS
+static cl::opt<bool> GNUAsOnzOSCL("emit-gnuas-syntax-on-zos",
+ cl::desc("Emit GNU Assembly Syntax on z/OS."),
+ cl::init(true));
+
const unsigned SystemZMC::GR32Regs[16] = {
SystemZ::R0L, SystemZ::R1L, SystemZ::R2L, SystemZ::R3L,
SystemZ::R4L, SystemZ::R5L, SystemZ::R6L, SystemZ::R7L,
@@ -212,12 +220,33 @@ class SystemZTargetELFStreamer : public SystemZTargetStreamer {
static MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S,
formatted_raw_ostream &OS,
MCInstPrinter *InstPrint) {
- return new SystemZTargetAsmStreamer(S, OS);
+ if (S.getContext().getTargetTriple().isOSzOS())
+ return new SystemZTargetHLASMStreamer(S, OS);
+ else
+ return new SystemZTargetAsmStreamer(S, OS);
+}
+
+static MCStreamer *createAsmStreamer(MCContext &Ctx,
+ std::unique_ptr<formatted_raw_ostream> OS,
+ MCInstPrinter *IP,
+ std::unique_ptr<MCCodeEmitter> CE,
+ std::unique_ptr<MCAsmBackend> TAB) {
+
+ auto TT = Ctx.getTargetTriple();
+ if (TT.isOSzOS() && !GNUAsOnzOSCL)
+ return new SystemZHLASMAsmStreamer(Ctx, std::move(OS), IP, std::move(CE),
+ std::move(TAB));
+
+ return llvm::createAsmStreamer(Ctx, std::move(OS), IP, std::move(CE),
+ std::move(TAB));
}
static MCTargetStreamer *
createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
- return new SystemZTargetELFStreamer(S);
+ if (S.getContext().getTargetTriple().isOSzOS())
+ return new SystemZTargetGOFFStreamer(S);
+ else
+ return new SystemZTargetELFStreamer(S);
}
static MCTargetStreamer *
@@ -259,6 +288,10 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSystemZTargetMC() {
createSystemZMCInstPrinter);
// Register the asm streamer.
+ TargetRegistry::RegisterAsmStreamer(getTheSystemZTarget(),
+ createAsmStreamer);
+
+ // Register the asm target streamer.
TargetRegistry::RegisterAsmTargetStreamer(getTheSystemZTarget(),
createAsmTargetStreamer);
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp
new file mode 100644
index 0000000000000..94e2d20d7fda5
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp
@@ -0,0 +1,42 @@
+//==-- SystemZTargetStreamer.cpp - SystemZ Target Streamer Methods ----------=//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines SystemZ-specific target streamer classes.
+/// These are for implementing support for target-specific assembly directives.
+///
+//===----------------------------------------------------------------------===//
+
+#include "SystemZTargetStreamer.h"
+
+using namespace llvm;
+
+void SystemZTargetHLASMStreamer::emitExtern(StringRef Sym) {
+ getStreamer().emitRawText(Twine(" EXTRN ") + Twine(Sym));
+}
+
+// HLASM statements can only perform a single operation at a time
+const MCExpr *SystemZTargetHLASMStreamer::createWordDiffExpr(MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) {
+ assert(Hi && Lo && "Symbols required to calculate expression");
+ MCSymbol *Temp = Ctx.createTempSymbol();
+ OS << Temp->getName() << " EQU ";
+ const MCBinaryExpr *TempExpr = MCBinaryExpr::createSub(MCSymbolRefExpr::create(Hi, Ctx),
+ MCSymbolRefExpr::create(Lo, Ctx), Ctx);
+ TempExpr->print(OS, Ctx.getAsmInfo());
+ OS << "\n";
+ return MCBinaryExpr::createLShr(MCSymbolRefExpr::create(Temp, Ctx),
+ MCConstantExpr::create(1, Ctx), Ctx);
+}
+
+const MCExpr *SystemZTargetGOFFStreamer::createWordDiffExpr(MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) {
+ assert(Hi && Lo && "Symbols required to calculate expression");
+ return MCBinaryExpr::createLShr(
+ MCBinaryExpr::createSub(MCSymbolRefExpr::create(Hi, Ctx),
+ MCSymbolRefExpr::create(Lo, Ctx), Ctx),
+ MCConstantExpr::create(1, Ctx), Ctx);
+}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h
index 4c7a6ca386433..bd71dfac0a070 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h
@@ -10,8 +10,12 @@
#define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZTARGETSTREAMER_H
#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/FormattedStream.h"
#include <map>
#include <utility>
@@ -51,6 +55,29 @@ class SystemZTargetStreamer : public MCTargetStreamer {
void emitConstantPools() override;
virtual void emitMachine(StringRef CPU) {};
+
+ virtual void emitExtern(StringRef Str) {};
+
+ virtual const MCExpr *createWordDiffExpr(MCContext &Ctx, const MCSymbol *Hi,
+ const MCSymbol *Lo) { return nullptr; }
+};
+
+class SystemZTargetGOFFStreamer : public SystemZTargetStreamer {
+public:
+ SystemZTargetGOFFStreamer(MCStreamer &S) : SystemZTargetStreamer(S) {}
+ const MCExpr *createWordDiffExpr(MCContext &Ctx, const MCSymbol *Hi,
+ const MCSymbol *Lo) override;
+};
+
+class SystemZTargetHLASMStreamer : public SystemZTargetStreamer {
+ formatted_raw_ostream &OS;
+
+public:
+ SystemZTargetHLASMStreamer(MCStreamer &S, formatted_raw_ostream &OS)
+ : SystemZTargetStreamer(S), OS(OS) {}
+ void emitExtern(StringRef Sym) override;
+ const MCExpr *createWordDiffExpr(MCContext &Ctx, const MCSymbol *Hi,
+ const MCSymbol *Lo) override;
};
} // end namespace llvm
diff --git a/llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll b/llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll
new file mode 100644
index 0000000000000..fc52de6c387d1
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll
@@ -0,0 +1,51 @@
+; Test the HLASM streamer on z/OS to ensure there's no GNU syntax anywhere
+
+; RUN: llc < %s -mtriple=s390x-ibm-zos -emit-gnuas-syntax-on-zos=0 | FileCheck %s
+
+ at .str = private unnamed_addr constant [10 x i8] c"Hello %s\0A\00", align 2
+ at Greeting = global ptr @.str, align 8
+ at .str.1 = private unnamed_addr constant [6 x i8] c"World\00", align 2
+
+; Function Attrs: noinline nounwind optnone
+define void @foo() {
+; CHECK-LABEL: L#PPA2 DS 0H
+; CHECK: DC XL1'03'
+; CHECK: DC XL1'E7'
+; CHECK: DC XL1'22'
+; CHECK: DC XL1'04'
+; CHECK: DC A(CELQSTRT-L#PPA2)
+; CHECK: DC XL4'00000000'
+; CHECK: DC A(L#DVS-L#PPA2)
+; CHECK: DC XL4'00000000'
+; CHECK: DC XL1'81'
+; CHECK: DC XL1'00'
+; CHECK: DC XL2'0000'
+; CHECK-LABEL: L#PPA1_foo_0 DS 0H
+; CHECK: DC XL1'02'
+; CHECK: DC XL1'CE'
+; CHECK: DC XL2'0300'
+; CHECK: DC A(L#PPA2-L#PPA1_foo_0)
+; CHECK: DC XL1'80'
+; CHECK: DC XL1'80'
+; CHECK: DC XL1'00'
+; CHECK: DC XL1'81'
+; CHECK: DC XL2'0000'
+; CHECK: DC A(L#func_end0-L#EPM_foo_0)
+; CHECK: DC XL2'0003'
+; CHECK: DC XL3'869696'
+; CHECK: DC A(L#EPM_foo_0-L#PPA1_foo_0)
+; CHECK-LABEL: L#.str DS 0H
+; CHECK: DC XL10'48656C6C6F2025730A00'
+; CHECK: DS 0B
+; CHECK-LABEL: Greeting DS 0H
+; CHECK: DC A(L#.str)
+; CHECK: DS 0B
+; CHECK-LABEL: L#.str.1 DS 0H
+; CHECK: DC XL6'576F726C6400'
+entry:
+ %0 = load ptr, ptr @Greeting, align 8
+ call void (ptr, ...) @outs(ptr noundef %0, ptr noundef @.str.1)
+ ret void
+}
+
+declare void @outs(ptr noundef, ...)
More information about the llvm-commits
mailing list