[llvm] r262085 - [LVI] Extend select handling to catch min/max/clamp idioms

Chandler Carruth via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 26 19:13:19 PST 2016


On Fri, Feb 26, 2016 at 2:58 PM Philip Reames via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: reames
> Date: Fri Feb 26 16:53:59 2016
> New Revision: 262085
>
> URL: http://llvm.org/viewvc/llvm-project?rev=262085&view=rev
> Log:
> [LVI] Extend select handling to catch min/max/clamp idioms
>
> 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.
>
> 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.
>
> Differential Revision: http://reviews.llvm.org/D17184
>
>
> Modified:
>     llvm/trunk/lib/Analysis/LazyValueInfo.cpp
>     llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll
>
> Modified: llvm/trunk/lib/Analysis/LazyValueInfo.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LazyValueInfo.cpp?rev=262085&r1=262084&r2=262085&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/LazyValueInfo.cpp (original)
> +++ llvm/trunk/lib/Analysis/LazyValueInfo.cpp Fri Feb 26 16:53:59 2016
> @@ -910,6 +910,37 @@ bool LazyValueInfoCache::solveBlockValue
>      return true;
>    }
>
> +  if (TrueVal.isConstantRange() && FalseVal.isConstantRange()) {
> +    ConstantRange TrueCR = TrueVal.getConstantRange();
> +    ConstantRange FalseCR = FalseVal.getConstantRange();
> +    Value *LHS = nullptr;
> +    Value *RHS = nullptr;
> +    SelectPatternResult SPR = matchSelectPattern(SI, LHS, RHS);
> +    // Is this a min specifically of our two inputs?  (Avoid the risk of
> +    // ValueTracking getting smarter looking back past our immediate
> inputs.)
> +    if (SelectPatternResult::isMinOrMax(SPR.Flavor) &&
> +        LHS == SI->getTrueValue() && RHS == SI->getFalseValue()) {
> +      switch (SPR.Flavor) {
> +      default:
> +        llvm_unreachable("unexpected minmax type!");
> +      case SPF_SMIN:                   /// Signed minimum
> +        BBLV.markConstantRange(TrueCR.smin(FalseCR));
> +        return true;
> +      case SPF_UMIN:                   /// Unsigned minimum
> +        BBLV.markConstantRange(TrueCR.umin(FalseCR));
> +        return true;
> +      case SPF_SMAX:                   /// Signed maximum
> +        BBLV.markConstantRange(TrueCR.smax(FalseCR));
> +        return true;
> +      case SPF_UMAX:                   /// Unsigned maximum
> +        BBLV.markConstantRange(TrueCR.umax(FalseCR));
> +        return true;
> +      };
> +    }
> +
> +    // TODO: ABS, NABS from the SelectPatternResult
> +  }
> +
>    // Can we constrain the facts about the true and false values by using
> the
>    // condition itself?  This shows up with idioms like e.g. select(a > 5,
> a, 5).
>    // TODO: We could potentially refine an overdefined true value above.
> @@ -924,10 +955,47 @@ bool LazyValueInfoCache::solveBlockValue
>
>      TrueVal = intersect(TrueVal, TrueValTaken);
>      FalseVal = intersect(FalseVal, FalseValTaken);
> -  }
>
> -  // TODO: handle idioms like min & max where we can use a more precise
> merge
> -  // when our inputs are constant ranges.
> +
> +    // Handle clamp idioms such as:
> +    //   %24 = constantrange<0, 17>
> +    //   %39 = icmp eq i32 %24, 0
> +    //   %40 = add i32 %24, -1
> +    //   %siv.next = select i1 %39, i32 16, i32 %40
> +    //   %siv.next = constantrange<0, 17> not <-1, 17>
> +    // In general, this can handle any clamp idiom which tests the edge
> +    // condition via an equality or inequality.
> +    ICmpInst::Predicate Pred = ICI->getPredicate();
> +    Value *A = ICI->getOperand(0);
> +    if (ConstantInt *CIBase = dyn_cast<ConstantInt>(ICI->getOperand(1))) {
> +      auto addConstants = [](ConstantInt *A, ConstantInt *B) {
> +        assert(A->getType() == B->getType());
> +        return ConstantInt::get(A->getType(), A->getValue() +
> B->getValue());
> +      };
> +      // See if either input is A + C2, subject to the constraint from the
> +      // condition that A != C when that input is used.  We can assume
> that
> +      // that input doesn't include C + C2.
> +      ConstantInt *CIAdded;
> +      switch (Pred) {
>

I now get:

[738/1813] Building CXX object
lib/Analysis/CMakeFiles/LLVMAnalysis.dir/LazyValueInfo.cpp.o
../lib/Analysis/LazyValueInfo.cpp:979:15: warning: 26 enumeration values
not handled in switch: 'FCMP_FALSE', 'FCMP_OEQ', 'FCMP_OGT'... [-Wswitch]
      switch (Pred) {
              ^

Please fix?


> +      case ICmpInst::ICMP_EQ:
> +        if (match(SI->getFalseValue(), m_Add(m_Specific(A),
> +                                             m_ConstantInt(CIAdded)))) {
> +          auto ResNot = addConstants(CIBase, CIAdded);
> +          FalseVal = intersect(FalseVal,
> +                               LVILatticeVal::getNot(ResNot));
> +        }
> +        break;
> +      case ICmpInst::ICMP_NE:
> +        if (match(SI->getTrueValue(), m_Add(m_Specific(A),
> +                                            m_ConstantInt(CIAdded)))) {
> +          auto ResNot = addConstants(CIBase, CIAdded);
> +          TrueVal = intersect(TrueVal,
> +                              LVILatticeVal::getNot(ResNot));
> +        }
> +        break;
> +      };
> +    }
> +  }
>
>    LVILatticeVal Result;  // Start Undefined.
>    Result.mergeIn(TrueVal, DL);
>
> Modified: llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll?rev=262085&r1=262084&r2=262085&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll
> (original)
> +++ llvm/trunk/test/Transforms/CorrelatedValuePropagation/basic.ll Fri Feb
> 26 16:53:59 2016
> @@ -199,3 +199,196 @@ out:
>  next:
>    ret void
>  }
> +
> +define i1 @umin(i32 %a, i32 %b) {
> +; CHECK-LABEL: @umin(
> +entry:
> +  %cmp = icmp ult i32 %a, 5
> +  br i1 %cmp, label %a_guard, label %out
> +
> +a_guard:
> +  %cmp2 = icmp ult i32 %b, 20
> +  br i1 %cmp2, label %b_guard, label %out
> +
> +b_guard:
> +  %sel_cmp = icmp ult i32 %a, %b
> +  %min = select i1 %sel_cmp, i32 %a, i32 %b
> +  %res = icmp eq i32 %min, 7
> +  br label %next
> +next:
> +; CHECK: next:
> +; CHECK: ret i1 false
> +  ret i1 %res
> +out:
> +  ret i1 false
> +}
> +
> +define i1 @smin(i32 %a, i32 %b) {
> +; CHECK-LABEL: @smin(
> +entry:
> +  %cmp = icmp ult i32 %a, 5
> +  br i1 %cmp, label %a_guard, label %out
> +
> +a_guard:
> +  %cmp2 = icmp ult i32 %b, 20
> +  br i1 %cmp2, label %b_guard, label %out
> +
> +b_guard:
> +  %sel_cmp = icmp sle i32 %a, %b
> +  %min = select i1 %sel_cmp, i32 %a, i32 %b
> +  %res = icmp eq i32 %min, 7
> +  br label %next
> +next:
> +; CHECK: next:
> +; CHECK: ret i1 false
> +  ret i1 %res
> +out:
> +  ret i1 false
> +}
> +
> +define i1 @smax(i32 %a, i32 %b) {
> +; CHECK-LABEL: @smax(
> +entry:
> +  %cmp = icmp sgt i32 %a, 5
> +  br i1 %cmp, label %a_guard, label %out
> +
> +a_guard:
> +  %cmp2 = icmp sgt i32 %b, 20
> +  br i1 %cmp2, label %b_guard, label %out
> +
> +b_guard:
> +  %sel_cmp = icmp sge i32 %a, %b
> +  %max = select i1 %sel_cmp, i32 %a, i32 %b
> +  %res = icmp eq i32 %max, 7
> +  br label %next
> +next:
> +; CHECK: next:
> +; CHECK: ret i1 false
> +  ret i1 %res
> +out:
> +  ret i1 false
> +}
> +
> +define i1 @umax(i32 %a, i32 %b) {
> +; CHECK-LABEL: @umax(
> +entry:
> +  %cmp = icmp sgt i32 %a, 5
> +  br i1 %cmp, label %a_guard, label %out
> +
> +a_guard:
> +  %cmp2 = icmp sgt i32 %b, 20
> +  br i1 %cmp2, label %b_guard, label %out
> +
> +b_guard:
> +  %sel_cmp = icmp uge i32 %a, %b
> +  %max = select i1 %sel_cmp, i32 %a, i32 %b
> +  %res = icmp eq i32 %max, 7
> +  br label %next
> +next:
> +; CHECK: next:
> +; CHECK: ret i1 false
> +  ret i1 %res
> +out:
> +  ret i1 false
> +}
> +
> +define i1 @clamp_low1(i32 %a) {
> +; CHECK-LABEL: @clamp_low1(
> +entry:
> +  %cmp = icmp sge i32 %a, 5
> +  br i1 %cmp, label %a_guard, label %out
> +
> +a_guard:
> +  %sel_cmp = icmp eq i32 %a, 5
> +  %add = add i32 %a, -1
> +  %sel = select i1 %sel_cmp, i32 5, i32 %a
> +  %res = icmp eq i32 %sel, 4
> +  br label %next
> +next:
> +; CHECK: next:
> +; CHECK: ret i1 false
> +  ret i1 %res
> +out:
> +  ret i1 false
> +}
> +
> +define i1 @clamp_low2(i32 %a) {
> +; CHECK-LABEL: @clamp_low2(
> +entry:
> +  %cmp = icmp sge i32 %a, 5
> +  br i1 %cmp, label %a_guard, label %out
> +
> +a_guard:
> +  %sel_cmp = icmp ne i32 %a, 5
> +  %add = add i32 %a, -1
> +  %sel = select i1 %sel_cmp, i32 %a, i32 5
> +  %res = icmp eq i32 %sel, 4
> +  br label %next
> +next:
> +; CHECK: next:
> +; CHECK: ret i1 false
> +  ret i1 %res
> +out:
> +  ret i1 false
> +}
> +
> +define i1 @clamp_high1(i32 %a) {
> +; CHECK-LABEL: @clamp_high1(
> +entry:
> +  %cmp = icmp sle i32 %a, 5
> +  br i1 %cmp, label %a_guard, label %out
> +
> +a_guard:
> +  %sel_cmp = icmp eq i32 %a, 5
> +  %add = add i32 %a, 1
> +  %sel = select i1 %sel_cmp, i32 5, i32 %a
> +  %res = icmp eq i32 %sel, 6
> +  br label %next
> +next:
> +; CHECK: next:
> +; CHECK: ret i1 false
> +  ret i1 %res
> +out:
> +  ret i1 false
> +}
> +
> +define i1 @clamp_high2(i32 %a) {
> +; CHECK-LABEL: @clamp_high2(
> +entry:
> +  %cmp = icmp sle i32 %a, 5
> +  br i1 %cmp, label %a_guard, label %out
> +
> +a_guard:
> +  %sel_cmp = icmp ne i32 %a, 5
> +  %add = add i32 %a, 1
> +  %sel = select i1 %sel_cmp, i32 %a, i32 5
> +  %res = icmp eq i32 %sel, 6
> +  br label %next
> +next:
> +; CHECK: next:
> +; CHECK: ret i1 false
> +  ret i1 %res
> +out:
> +  ret i1 false
> +}
> +
> +; Just showing arbitrary constants work, not really a clamp
> +define i1 @clamp_high3(i32 %a) {
> +; CHECK-LABEL: @clamp_high3(
> +entry:
> +  %cmp = icmp sle i32 %a, 5
> +  br i1 %cmp, label %a_guard, label %out
> +
> +a_guard:
> +  %sel_cmp = icmp ne i32 %a, 5
> +  %add = add i32 %a, 100
> +  %sel = select i1 %sel_cmp, i32 %a, i32 5
> +  %res = icmp eq i32 %sel, 105
> +  br label %next
> +next:
> +; CHECK: next:
> +; CHECK: ret i1 false
> +  ret i1 %res
> +out:
> +  ret i1 false
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160227/74792a75/attachment.html>


More information about the llvm-commits mailing list