<div dir="ltr">This seems to have broken gcc builds: <div><a href="http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fuzzer/builds/679/steps/build%20clang/logs/stdio">http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fuzzer/builds/679/steps/build%20clang/logs/stdio</a><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Mar 4, 2015 at 2:24 PM, Sanjoy Das <span dir="ltr"><<a href="mailto:sanjoy@playingwithpointers.com" target="_blank">sanjoy@playingwithpointers.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: sanjoy<br>
Date: Wed Mar  4 16:24:17 2015<br>
New Revision: 231305<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=231305&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=231305&view=rev</a><br>
Log:<br>
[SCEV] make SCEV smarter about proving no-wrap.<br>
<br>
Summary:<br>
Teach SCEV to prove no overflow for an add recurrence by proving<br>
something about the range of another add recurrence a loop-invariant<br>
distance away from it.<br>
<br>
Reviewers: atrick, hfinkel<br>
<br>
Subscribers: llvm-commits<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D7980" target="_blank">http://reviews.llvm.org/D7980</a><br>
<br>
Added:<br>
    llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll<br>
Modified:<br>
    llvm/trunk/include/llvm/Analysis/ScalarEvolution.h<br>
    llvm/trunk/lib/Analysis/ScalarEvolution.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolution.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolution.h?rev=231305&r1=231304&r2=231305&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolution.h?rev=231305&r1=231304&r2=231305&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Analysis/ScalarEvolution.h (original)<br>
+++ llvm/trunk/include/llvm/Analysis/ScalarEvolution.h Wed Mar  4 16:24:17 2015<br>
@@ -561,6 +561,15 @@ namespace llvm {<br>
     /// pointer.<br>
     bool checkValidity(const SCEV *S) const;<br>
<br>
+    // Return true if `ExtendOpTy`({`Start`,+,`Step`}) can be proved to be equal<br>
+    // to {`ExtendOpTy`(`Start`),+,`ExtendOpTy`(`Step`)}.  This is equivalent to<br>
+    // proving no signed (resp. unsigned) wrap in {`Start`,+,`Step`} if<br>
+    // `ExtendOpTy` is `SCEVSignExtendExpr` (resp. `SCEVZeroExtendExpr`).<br>
+    //<br>
+    template<typename ExtendOpTy><br>
+    bool proveNoWrapByVaryingStart(const SCEV *Start, const SCEV *Step,<br>
+                                   const Loop *L);<br>
+<br>
   public:<br>
     static char ID; // Pass identification, replacement for typeid<br>
     ScalarEvolution();<br>
<br>
Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=231305&r1=231304&r2=231305&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=231305&r1=231304&r2=231305&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original)<br>
+++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Wed Mar  4 16:24:17 2015<br>
@@ -1325,6 +1325,85 @@ static const SCEV *getExtendAddRecStart(<br>
                         (SE->*GetExtendExpr)(PreStart, Ty));<br>
 }<br>
<br>
+// Try to prove away overflow by looking at "nearby" add recurrences.  A<br>
+// motivating example for this rule: if we know `{0,+,4}` is `ult` `-1` and it<br>
+// does not itself wrap then we can conclude that `{1,+,4}` is `nuw`.<br>
+//<br>
+// Formally:<br>
+//<br>
+//     {S,+,X} == {S-T,+,X} + T<br>
+//  => Ext({S,+,X}) == Ext({S-T,+,X} + T)<br>
+//<br>
+// If ({S-T,+,X} + T) does not overflow  ... (1)<br>
+//<br>
+//  RHS == Ext({S-T,+,X} + T) == Ext({S-T,+,X}) + Ext(T)<br>
+//<br>
+// If {S-T,+,X} does not overflow  ... (2)<br>
+//<br>
+//  RHS == Ext({S-T,+,X}) + Ext(T) == {Ext(S-T),+,Ext(X)} + Ext(T)<br>
+//      == {Ext(S-T)+Ext(T),+,Ext(X)}<br>
+//<br>
+// If (S-T)+T does not overflow  ... (3)<br>
+//<br>
+//  RHS == {Ext(S-T)+Ext(T),+,Ext(X)} == {Ext(S-T+T),+,Ext(X)}<br>
+//      == {Ext(S),+,Ext(X)} == LHS<br>
+//<br>
+// Thus, if (1), (2) and (3) are true for some T, then<br>
+//   Ext({S,+,X}) == {Ext(S),+,Ext(X)}<br>
+//<br>
+// (3) is implied by (1) -- "(S-T)+T does not overflow" is simply "({S-T,+,X}+T)<br>
+// does not overflow" restricted to the 0th iteration.  Therefore we only need<br>
+// to check for (1) and (2).<br>
+//<br>
+// In the current context, S is `Start`, X is `Step`, Ext is `ExtendOpTy` and T<br>
+// is `Delta` (defined below).<br>
+//<br>
+template <typename ExtendOpTy><br>
+bool ScalarEvolution::proveNoWrapByVaryingStart(const SCEV *Start,<br>
+                                                const SCEV *Step,<br>
+                                                const Loop *L) {<br>
+  auto WrapType = ExtendOpTraits<ExtendOpTy>::WrapType;<br>
+<br>
+  // We restrict `Start` to a constant to prevent SCEV from spending too much<br>
+  // time here.  It is correct (but more expensive) to continue with a<br>
+  // non-constant `Start` and do a general SCEV subtraction to compute<br>
+  // `PreStart` below.<br>
+  //<br>
+  const SCEVConstant *StartC = dyn_cast<SCEVConstant>(Start);<br>
+  if (!StartC)<br>
+    return false;<br>
+<br>
+  APInt StartAI = StartC->getValue()->getValue();<br>
+<br>
+  for (unsigned Delta : {-2, -1, 1, 2}) {<br>
+    const SCEV *PreStart = getConstant(StartAI - Delta);<br>
+<br>
+    // Give up if we don't already have the add recurrence we need because<br>
+    // actually constructing an add recurrence is relatively expensive.<br>
+    const SCEVAddRecExpr *PreAR = [&]() {<br>
+      FoldingSetNodeID ID;<br>
+      ID.AddInteger(scAddRecExpr);<br>
+      ID.AddPointer(PreStart);<br>
+      ID.AddPointer(Step);<br>
+      ID.AddPointer(L);<br>
+      void *IP = nullptr;<br>
+      return static_cast<SCEVAddRecExpr *>(<br>
+        UniqueSCEVs.FindNodeOrInsertPos(ID, IP));<br>
+    }();<br>
+<br>
+    if (PreAR && PreAR->getNoWrapFlags(WrapType)) {  // proves (2)<br>
+      const SCEV *DeltaS = getConstant(StartC->getType(), Delta);<br>
+      ICmpInst::Predicate Pred = ICmpInst::BAD_ICMP_PREDICATE;<br>
+      const SCEV *Limit = ExtendOpTraits<ExtendOpTy>::getOverflowLimitForStep(<br>
+          DeltaS, &Pred, this);<br>
+      if (Limit && isKnownPredicate(Pred, PreAR, Limit))  // proves (1)<br>
+        return true;<br>
+    }<br>
+  }<br>
+<br>
+  return false;<br>
+}<br>
+<br>
 const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,<br>
                                                Type *Ty) {<br>
   assert(getTypeSizeInBits(Op->getType()) < getTypeSizeInBits(Ty) &&<br>
@@ -1473,6 +1552,13 @@ const SCEV *ScalarEvolution::getZeroExte<br>
           }<br>
         }<br>
       }<br>
