<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Fri, Feb 26, 2016 at 2:58 PM Philip Reames via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: reames<br>
Date: Fri Feb 26 16:53:59 2016<br>
New Revision: 262085<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=262085&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=262085&view=rev</a><br>
Log:<br>
[LVI] Extend select handling to catch min/max/clamp idioms<br>
<br>
Most of this is fairly straight forward. Add handling for min/max via existing matcher utility and ConstantRange routines.  Add handling for clamp by exploiting condition constraints on inputs.<br>
<br>
Note that I'm only handling two constant ranges at this point. It would be reasonable to consider treating overdefined as a full range if the instruction is typed as an integer, but that should be a separate change.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D17184" rel="noreferrer" target="_blank">http://reviews.llvm.org/D17184</a><br>
<br>
<br>
Modified:<br>
    llvm/trunk/lib/Analysis/LazyValueInfo.cpp<br>
    llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll<br>
<br>
Modified: llvm/trunk/lib/Analysis/LazyValueInfo.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LazyValueInfo.cpp?rev=262085&r1=262084&r2=262085&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LazyValueInfo.cpp?rev=262085&r1=262084&r2=262085&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Analysis/LazyValueInfo.cpp (original)<br>
+++ llvm/trunk/lib/Analysis/LazyValueInfo.cpp Fri Feb 26 16:53:59 2016<br>
@@ -910,6 +910,37 @@ bool LazyValueInfoCache::solveBlockValue<br>
     return true;<br>
   }<br>
<br>
+  if (TrueVal.isConstantRange() && FalseVal.isConstantRange()) {<br>
+    ConstantRange TrueCR = TrueVal.getConstantRange();<br>
+    ConstantRange FalseCR = FalseVal.getConstantRange();<br>
+    Value *LHS = nullptr;<br>
+    Value *RHS = nullptr;<br>
+    SelectPatternResult SPR = matchSelectPattern(SI, LHS, RHS);<br>
+    // Is this a min specifically of our two inputs?  (Avoid the risk of<br>
+    // ValueTracking getting smarter looking back past our immediate inputs.)<br>
+    if (SelectPatternResult::isMinOrMax(SPR.Flavor) &&<br>
+        LHS == SI->getTrueValue() && RHS == SI->getFalseValue()) {<br>
+      switch (SPR.Flavor) {<br>
+      default:<br>
+        llvm_unreachable("unexpected minmax type!");<br>
+      case SPF_SMIN:                   /// Signed minimum<br>
+        BBLV.markConstantRange(TrueCR.smin(FalseCR));<br>
+        return true;<br>
+      case SPF_UMIN:                   /// Unsigned minimum<br>
+        BBLV.markConstantRange(TrueCR.umin(FalseCR));<br>
+        return true;<br>
+      case SPF_SMAX:                   /// Signed maximum<br>
+        BBLV.markConstantRange(TrueCR.smax(FalseCR));<br>
+        return true;<br>
+      case SPF_UMAX:                   /// Unsigned maximum<br>
+        BBLV.markConstantRange(TrueCR.umax(FalseCR));<br>
+        return true;<br>
+      };<br>
+    }<br>
+<br>
+    // TODO: ABS, NABS from the SelectPatternResult<br>
+  }<br>
+<br>
   // Can we constrain the facts about the true and false values by using the<br>
   // condition itself?  This shows up with idioms like e.g. select(a > 5, a, 5).<br>
   // TODO: We could potentially refine an overdefined true value above.<br>
@@ -924,10 +955,47 @@ bool LazyValueInfoCache::solveBlockValue<br>
<br>
     TrueVal = intersect(TrueVal, TrueValTaken);<br>
     FalseVal = intersect(FalseVal, FalseValTaken);<br>
