diff options
-rw-r--r-- | include/llvm/ADT/SetVector.h | 26 | ||||
-rw-r--r-- | lib/Transforms/Scalar/SROA.cpp | 4 | ||||
-rw-r--r-- | test/Transforms/SROA/basictest.ll | 29 |
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 +} |