diff options
Diffstat (limited to 'lib/CodeGen/SelectionDAG/SelectionDAG.cpp')
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 88 |
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(); } } |