[llvm] r243883 - Linker: Move distinct MDNodes instead of cloning

Duncan P. N. Exon Smith dexonsmith at apple.com
Mon Aug 3 10:09:39 PDT 2015


Author: dexonsmith
Date: Mon Aug  3 12:09:38 2015
New Revision: 243883

URL: http://llvm.org/viewvc/llvm-project?rev=243883&view=rev
Log:
Linker: Move distinct MDNodes instead of cloning

Instead of cloning distinct `MDNode`s when linking in a module, just
move them over.  The module linker destroys the source module, so the
old node would otherwise just be leaked on the context.  Create the new
node in place.  This also reduces the number of cloned uniqued nodes
(since it's less likely their operands have changed).

This mapping strategy is only correct when we're discarding the source,
so the linker turns it on via a ValueMapper flag, `RF_MoveDistinctMDs`.

There's nothing observable in terms of `llvm-link` output here: the
linked module should be semantically identical.

I'll be adding more 'distinct' nodes to the debug info metadata graph in
order to break uniquing cycles, so the benefits of this will partly come
in future commits.  However, we should get some gains immediately, since
we have a fair number of 'distinct' `DILocation`s being linked in.

Modified:
    llvm/trunk/include/llvm/Transforms/Utils/ValueMapper.h
    llvm/trunk/lib/Linker/LinkModules.cpp
    llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp
    llvm/trunk/unittests/Linker/LinkModulesTest.cpp
    llvm/trunk/unittests/Transforms/Utils/ValueMapperTest.cpp

Modified: llvm/trunk/include/llvm/Transforms/Utils/ValueMapper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/ValueMapper.h?rev=243883&r1=243882&r2=243883&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Utils/ValueMapper.h (original)
+++ llvm/trunk/include/llvm/Transforms/Utils/ValueMapper.h Mon Aug  3 12:09:38 2015
@@ -59,7 +59,11 @@ namespace llvm {
     /// RF_IgnoreMissingEntries - If this flag is set, the remapper ignores
     /// entries that are not in the value map.  If it is unset, it aborts if an
     /// operand is asked to be remapped which doesn't exist in the mapping.
-    RF_IgnoreMissingEntries = 2
+    RF_IgnoreMissingEntries = 2,
+
+    /// Instruct the remapper to move distinct metadata instead of duplicating
+    /// it when there are module-level changes.
+    RF_MoveDistinctMDs = 4,
   };
 
   static inline RemapFlags operator|(RemapFlags LHS, RemapFlags RHS) {

Modified: llvm/trunk/lib/Linker/LinkModules.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Linker/LinkModules.cpp?rev=243883&r1=243882&r2=243883&view=diff
==============================================================================
--- llvm/trunk/lib/Linker/LinkModules.cpp (original)
+++ llvm/trunk/lib/Linker/LinkModules.cpp Mon Aug  3 12:09:38 2015
@@ -1156,7 +1156,7 @@ void ModuleLinker::linkAppendingVarInit(
         continue;
     }
     DstElements.push_back(
-        MapValue(V, ValueMap, RF_None, &TypeMap, &ValMaterializer));
+        MapValue(V, ValueMap, RF_MoveDistinctMDs, &TypeMap, &ValMaterializer));
   }
   if (IsNewStructor) {
     NewType = ArrayType::get(NewType->getElementType(), DstElements.size());
@@ -1170,8 +1170,8 @@ void ModuleLinker::linkAppendingVarInit(
 /// referenced are in Dest.
 void ModuleLinker::linkGlobalInit(GlobalVariable &Dst, GlobalVariable &Src) {
   // Figure out what the initializer looks like in the dest module.
-  Dst.setInitializer(MapValue(Src.getInitializer(), ValueMap, RF_None, &TypeMap,
-                              &ValMaterializer));
+  Dst.setInitializer(MapValue(Src.getInitializer(), ValueMap,
+                              RF_MoveDistinctMDs, &TypeMap, &ValMaterializer));
 }
 
 /// Copy the source function over into the dest function and fix up references
@@ -1186,18 +1186,20 @@ bool ModuleLinker::linkFunctionBody(Func
 
   // Link in the prefix data.
   if (Src.hasPrefixData())
-    Dst.setPrefixData(MapValue(Src.getPrefixData(), ValueMap, RF_None, &TypeMap,
-                               &ValMaterializer));
+    Dst.setPrefixData(MapValue(Src.getPrefixData(), ValueMap,
+                               RF_MoveDistinctMDs, &TypeMap, &ValMaterializer));
 
   // Link in the prologue data.
   if (Src.hasPrologueData())
-    Dst.setPrologueData(MapValue(Src.getPrologueData(), ValueMap, RF_None,
-                                 &TypeMap, &ValMaterializer));
+    Dst.setPrologueData(MapValue(Src.getPrologueData(), ValueMap,
+                                 RF_MoveDistinctMDs, &TypeMap,
+                                 &ValMaterializer));
 
   // Link in the personality function.
   if (Src.hasPersonalityFn())
-    Dst.setPersonalityFn(MapValue(Src.getPersonalityFn(), ValueMap, RF_None,
-                                  &TypeMap, &ValMaterializer));
+    Dst.setPersonalityFn(MapValue(Src.getPersonalityFn(), ValueMap,
+                                  RF_MoveDistinctMDs, &TypeMap,
+                                  &ValMaterializer));
 
   // Go through and convert function arguments over, remembering the mapping.
   Function::arg_iterator DI = Dst.arg_begin();
@@ -1213,8 +1215,8 @@ bool ModuleLinker::linkFunctionBody(Func
   SmallVector<std::pair<unsigned, MDNode *>, 8> MDs;
   Src.getAllMetadata(MDs);
   for (const auto &I : MDs)
-    Dst.setMetadata(I.first, MapMetadata(I.second, ValueMap, RF_None, &TypeMap,
-                                         &ValMaterializer));
+    Dst.setMetadata(I.first, MapMetadata(I.second, ValueMap, RF_MoveDistinctMDs,
+                                         &TypeMap, &ValMaterializer));
 
   // Splice the body of the source function into the dest function.
   Dst.getBasicBlockList().splice(Dst.end(), Src.getBasicBlockList());
@@ -1225,7 +1227,8 @@ bool ModuleLinker::linkFunctionBody(Func
   // functions and patch them up to point to the local versions.
   for (BasicBlock &BB : Dst)
     for (Instruction &I : BB)
-      RemapInstruction(&I, ValueMap, RF_IgnoreMissingEntries, &TypeMap,
+      RemapInstruction(&I, ValueMap,
+                       RF_IgnoreMissingEntries | RF_MoveDistinctMDs, &TypeMap,
                        &ValMaterializer);
 
   // There is no need to map the arguments anymore.
@@ -1238,8 +1241,8 @@ bool ModuleLinker::linkFunctionBody(Func
 
 void ModuleLinker::linkAliasBody(GlobalAlias &Dst, GlobalAlias &Src) {
   Constant *Aliasee = Src.getAliasee();
-  Constant *Val =
-      MapValue(Aliasee, ValueMap, RF_None, &TypeMap, &ValMaterializer);
+  Constant *Val = MapValue(Aliasee, ValueMap, RF_MoveDistinctMDs, &TypeMap,
+                           &ValMaterializer);
   Dst.setAliasee(Val);
 }
 
@@ -1266,8 +1269,8 @@ void ModuleLinker::linkNamedMDNodes() {
     NamedMDNode *DestNMD = DstM->getOrInsertNamedMetadata(NMD.getName());
     // Add Src elements into Dest node.
     for (const MDNode *op : NMD.operands())
-      DestNMD->addOperand(
-          MapMetadata(op, ValueMap, RF_None, &TypeMap, &ValMaterializer));
+      DestNMD->addOperand(MapMetadata(op, ValueMap, RF_MoveDistinctMDs,
+                                      &TypeMap, &ValMaterializer));
   }
 }
 
@@ -1574,7 +1577,7 @@ bool ModuleLinker::run() {
       continue;
     const GlobalValue *GV = SrcM->getNamedValue(C.getName());
     if (GV)
-      MapValue(GV, ValueMap, RF_None, &TypeMap, &ValMaterializer);
+      MapValue(GV, ValueMap, RF_MoveDistinctMDs, &TypeMap, &ValMaterializer);
   }
 
   // Strip replaced subprograms before mapping any metadata -- so that we're

Modified: llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp?rev=243883&r1=243882&r2=243883&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp Mon Aug  3 12:09:38 2015
@@ -216,9 +216,12 @@ static bool remap(const MDNode *OldNode,
   return AnyChanged;
 }
 
-/// \brief Map a distinct MDNode.
+/// Map a distinct MDNode.
 ///
-/// Distinct nodes are not uniqued, so they must always recreated.
+/// Whether distinct nodes change is independent of their operands.  If \a
+/// RF_MoveDistinctMDs, then they are reused, and their operands remapped in
+/// place; effectively, they're moved from one graph to another.  Otherwise,
+/// they're cloned/duplicated, and the new copy's operands are remapped.
 static Metadata *mapDistinctNode(const MDNode *Node,
                                  SmallVectorImpl<MDNode *> &Cycles,
                                  ValueToValueMapTy &VM, RemapFlags Flags,
@@ -226,7 +229,11 @@ static Metadata *mapDistinctNode(const M
                                  ValueMaterializer *Materializer) {
   assert(Node->isDistinct() && "Expected distinct node");
 
-  MDNode *NewMD = MDNode::replaceWithDistinct(Node->clone());
+  MDNode *NewMD;
+  if (Flags & RF_MoveDistinctMDs)
+    NewMD = const_cast<MDNode *>(Node);
+  else
+    NewMD = MDNode::replaceWithDistinct(Node->clone());
 
   // Remap the operands.  If any change, track those that could be involved in
   // uniquing cycles.
@@ -318,20 +325,21 @@ Metadata *llvm::MapMetadata(const Metada
   Metadata *NewMD =
       MapMetadataImpl(MD, Cycles, VM, Flags, TypeMapper, Materializer);
 
-  // Resolve cycles underneath MD.
-  if (NewMD && NewMD != MD) {
-    if (auto *N = dyn_cast<MDNode>(NewMD))
-      if (!N->isResolved())
-        N->resolveCycles();
-
-    for (MDNode *N : Cycles)
-      if (!N->isResolved())
-        N->resolveCycles();
-  } else {
-    // Shouldn't get unresolved cycles if nothing was remapped.
-    assert(Cycles.empty() && "Expected no unresolved cycles");
+  if ((Flags & RF_NoModuleLevelChanges) ||
+      (MD == NewMD && !(Flags & RF_MoveDistinctMDs))) {
+    assert(Cycles.empty() && "Unresolved cycles without remapping anything?");
+    return NewMD;
   }
 
+  if (auto *N = dyn_cast<MDNode>(NewMD))
+    if (!N->isResolved())
+      N->resolveCycles();
+
+  // Resolve cycles underneath MD.
+  for (MDNode *N : Cycles)
+    if (!N->isResolved())
+      N->resolveCycles();
+
   return NewMD;
 }
 

Modified: llvm/trunk/unittests/Linker/LinkModulesTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Linker/LinkModulesTest.cpp?rev=243883&r1=243882&r2=243883&view=diff
==============================================================================
--- llvm/trunk/unittests/Linker/LinkModulesTest.cpp (original)
+++ llvm/trunk/unittests/Linker/LinkModulesTest.cpp Mon Aug  3 12:09:38 2015
@@ -7,6 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/DataLayout.h"
@@ -219,4 +220,77 @@ TEST_F(LinkModuleTest, CAPIFailure) {
   LLVMDisposeMessage(errout);
 }
 
+TEST_F(LinkModuleTest, MoveDistinctMDs) {
+  LLVMContext C;
+  SMDiagnostic Err;
+
+  const char *SrcStr = "define void @foo() !attach !0 {\n"
+                       "entry:\n"
+                       "  call void @llvm.md(metadata !1)\n"
+                       "  ret void, !attach !2\n"
+                       "}\n"
+                       "declare void @llvm.md(metadata)\n"
+                       "!named = !{!3, !4}\n"
+                       "!0 = distinct !{}\n"
+                       "!1 = distinct !{}\n"
+                       "!2 = distinct !{}\n"
+                       "!3 = distinct !{}\n"
+                       "!4 = !{!3}\n";
+
+  std::unique_ptr<Module> Src = parseAssemblyString(SrcStr, Err, C);
+  assert(Src);
+  ASSERT_TRUE(Src.get());
+
+  // Get the addresses of the Metadata before merging.
+  Function *F = &*Src->begin();
+  ASSERT_EQ("foo", F->getName());
+  BasicBlock *BB = &F->getEntryBlock();
+  auto *CI = cast<CallInst>(&BB->front());
+  auto *RI = cast<ReturnInst>(BB->getTerminator());
+  NamedMDNode *NMD = &*Src->named_metadata_begin();
+
+  MDNode *M0 = F->getMetadata("attach");
+  MDNode *M1 =
+      cast<MDNode>(cast<MetadataAsValue>(CI->getArgOperand(0))->getMetadata());
+  MDNode *M2 = RI->getMetadata("attach");
+  MDNode *M3 = NMD->getOperand(0);
+  MDNode *M4 = NMD->getOperand(1);
+
+  // Confirm a few things about the IR.
+  EXPECT_TRUE(M0->isDistinct());
+  EXPECT_TRUE(M1->isDistinct());
+  EXPECT_TRUE(M2->isDistinct());
+  EXPECT_TRUE(M3->isDistinct());
+  EXPECT_TRUE(M4->isUniqued());
+  EXPECT_EQ(M3, M4->getOperand(0));
+
+  // Link into destination module.
+  auto Dst = llvm::make_unique<Module>("Linked", C);
+  ASSERT_TRUE(Dst.get());
+  Linker::LinkModules(Dst.get(), Src.get(),
+                      [](const llvm::DiagnosticInfo &) {});
+
+  // Check that distinct metadata was moved, not cloned.  Even !4, the uniqued
+  // node, should effectively be moved, since its only operand hasn't changed.
+  F = &*Dst->begin();
+  BB = &F->getEntryBlock();
+  CI = cast<CallInst>(&BB->front());
+  RI = cast<ReturnInst>(BB->getTerminator());
+  NMD = &*Dst->named_metadata_begin();
+
+  EXPECT_EQ(M0, F->getMetadata("attach"));
+  EXPECT_EQ(M1, cast<MetadataAsValue>(CI->getArgOperand(0))->getMetadata());
+  EXPECT_EQ(M2, RI->getMetadata("attach"));
+  EXPECT_EQ(M3, NMD->getOperand(0));
+  EXPECT_EQ(M4, NMD->getOperand(1));
+
+  // Confirm a few things about the IR.  This shouldn't have changed.
+  EXPECT_TRUE(M0->isDistinct());
+  EXPECT_TRUE(M1->isDistinct());
+  EXPECT_TRUE(M2->isDistinct());
+  EXPECT_TRUE(M3->isDistinct());
+  EXPECT_TRUE(M4->isUniqued());
+  EXPECT_EQ(M3, M4->getOperand(0));
+}
+
 } // end anonymous namespace

Modified: llvm/trunk/unittests/Transforms/Utils/ValueMapperTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Transforms/Utils/ValueMapperTest.cpp?rev=243883&r1=243882&r2=243883&view=diff
==============================================================================
--- llvm/trunk/unittests/Transforms/Utils/ValueMapperTest.cpp (original)
+++ llvm/trunk/unittests/Transforms/Utils/ValueMapperTest.cpp Mon Aug  3 12:09:38 2015
@@ -24,4 +24,35 @@ TEST(ValueMapperTest, MapMetadataUnresol
   EXPECT_EQ(T.get(), MapMetadata(T.get(), VM, RF_NoModuleLevelChanges));
 }
 
+TEST(ValueMapperTest, MapMetadataDistinct) {
+  LLVMContext Context;
+  auto *D = MDTuple::getDistinct(Context, None);
+
+  {
+    // The node should be cloned.
+    ValueToValueMapTy VM;
+    EXPECT_NE(D, MapMetadata(D, VM, RF_None));
+  }
+  {
+    // The node should be moved.
+    ValueToValueMapTy VM;
+    EXPECT_EQ(D, MapMetadata(D, VM, RF_MoveDistinctMDs));
+  }
+}
+
+TEST(ValueMapperTest, MapMetadataDistinctOperands) {
+  LLVMContext Context;
+  Metadata *Old = MDTuple::getDistinct(Context, None);
+  auto *D = MDTuple::getDistinct(Context, Old);
+  ASSERT_EQ(Old, D->getOperand(0));
+
+  Metadata *New = MDTuple::getDistinct(Context, None);
+  ValueToValueMapTy VM;
+  VM.MD()[Old].reset(New);
+
+  // Make sure operands are updated.
+  EXPECT_EQ(D, MapMetadata(D, VM, RF_MoveDistinctMDs));
+  EXPECT_EQ(New, D->getOperand(0));
+}
+
 }





More information about the llvm-commits mailing list