-  }<br>
<br>
-  // TODO: handle idioms like min & max where we can use a more precise merge<br>
-  // when our inputs are constant ranges.<br>
+<br>
+    // Handle clamp idioms such as:<br>
+    //   %24 = constantrange<0, 17><br>
+    //   %39 = icmp eq i32 %24, 0<br>
+    //   %40 = add i32 %24, -1<br>
+    //   %siv.next = select i1 %39, i32 16, i32 %40<br>
+    //   %siv.next = constantrange<0, 17> not <-1, 17><br>
+    // In general, this can handle any clamp idiom which tests the edge<br>
+    // condition via an equality or inequality.<br>
+    ICmpInst::Predicate Pred = ICI->getPredicate();<br>
+    Value *A = ICI->getOperand(0);<br>
+    if (ConstantInt *CIBase = dyn_cast<ConstantInt>(ICI->getOperand(1))) {<br>
+      auto addConstants = [](ConstantInt *A, ConstantInt *B) {<br>
+        assert(A->getType() == B->getType());<br>
+        return ConstantInt::get(A->getType(), A->getValue() + B->getValue());<br>
+      };<br>
+      // See if either input is A + C2, subject to the constraint from the<br>
+      // condition that A != C when that input is used.  We can assume that<br>
+      // that input doesn't include C + C2.<br>
+      ConstantInt *CIAdded;<br>
+      switch (Pred) {<br></blockquote><div><br></div><div>I now get:</div><div><br></div><div><div>[738/1813] Building CXX object lib/Analysis/CMakeFiles/LLVMAnalysis.dir/LazyValueInfo.cpp.o</div><div>../lib/Analysis/LazyValueInfo.cpp:979:15: warning: 26 enumeration values not handled in switch: 'FCMP_FALSE', 'FCMP_OEQ', 'FCMP_OGT'... [-Wswitch]</div><div>      switch (Pred) {</div><div>              ^</div></div><div><br></div><div>Please fix?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      case ICmpInst::ICMP_EQ:<br>
+        if (match(SI->getFalseValue(), m_Add(m_Specific(A),<br>
+                                             m_ConstantInt(CIAdded)))) {<br>
+          auto ResNot = addConstants(CIBase, CIAdded);<br>
+          FalseVal = intersect(FalseVal,<br>
+                               LVILatticeVal::getNot(ResNot));<br>
+        }<br>
+        break;<br>
+      case ICmpInst::ICMP_NE:<br>
+        if (match(SI->getTrueValue(), m_Add(m_Specific(A),<br>
+                                            m_ConstantInt(CIAdded)))) {<br>
+          auto ResNot = addConstants(CIBase, CIAdded);<br>
+          TrueVal = intersect(TrueVal,<br>
+                              LVILatticeVal::getNot(ResNot));<br>
+        }<br>
+        break;<br>
+      };<br>
+    }<br>
+  }<br>
<br>
   LVILatticeVal Result;  // Start Undefined.<br>
   Result.mergeIn(TrueVal, DL);<br>
<br>
Modified: llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll?rev=262085&r1=262084&r2=262085&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll?rev=262085&r1=262084&r2=262085&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll (original)<br>
+++ llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll Fri Feb 26 16:53:59 2016<br>
@@ -199,3 +199,196 @@ out:<br>
 next:<br>
   ret void<br>
 }<br>
