Skip to content

[ValueTracking] Extend LHS/RHS with matching operand to work without constants. #85557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 35 additions & 17 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8857,20 +8857,20 @@ isImpliedCondMatchingOperands(CmpInst::Predicate LPred,
return std::nullopt;
}

/// Return true if "icmp LPred X, LC" implies "icmp RPred X, RC" is true.
/// Return false if "icmp LPred X, LC" implies "icmp RPred X, RC" is false.
/// Return true if "icmp LPred X, LCR" implies "icmp RPred X, RCR" is true.
/// Return false if "icmp LPred X, LCR" implies "icmp RPred X, RCR" is false.
/// Otherwise, return std::nullopt if we can't infer anything.
static std::optional<bool> isImpliedCondCommonOperandWithConstants(
CmpInst::Predicate LPred, const APInt &LC, CmpInst::Predicate RPred,
const APInt &RC) {
ConstantRange DomCR = ConstantRange::makeExactICmpRegion(LPred, LC);
ConstantRange CR = ConstantRange::makeExactICmpRegion(RPred, RC);
ConstantRange Intersection = DomCR.intersectWith(CR);
ConstantRange Difference = DomCR.difference(CR);
if (Intersection.isEmptySet())
return false;
if (Difference.isEmptySet())
static std::optional<bool> isImpliedCondCommonOperandWithCR(
CmpInst::Predicate LPred, const ConstantRange &LCR,
CmpInst::Predicate RPred, const ConstantRange &RCR) {
ConstantRange DomCR = ConstantRange::makeAllowedICmpRegion(LPred, LCR);
// If all true values for lhs and true for rhs, lhs implies rhs
if (DomCR.icmp(RPred, RCR))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nikic, did you comment a concern here then delete it, or is my github not updating properly? I see the email notification but nothing here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

I think ConstantRange::makeAllowedICmpRegion is correct here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I believe this is correct aswell b.c icmp uses makeSatisfyingICmpRegion. @nikic assuming you deleted your comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I deleted my comment because I realized I was thinking about it the wrong way around right after I posted it. Sorry for the confusion.

return true;

// If there is no overlap, lhs implies not rhs
if (DomCR.icmp(CmpInst::getInversePredicate(RPred), RCR))
return false;
return std::nullopt;
}

Expand Down Expand Up @@ -8910,11 +8910,29 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
}
}

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

