[llvm] r264103 - Drop comdats from the dst module if they are not selected.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 22 14:35:47 PDT 2016


Author: rafael
Date: Tue Mar 22 16:35:47 2016
New Revision: 264103

URL: http://llvm.org/viewvc/llvm-project?rev=264103&view=rev
Log:
Drop comdats from the dst module if they are not selected.

A really unfortunate design of llvm-link and related libraries is that
they operate one module at a time.

This means they can copy a GV to the destination module that should not
be there in the final result because a later bitcode file takes
precedence.

We already handled cases like a strong GV replacing a weak for example.

One case that is not currently handled is a comdat replacing another.
This doesn't happen in ELF, but with COFF largest selection kind it is
possible.

In "llvm-link a.ll b.ll" if the selected comdat was from a.ll,
everything will work and we will not copy the comdat from b.ll.

But if we run "llvm-link b.ll a.ll", we fail to delete the already
copied comdat from b.ll. This patch fixes that.

Added:
    llvm/trunk/test/Linker/Inputs/comdat-rm-dst.ll
    llvm/trunk/test/Linker/comdat-rm-dst.ll
Modified:
    llvm/trunk/lib/Linker/LinkModules.cpp

Modified: llvm/trunk/lib/Linker/LinkModules.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Linker/LinkModules.cpp?rev=264103&r1=264102&r2=264103&view=diff
==============================================================================
--- llvm/trunk/lib/Linker/LinkModules.cpp (original)
+++ llvm/trunk/lib/Linker/LinkModules.cpp Tue Mar 22 16:35:47 2016
@@ -102,6 +102,11 @@ class ModuleLinker {
     return DGV;
   }
 
+  /// Drop GV if it is a member of a comdat that we are dropping.
+  /// This can happen with COFF's largest selection kind.
+  void dropReplacedComdat(GlobalValue &GV,
+                          const DenseSet<const Comdat *> &ReplacedDstComdats);
+
   bool linkIfNeeded(GlobalValue &GV);
 
   /// Helper method to check if we are importing from the current source
@@ -449,7 +454,45 @@ void ModuleLinker::addLazyFor(GlobalValu
   }
 }
 
+void ModuleLinker::dropReplacedComdat(
+    GlobalValue &GV, const DenseSet<const Comdat *> &ReplacedDstComdats) {
+  Comdat *C = GV.getComdat();
+  if (!C)
+    return;
+  if (!ReplacedDstComdats.count(C))
+    return;
+  if (GV.use_empty()) {
+    GV.eraseFromParent();
+    return;
+  }
+
+  if (auto *F = dyn_cast<Function>(&GV)) {
+    F->deleteBody();
+  } else if (auto *Var = dyn_cast<GlobalVariable>(&GV)) {
+    Var->setInitializer(nullptr);
+  } else {
+    auto &Alias = cast<GlobalAlias>(GV);
+    Module &M = *Alias.getParent();
+    PointerType &Ty = *cast<PointerType>(Alias.getType());
+    GlobalValue *Declaration;
+    if (auto *FTy = dyn_cast<FunctionType>(Alias.getValueType())) {
+      Declaration = Function::Create(FTy, GlobalValue::ExternalLinkage, "", &M);
+    } else {
+      Declaration =
+          new GlobalVariable(M, Ty.getElementType(), /*isConstant*/ false,
+                             GlobalValue::ExternalLinkage,
+                             /*Initializer*/ nullptr);
+    }
+    Declaration->takeName(&Alias);
+    Alias.replaceAllUsesWith(Declaration);
+    Alias.eraseFromParent();
+  }
+}
+
 bool ModuleLinker::run() {
+  Module &DstM = Mover.getModule();
+  DenseSet<const Comdat *> ReplacedDstComdats;
+
   for (const auto &SMEC : SrcM->getComdatSymbolTable()) {
     const Comdat &C = SMEC.getValue();
     if (ComdatsChosen.count(&C))
@@ -459,6 +502,35 @@ bool ModuleLinker::run() {
     if (getComdatResult(&C, SK, LinkFromSrc))
       return true;
     ComdatsChosen[&C] = std::make_pair(SK, LinkFromSrc);
+
+    if (!LinkFromSrc)
+      continue;
+
+    Module::ComdatSymTabType &ComdatSymTab = DstM.getComdatSymbolTable();
+    Module::ComdatSymTabType::iterator DstCI = ComdatSymTab.find(C.getName());
+    if (DstCI == ComdatSymTab.end())
+      continue;
+
+    // The source comdat is replacing the dest one.
+    const Comdat *DstC = &DstCI->second;
+    ReplacedDstComdats.insert(DstC);
+  }
+
+  // Alias have to go first, since we are not able to find their comdats
+  // otherwise.
+  for (auto I = DstM.alias_begin(), E = DstM.alias_end(); I != E;) {
+    GlobalAlias &GV = *I++;
+    dropReplacedComdat(GV, ReplacedDstComdats);
+  }
+
+  for (auto I = DstM.global_begin(), E = DstM.global_end(); I != E;) {
+    GlobalVariable &GV = *I++;
+    dropReplacedComdat(GV, ReplacedDstComdats);
+  }
+
+  for (auto I = DstM.begin(), E = DstM.end(); I != E;) {
+    Function &GV = *I++;
+    dropReplacedComdat(GV, ReplacedDstComdats);
   }
 
   for (GlobalVariable &GV : SrcM->globals())
@@ -507,7 +579,6 @@ bool ModuleLinker::run() {
                  },
                  ValIDToTempMDMap, false))
     return true;
