[llvm] [SystemZ][z/OS] yaml2obj for header and end records (PR #73859)

Yusra Syeda via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 12 11:34:55 PST 2023


https://github.com/ysyeda updated https://github.com/llvm/llvm-project/pull/73859

>From 4c8cb6d379054e07d481bcbc5fb9c448c4f6fe0f Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Wed, 29 Nov 2023 16:30:21 -0500
Subject: [PATCH 1/4] yaml2obj for header and end records

---
 llvm/include/llvm/ObjectYAML/GOFFYAML.h       |  49 +++
 llvm/include/llvm/ObjectYAML/ObjectYAML.h     |   2 +
 llvm/include/llvm/ObjectYAML/yaml2obj.h       |   5 +
 llvm/lib/ObjectYAML/CMakeLists.txt            |   2 +
 llvm/lib/ObjectYAML/GOFFEmitter.cpp           | 292 ++++++++++++++++++
 llvm/lib/ObjectYAML/GOFFYAML.cpp              |  46 +++
 llvm/lib/ObjectYAML/ObjectYAML.cpp            |   5 +
 llvm/lib/ObjectYAML/yaml2obj.cpp              |   2 +
 .../test/ObjectYAML/GOFF/GOFF-Header-End.yaml |  18 ++
 9 files changed, 421 insertions(+)
 create mode 100644 llvm/include/llvm/ObjectYAML/GOFFYAML.h
 create mode 100644 llvm/lib/ObjectYAML/GOFFEmitter.cpp
 create mode 100644 llvm/lib/ObjectYAML/GOFFYAML.cpp
 create mode 100644 llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml

diff --git a/llvm/include/llvm/ObjectYAML/GOFFYAML.h b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
new file mode 100644
index 00000000000000..8053dd1e640c28
--- /dev/null
+++ b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
@@ -0,0 +1,49 @@
+//===- GOFFYAML.h - GOFF YAMLIO implementation ------------------*- 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 classes for handling the YAML representation of GOFF.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_GOFFYAML_H
+#define LLVM_OBJECTYAML_GOFFYAML_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/ObjectYAML/YAML.h"
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+
+// The structure of the yaml files is not an exact 1:1 match to GOFF. In order
+// to use yaml::IO, we use these structures which are closer to the source.
+namespace GOFFYAML {
+
+struct FileHeader {
+  uint32_t TargetEnvironment;
+  uint32_t TargetOperatingSystem;
+  uint16_t CCSID;
+  StringRef CharacterSetName;
+  StringRef LanguageProductIdentifier;
+  uint32_t ArchitectureLevel;
+  std::optional<uint16_t> InternalCCSID;
+  std::optional<uint8_t> TargetSoftwareEnvironment;
+};
+
+struct Object {
+  FileHeader Header;
+  Object();
+};
+} // end namespace GOFFYAML
+} // end namespace llvm
+
+LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::FileHeader)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(GOFFYAML::Object)
+
+#endif // LLVM_OBJECTYAML_GOFFYAML_H
diff --git a/llvm/include/llvm/ObjectYAML/ObjectYAML.h b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
index b63607e6796b0b..7fd15cf290f4a4 100644
--- a/llvm/include/llvm/ObjectYAML/ObjectYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ObjectYAML.h
@@ -13,6 +13,7 @@
 #include "llvm/ObjectYAML/COFFYAML.h"
 #include "llvm/ObjectYAML/DXContainerYAML.h"
 #include "llvm/ObjectYAML/ELFYAML.h"
+#include "llvm/ObjectYAML/GOFFYAML.h"
 #include "llvm/ObjectYAML/MachOYAML.h"
 #include "llvm/ObjectYAML/MinidumpYAML.h"
 #include "llvm/ObjectYAML/OffloadYAML.h"
@@ -30,6 +31,7 @@ struct YamlObjectFile {
   std::unique_ptr<ArchYAML::Archive> Arch;
   std::unique_ptr<ELFYAML::Object> Elf;
   std::unique_ptr<COFFYAML::Object> Coff;
+  std::unique_ptr<GOFFYAML::Object> Goff;
   std::unique_ptr<MachOYAML::Object> MachO;
   std::unique_ptr<MachOYAML::UniversalBinary> FatMachO;
   std::unique_ptr<MinidumpYAML::Object> Minidump;
diff --git a/llvm/include/llvm/ObjectYAML/yaml2obj.h b/llvm/include/llvm/ObjectYAML/yaml2obj.h
index 000da077bb18c6..3b458c3cd890b1 100644
--- a/llvm/include/llvm/ObjectYAML/yaml2obj.h
+++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h
@@ -32,6 +32,10 @@ namespace ELFYAML {
 struct Object;
 }
 
+namespace GOFFYAML {
+struct Object;
+}
+
 namespace MinidumpYAML {
 struct Object;
 }
@@ -64,6 +68,7 @@ using ErrorHandler = llvm::function_ref<void(const Twine &Msg)>;
 
 bool yaml2archive(ArchYAML::Archive &Doc, raw_ostream &Out, ErrorHandler EH);
 bool yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH);
