Assume that mergeable input sections are smaller than 4 GiB.

By assuming that mergeable input sections are smaller than 4 GiB,
lld's memory usage when linking clang with debug info drops from
2.788 GiB to 2.019 GiB (measured by valgrind, and that does not include
memory space for mmap'ed files). I think that's a reasonable assumption
given such a large RAM savings, so this patch.

According to valgrind, gold needs 3.54 GiB of RAM to do the same thing.

NB: This patch does not introduce a limitation on the size of
output sections. You can still create sections larger than 4 GiB.

llvm-svn: 316280
diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
index 51b2259..fc03749 100644
--- a/lld/ELF/InputSection.h
+++ b/lld/ELF/InputSection.h
@@ -214,15 +214,17 @@
 // have to be as compact as possible, which is why we don't store the size (can
 // be found by looking at the next one) and put the hash in a side table.
 struct SectionPiece {
-  SectionPiece(size_t Off, bool Live)
-      : InputOff(Off), Live(Live || !Config->GcSections), OutputOff(-1) {}
+  SectionPiece(size_t Off, uint32_t Hash, bool Live)
+      : InputOff(Off), Hash(Hash), OutputOff(-1),
+        Live(Live || !Config->GcSections) {}
 
-  size_t InputOff : 8 * sizeof(ssize_t) - 1;
-  size_t Live : 1;
-  ssize_t OutputOff;
+  uint32_t InputOff;
+  uint32_t Hash;
+  uint64_t OutputOff : 63;
+  uint64_t Live : 1;
 };
-static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t),
-              "SectionPiece is too big");
+
+static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big");
 
 // This corresponds to a SHF_MERGE section of an input file.
 class MergeInputSection : public InputSectionBase {
@@ -252,14 +254,9 @@
   LLVM_ATTRIBUTE_ALWAYS_INLINE
   llvm::CachedHashStringRef getData(size_t I) const {
     size_t Begin = Pieces[I].InputOff;
-    size_t End;
-    if (Pieces.size() - 1 == I)
-      End = this->Data.size();
-    else
-      End = Pieces[I + 1].InputOff;
-
-    StringRef S = {(const char *)(this->Data.data() + Begin), End - Begin};
-    return {S, Hashes[I]};
+    size_t End =
+        (Pieces.size() - 1 == I) ? Data.size() : Pieces[I + 1].InputOff;
+    return {toStringRef(Data.slice(Begin, End - Begin)), Pieces[I].Hash};
   }
 
   // Returns the SectionPiece at a given input section offset.
@@ -272,9 +269,7 @@
   void splitStrings(ArrayRef<uint8_t> A, size_t Size);
   void splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
 
-  std::vector<uint32_t> Hashes;
-
-  mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap;
+  mutable llvm::DenseMap<uint32_t, uint32_t> OffsetMap;
   mutable llvm::once_flag InitOffsetMap;
 
   llvm::DenseSet<uint64_t> LiveOffsets;