[llvm] [CVP] Propagate constant range on icmp at use level (PR #73767)

via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 29 03:44:57 PST 2023


https://github.com/XChy updated https://github.com/llvm/llvm-project/pull/73767

>From 8ede35173d96d0dcbedc52751ac644bfb4561fe2 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Tue, 28 Nov 2023 19:55:00 +0800
Subject: [PATCH 1/2] [CVP] Precommit test for constant propagation of icmp

---
 .../CorrelatedValuePropagation/icmp.ll        | 102 ++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
index 101820a4c65f23b..ff9b5df666860c4 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
@@ -1455,3 +1455,105 @@ entry:
   %select = select i1 %cmp1, i1 %cmp2, i1 false
   ret i1 %select
 }
+
+define i1 @select_ternary_icmp1(i32 noundef %a) {
+; CHECK-LABEL: @select_ternary_icmp1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[A]], 5
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[A]], 7
+; CHECK-NEXT:    [[COND_V:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP2]]
+; CHECK-NEXT:    ret i1 [[COND_V]]
+;
+entry:
+  %cmp = icmp slt i32 %a, 3
+  %cmp1 = icmp slt i32 %a, 5
+  %cmp2 = icmp slt i32 %a, 7
+  %cond.v = select i1 %cmp, i1 %cmp1, i1 %cmp2
+  ret i1 %cond.v
+}
+
+define i1 @select_ternary_icmp2(i32 noundef %a) {
+; CHECK-LABEL: @select_ternary_icmp2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 5
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[A]], 7
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], 3
+; CHECK-NEXT:    [[COND_V:%.*]] = select i1 [[CMP]], i1 true, i1 false
+; CHECK-NEXT:    ret i1 [[COND_V]]
+;
+entry:
+  %cmp = icmp slt i32 %a, 5
+  %cmp1 = icmp slt i32 %a, 7
+  %cmp2 = icmp slt i32 %a, 3
+  %cond.v = select i1 %cmp, i1 %cmp1, i1 %cmp2
+  ret i1 %cond.v
+}
+
+define i1 @select_ternary_icmp3(i32 noundef %a) {
+; CHECK-LABEL: @select_ternary_icmp3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[A]], 3
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[A]], 5
+; CHECK-NEXT:    [[COND_V:%.*]] = select i1 [[CMP]], i1 [[CMP1]], i1 false
+; CHECK-NEXT:    ret i1 [[COND_V]]
+;
+entry:
+  %cmp = icmp slt i32 %a, 7
+  %cmp1 = icmp slt i32 %a, 3
+  %cmp2 = icmp slt i32 %a, 5
+  %cond.v = select i1 %cmp, i1 %cmp1, i1 %cmp2
+  ret i1 %cond.v
+}
+
+define i1 @select_ternary_icmp3_reverse(i32 noundef %a) {
+; CHECK-LABEL: @select_ternary_icmp3_reverse(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 [[A]], 5
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[A]], 7
+; CHECK-NEXT:    [[COND_V:%.*]] = select i1 [[CMP]], i1 false, i1 [[CMP2]]
+; CHECK-NEXT:    ret i1 [[COND_V]]
+;
+entry:
+  %cmp = icmp slt i32 %a, 3
+  %cmp1 = icmp sge i32 %a, 5
+  %cmp2 = icmp sge i32 %a, 7
+  %cond.v = select i1 %cmp, i1 %cmp1, i1 %cmp2
+  ret i1 %cond.v
+}
+
+define i1 @select_ternary_icmp_fail1(i32 noundef %a, i32 noundef %b) {
+; CHECK-LABEL: @select_ternary_icmp_fail1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[B:%.*]], 5
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[B]], 7
+; CHECK-NEXT:    [[COND_V:%.*]] = select i1 [[CMP]], i1 [[CMP1]], i1 [[CMP2]]
+; CHECK-NEXT:    ret i1 [[COND_V]]
+;
+entry:
+  %cmp = icmp slt i32 %a, 3
+  %cmp1 = icmp slt i32 %b, 5
+  %cmp2 = icmp slt i32 %b, 7
+  %cond.v = select i1 %cmp, i1 %cmp1, i1 %cmp2
+  ret i1 %cond.v
+}
+
+define i1 @select_ternary_icmp_fail2(i32 noundef %a, i32 noundef %b) {
+; CHECK-LABEL: @select_ternary_icmp_fail2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[A:%.*]], 3
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp sge i32 5, [[B:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sge i32 7, [[B]]
+; CHECK-NEXT:    [[COND_V:%.*]] = select i1 [[CMP]], i1 [[CMP1]], i1 [[CMP2]]
+; CHECK-NEXT:    ret i1 [[COND_V]]
+;
+entry:
+  %cmp = icmp slt i32 %a, 3
+  %cmp1 = icmp sge i32 5, %b
+  %cmp2 = icmp sge i32 7, %b
+  %cond.v = select i1 %cmp, i1 %cmp1, i1 %cmp2
+  ret i1 %cond.v
+}

>From 0fe7abab3a1bc84822bb3d699911fce50efff440 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sun, 26 Nov 2023 16:22:29 +0800
Subject: [PATCH 2/2] [CVP] Propagate constant range on icmp at use level

---
 llvm/include/llvm/Analysis/LazyValueInfo.h    | 11 ++++++++
 llvm/lib/Analysis/LazyValueInfo.cpp           | 25 +++++++++++++++++++
 .../Scalar/CorrelatedValuePropagation.cpp     | 23 ++++++++++++++---
 .../CorrelatedValuePropagation/sdiv.ll        |  8 +++---
 .../CorrelatedValuePropagation/srem.ll        |  8 +++---
 .../CorrelatedValuePropagation/sub.ll         |  8 +++---
 6 files changed, 67 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/Analysis/LazyValueInfo.h b/llvm/include/llvm/Analysis/LazyValueInfo.h
index ead9f5f0225cd09..0ea9e36eeb85432 100644
--- a/llvm/include/llvm/Analysis/LazyValueInfo.h
+++ b/llvm/include/llvm/Analysis/LazyValueInfo.h
@@ -87,6 +87,17 @@ namespace llvm {
     Tristate getPredicateAt(unsigned Pred, Value *LHS, Value *RHS,
                             Instruction *CxtI, bool UseBlockValue);
 
+    /// Determine whether the specified value comparison is known to be true
+    /// or false at the specified use-site.
+    /// \p Pred is a CmpInst predicate.
+    Tristate getPredicateAtUse(unsigned P, const Use &LHS, const Use &RHS);
+
+    // \p LHSRange is the range of LHS we get at the specified use-site.
+    // \p RHSRange serves as the same purpose too.
+    Tristate getPredicateAtUse(unsigned P, const Use &LHS, const Use &RHS,
+                               ConstantRange &LHSRange,
+                               ConstantRange &RHSRange);
+
     /// Determine whether the specified value is known to be a constant at the
     /// specified instruction. Return null if not.
     Constant *getConstant(Value *V, Instruction *CxtI);
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 3c2f26e9242137b..9eb3d9377d543f3 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -2008,6 +2008,31 @@ LazyValueInfo::Tristate LazyValueInfo::getPredicateAt(unsigned P, Value *LHS,
   return LazyValueInfo::Unknown;
 }
 
+LazyValueInfo::Tristate
+LazyValueInfo::getPredicateAtUse(unsigned P, const Use &LHS, const Use &RHS) {
+  uint32_t BitWidth = LHS.get()->getType()->getScalarSizeInBits();
+  ConstantRange LHSRange = ConstantRange::getFull(BitWidth);
+  ConstantRange RHSRange = ConstantRange::getFull(BitWidth);
+  return getPredicateAtUse(P, LHS, RHS, LHSRange, RHSRange);
+}
+
+LazyValueInfo::Tristate
+LazyValueInfo::getPredicateAtUse(unsigned P, const Use &LHS, const Use &RHS,
+                                 ConstantRange &LHSRange,
+                                 ConstantRange &RHSRange) {
+  CmpInst::Predicate Pred = (CmpInst::Predicate)P;
+  LHSRange = getConstantRangeAtUse(LHS);
+  RHSRange = getConstantRangeAtUse(RHS);
+
+  if (LHSRange.icmp(Pred, RHSRange))
+    return LazyValueInfo::True;
+
+  if (LHSRange.icmp(CmpInst::getInversePredicate(Pred), RHSRange))
+    return LazyValueInfo::False;
+
+  return LazyValueInfo::Unknown;
+}
+
 void LazyValueInfo::threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc,
                                BasicBlock *NewSucc) {
   if (auto *Impl = getImpl())
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index 1bdc441d18ea65e..fb83281d259b1c3 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -272,14 +272,29 @@ static bool processICmp(ICmpInst *Cmp, LazyValueInfo *LVI) {
       !Cmp->getOperand(0)->getType()->isIntegerTy())
     return false;
 
+  uint32_t BitWidth = Cmp->getOperand(0)->getType()->getScalarSizeInBits();
+  auto LHSRange = ConstantRange::getFull(BitWidth);
+  auto RHSRange = ConstantRange::getFull(BitWidth);
+
+  LazyValueInfo::Tristate Result =
+      LVI->getPredicateAtUse(Cmp->getPredicate(), Cmp->getOperandUse(0),
+                             Cmp->getOperandUse(1), LHSRange, RHSRange);
+
+  // NOTE: It's not the original purpose. Do simple constant propagation at use
+  // level here.
+  if (Result != LazyValueInfo::Unknown) {
+    Cmp->replaceAllUsesWith(Result == LazyValueInfo::True
+                                ? Constant::getAllOnesValue(Cmp->getType())
+                                : Constant::getNullValue(Cmp->getType()));
+    return true;
+  }
+
   if (!Cmp->isSigned())
     return false;
 
   ICmpInst::Predicate UnsignedPred =
-      ConstantRange::getEquivalentPredWithFlippedSignedness(
-          Cmp->getPredicate(),
-          LVI->getConstantRangeAtUse(Cmp->getOperandUse(0)),
-          LVI->getConstantRangeAtUse(Cmp->getOperandUse(1)));
+      ConstantRange::getEquivalentPredWithFlippedSignedness(Cmp->getPredicate(),
+                                                            LHSRange, RHSRange);
 
   if (UnsignedPred == ICmpInst::Predicate::BAD_ICMP_PREDICATE)
     return false;
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll b/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll
index d88fe358a0aa2cd..1f4b6ac46801cee 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll
@@ -483,13 +483,13 @@ define i9 @test18_i9_i9(i9 %x, i9 %y) {
 ; CHECK-LABEL: @test18_i9_i9(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[C0:%.*]] = icmp sle i9 [[X:%.*]], 255
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
+; CHECK-NEXT:    call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    [[C1:%.*]] = icmp sge i9 [[X]], -256
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    [[C2:%.*]] = icmp sle i9 [[Y:%.*]], 255
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
+; CHECK-NEXT:    call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    [[C3:%.*]] = icmp sge i9 [[Y]], -256
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
+; CHECK-NEXT:    call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    [[DIV:%.*]] = sdiv i9 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i9 [[DIV]]
 ;
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll b/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll
index bc2b0aec269b9dc..b504086ee9018e5 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll
@@ -396,13 +396,13 @@ define i9 @test18_i9_i9(i9 %x, i9 %y) {
 ; CHECK-LABEL: @test18_i9_i9(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[C0:%.*]] = icmp sle i9 [[X:%.*]], 255
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C0]])
+; CHECK-NEXT:    call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    [[C1:%.*]] = icmp sge i9 [[X]], -256
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    [[C2:%.*]] = icmp sle i9 [[Y:%.*]], 255
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
+; CHECK-NEXT:    call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    [[C3:%.*]] = icmp sge i9 [[Y]], -256
-; CHECK-NEXT:    call void @llvm.assume(i1 [[C3]])
+; CHECK-NEXT:    call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    [[DIV:%.*]] = srem i9 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i9 [[DIV]]
 ;
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/sub.ll b/llvm/test/Transforms/CorrelatedValuePropagation/sub.ll
index 8b67574c06cd953..57e9d168051a18c 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/sub.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/sub.ll
@@ -51,9 +51,9 @@ define void @test2(i32 %a) {
 ; CHECK-LABEL: @test2(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], -1
-; CHECK-NEXT:    br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
+; CHECK-NEXT:    br i1 false, label [[BB:%.*]], label [[EXIT:%.*]]
 ; CHECK:       bb:
-; CHECK-NEXT:    [[SUB:%.*]] = sub nuw nsw i32 [[A]], 1
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[A]], 1
 ; CHECK-NEXT:    br label [[EXIT]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
@@ -120,7 +120,7 @@ define void @test5(i32 %a) {
 ; CHECK-LABEL: @test5(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp sle i32 [[A:%.*]], 2147483647
-; CHECK-NEXT:    br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
+; CHECK-NEXT:    br i1 true, label [[BB:%.*]], label [[EXIT:%.*]]
 ; CHECK:       bb:
 ; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[A]], 1
 ; CHECK-NEXT:    br label [[EXIT]]
@@ -300,7 +300,7 @@ exit:
 @limit = external global i32
 define i32 @test11(ptr %p, i32 %i) {
 ; CHECK-LABEL: @test11(
-; CHECK-NEXT:    [[LIMIT:%.*]] = load i32, ptr [[P:%.*]], !range !0
+; CHECK-NEXT:    [[LIMIT:%.*]] = load i32, ptr [[P:%.*]], align 4, !range [[RNG0:![0-9]+]]
 ; CHECK-NEXT:    [[WITHIN_1:%.*]] = icmp slt i32 [[LIMIT]], [[I:%.*]]
 ; CHECK-NEXT:    [[I_MINUS_7:%.*]] = add i32 [[I]], -7
 ; CHECK-NEXT:    [[WITHIN_2:%.*]] = icmp slt i32 [[LIMIT]], [[I_MINUS_7]]



More information about the llvm-commits mailing list