+bool yaml2goff(GOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH);
 bool yaml2elf(ELFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH,
               uint64_t MaxSize);
 bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH);
diff --git a/llvm/lib/ObjectYAML/CMakeLists.txt b/llvm/lib/ObjectYAML/CMakeLists.txt
index c081009653d4f8..b36974d47d9f89 100644
--- a/llvm/lib/ObjectYAML/CMakeLists.txt
+++ b/llvm/lib/ObjectYAML/CMakeLists.txt
@@ -13,6 +13,8 @@ add_llvm_component_library(LLVMObjectYAML
   DXContainerYAML.cpp
   ELFEmitter.cpp
   ELFYAML.cpp
+  GOFFEmitter.cpp
+  GOFFYAML.cpp
   MachOEmitter.cpp
   MachOYAML.cpp
   ObjectYAML.cpp
diff --git a/llvm/lib/ObjectYAML/GOFFEmitter.cpp b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
new file mode 100644
index 00000000000000..bfa44304345e6a
--- /dev/null
+++ b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
@@ -0,0 +1,292 @@
+//===- yaml2goff - Convert YAML to a GOFF object file ---------------------===//
+//
+// 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
+/// The GOFF component of yaml2obj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/IndexedMap.h"
+#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/ConvertEBCDIC.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace {
+
+// Common flag values on records.
+enum {
+  // Flag: This record is continued.
+  Rec_Continued = 1,
+
+  // Flag: This record is a continuation.
+  Rec_Continuation = 1 << (8 - 6 - 1),
+};
+
+template <typename ValueType> struct BinaryBeImpl {
+  ValueType Value;
+  BinaryBeImpl(ValueType V) : Value(V) {}
+};
+
+template <typename ValueType>
+raw_ostream &operator<<(raw_ostream &OS, const BinaryBeImpl<ValueType> &BBE) {
+  char Buffer[sizeof(BBE.Value)];
+  support::endian::write<ValueType, llvm::endianness::big, support::unaligned>(
+      Buffer, BBE.Value);
+  OS.write(Buffer, sizeof(BBE.Value));
+  return OS;
+}
+
+template <typename ValueType> BinaryBeImpl<ValueType> binaryBe(ValueType V) {
+  return BinaryBeImpl<ValueType>(V);
+}
+
+struct ZerosImpl {
+  size_t NumBytes;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const ZerosImpl &Z) {
+  OS.write_zeros(Z.NumBytes);
+  return OS;
+}
+
+ZerosImpl zeros(const size_t NumBytes) { return ZerosImpl{NumBytes}; }
+
+// 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 payload. While writing the payload, the
+// physical records are created for the data. Possible fill bytes at the end of
+// a physical record are written automatically.
+class GOFFOstream : public raw_ostream {
+public:
+  explicit GOFFOstream(raw_ostream &OS)
+      : OS(OS), LogicalRecords(0), RemainingSize(0), NewLogicalRecord(false) {
+    SetBufferSize(GOFF::PayloadLength);
+  }
+
+  ~GOFFOstream() { finalize(); }
+
+  void makeNewRecord(GOFF::RecordType Type, size_t Size);
+
+  void finalize() { fillRecord(); }
+
+  uint32_t logicalRecords() { return LogicalRecords; }
+
+private:
+  /// The underlying raw_ostream.
+  raw_ostream &OS;
+
+  /// The number of logical records emitted so far.
+  uint32_t LogicalRecords;
+
+  /// The remaining size of this logical record, including fill
+  /// bytes.
+  size_t RemainingSize;
+
+  /// The type of the current (logical) record.
+  GOFF::RecordType CurrentType;
+
+  /// Signals start of new record.
+  bool NewLogicalRecord;
+
+  // Return the number of bytes left to write until next physical record.
+  // Please note that we maintain the total number of bytes left, not the
+  // written size.
+  size_t bytesToNextPhysicalRecord() {
+    size_t Bytes = RemainingSize % GOFF::PayloadLength;
+    return Bytes ? Bytes : GOFF::PayloadLength;
+  }
+
+  /// Write the record prefix of a physical record, using the current record
+  /// type.
+  static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
+                                size_t RemainingSize,
+                                uint8_t Flags = Rec_Continuation);
+
+  /// 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(); }
+};
+
+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 |= Rec_Continued;
+  OS << binaryBe(static_cast<unsigned char>(GOFF::PTVPrefix))
+     << binaryBe(static_cast<unsigned char>(TypeAndFlags))
+     << binaryBe(static_cast<unsigned char>(0));
+}
+
+void GOFFOstream::makeNewRecord(GOFF::RecordType Type, size_t Size) {
+  fillRecord();
+  CurrentType = Type;
+  RemainingSize = Size;
+  if (size_t Gap = (RemainingSize % GOFF::PayloadLength))
+    RemainingSize += GOFF::PayloadLength - 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 < GOFF::RecordLength) &&
+           "Attempting 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");
+}
+
+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::PayloadLength)) {
+    writeRecordPrefix(OS, CurrentType, RemainingSize,
+                      NewLogicalRecord ? 0 : Rec_Continuation);
+    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 GOFFState {
+  void writeHeader(GOFFYAML::FileHeader &FileHdr);
+  void writeEnd();
+
+  void reportError(const Twine &Msg) {
+    ErrHandler(Msg);
+    HasError = true;
+  }
+
+  GOFFState(raw_ostream &OS, GOFFYAML::Object &Doc,
+            yaml::ErrorHandler ErrHandler)
+      : GW(OS), Doc(Doc), ErrHandler(ErrHandler), HasError(false) {}
+
+  ~GOFFState() { GW.finalize(); }
+
+  bool writeObject();
+
+public:
+  static bool writeGOFF(raw_ostream &OS, GOFFYAML::Object &Doc,
+                        yaml::ErrorHandler ErrHandler);
+
+private:
+  GOFFOstream GW;
+  GOFFYAML::Object &Doc;
+  yaml::ErrorHandler ErrHandler;
+  bool HasError;
+};
+
+void GOFFState::writeHeader(GOFFYAML::FileHeader &FileHdr) {
+  SmallString<16> CCSIDName;
+  if (std::error_code EC =
+          ConverterEBCDIC::convertToEBCDIC(FileHdr.CharacterSetName, CCSIDName))
+    reportError("Conversion error on " + FileHdr.CharacterSetName);
+  if (CCSIDName.size() > 16) {
+    reportError("CharacterSetName too long");
+    CCSIDName.resize(16);
+  }
+  SmallString<16> LangProd;
+  if (std::error_code EC = ConverterEBCDIC::convertToEBCDIC(
+          FileHdr.LanguageProductIdentifier, LangProd))
+    reportError("Conversion error on " + FileHdr.LanguageProductIdentifier);
+  if (LangProd.size() > 16) {
+    reportError("LanguageProductIdentifier too long");
+    LangProd.resize(16);
+  }
+
+  GW.makeNewRecord(GOFF::RT_HDR, GOFF::PayloadLength);
+  GW << binaryBe(FileHdr.TargetEnvironment)     // TargetEnvironment
+     << binaryBe(FileHdr.TargetOperatingSystem) // TargetOperatingSystem
+     << zeros(2)                                // Reserved
+     << binaryBe(FileHdr.CCSID)                 // CCSID
+     << CCSIDName                               // CharacterSetName
+     << zeros(16 - CCSIDName.size())            // Fill bytes
+     << LangProd                                // LanguageProductIdentifier
+     << zeros(16 - LangProd.size())             // Fill bytes
+     << binaryBe(FileHdr.ArchitectureLevel);    // ArchitectureLevel
+  // The module propties are optional. Figure out if we need to write them.
+  uint16_t ModPropLen = 0;
+  if (FileHdr.TargetSoftwareEnvironment)
+    ModPropLen = 3;
+  else if (FileHdr.InternalCCSID)
+    ModPropLen = 2;
+  if (ModPropLen) {
+    GW << binaryBe(ModPropLen) << zeros(6);
+    if (ModPropLen >= 2)
+      GW << binaryBe(FileHdr.InternalCCSID ? *FileHdr.InternalCCSID : 0);
+    if (ModPropLen >= 3)
+      GW << binaryBe(FileHdr.TargetSoftwareEnvironment
+                         ? *FileHdr.TargetSoftwareEnvironment
+                         : 0);
+  }
+}
+
+void GOFFState::writeEnd() {
+  GW.makeNewRecord(GOFF::RT_END, GOFF::PayloadLength);
+  GW << binaryBe(uint8_t(0)) // No entry point
+     << binaryBe(uint8_t(0)) // No AMODE
+     << zeros(3)             // Reserved
+     << binaryBe(GW.logicalRecords());
+  // No entry point yet. Automatically fill remaining space with zero bytes.
+  GW.finalize();
+}
+
+bool GOFFState::writeObject() {
+  writeHeader(Doc.Header);
+  if (HasError)
+    return false;
+  writeEnd();
+  return true;
+}
+
+bool GOFFState::writeGOFF(raw_ostream &OS, GOFFYAML::Object &Doc,
+                          yaml::ErrorHandler ErrHandler) {
+  GOFFState State(OS, Doc, ErrHandler);
+  return State.writeObject();
+}
+} // namespace
+
+namespace llvm {
+namespace yaml {
+
+bool yaml2goff(llvm::GOFFYAML::Object &Doc, raw_ostream &Out,
+               ErrorHandler ErrHandler) {
+  return GOFFState::writeGOFF(Out, Doc, ErrHandler);
+}
+
+} // namespace yaml
+} // namespace llvm
diff --git a/llvm/lib/ObjectYAML/GOFFYAML.cpp b/llvm/lib/ObjectYAML/GOFFYAML.cpp
new file mode 100644
index 00000000000000..a7d0021e9fd21e
--- /dev/null
+++ b/llvm/lib/ObjectYAML/GOFFYAML.cpp
@@ -0,0 +1,46 @@
+//===-- GOFFYAML.cpp - GOFF YAMLIO implementation ---------------*- 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 defines classes for handling the YAML representation of GOFF.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ObjectYAML/GOFFYAML.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include <string.h>
+
+namespace llvm {
+namespace GOFFYAML {
+
+Object::Object() { memset(&Header, 0, sizeof(Header)); }
+
+} // namespace GOFFYAML
+
+namespace yaml {
+
+void MappingTraits<GOFFYAML::FileHeader>::mapping(
+    IO &IO, GOFFYAML::FileHeader &FileHdr) {
+  IO.mapOptional("TargetEnvironment", FileHdr.TargetEnvironment, 0);
+  IO.mapOptional("TargetOperatingSystem", FileHdr.TargetOperatingSystem, 0);
+  IO.mapOptional("CCSID", FileHdr.CCSID, 0);
+  IO.mapOptional("CharacterSetName", FileHdr.CharacterSetName, "");
+  IO.mapOptional("LanguageProductIdentifier", FileHdr.LanguageProductIdentifier,
+                 "");
+  IO.mapOptional("ArchitectureLevel", FileHdr.ArchitectureLevel, 1);
+  IO.mapOptional("InternalCCSID", FileHdr.InternalCCSID);
+  IO.mapOptional("TargetSoftwareEnvironment",
+                 FileHdr.TargetSoftwareEnvironment);
+}
+
+void MappingTraits<GOFFYAML::Object>::mapping(IO &IO, GOFFYAML::Object &Obj) {
+  IO.mapTag("!GOFF", true);
+  IO.mapRequired("FileHeader", Obj.Header);
+}
+
+} // namespace yaml
+} // namespace llvm
diff --git a/llvm/lib/ObjectYAML/ObjectYAML.cpp b/llvm/lib/ObjectYAML/ObjectYAML.cpp
index d57e5583016b50..1815eaff8e36dd 100644
--- a/llvm/lib/ObjectYAML/ObjectYAML.cpp
+++ b/llvm/lib/ObjectYAML/ObjectYAML.cpp
@@ -26,6 +26,8 @@ void MappingTraits<YamlObjectFile>::mapping(IO &IO,
       MappingTraits<ELFYAML::Object>::mapping(IO, *ObjectFile.Elf);
     if (ObjectFile.Coff)
       MappingTraits<COFFYAML::Object>::mapping(IO, *ObjectFile.Coff);
+    if (ObjectFile.Goff)
+      MappingTraits<GOFFYAML::Object>::mapping(IO, *ObjectFile.Goff);
     if (ObjectFile.MachO)
       MappingTraits<MachOYAML::Object>::mapping(IO, *ObjectFile.MachO);
     if (ObjectFile.FatMachO)
@@ -46,6 +48,9 @@ void MappingTraits<YamlObjectFile>::mapping(IO &IO,
     } else if (IO.mapTag("!COFF")) {
       ObjectFile.Coff.reset(new COFFYAML::Object());
       MappingTraits<COFFYAML::Object>::mapping(IO, *ObjectFile.Coff);
+    } else if (IO.mapTag("!GOFF")) {
+      ObjectFile.Goff.reset(new GOFFYAML::Object());
+      MappingTraits<GOFFYAML::Object>::mapping(IO, *ObjectFile.Goff);
     } else if (IO.mapTag("!mach-o")) {
       ObjectFile.MachO.reset(new MachOYAML::Object());
       MappingTraits<MachOYAML::Object>::mapping(IO, *ObjectFile.MachO);
diff --git a/llvm/lib/ObjectYAML/yaml2obj.cpp b/llvm/lib/ObjectYAML/yaml2obj.cpp
index 06050e246fbff3..b9a9ad63970995 100644
--- a/llvm/lib/ObjectYAML/yaml2obj.cpp
+++ b/llvm/lib/ObjectYAML/yaml2obj.cpp
@@ -38,6 +38,8 @@ bool convertYAML(yaml::Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler,
       return yaml2elf(*Doc.Elf, Out, ErrHandler, MaxSize);
     if (Doc.Coff)
       return yaml2coff(*Doc.Coff, Out, ErrHandler);
+    if (Doc.Goff)
+      return yaml2goff(*Doc.Goff, Out, ErrHandler);
     if (Doc.MachO || Doc.FatMachO)
       return yaml2macho(Doc, Out, ErrHandler);
     if (Doc.Minidump)
diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml b/llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml
new file mode 100644
index 00000000000000..7f7cf21390c0ec
--- /dev/null
+++ b/llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml
@@ -0,0 +1,18 @@
+# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s
+
+# Verify that GOFF Header is correct.
+# CHECK: 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK: 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+# Verify GOFF Module end.
+# CHECK: 03 40 00 00 00 00 00 00 00 00 00 02 00 00 00 00
+# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+--- !GOFF
+FileHeader:
+  ArchitectureLevel: 1

>From 4700e6b41471f8f5244c3835abdca7bb7eb5950b Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Thu, 30 Nov 2023 15:17:00 -0500
Subject: [PATCH 2/4] address some nits

---
 llvm/lib/ObjectYAML/GOFFEmitter.cpp           | 143 ++++++++----------
 .../test/ObjectYAML/GOFF/GOFF-Header-End.yaml |  23 +--
 .../ObjectYAML/GOFF/GOFF-Header-Settings.yaml |  26 ++++
 3 files changed, 104 insertions(+), 88 deletions(-)
 create mode 100644 llvm/test/ObjectYAML/GOFF/GOFF-Header-Settings.yaml

diff --git a/llvm/lib/ObjectYAML/GOFFEmitter.cpp b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
index bfa44304345e6a..5ae9932df498f8 100644
--- a/llvm/lib/ObjectYAML/GOFFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
@@ -74,27 +74,34 @@ class GOFFOstream : public raw_ostream {
 
   ~GOFFOstream() { finalize(); }
 
-  void makeNewRecord(GOFF::RecordType Type, size_t Size);
+  void makeNewRecord(GOFF::RecordType Type, size_t Size) {
+    fillRecord();
+    CurrentType = Type;
+    RemainingSize = Size;
+    if (size_t Gap = (RemainingSize % GOFF::PayloadLength))
+      RemainingSize += GOFF::PayloadLength - Gap;
+    NewLogicalRecord = true;
+    ++LogicalRecords;
+  }
 
   void finalize() { fillRecord(); }
 
   uint32_t logicalRecords() { return LogicalRecords; }
 
 private:
-  /// The underlying raw_ostream.
+  // The underlying raw_ostream.
   raw_ostream &OS;
 
-  /// The number of logical records emitted so far.
+  // The number of logical records emitted so far.
   uint32_t LogicalRecords;
 
-  /// The remaining size of this logical record, including fill
-  /// bytes.
+  // The remaining size of this logical record, including fill bytes.
   size_t RemainingSize;
 
-  /// The type of the current (logical) record.
+  // The type of the current (logical) record.
   GOFF::RecordType CurrentType;
 
-  /// Signals start of new record.
+  // Signals start of new record.
   bool NewLogicalRecord;
 
   // Return the number of bytes left to write until next physical record.
@@ -105,82 +112,64 @@ class GOFFOstream : public raw_ostream {
     return Bytes ? Bytes : GOFF::PayloadLength;
   }
 
-  /// Write the record prefix of a physical record, using the current record
-  /// type.
+  // Write the record prefix of a physical record, using the current record
+  // type.
   static void writeRecordPrefix(raw_ostream &OS, GOFF::RecordType Type,
                                 size_t RemainingSize,
-                                uint8_t Flags = Rec_Continuation);
-
-  /// 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(); }
-};
-
-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 |= Rec_Continued;
-  OS << binaryBe(static_cast<unsigned char>(GOFF::PTVPrefix))
-     << binaryBe(static_cast<unsigned char>(TypeAndFlags))
-     << binaryBe(static_cast<unsigned char>(0));
-}
-
-void GOFFOstream::makeNewRecord(GOFF::RecordType Type, size_t Size) {
-  fillRecord();
-  CurrentType = Type;
-  RemainingSize = Size;
-  if (size_t Gap = (RemainingSize % GOFF::PayloadLength))
-    RemainingSize += GOFF::PayloadLength - 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 < GOFF::RecordLength) &&
-           "Attempting to fill more than one physical record");
-    raw_ostream::write_zeros(Remains);
+                                uint8_t Flags = Rec_Continuation) {
+    uint8_t TypeAndFlags = Flags | (Type << 4);
+    if (RemainingSize > GOFF::RecordLength)
+      TypeAndFlags |= Rec_Continued;
+    OS << binaryBe(static_cast<unsigned char>(GOFF::PTVPrefix))
+       << binaryBe(static_cast<unsigned char>(TypeAndFlags))
+       << binaryBe(static_cast<unsigned char>(0));
   }
