[llvm] 90ae538 - [SCEV] Prove implication of predicates to their sign-flipped counterparts
Max Kazantsev via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 14 21:49:36 PDT 2021
Author: Max Kazantsev
Date: 2021-10-15T11:49:18+07:00
New Revision: 90ae538cab4b0535450b079244241424ff90711c
URL: https://github.com/llvm/llvm-project/commit/90ae538cab4b0535450b079244241424ff90711c
DIFF: https://github.com/llvm/llvm-project/commit/90ae538cab4b0535450b079244241424ff90711c.diff
LOG: [SCEV] Prove implication of predicates to their sign-flipped counterparts
This patch teaches SCEV two implication rules:
x <u y && y >=s 0 --> x <s y,
x <s y && y <s 0 --> x <u y.
And all equivalents with signs/parts swapped.
Differential Revision: https://reviews.llvm.org/D110517
Reviewed By: nikic
Added:
Modified:
llvm/lib/Analysis/ScalarEvolution.cpp
llvm/test/Transforms/IndVarSimplify/outer_phi.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index a0faf7dad9f04..f022052f4530d 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -10770,18 +10770,49 @@ bool ScalarEvolution::isImpliedCondBalancedTypes(
return false;
}
- // Unsigned comparison is the same as signed comparison when both the operands
- // are non-negative or negative.
auto IsSignFlippedPredicate = [](CmpInst::Predicate P1,
CmpInst::Predicate P2) {
assert(P1 != P2 && "Handled earlier!");
return CmpInst::isRelational(P2) &&
P1 == CmpInst::getFlippedSignednessPredicate(P2);
};
- if (IsSignFlippedPredicate(Pred, FoundPred) &&
- ((isKnownNonNegative(FoundLHS) && isKnownNonNegative(FoundRHS)) ||
- (isKnownNegative(FoundLHS) && isKnownNegative(FoundRHS))))
- return isImpliedCondOperands(Pred, LHS, RHS, FoundLHS, FoundRHS, CtxI);
+ if (IsSignFlippedPredicate(Pred, FoundPred)) {
+ // Unsigned comparison is the same as signed comparison when both the
+ // operands are non-negative or negative.
+ if ((isKnownNonNegative(FoundLHS) && isKnownNonNegative(FoundRHS)) ||
+ (isKnownNegative(FoundLHS) && isKnownNegative(FoundRHS)))
+ return isImpliedCondOperands(Pred, LHS, RHS, FoundLHS, FoundRHS, CtxI);
+ // Create local copies that we can freely swap and canonicalize our
+ // conditions to "le/lt".
+ ICmpInst::Predicate CanonicalPred = Pred, CanonicalFoundPred = FoundPred;
+ const SCEV *CanonicalLHS = LHS, *CanonicalRHS = RHS,
+ *CanonicalFoundLHS = FoundLHS, *CanonicalFoundRHS = FoundRHS;
+ if (ICmpInst::isGT(CanonicalPred) || ICmpInst::isGE(CanonicalPred)) {
+ CanonicalPred = ICmpInst::getSwappedPredicate(CanonicalPred);
+ CanonicalFoundPred = ICmpInst::getSwappedPredicate(CanonicalFoundPred);
+ std::swap(CanonicalLHS, CanonicalRHS);
+ std::swap(CanonicalFoundLHS, CanonicalFoundRHS);
+ }
+ assert((ICmpInst::isLT(CanonicalPred) || ICmpInst::isLE(CanonicalPred)) &&
+ "Must be!");
+ assert((ICmpInst::isLT(CanonicalFoundPred) ||
+ ICmpInst::isLE(CanonicalFoundPred)) &&
+ "Must be!");
+ if (ICmpInst::isSigned(CanonicalPred) && isKnownNonNegative(CanonicalRHS))
+ // Use implication:
+ // x <u y && y >=s 0 --> x <s y.
+ // If we can prove the left part, the right part is also proven.
+ return isImpliedCondOperands(CanonicalFoundPred, CanonicalLHS,
+ CanonicalRHS, CanonicalFoundLHS,
+ CanonicalFoundRHS);
+ if (ICmpInst::isUnsigned(CanonicalPred) && isKnownNegative(CanonicalRHS))
+ // Use implication:
+ // x <s y && y <s 0 --> x <u y.
+ // If we can prove the left part, the right part is also proven.
+ return isImpliedCondOperands(CanonicalFoundPred, CanonicalLHS,
+ CanonicalRHS, CanonicalFoundLHS,
+ CanonicalFoundRHS);
+ }
// Check if we can make progress by sharpening ranges.
if (FoundPred == ICmpInst::ICMP_NE &&
diff --git a/llvm/test/Transforms/IndVarSimplify/outer_phi.ll b/llvm/test/Transforms/IndVarSimplify/outer_phi.ll
index ebb6c9269e426..8da1648f64e5d 100644
--- a/llvm/test/Transforms/IndVarSimplify/outer_phi.ll
+++ b/llvm/test/Transforms/IndVarSimplify/outer_phi.ll
@@ -463,7 +463,6 @@ exit:
; Same as test_01a, but non-negativity of %b is known without context.
-; FIXME: We can remove 2nd check in loop.
define i32 @test_05a(i32 %a, i32* %bp) {
; CHECK-LABEL: @test_05a(
; CHECK-NEXT: entry:
@@ -477,8 +476,7 @@ define i32 @test_05a(i32 %a, i32* %bp) {
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]]
; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
; CHECK: inner.1:
-; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]]
-; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
+; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
; CHECK: inner.backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond()
@@ -527,7 +525,6 @@ exit:
}
; Similar to test_05a, but inverted 2nd condition.
-; FIXME: We can remove 2nd check in loop.
define i32 @test_05b(i32 %a, i32* %bp) {
; CHECK-LABEL: @test_05b(
; CHECK-NEXT: entry:
@@ -541,8 +538,7 @@ define i32 @test_05b(i32 %a, i32* %bp) {
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]]
; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
; CHECK: inner.1:
-; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp sgt i32 [[B]], [[IV]]
-; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
+; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
; CHECK: inner.backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond()
@@ -591,7 +587,6 @@ exit:
}
; We should prove implication: iv <s b, b <s 0 => iv <u b.
-; FIXME: Can remove 2nd check
define i32 @test_05c(i32 %a, i32* %bp) {
; CHECK-LABEL: @test_05c(
; CHECK-NEXT: entry:
@@ -605,8 +600,7 @@ define i32 @test_05c(i32 %a, i32* %bp) {
; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]]
; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
; CHECK: inner.1:
-; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]]
-; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
+; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
; CHECK: inner.backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond()
@@ -655,7 +649,6 @@ exit:
}
; Same as test_05c, but 2nd condition reversed.
-; FIXME: Can remove 2nd check
define i32 @test_05d(i32 %a, i32* %bp) {
; CHECK-LABEL: @test_05d(
; CHECK-NEXT: entry:
@@ -669,8 +662,7 @@ define i32 @test_05d(i32 %a, i32* %bp) {
; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]]
; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
; CHECK: inner.1:
-; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ugt i32 [[B]], [[IV]]
-; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
+; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
; CHECK: inner.backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond()
@@ -720,7 +712,6 @@ exit:
; Same as test_05a, but 1st condition inverted.
-; FIXME: We can remove 2nd check in loop.
define i32 @test_05e(i32 %a, i32* %bp) {
; CHECK-LABEL: @test_05e(
; CHECK-NEXT: entry:
@@ -734,8 +725,7 @@ define i32 @test_05e(i32 %a, i32* %bp) {
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ugt i32 [[B]], [[IV]]
; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
; CHECK: inner.1:
-; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp slt i32 [[IV]], [[B]]
-; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
+; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
; CHECK: inner.backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond()
@@ -784,7 +774,6 @@ exit:
}
; Same as test_05b, but 1st condition inverted.
-; FIXME: We can remove 2nd check in loop.
define i32 @test_05f(i32 %a, i32* %bp) {
; CHECK-LABEL: @test_05f(
; CHECK-NEXT: entry:
@@ -798,8 +787,7 @@ define i32 @test_05f(i32 %a, i32* %bp) {
; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ugt i32 [[B]], [[IV]]
; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
; CHECK: inner.1:
-; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp sgt i32 [[B]], [[IV]]
-; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
+; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
; CHECK: inner.backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond()
@@ -848,7 +836,6 @@ exit:
}
; Same as test_05c, but 1st condition inverted.
-; FIXME: We can remove 2nd check in loop.
define i32 @test_05g(i32 %a, i32* %bp) {
; CHECK-LABEL: @test_05g(
; CHECK-NEXT: entry:
@@ -862,8 +849,7 @@ define i32 @test_05g(i32 %a, i32* %bp) {
; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp sgt i32 [[B]], [[IV]]
; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
; CHECK: inner.1:
-; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ult i32 [[IV]], [[B]]
-; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
+; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
; CHECK: inner.backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond()
@@ -912,7 +898,6 @@ exit:
}
; Same as test_05d, but 1st condition inverted.
-; FIXME: We can remove 2nd check in loop.
define i32 @test_05h(i32 %a, i32* %bp) {
; CHECK-LABEL: @test_05h(
; CHECK-NEXT: entry:
@@ -926,8 +911,7 @@ define i32 @test_05h(i32 %a, i32* %bp) {
; CHECK-NEXT: [[SIGNED_COND:%.*]] = icmp sgt i32 [[B]], [[IV]]
; CHECK-NEXT: br i1 [[SIGNED_COND]], label [[INNER_1:%.*]], label [[SIDE_EXIT:%.*]]
; CHECK: inner.1:
-; CHECK-NEXT: [[UNSIGNED_COND:%.*]] = icmp ugt i32 [[B]], [[IV]]
-; CHECK-NEXT: br i1 [[UNSIGNED_COND]], label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
+; CHECK-NEXT: br i1 true, label [[INNER_BACKEDGE]], label [[SIDE_EXIT]]
; CHECK: inner.backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: [[INNER_LOOP_COND:%.*]] = call i1 @cond()
More information about the llvm-commits
mailing list