[llvm] [SystemZ][z/OS] Show instruction encoding in HLASM output (PR #181904)

Kai Nacke via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 20 10:48:03 PST 2026


https://github.com/redstar updated https://github.com/llvm/llvm-project/pull/181904

>From 072c0f1f1371b8efc61789fa6033a2be9fba460d Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Tue, 17 Feb 2026 14:32:24 -0500
Subject: [PATCH 1/3] [SystemZ][z/OS] Show instruction encoding in HLASM output

This change adds the support to show instruction encoding as a comment
when emitting HLASM text. With this, the last 2 LIT tests migrate to
HLASM syntax.
---
 .../MCTargetDesc/SystemZHLASMAsmStreamer.cpp  | 102 +++++++++++++
 .../MCTargetDesc/SystemZHLASMAsmStreamer.h    |   4 +
 llvm/test/CodeGen/SystemZ/call-zos-02.ll      |  12 +-
 llvm/test/MC/SystemZ/insn-good-zos-pcrel.s    | 140 +++++++++++-------
 4 files changed, 197 insertions(+), 61 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
index 8a559e1ab261b..32c9eafd25615 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
@@ -115,6 +115,12 @@ void SystemZHLASMAsmStreamer::emitAlignmentDS(uint64_t ByteAlignment,
   EmitEOL();
 }
 
+raw_ostream &SystemZHLASMAsmStreamer::getCommentOS() {
+  if (!IsVerboseAsm)
+    return nulls();  // Discard comments unless in verbose asm mode.
+  return CommentStream;
+}
+
 void SystemZHLASMAsmStreamer::AddComment(const Twine &T, bool EOL) {
   if (!IsVerboseAsm)
     return;
@@ -186,8 +192,104 @@ void SystemZHLASMAsmStreamer::emitBytes(StringRef Data) {
   EmitEOL();
 }
 
+void SystemZHLASMAsmStreamer::addEncodingComment(const MCInst &Inst,
+                                                 const MCSubtargetInfo &STI) {
+  raw_ostream &OS = getCommentOS();
+  SmallString<256> Code;
+  SmallVector<MCFixup, 4> Fixups;
+
+  // If we have no code emitter, don't emit code.
+  if (!getAssembler().getEmitterPtr())
+    return;
+
+  getAssembler().getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
+
+  // If we are showing fixups, create symbolic markers in the encoded
+  // representation. We do this by making a per-bit map to the fixup item index,
+  // then trying to display it as nicely as possible.
+  SmallVector<uint8_t, 64> FixupMap;
+  FixupMap.resize(Code.size() * 8);
+  for (unsigned I = 0, E = Code.size() * 8; I != E; ++I)
+    FixupMap[I] = 0;
+
+  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
+    MCFixup &F = Fixups[I];
+    MCFixupKindInfo Info =
+        getAssembler().getBackend().getFixupKindInfo(F.getKind());
+    for (unsigned J = 0; J != Info.TargetSize; ++J) {
+      unsigned Index = F.getOffset() * 8 + Info.TargetOffset + J;
+      assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
+      FixupMap[Index] = 1 + I;
+    }
+  }
+
+  OS << "encoding: [";
+  for (unsigned I = 0, E = Code.size(); I != E; ++I) {
+    if (I)
+      OS << ',';
+
+    // See if all bits are the same map entry.
+    uint8_t MapEntry = FixupMap[I * 8 + 0];
+    for (unsigned J = 1; J != 8; ++J) {
+      if (FixupMap[I * 8 + J] == MapEntry)
+        continue;
+
+      MapEntry = uint8_t(~0U);
+      break;
+    }
+
+    if (MapEntry != uint8_t(~0U)) {
+      if (MapEntry == 0) {
+        OS << format("0x%02x", uint8_t(Code[I]));
+      } else {
+        if (Code[I]) {
+          // FIXME: Some of the 8 bits require fix up.
+          OS << format("0x%02x", uint8_t(Code[I])) << '\''
+             << char('A' + MapEntry - 1) << '\'';
+        } else
+          OS << char('A' + MapEntry - 1);
+      }
+    } else {
+      // Otherwise, write out in binary.
+      OS << "0b";
+      for (unsigned J = 8; J--;) {
+        unsigned Bit = (Code[I] >> J) & 1;
+        unsigned FixupBit = I * 8 + (7-J);
+        if (uint8_t MapEntry = FixupMap[FixupBit]) {
+          assert(Bit == 0 && "Encoder wrote into fixed up bit!");
+          OS << char('A' + MapEntry - 1);
+        } else
+          OS << Bit;
+      }
+    }
+  }
+  OS << "]";
+  EmitEOL();
+
+  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
+    MCFixup &F = Fixups[I];
+    OS << "  fixup " << char('A' + I) << " - "
+       << "offset: " << F.getOffset() << ", value: ";
+    MAI->printExpr(OS, *F.getValue());
+    auto Kind = F.getKind();
+    if (mc::isRelocation(Kind))
+      OS << ", relocation type: " << Kind;
+    else {
+      OS << ", kind: ";
+      auto Info = getAssembler().getBackend().getFixupKindInfo(Kind);
+      if (F.isPCRel() && StringRef(Info.Name).starts_with("FK_Data_"))
+        OS << "FK_PCRel_" << (Info.TargetSize / 8);
+      else
+        OS << Info.Name;
+    }
+    EmitEOL();
+  }
+}
+
 void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst,
                                               const MCSubtargetInfo &STI) {
+  // Show the encoding in a comment if we have a code emitter.
+  addEncodingComment(Inst, STI);
 
   InstPrinter->printInst(&Inst, 0, "", STI, OS);
   EmitEOL();
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
index 1eb358d45e0f4..34bf5f1e68ba2 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
@@ -83,6 +83,8 @@ class SystemZHLASMAsmStreamer final : public MCStreamer {
   /// and only when verbose assembly output is enabled.
   void AddComment(const Twine &T, bool EOL = true) override;
 
+  raw_ostream &getCommentOS() override;
+  
   void emitBytes(StringRef Data) override;
 
   void emitAlignmentDS(uint64_t ByteAlignment, std::optional<int64_t> Value,
@@ -99,6 +101,8 @@ class SystemZHLASMAsmStreamer final : public MCStreamer {
   /// Do we support EmitRawText?
   bool hasRawTextSupport() const override { return true; }
 
+  void addEncodingComment(const MCInst &Inst, const MCSubtargetInfo &STI);
+
   /// @name MCStreamer Interface
   /// @{
   void visitUsedSymbol(const MCSymbol &Sym) override;
diff --git a/llvm/test/CodeGen/SystemZ/call-zos-02.ll b/llvm/test/CodeGen/SystemZ/call-zos-02.ll
index 4f1013fc8974d..7ddfda84ef4f6 100644
--- a/llvm/test/CodeGen/SystemZ/call-zos-02.ll
+++ b/llvm/test/CodeGen/SystemZ/call-zos-02.ll
@@ -1,4 +1,4 @@
-; RUN: llc --mtriple=s390x-ibm-zos --show-mc-encoding -emit-gnuas-syntax-on-zos=1 < %s | FileCheck %s
+; RUN: llc --mtriple=s390x-ibm-zos --show-mc-encoding < %s | FileCheck %s
 
 define internal signext i32 @caller() {
 entry:
@@ -8,10 +8,12 @@ entry:
 
 define hidden signext i32 @caller2() {
 entry:
-; CHECK-LABEL:   caller2:
-; CHECK:         brasl 7,caller       * encoding: [0xc0,0x75,A,A,A,A]
-; CHECK-NEXT:    * fixup A - offset: 2, value: caller+2, kind: FK_390_PC32DBL
-; CHECK-NEXT:    bcr     0,3          * encoding: [0x07,0x03]
+; CHECK-LABEL:   caller2 DS 0H
+; CHECK:      * encoding: [0xc0,0x75,A,A,A,A]
+; CHECK-NEXT: * fixup A - offset: 2, value: caller+2, kind: FK_390_PC32DBL
+; CHECK-NEXT:     brasl 7,caller
+; CHECK-NEXT: * encoding: [0x07,0x03]
+; CHECK-NEXT:    bcr     0,3
   %call = call signext i32 @caller()
   ret i32 %call
 }
diff --git a/llvm/test/MC/SystemZ/insn-good-zos-pcrel.s b/llvm/test/MC/SystemZ/insn-good-zos-pcrel.s
index 07bf680f48b1d..50ec132f10723 100644
--- a/llvm/test/MC/SystemZ/insn-good-zos-pcrel.s
+++ b/llvm/test/MC/SystemZ/insn-good-zos-pcrel.s
@@ -1,102 +1,130 @@
 * For z10 and above.
-* RUN: llvm-mc -triple s390x-ibm-zos -show-encoding -emit-gnuas-syntax-on-zos=1 %s | FileCheck %s
-
-*CHECK: brcl	0, FOO                  * encoding: [0xc0,0x04,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgnop	FOO                     * encoding: [0xc0,0x04,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+* RUN: llvm-mc -triple s390x-ibm-zos -show-encoding %s | FileCheck %s
+
+*CHECK: * encoding: [0xc0,0x04,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: brcl	0, FOO
+*CHECK: * encoding: [0xc0,0x04,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnop	FOO
 	brcl	0,FOO
 	jlnop	FOO
 
-*CHECK: jge	FOO                     * encoding: [0xc0,0x84,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jge	FOO                     * encoding: [0xc0,0x84,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0x84,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jge	FOO
+*CHECK: * encoding: [0xc0,0x84,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jge	FOO
 	jle	FOO
 	brel	FOO
 
-*CHECK: jgne	FOO                     * encoding: [0xc0,0x74,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgne	FOO                     * encoding: [0xc0,0x74,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0x74,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgne	FOO
+*CHECK: * encoding: [0xc0,0x74,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgne	FOO
 	jlne	FOO
 	brnel	FOO
 
-*CHECK: jgh	FOO                     * encoding: [0xc0,0x24,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgh	FOO                     * encoding: [0xc0,0x24,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0x24,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgh	FOO
+*CHECK: * encoding: [0xc0,0x24,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgh	FOO
 	jlh	FOO
 	brhl	FOO
 
-*CHECK: jgnh	FOO                     * encoding: [0xc0,0xd4,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgnh	FOO                     * encoding: [0xc0,0xd4,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0xd4,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnh	FOO
+*CHECK: * encoding: [0xc0,0xd4,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnh	FOO
 	jlnh	FOO
 	brnhl	FOO
 
-*CHECK: jgl	FOO                     * encoding: [0xc0,0x44,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgl	FOO                     * encoding: [0xc0,0x44,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0x44,A,A,A,A]
+*CHECK: fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgl	FOO
+*CHECK: * encoding: [0xc0,0x44,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgl	FOO
 	jll	FOO
 	brll	FOO
 
-*CHECK: jgnl	FOO                     * encoding: [0xc0,0xb4,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgnl	FOO                     * encoding: [0xc0,0xb4,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0xb4,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnl	FOO
+*CHECK: * encoding: [0xc0,0xb4,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnl	FOO
 	jlnl	FOO
 	brnll	FOO
 
-*CHECK: jgz	FOO                     * encoding: [0xc0,0x84,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgz	FOO                     * encoding: [0xc0,0x84,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0x84,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgz	FOO
+*CHECK: * encoding: [0xc0,0x84,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgz	FOO
 	jlz	FOO
 	brzl	FOO
 
-*CHECK: jgnz	FOO                     * encoding: [0xc0,0x74,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgnz	FOO                     * encoding: [0xc0,0x74,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0x74,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnz	FOO
+*CHECK: * encoding: [0xc0,0x74,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnz	FOO
 	jlnz	FOO
 	brnzl	FOO
 
-*CHECK: jgp	FOO                     * encoding: [0xc0,0x24,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgp	FOO                     * encoding: [0xc0,0x24,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0x24,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgp	FOO
+*CHECK: * encoding: [0xc0,0x24,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgp	FOO
 	jlp	FOO
 	brpl	FOO
 
-*CHECK: jgnp	FOO                     * encoding: [0xc0,0xd4,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgnp	FOO                     * encoding: [0xc0,0xd4,A,A,A,A]
+*CHECK: * encoding: [0xc0,0xd4,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnp	FOO
+*CHECK: * encoding: [0xc0,0xd4,A,A,A,A]
 *CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnp	FOO
 	jlnp	FOO
 	brnpl	FOO
 
-*CHECK: jgm	FOO                     * encoding: [0xc0,0x44,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgm	FOO                     * encoding: [0xc0,0x44,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0x44,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgm	FOO
+*CHECK: * encoding: [0xc0,0x44,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgm	FOO
 	jlm	FOO
 	brml	FOO
 
 
-*CHECK: jgnm	FOO                     * encoding: [0xc0,0xb4,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jgnm	FOO                     * encoding: [0xc0,0xb4,A,A,A,A]
+*CHECK: * encoding: [0xc0,0xb4,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnm	FOO
+*CHECK: * encoding: [0xc0,0xb4,A,A,A,A]
 *CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jgnm	FOO
 	jlnm	FOO
 	brnml	FOO
 
-*CHECK: jg	FOO                     * encoding: [0xc0,0xf4,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
-*CHECK: jg	FOO                     * encoding: [0xc0,0xf4,A,A,A,A]
-*CHECK:  fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: * encoding: [0xc0,0xf4,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jg	FOO
+*CHECK: * encoding: [0xc0,0xf4,A,A,A,A]
+*CHECK: * fixup A - offset: 2, value: FOO+2, kind: FK_390_PC32DBL
+*CHECK: jg	FOO
 	jlu	FOO
 	brul	FOO
 

>From b9b0a7e615477cd120d8d984b4d8d358623416ae Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Tue, 17 Feb 2026 15:55:09 -0500
Subject: [PATCH 2/3] Fix formatting

---
 .../SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp   | 10 +++++-----
 .../SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h     |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
index 32c9eafd25615..d9d599064eabf 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
@@ -117,7 +117,7 @@ void SystemZHLASMAsmStreamer::emitAlignmentDS(uint64_t ByteAlignment,
 
 raw_ostream &SystemZHLASMAsmStreamer::getCommentOS() {
   if (!IsVerboseAsm)
-    return nulls();  // Discard comments unless in verbose asm mode.
+    return nulls(); // Discard comments unless in verbose asm mode.
   return CommentStream;
 }
 
@@ -254,7 +254,7 @@ void SystemZHLASMAsmStreamer::addEncodingComment(const MCInst &Inst,
       OS << "0b";
       for (unsigned J = 8; J--;) {
         unsigned Bit = (Code[I] >> J) & 1;
-        unsigned FixupBit = I * 8 + (7-J);
+        unsigned FixupBit = I * 8 + (7 - J);
         if (uint8_t MapEntry = FixupMap[FixupBit]) {
           assert(Bit == 0 && "Encoder wrote into fixed up bit!");
           OS << char('A' + MapEntry - 1);
@@ -263,8 +263,7 @@ void SystemZHLASMAsmStreamer::addEncodingComment(const MCInst &Inst,
       }
     }
   }
-  OS << "]";
-  EmitEOL();
+  OS << "]\n";
 
   for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
     MCFixup &F = Fixups[I];
@@ -282,7 +281,7 @@ void SystemZHLASMAsmStreamer::addEncodingComment(const MCInst &Inst,
       else
         OS << Info.Name;
     }
-    EmitEOL();
+    OS << "\n";
   }
 }
 
@@ -290,6 +289,7 @@ void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst,
                                               const MCSubtargetInfo &STI) {
   // Show the encoding in a comment if we have a code emitter.
   addEncodingComment(Inst, STI);
+  EmitEOL();
 
   InstPrinter->printInst(&Inst, 0, "", STI, OS);
   EmitEOL();
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
index 34bf5f1e68ba2..7f018ad7fe884 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
@@ -84,7 +84,7 @@ class SystemZHLASMAsmStreamer final : public MCStreamer {
   void AddComment(const Twine &T, bool EOL = true) override;
 
   raw_ostream &getCommentOS() override;
-  
+
   void emitBytes(StringRef Data) override;
 
   void emitAlignmentDS(uint64_t ByteAlignment, std::optional<int64_t> Value,

>From 89dd6e775d7f1b43245475cbf8df681102239c93 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Fri, 20 Feb 2026 09:48:09 -0500
Subject: [PATCH 3/3] Refactor function

Move `AddEncodingComment()` as a free function into a new compilation
unit, and update the callers accordingly.
---
 .../include/llvm/MC/MCEncodingCommentHelper.h |  44 ++++++
 llvm/lib/MC/CMakeLists.txt                    |   1 +
 llvm/lib/MC/MCAsmStreamer.cpp                 | 100 +-------------
 llvm/lib/MC/MCEncodingCommentHelper.cpp       | 127 ++++++++++++++++++
 .../MCTargetDesc/SystemZHLASMAsmStreamer.cpp  |  91 +------------
 5 files changed, 178 insertions(+), 185 deletions(-)
 create mode 100644 llvm/include/llvm/MC/MCEncodingCommentHelper.h
 create mode 100644 llvm/lib/MC/MCEncodingCommentHelper.cpp

diff --git a/llvm/include/llvm/MC/MCEncodingCommentHelper.h b/llvm/include/llvm/MC/MCEncodingCommentHelper.h
new file mode 100644
index 0000000000000..1b0f281410697
--- /dev/null
+++ b/llvm/include/llvm/MC/MCEncodingCommentHelper.h
@@ -0,0 +1,44 @@
+//===- MCEncodingCommentHelper.h - Encoding Comment Helper ------*- 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 helper functions for emitting encoding comments in
+// assembly output.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCENCODINGCOMMENTHELPER_H
+#define LLVM_MC_MCENCODINGCOMMENTHELPER_H
+
+namespace llvm {
+
+class MCInst;
+class MCSubtargetInfo;
+class MCAssembler;
+class MCAsmInfo;
+class raw_ostream;
+
+namespace mc {
+
+/// Emit an encoding comment for the given instruction.
+///
+/// This function encodes the instruction and emits a comment showing the
+/// encoding bytes and any fixups that need to be applied.
+///
+/// \param OS - The output stream to write the comment to.
+/// \param Inst - The instruction to encode.
+/// \param STI - Subtarget information.
+/// \param Assembler - The assembler containing the code emitter and backend.
+/// \param MAI - Assembly info for formatting.
+/// \param ForceLE - Force little-endian encoding regardless of target.
+void emitEncodingComment(raw_ostream &OS, const MCInst &Inst,
+                         const MCSubtargetInfo &STI, MCAssembler &Assembler,
+                         const MCAsmInfo &MAI, bool ForceLE = false);
+} // namespace mc
+} // end namespace llvm
+
+#endif // LLVM_MC_MCENCODINGCOMMENTHELPER_H
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index 1388f130bb806..f29029781649a 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -23,6 +23,7 @@ add_llvm_component_library(LLVMMC
   MCDXContainerWriter.cpp
   MCELFObjectTargetWriter.cpp
   MCELFStreamer.cpp
+  MCEncodingCommentHelper.cpp
   MCExpr.cpp
   MCFragment.cpp
   MCGOFFStreamer.cpp
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index d9a22bc2716fd..aa173601565c4 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -16,6 +16,7 @@
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCCodeView.h"
 #include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCEncodingCommentHelper.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstPrinter.h"
@@ -2388,108 +2389,11 @@ void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
 void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
                                        const MCSubtargetInfo &STI) {
   raw_ostream &OS = getCommentOS();
-  SmallString<256> Code;
-  SmallVector<MCFixup, 4> Fixups;
-
-  // If we have no code emitter, don't emit code.
-  if (!getAssembler().getEmitterPtr())
-    return;
-
-  getAssembler().getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
 
   // RISC-V instructions are always little-endian, even on BE systems.
   bool ForceLE = getContext().getTargetTriple().isRISCV();
 
-  // If we are showing fixups, create symbolic markers in the encoded
-  // representation. We do this by making a per-bit map to the fixup item index,
-  // then trying to display it as nicely as possible.
-  SmallVector<uint8_t, 64> FixupMap;
-  FixupMap.resize(Code.size() * 8);
-  for (unsigned i = 0, e = Code.size() * 8; i != e; ++i)
-    FixupMap[i] = 0;
-
-  for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
-    MCFixup &F = Fixups[i];
-    MCFixupKindInfo Info =
-        getAssembler().getBackend().getFixupKindInfo(F.getKind());
-    for (unsigned j = 0; j != Info.TargetSize; ++j) {
-      unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j;
-      assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
-      FixupMap[Index] = 1 + i;
-    }
-  }
-
-  // FIXME: Note the fixup comments for Thumb2 are completely bogus since the
-  // high order halfword of a 32-bit Thumb2 instruction is emitted first.
-  OS << "encoding: [";
-  for (unsigned i = 0, e = Code.size(); i != e; ++i) {
-    if (i)
-      OS << ',';
-
-    // See if all bits are the same map entry.
-    uint8_t MapEntry = FixupMap[i * 8 + 0];
-    for (unsigned j = 1; j != 8; ++j) {
-      if (FixupMap[i * 8 + j] == MapEntry)
-        continue;
-
-      MapEntry = uint8_t(~0U);
-      break;
-    }
-
-    if (MapEntry != uint8_t(~0U)) {
-      if (MapEntry == 0) {
-        OS << format("0x%02x", uint8_t(Code[i]));
-      } else {
-        if (Code[i]) {
-          // FIXME: Some of the 8 bits require fix up.
-          OS << format("0x%02x", uint8_t(Code[i])) << '\''
-             << char('A' + MapEntry - 1) << '\'';
-        } else
-          OS << char('A' + MapEntry - 1);
-      }
-    } else {
-      // Otherwise, write out in binary.
-      OS << "0b";
-      for (unsigned j = 8; j--;) {
-        unsigned Bit = (Code[i] >> j) & 1;
-
-        unsigned FixupBit;
-        // RISC-V instructions are always little-endian.
-        // The FixupMap is indexed by actual bit positions in the LE
-        // instruction.
-        if (MAI->isLittleEndian() || ForceLE)
-          FixupBit = i * 8 + j;
-        else
-          FixupBit = i * 8 + (7-j);
-
-        if (uint8_t MapEntry = FixupMap[FixupBit]) {
-          assert(Bit == 0 && "Encoder wrote into fixed up bit!");
-          OS << char('A' + MapEntry - 1);
-        } else
-          OS << Bit;
-      }
-    }
-  }
-  OS << "]\n";
-
-  for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
-    MCFixup &F = Fixups[i];
-    OS << "  fixup " << char('A' + i) << " - "
-       << "offset: " << F.getOffset() << ", value: ";
-    MAI->printExpr(OS, *F.getValue());
-    auto Kind = F.getKind();
-    if (mc::isRelocation(Kind))
-      OS << ", relocation type: " << Kind;
-    else {
-      OS << ", kind: ";
-      auto Info = getAssembler().getBackend().getFixupKindInfo(Kind);
-      if (F.isPCRel() && StringRef(Info.Name).starts_with("FK_Data_"))
-        OS << "FK_PCRel_" << (Info.TargetSize / 8);
-      else
-        OS << Info.Name;
-    }
-    OS << '\n';
-  }
+  mc::emitEncodingComment(OS, Inst, STI, getAssembler(), *MAI, ForceLE);
 }
 
 void MCAsmStreamer::emitInstruction(const MCInst &Inst,
diff --git a/llvm/lib/MC/MCEncodingCommentHelper.cpp b/llvm/lib/MC/MCEncodingCommentHelper.cpp
new file mode 100644
index 0000000000000..be5e028b55bd2
--- /dev/null
+++ b/llvm/lib/MC/MCEncodingCommentHelper.cpp
@@ -0,0 +1,127 @@
+//===- MCEncodingCommentHelper.cpp - Encoding Comment Helper ----*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCEncodingCommentHelper.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.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/MCFixup.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void llvm::mc::emitEncodingComment(raw_ostream &OS, const MCInst &Inst,
+                                   const MCSubtargetInfo &STI,
+                                   MCAssembler &Assembler, const MCAsmInfo &MAI,
+                                   bool ForceLE) {
+  SmallString<256> Code;
+  SmallVector<MCFixup, 4> Fixups;
+
+  // If we have no code emitter, don't emit code.
+  if (!Assembler.getEmitterPtr())
+    return;
+
+  Assembler.getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
+
+  // If we are showing fixups, create symbolic markers in the encoded
+  // representation. We do this by making a per-bit map to the fixup item index,
+  // then trying to display it as nicely as possible.
+  SmallVector<uint8_t, 64> FixupMap;
+  FixupMap.resize(Code.size() * 8);
+  for (unsigned I = 0, E = Code.size() * 8; I != E; ++I)
+    FixupMap[I] = 0;
+
+  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
+    MCFixup &F = Fixups[I];
+    MCFixupKindInfo Info = Assembler.getBackend().getFixupKindInfo(F.getKind());
+    for (unsigned J = 0; J != Info.TargetSize; ++J) {
+      unsigned Index = F.getOffset() * 8 + Info.TargetOffset + J;
+      assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
+      FixupMap[Index] = 1 + I;
+    }
+  }
+
+  // FIXME: Note the fixup comments for Thumb2 are completely bogus since the
+  // high order halfword of a 32-bit Thumb2 instruction is emitted first.
+  OS << "encoding: [";
+  for (unsigned I = 0, E = Code.size(); I != E; ++I) {
+    if (I)
+      OS << ',';
+
+    // See if all bits are the same map entry.
+    uint8_t MapEntry = FixupMap[I * 8 + 0];
+    for (unsigned J = 1; J != 8; ++J) {
+      if (FixupMap[I * 8 + J] == MapEntry)
+        continue;
+
+      MapEntry = uint8_t(~0U);
+      break;
+    }
+
+    if (MapEntry != uint8_t(~0U)) {
+      if (MapEntry == 0) {
+        OS << format("0x%02x", uint8_t(Code[I]));
+      } else {
+        if (Code[I]) {
+          // FIXME: Some of the 8 bits require fix up.
+          OS << format("0x%02x", uint8_t(Code[I])) << '\''
+             << char('A' + MapEntry - 1) << '\'';
+        } else
+          OS << char('A' + MapEntry - 1);
+      }
+    } else {
+      // Otherwise, write out in binary.
+      OS << "0b";
+      for (unsigned J = 8; J--;) {
+        unsigned Bit = (Code[I] >> J) & 1;
+
+        unsigned FixupBit;
+        // RISC-V instructions are always little-endian.
+        // The FixupMap is indexed by actual bit positions in the LE
+        // instruction.
+        if (MAI.isLittleEndian() || ForceLE)
+          FixupBit = I * 8 + J;
+        else
+          FixupBit = I * 8 + (7 - J);
+
+        if (uint8_t MapEntry = FixupMap[FixupBit]) {
+          assert(Bit == 0 && "Encoder wrote into fixed up bit!");
+          OS << char('A' + MapEntry - 1);
+        } else
+          OS << Bit;
+      }
+    }
+  }
+  OS << "]\n";
+
+  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
+    MCFixup &F = Fixups[I];
+    OS << "  fixup " << char('A' + I) << " - "
+       << "offset: " << F.getOffset() << ", value: ";
+    MAI.printExpr(OS, *F.getValue());
+    auto Kind = F.getKind();
+    if (mc::isRelocation(Kind))
+      OS << ", relocation type: " << Kind;
+    else {
+      OS << ", kind: ";
+      auto Info = Assembler.getBackend().getFixupKindInfo(Kind);
+      if (F.isPCRel() && StringRef(Info.Name).starts_with("FK_Data_"))
+        OS << "FK_PCRel_" << (Info.TargetSize / 8);
+      else
+        OS << Info.Name;
+    }
+    OS << '\n';
+  }
+}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
index d9d599064eabf..01207e9194cf4 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp
@@ -9,6 +9,7 @@
 #include "SystemZHLASMAsmStreamer.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/MC/MCEncodingCommentHelper.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCGOFFAttributes.h"
 #include "llvm/MC/MCGOFFStreamer.h"
@@ -195,94 +196,10 @@ void SystemZHLASMAsmStreamer::emitBytes(StringRef Data) {
 void SystemZHLASMAsmStreamer::addEncodingComment(const MCInst &Inst,
                                                  const MCSubtargetInfo &STI) {
   raw_ostream &OS = getCommentOS();
-  SmallString<256> Code;
-  SmallVector<MCFixup, 4> Fixups;
 
-  // If we have no code emitter, don't emit code.
-  if (!getAssembler().getEmitterPtr())
-    return;
-
-  getAssembler().getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
-
-  // If we are showing fixups, create symbolic markers in the encoded
-  // representation. We do this by making a per-bit map to the fixup item index,
-  // then trying to display it as nicely as possible.
-  SmallVector<uint8_t, 64> FixupMap;
-  FixupMap.resize(Code.size() * 8);
-  for (unsigned I = 0, E = Code.size() * 8; I != E; ++I)
-    FixupMap[I] = 0;
-
-  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
-    MCFixup &F = Fixups[I];
-    MCFixupKindInfo Info =
-        getAssembler().getBackend().getFixupKindInfo(F.getKind());
-    for (unsigned J = 0; J != Info.TargetSize; ++J) {
-      unsigned Index = F.getOffset() * 8 + Info.TargetOffset + J;
-      assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
-      FixupMap[Index] = 1 + I;
-    }
-  }
-
-  OS << "encoding: [";
-  for (unsigned I = 0, E = Code.size(); I != E; ++I) {
-    if (I)
-      OS << ',';
-
-    // See if all bits are the same map entry.
-    uint8_t MapEntry = FixupMap[I * 8 + 0];
-    for (unsigned J = 1; J != 8; ++J) {
-      if (FixupMap[I * 8 + J] == MapEntry)
-        continue;
-
-      MapEntry = uint8_t(~0U);
-      break;
-    }
-
-    if (MapEntry != uint8_t(~0U)) {
-      if (MapEntry == 0) {
-        OS << format("0x%02x", uint8_t(Code[I]));
-      } else {
-        if (Code[I]) {
-          // FIXME: Some of the 8 bits require fix up.
-          OS << format("0x%02x", uint8_t(Code[I])) << '\''
-             << char('A' + MapEntry - 1) << '\'';
-        } else
-          OS << char('A' + MapEntry - 1);
-      }
-    } else {
-      // Otherwise, write out in binary.
-      OS << "0b";
-      for (unsigned J = 8; J--;) {
-        unsigned Bit = (Code[I] >> J) & 1;
-        unsigned FixupBit = I * 8 + (7 - J);
-        if (uint8_t MapEntry = FixupMap[FixupBit]) {
-          assert(Bit == 0 && "Encoder wrote into fixed up bit!");
-          OS << char('A' + MapEntry - 1);
-        } else
-          OS << Bit;
-      }
-    }
-  }
-  OS << "]\n";
-
-  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
-    MCFixup &F = Fixups[I];
-    OS << "  fixup " << char('A' + I) << " - "
-       << "offset: " << F.getOffset() << ", value: ";
-    MAI->printExpr(OS, *F.getValue());
-    auto Kind = F.getKind();
-    if (mc::isRelocation(Kind))
-      OS << ", relocation type: " << Kind;
-    else {
-      OS << ", kind: ";
-      auto Info = getAssembler().getBackend().getFixupKindInfo(Kind);
-      if (F.isPCRel() && StringRef(Info.Name).starts_with("FK_Data_"))
-        OS << "FK_PCRel_" << (Info.TargetSize / 8);
-      else
-        OS << Info.Name;
-    }
-    OS << "\n";
-  }
+  // SystemZ uses big-endian encoding, so don't force little-endian.
+  mc::emitEncodingComment(OS, Inst, STI, getAssembler(), *MAI,
+                          /*ForceLE=*/false);
 }
 
 void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst,



More information about the llvm-commits mailing list