// Can we infer anything when the two compares have matching operands?
if (L0 == R0 && L1 == R1)
Expand Down
20 changes: 10 additions & 10 deletions llvm/test/Transforms/InstCombine/icmp-select-implies-common-op.ll
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ define i1 @sgt_3_impliesT_sgt_2(i8 %x, i8 %y) {

define i1 @sgt_x_impliesF_eq_smin_todo(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @sgt_x_impliesF_eq_smin_todo(
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 -128, i8 [[Y:%.*]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[SEL]], [[X]]
; CHECK-NEXT: ret i1 [[CMP2]]
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[SEL:%.*]], [[X]]
; CHECK-NEXT: [[CMP3:%.*]] = select i1 [[CMP]], i1 [[CMP2]], i1 false
; CHECK-NEXT: ret i1 [[CMP3]]
;
%cmp = icmp sgt i8 %x, %z
%sel = select i1 %cmp, i8 -128, i8 %y
Expand All @@ -43,9 +43,9 @@ define i1 @sgt_x_impliesF_eq_smin_todo(i8 %x, i8 %y, i8 %z) {
define i1 @slt_x_impliesT_ne_smin_todo(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @slt_x_impliesT_ne_smin_todo(
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 127, i8 [[Y:%.*]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[SEL]], [[X]]
; CHECK-NEXT: ret i1 [[CMP2]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[SEL:%.*]], [[X]]
; CHECK-NEXT: [[CMP3:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP2]]
; CHECK-NEXT: ret i1 [[CMP3]]
;
%cmp = icmp slt i8 %x, %z
%sel = select i1 %cmp, i8 127, i8 %y
Expand All @@ -56,9 +56,9 @@ define i1 @slt_x_impliesT_ne_smin_todo(i8 %x, i8 %y, i8 %z) {
define i1 @ult_x_impliesT_eq_umax_todo(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @ult_x_impliesT_eq_umax_todo(
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[Z:%.*]], [[X:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 -1, i8 [[Y:%.*]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[SEL]], [[X]]
; CHECK-NEXT: ret i1 [[CMP2]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[SEL:%.*]], [[X]]
; CHECK-NEXT: [[CMP3:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP2]]
; CHECK-NEXT: ret i1 [[CMP3]]
;
%cmp = icmp ugt i8 %z, %x
%sel = select i1 %cmp, i8 255, i8 %y
Expand Down
12 changes: 2 additions & 10 deletions llvm/test/Transforms/InstCombine/range-check.ll
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,7 @@ define i1 @negative4_logical(i32 %x, i32 %n) {

define i1 @negative5(i32 %x, i32 %n) {
; CHECK-LABEL: @negative5(
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[NN]], [[X:%.*]]
; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[X]], -1
; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]]
; CHECK-NEXT: ret i1 [[C]]
; CHECK-NEXT: ret i1 true
;
%nn = and i32 %n, 2147483647
%a = icmp slt i32 %x, %nn
Expand All @@ -355,11 +351,7 @@ define i1 @negative5(i32 %x, i32 %n) {

define i1 @negative5_logical(i32 %x, i32 %n) {
; CHECK-LABEL: @negative5_logical(
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[NN]], [[X:%.*]]
; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[X]], -1
; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]]
; CHECK-NEXT: ret i1 [[C]]
; CHECK-NEXT: ret i1 true
;
%nn = and i32 %n, 2147483647
%a = icmp slt i32 %x, %nn
Expand Down
7 changes: 3 additions & 4 deletions llvm/test/Transforms/LoopVectorize/X86/pr23997.ll
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
; CHECK: preheader:
; CHECK-NEXT: [[DOT10:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[TMP0:%.*]], i64 16
; CHECK-NEXT: [[DOT12:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[TMP1:%.*]], i64 16
; CHECK-NEXT: [[UMAX2:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2:%.*]], i64 1)
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2]], 16
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2:%.*]], 16
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_MEMCHECK:%.*]]
; CHECK: vector.memcheck:
; CHECK-NEXT: [[TMP3:%.*]] = shl i64 [[TMP2]], 3
Expand All @@ -25,7 +24,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
; CHECK-NEXT: [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]
; CHECK-NEXT: br i1 [[FOUND_CONFLICT]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[UMAX2]], -16
; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[TMP2]], -16
; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
; CHECK: vector.body:
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
Expand All @@ -49,7 +48,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
; CHECK-NEXT: [[TMP13:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
; CHECK-NEXT: br i1 [[TMP13]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]]
; CHECK: middle.block:
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[UMAX2]], [[N_VEC]]
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N_VEC]], [[TMP2]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[LOOPEXIT:%.*]], label [[SCALAR_PH]]
; CHECK: scalar.ph:
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], [[MIDDLE_BLOCK]] ], [ 0, [[PREHEADER]] ], [ 0, [[VECTOR_MEMCHECK]] ]
Expand Down
9 changes: 3 additions & 6 deletions llvm/test/Transforms/NewGVN/pr35125.ll
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,12 @@ define i32 @main() #0 {
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[STOREMERGE]], [[PHIOFOPS]]
; CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END6:%.*]]
; CHECK: if.then3:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[STOREMERGE]], -1
; CHECK-NEXT: br i1 [[TOBOOL]], label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
; CHECK-NEXT: br i1 false, label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
; CHECK: lor.rhs:
; CHECK-NEXT: [[TOBOOL5:%.*]] = icmp ne i32 [[TMP0]], 0
; CHECK-NEXT: [[PHITMP:%.*]] = zext i1 [[TOBOOL5]] to i32
; CHECK-NEXT: store i8 poison, ptr null, align 1
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ 1, [[IF_THEN3]] ], [ [[PHITMP]], [[LOR_RHS]] ]
; CHECK-NEXT: store i32 [[TMP1]], ptr @a, align 4
; CHECK-NEXT: store i32 1, ptr @a, align 4
; CHECK-NEXT: br label [[IF_END6]]
; CHECK: if.end6:
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @a, align 4
Expand Down
Loading