+/// Resolve uniquing cycles involving the given metadata.
+static void resolveCycles(Metadata *MD, bool AllowTemps) {
+ if (auto *N = dyn_cast_or_null<MDNode>(MD)) {
+ if (AllowTemps && N->isTemporary())
+ return;
+ if (!N->isResolved()) {
+ if (AllowTemps)
+ // Note that this will drop RAUW support on any temporaries, which
+ // blocks uniquing. If this ends up being an issue, in the future
+ // we can experiment with delaying resolving these nodes until
+ // after metadata is fully materialized (i.e. when linking metadata
+ // as a postpass after function importing).
+ N->resolveNonTemporaries();
+ else
+ N->resolveCycles();
+ }
+ }
+}
+
+/// Remap the operands of an MDNode.
+///
+/// If \c Node is temporary, uniquing cycles are ignored. If \c Node is
+/// distinct, uniquing cycles are resolved as they're found.
+///
+/// \pre \c Node.isDistinct() or \c Node.isTemporary().
+static bool remapOperands(MDNode &Node,
+ SmallVectorImpl<MDNode *> &DistinctWorklist,
+ ValueToValueMapTy &VM, RemapFlags Flags,
+ ValueMapTypeRemapper *TypeMapper,
+ ValueMaterializer *Materializer) {
+ assert(!Node.isUniqued() && "Expected temporary or distinct node");
+ const bool IsDistinct = Node.isDistinct();
+
+ bool AnyChanged = false;
+ for (unsigned I = 0, E = Node.getNumOperands(); I != E; ++I) {
+ Metadata *Old = Node.getOperand(I);
+ Metadata *New = mapMetadataOp(Old, DistinctWorklist, VM, Flags, TypeMapper,
+ Materializer);
+ if (Old != New) {
+ AnyChanged = true;
+ Node.replaceOperandWith(I, New);
+
+ // Resolve uniquing cycles underneath distinct nodes on the fly so they
+ // don't infect later operands.
+ if (IsDistinct)
+ resolveCycles(New, Flags & RF_HaveUnmaterializedMetadata);
+ }
+ }
+
+ return AnyChanged;
+}
+
+/// Map a distinct MDNode.
+///
+/// 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 *> &DistinctWorklist,
+ ValueToValueMapTy &VM, RemapFlags Flags,
+ ValueMapTypeRemapper *TypeMapper,
+ ValueMaterializer *Materializer) {
+ assert(Node->isDistinct() && "Expected distinct node");
+
+ MDNode *NewMD;
+ if (Flags & RF_MoveDistinctMDs)
+ NewMD = const_cast<MDNode *>(Node);
+ else
+ NewMD = MDNode::replaceWithDistinct(Node->clone());
+
+ // Remap operands later.
+ DistinctWorklist.push_back(NewMD);
+ return mapToMetadata(VM, Node, NewMD, Materializer, Flags);
+}
+
+/// \brief Map a uniqued MDNode.
+///
+/// Uniqued nodes may not need to be recreated (they may map to themselves).
+static Metadata *mapUniquedNode(const MDNode *Node,
+ SmallVectorImpl<MDNode *> &DistinctWorklist,
+ ValueToValueMapTy &VM, RemapFlags Flags,
+ ValueMapTypeRemapper *TypeMapper,
+ ValueMaterializer *Materializer) {
+ assert(((Flags & RF_HaveUnmaterializedMetadata) || Node->isUniqued()) &&
+ "Expected uniqued node");
+
+ // Create a temporary node and map it upfront in case we have a uniquing
+ // cycle. If necessary, this mapping will get updated by RAUW logic before
+ // returning.
+ auto ClonedMD = Node->clone();
+ mapToMetadata(VM, Node, ClonedMD.get(), Materializer, Flags);
+ if (!remapOperands(*ClonedMD, DistinctWorklist, VM, Flags, TypeMapper,
+ Materializer)) {
+ // No operands changed, so use the original.
+ ClonedMD->replaceAllUsesWith(const_cast<MDNode *>(Node));
+ // Even though replaceAllUsesWith would have replaced the value map
+ // entry, we need to explictly map with the final non-temporary node
+ // to replace any temporary metadata via the callback.
+ return mapToSelf(VM, Node, Materializer, Flags);
+ }
+
+ // Uniquify the cloned node. Explicitly map it with the final non-temporary
+ // node so that replacement of temporary metadata via the callback occurs.
+ return mapToMetadata(VM, Node,
+ MDNode::replaceWithUniqued(std::move(ClonedMD)),
+ Materializer, Flags);
+}
+
+static Metadata *MapMetadataImpl(const Metadata *MD,
+ SmallVectorImpl<MDNode *> &DistinctWorklist,
+ ValueToValueMapTy &VM, RemapFlags Flags,