Skip to content

Commit 7c96469

Browse files
committed
[ValueTracking] Extend LHS/RHS with matching operand to work without constants.
Previously we only handled the `L0 == R0` case if both `L1` and `R1` where constant. We can get more out of the analysis using general constant ranges instead. For example, `X u> Y` implies `X != 0`. In general, any strict comparison on `X` implies that `X` is not equal to the boundary value for the sign and constant ranges with/without sign bits can be useful in deducing implications. Closes #85557
1 parent fb7f65b commit 7c96469

File tree

5 files changed

+53
-47
lines changed

5 files changed

+53
-47
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8857,20 +8857,20 @@ isImpliedCondMatchingOperands(CmpInst::Predicate LPred,
88578857
return std::nullopt;
88588858
}
88598859

8860-
/// Return true if "icmp LPred X, LC" implies "icmp RPred X, RC" is true.
8861-
/// Return false if "icmp LPred X, LC" implies "icmp RPred X, RC" is false.
8860+
/// Return true if "icmp LPred X, LCR" implies "icmp RPred X, RCR" is true.
8861+
/// Return false if "icmp LPred X, LCR" implies "icmp RPred X, RCR" is false.
88628862
/// Otherwise, return std::nullopt if we can't infer anything.
8863-
static std::optional<bool> isImpliedCondCommonOperandWithConstants(
8864-
CmpInst::Predicate LPred, const APInt &LC, CmpInst::Predicate RPred,
8865-
const APInt &RC) {
8866-
ConstantRange DomCR = ConstantRange::makeExactICmpRegion(LPred, LC);
8867-
ConstantRange CR = ConstantRange::makeExactICmpRegion(RPred, RC);
8868-
ConstantRange Intersection = DomCR.intersectWith(CR);
8869-
ConstantRange Difference = DomCR.difference(CR);
8870-
if (Intersection.isEmptySet())
8871-
return false;
8872-
if (Difference.isEmptySet())
8863+
static std::optional<bool> isImpliedCondCommonOperandWithCR(
8864+
CmpInst::Predicate LPred, const ConstantRange &LCR,
8865+
CmpInst::Predicate RPred, const ConstantRange &RCR) {
8866+
ConstantRange DomCR = ConstantRange::makeAllowedICmpRegion(LPred, LCR);
8867+
// If all true values for lhs and true for rhs, lhs implies rhs
8868+
if (DomCR.icmp(RPred, RCR))
88738869
return true;
8870+
8871+
// If there is no overlap, lhs implies not rhs
8872+
if (DomCR.icmp(CmpInst::getInversePredicate(RPred), RCR))
8873+
return false;
88748874
return std::nullopt;
88758875
}
88768876

@@ -8910,11 +8910,29 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
89108910
}
89118911
}
89128912

8913-
// Can we infer anything when the 0-operands match and the 1-operands are
8914-
// constants (not necessarily matching)?
8915-
const APInt *LC, *RC;
8916-
if (L0 == R0 && match(L1, m_APInt(LC)) && match(R1, m_APInt(RC)))
8917-
return isImpliedCondCommonOperandWithConstants(LPred, *LC, RPred, *RC);
8913+
// See if we can infer anything if operand-0 matches and we have at least one
8914+
// constant.
8915+
const APInt *Unused;
8916+
if (L0 == R0 && (match(L1, m_APInt(Unused)) || match(R1, m_APInt(Unused)))) {
8917+
// Potential TODO: We could also further use the constant range of L0/R0 to
8918+
// further constraint the constant ranges. At the moment this leads to
8919+
// several regressions related to not transforming `multi_use(A + C0) eq/ne
8920+
// C1` (see discussion: D58633).
8921+
ConstantRange LCR = computeConstantRange(
8922+
L1, ICmpInst::isSigned(LPred), /* UseInstrInfo=*/true, /*AC=*/nullptr,
8923+
/*CxtI=*/nullptr, /*DT=*/nullptr, MaxAnalysisRecursionDepth - 1);
8924+
ConstantRange RCR = computeConstantRange(
8925+
R1, ICmpInst::isSigned(RPred), /* UseInstrInfo=*/true, /*AC=*/nullptr,
8926+
/*CxtI=*/nullptr, /*DT=*/nullptr, MaxAnalysisRecursionDepth - 1);
8927+
// Even if L1/R1 are not both constant, we can still sometimes deduce
8928+
// relationship from a single constant. For example X u> Y implies X != 0.
8929+
if (auto R = isImpliedCondCommonOperandWithCR(LPred, LCR, RPred, RCR))
8930+
return R;
8931+
// If both L1/R1 were exact constant ranges and we didn't get anything
8932+
// here, we won't be able to deduce this.
8933+
if (match(L1, m_APInt(Unused)) && match(R1, m_APInt(Unused)))
8934+
return std::nullopt;
8935+
}
89188936

