[LVI] Simplify and generalize handling of clamp patterns

Instead of handling a number of special cases for selects, handle
this generally when inferring ranges from conditions. We already
infer ranges from `x + C pred C2` to `x`, so doing the same for
`x pred C2` to `x + C` is straightforward.
This commit is contained in:
Nikita Popov 2021-03-06 10:24:34 +01:00
parent 906deaa0d9
commit a917fb89dc
2 changed files with 11 additions and 50 deletions

View File

@ -875,48 +875,6 @@ Optional<ValueLatticeElement> LazyValueInfoImpl::solveBlockValueSelect(
FalseVal = intersect(FalseVal,
getValueFromCondition(SI->getFalseValue(), Cond, false));
// 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.
if (auto *ICI = dyn_cast<ICmpInst>(Cond)) {
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) {
default: break;
case ICmpInst::ICMP_EQ:
if (match(SI->getFalseValue(), m_Add(m_Specific(A),
m_ConstantInt(CIAdded)))) {
auto ResNot = addConstants(CIBase, CIAdded);
FalseVal = intersect(FalseVal,
ValueLatticeElement::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,
ValueLatticeElement::getNot(ResNot));
}
break;
};
}
}
ValueLatticeElement Result = TrueVal;
Result.mergeIn(FalseVal);
return Result;
@ -1089,6 +1047,13 @@ static bool matchICmpOperand(APInt &Offset, Value *LHS, Value *Val,
return true;
}
// Handle the symmetric case. This appears in saturation patterns like
// (x == 16) ? 16 : (x + 1).
if (match(Val, m_Add(m_Specific(LHS), m_APInt(C)))) {
Offset = -*C;
return true;
}
// If (x | y) < C, then (x < C) && (y < C).
if (match(LHS, m_c_Or(m_Specific(Val), m_Value())) &&
(Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE))

View File

@ -587,8 +587,7 @@ define i1 @clamp_low3(i32 %a) {
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sgt i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 4
; CHECK-NEXT: ret i1 [[RES]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
@ -615,8 +614,7 @@ define i1 @clamp_low4(i32 %a) {
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sle i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 4
; CHECK-NEXT: ret i1 [[RES]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
@ -697,8 +695,7 @@ define i1 @clamp_high3(i32 %a) {
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp slt i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 6
; CHECK-NEXT: ret i1 [[RES]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
@ -725,8 +722,7 @@ define i1 @clamp_high4(i32 %a) {
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sge i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 6
; CHECK-NEXT: ret i1 [[RES]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;