Implement -frecord-command-line for XCOFF integrated assembler path
authorJake Egan <5326451+jakeegan@users.noreply.github.com>
Thu, 20 Jul 2023 13:44:14 +0000 (09:44 -0400)
committerJake Egan <5326451+jakeegan@users.noreply.github.com>
Thu, 20 Jul 2023 13:45:37 +0000 (09:45 -0400)
The patch D153600 implemented `-frecord-command-line` for the XCOFF direct assembly path. This patch adds support for the XCOFF integrated assembly path.

Reviewed By: scott.linder

Differential Revision: https://reviews.llvm.org/D154921

llvm/include/llvm/MC/MCObjectWriter.h
llvm/include/llvm/MC/MCXCOFFStreamer.h
llvm/lib/MC/MCXCOFFStreamer.cpp
llvm/lib/MC/XCOFFObjectWriter.cpp
llvm/test/CodeGen/PowerPC/aix-command-line-metadata.ll

index 2a43266..8c10452 100644 (file)
@@ -110,6 +110,9 @@ public:
                                  unsigned FunctionSize, bool hasDebug) {
     report_fatal_error("addExceptionEntry is only supported on XCOFF targets");
   }
+  virtual void addCInfoSymEntry(StringRef Name, StringRef Metadata) {
+    report_fatal_error("addCInfoSymEntry is only supported on XCOFF targets");
+  }
   /// Write the object file and returns the number of bytes written.
   ///
   /// This routine is called by the assembler after layout and relaxation is
index a3db636..041bbbf 100644 (file)
@@ -40,10 +40,7 @@ public:
   void emitXCOFFExceptDirective(const MCSymbol *Symbol, const MCSymbol *Trap,
                                 unsigned Lang, unsigned Reason,
                                 unsigned FunctionSize, bool hasDebug) override;
-  void emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) override {
-    report_fatal_error("emitXCOFFCInfoSym is not implemented yet on "
-                       "object generation path");
-  }
+  void emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) override;
 };
 
 } // end namespace llvm
index d996dcf..8585416 100644 (file)
@@ -105,6 +105,10 @@ void MCXCOFFStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol,
                                                FunctionSize, hasDebug);
 }
 