89198937
// Can we infer anything when the two compares have matching operands?
89208938
if (L0 == R0 && L1 == R1)

llvm/test/Transforms/InstCombine/icmp-select-implies-common-op.ll

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ define i1 @sgt_3_impliesT_sgt_2(i8 %x, i8 %y) {
2929

3030
define i1 @sgt_x_impliesF_eq_smin_todo(i8 %x, i8 %y, i8 %z) {
3131
; CHECK-LABEL: @sgt_x_impliesF_eq_smin_todo(
32-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], [[Z:%.*]]
33-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 -128, i8 [[Y:%.*]]
34-
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[SEL]], [[X]]
35-
; CHECK-NEXT: ret i1 [[CMP2]]
32+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X:%.*]], [[Z:%.*]]
33+
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[SEL:%.*]], [[X]]
34+
; CHECK-NEXT: [[CMP3:%.*]] = select i1 [[CMP]], i1 [[CMP2]], i1 false
35+
; CHECK-NEXT: ret i1 [[CMP3]]
3636
;
3737
%cmp = icmp sgt i8 %x, %z
3838
%sel = select i1 %cmp, i8 -128, i8 %y
@@ -43,9 +43,9 @@ define i1 @sgt_x_impliesF_eq_smin_todo(i8 %x, i8 %y, i8 %z) {
4343
define i1 @slt_x_impliesT_ne_smin_todo(i8 %x, i8 %y, i8 %z) {
4444
; CHECK-LABEL: @slt_x_impliesT_ne_smin_todo(
4545
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], [[Z:%.*]]
46-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 127, i8 [[Y:%.*]]
47-
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[SEL]], [[X]]
48-
; CHECK-NEXT: ret i1 [[CMP2]]
46+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[SEL:%.*]], [[X]]
47+
; CHECK-NEXT: [[CMP3:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP2]]
48+
; CHECK-NEXT: ret i1 [[CMP3]]
4949
;
5050
%cmp = icmp slt i8 %x, %z
5151
%sel = select i1 %cmp, i8 127, i8 %y
@@ -56,9 +56,9 @@ define i1 @slt_x_impliesT_ne_smin_todo(i8 %x, i8 %y, i8 %z) {
5656
define i1 @ult_x_impliesT_eq_umax_todo(i8 %x, i8 %y, i8 %z) {
5757
; CHECK-LABEL: @ult_x_impliesT_eq_umax_todo(
5858
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[Z:%.*]], [[X:%.*]]
59-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 -1, i8 [[Y:%.*]]
60-
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[SEL]], [[X]]
61-
; CHECK-NEXT: ret i1 [[CMP2]]
59+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[SEL:%.*]], [[X]]
60+
; CHECK-NEXT: [[CMP3:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP2]]
61+
; CHECK-NEXT: ret i1 [[CMP3]]
6262
;
6363
%cmp = icmp ugt i8 %z, %x
6464
%sel = select i1 %cmp, i8 255, i8 %y