-  flush();
-  assert(RemainingSize == 0 && "Not fully flushed");
-  assert(GetNumBytesInBuffer() == 0 && "Buffer not fully empty");
-}
-
-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::PayloadLength)) {
-    writeRecordPrefix(OS, CurrentType, RemainingSize,
-                      NewLogicalRecord ? 0 : Rec_Continuation);
-    NewLogicalRecord = false;
+  // Fill the last physical record of a logical record with zero bytes.
+  void fillRecord() {
+    assert((GetNumBytesInBuffer() <= RemainingSize) &&
+           "More bytes in buffer than expected");
+    size_t Remains = RemainingSize - GetNumBytesInBuffer();
+    if (Remains) {
+      assert((Remains < GOFF::RecordLength) &&
+             "Attempting 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");
   }
-  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);
+
+  // See raw_ostream::write_impl.
+  void write_impl(const char *Ptr, size_t Size) override {
+    assert((RemainingSize >= Size) && "Attempt to write too much data");
+    assert(RemainingSize && "Logical record overflow");
+    if (!(RemainingSize % GOFF::PayloadLength)) {
+      writeRecordPrefix(OS, CurrentType, RemainingSize,
+                        NewLogicalRecord ? 0 : Rec_Continuation);
+      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);
+      }
     }
   }