+<br>
+      if (proveNoWrapByVaryingStart<SCEVZeroExtendExpr>(Start, Step, L)) {<br>
+        const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNUW);<br>
+        return getAddRecExpr(<br>
+            getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this),<br>
+            getZeroExtendExpr(Step, Ty), L, AR->getNoWrapFlags());<br>
+      }<br>
     }<br>
<br>
   // The cast wasn't folded; create an explicit cast node.<br>
@@ -1664,6 +1750,13 @@ const SCEV *ScalarEvolution::getSignExte<br>
           return getAddExpr(Start, getSignExtendExpr(NewAR, Ty));<br>
         }<br>
       }<br>
+<br>
+      if (proveNoWrapByVaryingStart<SCEVSignExtendExpr>(Start, Step, L)) {<br>
+        const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNSW);<br>
+        return getAddRecExpr(<br>
+            getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this),<br>
+            getSignExtendExpr(Step, Ty), L, AR->getNoWrapFlags());<br>
+      }<br>
     }<br>
<br>
   // The cast wasn't folded; create an explicit cast node.<br>
<br>
Added: llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll?rev=231305&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll?rev=231305&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll (added)<br>
+++ llvm/trunk/test/Analysis/ScalarEvolution/nowrap-preinc-limits.ll Wed Mar  4 16:24:17 2015<br>
@@ -0,0 +1,44 @@<br>
+; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s<br>
+<br>
+define void @f(i1* %condition) {<br>
+; CHECK-LABEL: Classifying expressions for: @f<br>
+ entry:<br>
+  br label %loop<br>
+<br>
+ loop:<br>
+  %idx = phi i32 [ 0, %entry ], [ %idx.inc, %loop ]<br>
+  %idx.inc = add nsw i32 %idx, 1<br>
+<br>
+  %idx.inc2 = add i32 %idx.inc, 1<br>
+  %idx.inc2.zext = zext i32 %idx.inc2 to i64<br>
+<br>
+; CHECK: %idx.inc2.zext = zext i32 %idx.inc2 to i64<br>
+; CHECK-NEXT: -->  {2,+,1}<nuw><%loop><br>
+<br>
+  %c = load volatile i1, i1* %condition<br>
+  br i1 %c, label %loop, label %exit<br>
+<br>
+ exit:<br>
+  ret void<br>
+}<br>
+<br>
+define void @g(i1* %condition) {<br>
+; CHECK-LABEL: Classifying expressions for: @g<br>
+ entry:<br>
+  br label %loop<br>
+<br>
+ loop:<br>
+  %idx = phi i32 [ 0, %entry ], [ %idx.inc, %loop ]<br>
+  %idx.inc = add nsw i32 %idx, 3<br>
+<br>
+  %idx.inc2 = add i32 %idx.inc, -1<br>
+  %idx.inc2.sext = sext i32 %idx.inc2 to i64<br>
+; CHECK: %idx.inc2.sext = sext i32 %idx.inc2 to i64<br>
+; CHECK-NEXT: -->  {2,+,3}<nuw><nsw><%loop><br>
+<br>
+  %c = load volatile i1, i1* %condition<br>
+  br i1 %c, label %loop, label %exit<br>
+<br>
+ exit:<br>
+  ret void<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>