Skip to content

Commit a872293

Browse files
committed
[ValueTracking] Improve isImpliedCondICmps to handle binops
1 parent c4238e6 commit a872293

File tree

12 files changed

+1278
-1577
lines changed

12 files changed

+1278
-1577
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8211,14 +8211,11 @@ isImpliedCondMatchingOperands(CmpInst::Predicate LPred,
82118211
return std::nullopt;
82128212
}
82138213

8214-
/// Return true if "icmp LPred X, LC" implies "icmp RPred X, RC" is true.
8215-
/// Return false if "icmp LPred X, LC" implies "icmp RPred X, RC" is false.
8214+
/// Return true if `X in DomCR` implies `X in CR` is true.
8215+
/// Return false if `X in DomCR` implies `X in CR` is false.
82168216
/// Otherwise, return std::nullopt if we can't infer anything.
8217-
static std::optional<bool> isImpliedCondCommonOperandWithConstants(
8218-
CmpInst::Predicate LPred, const APInt &LC, CmpInst::Predicate RPred,
8219-
const APInt &RC) {
8220-
ConstantRange DomCR = ConstantRange::makeExactICmpRegion(LPred, LC);
8221-
ConstantRange CR = ConstantRange::makeExactICmpRegion(RPred, RC);
8217+
static std::optional<bool> isImpliedCondWithRange(const ConstantRange &DomCR,
8218+
const ConstantRange &CR) {
82228219
ConstantRange Intersection = DomCR.intersectWith(CR);
82238220
ConstantRange Difference = DomCR.difference(CR);
82248221
if (Intersection.isEmptySet())
@@ -8228,6 +8225,17 @@ static std::optional<bool> isImpliedCondCommonOperandWithConstants(
82288225
return std::nullopt;
82298226
}
82308227

8228+
/// Return true if "icmp LPred X, LC" implies "icmp RPred X, RC" is true.
8229+
/// Return false if "icmp LPred X, LC" implies "icmp RPred X, RC" is false.
8230+
/// Otherwise, return std::nullopt if we can't infer anything.
8231+
static std::optional<bool> isImpliedCondCommonOperandWithConstants(
8232+
CmpInst::Predicate LPred, const APInt &LC, CmpInst::Predicate RPred,
8233+
const APInt &RC) {
8234+
ConstantRange DomCR = ConstantRange::makeExactICmpRegion(LPred, LC);
8235+
ConstantRange CR = ConstantRange::makeExactICmpRegion(RPred, RC);
8236+
return isImpliedCondWithRange(DomCR, CR);
8237+
}
8238+
82318239
/// Return true if LHS implies RHS (expanded to its components as "R0 RPred R1")
82328240
/// is true. Return false if LHS implies RHS is false. Otherwise, return
82338241
/// std::nullopt if we can't infer anything.
@@ -8247,8 +8255,36 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
82478255
// Can we infer anything when the 0-operands match and the 1-operands are
82488256
// constants (not necessarily matching)?
82498257
const APInt *LC, *RC;
8250-
if (L0 == R0 && match(L1, m_APInt(LC)) && match(R1, m_APInt(RC)))
8251-
return isImpliedCondCommonOperandWithConstants(LPred, *LC, RPred, *RC);
8258+
if (match(L1, m_APInt(LC)) && match(R1, m_APInt(RC))) {
8259+
if (L0 == R0)
8260+
return isImpliedCondCommonOperandWithConstants(LPred, *LC, RPred, *RC);
8261+
8262+
// handle R0 = L0 binop V and R0 = V binop L0
8263+
Value *R0Op1 = nullptr;
8264+
if (match(R0, m_c_BinOp(m_Specific(L0), m_Value(R0Op1)))) {
8265+
ConstantRange LHSRange = ConstantRange::makeExactICmpRegion(LPred, *LC);
8266+
ConstantRange CR = ConstantRange::makeExactICmpRegion(RPred, *RC);
8267+
// TODO: use contextual information from SimplifyQuery
8268+
ConstantRange RHSRange =
8269+
computeConstantRange(R0Op1, ICmpInst::isSigned(RPred),
8270+
/*UseInstrInfo*/ true, /*AC*/ nullptr,
8271+
/*CtxI*/ nullptr, /*DT*/ nullptr, Depth);
8272+
auto *BO = cast<BinaryOperator>(R0);
8273+
if (BO->getOperand(0) != L0)
8274+
std::swap(LHSRange, RHSRange);
8275+
unsigned NoWrapKind = 0;
8276+
if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(BO)) {
8277+
if (OBO->hasNoUnsignedWrap())
8278+
NoWrapKind |= OverflowingBinaryOperator::NoUnsignedWrap;
8279+
if (OBO->hasNoSignedWrap())
8280+
NoWrapKind |= OverflowingBinaryOperator::NoSignedWrap;
8281+
}
8282+
ConstantRange Range =
8283+
LHSRange.overflowingBinaryOp(BO->getOpcode(), RHSRange, NoWrapKind);
8284+
if (auto Res = isImpliedCondWithRange(Range, CR))
8285+
return Res;
8286+
}
8287+
}
82528288

82538289
// Can we infer anything when the two compares have matching operands?
82548290
bool AreSwappedOps;

llvm/test/Analysis/ValueTracking/implied-icmp-binop.ll

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ define i1 @f_and(i32 %x, i32 %y) {
77
; CHECK-LABEL: define i1 @f_and(
88
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
99
; CHECK-NEXT: entry:
10-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[X]], 0
11-
; CHECK-NEXT: [[TMP0:%.*]] = or i32 [[X]], [[Y]]
12-
; CHECK-NEXT: [[AND14:%.*]] = icmp eq i32 [[TMP0]], 0
13-
; CHECK-NEXT: [[AND1115:%.*]] = and i1 [[CMP]], [[AND14]]
14-
; CHECK-NEXT: ret i1 [[AND1115]]
10+
; CHECK-NEXT: ret i1 false
1511
;
1612
entry:
1713
%cmp = icmp ne i32 %x, 0
@@ -25,11 +21,7 @@ define i1 @f_or(i32 %x, i32 %y) {
2521
; CHECK-LABEL: define i1 @f_or(
2622
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
2723
; CHECK-NEXT: entry:
28-
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[X]], 0
29-
; CHECK-NEXT: [[TMP0:%.*]] = or i32 [[X]], [[Y]]
30-
; CHECK-NEXT: [[OR14:%.*]] = icmp ne i32 [[TMP0]], 0
31-
; CHECK-NEXT: [[OR1115:%.*]] = or i1 [[CMP_NOT]], [[OR14]]
32-
; CHECK-NEXT: ret i1 [[OR1115]]
24+
; CHECK-NEXT: ret i1 true
3325
;
3426
entry:
3527
%cmp.not = icmp eq i32 %x, 0
@@ -45,12 +37,7 @@ define i1 @f_add(i32 %x, i32 %y) {
4537
; CHECK-LABEL: define i1 @f_add(
4638
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
4739
; CHECK-NEXT: entry:
48-
; CHECK-NEXT: [[YR:%.*]] = and i32 [[Y]], 7
49-
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X]], 8
50-
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[YR]], [[X]]
51-
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[TMP0]], 16
52-
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], [[CMP2]]
53-
; CHECK-NEXT: ret i1 [[AND]]
40+
; CHECK-NEXT: ret i1 false
5441
;
5542
entry:
5643
%yr = and i32 %y, 7
@@ -65,12 +52,7 @@ define i1 @f_add_nsw(i32 %x, i32 %y) {
6552
; CHECK-LABEL: define i1 @f_add_nsw(
6653
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
6754
; CHECK-NEXT: entry:
68-
; CHECK-NEXT: [[YR:%.*]] = and i32 [[Y]], 2147483647
69-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], 5
70-
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[YR]], [[X]]
71-
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[TMP0]], 5
72-
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], [[CMP2]]
73-
; CHECK-NEXT: ret i1 [[AND]]
55+
; CHECK-NEXT: ret i1 false
7456
;
7557
entry:
7658
%yr = and i32 %y, 2147483647
@@ -85,11 +67,7 @@ define i1 @f_add_nuw(i32 %x, i32 %y) {
8567
; CHECK-LABEL: define i1 @f_add_nuw(
8668
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
8769
; CHECK-NEXT: entry:
88-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 1
89-
; CHECK-NEXT: [[TMP0:%.*]] = add nuw i32 [[X]], [[Y]]
90-
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP0]], 1
91-
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], [[CMP2]]
92-
; CHECK-NEXT: ret i1 [[AND]]
70+
; CHECK-NEXT: ret i1 false
9371
;
9472
entry:
9573
%cmp = icmp ugt i32 %x, 1
@@ -103,12 +81,8 @@ define i1 @f_sub_nsw(i32 %x, i32 %y) {
10381
; CHECK-LABEL: define i1 @f_sub_nsw(
10482
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
10583
; CHECK-NEXT: entry:
106-
; CHECK-NEXT: [[YR:%.*]] = and i32 [[Y]], 2147483647
10784
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], 5
108-
; CHECK-NEXT: [[TMP0:%.*]] = sub nsw i32 [[X]], [[YR]]
109-
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[TMP0]], 5
110-
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], [[CMP2]]
111-
; CHECK-NEXT: ret i1 [[AND]]
85+
; CHECK-NEXT: ret i1 [[CMP]]
11286
;
11387
entry:
11488
%yr = and i32 %y, 2147483647
@@ -123,11 +97,7 @@ define i1 @f_sub_nuw(i32 %x, i32 %y) {
12397
; CHECK-LABEL: define i1 @f_sub_nuw(
12498
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
12599
; CHECK-NEXT: entry:
126-
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X]], 5
127-
; CHECK-NEXT: [[TMP0:%.*]] = sub nuw i32 [[X]], [[Y]]
128-
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP0]], 6
129-
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], [[CMP2]]
130-
; CHECK-NEXT: ret i1 [[AND]]
100+
; CHECK-NEXT: ret i1 false
131101
;
132102
entry:
133103
%cmp = icmp ult i32 %x, 5
@@ -226,10 +196,7 @@ define i1 @pr69038(i32 %a, i32 %b) {
226196
; CHECK-LABEL: define i1 @pr69038(
227197
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
228198
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[A]], 0
229-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[A]], [[B]]
230-
; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp ne i32 [[OR]], 0
231-
; CHECK-NEXT: [[AND:%.*]] = and i1 [[TOBOOL]], [[TOBOOL1]]
232-
; CHECK-NEXT: ret i1 [[AND]]
199+
; CHECK-NEXT: ret i1 [[TOBOOL]]
233200
;
234201
%tobool = icmp ne i32 %a, 0
235202
%or = or i32 %a, %b

0 commit comments

Comments
 (0)