+<br>
+define i1 @umin(i32 %a, i32 %b) {<br>
+; CHECK-LABEL: @umin(<br>
+entry:<br>
+  %cmp = icmp ult i32 %a, 5<br>
+  br i1 %cmp, label %a_guard, label %out<br>
+<br>
+a_guard:<br>
+  %cmp2 = icmp ult i32 %b, 20<br>
+  br i1 %cmp2, label %b_guard, label %out<br>
+<br>
+b_guard:<br>
+  %sel_cmp = icmp ult i32 %a, %b<br>
+  %min = select i1 %sel_cmp, i32 %a, i32 %b<br>
+  %res = icmp eq i32 %min, 7<br>
+  br label %next<br>
+next:<br>
+; CHECK: next:<br>
+; CHECK: ret i1 false<br>
+  ret i1 %res<br>
+out:<br>
+  ret i1 false<br>
+}<br>
+<br>
+define i1 @smin(i32 %a, i32 %b) {<br>
+; CHECK-LABEL: @smin(<br>
+entry:<br>
+  %cmp = icmp ult i32 %a, 5<br>
+  br i1 %cmp, label %a_guard, label %out<br>
+<br>
+a_guard:<br>
+  %cmp2 = icmp ult i32 %b, 20<br>
+  br i1 %cmp2, label %b_guard, label %out<br>
+<br>
+b_guard:<br>
+  %sel_cmp = icmp sle i32 %a, %b<br>
+  %min = select i1 %sel_cmp, i32 %a, i32 %b<br>
+  %res = icmp eq i32 %min, 7<br>
+  br label %next<br>
+next:<br>
+; CHECK: next:<br>
+; CHECK: ret i1 false<br>
+  ret i1 %res<br>
+out:<br>
+  ret i1 false<br>
+}<br>
+<br>
+define i1 @smax(i32 %a, i32 %b) {<br>
+; CHECK-LABEL: @smax(<br>
+entry:<br>
+  %cmp = icmp sgt i32 %a, 5<br>
+  br i1 %cmp, label %a_guard, label %out<br>
+<br>
+a_guard:<br>
+  %cmp2 = icmp sgt i32 %b, 20<br>
+  br i1 %cmp2, label %b_guard, label %out<br>
+<br>
+b_guard:<br>
+  %sel_cmp = icmp sge i32 %a, %b<br>
+  %max = select i1 %sel_cmp, i32 %a, i32 %b<br>
+  %res = icmp eq i32 %max, 7<br>
+  br label %next<br>
+next:<br>
+; CHECK: next:<br>
+; CHECK: ret i1 false<br>
+  ret i1 %res<br>
+out:<br>
+  ret i1 false<br>
+}<br>
+<br>
+define i1 @umax(i32 %a, i32 %b) {<br>
+; CHECK-LABEL: @umax(<br>
+entry:<br>
+  %cmp = icmp sgt i32 %a, 5<br>
+  br i1 %cmp, label %a_guard, label %out<br>
+<br>
+a_guard:<br>
+  %cmp2 = icmp sgt i32 %b, 20<br>
+  br i1 %cmp2, label %b_guard, label %out<br>
+<br>
+b_guard:<br>
+  %sel_cmp = icmp uge i32 %a, %b<br>
+  %max = select i1 %sel_cmp, i32 %a, i32 %b<br>
+  %res = icmp eq i32 %max, 7<br>
+  br label %next<br>
+next:<br>
+; CHECK: next:<br>
+; CHECK: ret i1 false<br>
+  ret i1 %res<br>
+out:<br>
+  ret i1 false<br>
+}<br>
+<br>
+define i1 @clamp_low1(i32 %a) {<br>
+; CHECK-LABEL: @clamp_low1(<br>
+entry:<br>
+  %cmp = icmp sge i32 %a, 5<br>
+  br i1 %cmp, label %a_guard, label %out<br>
+<br>
+a_guard:<br>
+  %sel_cmp = icmp eq i32 %a, 5<br>
+  %add = add i32 %a, -1<br>
+  %sel = select i1 %sel_cmp, i32 5, i32 %a<br>
+  %res = icmp eq i32 %sel, 4<br>
+  br label %next<br>
+next:<br>
+; CHECK: next:<br>
+; CHECK: ret i1 false<br>
+  ret i1 %res<br>
+out:<br>
+  ret i1 false<br>
+}<br>
+<br>
+define i1 @clamp_low2(i32 %a) {<br>
+; CHECK-LABEL: @clamp_low2(<br>
+entry:<br>
+  %cmp = icmp sge i32 %a, 5<br>
+  br i1 %cmp, label %a_guard, label %out<br>
+<br>
+a_guard:<br>
+  %sel_cmp = icmp ne i32 %a, 5<br>
+  %add = add i32 %a, -1<br>
+  %sel = select i1 %sel_cmp, i32 %a, i32 5<br>
+  %res = icmp eq i32 %sel, 4<br>
+  br label %next<br>
+next:<br>
+; CHECK: next:<br>
+; CHECK: ret i1 false<br>
+  ret i1 %res<br>
+out:<br>
+  ret i1 false<br>
+}<br>
+<br>
+define i1 @clamp_high1(i32 %a) {<br>
+; CHECK-LABEL: @clamp_high1(<br>
+entry:<br>
+  %cmp = icmp sle i32 %a, 5<br>
+  br i1 %cmp, label %a_guard, label %out<br>
+<br>
+a_guard:<br>
+  %sel_cmp = icmp eq i32 %a, 5<br>
+  %add = add i32 %a, 1<br>
+  %sel = select i1 %sel_cmp, i32 5, i32 %a<br>
+  %res = icmp eq i32 %sel, 6<br>
+  br label %next<br>
+next:<br>
+; CHECK: next:<br>
+; CHECK: ret i1 false<br>
+  ret i1 %res<br>
+out:<br>
+  ret i1 false<br>
+}<br>
+<br>
+define i1 @clamp_high2(i32 %a) {<br>
+; CHECK-LABEL: @clamp_high2(<br>
+entry:<br>
+  %cmp = icmp sle i32 %a, 5<br>
+  br i1 %cmp, label %a_guard, label %out<br>
+<br>
+a_guard:<br>
+  %sel_cmp = icmp ne i32 %a, 5<br>
+  %add = add i32 %a, 1<br>
+  %sel = select i1 %sel_cmp, i32 %a, i32 5<br>
+  %res = icmp eq i32 %sel, 6<br>
+  br label %next<br>
+next:<br>
+; CHECK: next:<br>
+; CHECK: ret i1 false<br>
+  ret i1 %res<br>
+out:<br>
+  ret i1 false<br>
+}<br>
+<br>
+; Just showing arbitrary constants work, not really a clamp<br>
+define i1 @clamp_high3(i32 %a) {<br>
+; CHECK-LABEL: @clamp_high3(<br>
+entry:<br>
+  %cmp = icmp sle i32 %a, 5<br>
+  br i1 %cmp, label %a_guard, label %out<br>
+<br>
+a_guard:<br>
+  %sel_cmp = icmp ne i32 %a, 5<br>
+  %add = add i32 %a, 100<br>
+  %sel = select i1 %sel_cmp, i32 %a, i32 5<br>
+  %res = icmp eq i32 %sel, 105<br>
+  br label %next<br>
+next:<br>
+; CHECK: next:<br>
+; CHECK: ret i1 false<br>
+  ret i1 %res<br>
+out:<br>
+  ret i1 false<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div></div>