aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/SelectionDAG/SelectionDAG.cpp')
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAG.cpp88
1 files changed, 53 insertions, 35 deletions
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index eb6e60302d..9a1ea7cb38 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -3232,11 +3232,11 @@ void SelectionDAG::ReplaceAllUsesWith(SDNode *From,
/// uses of other values produced by From.Val alone. The Deleted vector is
/// handled the same was as for ReplaceAllUsesWith.
void SelectionDAG::ReplaceAllUsesOfValueWith(SDOperand From, SDOperand To,
- std::vector<SDNode*> &Deleted) {
+ std::vector<SDNode*> *Deleted) {
assert(From != To && "Cannot replace a value with itself");
// Handle the simple, trivial, case efficiently.
if (From.Val->getNumValues() == 1 && To.Val->getNumValues() == 1) {
- ReplaceAllUsesWith(From, To, &Deleted);
+ ReplaceAllUsesWith(From, To, Deleted);
return;
}
@@ -3244,48 +3244,66 @@ void SelectionDAG::ReplaceAllUsesOfValueWith(SDOperand From, SDOperand To,
// deterministically ordered and uniqued set, so we use a SmallSetVector.
SmallSetVector<SDNode*, 16> Users(From.Val->use_begin(), From.Val->use_end());
+ std::vector<SDNode*> LocalDeletionVector;
+
+ // Pick a deletion vector to use. If the user specified one, use theirs,
+ // otherwise use a local one.
+ std::vector<SDNode*> *DeleteVector = Deleted ? Deleted : &LocalDeletionVector;
while (!Users.empty()) {
// We know that this user uses some value of From. If it is the right
// value, update it.
SDNode *User = Users.back();
Users.pop_back();
- for (SDOperand *Op = User->OperandList,
- *E = User->OperandList+User->NumOperands; Op != E; ++Op) {
+ // Scan for an operand that matches From.
+ SDOperand *Op = User->OperandList, *E = User->OperandList+User->NumOperands;
+ for (; Op != E; ++Op)
+ if (*Op == From) break;
+
+ // If there are no matches, the user must use some other result of From.
+ if (Op == E) continue;
+
+ // Okay, we know this user needs to be updated. Remove its old self
+ // from the CSE maps.
+ RemoveNodeFromCSEMaps(User);
+
+ // Update all operands that match "From".
+ for (; Op != E; ++Op) {
if (*Op == From) {
- // Okay, we know this user needs to be updated. Remove its old self
- // from the CSE maps.
- RemoveNodeFromCSEMaps(User);
-
- // Update all operands that match "From".
- for (; Op != E; ++Op) {
- if (*Op == From) {
- From.Val->removeUser(User);
- *Op = To;
- To.Val->addUser(User);
- }
- }
-
- // Now that we have modified User, add it back to the CSE maps. If it
- // already exists there, recursively merge the results together.
- if (SDNode *Existing = AddNonLeafNodeToCSEMaps(User)) {
- unsigned NumDeleted = Deleted.size();
- ReplaceAllUsesWith(User, Existing, &Deleted);
-
- // User is now dead.
- Deleted.push_back(User);
- DeleteNodeNotInCSEMaps(User);
-
- // We have to be careful here, because ReplaceAllUsesWith could have
- // deleted a user of From, which means there may be dangling pointers
- // in the "Users" setvector. Scan over the deleted node pointers and
- // remove them from the setvector.
- for (unsigned i = NumDeleted, e = Deleted.size(); i != e; ++i)
- Users.remove(Deleted[i]);
- }
- break; // Exit the operand scanning loop.
+ From.Val->removeUser(User);
+ *Op = To;
+ To.Val->addUser(User);
}
}
+
+ // Now that we have modified User, add it back to the CSE maps. If it
+ // already exists there, recursively merge the results together.
+ SDNode *Existing = AddNonLeafNodeToCSEMaps(User);
+ if (!Existing) continue; // Continue on to next user.
+
+ // If there was already an existing matching node, use ReplaceAllUsesWith
+ // to replace the dead one with the existing one. However, this can cause
+ // recursive merging of other unrelated nodes down the line. The merging
+ // can cause deletion of nodes that used the old value. In this case,
+ // we have to be certain to remove them from the Users set.
+ unsigned NumDeleted = DeleteVector->size();
+ ReplaceAllUsesWith(User, Existing, DeleteVector);
+
+ // User is now dead.
+ DeleteVector->push_back(User);
+ DeleteNodeNotInCSEMaps(User);
+
+ // We have to be careful here, because ReplaceAllUsesWith could have
+ // deleted a user of From, which means there may be dangling pointers
+ // in the "Users" setvector. Scan over the deleted node pointers and
+ // remove them from the setvector.
+ for (unsigned i = NumDeleted, e = DeleteVector->size(); i != e; ++i)
+ Users.remove((*DeleteVector)[i]);
+
+ // If the user doesn't need the set of deleted elements, don't retain them
+ // to the next loop iteration.
+ if (Deleted == 0)
+ LocalDeletionVector.clear();
}
}