+void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
+  getAssembler().getWriter().addCInfoSymEntry(Name, Metadata);
+}
+
 void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                        Align ByteAlignment) {
   getAssembler().registerSymbol(*Symbol);
index e7fa328..30fa727 100644 (file)
@@ -255,6 +255,42 @@ struct ExceptionSectionEntry : public SectionEntry {
   virtual ~ExceptionSectionEntry() = default;
 };
 
+struct CInfoSymInfo {
+  // Name of the C_INFO symbol associated with the section
+  std::string Name;
+  std::string Metadata;
+  // Offset into the start of the metadata in the section
+  uint64_t Offset;
+
+  CInfoSymInfo(std::string Name, std::string Metadata)
+      : Name(Name), Metadata(Metadata) {}
+  // Metadata needs to be padded out to an even word size.
+  uint32_t paddingSize() const {
+    return alignTo(Metadata.size(), sizeof(uint32_t)) - Metadata.size();
+  };
+
+  // Total size of the entry, including the 4 byte length
+  uint32_t size() const {
+    return Metadata.size() + paddingSize() + sizeof(uint32_t);
+  };
+};
+
+struct CInfoSymSectionEntry : public SectionEntry {
+  std::unique_ptr<CInfoSymInfo> Entry;
+
+  CInfoSymSectionEntry(StringRef N, int32_t Flags) : SectionEntry(N, Flags) {}
+  virtual ~CInfoSymSectionEntry() = default;
+  void addEntry(std::unique_ptr<CInfoSymInfo> NewEntry) {
+    Entry = std::move(NewEntry);
+    Entry->Offset = sizeof(uint32_t);
+    Size += Entry->size();
+  }
+  void reset() override {
+    SectionEntry::reset();
+    Entry.reset();
+  }
+};
+
 class XCOFFObjectWriter : public MCObjectWriter {
 
   uint32_t SymbolTableEntryCount = 0;
@@ -309,6 +345,7 @@ class XCOFFObjectWriter : public MCObjectWriter {
   std::vector<SectionEntry> OverflowSections;
 
   ExceptionSectionEntry ExceptionSection;
+  CInfoSymSectionEntry CInfoSymSection;
 
   CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec);
 
@@ -350,6 +387,10 @@ class XCOFFObjectWriter : public MCObjectWriter {
   void writeSectionForExceptionSectionEntry(
       const MCAssembler &Asm, const MCAsmLayout &Layout,
       ExceptionSectionEntry &ExceptionEntry, uint64_t &CurrentAddressLocation);
+  void writeSectionForCInfoSymSectionEntry(const MCAssembler &Asm,
+                                           const MCAsmLayout &Layout,
+                                           CInfoSymSectionEntry &CInfoSymEntry,
+                                           uint64_t &CurrentAddressLocation);
   void writeSymbolTable(const MCAsmLayout &Layout);
   void writeSymbolAuxDwarfEntry(uint64_t LengthOfSectionPortion,
                                 uint64_t NumberOfRelocEnt = 0);
@@ -390,6 +431,7 @@ class XCOFFObjectWriter : public MCObjectWriter {
   unsigned getExceptionSectionSize();
   unsigned getExceptionOffset(const MCSymbol *Symbol);
 
+  void addCInfoSymEntry(StringRef Name, StringRef Metadata) override;
   size_t auxiliaryHeaderSize() const {
     // 64-bit object files have no auxiliary header.
     return HasVisibility && !is64Bit() ? XCOFF::AuxFileHeaderSizeShort : 0;
@@ -418,7 +460,8 @@ XCOFFObjectWriter::XCOFFObjectWriter(
             CsectGroups{&TDataCsects}),
       TBSS(".tbss", XCOFF::STYP_TBSS, /* IsVirtual */ true,
            CsectGroups{&TBSSCsects}),
-      ExceptionSection(".except", XCOFF::STYP_EXCEPT) {}
+      ExceptionSection(".except", XCOFF::STYP_EXCEPT),
+      CInfoSymSection(".info", XCOFF::STYP_INFO) {}
 
 void XCOFFObjectWriter::reset() {
   // Clear the mappings we created.
@@ -434,6 +477,7 @@ void XCOFFObjectWriter::reset() {
   for (auto &OverflowSec : OverflowSections)
     OverflowSec.reset();
   ExceptionSection.reset();
+  CInfoSymSection.reset();
 
   // Reset states in XCOFFObjectWriter.
   SymbolTableEntryCount = 0;
@@ -581,6 +625,10 @@ void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
       Strings.add(XSym->getSymbolTableName());
   }
 
+  std::unique_ptr<CInfoSymInfo> &CISI = CInfoSymSection.Entry;
+  if (CISI && nameShouldBeInStringTable(CISI->Name))
+    Strings.add(CISI->Name);
+
   FileNames = Asm.getFileNames();
   // Emit ".file" as the source file name when there is no file name.
   if (FileNames.empty())
@@ -743,6 +791,8 @@ void XCOFFObjectWriter::writeSections(const MCAssembler &Asm,
                                      CurrentAddressLocation);
   writeSectionForExceptionSectionEntry(Asm, Layout, ExceptionSection,
                                        CurrentAddressLocation);
+  writeSectionForCInfoSymSectionEntry(Asm, Layout, CInfoSymSection,
+                                      CurrentAddressLocation);
 }
 
 uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm,
@@ -1012,6 +1062,8 @@ void XCOFFObjectWriter::writeSectionHeaderTable() {
     writeSectionHeader(&OverflowSec);
   if (hasExceptionSection())
     writeSectionHeader(&ExceptionSection);
+  if (CInfoSymSection.Entry)
+    writeSectionHeader(&CInfoSymSection);
 }
 
 void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc,
@@ -1060,6 +1112,12 @@ void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) {
                      /*NumberOfAuxEntries=*/0);
   }
 
+  if (CInfoSymSection.Entry)
+    writeSymbolEntry(CInfoSymSection.Entry->Name, CInfoSymSection.Entry->Offset,
+                     CInfoSymSection.Index,
+                     /*SymbolType=*/0, XCOFF::C_INFO,
+                     /*NumberOfAuxEntries=*/0);
+
   for (const auto &Csect : UndefinedCsects) {
     writeSymbolEntryForControlSection(Csect, XCOFF::ReservedSectionNum::N_UNDEF,
                                       Csect.MCSec->getStorageClass());
@@ -1197,6 +1255,9 @@ void XCOFFObjectWriter::finalizeSectionInfo() {
   if (hasExceptionSection())
     RawPointer = ExceptionSection.advanceFileOffset(MaxRawDataSize, RawPointer);
 
+  if (CInfoSymSection.Entry)
+    RawPointer = CInfoSymSection.advanceFileOffset(MaxRawDataSize, RawPointer);
+
   for (auto *Sec : Sections) {
     if (Sec->Index != SectionEntry::UninitializedIndex)
       calcOffsetToRelocations(Sec, RawPointer);
@@ -1258,10 +1319,19 @@ unsigned XCOFFObjectWriter::getExceptionOffset(const MCSymbol *Symbol) {
                                : XCOFF::ExceptionSectionEntrySize32);
 }
 
+void XCOFFObjectWriter::addCInfoSymEntry(StringRef Name, StringRef Metadata) {
+  assert(!CInfoSymSection.Entry && "Multiple entries are not supported");
+  CInfoSymSection.addEntry(
+      std::make_unique<CInfoSymInfo>(Name.str(), Metadata.str()));
+}
+
 void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
   // The symbol table starts with all the C_FILE symbols.
   uint32_t SymbolTableIndex = FileNames.size();
 
+  if (CInfoSymSection.Entry)
+    SymbolTableIndex++;
+
   // Calculate indices for undefined symbols.
   for (auto &Csect : UndefinedCsects) {
     Csect.Size = 0;
@@ -1418,6 +1488,14 @@ void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
     Address = alignTo(Address, DefaultSectionAlign);
   }
 
+  if (CInfoSymSection.Entry) {
+    CInfoSymSection.Index = SectionIndex++;
+    SectionCount++;
+    CInfoSymSection.Address = 0;
+    Address += CInfoSymSection.Size;
+    Address = alignTo(Address, DefaultSectionAlign);
+  }
+
   SymbolTableEntryCount = SymbolTableIndex;
 }
 
@@ -1519,6 +1597,41 @@ void XCOFFObjectWriter::writeSectionForExceptionSectionEntry(
   CurrentAddressLocation += getExceptionSectionSize();
 }
 
+void XCOFFObjectWriter::writeSectionForCInfoSymSectionEntry(
+    const MCAssembler &Asm, const MCAsmLayout &Layout,
+    CInfoSymSectionEntry &CInfoSymEntry, uint64_t &CurrentAddressLocation) {
+  if (!CInfoSymSection.Entry)
+    return;
+
+  constexpr int WordSize = sizeof(uint32_t);
+  std::unique_ptr<CInfoSymInfo> &CISI = CInfoSymEntry.Entry;
+  const std::string &Metadata = CISI->Metadata;
+
+  // Emit the 4-byte length of the metadata.
+  W.write<uint32_t>(Metadata.size());
+
+  if (Metadata.size() == 0)
+    return;
+
+  // Write out the payload one word at a time.
+  size_t Index = 0;
+  while (Index + WordSize <= Metadata.size()) {
+    uint32_t NextWord =
+        llvm::support::endian::read32be(Metadata.data() + Index);
+    W.write<uint32_t>(NextWord);
+    Index += WordSize;
+  }
+
+  // If there is padding, we have at least one byte of payload left to emit.
+  if (CISI->paddingSize()) {
+    std::array<uint8_t, WordSize> LastWord = {0};
+    ::memcpy(LastWord.data(), Metadata.data() + Index, Metadata.size() - Index);
+    W.write<uint32_t>(llvm::support::endian::read32be(LastWord.data()));
+  }
+
+  CurrentAddressLocation += CISI->size();
+}
+
 // Takes the log base 2 of the alignment and shifts the result into the 5 most
 // significant bits of a byte, then or's in the csect type into the least
 // significant 3 bits.
index 2164fed..99725c6 100644 (file)
@@ -3,21 +3,27 @@
 ; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | \
 ; RUN: FileCheck --check-prefix=ASM %s
 
-; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff -filetype=obj  < %s 2>&1 | \
+; RUN: llc -mtriple powerpc-ibm-aix-xcoff -filetype=obj  -o %t.o < %s
+; RUN: llvm-objdump --full-contents --section=.info %t.o | \
 ; RUN: FileCheck --check-prefix=OBJ %s
-; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff -filetype=obj  < %s 2>&1 | \
+; RUN: llc -mtriple powerpc64-ibm-aix-xcoff -filetype=obj  -o %t.o < %s
+; RUN: llvm-objdump --full-contents --section=.info %t.o | \
 ; RUN: FileCheck --check-prefix=OBJ %s
 
 ; Verify that llvm.commandline metadata is emitted to .info sections and that the
 ; metadata is padded if necessary.
 
-; OBJ: LLVM ERROR: emitXCOFFCInfoSym is not implemented yet on object generation path
-
 ; ASM: .info ".GCC.command.line", 0x0000003a,
 ; ASM: .info , 0x40282329, 0x6f707420, 0x636c616e, 0x67202d63, 0x6f6d6d61, 0x6e64202d
 ; ASM: .info , 0x6c696e65, 0x0a004028, 0x23296f70, 0x7420736f, 0x6d657468, 0x696e6720
 ; ASM: .info , 0x656c7365, 0x20313233, 0x0a000000
 
+; OBJ: Contents of section .info:
+; OBJ: 0000 0000003a 40282329 6f707420 636c616e  ...:@(#)opt clan
+; OBJ: 0010 67202d63 6f6d6d61 6e64202d 6c696e65  g -command -line
+; OBJ: 0020 0a004028 23296f70 7420736f 6d657468  ..@(#)opt someth
+; OBJ: 0030 696e6720 656c7365 20313233 0a000000  ing else 123....
+
 !llvm.commandline = !{!0, !1}
 !0 = !{!"clang -command -line"}
 !1 = !{!"something else 123"}