[llvm] r266537 - ValueMapper: Separate mapping of distinct and uniqued nodes (again)

Duncan P. N. Exon Smith via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 16 14:44:08 PDT 2016


Author: dexonsmith
Date: Sat Apr 16 16:44:08 2016
New Revision: 266537

URL: http://llvm.org/viewvc/llvm-project?rev=266537&view=rev
Log:
ValueMapper: Separate mapping of distinct and uniqued nodes (again)

Since the result of a mapped distinct node is known up front, it's more
efficient to map them separately from uniqued nodes.  This commit pulls
them out of the post-order traversal and stores them in a worklist to be
remapped at the top-level.

This is essentially reapplying r244181 ("ValueMapper: Rotate distinct
node remapping algorithm") to the new iterative algorithm from r265456
("ValueMapper: Rewrite Mapper::mapMetadata without recursion").

Now that the traversal logic only handles uniqued MDNodes, it's much
simpler to inline it all into MDNodeMapper::createPOT (I've killed the
MDNodeMapper::push and MDNodeMapper::tryToPop helpers and localized the
traversal worklist).

The resulting high-level algorithm for MDNodeMapper::map now looks like
this:

  - Distinct nodes are immediately mapped and added to
    MDNodeMapper::DistinctWorklist using MDNodeMapper::mapDistinctNode.

  - Uniqued nodes are mapped via MDNodeMapper::mapTopLevelUniquedNode,
    which traverses the transitive uniqued subgraph of a node to
    calculate uniqued node mappings in bulk.

      - This is a simplified version of MDNodeMapper::map from before
        this commit (originally r265456) that doesn't traverse through
        any distinct nodes.

      - Distinct nodes are added to MDNodeMapper::DistinctWorklist via
        MDNodeMapper::mapDistinctNode.

      - This uses MDNodeMapper::createPOT to fill a
        MDNodeMapper::UniquedGraph (a post-order traversal and side
        table), UniquedGraph::propagateChanges to track which uniqued
        nodes need to change, and MDNodeMapper::mapNodesInPOT to create
        the uniqued nodes.

      - Placeholders for forward references are now only needed when
        there's a uniquing cycle (a cycle of uniqued nodes unbroken by
        distinct nodes).  This is the key functionality change that
        we're reintroducing (from r244181).  As of r265456, a temporary
        forward reference might be needed for any cycle that involved
        uniqued nodes.

  - After mapping the first node appropriately, MDNodeMapper::map works
    through MDNodeMapper::DistinctWorklist.  For each distinct node, its
    operands are remapped with MDNodeMapper::mapDistinctNode and
    MDNodeMapper::mapTopLevelUniquedNode until all nodes have been
    mapped.

Sadly there's nothing observable I can test here; no real functionality
change, just a compile-time speedup from reduced malloc traffic.

Modified:
    llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp

