aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/ADT/SetVector.h26
-rw-r--r--lib/Transforms/Scalar/SROA.cpp4
-rw-r--r--test/Transforms/SROA/basictest.ll29
3 files changed, 59 insertions, 0 deletions
diff --git a/include/llvm/ADT/SetVector.h b/include/llvm/ADT/SetVector.h
index acc4daf..e8d63ed 100644
--- a/include/llvm/ADT/SetVector.h
+++ b/include/llvm/ADT/SetVector.h
@@ -126,6 +126,32 @@ public:
return false;
}
+ /// \brief Remove items from the set vector based on a predicate function.
+ ///
+ /// This is intended to be equivalent to the following code, if we could
+ /// write it:
+ ///
+ /// \code
+ /// V.erase(std::remove_if(V.begin(), V.end(), P), V.end());
+ /// \endcode
+ ///
+ /// However, SetVector doesn't expose non-const iterators, making any
+ /// algorithm like remove_if impossible to use.
+ ///
+ /// \returns true if any element is removed.
+ template <typename UnaryPredicate>
+ bool remove_if(UnaryPredicate P) {
+ typename vector_type::iterator B = std::remove_if(vector_.begin(),
+ vector_.end(), P),
+ E = vector_.end();
+ if (B == E)
+ return false;
+ for (typename vector_type::iterator I = B; I != E; ++I)
+ set_.erase(*I);
+ vector_.erase(B, E);
+ return true;
+ }
+
/// \brief Count the number of elements of a given key in the SetVector.
/// \returns 0 if the element is not in the SetVector, 1 if it is.
diff --git a/lib/Transforms/Scalar/SROA.cpp b/lib/Transforms/Scalar/SROA.cpp
index 61d49fa..58c3bc0 100644
--- a/lib/Transforms/Scalar/SROA.cpp
+++ b/lib/Transforms/Scalar/SROA.cpp
@@ -3302,7 +3302,11 @@ bool SROA::runOnFunction(Function &F) {
while (!Worklist.empty()) {
Changed |= runOnAlloca(*Worklist.pop_back_val());
deleteDeadInstructions(DeletedAllocas);
+
+ // Remove the deleted allocas from various lists so that we don't try to
+ // continue processing them.
if (!DeletedAllocas.empty()) {
+ Worklist.remove_if(IsAllocaInSet(DeletedAllocas));
PromotableAllocas.erase(std::remove_if(PromotableAllocas.begin(),
PromotableAllocas.end(),
IsAllocaInSet(DeletedAllocas)),
diff --git a/test/Transforms/SROA/basictest.ll b/test/Transforms/SROA/basictest.ll
index e58cef6..54a25df 100644
--- a/test/Transforms/SROA/basictest.ll
+++ b/test/Transforms/SROA/basictest.ll
@@ -897,3 +897,32 @@ if.end:
%tmp2 = load i8* %gep
ret void
}
+
+define void @PR13990() {
+; Ensure we can handle cases where processing one alloca causes the other
+; alloca to become dead and get deleted. This might crash or fail under
+; Valgrind if we regress.
+; CHECK: @PR13990
+; CHECK-NOT: alloca
+; CHECK: unreachable
+; CHECK: unreachable
+
+entry:
+ %tmp1 = alloca i8*
+ %tmp2 = alloca i8*
+ br i1 undef, label %bb1, label %bb2
+
+bb1:
+ store i8* undef, i8** %tmp2
+ br i1 undef, label %bb2, label %bb3
+
+bb2:
+ %tmp50 = select i1 undef, i8** %tmp2, i8** %tmp1
+ br i1 undef, label %bb3, label %bb4
+
+bb3:
+ unreachable
+
+bb4:
+ unreachable
+}