[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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
282
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
Normal file
282
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
Normal 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();
|
||||
}
|
||||
122
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
Normal file
122
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
Normal 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);
|
||||
/// @}
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
51
llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll
Normal file
51
llvm/test/CodeGen/SystemZ/zos-hlasm-out.ll
Normal 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, ...)
|
||||
Reference in New Issue
Block a user