Teach ScalarEvolution to sharpen range information.
authorSanjoy Das <sanjoy@playingwithpointers.com>
Wed, 15 Oct 2014 19:25:28 +0000 (19:25 +0000)
committerSanjoy Das <sanjoy@playingwithpointers.com>
Wed, 15 Oct 2014 19:25:28 +0000 (19:25 +0000)
If x is known to have the range [a, b) in a loop predicated by (icmp
ne x, a), its range can be sharpened to [a + 1, b).  Get
ScalarEvolution and hence IndVars to exploit this fact.

This change triggers an optimization to widen-loop-comp.ll, so it had
to be edited to get it to pass.

phabricator: http://reviews.llvm.org/D5639

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

lib/Analysis/ScalarEvolution.cpp
test/Transforms/IndVarSimplify/sharpen-range-metadata.ll [new file with mode: 0644]
test/Transforms/IndVarSimplify/widen-loop-comp.ll

index b015481b76cc38786fd343b878b8fcf0ffef176a..8d1c632008a21be6d6a0d6cc3a3ec2b315bbb56e 100644 (file)
@@ -6782,6 +6782,44 @@ bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred,
                                    RHS, LHS, FoundLHS, FoundRHS);
   }
 
+  if (FoundPred == ICmpInst::ICMP_NE) {
+    // If we are predicated on something with range [a, b) known not
+    // equal to a, the range can be sharpened to [a + 1, b).  Use this
+    // fact.
+    auto CheckRange = [this, Pred, LHS, RHS](const SCEV *C, const SCEV *V) {
+      if (!isa<SCEVConstant>(C)) return false;
+
+      ConstantInt *CI = cast<SCEVConstant>(C)->getValue();
+      APInt Min = ICmpInst::isSigned(Pred) ?
+        getSignedRange(V).getSignedMin() : getUnsignedRange(V).getUnsignedMin();
+
+      if (Min!= CI->getValue()) return false; // nothing to sharpen
+      Min++;
+
+      // We know V >= Min, in the same signedness as in Pred.  We can
+      // use this to simplify slt and ult.  If the range had a single
+      // value, Min, we now know that FoundValue can never be true;
+      // and any answer is a correct answer.
+
+      switch (Pred) {
+        case ICmpInst::ICMP_SGT:
+        case ICmpInst::ICMP_UGT:
+          return isImpliedCondOperands(Pred, LHS, RHS, V, getConstant(Min));
+
+        default:
+          llvm_unreachable("don't call with predicates other than ICMP_SGT "
+                           "and ICMP_UGT");
+      }
+    };
+
+    if ((Pred == ICmpInst::ICMP_SGT) || (Pred == ICmpInst::ICMP_UGT)) {
+      // Inequality is reflexive -- check both the combinations.
+      if (CheckRange(FoundLHS, FoundRHS) || CheckRange(FoundRHS, FoundLHS)) {
+        return true;
+      }
+    }
+  }
+
   // Check whether the actual condition is beyond sufficient.
   if (FoundPred == ICmpInst::ICMP_EQ)
     if (ICmpInst::isTrueWhenEqual(Pred))
diff --git a/test/Transforms/IndVarSimplify/sharpen-range-metadata.ll b/test/Transforms/IndVarSimplify/sharpen-range-metadata.ll
new file mode 100644 (file)
index 0000000..5faafe6
--- /dev/null
@@ -0,0 +1,39 @@
+;; RUN: opt -S < %s -indvars | FileCheck %s
+
+;; Check if llvm can narrow !range metadata based on loop entry
+;; predicates.
+
+declare void @abort()
+
+define i1 @bounded_below(i32* nocapture readonly %buffer) {
+entry:
+  %length = load i32* %buffer, !range !0
+  %entry.pred = icmp eq i32 %length, 0
+  br i1 %entry.pred, label %abort, label %loop.preheader
+
+loop.preheader:
+  br label %loop
+
+loop:
+  %idx = phi i32 [ %idx.inc, %loop.next ], [ 0, %loop.preheader ]
+  %oob.pred = icmp slt i32 %idx, %length
+  br i1 %oob.pred, label %loop.next, label %oob
+; CHECK: br i1 true, label %loop.next, label %oob
+
+loop.next:
+  %idx.inc = add i32 %idx, 1
+  %exit.pred = icmp slt i32 %idx.inc, %length
+  br i1 %exit.pred, label %loop, label %abort.loopexit
+
+abort.loopexit:
+  br label %abort
+
+abort:
+  ret i1 false
+
+oob:
+  tail call void @abort()
+  ret i1 false
+}
+
+!0 = metadata !{i32 0, i32 100}
index bfe74afe8940fd0f26e2eee28dc6e885bc95f3db..0930a0c413904a9378caf27c4d78ef4ecfd505cc 100644 (file)
@@ -67,8 +67,7 @@ for.end:
 define void @test2([8 x i8]* %a, i8* %b, i8 %limit) {
 entry:
   %conv = zext i8 %limit to i32
-  %cmp23 = icmp eq i8 %limit, 0
-  br i1 %cmp23, label %for.cond1.preheader, label %for.cond1.preheader.us
+  br i1 undef, label %for.cond1.preheader, label %for.cond1.preheader.us
 
 for.cond1.preheader.us:
   %storemerge5.us = phi i32 [ 0, %entry ], [ %inc14.us, %for.inc13.us ]