forked from OSchip/llvm-project
[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:
parent
906deaa0d9
commit
a917fb89dc
|
@ -875,48 +875,6 @@ Optional<ValueLatticeElement> LazyValueInfoImpl::solveBlockValueSelect(
|
||||||
FalseVal = intersect(FalseVal,
|
FalseVal = intersect(FalseVal,
|
||||||
getValueFromCondition(SI->getFalseValue(), Cond, false));
|
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;
|
ValueLatticeElement Result = TrueVal;
|
||||||
Result.mergeIn(FalseVal);
|
Result.mergeIn(FalseVal);
|
||||||
return Result;
|
return Result;
|
||||||
|
@ -1089,6 +1047,13 @@ static bool matchICmpOperand(APInt &Offset, Value *LHS, Value *Val,
|
||||||
return true;
|
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 (x | y) < C, then (x < C) && (y < C).
|
||||||
if (match(LHS, m_c_Or(m_Specific(Val), m_Value())) &&
|
if (match(LHS, m_c_Or(m_Specific(Val), m_Value())) &&
|
||||||
(Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE))
|
(Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE))
|
||||||
|
|
|
@ -587,8 +587,7 @@ define i1 @clamp_low3(i32 %a) {
|
||||||
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sgt i32 [[A]], 5
|
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sgt i32 [[A]], 5
|
||||||
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
|
||||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
|
||||||
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 4
|
; CHECK-NEXT: ret i1 false
|
||||||
; CHECK-NEXT: ret i1 [[RES]]
|
|
||||||
; CHECK: out:
|
; CHECK: out:
|
||||||
; CHECK-NEXT: ret i1 false
|
; 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: [[SEL_CMP:%.*]] = icmp sle i32 [[A]], 5
|
||||||
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
|
||||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
|
||||||
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 4
|
; CHECK-NEXT: ret i1 false
|
||||||
; CHECK-NEXT: ret i1 [[RES]]
|
|
||||||
; CHECK: out:
|
; CHECK: out:
|
||||||
; CHECK-NEXT: ret i1 false
|
; 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: [[SEL_CMP:%.*]] = icmp slt i32 [[A]], 5
|
||||||
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
||||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
|
||||||
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 6
|
; CHECK-NEXT: ret i1 false
|
||||||
; CHECK-NEXT: ret i1 [[RES]]
|
|
||||||
; CHECK: out:
|
; CHECK: out:
|
||||||
; CHECK-NEXT: ret i1 false
|
; 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: [[SEL_CMP:%.*]] = icmp sge i32 [[A]], 5
|
||||||
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
||||||
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
|
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
|
||||||
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[SEL]], 6
|
; CHECK-NEXT: ret i1 false
|
||||||
; CHECK-NEXT: ret i1 [[RES]]
|
|
||||||
; CHECK: out:
|
; CHECK: out:
|
||||||
; CHECK-NEXT: ret i1 false
|
; CHECK-NEXT: ret i1 false
|
||||||
;
|
;
|
||||||
|
|
Loading…
Reference in New Issue