[llvm] MC: Simplify fragment reuse determination (PR #149471)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 18 09:40:04 PDT 2025


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/149471

>From 2efea545f37c57f52037168ec15aa4596ba8fcf2 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Fri, 18 Jul 2025 01:20:16 -0700
Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.5-bogner
---
 llvm/include/llvm/MC/MCObjectStreamer.h    | 13 +------------
 llvm/include/llvm/MC/MCSection.h           |  1 +
 llvm/include/llvm/MC/MCStreamer.h          |  4 +++-
 llvm/lib/MC/MCObjectStreamer.cpp           | 16 ++++------------
 llvm/lib/MC/MCParser/MCTargetAsmParser.cpp |  4 ++++
 llvm/lib/MC/MCStreamer.cpp                 | 13 +++++++++++++
 6 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h
index a55fd4a14675f..319e131999d48 100644
--- a/llvm/include/llvm/MC/MCObjectStreamer.h
+++ b/llvm/include/llvm/MC/MCObjectStreamer.h
@@ -73,20 +73,9 @@ class MCObjectStreamer : public MCStreamer {
   MCSymbol *emitCFILabel() override;
   void emitCFISections(bool EH, bool Debug) override;
 
-  void insert(MCFragment *F) {
-    auto *Sec = CurFrag->getParent();
-    F->setParent(Sec);
-    F->setLayoutOrder(CurFrag->getLayoutOrder() + 1);
-    CurFrag->Next = F;
-    CurFrag = F;
-    Sec->curFragList()->Tail = F;
-  }
-
   /// Get a data fragment to write into, creating a new one if the current
   /// fragment is not FT_Data.
-  /// Optionally a \p STI can be passed in so that a new fragment is created
-  /// if the Subtarget differs from the current fragment.
-  MCFragment *getOrCreateDataFragment(const MCSubtargetInfo *STI = nullptr);
+  MCFragment *getOrCreateDataFragment();
 
 protected:
   bool changeSectionImpl(MCSection *Section, uint32_t Subsection);
diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h
index 296fdd8af0d14..313071ec75033 100644
--- a/llvm/include/llvm/MC/MCSection.h
+++ b/llvm/include/llvm/MC/MCSection.h
@@ -188,6 +188,7 @@ class LLVM_ABI MCSection {
 // destructors.
 class MCFragment {
   friend class MCAssembler;
+  friend class MCStreamer;
   friend class MCObjectStreamer;
   friend class MCSection;
 
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index b3a9aabd6ece5..4b91dbc794682 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -429,7 +429,6 @@ class LLVM_ABI MCStreamer {
            CurFrag->getParent() == getCurrentSection().first);
     return CurFrag;
   }
-
   /// Save the current and previous section on the section stack.
   void pushSection() {
     SectionStack.push_back(
@@ -457,6 +456,9 @@ class LLVM_ABI MCStreamer {
 
   MCSymbol *endSection(MCSection *Section);
 
+  void insert(MCFragment *F);
+  void newFragment();
+
   /// Returns the mnemonic for \p MI, if the streamer has access to a
   /// instruction printer and returns an empty string otherwise.
   virtual StringRef getMnemonic(const MCInst &MI) const { return ""; }
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index 67433f2b265e5..8a3e8efee0b36 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -106,26 +106,18 @@ void MCObjectStreamer::emitFrames(MCAsmBackend *MAB) {
     MCDwarfFrameEmitter::Emit(*this, MAB, false);
 }
 
-static bool canReuseDataFragment(const MCFragment &F,
-                                 const MCAssembler &Assembler,
-                                 const MCSubtargetInfo *STI) {
+static bool canReuseDataFragment(const MCFragment &F) {
   if (!F.hasInstructions())
     return true;
   // Do not add data after a linker-relaxable instruction. The difference
   // between a new label and a label at or before the linker-relaxable
   // instruction cannot be resolved at assemble-time.
-  if (F.isLinkerRelaxable())
-    return false;
-  // If the subtarget is changed mid fragment we start a new fragment to record
-  // the new STI.
-  return !STI || F.getSubtargetInfo() == STI;
+  return !F.isLinkerRelaxable();
 }
 
-MCFragment *
-MCObjectStreamer::getOrCreateDataFragment(const MCSubtargetInfo *STI) {
+MCFragment *MCObjectStreamer::getOrCreateDataFragment() {
   auto *F = getCurrentFragment();
-  if (F->getKind() != MCFragment::FT_Data ||
-      !canReuseDataFragment(*F, *Assembler, STI)) {
+  if (F->getKind() != MCFragment::FT_Data || !canReuseDataFragment(*F)) {
     F = getContext().allocFragment<MCFragment>();
     insert(F);
   }
diff --git a/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp b/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
index 665d92eb9a21c..44498f21a9060 100644
--- a/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
+++ b/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
@@ -9,6 +9,7 @@
 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCStreamer.h"
 
 using namespace llvm;
 
@@ -22,6 +23,9 @@ MCTargetAsmParser::~MCTargetAsmParser() = default;
 MCSubtargetInfo &MCTargetAsmParser::copySTI() {
   MCSubtargetInfo &STICopy = getContext().getSubtargetCopy(getSTI());
   STI = &STICopy;
+  // The returned STI will likely be modified. Create a new fragment to avoid
+  // mixed STI values within a fragment.
+  getStreamer().newFragment();
   return STICopy;
 }
 
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index d814ab8880500..c3ecf8fc717f5 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -1404,6 +1404,19 @@ MCSymbol *MCStreamer::endSection(MCSection *Section) {
   return Sym;
 }
 
+void MCStreamer::insert(MCFragment *F) {
+  auto *Sec = CurFrag->getParent();
+  F->setParent(Sec);
+  F->setLayoutOrder(CurFrag->getLayoutOrder() + 1);
+  CurFrag->Next = F;
+  CurFrag = F;
+  Sec->curFragList()->Tail = F;
+}
+
+void MCStreamer::newFragment() {
+  insert(getContext().allocFragment<MCFragment>());
+}
+
 static VersionTuple
 targetVersionOrMinimumSupportedOSVersion(const Triple &Target,
                                          VersionTuple TargetVersion) {

>From 6d464992e56f064adc47ea4e5dd47bd714d7b353 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Fri, 18 Jul 2025 09:33:30 -0700
Subject: [PATCH 2/2] optimize linker-relaxable and remove canReuseDataFragment

Created using spr 1.3.5-bogner
---
 llvm/lib/MC/MCObjectStreamer.cpp           | 33 ++++++++++++----------
 llvm/lib/MC/MCParser/MCTargetAsmParser.cpp |  3 +-
 llvm/test/MC/RISCV/Relocations/mc-dump.s   |  1 +
 3 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index 8a3e8efee0b36..d5b8f22463894 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -106,18 +106,12 @@ void MCObjectStreamer::emitFrames(MCAsmBackend *MAB) {
     MCDwarfFrameEmitter::Emit(*this, MAB, false);
 }
 
-static bool canReuseDataFragment(const MCFragment &F) {
-  if (!F.hasInstructions())
-    return true;
-  // Do not add data after a linker-relaxable instruction. The difference
-  // between a new label and a label at or before the linker-relaxable
-  // instruction cannot be resolved at assemble-time.
-  return !F.isLinkerRelaxable();
-}
-
 MCFragment *MCObjectStreamer::getOrCreateDataFragment() {
+  // TODO: Start a new fragment whenever finalizing the variable-size tail of a
+  // previous one, so that all getOrCreateDataFragment calls can be replaced
+  // with getCurrentFragment
   auto *F = getCurrentFragment();
-  if (F->getKind() != MCFragment::FT_Data || !canReuseDataFragment(*F)) {
+  if (F->getKind() != MCFragment::FT_Data) {
     F = getContext().allocFragment<MCFragment>();
     insert(F);
   }
@@ -355,16 +349,23 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst,
   F->doneAppending();
   if (!Fixups.empty())
     F->appendFixups(Fixups);
+  F->setHasInstructions(STI);
 
+  bool MarkedLinkerRelaxable = false;
   for (auto &Fixup : MutableArrayRef(F->getFixups()).slice(FixupStartIndex)) {
     Fixup.setOffset(Fixup.getOffset() + CodeOffset);
-    if (Fixup.isLinkerRelaxable()) {
-      F->setLinkerRelaxable();
+    if (!Fixup.isLinkerRelaxable())
+      continue;
+    F->setLinkerRelaxable();
+    // Do not add data after a linker-relaxable instruction. The difference
+    // between a new label and a label at or before the linker-relaxable
+    // instruction cannot be resolved at assemble-time.
+    if (!MarkedLinkerRelaxable) {
+      MarkedLinkerRelaxable = true;
       getCurrentSectionOnly()->setLinkerRelaxable();
+      newFragment();
     }
   }
-
-  F->setHasInstructions(STI);
 }
 
 void MCObjectStreamer::emitInstToFragment(const MCInst &Inst,
@@ -560,8 +561,10 @@ void MCObjectStreamer::emitCodeAlignment(Align Alignment,
   // if the alignment is larger than the minimum NOP size.
   unsigned Size;
   if (getAssembler().getBackend().shouldInsertExtraNopBytesForCodeAlign(*F,
-                                                                        Size))
+                                                                        Size)) {
     getCurrentSectionOnly()->setLinkerRelaxable();
+    newFragment();
+  }
 }
 
 void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset,
diff --git a/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp b/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
index 44498f21a9060..fb32a92f16def 100644
--- a/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
+++ b/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
@@ -25,7 +25,8 @@ MCSubtargetInfo &MCTargetAsmParser::copySTI() {
   STI = &STICopy;
   // The returned STI will likely be modified. Create a new fragment to avoid
   // mixed STI values within a fragment.
-  getStreamer().newFragment();
+  if (getStreamer().getCurrentFragment())
+    getStreamer().newFragment();
   return STICopy;
 }
 
diff --git a/llvm/test/MC/RISCV/Relocations/mc-dump.s b/llvm/test/MC/RISCV/Relocations/mc-dump.s
index 24f3e67ebbdda..f72258498169f 100644
--- a/llvm/test/MC/RISCV/Relocations/mc-dump.s
+++ b/llvm/test/MC/RISCV/Relocations/mc-dump.s
@@ -9,6 +9,7 @@
 # CHECK-NEXT:0 Data LinkerRelaxable Size:8 [97,00,00,00,e7,80,00,00]
 # CHECK-NEXT:  Fixup @0 Value:specifier(19,ext) Kind:4023
 # CHECK-NEXT:  Symbol @0 $x
+# CHECK-NEXT:8 Data Size:0 []
 # CHECK-NEXT:8 Align Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops
 # CHECK-NEXT:12 Data Size:4 [13,05,30,00]
 # CHECK-NEXT:16 Align Align:8 Fill:0 FillLen:1 MaxBytesToEmit:8 Nops



More information about the llvm-commits mailing list