diff --git a/lib/Bitcode/Writer/ValueEnumerator.cpp b/lib/Bitcode/Writer/ValueEnumerator.cpp index 7eb23f0b20a..068bf622df1 100644 --- a/lib/Bitcode/Writer/ValueEnumerator.cpp +++ b/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -569,36 +569,40 @@ void ValueEnumerator::dropFunctionFromMetadata( void ValueEnumerator::EnumerateMetadata(unsigned F, const Metadata *MD) { // Start by enumerating MD, and then work through its transitive operands in // post-order. This requires a depth-first search. - SmallVector, 32> Worklist; - enumerateMetadataImpl(F, MD, Worklist); + SmallVector, 32> Worklist; + if (const MDNode *N = enumerateMetadataImpl(F, MD)) + Worklist.push_back(std::make_pair(N, N->op_begin())); + while (!Worklist.empty()) { const MDNode *N = Worklist.back().first; - const MDOperand *&Op = Worklist.back().second; // Be careful of lifetime... + MDNode::op_iterator &I = Worklist.back().second; // Enumerate operands until the worklist changes. We need to traverse new // nodes before visiting the rest of N's operands. - bool DidWorklistChange = false; - for (const MDOperand *E = N->op_end(); Op != E;) - if (enumerateMetadataImpl(F, *Op++, Worklist)) { - DidWorklistChange = true; - break; - } - if (DidWorklistChange) + if (const MDNode *Op = enumerateMetadataOperands(F, I, N->op_end())) { + Worklist.push_back(std::make_pair(Op, Op->op_begin())); continue; + } // All the operands have been visited. Now assign an ID. Worklist.pop_back(); MDs.push_back(N); MetadataMap[N].ID = MDs.size(); - continue; } } -bool ValueEnumerator::enumerateMetadataImpl( - unsigned F, const Metadata *MD, - SmallVectorImpl> &Worklist) { +const MDNode * +ValueEnumerator::enumerateMetadataOperands(unsigned F, MDNode::op_iterator &I, + MDNode::op_iterator E) { + while (I != E) + if (const MDNode *N = enumerateMetadataImpl(F, *I++)) // Always increment I. + return N; + return nullptr; +} + +const MDNode *ValueEnumerator::enumerateMetadataImpl(unsigned F, const Metadata *MD) { if (!MD) - return false; + return nullptr; assert( (isa(MD) || isa(MD) || isa(MD)) && @@ -610,14 +614,12 @@ bool ValueEnumerator::enumerateMetadataImpl( // Already mapped. If F doesn't match the function tag, drop it. if (Entry.hasDifferentFunction(F)) dropFunctionFromMetadata(*Insertion.first); - return false; + return nullptr; } - // MDNodes are handled separately to avoid recursion. - if (auto *N = dyn_cast(MD)) { - Worklist.push_back(std::make_pair(N, N->op_begin())); - return true; // Changed the worklist. - } + // Don't assign IDs to metadata nodes. + if (auto *N = dyn_cast(MD)) + return N; // Save the metadata. MDs.push_back(MD); @@ -627,7 +629,7 @@ bool ValueEnumerator::enumerateMetadataImpl( if (auto *C = dyn_cast(MD)) EnumerateValue(C->getValue()); - return false; + return nullptr; } /// EnumerateFunctionLocalMetadataa - Incorporate function-local metadata diff --git a/lib/Bitcode/Writer/ValueEnumerator.h b/lib/Bitcode/Writer/ValueEnumerator.h index e858c7a5739..9acb9224212 100644 --- a/lib/Bitcode/Writer/ValueEnumerator.h +++ b/lib/Bitcode/Writer/ValueEnumerator.h @@ -246,9 +246,24 @@ private: /// function. void incorporateFunctionMetadata(const Function &F); - bool enumerateMetadataImpl( - unsigned F, const Metadata *MD, - SmallVectorImpl> &Worklist); + /// Enumerate operands with the given function tag. + /// + /// Enumerate the Metadata operands between \c I and \c E, returning the + /// first newly-enumerated MDNode without assigning it an ID. + /// + /// \post If a node was found, \c I points just past the node. + /// \post If no node was found, \c I is equal to \c E. + const MDNode *enumerateMetadataOperands(unsigned F, const MDOperand *&I, + const MDOperand *E); + + /// Enumerate a single instance of metadata with the given function tag. + /// + /// If \c MD has already been enumerated, check that \c F matches its + /// function tag. If not, call \a dropFunctionFromMetadata(). + /// + /// Otherwise, mark \c MD as visited. Assign it an ID, or just return it if + /// it's an \a MDNode. + const MDNode *enumerateMetadataImpl(unsigned F, const Metadata *MD); unsigned getMetadataFunctionID(const Function *F) const; void EnumerateMetadata(const Function *F, const Metadata *MD); diff --git a/lib/Transforms/Utils/ValueMapper.cpp b/lib/Transforms/Utils/ValueMapper.cpp index 548a6fc702f..f44e79fba60 100644 --- a/lib/Transforms/Utils/ValueMapper.cpp +++ b/lib/Transforms/Utils/ValueMapper.cpp @@ -228,18 +228,6 @@ class MDNodeMapper { Metadata &getFwdReference(MDNode &Op); }; - /// An entry in the worklist for the post-order traversal. - struct POTWorklistEntry { - MDNode *N; ///< Current node. - const MDOperand *Op; ///< Current operand of \c N. - - /// Keep a flag of whether operands have changed in the worklist to avoid - /// hitting the map in \a UniquedGraph. - bool HasChanged = false; - - POTWorklistEntry(MDNode &N) : N(&N), Op(N.op_begin()) {} - }; - /// Worklist of distinct nodes whose operands need to be remapped. SmallVector DistinctWorklist; @@ -330,11 +318,15 @@ private: /// to change because of operands outside the graph. bool createPOT(UniquedGraph &G, const MDNode &FirstN); - /// Visit an operand of a node in the POT. + /// Visit the operands of a uniqued node in the POT. /// - /// Return \c true iff a new node was pushed onto \c Worklist. - bool visitOperand(UniquedGraph &G, Metadata *Op, - SmallVectorImpl &Worklist); + /// Visit the operands in the range from \c I to \c E, returning the first + /// uniqued node we find that isn't yet in \c G. \c I is always advanced to + /// where to continue the loop through the operands. + /// + /// This sets \c HasChanged if any of the visited operands change. + MDNode *visitOperands(UniquedGraph &G, MDNode::op_iterator &I, + MDNode::op_iterator E, bool &HasChanged); /// Map all the nodes in the given uniqued graph. /// @@ -609,6 +601,20 @@ void MDNodeMapper::remapOperands(MDNode &N, OperandMapper mapOperand) { } } +namespace { +/// An entry in the worklist for the post-order traversal. +struct POTWorklistEntry { + MDNode *N; ///< Current node. + MDNode::op_iterator Op; ///< Current operand of \c N. + + /// Keep a flag of whether operands have changed in the worklist to avoid + /// hitting the map in \a UniquedGraph. + bool HasChanged = false; + + POTWorklistEntry(MDNode &N) : N(&N), Op(N.op_begin()) {} +}; +} // end namespace + bool MDNodeMapper::createPOT(UniquedGraph &G, const MDNode &FirstN) { assert(G.Info.empty() && "Expected a fresh traversal"); assert(FirstN.isUniqued() && "Expected uniqued node in POT"); @@ -619,49 +625,46 @@ bool MDNodeMapper::createPOT(UniquedGraph &G, const MDNode &FirstN) { Worklist.push_back(POTWorklistEntry(const_cast(FirstN))); (void)G.Info[&FirstN]; while (!Worklist.empty()) { - MDNode &N = *Worklist.back().N; - const MDOperand *&Op = Worklist.back().Op; // Careful of lifetime... - assert(N.isUniqued() && "Expected only uniqued nodes in POT"); - - // Pick up the traversal from Op and continue. Since this is a DFS, pause - // as soon as a new node is pushed onto the worklist. - bool DidWorklistSizeChange = false; - for (const MDOperand *E = N.op_end(); Op != E;) { - assert(*Op != &N && "Uniqued nodes cannot have self-references"); - if (visitOperand(G, *Op++, Worklist)) { - DidWorklistSizeChange = true; - break; - } - } - if (DidWorklistSizeChange) + // Start or continue the traversal through the this node's operands. + auto &WE = Worklist.back(); + if (MDNode *N = visitOperands(G, WE.Op, WE.N->op_end(), WE.HasChanged)) { + // Push a new node to traverse first. + Worklist.push_back(POTWorklistEntry(*N)); continue; + } - // All operands of N have been visited. Push N into the POT. - auto &D = G.Info[&N]; - AnyChanges |= D.HasChanged = Worklist.pop_back_val().HasChanged; + // Push the node onto the POT. + assert(WE.N->isUniqued() && "Expected only uniqued nodes"); + assert(WE.Op == WE.N->op_end() && "Expected to visit all operands"); + auto &D = G.Info[WE.N]; + AnyChanges |= D.HasChanged = WE.HasChanged; D.ID = G.POT.size(); - G.POT.push_back(&N); + G.POT.push_back(WE.N); + + // Pop the node off the worklist. + Worklist.pop_back(); } return AnyChanges; } -bool MDNodeMapper::visitOperand(UniquedGraph &G, Metadata *Op, - SmallVectorImpl &Worklist) { - // Try to map Op, and check it for changes. - if (Optional MappedOp = tryToMapOperand(Op)) { - Worklist.back().HasChanged |= Op != *MappedOp; - return false; +MDNode *MDNodeMapper::visitOperands(UniquedGraph &G, MDNode::op_iterator &I, + MDNode::op_iterator E, bool &HasChanged) { + while (I != E) { + Metadata *Op = *I++; // Increment even on early return. + if (Optional MappedOp = tryToMapOperand(Op)) { + // Check if the operand changes. + HasChanged |= Op != *MappedOp; + continue; + } + + // A uniqued metadata node. + MDNode &OpN = *cast(Op); + assert(OpN.isUniqued() && + "Only uniqued operands cannot be mapped immediately"); + if (G.Info.insert(std::make_pair(&OpN, Data())).second) + return &OpN; // This is a new one. Return it. } - - // Push Op onto the Worklist unless it's already in G. - MDNode &OpN = *cast(Op); - assert(OpN.isUniqued() && - "Only uniqued operands cannot be mapped immediately"); - if (!G.Info.insert(std::make_pair(&OpN, Data())).second) - return false; - - Worklist.push_back(POTWorklistEntry(OpN)); - return true; + return nullptr; } void MDNodeMapper::UniquedGraph::propagateChanges() {