diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 6434de3e463c9..7660009b088d0 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -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 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 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)) return true; + + // If there is no overlap, lhs implies not rhs + if (DomCR.icmp(CmpInst::getInversePredicate(RPred), RCR)) + return false; return std::nullopt; } @@ -8910,11 +8910,29 @@ static std::optional 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) diff --git a/llvm/test/Transforms/InstCombine/icmp-select-implies-common-op.ll b/llvm/test/Transforms/InstCombine/icmp-select-implies-common-op.ll index bacdb54f787d6..8d393a7ae28c9 100644 --- a/llvm/test/Transforms/InstCombine/icmp-select-implies-common-op.ll +++ b/llvm/test/Transforms/InstCombine/icmp-select-implies-common-op.ll @@ -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 @@ -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 @@ -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 diff --git a/llvm/test/Transforms/InstCombine/range-check.ll b/llvm/test/Transforms/InstCombine/range-check.ll index 0d138b6ba7e79..210e57c1d1fe4 100644 --- a/llvm/test/Transforms/InstCombine/range-check.ll +++ b/llvm/test/Transforms/InstCombine/range-check.ll @@ -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 @@ -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 diff --git a/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll b/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll index 3d7153e66fc66..8800fa26f067c 100644 --- a/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll +++ b/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll @@ -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 @@ -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]] ] @@ -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]] ] diff --git a/llvm/test/Transforms/NewGVN/pr35125.ll b/llvm/test/Transforms/NewGVN/pr35125.ll index 9a96594e3446d..6724538a5a7f2 100644 --- a/llvm/test/Transforms/NewGVN/pr35125.ll +++ b/llvm/test/Transforms/NewGVN/pr35125.ll @@ -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