Teach the new SROA to handle cases where an alloca that has already been
authorChandler Carruth <chandlerc@gmail.com>
Tue, 2 Oct 2012 22:46:45 +0000 (22:46 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Tue, 2 Oct 2012 22:46:45 +0000 (22:46 +0000)
scheduled for processing on the worklist eventually gets deleted while
we are processing another alloca, fixing the original test case in
PR13990.

To facilitate this, add a remove_if helper to the SetVector abstraction.
It's not easy to use the standard abstractions for this because of the
specifics of SetVectors types and implementation.

Finally, a nice small test case is included. Thanks to Benjamin for the
fantastic reduced test case here! All I had to do was delete some empty
basic blocks!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@165065 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ADT/SetVector.h
lib/Transforms/Scalar/SROA.cpp
test/Transforms/SROA/basictest.ll

index acc4daf1468f9d237dccef3d85b767ad43e05bc5..e8d63edf9e5c02f14d530ff64f9d140b3acbfb17 100644 (file)
@@ -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.
index 61d49faf38dcab8d8f1185ad6f920f40280bbf3e..58c3bc0f200e23487e5442ccdd8b4da885f4bdfe 100644 (file)
@@ -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)),
index e58cef63badcd91635351b873fcd829f0a917f4b..54a25df1fbec95c2687770eb34b7432e78cbd5c2 100644 (file)
@@ -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
+}