Inliner: Non-local functions in COMDATs shouldn't be dropped
authorDavid Majnemer <david.majnemer@gmail.com>
Wed, 8 Oct 2014 19:32:32 +0000 (19:32 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Wed, 8 Oct 2014 19:32:32 +0000 (19:32 +0000)
A function with discardable linkage cannot be discarded if its a member
of a COMDAT group without considering all the other COMDAT members as
well.  This sort of thing is already handled by GlobalOpt/GlobalDCE.

This fixes PR21206.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219335 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/IPO/Inliner.cpp
test/Transforms/Inline/pr21206.ll [new file with mode: 0644]

index de9795047423d2b75142bbda81ef8345ce93cb9d..4ce6dfed7c421ee42940650d5117a1576cd5f5b2 100644 (file)
@@ -669,6 +669,13 @@ bool Inliner::removeDeadFunctions(CallGraph &CG, bool AlwaysInlineOnly) {
 
     if (!F->isDefTriviallyDead())
       continue;
+
+    // It is unsafe to drop a function with discardable linkage from a COMDAT
+    // without also dropping the other members of the COMDAT.
+    // The inliner doesn't visit non-function entities which are in COMDAT
+    // groups so it is unsafe to do so *unless* the linkage is local.
+    if (!F->hasLocalLinkage() && F->hasComdat())
+      continue;
     
     // Remove any call graph edges from the function to its callees.
     CGN->removeAllCalledFunctions();
diff --git a/test/Transforms/Inline/pr21206.ll b/test/Transforms/Inline/pr21206.ll
new file mode 100644 (file)
index 0000000..1a4366e
--- /dev/null
@@ -0,0 +1,18 @@
+; RUN: opt < %s -inline -S | FileCheck %s
+
+$c = comdat any
+; CHECK: $c = comdat any
+
+define linkonce_odr void @foo() comdat $c {
+  ret void
+}
+; CHECK: define linkonce_odr void @foo() comdat $c
+
+define linkonce_odr void @bar() comdat $c {
+  ret void
+}
+; CHECK: define linkonce_odr void @bar() comdat $c
+
+define void()* @zed()  {
+  ret void()* @foo
+}