Modified: llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp?rev=266537&r1=266536&r2=266537&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/ValueMapper.cpp Sat Apr 16 16:44:08 2016
@@ -189,149 +189,149 @@ private:
 class MDNodeMapper {
   Mapper &M;
 
+  /// Data about a node in \a UniquedGraph.
   struct Data {
-    bool HasChangedOps = false;
-    bool HasChangedAddress = false;
+    bool HasChanged = false;
     unsigned ID = ~0u;
     TempMDNode Placeholder;
 
     Data() {}
     Data(Data &&X)
-        : HasChangedOps(std::move(X.HasChangedOps)),
-          HasChangedAddress(std::move(X.HasChangedAddress)),
-          ID(std::move(X.ID)), Placeholder(std::move(X.Placeholder)) {}
+        : HasChanged(std::move(X.HasChanged)), ID(std::move(X.ID)),
+          Placeholder(std::move(X.Placeholder)) {}
     Data &operator=(Data &&X) {
-      HasChangedOps = std::move(X.HasChangedOps);
-      HasChangedAddress = std::move(X.HasChangedAddress);
+      HasChanged = std::move(X.HasChanged);
       ID = std::move(X.ID);
       Placeholder = std::move(X.Placeholder);
       return *this;
     }
   };
 
-  SmallDenseMap<const Metadata *, Data, 32> Info;
-  SmallVector<std::pair<MDNode *, bool>, 16> Worklist;
-  SmallVector<MDNode *, 16> POT;
+  /// A graph of uniqued nodes.
+  struct UniquedGraph {
+    SmallDenseMap<const Metadata *, Data, 32> Info; // Node properties.
+    SmallVector<MDNode *, 16> POT;                  // Post-order traversal.
+
+    /// Propagate changed operands through the post-order traversal.
+    ///
+    /// Iteratively update \a Data::HasChanged for each node based on \a
+    /// Data::HasChanged of its operands, until fixed point.
+    void propagateChanges();
+
+    /// Get a forward reference to a node to use as an operand.
+    Metadata &getFwdReference(MDNode &Op);
+  };
+
+  /// Worklist of distinct nodes whose operands need to be remapped.
+  SmallVector<MDNode *, 16> DistinctWorklist;
+
+  // Storage for a UniquedGraph.
+  SmallDenseMap<const Metadata *, Data, 32> InfoStorage;
+  SmallVector<MDNode *, 16> POTStorage;
 
 public:
   MDNodeMapper(Mapper &M) : M(M) {}
 
   /// Map a metadata node (and its transitive operands).
   ///
-  /// This is the only entry point into MDNodeMapper.  It works as follows:
+  /// Map all the (unmapped) nodes in the subgraph under \c N.  The iterative
+  /// algorithm handles distinct nodes and uniqued node subgraphs using
+  /// different strategies.
+  ///
+  /// Distinct nodes are immediately mapped and added to \a DistinctWorklist
+  /// using \a mapDistinctNode().  Their mapping can always be computed
+  /// immediately without visiting operands, even if their operands change.
+  ///
+  /// The mapping for uniqued nodes depends on whether their operands change.
+  /// \a mapTopLevelUniquedNode() traverses the transitive uniqued subgraph of
+  /// a node to calculate uniqued node mappings in bulk.  Distinct leafs are
+  /// added to \a DistinctWorklist with \a mapDistinctNode().
+  ///
+  /// After mapping \c N itself, this function remaps the operands of the
+  /// distinct nodes in \a DistinctWorklist until the entire subgraph under \c
+  /// N has been mapped.
+  Metadata *map(const MDNode &N);
+
+private:
+  /// Map a top-level uniqued node and the uniqued subgraph underneath it.
   ///
-  ///  1. \a createPOT(): use a worklist to perform a post-order traversal of
-  ///     the transitively referenced unmapped nodes.
+  /// This builds up a post-order traversal of the (unmapped) uniqued subgraph
+  /// underneath \c FirstN and calculates the nodes' mapping.  Each node uses
+  /// the identity mapping (\a Mapper::mapToSelf()) as long as all of its
+  /// operands uses the identity mapping.
   ///
-  ///  2. \a propagateChangedOperands(): track which nodes will change
-  ///     operands, and which will have new addresses in the mapped scheme.
-  ///     Propagate the changes through the POT until fixed point, to pick up
-  ///     uniquing cycles that need to change.
+  /// The algorithm works as follows:
   ///
-  ///  3. \a mapDistinctNodes(): map all the distinct nodes without touching
-  ///     their operands.  If RF_MoveDistinctMetadata, they get mapped to
-  ///     themselves; otherwise, they get mapped to clones.
+  ///  1. \a createPOT(): traverse the uniqued subgraph under \c FirstN and
+  ///     save the post-order traversal in the given \a UniquedGraph, tracking
+  ///     nodes' operands change.
   ///
-  ///  4. \a mapUniquedNodes(): map the uniqued nodes (bottom-up), lazily
-  ///     creating temporaries for forward references as needed.
+  ///  2. \a UniquedGraph::propagateChanges(): propagate changed operands
+  ///     through the \a UniquedGraph until fixed point, following the rule
+  ///     that if a node changes, any node that references must also change.
   ///
-  ///  5. \a remapDistinctOperands(): remap the operands of the distinct nodes.
-  Metadata *map(const MDNode &FirstN);
-
-private:
-  /// Return \c true as long as there's work to do.
-  bool hasWork() const { return !Worklist.empty(); }
+  ///  3. \a mapNodesInPOT(): map the uniqued nodes, creating new uniqued nodes
+  ///     (referencing new operands) where necessary.
+  Metadata *mapTopLevelUniquedNode(const MDNode &FirstN);
 
-  /// Get the current node in the worklist.
-  MDNode &getCurrentNode() const { return *Worklist.back().first; }
-
-  /// Push a node onto the worklist.
-  ///
-  /// Adds \c N to \a Worklist and \a Info, unless it's already inserted.  If
-  /// \c N.isDistinct(), \a Data::HasChangedAddress will be set based on \a
-  /// RF_MoveDistinctMDs.
+  /// Try to map the operand of an \a MDNode.
   ///
-  /// Returns the data for the node.
+  /// If \c Op is already mapped, return the mapping.  If it's not an \a
+  /// MDNode, compute and return the mapping.  If it's a distinct \a MDNode,
+  /// return the result of \a mapDistinctNode().
   ///
-  /// \post Data::HasChangedAddress iff !RF_MoveDistinctMDs && N.isDistinct().
-  /// \post Worklist.back().first == &N.
-  /// \post Worklist.back().second == false.
-  Data &push(const MDNode &N);
+  /// \return None if \c Op is an unmapped uniqued \a MDNode.
+  /// \post getMappedOp(Op) only returns None if this returns None.
+  Optional<Metadata *> tryToMapOperand(const Metadata *Op);
 
-  /// Map a node operand, and return true if it changes.
+  /// Map a distinct node.
   ///
-  /// \post getMappedOp(Op) does not return None.
-  bool mapOperand(const Metadata *Op);
+  /// Return the mapping for the distinct node \c N, saving the result in \a
+  /// DistinctWorklist for later remapping.
+  ///
+  /// \pre \c N is not yet mapped.
+  /// \pre \c N.isDistinct().
+  MDNode *mapDistinctNode(const MDNode &N);
 
   /// Get a previously mapped node.
   Optional<Metadata *> getMappedOp(const Metadata *Op) const;
 
-  /// Try to pop a node off the worklist and store it in POT.
-  ///
-  /// Returns \c true if it popped; \c false if its operands need to be
-  /// visited.
-  ///
-  /// \post If Worklist.back().second == false: Worklist.back().second == true.
-  /// \post Else: Worklist.back() has been popped off and added to \a POT.
-  bool tryToPop();
-
-  /// Get a forward reference to a node to use as an operand.
-  ///
-  /// Returns \c Op if it's not changing; otherwise, lazily creates a temporary
-  /// node and returns it.
-  Metadata &getFwdReference(const Data &D, MDNode &Op);
-
-  /// Create a post-order traversal from the given node.
+  /// Create a post-order traversal of an unmapped uniqued node subgraph.
   ///
   /// This traverses the metadata graph deeply enough to map \c FirstN.  It
-  /// uses \a mapOperand() (indirectly, \a Mapper::mapSimplifiedNode()), so any
+  /// uses \a tryToMapOperand() (via \a Mapper::mapSimplifiedNode()), so any
   /// metadata that has already been mapped will not be part of the POT.
   ///
-  /// \post \a POT is a post-order traversal ending with \c FirstN.
-  bool createPOT(const MDNode &FirstN);
+  /// Each node that has a changed operand from outside the graph (e.g., a
+  /// distinct node, an already-mapped uniqued node, or \a ConstantAsMetadata)
+  /// is marked with \a Data::HasChanged.
+  ///
+  /// \return \c true if any nodes in \c G have \a Data::HasChanged.
+  /// \post \c G.POT is a post-order traversal ending with \c FirstN.
+  /// \post \a Data::hasChanged in \c G.Info indicates whether any node needs
+  /// to change because of operands outside the graph.
+  bool createPOT(UniquedGraph &G, const MDNode &FirstN);
+
+  /// Map all the nodes in the given uniqued graph.
+  ///
+  /// This visits all the nodes in \c G in post-order, using the identity
+  /// mapping or creating a new node depending on \a Data::HasChanged.
+  ///
+  /// \pre \a getMappedOp() returns None for nodes in \c G, but not for any of
+  /// their operands outside of \c G.
+  /// \pre \a Data::HasChanged is true for a node in \c G iff any of its
+  /// operands have changed.
+  /// \post \a getMappedOp() returns the mapped node for every node in \c G.
+  void mapNodesInPOT(UniquedGraph &G);
 
-  /// Propagate changed operands through post-order traversal.
+  /// Remap a node's operands using the given functor.
   ///
-  /// Until fixed point, iteratively update:
-  ///
-  ///   - \a Data::HasChangedOps based on \a Data::HasChangedAddress of operands;
-  ///   - \a Data::HasChangedAddress based on Data::HasChangedOps.
-  ///
-  /// This algorithm never changes \a Data::HasChangedAddress for distinct
-  /// nodes.
-  ///
-  /// \post \a POT is a post-order traversal ending with \c FirstN.
-  void propagateChangedOperands();
-
-  /// Map all distinct nodes in POT.
-  ///
-  /// \post \a getMappedOp() returns the correct node for every distinct node.
-  void mapDistinctNodes();
-
-  /// Map all uniqued nodes in POT with the correct operands.
-  ///
-  /// \pre Distinct nodes are mapped (\a mapDistinctNodes() has been called).
-  /// \post \a getMappedOp() returns the correct node for every node.
-  /// \post \a MDNode::operands() is correct for every uniqued node.
-  /// \post \a MDNode::isResolved() returns true for every node.
-  void mapUniquedNodes();
-
-  /// Re-map the operands for distinct nodes in POT.
-  ///
-  /// \pre Distinct nodes are mapped (\a mapDistinctNodes() has been called).
-  /// \pre Uniqued nodes are mapped (\a mapUniquedNodes() has been called).
-  /// \post \a MDNode::operands() is correct for every distinct node.
-  void remapDistinctOperands();
-
-  /// Remap a node's operands.
-  ///
-  /// Iterate through operands and update them in place using \a getMappedOp()
-  /// and \a getFwdReference().
+  /// Iterate through the operands of \c N and update them in place using \c
+  /// mapOperand.
   ///
   /// \pre N.isDistinct() or N.isTemporary().
-  /// \pre Distinct nodes are mapped (\a mapDistinctNodes() has been called).
-  /// \pre If \c N is distinct, all uniqued nodes are already mapped.
-  void remapOperands(const Data &D, MDNode &N);
+  template <class OperandMapper>
+  void remapOperands(MDNode &N, OperandMapper mapOperand);
 };
 
 } // end namespace