-  Module &DstM = Mover.getModule();
   for (auto &P : Internalize) {
     GlobalValue *GV = DstM.getNamedValue(P.first());
     GV->setLinkage(GlobalValue::InternalLinkage);

Added: llvm/trunk/test/Linker/Inputs/comdat-rm-dst.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Linker/Inputs/comdat-rm-dst.ll?rev=264103&view=auto
==============================================================================
--- llvm/trunk/test/Linker/Inputs/comdat-rm-dst.ll (added)
+++ llvm/trunk/test/Linker/Inputs/comdat-rm-dst.ll Tue Mar 22 16:35:47 2016
@@ -0,0 +1,5 @@
+target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
+target triple = "i686-pc-windows-msvc"
+
+$foo = comdat largest
+ at foo = global i64 43, comdat

Added: llvm/trunk/test/Linker/comdat-rm-dst.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Linker/comdat-rm-dst.ll?rev=264103&view=auto
==============================================================================
--- llvm/trunk/test/Linker/comdat-rm-dst.ll (added)
+++ llvm/trunk/test/Linker/comdat-rm-dst.ll Tue Mar 22 16:35:47 2016
@@ -0,0 +1,33 @@
+; RUN: llvm-link -S -o %t %s %p/Inputs/comdat-rm-dst.ll
+; RUN: FileCheck %s < %t
+; RUN: FileCheck --check-prefix=RM %s < %t
+
+target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
+target triple = "i686-pc-windows-msvc"
+
+$foo = comdat largest
+ at foo = global i32 42, comdat
+; CHECK-DAG: @foo = global i64 43, comdat
+
+; RM-NOT: @alias =
+ at alias = alias i32, i32* @foo
+
+; We should arguably reject an out of comdat reference to int_alias. Given that
+; the verifier accepts it, test that we at least produce an output that passes
+; the verifier.
+; CHECK-DAG: @int_alias = external global i32
+ at int_alias = internal alias i32, i32* @foo
+ at bar = global i32* @int_alias
+
+ at func_alias = alias void (), void ()* @func
+ at zed = global void()* @func_alias
+; CHECK-DAG: @zed = global void ()* @func_alias
+; CHECK-DAG: declare void @func_alias()
+
+; RM-NOT: @func()
+define void @func() comdat($foo) {
+  ret void
+}
+
+; RM-NOT: var
+ at var = global i32 42, comdat($foo)




More information about the llvm-commits mailing list