LLVM 20.0.0git
GOFFEmitter.cpp
Go to the documentation of this file.
1//===- yaml2goff - Convert YAML to a GOFF object file ---------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// The GOFF component of yaml2obj.
11///
12//===----------------------------------------------------------------------===//
13
17#include "llvm/Support/Endian.h"
19
20using namespace llvm;
21
22namespace {
23
24// Common flag values on records.
25enum {
26 // Flag: This record is continued.
27 Rec_Continued = 1,
28
29 // Flag: This record is a continuation.
30 Rec_Continuation = 1 << (8 - 6 - 1),
31};
32
33template <typename ValueType> struct BinaryBeImpl {
35 BinaryBeImpl(ValueType V) : Value(V) {}
36};
37
38template <typename ValueType>
39raw_ostream &operator<<(raw_ostream &OS, const BinaryBeImpl<ValueType> &BBE) {
40 char Buffer[sizeof(BBE.Value)];
41 support::endian::write<ValueType, llvm::endianness::big, support::unaligned>(
42 Buffer, BBE.Value);
43 OS.write(Buffer, sizeof(BBE.Value));
44 return OS;
45}
46
47template <typename ValueType> BinaryBeImpl<ValueType> binaryBe(ValueType V) {
48 return BinaryBeImpl<ValueType>(V);
49}
50
51struct ZerosImpl {
52 size_t NumBytes;
53};
54
55raw_ostream &operator<<(raw_ostream &OS, const ZerosImpl &Z) {
56 OS.write_zeros(Z.NumBytes);
57 return OS;
58}
59
60ZerosImpl zeros(const size_t NumBytes) { return ZerosImpl{NumBytes}; }
61
62// The GOFFOstream is responsible to write the data into the fixed physical
63// records of the format. A user of this class announces the start of a new
64// logical record and the size of its payload. While writing the payload, the
65// physical records are created for the data. Possible fill bytes at the end of
66// a physical record are written automatically.
67class GOFFOstream : public raw_ostream {
68public:
69 explicit GOFFOstream(raw_ostream &OS)
70 : OS(OS), LogicalRecords(0), RemainingSize(0), NewLogicalRecord(false) {
72 }
73
74 ~GOFFOstream() { finalize(); }
75
76 void makeNewRecord(GOFF::RecordType Type, size_t Size) {
77 fillRecord();
78 CurrentType = Type;
79 RemainingSize = Size;
80 if (size_t Gap = (RemainingSize % GOFF::PayloadLength))
81 RemainingSize += GOFF::PayloadLength - Gap;
82 NewLogicalRecord = true;
83 ++LogicalRecords;
84 }
85
86 void finalize() { fillRecord(); }
87
88 uint32_t logicalRecords() { return LogicalRecords; }
89
90private:
91 // The underlying raw_ostream.
93
94 // The number of logical records emitted so far.
95 uint32_t LogicalRecords;
96
97 // The remaining size of this logical record, including fill bytes.
98 size_t RemainingSize;
99
100 // The type of the current (logical) record.
101 GOFF::RecordType CurrentType;
102
103 // Signals start of new record.
104 bool NewLogicalRecord;
105
106 // Return the number of bytes left to write until next physical record.
107 // Please note that we maintain the total number of bytes left, not the
108 // written size.
109 size_t bytesToNextPhysicalRecord() {
110 size_t Bytes = RemainingSize % GOFF::PayloadLength;
111 return Bytes ? Bytes : GOFF::PayloadLength;
112 }
113
114 // Write the record prefix of a physical record, using the current record
115 // type.
116 static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
117 size_t RemainingSize,
118 uint8_t Flags = Rec_Continuation) {
119 uint8_t TypeAndFlags = Flags | (Type << 4);
120 if (RemainingSize > GOFF::RecordLength)
121 TypeAndFlags |= Rec_Continued;
122 OS << binaryBe(static_cast<unsigned char>(GOFF::PTVPrefix))
123 << binaryBe(static_cast<unsigned char>(TypeAndFlags))
124 << binaryBe(static_cast<unsigned char>(0));
125 }
126
127 // Fill the last physical record of a logical record with zero bytes.
128 void fillRecord() {
129 assert((GetNumBytesInBuffer() <= RemainingSize) &&
130 "More bytes in buffer than expected");
131 size_t Remains = RemainingSize - GetNumBytesInBuffer();
132 if (Remains) {
133 assert((Remains < GOFF::RecordLength) &&
134 "Attempting to fill more than one physical record");
136 }
137 flush();
138 assert(RemainingSize == 0 && "Not fully flushed");
139 assert(GetNumBytesInBuffer() == 0 && "Buffer not fully empty");
140 }
141
142 // See raw_ostream::write_impl.
143 void write_impl(const char *Ptr, size_t Size) override {
144 assert((RemainingSize >= Size) && "Attempt to write too much data");
145 assert(RemainingSize && "Logical record overflow");
146 if (!(RemainingSize % GOFF::PayloadLength)) {
147 writeRecordPrefix(OS, CurrentType, RemainingSize,
148 NewLogicalRecord ? 0 : Rec_Continuation);
149 NewLogicalRecord = false;
150 }
151 assert(!NewLogicalRecord &&
152 "New logical record not on physical record boundary");
153
154 size_t Idx = 0;
155 while (Size > 0) {
156 size_t BytesToWrite = bytesToNextPhysicalRecord();
157 if (BytesToWrite > Size)
158 BytesToWrite = Size;
159 OS.write(Ptr + Idx, BytesToWrite);
160 Idx += BytesToWrite;
161 Size -= BytesToWrite;
162 RemainingSize -= BytesToWrite;
163 if (Size) {
164 writeRecordPrefix(OS, CurrentType, RemainingSize);
165 }
166 }
167 }
168
169 // Return the current position within the stream, not counting the bytes
170 // currently in the buffer.
171 uint64_t current_pos() const override { return OS.tell(); }
172};
173
174class GOFFState {
175 void writeHeader(GOFFYAML::FileHeader &FileHdr);
176 void writeEnd();
177
178 void reportError(const Twine &Msg) {
179 ErrHandler(Msg);
180 HasError = true;
181 }
182
183 GOFFState(raw_ostream &OS, GOFFYAML::Object &Doc,
184 yaml::ErrorHandler ErrHandler)
185 : GW(OS), Doc(Doc), ErrHandler(ErrHandler), HasError(false) {}
186
187 ~GOFFState() { GW.finalize(); }
188
189 bool writeObject();
190
191public:
192 static bool writeGOFF(raw_ostream &OS, GOFFYAML::Object &Doc,
193 yaml::ErrorHandler ErrHandler);
194
195private:
196 GOFFOstream GW;
197 GOFFYAML::Object &Doc;
198 yaml::ErrorHandler ErrHandler;
199 bool HasError;
200};
201
202void GOFFState::writeHeader(GOFFYAML::FileHeader &FileHdr) {
203 SmallString<16> CCSIDName;
204 if (std::error_code EC =
206 reportError("Conversion error on " + FileHdr.CharacterSetName);
207 if (CCSIDName.size() > 16) {
208 reportError("CharacterSetName too long");
209 CCSIDName.resize(16);
210 }
211 SmallString<16> LangProd;
212 if (std::error_code EC = ConverterEBCDIC::convertToEBCDIC(
213 FileHdr.LanguageProductIdentifier, LangProd))
214 reportError("Conversion error on " + FileHdr.LanguageProductIdentifier);
215 if (LangProd.size() > 16) {
216 reportError("LanguageProductIdentifier too long");
217 LangProd.resize(16);
218 }
219
220 GW.makeNewRecord(GOFF::RT_HDR, GOFF::PayloadLength);
221 GW << binaryBe(FileHdr.TargetEnvironment) // TargetEnvironment
222 << binaryBe(FileHdr.TargetOperatingSystem) // TargetOperatingSystem
223 << zeros(2) // Reserved
224 << binaryBe(FileHdr.CCSID) // CCSID
225 << CCSIDName // CharacterSetName
226 << zeros(16 - CCSIDName.size()) // Fill bytes
227 << LangProd // LanguageProductIdentifier
228 << zeros(16 - LangProd.size()) // Fill bytes
229 << binaryBe(FileHdr.ArchitectureLevel); // ArchitectureLevel
230 // The module propties are optional. Figure out if we need to write them.
231 uint16_t ModPropLen = 0;
232 if (FileHdr.TargetSoftwareEnvironment)
233 ModPropLen = 3;
234 else if (FileHdr.InternalCCSID)
235 ModPropLen = 2;
236 if (ModPropLen) {
237 GW << binaryBe(ModPropLen) << zeros(6);
238 if (ModPropLen >= 2)
239 GW << binaryBe(FileHdr.InternalCCSID.value_or(0));
240 if (ModPropLen >= 3)
241 GW << binaryBe(FileHdr.TargetSoftwareEnvironment.value_or(0));
242 }
243}
244
245void GOFFState::writeEnd() {
246 GW.makeNewRecord(GOFF::RT_END, GOFF::PayloadLength);
247 GW << binaryBe(uint8_t(0)) // No entry point
248 << binaryBe(uint8_t(0)) // No AMODE
249 << zeros(3) // Reserved
250 << binaryBe(GW.logicalRecords());
251 // No entry point yet. Automatically fill remaining space with zero bytes.
252 GW.finalize();
253}
254
255bool GOFFState::writeObject() {
256 writeHeader(Doc.Header);
257 if (HasError)
258 return false;
259 writeEnd();
260 return true;
261}
262
263bool GOFFState::writeGOFF(raw_ostream &OS, GOFFYAML::Object &Doc,
264 yaml::ErrorHandler ErrHandler) {
265 GOFFState State(OS, Doc, ErrHandler);
266 return State.writeObject();
267}
268} // namespace
269
270namespace llvm {
271namespace yaml {
272
274 ErrorHandler ErrHandler) {
275 return GOFFState::writeGOFF(Out, Doc, ErrHandler);
276}
277
278} // namespace yaml
279} // namespace llvm
arc branch finalize
static Error reportError(StringRef Message)
zeros_impl< sizeof(T)> zeros(const T &)
This file provides utility functions for converting between EBCDIC-1047 and UTF-8.
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
uint64_t Size
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
size_t size() const
Definition: SmallVector.h:78
void resize(size_type N)
Definition: SmallVector.h:638
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM Value Representation.
Definition: Value.h:74
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
raw_ostream & write_zeros(unsigned NumZeros)
write_zeros - Insert 'NumZeros' nulls.
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:147
void SetBufferSize(size_t Size)
Set the stream to be buffered, using the specified buffer size.
Definition: raw_ostream.h:167
raw_ostream & write(unsigned char C)
size_t GetNumBytesInBuffer() const
Definition: raw_ostream.h:190
std::error_code convertToEBCDIC(StringRef Source, SmallVectorImpl< char > &Result)
RecordType
Definition: GOFF.h:44
@ RT_HDR
Definition: GOFF.h:50
@ RT_END
Definition: GOFF.h:49
constexpr uint8_t PayloadLength
Definition: GOFF.h:30
constexpr uint8_t PTVPrefix
Prefix byte on every record. This indicates GOFF format.
Definition: GOFF.h:42
constexpr uint8_t RecordLength
Length of the parts of a physical GOFF record.
Definition: GOFF.h:28
bool yaml2goff(GOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
Definition: APFixedPoint.h:303
std::optional< uint8_t > TargetSoftwareEnvironment
Definition: GOFFYAML.h:36
StringRef LanguageProductIdentifier
Definition: GOFFYAML.h:33
StringRef CharacterSetName
Definition: GOFFYAML.h:32
uint32_t TargetOperatingSystem
Definition: GOFFYAML.h:30
std::optional< uint16_t > InternalCCSID
Definition: GOFFYAML.h:35
Common declarations for yaml2obj.