@@ -500,9 +500,9 @@ Metadata *Mapper::mapToSelf(const Metada
   return mapToMetadata(MD, const_cast<Metadata *>(MD));
 }
 
-bool MDNodeMapper::mapOperand(const Metadata *Op) {
+Optional<Metadata *> MDNodeMapper::tryToMapOperand(const Metadata *Op) {
   if (!Op)
-    return false;
+    return nullptr;
 
   if (Optional<Metadata *> MappedOp = M.mapSimpleMetadata(Op)) {
 #ifndef NDEBUG
@@ -514,10 +514,23 @@ bool MDNodeMapper::mapOperand(const Meta
       assert((isa<MDString>(Op) || M.getVM().getMappedMD(Op)) &&
              "Expected result to be memoized");
 #endif
-    return *MappedOp != Op;
+    return *MappedOp;
   }
 
-  return push(*cast<MDNode>(Op)).HasChangedAddress;
+  const MDNode &N = *cast<MDNode>(Op);
+  if (N.isDistinct())
+    return mapDistinctNode(N);
+  return None;
+}
+
+MDNode *MDNodeMapper::mapDistinctNode(const MDNode &N) {
+  assert(N.isDistinct() && "Expected a distinct node");
+  assert(!M.getVM().getMappedMD(&N) && "Expected an unmapped node");
+  DistinctWorklist.push_back(cast<MDNode>(
+      (M.Flags & RF_MoveDistinctMDs)
+          ? M.mapToSelf(&N)
+          : M.mapToMetadata(&N, MDNode::replaceWithDistinct(N.clone()))));
+  return DistinctWorklist.back();
 }
 
 static ConstantAsMetadata *wrapConstantAsMetadata(const ConstantAsMetadata &CMD,
@@ -543,14 +556,12 @@ Optional<Metadata *> MDNodeMapper::getMa
   return None;
 }
 
-Metadata &MDNodeMapper::getFwdReference(const Data &D, MDNode &Op) {
+Metadata &MDNodeMapper::UniquedGraph::getFwdReference(MDNode &Op) {
   auto Where = Info.find(&Op);
   assert(Where != Info.end() && "Expected a valid reference");
 
   auto &OpD = Where->second;
-  assert(OpD.ID > D.ID && "Expected a forward reference");
-
-  if (!OpD.HasChangedAddress)
+  if (!OpD.HasChanged)
     return Op;
 
   // Lazily construct a temporary node.
@@ -560,128 +571,93 @@ Metadata &MDNodeMapper::getFwdReference(
   return *OpD.Placeholder;
 }
 
-void MDNodeMapper::remapOperands(const Data &D, MDNode &N) {
+template <class OperandMapper>
+void MDNodeMapper::remapOperands(MDNode &N, OperandMapper mapOperand) {
+  assert(!N.isUniqued() && "Expected distinct or temporary nodes");
   for (unsigned I = 0, E = N.getNumOperands(); I != E; ++I) {
     Metadata *Old = N.getOperand(I);
-    Metadata *New;
-    if (Optional<Metadata *> MappedOp = getMappedOp(Old)){
-      New = *MappedOp;
-    } else {
-      assert(!N.isDistinct() &&
-             "Expected all nodes to be pre-mapped for distinct operands");
-      MDNode &OldN = *cast<MDNode>(Old);
-      assert(!OldN.isDistinct() && "Expected distinct nodes to be pre-mapped");
-      New = &getFwdReference(D, OldN);
-    }
+    Metadata *New = mapOperand(Old);
 
     if (Old != New)
       N.replaceOperandWith(I, New);
   }
 }
 
-MDNodeMapper::Data &MDNodeMapper::push(const MDNode &N) {
-  auto Insertion = Info.insert(std::make_pair(&N, Data()));
-  auto &D = Insertion.first->second;
-  if (!Insertion.second)
-    return D;
-
-  // Add to the worklist; check for distinct nodes that are required to be
-  // copied.
-  Worklist.push_back(std::make_pair(&const_cast<MDNode &>(N), false));
-  D.HasChangedAddress = !(M.Flags & RF_MoveDistinctMDs) && N.isDistinct();
-  return D;
-}
-
-bool MDNodeMapper::tryToPop() {
-  if (!Worklist.back().second) {
-    Worklist.back().second = true;
-    return false;
-  }
+bool MDNodeMapper::createPOT(UniquedGraph &G, const MDNode &FirstN) {
+  assert(G.Info.empty() && "Expected a fresh traversal");
+  assert(FirstN.isUniqued() && "Expected uniqued node in POT");
 
-  MDNode *N = Worklist.pop_back_val().first;
-  Info[N].ID = POT.size();
-  POT.push_back(N);
-  return true;
-}
-
-bool MDNodeMapper::createPOT(const MDNode &FirstN) {
+  // Construct a post-order traversal of the uniqued subgraph under FirstN.
   bool AnyChanges = false;
 
-  // Do a traversal of the unmapped subgraph, tracking whether operands change.
-  // In some cases, these changes will propagate naturally, but
-  // propagateChangedOperands() catches the general case.
-  AnyChanges |= push(FirstN).HasChangedAddress;
-  while (hasWork()) {
-    if (tryToPop())
+  // The flag on the worklist indicates whether this is the first or second
+  // visit of a node.  The first visit looks through the operands; the second
+  // visit adds the node to POT.
+  SmallVector<std::pair<MDNode *, bool>, 16> Worklist;
+  Worklist.push_back(std::make_pair(&const_cast<MDNode &>(FirstN), false));
+  (void)G.Info[&FirstN];
+  while (!Worklist.empty()) {
+    MDNode &N = *Worklist.back().first;
+    if (Worklist.back().second) {
+      // We've already visited operands.  Add this to POT.
+      Worklist.pop_back();
+      G.Info[&N].ID = G.POT.size();
+      G.POT.push_back(&N);
       continue;
+    }
+    Worklist.back().second = true;
 
-    MDNode &N = getCurrentNode();
+    // Look through the operands for changes, pushing unmapped uniqued nodes
+    // onto to the worklist.
+    assert(N.isUniqued() && "Expected only uniqued nodes in POT");
     bool LocalChanges = false;
-    for (const Metadata *Op : N.operands())
-      LocalChanges |= mapOperand(Op);
+    for (Metadata *Op : N.operands()) {
+      assert(Op != &N && "Uniqued nodes cannot have self-references");
+      if (Optional<Metadata *> MappedOp = tryToMapOperand(Op)) {
+        AnyChanges |= LocalChanges |= Op != *MappedOp;
+        continue;
+      }
 
-    if (!LocalChanges)
-      continue;
+      MDNode &OpN = *cast<MDNode>(Op);
+      assert(OpN.isUniqued() &&
+             "Only uniqued operands cannot be mapped immediately");
+      if (G.Info.insert(std::make_pair(&OpN, Data())).second)
+        Worklist.push_back(std::make_pair(&OpN, false));
+    }
 
-    AnyChanges = true;
-    auto &D = Info[&N];
-    D.HasChangedOps = true;
-
-    // Uniqued nodes change address when operands change.
-    if (!N.isDistinct())
-      D.HasChangedAddress = true;
+    if (LocalChanges)
+      G.Info[&N].HasChanged = true;
   }
   return AnyChanges;
 }
 
-void MDNodeMapper::propagateChangedOperands() {
-  bool AnyChangedAddresses;
+void MDNodeMapper::UniquedGraph::propagateChanges() {
+  bool AnyChanges;
   do {
-    AnyChangedAddresses = false;
+    AnyChanges = false;
     for (MDNode *N : POT) {
-      auto &NI = Info[N];
-      if (NI.HasChangedOps)
+      auto &D = Info[N];
+      if (D.HasChanged)
         continue;
 
       if (!llvm::any_of(N->operands(), [&](const Metadata *Op) {
             auto Where = Info.find(Op);
-            return Where != Info.end() && Where->second.HasChangedAddress;
+            return Where != Info.end() && Where->second.HasChanged;
           }))
         continue;
 
-      NI.HasChangedOps = true;
-      if (!N->isDistinct()) {
-        NI.HasChangedAddress = true;
-        AnyChangedAddresses = true;
-      }
+      AnyChanges = D.HasChanged = true;
     }
-  } while (AnyChangedAddresses);
+  } while (AnyChanges);
 }
 
-void MDNodeMapper::mapDistinctNodes() {
-  // Map all the distinct nodes in POT.
-  for (MDNode *N : POT) {
-    if (!N->isDistinct())
-      continue;
-
-    if (M.Flags & RF_MoveDistinctMDs)
-      M.mapToSelf(N);
-    else
-      M.mapToMetadata(N, MDNode::replaceWithDistinct(N->clone()));
-  }
-}
-
-void MDNodeMapper::mapUniquedNodes() {
+void MDNodeMapper::mapNodesInPOT(UniquedGraph &G) {
   // Construct uniqued nodes, building forward references as necessary.
   SmallVector<MDNode *, 16> CyclicNodes;
-  for (auto *N : POT) {
-    if (N->isDistinct())
-      continue;
-
-    auto &D = Info[N];
-    assert(D.HasChangedAddress == D.HasChangedOps &&
-           "Uniqued nodes should change address iff ops change");
-    if (!D.HasChangedAddress) {
+  for (auto *N : G.POT) {
+    auto &D = G.Info[N];
+    if (!D.HasChanged) {
+      // The node hasn't changed.
       M.mapToSelf(N);
       continue;
     }
@@ -691,7 +667,13 @@ void MDNodeMapper::mapUniquedNodes() {
 
     // Clone the uniqued node and remap the operands.
     TempMDNode ClonedN = D.Placeholder ? std::move(D.Placeholder) : N->clone();
-    remapOperands(D, *ClonedN);
+    remapOperands(*ClonedN, [this, &D, &G](Metadata *Old) {
+      if (Optional<Metadata *> MappedOp = getMappedOp(Old))
+        return *MappedOp;
+      assert(G.Info[Old].ID > D.ID && "Expected a forward reference");
+      return &G.getFwdReference(*cast<MDNode>(Old));
+    });
+
     auto *NewN = MDNode::replaceWithUniqued(std::move(ClonedN));
     M.mapToMetadata(N, NewN);
 
@@ -707,40 +689,42 @@ void MDNodeMapper::mapUniquedNodes() {
       N->resolveCycles();
 }
 
-void MDNodeMapper::remapDistinctOperands() {
-  for (auto *N : POT) {
-    if (!N->isDistinct())
-      continue;
-
-    auto &D = Info[N];
-    if (!D.HasChangedOps)
-      continue;
-
-    assert(D.HasChangedAddress == !bool(M.Flags & RF_MoveDistinctMDs) &&
-           "Distinct nodes should change address iff they cannot be moved");
-    remapOperands(D, D.HasChangedAddress ? *cast<MDNode>(*getMappedOp(N)) : *N);
-  }
-}
-
-Metadata *MDNodeMapper::map(const MDNode &FirstN) {
+Metadata *MDNodeMapper::map(const MDNode &N) {
+  assert(DistinctWorklist.empty() && "MDNodeMapper::map is not recursive");
   assert(!(M.Flags & RF_NoModuleLevelChanges) &&
          "MDNodeMapper::map assumes module-level changes");
-  assert(POT.empty() && "MDNodeMapper::map is not re-entrant");
 
   // Require resolved nodes whenever metadata might be remapped.
-  assert(FirstN.isResolved() && "Unexpected unresolved node");
+  assert(N.isResolved() && "Unexpected unresolved node");
 
-  // Return early if nothing at all changed.
-  if (!createPOT(FirstN)) {
-    for (const MDNode *N : POT)
+  Metadata *MappedN =
+      N.isUniqued() ? mapTopLevelUniquedNode(N) : mapDistinctNode(N);
+  while (!DistinctWorklist.empty())
+    remapOperands(*DistinctWorklist.pop_back_val(), [this](Metadata *Old) {
+      if (Optional<Metadata *> MappedOp = tryToMapOperand(Old))
+        return *MappedOp;
+      return mapTopLevelUniquedNode(*cast<MDNode>(Old));
+    });
+  return MappedN;
+}
+
+Metadata *MDNodeMapper::mapTopLevelUniquedNode(const MDNode &FirstN) {
+  assert(FirstN.isUniqued() && "Expected uniqued node");
+
+  // Create a post-order traversal of uniqued nodes under FirstN.
+  UniquedGraph G;
+  if (!createPOT(G, FirstN)) {
+    // Return early if no nodes have changed.
+    for (const MDNode *N : G.POT)
       M.mapToSelf(N);
     return &const_cast<MDNode &>(FirstN);
   }
 
-  propagateChangedOperands();
-  mapDistinctNodes();
-  mapUniquedNodes();
-  remapDistinctOperands();
+  // Update graph with all nodes that have changed.
+  G.propagateChanges();
+
+  // Map all the nodes in the graph.
+  mapNodesInPOT(G);
 
   // Return the original node, remapped.
   return *getMappedOp(&FirstN);




More information about the llvm-commits mailing list