diff --git a/llvm/include/llvm/MC/TargetRegistry.h b/llvm/include/llvm/MC/TargetRegistry.h index 363fa03f27a70..bf8210cbe644e 100644 --- a/llvm/include/llvm/MC/TargetRegistry.h +++ b/llvm/include/llvm/MC/TargetRegistry.h @@ -208,14 +208,19 @@ 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 OS, + MCInstPrinter *IP, std::unique_ptr CE, + std::unique_ptr 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 &&RelInfo); + using MCSymbolizerCtorTy = + MCSymbolizer *(*)(const Triple &TT, LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp, void *DisInfo, + MCContext *Ctx, + std::unique_ptr &&RelInfo); using CustomBehaviourCtorTy = mca::CustomBehaviour *(*)(const MCSubtargetInfo &STI, @@ -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 CE, std::unique_ptr 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 + +#include + +void SystemZHLASMAsmStreamer::EmitEOL() { + // Comments are emitted on a new line before the instruction. + if (IsVerboseAsm) + EmitComment(); + + std::istringstream Stream(Str); + SmallVector 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 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 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(*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(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 FOSOwner; + formatted_raw_ostream &FOS; + std::string Str; + raw_string_ostream OS; + const MCAsmInfo *MAI; + std::unique_ptr InstPrinter; + std::unique_ptr Assembler; + SmallString<128> CommentToEmit; + raw_svector_ostream CommentStream; + raw_null_ostream NullStream; + bool IsVerboseAsm = false; + +public: + SystemZHLASMAsmStreamer(MCContext &Context, + std::unique_ptr os, + MCInstPrinter *printer, + std::unique_ptr emitter, + std::unique_ptr asmbackend) + : MCStreamer(Context), FOSOwner(std::move(os)), FOS(*FOSOwner), OS(Str), + MAI(Context.getAsmInfo()), InstPrinter(printer), + Assembler(std::make_unique( + 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 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/SystemZMCTargetDesc.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp index e84368c769e29..0fb5c30d37d2b 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 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 OS, + MCInstPrinter *IP, + std::unique_ptr CE, + std::unique_ptr 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); diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp new file mode 100644 index 0000000000000..1946cd1da8506 --- /dev/null +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.cpp @@ -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); +} diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZTargetStreamer.h index 4c7a6ca386433..26be26e287412 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 #include @@ -51,6 +55,31 @@ 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 + +@.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, ...)