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

Sean Silva via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 26 21:10:44 PST 2016


+1. I just came here to say the same thing.

-- Sean Silva

On Fri, Feb 26, 2016 at 7:13 PM, Chandler Carruth via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> 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
>>
>
> _______________________________________________
> 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/20160226/0570350d/attachment.html>


More information about the llvm-commits mailing list