Make dead-striping to handle reverse edges.
authorRui Ueyama <ruiu@google.com>
Tue, 3 Jun 2014 01:59:02 +0000 (01:59 +0000)
committerRui Ueyama <ruiu@google.com>
Tue, 3 Jun 2014 01:59:02 +0000 (01:59 +0000)
Layout-before edges are no longer used for layout, but they are
still there for dead-stripping. If we would just remove them
from code, LLD would wrongly remove live atoms that were
referenced by layout-befores.

This patch fixes the issue. Before dead-stripping, it scans all
atoms to construct a reverse map for layout-after edges. Dead-
stripping pass uses the map to traverse the graph.

Differential Revision: http://reviews.llvm.org/D3986

llvm-svn: 210057

lld/include/lld/Core/Reference.h
lld/include/lld/Core/Resolver.h
lld/lib/Core/Resolver.cpp
lld/test/core/dead-strip-reverse.objtxt [new file with mode: 0644]

index c525249..5283197 100644 (file)
@@ -36,6 +36,12 @@ class Atom;
 /// means R_X86_64_32 for x86_64, and R_386_GOTPC for i386. For PE/COFF
 /// relocation 10 means IMAGE_REL_AMD64_SECTION.
 ///
+/// References and atoms form a directed graph. The dead-stripping pass
+/// traverses them starting from dead-strip root atoms to garbage collect
+/// unreachable ones.
+///
+/// References of any kind are considered as directed edges. In addition to
+/// that, references of some kind is considered as bidirected edges.
 class Reference {
 public:
   /// Which universe defines the kindValue().
@@ -77,10 +83,11 @@ public:
   /// KindValues used with KindNamespace::all and KindArch::all.
   enum {
     kindInGroup = 1,
+    // kindLayoutAfter is treated as a bidirected edge by the dead-stripping
+    // pass.
     kindLayoutAfter = 2,
-    // kindLayoutBefore is currently used only by dead-stripping pass in
-    // the Resolver. Will be removed soon. To enforce layout, use
-    // kindLayoutAfter instead.
+    // kindLayoutBefore is currently used only by PECOFF port, and will
+    // be removed soon. To enforce layout, use kindLayoutAfter instead.
     kindLayoutBefore = 3,
     kindGroupChild = 4,
     kindGroupParent = 5
index 0bb1223..3d8fe9c 100644 (file)
@@ -14,6 +14,7 @@
 #include "lld/Core/SharedLibraryFile.h"
 #include "lld/Core/SymbolTable.h"
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 
 #include <set>
@@ -105,6 +106,7 @@ private:
   std::set<const Atom *>        _deadStripRoots;
   llvm::DenseSet<const Atom *>  _liveAtoms;
   std::unique_ptr<MergedFile>   _result;
+  llvm::DenseMap<const Atom *, llvm::DenseSet<const Atom *>> _reverseRef;
 };
 
 } // namespace lld
index bf4b484..b73d80a 100644 (file)
@@ -312,9 +312,17 @@ void Resolver::markLive(const Atom *atom) {
     return;
 
   // Mark all atoms it references as live
-  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
+  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
     for (const Reference *ref : *defAtom)
       markLive(ref->target());
+    for (const Atom *target : _reverseRef[defAtom])
+      markLive(target);
+  }
+}
+
+static bool isBackref(const Reference *ref) {
+  return ref->kindNamespace() == lld::Reference::KindNamespace::all &&
+    ref->kindValue() == lld::Reference::kindLayoutBefore;
 }
 
 // remove all atoms not actually used
@@ -323,7 +331,14 @@ void Resolver::deadStripOptimize() {
   // only do this optimization with -dead_strip
   if (!_context.deadStrip())
     return;
-  assert(_liveAtoms.empty());
+
+  // Some type of references prevent referring atoms to be dead-striped.
+  // Make a reverse map of such references before traversing the graph.
+  for (const Atom *atom : _atoms)
+    if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
+      for (const Reference *ref : *defAtom)
+        if (isBackref(ref))
+          _reverseRef[ref->target()].insert(atom);
 
   // By default, shared libraries are built with all globals as dead strip roots
   if (_context.globalsAreDeadStripRoots())
diff --git a/lld/test/core/dead-strip-reverse.objtxt b/lld/test/core/dead-strip-reverse.objtxt
new file mode 100644 (file)
index 0000000..f471beb
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: lld -core --dead-strip %s | FileCheck -check-prefix=CHECK1 %s
+# RUN: lld -core %s | FileCheck -check-prefix=CHECK2 %s
+
+---
+defined-atoms:
+  - name:            entry
+    dead-strip:      never
+    scope:           global
+    references:
+      - kind:            layout-after
+        offset:          0
+        target:          def
+  - name:            def
+    scope:           global
+  - name:            dead
+    scope:           global
+...
+
+# CHECK1:       name: entry
+# CHECK1:       name: def
+# CHECK1-NOT:   name: dead
+
+# CHECK2:       name: entry
+# CHECK2:       name: def
+# CHECK2:       name: dead