llvm/test/Transforms/InstCombine/range-check.ll

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -340,11 +340,7 @@ define i1 @negative4_logical(i32 %x, i32 %n) {
340340

341341
define i1 @negative5(i32 %x, i32 %n) {
342342
; CHECK-LABEL: @negative5(
343-
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
344-
; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[NN]], [[X:%.*]]
345-
; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[X]], -1
346-
; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]]
347-
; CHECK-NEXT: ret i1 [[C]]
343+
; CHECK-NEXT: ret i1 true
348344
;
349345
%nn = and i32 %n, 2147483647
350346
%a = icmp slt i32 %x, %nn
@@ -355,11 +351,7 @@ define i1 @negative5(i32 %x, i32 %n) {
355351

356352
define i1 @negative5_logical(i32 %x, i32 %n) {
357353
; CHECK-LABEL: @negative5_logical(
358-
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
359-
; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[NN]], [[X:%.*]]
360-
; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[X]], -1
361-
; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]]
362-
; CHECK-NEXT: ret i1 [[C]]
354+
; CHECK-NEXT: ret i1 true
363355
;
364356
%nn = and i32 %n, 2147483647
365357
%a = icmp slt i32 %x, %nn

llvm/test/Transforms/LoopVectorize/X86/pr23997.ll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
1212
; CHECK: preheader:
1313
; CHECK-NEXT: [[DOT10:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[TMP0:%.*]], i64 16
1414
; CHECK-NEXT: [[DOT12:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[TMP1:%.*]], i64 16
15-
; CHECK-NEXT: [[UMAX2:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2:%.*]], i64 1)
16-
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2]], 16
15+
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2:%.*]], 16
1716
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_MEMCHECK:%.*]]
1817
; CHECK: vector.memcheck:
1918
; CHECK-NEXT: [[TMP3:%.*]] = shl i64 [[TMP2]], 3
@@ -25,7 +24,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
2524
; CHECK-NEXT: [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]
2625
; CHECK-NEXT: br i1 [[FOUND_CONFLICT]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
2726
; CHECK: vector.ph:
28-
; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[UMAX2]], -16
27+
; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[TMP2]], -16
2928
; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
3029
; CHECK: vector.body:
3130
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
@@ -49,7 +48,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
4948
; CHECK-NEXT: [[TMP13:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
5049
; CHECK-NEXT: br i1 [[TMP13]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]]
5150
; CHECK: middle.block:
52-
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[UMAX2]], [[N_VEC]]
51+
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N_VEC]], [[TMP2]]
5352
; CHECK-NEXT: br i1 [[CMP_N]], label [[LOOPEXIT:%.*]], label [[SCALAR_PH]]
5453
; CHECK: scalar.ph:
5554
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], [[MIDDLE_BLOCK]] ], [ 0, [[PREHEADER]] ], [ 0, [[VECTOR_MEMCHECK]] ]

llvm/test/Transforms/NewGVN/pr35125.ll

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,12 @@ define i32 @main() #0 {
1818
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[STOREMERGE]], [[PHIOFOPS]]
1919
; CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END6:%.*]]
2020
; CHECK: if.then3:
21-
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[STOREMERGE]], -1
22-
; CHECK-NEXT: br i1 [[TOBOOL]], label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
21+
; CHECK-NEXT: br i1 false, label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
2322
; CHECK: lor.rhs:
24-
; CHECK-NEXT: [[TOBOOL5:%.*]] = icmp ne i32 [[TMP0]], 0
25-
; CHECK-NEXT: [[PHITMP:%.*]] = zext i1 [[TOBOOL5]] to i32
23+
; CHECK-NEXT: store i8 poison, ptr null, align 1
2624
; CHECK-NEXT: br label [[LOR_END]]
2725
; CHECK: lor.end:
28-
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ 1, [[IF_THEN3]] ], [ [[PHITMP]], [[LOR_RHS]] ]
29-
; CHECK-NEXT: store i32 [[TMP1]], ptr @a, align 4
26+
; CHECK-NEXT: store i32 1, ptr @a, align 4
3027
; CHECK-NEXT: br label [[IF_END6]]
3128
; CHECK: if.end6:
3229
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @a, align 4

0 commit comments

Comments
 (0)