[llvm] 3adc2a0 - [SystemZ/zOS/GOFF] Implement GOFF writer for empty files.
Kai Nacke via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 29 12:27:31 PDT 2023
Author: Kai Nacke
Date: 2023-09-29T19:27:11Z
New Revision: 3adc2a0b84d0fbccead5d77d1b7d7a9b0bec175d
URL: https://github.com/llvm/llvm-project/commit/3adc2a0b84d0fbccead5d77d1b7d7a9b0bec175d
DIFF: https://github.com/llvm/llvm-project/commit/3adc2a0b84d0fbccead5d77d1b7d7a9b0bec175d.diff
LOG: [SystemZ/zOS/GOFF] Implement GOFF writer for empty files.
Set ups the infrastructure to create an empty GOFF file.
Also adds a GOFF writer which writes only HDR/END records.
Reviewed By: jhenderson, kpn
Differential Revision: https://reviews.llvm.org/D111437
Added:
llvm/include/llvm/MC/MCGOFFObjectWriter.h
llvm/include/llvm/MC/MCGOFFStreamer.h
llvm/lib/MC/GOFFObjectWriter.cpp
llvm/lib/MC/MCGOFFStreamer.cpp
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp
llvm/test/MC/GOFF/empty-goff.s
Modified:
llvm/include/llvm/BinaryFormat/GOFF.h
llvm/include/llvm/MC/TargetRegistry.h
llvm/lib/MC/CMakeLists.txt
llvm/lib/MC/MCAsmBackend.cpp
llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h
Removed:
llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
################################################################################
diff --git a/llvm/include/llvm/BinaryFormat/GOFF.h b/llvm/include/llvm/BinaryFormat/GOFF.h
index b4ddbabdf1e4e78..f1a30e41b736bda 100644
--- a/llvm/include/llvm/BinaryFormat/GOFF.h
+++ b/llvm/include/llvm/BinaryFormat/GOFF.h
@@ -10,6 +10,8 @@
// constants for the GOFF file format.
//
// GOFF specifics can be found in MVS Program Management: Advanced Facilities.
+// See
+// https://www.ibm.com/docs/en/zos/3.1.0?topic=facilities-generalized-object-file-format-goff
//
//===----------------------------------------------------------------------===//
@@ -19,13 +21,24 @@
#include "llvm/Support/DataTypes.h"
namespace llvm {
+
namespace GOFF {
+/// \brief Length of the parts of a physical GOFF record.
constexpr uint8_t RecordLength = 80;
constexpr uint8_t RecordPrefixLength = 3;
constexpr uint8_t PayloadLength = 77;
+constexpr uint8_t RecordContentLength = RecordLength - RecordPrefixLength;
+
+/// \brief Maximum data length before starting a new card for RLD and TXT data.
+///
+/// The maximum number of bytes that can be included in an RLD or TXT record and
+/// their continuations is a SIGNED 16 bit int despite what the spec says. The
+/// number of bytes we allow ourselves to attach to a card is thus arbitrarily
+/// limited to 32K-1 bytes.
+constexpr uint16_t MaxDataLength = 32 * 1024 - 1;
-// Prefix byte on every record. This indicates GOFF format.
+/// \brief Prefix byte on every record. This indicates GOFF format.
constexpr uint8_t PTVPrefix = 0x03;
enum RecordType : uint8_t {
diff --git a/llvm/include/llvm/MC/MCGOFFObjectWriter.h b/llvm/include/llvm/MC/MCGOFFObjectWriter.h
new file mode 100644
index 000000000000000..85316a6fd5d0e17
--- /dev/null
+++ b/llvm/include/llvm/MC/MCGOFFObjectWriter.h
@@ -0,0 +1,42 @@
+//===- MCGOFFObjectWriter.h - GOFF Object Writer ----------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCGOFFOBJECTWRITER_H
+#define LLVM_MC_MCGOFFOBJECTWRITER_H
+
+#include "llvm/MC/MCObjectWriter.h"
+
+namespace llvm {
+class MCObjectWriter;
+class raw_pwrite_stream;
+
+class MCGOFFObjectTargetWriter : public MCObjectTargetWriter {
+protected:
+ MCGOFFObjectTargetWriter() = default;
+
+public:
+ virtual ~MCGOFFObjectTargetWriter() = default;
+
+ Triple::ObjectFormatType getFormat() const override { return Triple::GOFF; }
+
+ static bool classof(const MCObjectTargetWriter *W) {
+ return W->getFormat() == Triple::GOFF;
+ }
+};
+
+/// \brief Construct a new GOFF writer instance.
+///
+/// \param MOTW - The target-specific GOFF writer subclass.
+/// \param OS - The stream to write to.
+/// \returns The constructed object writer.
+std::unique_ptr<MCObjectWriter>
+createGOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS);
+} // namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/MC/MCGOFFStreamer.h b/llvm/include/llvm/MC/MCGOFFStreamer.h
new file mode 100644
index 000000000000000..2345509b161da5b
--- /dev/null
+++ b/llvm/include/llvm/MC/MCGOFFStreamer.h
@@ -0,0 +1,40 @@
+//===- MCGOFFStreamer.h - MCStreamer GOFF Object File Interface--*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCGOFFSTREAMER_H
+#define LLVM_MC_MCGOFFSTREAMER_H
+
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCObjectWriter.h"
+
+namespace llvm {
+
+class MCGOFFStreamer : public MCObjectStreamer {
+public:
+ MCGOFFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
+ std::unique_ptr<MCObjectWriter> OW,
+ std::unique_ptr<MCCodeEmitter> Emitter)
+ : MCObjectStreamer(Context, std::move(MAB), std::move(OW),
+ std::move(Emitter)) {}
+
+ ~MCGOFFStreamer() override;
+
+ bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
+ return false;
+ }
+ void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ Align ByteAlignment) override {}
+ void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override {}
+ void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
+ uint64_t Size = 0, Align ByteAlignment = Align(1),
+ SMLoc Loc = SMLoc()) override {}
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/MC/TargetRegistry.h b/llvm/include/llvm/MC/TargetRegistry.h
index bf23313c0f90087..47051447404d00f 100644
--- a/llvm/include/llvm/MC/TargetRegistry.h
+++ b/llvm/include/llvm/MC/TargetRegistry.h
@@ -94,6 +94,11 @@ MCStreamer *createELFStreamer(MCContext &Ctx,
std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&CE,
bool RelaxAll);
+MCStreamer *createGOFFStreamer(MCContext &Ctx,
+ std::unique_ptr<MCAsmBackend> &&TAB,
+ std::unique_ptr<MCObjectWriter> &&OW,
+ std::unique_ptr<MCCodeEmitter> &&CE,
+ bool RelaxAll);
MCStreamer *createMachOStreamer(MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&TAB,
std::unique_ptr<MCObjectWriter> &&OW,
@@ -195,6 +200,10 @@ class Target {
std::unique_ptr<MCAsmBackend> &&TAB,
std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
+ using GOFFStreamerCtorTy =
+ MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB,
+ std::unique_ptr<MCObjectWriter> &&OW,
+ std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
using MachOStreamerCtorTy =
MCStreamer *(*)(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB,
std::unique_ptr<MCObjectWriter> &&OW,
@@ -327,6 +336,7 @@ class Target {
// Construction functions for the various object formats, if registered.
COFFStreamerCtorTy COFFStreamerCtorFn = nullptr;
+ GOFFStreamerCtorTy GOFFStreamerCtorFn = nullptr;
MachOStreamerCtorTy MachOStreamerCtorFn = nullptr;
ELFStreamerCtorTy ELFStreamerCtorFn = nullptr;
WasmStreamerCtorTy WasmStreamerCtorFn = nullptr;
@@ -597,7 +607,13 @@ class Target {
std::move(Emitter), RelaxAll);
break;
case Triple::GOFF:
- report_fatal_error("GOFF MCObjectStreamer not implemented yet");
+ if (GOFFStreamerCtorFn)
+ S = GOFFStreamerCtorFn(Ctx, std::move(TAB), std::move(OW),
+ std::move(Emitter), RelaxAll);
+ else
+ S = createGOFFStreamer(Ctx, std::move(TAB), std::move(OW),
+ std::move(Emitter), RelaxAll);
+ break;
case Triple::XCOFF:
if (XCOFFStreamerCtorFn)
S = XCOFFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW),
@@ -1004,6 +1020,10 @@ struct TargetRegistry {
T.COFFStreamerCtorFn = Fn;
}
+ static void RegisterGOFFStreamer(Target &T, Target::GOFFStreamerCtorTy Fn) {
+ T.GOFFStreamerCtorFn = Fn;
+ }
+
static void RegisterMachOStreamer(Target &T, Target::MachOStreamerCtorTy Fn) {
T.MachOStreamerCtorFn = Fn;
}
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index 8a9515307947389..a089d2bff94f42c 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -2,6 +2,7 @@ add_llvm_component_library(LLVMMC
ConstantPools.cpp
DXContainerPSVInfo.cpp
ELFObjectWriter.cpp
+ GOFFObjectWriter.cpp
MCAsmBackend.cpp
MCAsmInfo.cpp
MCAsmInfoCOFF.cpp
@@ -23,6 +24,7 @@ add_llvm_component_library(LLVMMC
MCELFStreamer.cpp
MCExpr.cpp
MCFragment.cpp
+ MCGOFFStreamer.cpp
MCInst.cpp
MCInstPrinter.cpp
MCInstrAnalysis.cpp
diff --git a/llvm/lib/MC/GOFFObjectWriter.cpp b/llvm/lib/MC/GOFFObjectWriter.cpp
new file mode 100644
index 000000000000000..33244cbf88d919e
--- /dev/null
+++ b/llvm/lib/MC/GOFFObjectWriter.cpp
@@ -0,0 +1,296 @@
+//===- lib/MC/GOFFObjectWriter.cpp - GOFF File Writer ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements GOFF object file writer information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCGOFFObjectWriter.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "goff-writer"
+
+namespace {
+
+// The standard System/390 convention is to name the high-order (leftmost) bit
+// in a byte as bit zero. The Flags type helps to set bits in a byte according
+// to this numeration order.
+class Flags {
+ uint8_t Val;
+
+ constexpr static uint8_t bits(uint8_t BitIndex, uint8_t Length, uint8_t Value,
+ uint8_t OldValue) {
+ assert(BitIndex < 8 && "Bit index out of bounds!");
+ assert(Length + BitIndex <= 8 && "Bit length too long!");
+
+ uint8_t Mask = ((1 << Length) - 1) << (8 - BitIndex - Length);
+ Value = Value << (8 - BitIndex - Length);
+ assert((Value & Mask) == Value && "Bits set outside of range!");
+
+ return (OldValue & ~Mask) | Value;
+ }
+
+public:
+ constexpr Flags() : Val(0) {}
+ constexpr Flags(uint8_t BitIndex, uint8_t Length, uint8_t Value)
+ : Val(bits(BitIndex, Length, Value, 0)) {}
+
+ void set(uint8_t BitIndex, uint8_t Length, uint8_t Value) {
+ Val = bits(BitIndex, Length, Value, Val);
+ }
+
+ constexpr operator uint8_t() const { return Val; }
+};
+
+// Common flag values on records.
+
+// Flag: This record is continued.
+constexpr uint8_t RecContinued = Flags(7, 1, 1);
+
+// Flag: This record is a continuation.
+constexpr uint8_t RecContinuation = Flags(6, 1, 1);
+
+// The GOFFOstream is responsible to write the data into the fixed physical
+// records of the format. A user of this class announces the start of a new
+// logical record and the size of its content. While writing the content, the
+// physical records are created for the data. Possible fill bytes at the end of
+// a physical record are written automatically. In principle, the GOFFOstream
+// is agnostic of the endianness of the content. However, it also supports
+// writing data in big endian byte order.
+class GOFFOstream : public raw_ostream {
+ /// The underlying raw_pwrite_stream.
+ raw_pwrite_stream &OS;
+
+ /// The remaining size of this logical record, including fill bytes.
+ size_t RemainingSize;
+
+#ifndef NDEBUG
+ /// The number of bytes needed to fill up the last physical record.
+ size_t Gap = 0;
+#endif
+
+ /// The number of logical records emitted to far.
+ uint32_t LogicalRecords;
+
+ /// The type of the current (logical) record.
+ GOFF::RecordType CurrentType;
+
+ /// Signals start of new record.
+ bool NewLogicalRecord;
+
+ /// Static allocated buffer for the stream, used by the raw_ostream class. The
+ /// buffer is sized to hold the content of a physical record.
+ char Buffer[GOFF::RecordContentLength];
+
+ // Return the number of bytes left to write until next physical record.
+ // Please note that we maintain the total numbers of byte left, not the
+ // written size.
+ size_t bytesToNextPhysicalRecord() {
+ size_t Bytes = RemainingSize % GOFF::RecordContentLength;
+ return Bytes ? Bytes : GOFF::RecordContentLength;
+ }
+
+ /// Write the record prefix of a physical record, using the given record type.
+ static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
+ size_t RemainingSize,
+ uint8_t Flags = RecContinuation);
+
+ /// Fill the last physical record of a logical record with zero bytes.
+ void fillRecord();
+
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ /// Return the current position within the stream, not counting the bytes
+ /// currently in the buffer.
+ uint64_t current_pos() const override { return OS.tell(); }
+
+public:
+ explicit GOFFOstream(raw_pwrite_stream &OS)
+ : OS(OS), RemainingSize(0), LogicalRecords(0), NewLogicalRecord(false) {
+ SetBuffer(Buffer, sizeof(Buffer));
+ }
+
+ ~GOFFOstream() { finalize(); }
+
+ raw_pwrite_stream &getOS() { return OS; }
+
+ void newRecord(GOFF::RecordType Type, size_t Size);
+
+ void finalize() { fillRecord(); }
+
+ uint32_t logicalRecords() { return LogicalRecords; }
+
+ // Support for endian-specific data.
+ template <typename value_type> void writebe(value_type Value) {
+ Value = support::endian::byte_swap<value_type>(Value, support::big);
+ write(reinterpret_cast<const char *>(&Value), sizeof(value_type));
+ }
+};
+
+void GOFFOstream::writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
+ size_t RemainingSize, uint8_t Flags) {
+ uint8_t TypeAndFlags = Flags | (Type << 4);
+ if (RemainingSize > GOFF::RecordLength)
+ TypeAndFlags |= RecContinued;
+ OS << static_cast<unsigned char>(GOFF::PTVPrefix) // Record Type
+ << static_cast<unsigned char>(TypeAndFlags) // Continuation
+ << static_cast<unsigned char>(0); // Version
+}
+
+void GOFFOstream::newRecord(GOFF::RecordType Type, size_t Size) {
+ fillRecord();
+ CurrentType = Type;
+ RemainingSize = Size;
+#ifdef NDEBUG
+ size_t Gap;
+#endif
+ Gap = (RemainingSize % GOFF::RecordContentLength);
+ if (Gap) {
+ Gap = GOFF::RecordContentLength - Gap;
+ RemainingSize += Gap;
+ }
+ NewLogicalRecord = true;
+ ++LogicalRecords;
+}
+
+void GOFFOstream::fillRecord() {
+ assert((GetNumBytesInBuffer() <= RemainingSize) &&
+ "More bytes in buffer than expected");
+ size_t Remains = RemainingSize - GetNumBytesInBuffer();
+ if (Remains) {
+ assert(Remains == Gap && "Wrong size of fill gap");
+ assert((Remains < GOFF::RecordLength) &&
+ "Attempt to fill more than one physical record");
+ raw_ostream::write_zeros(Remains);
+ }
+ flush();
+ assert(RemainingSize == 0 && "Not fully flushed");
+ assert(GetNumBytesInBuffer() == 0 && "Buffer not fully empty");
+}
+
+// This function is called from the raw_ostream implementation if:
+// - The internal buffer is full. Size is excactly the size of the buffer.
+// - Data larger than the internal buffer is written. Size is a multiple of the
+// buffer size.
+// - flush() has been called. Size is at most the buffer size.
+// The GOFFOstream implementation ensures that flush() is called before a new
+// logical record begins. Therefore it is sufficient to check for a new block
+// only once.
+void GOFFOstream::write_impl(const char *Ptr, size_t Size) {
+ assert((RemainingSize >= Size) && "Attempt to write too much data");
+ assert(RemainingSize && "Logical record overflow");
+ if (!(RemainingSize % GOFF::RecordContentLength)) {
+ writeRecordPrefix(OS, CurrentType, RemainingSize,
+ NewLogicalRecord ? 0 : RecContinuation);
+ NewLogicalRecord = false;
+ }
+ assert(!NewLogicalRecord &&
+ "New logical record not on physical record boundary");
+
+ size_t Idx = 0;
+ while (Size > 0) {
+ size_t BytesToWrite = bytesToNextPhysicalRecord();
+ if (BytesToWrite > Size)
+ BytesToWrite = Size;
+ OS.write(Ptr + Idx, BytesToWrite);
+ Idx += BytesToWrite;
+ Size -= BytesToWrite;
+ RemainingSize -= BytesToWrite;
+ if (Size)
+ writeRecordPrefix(OS, CurrentType, RemainingSize);
+ }
+}
+
+class GOFFObjectWriter : public MCObjectWriter {
+ // The target specific GOFF writer instance.
+ std::unique_ptr<MCGOFFObjectTargetWriter> TargetObjectWriter;
+
+ // The stream used to write the GOFF records.
+ GOFFOstream OS;
+
+public:
+ GOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS)
+ : TargetObjectWriter(std::move(MOTW)), OS(OS) {}
+
+ ~GOFFObjectWriter() override {}
+
+ // Write GOFF records.
+ void writeHeader();
+ void writeEnd();
+
+ // Implementation of the MCObjectWriter interface.
+ void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFragment *Fragment, const MCFixup &Fixup,
+ MCValue Target, uint64_t &FixedValue) override {}
+ void executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) override {}
+ uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
+};
+} // end anonymous namespace
+
+void GOFFObjectWriter::writeHeader() {
+ OS.newRecord(GOFF::RT_HDR, /*Size=*/57);
+ OS.write_zeros(1); // Reserved
+ OS.writebe<uint32_t>(0); // Target Hardware Environment
+ OS.writebe<uint32_t>(0); // Target Operating System Environment
+ OS.write_zeros(2); // Reserved
+ OS.writebe<uint16_t>(0); // CCSID
+ OS.write_zeros(16); // Character Set name
+ OS.write_zeros(16); // Language Product Identifier
+ OS.writebe<uint32_t>(1); // Architecture Level
+ OS.writebe<uint16_t>(0); // Module Properties Length
+ OS.write_zeros(6); // Reserved
+}
+
+void GOFFObjectWriter::writeEnd() {
+ uint8_t F = GOFF::END_EPR_None;
+ uint8_t AMODE = 0;
+ uint32_t ESDID = 0;
+
+ // TODO Set Flags/AMODE/ESDID for entry point.
+
+ OS.newRecord(GOFF::RT_END, /*Size=*/13);
+ OS.writebe<uint8_t>(Flags(6, 2, F)); // Indicator flags
+ OS.writebe<uint8_t>(AMODE); // AMODE
+ OS.write_zeros(3); // Reserved
+ // The record count is the number of logical records. In principle, this value
+ // is available as OS.logicalRecords(). However, some tools rely on this field
+ // being zero.
+ OS.writebe<uint32_t>(0); // Record Count
+ OS.writebe<uint32_t>(ESDID); // ESDID (of entry point)
+ OS.finalize();
+}
+
+uint64_t GOFFObjectWriter::writeObject(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ uint64_t StartOffset = OS.tell();
+
+ writeHeader();
+ writeEnd();
+
+ LLVM_DEBUG(dbgs() << "Wrote " << OS.logicalRecords() << " logical records.");
+
+ return OS.tell() - StartOffset;
+}
+
+std::unique_ptr<MCObjectWriter>
+llvm::createGOFFObjectWriter(std::unique_ptr<MCGOFFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS) {
+ return std::make_unique<GOFFObjectWriter>(std::move(MOTW), OS);
+}
diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp
index c2e89f4dfa5dba7..4ad0e7a809307e2 100644
--- a/llvm/lib/MC/MCAsmBackend.cpp
+++ b/llvm/lib/MC/MCAsmBackend.cpp
@@ -10,6 +10,7 @@
#include "llvm/MC/MCDXContainerWriter.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCGOFFObjectWriter.h"
#include "llvm/MC/MCMachObjectWriter.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSPIRVObjectWriter.h"
@@ -46,6 +47,9 @@ MCAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {
case Triple::Wasm:
return createWasmObjectWriter(cast<MCWasmObjectTargetWriter>(std::move(TW)),
OS);
+ case Triple::GOFF:
+ return createGOFFObjectWriter(cast<MCGOFFObjectTargetWriter>(std::move(TW)),
+ OS);
case Triple::XCOFF:
return createXCOFFObjectWriter(
cast<MCXCOFFObjectTargetWriter>(std::move(TW)), OS);
diff --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp
new file mode 100644
index 000000000000000..58d13c9f3788534
--- /dev/null
+++ b/llvm/lib/MC/MCGOFFStreamer.cpp
@@ -0,0 +1,34 @@
+//===- lib/MC/MCGOFFStreamer.cpp - GOFF Object 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file assembles .s files and emits GOFF .o object files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCGOFFStreamer.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/TargetRegistry.h"
+
+using namespace llvm;
+
+MCGOFFStreamer::~MCGOFFStreamer() {}
+
+MCStreamer *llvm::createGOFFStreamer(MCContext &Context,
+ std::unique_ptr<MCAsmBackend> &&MAB,
+ std::unique_ptr<MCObjectWriter> &&OW,
+ std::unique_ptr<MCCodeEmitter> &&CE,
+ bool RelaxAll) {
+ MCGOFFStreamer *S =
+ new MCGOFFStreamer(Context, std::move(MAB), std::move(OW), std::move(CE));
+ if (RelaxAll)
+ S->getAssembler().setRelaxAll(true);
+ return S;
+}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
index 91aac7dd6603cbb..6700d7936970872 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt
@@ -1,10 +1,11 @@
add_llvm_component_library(LLVMSystemZDesc
+ SystemZELFObjectWriter.cpp
+ SystemZGOFFObjectWriter.cpp
SystemZInstPrinter.cpp
SystemZMCAsmBackend.cpp
SystemZMCAsmInfo.cpp
SystemZMCCodeEmitter.cpp
SystemZMCExpr.cpp
- SystemZMCObjectWriter.cpp
SystemZMCTargetDesc.cpp
LINK_COMPONENTS
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
similarity index 88%
rename from llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
rename to llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
index 9c6a1b6e8af01ca..138ce93ac66531c 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZELFObjectWriter.cpp
@@ -1,4 +1,4 @@
-//===-- SystemZMCObjectWriter.cpp - SystemZ ELF writer --------------------===//
+//===-- SystemZELFObjectWriter.cpp - SystemZ ELF writer -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -23,10 +23,10 @@ using namespace llvm;
namespace {
-class SystemZObjectWriter : public MCELFObjectTargetWriter {
+class SystemZELFObjectWriter : public MCELFObjectTargetWriter {
public:
- SystemZObjectWriter(uint8_t OSABI);
- ~SystemZObjectWriter() override = default;
+ SystemZELFObjectWriter(uint8_t OSABI);
+ ~SystemZELFObjectWriter() override = default;
protected:
// Override MCELFObjectTargetWriter.
@@ -36,9 +36,9 @@ class SystemZObjectWriter : public MCELFObjectTargetWriter {
} // end anonymous namespace
-SystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI)
- : MCELFObjectTargetWriter(/*Is64Bit_=*/true, OSABI, ELF::EM_S390,
- /*HasRelocationAddend_=*/ true) {}
+SystemZELFObjectWriter::SystemZELFObjectWriter(uint8_t OSABI)
+ : MCELFObjectTargetWriter(/*Is64Bit_=*/true, OSABI, ELF::EM_S390,
+ /*HasRelocationAddend_=*/true) {}
// Return the relocation type for an absolute value of MCFixupKind Kind.
static unsigned getAbsoluteReloc(MCContext &Ctx, SMLoc Loc, unsigned Kind) {
@@ -146,10 +146,10 @@ static unsigned getPLTReloc(MCContext &Ctx, SMLoc Loc, unsigned Kind) {
return 0;
}
-unsigned SystemZObjectWriter::getRelocType(MCContext &Ctx,
- const MCValue &Target,
- const MCFixup &Fixup,
- bool IsPCRel) const {
+unsigned SystemZELFObjectWriter::getRelocType(MCContext &Ctx,
+ const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsPCRel) const {
SMLoc Loc = Fixup.getLoc();
unsigned Kind = Fixup.getKind();
if (Kind >= FirstLiteralRelocationKind)
@@ -199,6 +199,6 @@ unsigned SystemZObjectWriter::getRelocType(MCContext &Ctx,
}
std::unique_ptr<MCObjectTargetWriter>
-llvm::createSystemZObjectWriter(uint8_t OSABI) {
- return std::make_unique<SystemZObjectWriter>(OSABI);
+llvm::createSystemZELFObjectWriter(uint8_t OSABI) {
+ return std::make_unique<SystemZELFObjectWriter>(OSABI);
}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp
new file mode 100644
index 000000000000000..e9989c3b450c7e2
--- /dev/null
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZGOFFObjectWriter.cpp
@@ -0,0 +1,26 @@
+//===- SystemZGOFFObjectWriter.cpp - SystemZ GOFF writer ------------------===//
+//
+// 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 "MCTargetDesc/SystemZMCTargetDesc.h"
+#include "llvm/MC/MCGOFFObjectWriter.h"
+
+using namespace llvm;
+
+namespace {
+class SystemZGOFFObjectWriter : public MCGOFFObjectTargetWriter {
+public:
+ SystemZGOFFObjectWriter();
+};
+} // end anonymous namespace
+
+SystemZGOFFObjectWriter::SystemZGOFFObjectWriter()
+ : MCGOFFObjectTargetWriter() {}
+
+std::unique_ptr<MCObjectTargetWriter> llvm::createSystemZGOFFObjectWriter() {
+ return std::make_unique<SystemZGOFFObjectWriter>();
+}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
index 880766a1a23fb0d..20dcf74cb8d92ba 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
@@ -106,10 +106,9 @@ static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value,
namespace {
class SystemZMCAsmBackend : public MCAsmBackend {
- uint8_t OSABI;
public:
- SystemZMCAsmBackend(uint8_t osABI)
- : MCAsmBackend(support::big), OSABI(osABI) {}
+ SystemZMCAsmBackend()
+ : MCAsmBackend(support::big) {}
// Override MCAsmBackend
unsigned getNumFixupKinds() const override {
@@ -130,10 +129,6 @@ class SystemZMCAsmBackend : public MCAsmBackend {
}
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
- std::unique_ptr<MCObjectTargetWriter>
- createObjectTargetWriter() const override {
- return createSystemZObjectWriter(OSABI);
- }
};
} // end anonymous namespace
@@ -208,11 +203,39 @@ bool SystemZMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
return true;
}
+namespace {
+class ELFSystemZAsmBackend : public SystemZMCAsmBackend {
+ uint8_t OSABI;
+
+public:
+ ELFSystemZAsmBackend(uint8_t OsABI) : SystemZMCAsmBackend(), OSABI(OsABI){};
+
+ std::unique_ptr<MCObjectTargetWriter>
+ createObjectTargetWriter() const override {
+ return createSystemZELFObjectWriter(OSABI);
+ }
+};
+
+class GOFFSystemZAsmBackend : public SystemZMCAsmBackend {
+public:
+ GOFFSystemZAsmBackend() : SystemZMCAsmBackend(){};
+
+ std::unique_ptr<MCObjectTargetWriter>
+ createObjectTargetWriter() const override {
+ return createSystemZGOFFObjectWriter();
+ }
+};
+} // namespace
+
MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T,
const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
const MCTargetOptions &Options) {
+ if (STI.getTargetTriple().isOSzOS()) {
+ return new GOFFSystemZAsmBackend();
+ }
+
uint8_t OSABI =
MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS());
- return new SystemZMCAsmBackend(OSABI);
+ return new ELFSystemZAsmBackend(OSABI);
}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h
index f2bfc9ac48e5dc3..39c1836a137005c 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h
@@ -85,7 +85,9 @@ MCAsmBackend *createSystemZMCAsmBackend(const Target &T,
const MCRegisterInfo &MRI,
const MCTargetOptions &Options);
-std::unique_ptr<MCObjectTargetWriter> createSystemZObjectWriter(uint8_t OSABI);
+std::unique_ptr<MCObjectTargetWriter>
+createSystemZELFObjectWriter(uint8_t OSABI);
+std::unique_ptr<MCObjectTargetWriter> createSystemZGOFFObjectWriter();
} // end namespace llvm
// Defines symbolic names for SystemZ registers.
diff --git a/llvm/test/MC/GOFF/empty-goff.s b/llvm/test/MC/GOFF/empty-goff.s
new file mode 100644
index 000000000000000..29bc6de71eacc1c
--- /dev/null
+++ b/llvm/test/MC/GOFF/empty-goff.s
@@ -0,0 +1,23 @@
+* RUN: llvm-mc <%s --triple s390x-ibm-zos --filetype=obj -o - | \
+* RUN: od -Ax -tx1 -v | FileCheck --ignore-case %s
+
+* Header record:
+* 03 is prefix byte
+* f. is header type
+* .0 is version
+* The 1 at offset 51 is the architecture level.
+* CHECK: 000000 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000030 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+* End record:
+* 03 is prefix byte
+* 4. is header type
+* .0 is version
+* CHECK: 000050 03 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+* CHECK: 000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
More information about the llvm-commits
mailing list