From 583dac827ca7daea75c6e92c4ebf6b2296118886 Mon Sep 17 00:00:00 2001
From: "Duncan P. N. Exon Smith" <dexonsmith@apple.com>
Date: Thu, 21 May 2015 02:41:23 +0000
Subject: [PATCH] AsmPrinter: Compute absolute label difference directly

Create a low-overhead path for `EmitLabelDifference()` that emits a
emits an absolute number when (1) the output is an object stream and (2)
the two symbols are in the same data fragment.

This drops memory usage on Mach-O from 975 MB down to 919 MB (5.8%).
The only call is when `!doesDwarfUseRelocationsAcrossSections()` --
i.e., on Mach-O -- since otherwise an absolute offset from the start of
the section needs a relocation.  (`EmitLabelDifference()` is cheaper on
ELF anyway, since it creates 1 fewer temp symbol, and it gets called far
less often.  It's not clear to me if this is even a bottleneck there.)

(I'm looking at `llc` memory usage on `verify-uselistorder.lto.opt.bc`;
see r236629 for details.)

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237876 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/llvm/MC/MCObjectStreamer.h    | 11 +++++++++++
 include/llvm/MC/MCStreamer.h          |  9 +++++++++
 lib/CodeGen/AsmPrinter/AsmPrinter.cpp |  4 ++++
 lib/MC/MCObjectStreamer.cpp           | 23 +++++++++++++++++++++++
 4 files changed, 47 insertions(+)

diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h
index 8499560d2d7..1a1222562f1 100644
--- a/include/llvm/MC/MCObjectStreamer.h
+++ b/include/llvm/MC/MCObjectStreamer.h
@@ -136,6 +136,17 @@ public:
   void EmitZeros(uint64_t NumBytes) override;
   void FinishImpl() override;
 
+  /// Emit the absolute difference between two symbols if possible.
+  ///
+  /// Emit the absolute difference between \c Hi and \c Lo, as long as we can
+  /// compute it.  Currently, that requires that both symbols are in the same
+  /// data fragment.  Otherwise, do nothing and return \c false.
+  ///
+  /// \pre Offset of \c Hi is greater than the offset \c Lo.
+  /// \return true on success.
+  bool emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo,
+                              unsigned Size) override;
+
   bool mayHaveInstructions() const override {
     return getCurrentSectionData()->hasInstructions();
   }
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h
index 9107df62933..3dec9491a26 100644
--- a/include/llvm/MC/MCStreamer.h
+++ b/include/llvm/MC/MCStreamer.h
@@ -652,6 +652,15 @@ public:
                                      unsigned Isa, unsigned Discriminator,
                                      StringRef FileName);
 
+  /// Emit the absolute difference between two symbols if possible.
+  ///
+  /// \pre Offset of \c Hi is greater than the offset \c Lo.
+  /// \return true on success.
+  virtual bool emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo,
+                                      unsigned Size) {
+    return false;
+  }
+
   virtual MCSymbol *getDwarfLineTableSymbol(unsigned CUID);
   virtual void EmitCFISections(bool EH, bool Debug);
   void EmitCFIStartProc(bool IsSimple);
diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 5af083536d7..17bbf01c43f 100644
--- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1591,6 +1591,10 @@ void AsmPrinter::EmitInt32(int Value) const {
 /// .set if it avoids relocations.
 void AsmPrinter::EmitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo,
                                      unsigned Size) const {
+  if (!MAI->doesDwarfUseRelocationsAcrossSections())
+    if (OutStreamer->emitAbsoluteSymbolDiff(Hi, Lo, Size))
+      return;
+
   // Get the Hi-Lo expression.
   const MCExpr *Diff =
     MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create(Hi, OutContext),
diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp
index d82dd15df2b..836b1ced5c5 100644
--- a/lib/MC/MCObjectStreamer.cpp
+++ b/lib/MC/MCObjectStreamer.cpp
@@ -53,6 +53,29 @@ void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
   }
 }
 
+bool MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi,
+                                              const MCSymbol *Lo,
+                                              unsigned Size) {
+  // Must have symbol data.
+  if (!Assembler->hasSymbolData(*Hi) || !Assembler->hasSymbolData(*Lo))
+    return false;
+  auto &HiD = Assembler->getSymbolData(*Hi);
+  auto &LoD = Assembler->getSymbolData(*Lo);
+
+  // Must both be assigned to the same (valid) fragment.
+  if (!HiD.getFragment() || HiD.getFragment() != LoD.getFragment())
+    return false;
+
+  // Must be a data fragment.
+  if (!isa<MCDataFragment>(HiD.getFragment()))
+    return false;
+
+  assert(HiD.getOffset() >= LoD.getOffset() &&
+         "Expected Hi to be greater than Lo");
+  EmitIntValue(HiD.getOffset() - LoD.getOffset(), Size);
+  return true;
+}
+
 void MCObjectStreamer::reset() {
   if (Assembler)
     Assembler->reset();
-- 
2.34.1