-}
+
+  // Return the current position within the stream, not counting the bytes
+  // currently in the buffer.
+  uint64_t current_pos() const override { return OS.tell(); }
+};
 
 class GOFFState {
   void writeHeader(GOFFYAML::FileHeader &FileHdr);
diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml b/llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml
index 7f7cf21390c0ec..3b8f57b647012a 100644
--- a/llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml
+++ b/llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml
@@ -1,18 +1,19 @@
 # RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s
 
-# Verify that GOFF Header is correct.
+## Verify that GOFF Header is correct.
 # CHECK: 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-# CHECK: 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
-# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+## Verify GOFF Module end.
+# CHECK-NEXT: 03 40 00 00 00 00 00 00 00 00 00 02 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 
-# Verify GOFF Module end.
-# CHECK: 03 40 00 00 00 00 00 00 00 00 00 02 00 00 00 00
-# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-# CHECK: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 --- !GOFF
 FileHeader:
   ArchitectureLevel: 1
diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-Header-Settings.yaml b/llvm/test/ObjectYAML/GOFF/GOFF-Header-Settings.yaml
new file mode 100644
index 00000000000000..bbf2f4a129137c
--- /dev/null
+++ b/llvm/test/ObjectYAML/GOFF/GOFF-Header-Settings.yaml
@@ -0,0 +1,26 @@
+# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s
+
+## Verify that GOFF Header is correct.
+# CHECK: 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 01 00 03 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+## Verify GOFF Module end.
+# CHECK-NEXT: 03 40 00 00 00 00 00 00 00 00 00 02 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+--- !GOFF
+FileHeader:
+  TargetEnvironment: 0
+  TargetOperatingSystem: 0
+  CCSID: 0
+  CharacterSetName: ""
+  LanguageProductIdentifier: ""
+  ArchitectureLevel: 1
+  InternalCCSID: 0
+  TargetSoftwareEnvironment: 0 

>From cddf23f1d2de22242584b867f3f68c2d40aa02a4 Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Tue, 5 Dec 2023 11:16:08 -0500
Subject: [PATCH 3/4] address comments

---
 llvm/include/llvm/ObjectYAML/GOFFYAML.h              | 12 ++++++------
 llvm/lib/ObjectYAML/GOFFEmitter.cpp                  |  1 +
 llvm/lib/ObjectYAML/GOFFYAML.cpp                     |  2 +-
 .../yaml2obj}/GOFF/GOFF-Header-End.yaml              |  4 ++--
 .../yaml2obj}/GOFF/GOFF-Header-Settings.yaml         |  2 +-
 llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml    |  5 +++++
 6 files changed, 16 insertions(+), 10 deletions(-)
 rename llvm/test/{ObjectYAML => tools/yaml2obj}/GOFF/GOFF-Header-End.yaml (84%)
 rename llvm/test/{ObjectYAML => tools/yaml2obj}/GOFF/GOFF-Header-Settings.yaml (93%)
 create mode 100644 llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml

