summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/CodeGenPrepare.cpp
diff options
context:
space:
mode:
authorBjorn Pettersson <bjorn.a.pettersson@ericsson.com>2018-03-20 09:06:37 +0000
committerBjorn Pettersson <bjorn.a.pettersson@ericsson.com>2018-03-20 09:06:37 +0000
commitbf3213e48517f8d6a5123903542d807ef21c0a17 (patch)
treec8973bae0a1215e343ff211a2fccc44ffc714523 /llvm/lib/CodeGen/CodeGenPrepare.cpp
parent8b8253fdc79e80f5de9aeed2201ea2d7582b729b (diff)
downloadbcm5719-llvm-bf3213e48517f8d6a5123903542d807ef21c0a17.tar.gz
bcm5719-llvm-bf3213e48517f8d6a5123903542d807ef21c0a17.zip
[CGP] Avoid segmentation fault when doing PHI node simplifications
Summary: Made PHI node simplifiations more robust in several ways: - Minor refactoring to let the SimplificationTracker own the sets with new PHI/Select nodes that are introduced. This is maybe not mapping to the original intention with the SimplificationTracker, but IMHO it encapsulates the logic behind those sets a little bit better. - MatchPhiNode can sometimes populate the Matched set with several entries, where it maps one PHI node to different candidates for replacement. The Matched set is changed into a SmallSetVector to make sure we get a deterministic iteration when doing the replacements. - As described above we may get several different replacements for a single PHI node. The loop in MatchPhiSet that is doing the replacements could end up calling eraseFromParent several times for the same PHI node, resulting in segmentation faults. This problem was supposed to be fixed in rL327250, but due to the non-determinism(?) it only appeared to be fixed (I still got crashes sometime when turning on/off -print-after-all etc to get different iteration order in the DenseSets). With this patch we follow the deterministic ordering in the Matched set when replacing the PHI nodes. If we find a new replacement for an already replaced PHI node we replace the new replacement by the old replacement instead. This is quite similar to what happened in the rl327250 patch, but here we also recursively verify that the old replacement hasn't been replaced already. - It was really hard to track down the fault described above (segementation fault due to doing eraseFromParent multiple times for the same instruction). The fault was intermittent and small changes in the code, or simply turning on -print-after-all etc could make the problem go away. This was basically due to the iteration over PhiNodesToMatch in MatchPhiSet no being deterministic. Therefore I've changed the data structure for the SimplificationTracker::AllPhiNodes into an SmallSetVector. This gives a deterministic behavior. Reviewers: skatkov, john.brawn Reviewed By: skatkov Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D44571 llvm-svn: 327961
Diffstat (limited to 'llvm/lib/CodeGen/CodeGenPrepare.cpp')
-rw-r--r--llvm/lib/CodeGen/CodeGenPrepare.cpp132
1 files changed, 71 insertions, 61 deletions
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index b8922bd8ed8..3afbb3cf3de 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -2591,14 +2591,15 @@ private:
class SimplificationTracker {
DenseMap<Value *, Value *> Storage;
const SimplifyQuery &SQ;
- SmallPtrSetImpl<PHINode *> &AllPhiNodes;
- SmallPtrSetImpl<SelectInst *> &AllSelectNodes;
+ // Tracks newly created Phi nodes. We use a SetVector to get deterministic
+ // order when iterating over the set in MatchPhiSet.
+ SmallSetVector<PHINode *, 32> AllPhiNodes;
+ // Tracks newly created Select nodes.
+ SmallPtrSet<SelectInst *, 32> AllSelectNodes;
public:
- SimplificationTracker(const SimplifyQuery &sq,
- SmallPtrSetImpl<PHINode *> &APN,
- SmallPtrSetImpl<SelectInst *> &ASN)
- : SQ(sq), AllPhiNodes(APN), AllSelectNodes(ASN) {}
+ SimplificationTracker(const SimplifyQuery &sq)
+ : SQ(sq) {}
Value *Get(Value *V) {
do {
@@ -2624,7 +2625,7 @@ public:
Put(PI, V);
PI->replaceAllUsesWith(V);
if (auto *PHI = dyn_cast<PHINode>(PI))
- AllPhiNodes.erase(PHI);
+ AllPhiNodes.remove(PHI);
if (auto *Select = dyn_cast<SelectInst>(PI))
AllSelectNodes.erase(Select);
PI->eraseFromParent();
@@ -2636,6 +2637,45 @@ public:
void Put(Value *From, Value *To) {
Storage.insert({ From, To });
}
+
+ void ReplacePhi(PHINode *From, PHINode *To) {
+ Value* OldReplacement = Get(From);
+ while (OldReplacement != From) {
+ From = To;
+ To = dyn_cast<PHINode>(OldReplacement);
+ OldReplacement = Get(From);
+ }
+ assert(Get(To) == To && "Replacement PHI node is already replaced.");
+ Put(From, To);
+ From->replaceAllUsesWith(To);
+ AllPhiNodes.remove(From);
+ From->eraseFromParent();
+ }
+
+ SmallSetVector<PHINode *, 32>& newPhiNodes() { return AllPhiNodes; }
+
+ void insertNewPhi(PHINode *PN) { AllPhiNodes.insert(PN); }
+
+ void insertNewSelect(SelectInst *SI) { AllSelectNodes.insert(SI); }
+
+ unsigned countNewPhiNodes() const { return AllPhiNodes.size(); }
+
+ unsigned countNewSelectNodes() const { return AllSelectNodes.size(); }
+
+ void destroyNewNodes(Type *CommonType) {
+ // For safe erasing, replace the uses with dummy value first.
+ auto Dummy = UndefValue::get(CommonType);
+ for (auto I : AllPhiNodes) {
+ I->replaceAllUsesWith(Dummy);
+ I->eraseFromParent();
+ }
+ AllPhiNodes.clear();
+ for (auto I : AllSelectNodes) {
+ I->replaceAllUsesWith(Dummy);
+ I->eraseFromParent();
+ }
+ AllSelectNodes.clear();
+ }
};
/// \brief A helper class for combining addressing modes.
@@ -2818,62 +2858,46 @@ private:
// <p, BB3> -> ?
// The function tries to find or build phi [b1, BB1], [b2, BB2] in BB3
Value *findCommon(FoldAddrToValueMapping &Map) {
- // Tracks newly created Phi nodes.
- SmallPtrSet<PHINode *, 32> NewPhiNodes;
- // Tracks newly created Select nodes.
- SmallPtrSet<SelectInst *, 32> NewSelectNodes;
// Tracks the simplification of newly created phi nodes. The reason we use
// this mapping is because we will add new created Phi nodes in AddrToBase.
// Simplification of Phi nodes is recursive, so some Phi node may
// be simplified after we added it to AddrToBase.
// Using this mapping we can find the current value in AddrToBase.
- SimplificationTracker ST(SQ, NewPhiNodes, NewSelectNodes);
+ SimplificationTracker ST(SQ);
// First step, DFS to create PHI nodes for all intermediate blocks.
// Also fill traverse order for the second step.
SmallVector<ValueInBB, 32> TraverseOrder;
- InsertPlaceholders(Map, TraverseOrder, NewPhiNodes, NewSelectNodes);
+ InsertPlaceholders(Map, TraverseOrder, ST);
// Second Step, fill new nodes by merged values and simplify if possible.
FillPlaceholders(Map, TraverseOrder, ST);
- if (!AddrSinkNewSelects && NewSelectNodes.size() > 0) {
- DestroyNodes(NewPhiNodes);
- DestroyNodes(NewSelectNodes);
+ if (!AddrSinkNewSelects && ST.countNewSelectNodes() > 0) {
+ ST.destroyNewNodes(CommonType);
return nullptr;
}
// Now we'd like to match New Phi nodes to existed ones.
unsigned PhiNotMatchedCount = 0;
- if (!MatchPhiSet(NewPhiNodes, ST, AddrSinkNewPhis, PhiNotMatchedCount)) {
- DestroyNodes(NewPhiNodes);
- DestroyNodes(NewSelectNodes);
+ if (!MatchPhiSet(ST, AddrSinkNewPhis, PhiNotMatchedCount)) {
+ ST.destroyNewNodes(CommonType);
return nullptr;
}
auto *Result = ST.Get(Map.find(Original)->second);
if (Result) {
- NumMemoryInstsPhiCreated += NewPhiNodes.size() + PhiNotMatchedCount;
- NumMemoryInstsSelectCreated += NewSelectNodes.size();
+ NumMemoryInstsPhiCreated += ST.countNewPhiNodes() + PhiNotMatchedCount;
+ NumMemoryInstsSelectCreated += ST.countNewSelectNodes();
}
return Result;
}
- /// \brief Destroy nodes from a set.
- template <typename T> void DestroyNodes(SmallPtrSetImpl<T *> &Instructions) {
- // For safe erasing, replace the Phi with dummy value first.
- auto Dummy = UndefValue::get(CommonType);
- for (auto I : Instructions) {
- I->replaceAllUsesWith(Dummy);
- I->eraseFromParent();
- }
- }
-
/// \brief Try to match PHI node to Candidate.
/// Matcher tracks the matched Phi nodes.
bool MatchPhiNode(PHINode *PHI, PHINode *Candidate,
- DenseSet<PHIPair> &Matcher,
- SmallPtrSetImpl<PHINode *> &PhiNodesToMatch) {
+ SmallSetVector<PHIPair, 8> &Matcher,
+ SmallSetVector<PHINode *, 32> &PhiNodesToMatch) {
SmallVector<PHIPair, 8> WorkList;
Matcher.insert({ PHI, Candidate });
WorkList.push_back({ PHI, Candidate });
@@ -2917,13 +2941,16 @@ private:
return true;
}
- /// \brief For the given set of PHI nodes try to find their equivalents.
+ /// \brief For the given set of PHI nodes (in the SimplificationTracker) try
+ /// to find their equivalents.
/// Returns false if this matching fails and creation of new Phi is disabled.
- bool MatchPhiSet(SmallPtrSetImpl<PHINode *> &PhiNodesToMatch,
- SimplificationTracker &ST, bool AllowNewPhiNodes,
+ bool MatchPhiSet(SimplificationTracker &ST, bool AllowNewPhiNodes,
unsigned &PhiNotMatchedCount) {
- DenseSet<PHIPair> Matched;
+ // Use a SetVector for Matched to make sure we do replacements (ReplacePhi)
+ // in a deterministic order below.
+ SmallSetVector<PHIPair, 8> Matched;
SmallPtrSet<PHINode *, 8> WillNotMatch;
+ SmallSetVector<PHINode *, 32> &PhiNodesToMatch = ST.newPhiNodes();
while (PhiNodesToMatch.size()) {
PHINode *PHI = *PhiNodesToMatch.begin();
@@ -2946,25 +2973,9 @@ private:
Matched.clear();
}
if (IsMatched) {
- // If we matched phi node to different but identical phis then
- // make a simplification here.
- DenseMap<PHINode *, PHINode *> MatchedPHINodeMapping;
- for (auto MV : Matched) {
- auto AlreadyMatched = MatchedPHINodeMapping.find(MV.first);
- if (AlreadyMatched != MatchedPHINodeMapping.end()) {
- MV.second->replaceAllUsesWith(AlreadyMatched->second);
- ST.Put(MV.second, AlreadyMatched->second);
- MV.second->eraseFromParent();
- } else
- MatchedPHINodeMapping.insert({ MV.first, MV.second });
- }
// Replace all matched values and erase them.
- for (auto MV : MatchedPHINodeMapping) {
- MV.first->replaceAllUsesWith(MV.second);
- PhiNodesToMatch.erase(MV.first);
- ST.Put(MV.first, MV.second);
- MV.first->eraseFromParent();
- }
+ for (auto MV : Matched)
+ ST.ReplacePhi(MV.first, MV.second);
Matched.clear();
continue;
}
@@ -2974,7 +2985,7 @@ private:
// Just remove all seen values in matcher. They will not match anything.
PhiNotMatchedCount += WillNotMatch.size();
for (auto *P : WillNotMatch)
- PhiNodesToMatch.erase(P);
+ PhiNodesToMatch.remove(P);
}
return true;
}
@@ -3032,8 +3043,7 @@ private:
/// Also reports and order in what basic blocks have been traversed.
void InsertPlaceholders(FoldAddrToValueMapping &Map,
SmallVectorImpl<ValueInBB> &TraverseOrder,
- SmallPtrSetImpl<PHINode *> &NewPhiNodes,
- SmallPtrSetImpl<SelectInst *> &NewSelectNodes) {
+ SimplificationTracker &ST) {
SmallVector<ValueInBB, 32> Worklist;
assert((isa<PHINode>(Original.first) || isa<SelectInst>(Original.first)) &&
"Address must be a Phi or Select node");
@@ -3068,7 +3078,7 @@ private:
PHINode *PHI = PHINode::Create(CommonType, PredCount, "sunk_phi",
&CurrentBlock->front());
Map[Current] = PHI;
- NewPhiNodes.insert(PHI);
+ ST.insertNewPhi(PHI);
// Add all predecessors in work list.
for (auto B : predecessors(CurrentBlock))
Worklist.push_back({ CurrentValue, B });
@@ -3082,7 +3092,7 @@ private:
SelectInst::Create(OrigSelect->getCondition(), Dummy, Dummy,
OrigSelect->getName(), OrigSelect, OrigSelect);
Map[Current] = Select;
- NewSelectNodes.insert(Select);
+ ST.insertNewSelect(Select);
// We are interested in True and False value in this basic block.
Worklist.push_back({ OrigSelect->getTrueValue(), CurrentBlock });
Worklist.push_back({ OrigSelect->getFalseValue(), CurrentBlock });
@@ -3094,7 +3104,7 @@ private:
PHINode *PHI = PHINode::Create(CommonType, PredCount, "sunk_phi",
&CurrentBlock->front());
Map[Current] = PHI;
- NewPhiNodes.insert(PHI);
+ ST.insertNewPhi(PHI);
// Add all predecessors in work list.
for (auto B : predecessors(CurrentBlock))
OpenPOWER on IntegriCloud