SCEV: Add MarkPendingLoopPredicates to avoid recursive isImpliedCond.
authorAndrew Trick <atrick@apple.com>
Sat, 19 May 2012 00:48:25 +0000 (00:48 +0000)
committerAndrew Trick <atrick@apple.com>
Sat, 19 May 2012 00:48:25 +0000 (00:48 +0000)
getUDivExpr attempts to simplify by checking for overflow.
isLoopEntryGuardedByCond then evaluates the loop predicate which
may lead to the same getUDivExpr causing endless recursion.

Fixes PR12868: clang 3.2 segmentation fault.

llvm-svn: 157092

llvm/include/llvm/Analysis/ScalarEvolution.h
llvm/lib/Analysis/ScalarEvolution.cpp
llvm/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll [new file with mode: 0644]

index 72408f7..8f87b58 100644 (file)
@@ -30,7 +30,7 @@
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/ConstantRange.h"
 #include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include <map>
 
 namespace llvm {
@@ -250,6 +250,9 @@ namespace llvm {
     ///
     ValueExprMapType ValueExprMap;
 
+    /// Mark predicate values currently being processed by isImpliedCond.
+    DenseSet<Value*> PendingLoopPredicates;
+
     /// ExitLimit - Information about the number of loop iterations for
     /// which a loop exit's branch condition evaluates to the not-taken path.
     /// This is a temporary pair of exact and max expressions that are
index d1ad8e0..4e3dc60 100644 (file)
@@ -6039,12 +6039,34 @@ ScalarEvolution::isLoopEntryGuardedByCond(const Loop *L,
   return false;
 }
 
+/// RAII wrapper to prevent recursive application of isImpliedCond.
+/// ScalarEvolution's PendingLoopPredicates set must be empty unless we are
+/// currently evaluating isImpliedCond.
+struct MarkPendingLoopPredicate {
+  Value *Cond;
+  DenseSet<Value*> &LoopPreds;
+  bool Pending;
+
+  MarkPendingLoopPredicate(Value *C, DenseSet<Value*> &LP)
+    : Cond(C), LoopPreds(LP) {
+    Pending = !LoopPreds.insert(Cond).second;
+  }
+  ~MarkPendingLoopPredicate() {
+    if (!Pending)
+      LoopPreds.erase(Cond);
+  }
+};
+
 /// isImpliedCond - Test whether the condition described by Pred, LHS,
 /// and RHS is true whenever the given Cond value evaluates to true.
 bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred,
                                     const SCEV *LHS, const SCEV *RHS,
                                     Value *FoundCondValue,
                                     bool Inverse) {
+  MarkPendingLoopPredicate Mark(FoundCondValue, PendingLoopPredicates);
+  if (Mark.Pending)
+    return false;
+
   // Recursively handle And and Or conditions.
   if (BinaryOperator *BO = dyn_cast<BinaryOperator>(FoundCondValue)) {
     if (BO->getOpcode() == Instruction::And) {
@@ -6571,6 +6593,8 @@ void ScalarEvolution::releaseMemory() {
     I->second.clear();
   }
 
+  assert(PendingLoopPredicates.empty() && "isImpliedCond garbage");
+
   BackedgeTakenCounts.clear();
   ConstantEvolutionLoopExitValue.clear();
   ValuesAtScopes.clear();
diff --git a/llvm/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll b/llvm/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll
new file mode 100644 (file)
index 0000000..52e6683
--- /dev/null
@@ -0,0 +1,30 @@
+; RUN: opt < %s -iv-users -S -disable-output
+;
+; PR12868: Infinite recursion:
+; getUDivExpr()->getZeroExtendExpr()->isLoopBackedgeGuardedBy()
+;
+; We actually want SCEV simplification to fail gracefully in this
+; case, so there's no output to check, just the absense of stack overflow.
+
+@c = common global i8 0, align 1
+
+define i32 @func() {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.body, %entry
+  %storemerge = phi i8 [ -1, %entry ], [ %inc, %for.body ]
+  %ui.0 = phi i32 [ undef, %entry ], [ %div, %for.body ]
+  %tobool = icmp eq i8 %storemerge, 0
+  br i1 %tobool, label %for.end, label %for.body
+
+for.body:                                         ; preds = %for.cond
+  %conv = sext i8 %storemerge to i32
+  %div = lshr i32 %conv, 1
+  %tobool2 = icmp eq i32 %div, 0
+  %inc = add i8 %storemerge, 1
+  br i1 %tobool2, label %for.cond, label %for.end
+
+for.end:                                          ; preds = %for.body, %for.cond
+  ret i32 0
+}