[MC][SystemZ] Introduce Target Specific HLASM Streamer for z/OS (#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.

RFC:
https://discourse.llvm.org/t/rfc-llvm-add-support-for-target-specific-asm-streamer/85095

---------

Co-authored-by: Tony Tao <tonytao@ca.ibm.com>
This commit is contained in:
tltao
2025-03-21 11:36:35 -04:00
committed by GitHub
parent d4ce57cb98
commit f7a32b85b5
9 changed files with 591 additions and 10 deletions

View File

@@ -208,14 +208,19 @@ public:
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 *(*)(
const Triple &TT, LLVMOpInfoCallback GetOpInfo,
LLVMSymbolLookupCallback SymbolLookUp, void *DisInfo, MCContext *Ctx,
std::unique_ptr<MCRelocationInfo> &&RelInfo);
using MCSymbolizerCtorTy =
MCSymbolizer *(*)(const Triple &TT, LLVMOpInfoCallback GetOpInfo,
LLVMSymbolLookupCallback SymbolLookUp, void *DisInfo,
MCContext *Ctx,
std::unique_ptr<MCRelocationInfo> &&RelInfo);
using CustomBehaviourCtorTy =
mca::CustomBehaviour *(*)(const MCSubtargetInfo &STI,
@@ -316,6 +321,10 @@ private:
/// 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;
@@ -948,6 +957,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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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);
/// @}
};

View File

@@ -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 @@ public:
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,9 @@ 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);

View File

@@ -0,0 +1,44 @@
//==-- 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);
}

View File

@@ -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,31 @@ public:
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

View File

@@ -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
@.str = private unnamed_addr constant [10 x i8] c"Hello %s\0A\00", align 2
@Greeting = global ptr @.str, align 8
@.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, ...)