[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