forked from OSchip/llvm-project
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. llvm-svn: 266537
This commit is contained in:
parent
0cb5c344b4
commit
694ab4e966
|
@ -189,149 +189,149 @@ private:
|
||||||
class MDNodeMapper {
|
class MDNodeMapper {
|
||||||
Mapper &M;
|
Mapper &M;
|
||||||
|
|
||||||
|
/// Data about a node in \a UniquedGraph.
|
||||||
struct Data {
|
struct Data {
|
||||||
bool HasChangedOps = false;
|
bool HasChanged = false;
|
||||||
bool HasChangedAddress = false;
|
|
||||||
unsigned ID = ~0u;
|
unsigned ID = ~0u;
|
||||||
TempMDNode Placeholder;
|
TempMDNode Placeholder;
|
||||||
|
|
||||||
Data() {}
|
Data() {}
|
||||||
Data(Data &&X)
|
Data(Data &&X)
|
||||||
: HasChangedOps(std::move(X.HasChangedOps)),
|
: HasChanged(std::move(X.HasChanged)), ID(std::move(X.ID)),
|
||||||
HasChangedAddress(std::move(X.HasChangedAddress)),
|
Placeholder(std::move(X.Placeholder)) {}
|
||||||
ID(std::move(X.ID)), Placeholder(std::move(X.Placeholder)) {}
|
|
||||||
Data &operator=(Data &&X) {
|
Data &operator=(Data &&X) {
|
||||||
HasChangedOps = std::move(X.HasChangedOps);
|
HasChanged = std::move(X.HasChanged);
|
||||||
HasChangedAddress = std::move(X.HasChangedAddress);
|
|
||||||
ID = std::move(X.ID);
|
ID = std::move(X.ID);
|
||||||
Placeholder = std::move(X.Placeholder);
|
Placeholder = std::move(X.Placeholder);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SmallDenseMap<const Metadata *, Data, 32> Info;
|
/// A graph of uniqued nodes.
|
||||||
SmallVector<std::pair<MDNode *, bool>, 16> Worklist;
|
struct UniquedGraph {
|
||||||
SmallVector<MDNode *, 16> POT;
|
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:
|
public:
|
||||||
MDNodeMapper(Mapper &M) : M(M) {}
|
MDNodeMapper(Mapper &M) : M(M) {}
|
||||||
|
|
||||||
/// Map a metadata node (and its transitive operands).
|
/// 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.
|
||||||
///
|
///
|
||||||
/// 1. \a createPOT(): use a worklist to perform a post-order traversal of
|
/// Distinct nodes are immediately mapped and added to \a DistinctWorklist
|
||||||
/// the transitively referenced unmapped nodes.
|
/// using \a mapDistinctNode(). Their mapping can always be computed
|
||||||
|
/// immediately without visiting operands, even if their operands change.
|
||||||
///
|
///
|
||||||
/// 2. \a propagateChangedOperands(): track which nodes will change
|
/// The mapping for uniqued nodes depends on whether their operands change.
|
||||||
/// operands, and which will have new addresses in the mapped scheme.
|
/// \a mapTopLevelUniquedNode() traverses the transitive uniqued subgraph of
|
||||||
/// Propagate the changes through the POT until fixed point, to pick up
|
/// a node to calculate uniqued node mappings in bulk. Distinct leafs are
|
||||||
/// uniquing cycles that need to change.
|
/// added to \a DistinctWorklist with \a mapDistinctNode().
|
||||||
///
|
///
|
||||||
/// 3. \a mapDistinctNodes(): map all the distinct nodes without touching
|
/// After mapping \c N itself, this function remaps the operands of the
|
||||||
/// their operands. If RF_MoveDistinctMetadata, they get mapped to
|
/// distinct nodes in \a DistinctWorklist until the entire subgraph under \c
|
||||||
/// themselves; otherwise, they get mapped to clones.
|
/// N has been mapped.
|
||||||
///
|
Metadata *map(const MDNode &N);
|
||||||
/// 4. \a mapUniquedNodes(): map the uniqued nodes (bottom-up), lazily
|
|
||||||
/// creating temporaries for forward references as needed.
|
|
||||||
///
|
|
||||||
/// 5. \a remapDistinctOperands(): remap the operands of the distinct nodes.
|
|
||||||
Metadata *map(const MDNode &FirstN);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Return \c true as long as there's work to do.
|
/// Map a top-level uniqued node and the uniqued subgraph underneath it.
|
||||||
bool hasWork() const { return !Worklist.empty(); }
|
///
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// The algorithm works as follows:
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// 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.
|
/// Try to map the operand of an \a MDNode.
|
||||||
MDNode &getCurrentNode() const { return *Worklist.back().first; }
|
///
|
||||||
|
/// 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().
|
||||||
|
///
|
||||||
|
/// \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);
|
||||||
|
|
||||||
/// Push a node onto the worklist.
|
/// Map a distinct node.
|
||||||
///
|
///
|
||||||
/// Adds \c N to \a Worklist and \a Info, unless it's already inserted. If
|
/// Return the mapping for the distinct node \c N, saving the result in \a
|
||||||
/// \c N.isDistinct(), \a Data::HasChangedAddress will be set based on \a
|
/// DistinctWorklist for later remapping.
|
||||||
/// RF_MoveDistinctMDs.
|
|
||||||
///
|
///
|
||||||
/// Returns the data for the node.
|
/// \pre \c N is not yet mapped.
|
||||||
///
|
/// \pre \c N.isDistinct().
|
||||||
/// \post Data::HasChangedAddress iff !RF_MoveDistinctMDs && N.isDistinct().
|
MDNode *mapDistinctNode(const MDNode &N);
|
||||||
/// \post Worklist.back().first == &N.
|
|
||||||
/// \post Worklist.back().second == false.
|
|
||||||
Data &push(const MDNode &N);
|
|
||||||
|
|
||||||
/// Map a node operand, and return true if it changes.
|
|
||||||
///
|
|
||||||
/// \post getMappedOp(Op) does not return None.
|
|
||||||
bool mapOperand(const Metadata *Op);
|
|
||||||
|
|
||||||
/// Get a previously mapped node.
|
/// Get a previously mapped node.
|
||||||
Optional<Metadata *> getMappedOp(const Metadata *Op) const;
|
Optional<Metadata *> getMappedOp(const Metadata *Op) const;
|
||||||
|
|
||||||
/// Try to pop a node off the worklist and store it in POT.
|
/// Create a post-order traversal of an unmapped uniqued node subgraph.
|
||||||
///
|
|
||||||
/// 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.
|
|
||||||
///
|
///
|
||||||
/// This traverses the metadata graph deeply enough to map \c FirstN. It
|
/// 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.
|
/// 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.
|
/// Each node that has a changed operand from outside the graph (e.g., a
|
||||||
bool createPOT(const MDNode &FirstN);
|
/// 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);
|
||||||
|
|
||||||
/// Propagate changed operands through post-order traversal.
|
/// Map all the nodes in the given uniqued graph.
|
||||||
///
|
///
|
||||||
/// Until fixed point, iteratively update:
|
/// 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.
|
||||||
///
|
///
|
||||||
/// - \a Data::HasChangedOps based on \a Data::HasChangedAddress of operands;
|
/// \pre \a getMappedOp() returns None for nodes in \c G, but not for any of
|
||||||
/// - \a Data::HasChangedAddress based on Data::HasChangedOps.
|
/// their operands outside of \c G.
|
||||||
///
|
/// \pre \a Data::HasChanged is true for a node in \c G iff any of its
|
||||||
/// This algorithm never changes \a Data::HasChangedAddress for distinct
|
/// operands have changed.
|
||||||
/// nodes.
|
/// \post \a getMappedOp() returns the mapped node for every node in \c G.
|
||||||
///
|
void mapNodesInPOT(UniquedGraph &G);
|
||||||
/// \post \a POT is a post-order traversal ending with \c FirstN.
|
|
||||||
void propagateChangedOperands();
|
|
||||||
|
|
||||||
/// Map all distinct nodes in POT.
|
/// Remap a node's operands using the given functor.
|
||||||
///
|
///
|
||||||
/// \post \a getMappedOp() returns the correct node for every distinct node.
|
/// Iterate through the operands of \c N and update them in place using \c
|
||||||
void mapDistinctNodes();
|
/// mapOperand.
|
||||||
|
|
||||||
/// 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().
|
|
||||||
///
|
///
|
||||||
/// \pre N.isDistinct() or N.isTemporary().
|
/// \pre N.isDistinct() or N.isTemporary().
|
||||||
/// \pre Distinct nodes are mapped (\a mapDistinctNodes() has been called).
|
template <class OperandMapper>
|
||||||
/// \pre If \c N is distinct, all uniqued nodes are already mapped.
|
void remapOperands(MDNode &N, OperandMapper mapOperand);
|
||||||
void remapOperands(const Data &D, MDNode &N);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
@ -500,9 +500,9 @@ Metadata *Mapper::mapToSelf(const Metadata *MD) {
|
||||||
return mapToMetadata(MD, const_cast<Metadata *>(MD));
|
return mapToMetadata(MD, const_cast<Metadata *>(MD));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MDNodeMapper::mapOperand(const Metadata *Op) {
|
Optional<Metadata *> MDNodeMapper::tryToMapOperand(const Metadata *Op) {
|
||||||
if (!Op)
|
if (!Op)
|
||||||
return false;
|
return nullptr;
|
||||||
|
|
||||||
if (Optional<Metadata *> MappedOp = M.mapSimpleMetadata(Op)) {
|
if (Optional<Metadata *> MappedOp = M.mapSimpleMetadata(Op)) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -514,10 +514,23 @@ bool MDNodeMapper::mapOperand(const Metadata *Op) {
|
||||||
assert((isa<MDString>(Op) || M.getVM().getMappedMD(Op)) &&
|
assert((isa<MDString>(Op) || M.getVM().getMappedMD(Op)) &&
|
||||||
"Expected result to be memoized");
|
"Expected result to be memoized");
|
||||||
#endif
|
#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,
|
static ConstantAsMetadata *wrapConstantAsMetadata(const ConstantAsMetadata &CMD,
|
||||||
|
@ -543,14 +556,12 @@ Optional<Metadata *> MDNodeMapper::getMappedOp(const Metadata *Op) const {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Metadata &MDNodeMapper::getFwdReference(const Data &D, MDNode &Op) {
|
Metadata &MDNodeMapper::UniquedGraph::getFwdReference(MDNode &Op) {
|
||||||
auto Where = Info.find(&Op);
|
auto Where = Info.find(&Op);
|
||||||
assert(Where != Info.end() && "Expected a valid reference");
|
assert(Where != Info.end() && "Expected a valid reference");
|
||||||
|
|
||||||
auto &OpD = Where->second;
|
auto &OpD = Where->second;
|
||||||
assert(OpD.ID > D.ID && "Expected a forward reference");
|
if (!OpD.HasChanged)
|
||||||
|
|
||||||
if (!OpD.HasChangedAddress)
|
|
||||||
return Op;
|
return Op;
|
||||||
|
|
||||||
// Lazily construct a temporary node.
|
// Lazily construct a temporary node.
|
||||||
|
@ -560,128 +571,93 @@ Metadata &MDNodeMapper::getFwdReference(const Data &D, MDNode &Op) {
|
||||||
return *OpD.Placeholder;
|
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) {
|
for (unsigned I = 0, E = N.getNumOperands(); I != E; ++I) {
|
||||||
Metadata *Old = N.getOperand(I);
|
Metadata *Old = N.getOperand(I);
|
||||||
Metadata *New;
|
Metadata *New = mapOperand(Old);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Old != New)
|
if (Old != New)
|
||||||
N.replaceOperandWith(I, New);
|
N.replaceOperandWith(I, New);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MDNodeMapper::Data &MDNodeMapper::push(const MDNode &N) {
|
bool MDNodeMapper::createPOT(UniquedGraph &G, const MDNode &FirstN) {
|
||||||
auto Insertion = Info.insert(std::make_pair(&N, Data()));
|
assert(G.Info.empty() && "Expected a fresh traversal");
|
||||||
auto &D = Insertion.first->second;
|
assert(FirstN.isUniqued() && "Expected uniqued node in POT");
|
||||||
if (!Insertion.second)
|
|
||||||
return D;
|
|
||||||
|
|
||||||
// Add to the worklist; check for distinct nodes that are required to be
|
// Construct a post-order traversal of the uniqued subgraph under FirstN.
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
MDNode *N = Worklist.pop_back_val().first;
|
|
||||||
Info[N].ID = POT.size();
|
|
||||||
POT.push_back(N);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MDNodeMapper::createPOT(const MDNode &FirstN) {
|
|
||||||
bool AnyChanges = false;
|
bool AnyChanges = false;
|
||||||
|
|
||||||
// Do a traversal of the unmapped subgraph, tracking whether operands change.
|
// The flag on the worklist indicates whether this is the first or second
|
||||||
// In some cases, these changes will propagate naturally, but
|
// visit of a node. The first visit looks through the operands; the second
|
||||||
// propagateChangedOperands() catches the general case.
|
// visit adds the node to POT.
|
||||||
AnyChanges |= push(FirstN).HasChangedAddress;
|
SmallVector<std::pair<MDNode *, bool>, 16> Worklist;
|
||||||
while (hasWork()) {
|
Worklist.push_back(std::make_pair(&const_cast<MDNode &>(FirstN), false));
|
||||||
if (tryToPop())
|
(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;
|
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;
|
bool LocalChanges = false;
|
||||||
for (const Metadata *Op : N.operands())
|
for (Metadata *Op : N.operands()) {
|
||||||
LocalChanges |= mapOperand(Op);
|
assert(Op != &N && "Uniqued nodes cannot have self-references");
|
||||||
|
if (Optional<Metadata *> MappedOp = tryToMapOperand(Op)) {
|
||||||
|
AnyChanges |= LocalChanges |= Op != *MappedOp;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!LocalChanges)
|
MDNode &OpN = *cast<MDNode>(Op);
|
||||||
continue;
|
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;
|
if (LocalChanges)
|
||||||
auto &D = Info[&N];
|
G.Info[&N].HasChanged = true;
|
||||||
D.HasChangedOps = true;
|
|
||||||
|
|
||||||
// Uniqued nodes change address when operands change.
|
|
||||||
if (!N.isDistinct())
|
|
||||||
D.HasChangedAddress = true;
|
|
||||||
}
|
}
|
||||||
return AnyChanges;
|
return AnyChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MDNodeMapper::propagateChangedOperands() {
|
void MDNodeMapper::UniquedGraph::propagateChanges() {
|
||||||
bool AnyChangedAddresses;
|
bool AnyChanges;
|
||||||
do {
|
do {
|
||||||
AnyChangedAddresses = false;
|
AnyChanges = false;
|
||||||
for (MDNode *N : POT) {
|
for (MDNode *N : POT) {
|
||||||
auto &NI = Info[N];
|
auto &D = Info[N];
|
||||||
if (NI.HasChangedOps)
|
if (D.HasChanged)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!llvm::any_of(N->operands(), [&](const Metadata *Op) {
|
if (!llvm::any_of(N->operands(), [&](const Metadata *Op) {
|
||||||
auto Where = Info.find(Op);
|
auto Where = Info.find(Op);
|
||||||
return Where != Info.end() && Where->second.HasChangedAddress;
|
return Where != Info.end() && Where->second.HasChanged;
|
||||||
}))
|
}))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
NI.HasChangedOps = true;
|
AnyChanges = D.HasChanged = true;
|
||||||
if (!N->isDistinct()) {
|
|
||||||
NI.HasChangedAddress = true;
|
|
||||||
AnyChangedAddresses = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} while (AnyChangedAddresses);
|
} while (AnyChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MDNodeMapper::mapDistinctNodes() {
|
void MDNodeMapper::mapNodesInPOT(UniquedGraph &G) {
|
||||||
// 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() {
|
|
||||||
// Construct uniqued nodes, building forward references as necessary.
|
// Construct uniqued nodes, building forward references as necessary.
|
||||||
SmallVector<MDNode *, 16> CyclicNodes;
|
SmallVector<MDNode *, 16> CyclicNodes;
|
||||||
for (auto *N : POT) {
|
for (auto *N : G.POT) {
|
||||||
if (N->isDistinct())
|
auto &D = G.Info[N];
|
||||||
continue;
|
if (!D.HasChanged) {
|
||||||
|
// The node hasn't changed.
|
||||||
auto &D = Info[N];
|
|
||||||
assert(D.HasChangedAddress == D.HasChangedOps &&
|
|
||||||
"Uniqued nodes should change address iff ops change");
|
|
||||||
if (!D.HasChangedAddress) {
|
|
||||||
M.mapToSelf(N);
|
M.mapToSelf(N);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -691,7 +667,13 @@ void MDNodeMapper::mapUniquedNodes() {
|
||||||
|
|
||||||
// Clone the uniqued node and remap the operands.
|
// Clone the uniqued node and remap the operands.
|
||||||
TempMDNode ClonedN = D.Placeholder ? std::move(D.Placeholder) : N->clone();
|
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));
|
auto *NewN = MDNode::replaceWithUniqued(std::move(ClonedN));
|
||||||
M.mapToMetadata(N, NewN);
|
M.mapToMetadata(N, NewN);
|
||||||
|
|
||||||
|
@ -707,40 +689,42 @@ void MDNodeMapper::mapUniquedNodes() {
|
||||||
N->resolveCycles();
|
N->resolveCycles();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MDNodeMapper::remapDistinctOperands() {
|
Metadata *MDNodeMapper::map(const MDNode &N) {
|
||||||
for (auto *N : POT) {
|
assert(DistinctWorklist.empty() && "MDNodeMapper::map is not recursive");
|
||||||
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) {
|
|
||||||
assert(!(M.Flags & RF_NoModuleLevelChanges) &&
|
assert(!(M.Flags & RF_NoModuleLevelChanges) &&
|
||||||
"MDNodeMapper::map assumes module-level changes");
|
"MDNodeMapper::map assumes module-level changes");
|
||||||
assert(POT.empty() && "MDNodeMapper::map is not re-entrant");
|
|
||||||
|
|
||||||
// Require resolved nodes whenever metadata might be remapped.
|
// 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.
|
Metadata *MappedN =
|
||||||
if (!createPOT(FirstN)) {
|
N.isUniqued() ? mapTopLevelUniquedNode(N) : mapDistinctNode(N);
|
||||||
for (const MDNode *N : POT)
|
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);
|
M.mapToSelf(N);
|
||||||
return &const_cast<MDNode &>(FirstN);
|
return &const_cast<MDNode &>(FirstN);
|
||||||
}
|
}
|
||||||
|
|
||||||
propagateChangedOperands();
|
// Update graph with all nodes that have changed.
|
||||||
mapDistinctNodes();
|
G.propagateChanges();
|
||||||
mapUniquedNodes();
|
|
||||||
remapDistinctOperands();
|
// Map all the nodes in the graph.
|
||||||
|
mapNodesInPOT(G);
|
||||||
|
|
||||||
// Return the original node, remapped.
|
// Return the original node, remapped.
|
||||||
return *getMappedOp(&FirstN);
|
return *getMappedOp(&FirstN);
|
||||||
|
|
Loading…
Reference in New Issue