diff --git a/llvm/include/llvm/ObjectYAML/GOFFYAML.h b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
index 8053dd1e640c28..3fd6093b016751 100644
--- a/llvm/include/llvm/ObjectYAML/GOFFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
@@ -26,12 +26,12 @@ namespace llvm {
 namespace GOFFYAML {
 
 struct FileHeader {
-  uint32_t TargetEnvironment;
-  uint32_t TargetOperatingSystem;
-  uint16_t CCSID;
-  StringRef CharacterSetName;
-  StringRef LanguageProductIdentifier;
-  uint32_t ArchitectureLevel;
+  uint32_t TargetEnvironment = 0;
+  uint32_t TargetOperatingSystem = 0;
+  uint16_t CCSID = 0;
+  StringRef CharacterSetName = "";
+  StringRef LanguageProductIdentifier = "";
+  uint32_t ArchitectureLevel = 0;
   std::optional<uint16_t> InternalCCSID;
   std::optional<uint8_t> TargetSoftwareEnvironment;
 };
diff --git a/llvm/lib/ObjectYAML/GOFFEmitter.cpp b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
index 5ae9932df498f8..345904407e1d24 100644
--- a/llvm/lib/ObjectYAML/GOFFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/GOFFEmitter.cpp
@@ -124,6 +124,7 @@ class GOFFOstream : public raw_ostream {
        << binaryBe(static_cast<unsigned char>(TypeAndFlags))
        << binaryBe(static_cast<unsigned char>(0));
   }
+
   // Fill the last physical record of a logical record with zero bytes.
   void fillRecord() {
     assert((GetNumBytesInBuffer() <= RemainingSize) &&
diff --git a/llvm/lib/ObjectYAML/GOFFYAML.cpp b/llvm/lib/ObjectYAML/GOFFYAML.cpp
index a7d0021e9fd21e..ae857980a521b0 100644
--- a/llvm/lib/ObjectYAML/GOFFYAML.cpp
+++ b/llvm/lib/ObjectYAML/GOFFYAML.cpp
@@ -17,7 +17,7 @@
 namespace llvm {
 namespace GOFFYAML {
 
-Object::Object() { memset(&Header, 0, sizeof(Header)); }
+Object::Object() {}
 
 } // namespace GOFFYAML
 
diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml b/llvm/test/tools/yaml2obj/GOFF/GOFF-Header-End.yaml
similarity index 84%
rename from llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml
rename to llvm/test/tools/yaml2obj/GOFF/GOFF-Header-End.yaml
index 3b8f57b647012a..8a526fe125bd5a 100644
--- a/llvm/test/ObjectYAML/GOFF/GOFF-Header-End.yaml
+++ b/llvm/test/tools/yaml2obj/GOFF/GOFF-Header-End.yaml
@@ -1,7 +1,7 @@
-# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s
+# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case  %s
 
 ## Verify that GOFF Header is correct.
-# CHECK: 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK:      03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 # CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 # CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 # CHECK-NEXT: 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00
diff --git a/llvm/test/ObjectYAML/GOFF/GOFF-Header-Settings.yaml b/llvm/test/tools/yaml2obj/GOFF/GOFF-Header-Settings.yaml
similarity index 93%
rename from llvm/test/ObjectYAML/GOFF/GOFF-Header-Settings.yaml
rename to llvm/test/tools/yaml2obj/GOFF/GOFF-Header-Settings.yaml
index bbf2f4a129137c..1971c407199fbe 100644
--- a/llvm/test/ObjectYAML/GOFF/GOFF-Header-Settings.yaml
+++ b/llvm/test/tools/yaml2obj/GOFF/GOFF-Header-Settings.yaml
@@ -1,7 +1,7 @@
 # RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s
 
 ## Verify that GOFF Header is correct.
-# CHECK: 03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+# CHECK:      03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 # CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 # CHECK-NEXT: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 # CHECK-NEXT: 00 00 01 00 03 00 00 00 00 00 00 00 00 00 00 00
diff --git a/llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml b/llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml
new file mode 100644
index 00000000000000..eea6e87630f26e
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml
@@ -0,0 +1,5 @@
+# RUN: not yaml2obj %s FileCheck --ignore-case %s --check-prefix=ERR
+
+#ERR: yaml2obj: error: unknown document type
+
+--- !GOFF

>From 74dcf8db955849719100a200cd56b42527cbc0e9 Mon Sep 17 00:00:00 2001
From: Yusra Syeda <yusra.syeda at ibm.com>
Date: Tue, 12 Dec 2023 14:33:46 -0500
Subject: [PATCH 4/4] address some nits + fix error test

---
 llvm/include/llvm/ObjectYAML/GOFFYAML.h                     | 4 ++--
 llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml           | 5 -----
 .../GOFF/{GOFF-Header-End.yaml => GOFF-header-end.yaml}     | 2 +-
 ...{GOFF-Header-Settings.yaml => GOFF-header-settings.yaml} | 0
 llvm/test/tools/yaml2obj/GOFF/GOFF-no-header.yaml           | 6 ++++++
 5 files changed, 9 insertions(+), 8 deletions(-)
 delete mode 100644 llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml
 rename llvm/test/tools/yaml2obj/GOFF/{GOFF-Header-End.yaml => GOFF-header-end.yaml} (91%)
 rename llvm/test/tools/yaml2obj/GOFF/{GOFF-Header-Settings.yaml => GOFF-header-settings.yaml} (100%)
 create mode 100644 llvm/test/tools/yaml2obj/GOFF/GOFF-no-header.yaml

diff --git a/llvm/include/llvm/ObjectYAML/GOFFYAML.h b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
index 3fd6093b016751..f9bf45e95bd3a4 100644
--- a/llvm/include/llvm/ObjectYAML/GOFFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/GOFFYAML.h
@@ -29,8 +29,8 @@ struct FileHeader {
   uint32_t TargetEnvironment = 0;
   uint32_t TargetOperatingSystem = 0;
   uint16_t CCSID = 0;
-  StringRef CharacterSetName = "";
-  StringRef LanguageProductIdentifier = "";
+  StringRef CharacterSetName;
+  StringRef LanguageProductIdentifier;
   uint32_t ArchitectureLevel = 0;
   std::optional<uint16_t> InternalCCSID;
   std::optional<uint8_t> TargetSoftwareEnvironment;
diff --git a/llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml b/llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml
deleted file mode 100644
index eea6e87630f26e..00000000000000
--- a/llvm/test/tools/yaml2obj/GOFF/GOFF-No-Header.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-# RUN: not yaml2obj %s FileCheck --ignore-case %s --check-prefix=ERR
-
-#ERR: yaml2obj: error: unknown document type
-
---- !GOFF
diff --git a/llvm/test/tools/yaml2obj/GOFF/GOFF-Header-End.yaml b/llvm/test/tools/yaml2obj/GOFF/GOFF-header-end.yaml
similarity index 91%
rename from llvm/test/tools/yaml2obj/GOFF/GOFF-Header-End.yaml
rename to llvm/test/tools/yaml2obj/GOFF/GOFF-header-end.yaml
index 8a526fe125bd5a..0a836fafc189b8 100644
--- a/llvm/test/tools/yaml2obj/GOFF/GOFF-Header-End.yaml
+++ b/llvm/test/tools/yaml2obj/GOFF/GOFF-header-end.yaml
@@ -1,4 +1,4 @@
-# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case  %s
+# RUN: yaml2obj %s | od -v -An -tx1 | FileCheck --ignore-case %s
 
 ## Verify that GOFF Header is correct.
 # CHECK:      03 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00
diff --git a/llvm/test/tools/yaml2obj/GOFF/GOFF-Header-Settings.yaml b/llvm/test/tools/yaml2obj/GOFF/GOFF-header-settings.yaml
similarity index 100%
rename from llvm/test/tools/yaml2obj/GOFF/GOFF-Header-Settings.yaml
rename to llvm/test/tools/yaml2obj/GOFF/GOFF-header-settings.yaml
diff --git a/llvm/test/tools/yaml2obj/GOFF/GOFF-no-header.yaml b/llvm/test/tools/yaml2obj/GOFF/GOFF-no-header.yaml
new file mode 100644
index 00000000000000..4a5b1b81074c11
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/GOFF/GOFF-no-header.yaml
@@ -0,0 +1,6 @@
+# RUN: not yaml2obj %s FileCheck --ignore-case %s --check-prefix=ERR
+
+## X: [] is an extra field is to workaround document of unknown type error
+# ERR: yaml2obj: error: missing required key 'FileHeader'
+--- !GOFF
+X: []



More information about the llvm-commits mailing list