[llvm] [polly] [llvm][ConstraintElimination]Insert ConditionFact into loop header in case of monotonic induction variables (PR #112080)

Grigory Pastukhov via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 26 15:46:24 PDT 2024


https://github.com/grigorypas updated https://github.com/llvm/llvm-project/pull/112080

>From b0da99d35286055d13733e5519c5d8d2ee69f865 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Fri, 11 Oct 2024 19:31:04 -0700
Subject: [PATCH 1/6] Insert ConditionFact into loop header

---
 .../Scalar/ConstraintElimination.cpp          | 55 +++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 7c06e0c757e1cc..56cc26093cee87 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -197,6 +197,8 @@ struct State {
   /// controlling the loop header.
   void addInfoForInductions(BasicBlock &BB);
 
+  void addConditionFactsIntoLoopHeader(BasicBlock &BB);
+  
   /// Returns true if we can add a known condition from BB to its successor
   /// block Succ.
   bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ) const {
@@ -900,7 +902,60 @@ static void dumpConstraint(ArrayRef<int64_t> C,
 }
 #endif
 
+// For monotonically decreasing/increasing variables in the loop,
+// this will insert ConditionFact PN >= StartingValue or PN <= StartingValue
+// associated with the loop header, where PN is the corresponding PHi node.
+void State::addConditionFactsIntoLoopHeader(BasicBlock &BB) {
+  auto *L = LI.getLoopFor(&BB);
+  if (!L || L->getHeader() != &BB)
+    return;
+  DomTreeNode *DTN = DT.getNode(&BB);
+  for(PHINode &PN :L->getHeader()->phis()){
+    if(PN.getNumIncomingValues() != 2 || PN.getParent() != &BB || !SE.isSCEVable(PN.getType()))
+      continue;
+    auto *AR = dyn_cast_or_null<SCEVAddRecExpr>(SE.getSCEV(&PN));
+    BasicBlock *LoopPred = L->getLoopPredecessor();
+    if (!AR || AR->getLoop() != L || !LoopPred)
+      return;
+    const SCEV *StartSCEV = AR->getStart();
+    Value *StartValue = nullptr;
+    if (auto *C = dyn_cast<SCEVConstant>(StartSCEV)) {
+      StartValue = C->getValue();
+    } else {
+      StartValue = PN.getIncomingValueForBlock(LoopPred);
+      assert(SE.getSCEV(StartValue) == StartSCEV && "inconsistent start value");
+    }
+    auto IncUnsigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_UGT);
+    auto IncSigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_SGT);
+    
+    // Monotonically Increasing 
+    bool MonotonicallyIncreasingUnsigned =
+      IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyIncreasing;
+    bool MonotonicallyIncreasingSigned =
+        IncSigned && *IncSigned == ScalarEvolution::MonotonicallyIncreasing;
+    if (MonotonicallyIncreasingUnsigned)
+      WorkList.push_back(
+          FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_UGE, &PN, StartValue));
+    if (MonotonicallyIncreasingSigned)
+      WorkList.push_back(
+          FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SGE, &PN, StartValue));
+
+    // Monotonically Decreasing
+    bool MonotonicallyDecreasingUnsigned =
+      IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyDecreasing;
+    bool MonotonicallyDecreasingSigned =
+        IncSigned && *IncSigned == ScalarEvolution::MonotonicallyDecreasing;
+    if(MonotonicallyDecreasingUnsigned)
+      WorkList.push_back(
+          FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_ULE, &PN, StartValue));
+    if(MonotonicallyDecreasingSigned)
+      WorkList.push_back(
+          FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SLE, &PN, StartValue));
+  }        
+}
+
 void State::addInfoForInductions(BasicBlock &BB) {
+  addConditionFactsIntoLoopHeader(BB);
   auto *L = LI.getLoopFor(&BB);
   if (!L || L->getHeader() != &BB)
     return;

>From ef9c0275982d51d0dbe79b46a3d4aa7460668073 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Fri, 11 Oct 2024 21:32:54 -0700
Subject: [PATCH 2/6] Fixed regression tests

---
 .../and-implied-by-operands.ll                |  3 +--
 .../loops-bottom-tested-base.ll               | 12 +++------
 .../loops-bottom-tested-pointer-cmps.ll       |  3 ---
 .../loops-header-tested-base.ll               | 27 +++++++------------
 .../loops-header-tested-pointer-cmps.ll       |  2 --
 .../loops-header-tested-pointer-iv.ll         |  3 +--
 .../monotonic-int-phis-wrapping.ll            |  9 +++----
 .../monotonic-pointer-phis-chain-of-exits.ll  | 12 +++------
 .../monotonic-pointer-phis-early-exits.ll     | 21 +++++----------
 .../monotonic-pointer-phis.ll                 |  4 +--
 ...facts-to-unsigned-is-known-non-negative.ll |  3 +--
 11 files changed, 31 insertions(+), 68 deletions(-)

diff --git a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll
index 6bbc73c9c996c8..ab1733caf10d14 100644
--- a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll
+++ b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll
@@ -326,9 +326,8 @@ define void @test_monotonic_ptr_iv_inc_1_eq_to_uge(ptr %start, i16 %len) {
 ; CHECK-NEXT:    [[AND_0:%.*]] = and i1 [[LEN_NEG]], [[C]]
 ; CHECK-NEXT:    br i1 [[AND_0]], label [[FOR_BODY:%.*]], label [[EXIT:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
diff --git a/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll b/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll
index 3dbea9496da8d7..6510fbb9d260f5 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll
@@ -11,10 +11,8 @@ define void @loop_iv_cond_variable_bound(i32 %n) {
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[IV]], [[N:%.*]]
 ; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], 0
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[T_3:%.*]] = icmp sge i32 [[IV]], -1
-; CHECK-NEXT:    call void @use(i1 [[T_3]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], [[N]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[IV]], 1
@@ -58,10 +56,8 @@ define void @loop_iv_cond_constant_bound() {
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[IV]], 2
 ; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], 0
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[T_3:%.*]] = icmp sge i32 [[IV]], -1
-; CHECK-NEXT:    call void @use(i1 [[T_3]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], 2
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[IV]], 1
diff --git a/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-pointer-cmps.ll b/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-pointer-cmps.ll
index 279238bea1842e..b003553ff51b23 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-pointer-cmps.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-pointer-cmps.ll
@@ -21,7 +21,6 @@ define void @checks_in_loops_removable(ptr %ptr, ptr %lower, ptr %upper, i8 %n)
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 0, [[PRE_2]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
 ; CHECK-NEXT:    [[PTR_IV:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IV]]
-; CHECK-NEXT:    [[CMP_PTR_IV_LOWER:%.*]] = icmp ugt ptr [[LOWER]], [[PTR_IV]]
 ; CHECK-NEXT:    [[CMP_PTR_IV_UPPER:%.*]] = icmp ule ptr [[UPPER]], [[PTR_IV]]
 ; CHECK-NEXT:    [[OR:%.*]] = or i1 false, [[CMP_PTR_IV_UPPER]]
 ; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_LATCH]]
@@ -86,7 +85,6 @@ define void @some_checks_in_loops_removable(ptr %ptr, ptr %lower, ptr %upper, i8
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 0, [[PRE_2]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
 ; CHECK-NEXT:    [[PTR_IV:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IV]]
-; CHECK-NEXT:    [[CMP_PTR_IV_LOWER:%.*]] = icmp ugt ptr [[LOWER]], [[PTR_IV]]
 ; CHECK-NEXT:    [[CMP_PTR_IV_UPPER:%.*]] = icmp ule ptr [[UPPER]], [[PTR_IV]]
 ; CHECK-NEXT:    [[OR:%.*]] = or i1 false, [[CMP_PTR_IV_UPPER]]
 ; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_BODY:%.*]]
@@ -163,7 +161,6 @@ define void @no_checks_in_loops_removable(ptr %ptr, ptr %lower, ptr %upper, i8 %
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 0, [[PRE_1]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
 ; CHECK-NEXT:    [[PTR_IV:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i16 [[IV]]
-; CHECK-NEXT:    [[CMP_PTR_IV_LOWER:%.*]] = icmp ugt ptr [[LOWER]], [[PTR_IV]]
 ; CHECK-NEXT:    [[CMP_PTR_IV_UPPER:%.*]] = icmp ule ptr [[UPPER]], [[PTR_IV]]
 ; CHECK-NEXT:    [[OR:%.*]] = or i1 false, [[CMP_PTR_IV_UPPER]]
 ; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_BODY:%.*]]
diff --git a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-base.ll b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-base.ll
index 7b928a030614b5..5ff87987300773 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-base.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-base.ll
@@ -14,15 +14,11 @@ define void @loop_phi_pos_start_value(i32 %y, i1 %c, i32 %n) {
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[X]], 10
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[C_2:%.*]] = icmp sle i32 [[X]], 9
-; CHECK-NEXT:    call void @use(i1 [[C_2]])
-; CHECK-NEXT:    [[C_3:%.*]] = icmp sgt i32 [[X]], 9
-; CHECK-NEXT:    call void @use(i1 [[C_3]])
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[C_5:%.*]] = icmp sge i32 [[X]], 9
-; CHECK-NEXT:    call void @use(i1 [[C_5]])
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[X_NEXT]] = add nsw i32 [[X]], 1
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit:
@@ -75,8 +71,7 @@ define void @loop_phi_neg_start_value(i32 %y, i1 %c, i32 %n) {
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[X]], -10
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp sle i32 [[X]], 9
 ; CHECK-NEXT:    call void @use(i1 [[C_2]])
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp sgt i32 [[X]], 9
@@ -299,10 +294,8 @@ define void @loop_iv_cond_variable_bound(i32 %n) {
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[IV]], [[N:%.*]]
 ; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], 0
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[T_3:%.*]] = icmp sge i32 [[IV]], -1
-; CHECK-NEXT:    call void @use(i1 [[T_3]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], [[N]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[IV]], 1
@@ -364,10 +357,8 @@ define void @loop_iv_cond_constant_bound() {
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[IV]], 2
 ; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], 0
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[T_3:%.*]] = icmp sge i32 [[IV]], -1
-; CHECK-NEXT:    call void @use(i1 [[T_3]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], 2
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[IV]], 1
diff --git a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
index 1842ca2d82545c..57191a8ebc0870 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
@@ -210,7 +210,6 @@ define void @test2_with_ne(ptr %src, ptr %lower, ptr %upper, i8 %N) {
 ; CHECK-NEXT:    br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP_BODY:%.*]]
 ; CHECK:       loop.body:
 ; CHECK-NEXT:    [[SRC_IV:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[IV]]
-; CHECK-NEXT:    [[CMP_IV_START:%.*]] = icmp ult ptr [[SRC_IV]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_END:%.*]] = icmp uge ptr [[SRC_IV]], [[UPPER]]
 ; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_IV_END]]
 ; CHECK-NEXT:    br i1 [[OR_1]], label [[TRAP_BB]], label [[LOOP_BODY_1:%.*]]
@@ -304,7 +303,6 @@ define void @test3(ptr %src, ptr %lower, ptr %upper, i8 %N) {
 ; CHECK-NEXT:    br i1 [[EC]], label [[LOOP_BODY:%.*]], label [[EXIT:%.*]]
 ; CHECK:       loop.body:
 ; CHECK-NEXT:    [[SRC_IV:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[IV]]
-; CHECK-NEXT:    [[CMP_IV_START:%.*]] = icmp ult ptr [[SRC_IV]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_END:%.*]] = icmp uge ptr [[SRC_IV]], [[UPPER]]
 ; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_IV_END]]
 ; CHECK-NEXT:    br i1 [[OR_1]], label [[TRAP_BB]], label [[LOOP_BODY_1:%.*]]
diff --git a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-iv.ll b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-iv.ll
index eb252d1a5444ea..8863907ecfd50a 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-iv.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-iv.ll
@@ -12,8 +12,7 @@ define void @loop_pointer_iv(ptr %start, ptr %end, ptr %upper) {
 ; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ule ptr [[IV]], [[END]]
 ; CHECK-NEXT:    call void @use(i1 [[C_2]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp uge ptr [[IV]], [[START]]
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ule ptr [[IV]], [[END]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll
index 17aa4d54abfbab..2a58220b78f000 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll
@@ -49,8 +49,7 @@ define void @test_iv_nuw_nsw_1_uge_start(i8 %len.n, i8 %a) {
 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ -1, [[LOOP_PH:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[IV]], 1
-; CHECK-NEXT:    br i1 [[C]], label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
+; CHECK-NEXT:    br i1 false, label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_LATCH]], label [[EXIT]]
@@ -90,8 +89,7 @@ define void @test_iv_nuw_nsw_2_uge_start(i8 %len.n, i8 %a) {
 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ [[START]], [[LOOP_PH:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[IV]], 1
-; CHECK-NEXT:    br i1 [[C]], label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
+; CHECK-NEXT:    br i1 false, label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_LATCH]], label [[EXIT]]
@@ -131,8 +129,7 @@ define void @test_iv_nsw_nuw_1_ult_end(i8 %len.n, i8 %a) {
 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ -2, [[LOOP_PH:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[IV]], 1
-; CHECK-NEXT:    br i1 [[C]], label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
+; CHECK-NEXT:    br i1 false, label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_LATCH]], label [[EXIT]]
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-chain-of-exits.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-chain-of-exits.ll
index 6b128d9e525ca3..16c8beff2780c3 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-chain-of-exits.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-chain-of-exits.ll
@@ -25,9 +25,8 @@ define void @test_monotonic_ptr_iv_inc_1_different_element_types_1_chain_of_2_ex
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_NEXT:%.*]], label [[EXIT]]
 ; CHECK:       loop.next:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -94,9 +93,8 @@ define void @test_monotonic_ptr_iv_inc_1_different_element_types_1_chain_of_3_ex
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_NEXT:%.*]], label [[EXIT]]
 ; CHECK:       loop.next:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -163,9 +161,8 @@ define void @test_monotonic_ptr_iv_inc_1_different_element_types_1_chain_of_2_ex
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_NEXT:%.*]], label [[EXIT]]
 ; CHECK:       loop.next:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -227,9 +224,8 @@ define void @test_header_not_exiting(ptr %start, i16 %len, i16 %x) {
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_NEXT:%.*]], label [[EXIT]]
 ; CHECK:       loop.next:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll
index f05f324ef9322f..07f10c342ac6fc 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll
@@ -376,9 +376,8 @@ define void @test_monotonic_ptr_iv_cond_doesnt_control_exit(ptr %start, i16 %len
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -437,9 +436,8 @@ define void @test_monotonic_ptr_iv_cond_doesnt_control_exit2(ptr %start, i16 %le
 ; CHECK-NEXT:    [[C_0:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_0]], label [[EXIT]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -500,9 +498,8 @@ define void @test_monotonic_ptr_iv_cond_doesnt_dominate_checks(ptr %start, i16 %
 ; CHECK:       then:
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
 ; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 1
@@ -619,9 +616,8 @@ define void @test_monotonic_ptr_iv_step_2_cond_doesnt_control_exit(ptr %start, i
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -680,9 +676,8 @@ define void @test_monotonic_ptr_iv_step_64_cond_doesnt_control_exit(ptr %start,
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -741,9 +736,8 @@ define void @test_monotonic_ptr_iv_step_80_cond_doesnt_control_exit(ptr %start,
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -807,9 +801,8 @@ define void @test_monotonic_ptr_iv_inc_1_check_outside_loop(ptr %start, i16 %len
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[EXIT_2:%.*]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[EXIT_2]]
 ; CHECK:       exit.2:
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
index b3432695a96a58..11ab1e24499007 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
@@ -996,9 +996,8 @@ define void @test_monotonic_ptr_iv_inc_1_loop_exits_on_ne(ptr %start, i16 %len)
 ; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 1
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    ret void
 ;
@@ -1083,4 +1082,3 @@ loop.latch:
 exit:
   ret void
 }
-
diff --git a/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned-is-known-non-negative.ll b/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned-is-known-non-negative.ll
index efb218ff099fb0..645411cc687d13 100644
--- a/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned-is-known-non-negative.ll
+++ b/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned-is-known-non-negative.ll
@@ -65,8 +65,7 @@ define void @iv_known_non_negative_constant_trip_count_no_nsw_flag(i8 %N) {
 ; CHECK-NEXT:    call void @use(i1 [[F_1]])
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp sle i8 [[N]], [[IV]]
 ; CHECK-NEXT:    call void @use(i1 [[F_2]])
-; CHECK-NEXT:    [[C_0:%.*]] = icmp ugt i8 [[IV]], 2
-; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw i8 [[IV]], 1
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit.1:

>From 3a5592a34a49d384a0dd5b7fc230cd3475bfee38 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Fri, 11 Oct 2024 22:12:44 -0700
Subject: [PATCH 3/6] Added regression test

---
 .../ConstraintElimination/loop-removal.ll     | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 llvm/test/Transforms/ConstraintElimination/loop-removal.ll

diff --git a/llvm/test/Transforms/ConstraintElimination/loop-removal.ll b/llvm/test/Transforms/ConstraintElimination/loop-removal.ll
new file mode 100644
index 00000000000000..9f963b1ff7aaf0
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/loop-removal.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=constraint-elimination -S | FileCheck %s
+
+define i32 @foo() {
+; CHECK-LABEL: define i32 @foo() {
+; CHECK-NEXT:  init:
+; CHECK-NEXT:    br label %[[OUTER_LOOP_CONTROL:.*]]
+; CHECK:       outer.loop.control:
+; CHECK-NEXT:    [[X_0:%.*]] = phi i32 [ 0, [[INIT:%.*]] ], [ [[X_OUTER:%.*]], %[[OUTER_LOOP_INC:.*]] ]
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp slt i32 [[X_0]], 10
+; CHECK-NEXT:    br i1 [[TMP0]], label %[[INNER_LOOP_CONTROL:.*]], label %[[EXIT:.*]]
+; CHECK:       inner.loop.control:
+; CHECK-NEXT:    [[X_1:%.*]] = phi i32 [ [[X_0]], %[[OUTER_LOOP_CONTROL]] ], [ [[X_INNER:%.*]], %[[INNER_LOOP_BODY:.*]] ]
+; CHECK-NEXT:    br i1 false, label %[[INNER_LOOP_BODY]], label %[[OUTER_LOOP_INC]]
+; CHECK:       inner.loop.body:
+; CHECK-NEXT:    [[X_INNER]] = add nsw i32 [[X_1]], -1
+; CHECK-NEXT:    br label %[[INNER_LOOP_CONTROL]]
+; CHECK:       outer.loop.inc:
+; CHECK-NEXT:    [[X_OUTER]] = add nsw i32 [[X_1]], 2
+; CHECK-NEXT:    br label %[[OUTER_LOOP_CONTROL]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 [[X_0]]
+;
+init:
+  br label %outer.loop.control
+
+outer.loop.control:                                                ; preds = %init, %outer.loop.inc
+  %x.0 = phi i32 [ 0, %init ], [ %x.outer, %outer.loop.inc ]
+  %0 = icmp slt i32 %x.0, 10
+  br i1 %0, label %inner.loop.control, label %exit
+
+inner.loop.control:                                                ; preds = %outer.loop.control, %inner.loop.body
+  %x.1 = phi i32 [ %x.0, %outer.loop.control ], [ %x.inner, %inner.loop.body ]
+  %1 = icmp sgt i32 %x.1, 20
+  br i1 %1, label %inner.loop.body, label %outer.loop.inc
+
+inner.loop.body:                                                ; preds = %inner.loop.control
+  %x.inner = add nsw i32 %x.1, -1
+  br label %inner.loop.control
+
+outer.loop.inc:                                                ; preds = %inner.loop.control
+  %x.outer = add nsw i32 %x.1, 2
+  br label %outer.loop.control
+
+exit:                                               ; preds = %1
+  ret i32 %x.0
+}

>From de54a169208204934e049f7f279bd4b6fd8295a1 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Sat, 12 Oct 2024 22:49:24 -0700
Subject: [PATCH 4/6] Restrict to functions with smaller number of conditional
 branches

---
 .../Scalar/ConstraintElimination.cpp          | 63 ++++++++++++-------
 1 file changed, 40 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 56cc26093cee87..e4b93789a67fde 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -186,9 +186,12 @@ struct State {
   LoopInfo &LI;
   ScalarEvolution &SE;
   SmallVector<FactOrCheck, 64> WorkList;
+  bool AddInductionInfoIntoHeader = false;
 
-  State(DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE)
-      : DT(DT), LI(LI), SE(SE) {}
+  State(DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE,
+        bool AddInductionInfoIntoHeader = false)
+      : DT(DT), LI(LI), SE(SE),
+        AddInductionInfoIntoHeader(AddInductionInfoIntoHeader) {}
 
   /// Process block \p BB and add known facts to work-list.
   void addInfoFor(BasicBlock &BB);
@@ -198,7 +201,7 @@ struct State {
   void addInfoForInductions(BasicBlock &BB);
 
   void addConditionFactsIntoLoopHeader(BasicBlock &BB);
-  
+
   /// Returns true if we can add a known condition from BB to its successor
   /// block Succ.
   bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ) const {
@@ -910,8 +913,9 @@ void State::addConditionFactsIntoLoopHeader(BasicBlock &BB) {
   if (!L || L->getHeader() != &BB)
     return;
   DomTreeNode *DTN = DT.getNode(&BB);
-  for(PHINode &PN :L->getHeader()->phis()){
-    if(PN.getNumIncomingValues() != 2 || PN.getParent() != &BB || !SE.isSCEVable(PN.getType()))
+  for (PHINode &PN : L->getHeader()->phis()) {
+    if (PN.getNumIncomingValues() != 2 || PN.getParent() != &BB ||
+        !SE.isSCEVable(PN.getType()))
       continue;
     auto *AR = dyn_cast_or_null<SCEVAddRecExpr>(SE.getSCEV(&PN));
     BasicBlock *LoopPred = L->getLoopPredecessor();
@@ -927,35 +931,36 @@ void State::addConditionFactsIntoLoopHeader(BasicBlock &BB) {
     }
     auto IncUnsigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_UGT);
     auto IncSigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_SGT);
-    
-    // Monotonically Increasing 
+
+    // Monotonically Increasing
     bool MonotonicallyIncreasingUnsigned =
-      IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyIncreasing;
+        IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyIncreasing;
     bool MonotonicallyIncreasingSigned =
         IncSigned && *IncSigned == ScalarEvolution::MonotonicallyIncreasing;
     if (MonotonicallyIncreasingUnsigned)
-      WorkList.push_back(
-          FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_UGE, &PN, StartValue));
+      WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_UGE,
+                                                       &PN, StartValue));
     if (MonotonicallyIncreasingSigned)
-      WorkList.push_back(
-          FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SGE, &PN, StartValue));
+      WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SGE,
+                                                       &PN, StartValue));
 
     // Monotonically Decreasing
     bool MonotonicallyDecreasingUnsigned =
-      IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyDecreasing;
+        IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyDecreasing;
     bool MonotonicallyDecreasingSigned =
         IncSigned && *IncSigned == ScalarEvolution::MonotonicallyDecreasing;
-    if(MonotonicallyDecreasingUnsigned)
-      WorkList.push_back(
-          FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_ULE, &PN, StartValue));
-    if(MonotonicallyDecreasingSigned)
-      WorkList.push_back(
-          FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SLE, &PN, StartValue));
-  }        
+    if (MonotonicallyDecreasingUnsigned)
+      WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_ULE,
+                                                       &PN, StartValue));
+    if (MonotonicallyDecreasingSigned)
+      WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SLE,
+                                                       &PN, StartValue));
+  }
 }
 
 void State::addInfoForInductions(BasicBlock &BB) {
-  addConditionFactsIntoLoopHeader(BB);
+  if (AddInductionInfoIntoHeader)
+    addConditionFactsIntoLoopHeader(BB);
   auto *L = LI.getLoopFor(&BB);
   if (!L || L->getHeader() != &BB)
     return;
@@ -1413,7 +1418,7 @@ static std::optional<bool> checkCondition(CmpInst::Predicate Pred, Value *A,
   LLVM_DEBUG(dbgs() << "Checking " << *CheckInst << "\n");
 
   auto R = Info.getConstraintForSolving(Pred, A, B);
-  if (R.empty() || !R.isValid(Info)){
+  if (R.empty() || !R.isValid(Info)) {
     LLVM_DEBUG(dbgs() << "   failed to decompose condition\n");
     return std::nullopt;
   }
@@ -1726,6 +1731,16 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
   return Changed;
 }
 
+static unsigned int getNumConditionalBranches(Function &F) {
+  unsigned int NumCondBranches = 0;
+  for (BasicBlock &BB : F) {
+    BranchInst *BranchInstr = dyn_cast_or_null<BranchInst>(BB.getTerminator());
+    if (BranchInstr && BranchInstr->isConditional())
+      NumCondBranches++;
+  }
+  return NumCondBranches;
+}
+
 static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
                                  ScalarEvolution &SE,
                                  OptimizationRemarkEmitter &ORE) {
@@ -1735,7 +1750,9 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
   for (Value &Arg : F.args())
     FunctionArgs.push_back(&Arg);
   ConstraintInfo Info(F.getDataLayout(), FunctionArgs);
-  State S(DT, LI, SE);
+  unsigned int NumCondBranches = getNumConditionalBranches(F);
+  State S(DT, LI, SE,
+          /* AddInductionInfoIntoHeader= */ NumCondBranches < MaxRows / 5);
   std::unique_ptr<Module> ReproducerModule(
       DumpReproducers ? new Module(F.getName(), F.getContext()) : nullptr);
 

>From 4bc49ac9397c29e5d2846134d4d9b899a465f499 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Fri, 25 Oct 2024 23:24:56 -0700
Subject: [PATCH 5/6] Added overflow test and fixed Polly test

---
 .../Scalar/ConstraintElimination.cpp          |  2 +-
 .../ConstraintElimination/loop-removal.ll     | 51 +++++++++++++++++++
 polly/test/Support/pipelineposition.ll        |  2 +-
 3 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index e4b93789a67fde..dadcc793138a61 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -920,7 +920,7 @@ void State::addConditionFactsIntoLoopHeader(BasicBlock &BB) {
     auto *AR = dyn_cast_or_null<SCEVAddRecExpr>(SE.getSCEV(&PN));
     BasicBlock *LoopPred = L->getLoopPredecessor();
     if (!AR || AR->getLoop() != L || !LoopPred)
-      return;
+      continue;
     const SCEV *StartSCEV = AR->getStart();
     Value *StartValue = nullptr;
     if (auto *C = dyn_cast<SCEVConstant>(StartSCEV)) {
diff --git a/llvm/test/Transforms/ConstraintElimination/loop-removal.ll b/llvm/test/Transforms/ConstraintElimination/loop-removal.ll
index 9f963b1ff7aaf0..752cca10c40ddb 100644
--- a/llvm/test/Transforms/ConstraintElimination/loop-removal.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loop-removal.ll
@@ -45,3 +45,54 @@ outer.loop.inc:                                                ; preds = %inner.
 exit:                                               ; preds = %1
   ret i32 %x.0
 }
+
+; int foo_with_overflow(unsigned x, int y){
+;     unsigned i = x;
+;     while(i < 10 || i > 20){
+;         if(i > x){
+;             y -= 23;
+;         }
+;         i -= 1;
+;     }
+;     return y;
+; }
+define dso_local noundef i32 @foo_with_overflow(i32 noundef %x, i32 noundef %y) local_unnamed_addr #0 {
+; CHECK-LABEL: i32 @foo_with_overflow(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[X:%.*]], -21
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[TMP0]], -11
+; CHECK-NEXT:    br i1 [[TMP1]], label %[[WHILE_BODY:.*]], label %[[WHILE_END:.*]]
+; CHECK:       while.body:
+; CHECK-NEXT:    [[I_02:%.*]] = phi i32 [ [[SUB3:%.*]], %[[WHILE_BODY]] ], [ [[X]], %[[ENTRY:.*]] ]
+; CHECK-NEXT:    [[Y_ADDR_01:%.*]] = phi i32 [ [[SPEC_SELECT:%.*]], %[[WHILE_BODY]] ], [ [[Y:%.*]], %[[ENTRY]] ]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i32 [[I_02]], [[X]]
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[Y_ADDR_01]], -23
+; CHECK-NEXT:    [[SPEC_SELECT]] = select i1 [[CMP2]], i32 [[SUB]], i32 [[Y_ADDR_01]]
+; CHECK-NEXT:    [[SUB3]] = add i32 [[I_02]], -1
+; CHECK-NEXT:    [[DOTREASS:%.*]] = add i32 [[I_02]], -22
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[DOTREASS]], -11
+; CHECK-NEXT:    br i1 [[TMP2]], label %[[WHILE_BODY]], label %[[WHILE_END]]
+; CHECK:       while.end:
+; CHECK-NEXT:    [[Y_ADDR_0_LCSSA:%.*]] = phi i32 [ [[Y]], %[[ENTRY]] ], [ [[SPEC_SELECT]], %[[WHILE_BODY]] ]
+; CHECK-NEXT:    ret i32 [[Y_ADDR_0_LCSSA]]
+;
+entry:
+  %0 = add i32 %x, -21
+  %1 = icmp ult i32 %0, -11
+  br i1 %1, label %while.body, label %while.end
+
+while.body:                                       ; preds = %entry, %while.body
+  %i.02 = phi i32 [ %sub3, %while.body ], [ %x, %entry ]
+  %y.addr.01 = phi i32 [ %spec.select, %while.body ], [ %y, %entry ]
+  %cmp2 = icmp ugt i32 %i.02, %x
+  %sub = add nsw i32 %y.addr.01, -23
+  %spec.select = select i1 %cmp2, i32 %sub, i32 %y.addr.01
+  %sub3 = add i32 %i.02, -1
+  %.reass = add i32 %i.02, -22
+  %2 = icmp ult i32 %.reass, -11
+  br i1 %2, label %while.body, label %while.end
+
+while.end:                                        ; preds = %while.body, %entry
+  %y.addr.0.lcssa = phi i32 [ %y, %entry ], [ %spec.select, %while.body ]
+  ret i32 %y.addr.0.lcssa
+}
diff --git a/polly/test/Support/pipelineposition.ll b/polly/test/Support/pipelineposition.ll
index a4506ba1d64ed7..8dbb0593f65d5b 100644
--- a/polly/test/Support/pipelineposition.ll
+++ b/polly/test/Support/pipelineposition.ll
@@ -81,4 +81,4 @@ return:
 
 ; INLINED3-LABEL: Function: caller
 ; INLINED3:       Schedule :=
-; INLINED3-NEXT:    [n] -> { Stmt_body_i_us[i0, i1] -> [i0, i1] };
+; INLINED3-NEXT:    [n] -> { Stmt_body_i[i0, i1] -> [i0, i1] };

>From cff36560058ef92b98f39702b31e91046bc54512 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Sat, 26 Oct 2024 15:19:53 -0700
Subject: [PATCH 6/6] Refactored common code into functions

---
 .../Scalar/ConstraintElimination.cpp          | 125 ++++++++++--------
 1 file changed, 68 insertions(+), 57 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index dadcc793138a61..f853bb390e60ad 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -200,7 +200,7 @@ struct State {
   /// controlling the loop header.
   void addInfoForInductions(BasicBlock &BB);
 
-  void addConditionFactsIntoLoopHeader(BasicBlock &BB);
+  void addConditionFactsIntoLoopHeader(Loop &L);
 
   /// Returns true if we can add a known condition from BB to its successor
   /// block Succ.
@@ -905,65 +905,88 @@ static void dumpConstraint(ArrayRef<int64_t> C,
 }
 #endif
 
+static Value *getStartValueFromAddRec(PHINode &PN, Loop &L,
+                                      ScalarEvolution &SE) {
+  auto *AR = dyn_cast_or_null<SCEVAddRecExpr>(SE.getSCEV(&PN));
+  const SCEV *StartSCEV = AR->getStart();
+  Value *StartValue = nullptr;
+  BasicBlock *LoopPred = L.getLoopPredecessor();
+  if (auto *C = dyn_cast<SCEVConstant>(StartSCEV)) {
+    StartValue = C->getValue();
+  } else {
+    StartValue = PN.getIncomingValueForBlock(LoopPred);
+    assert(SE.getSCEV(StartValue) == StartSCEV && "inconsistent start value");
+  }
+  return StartValue;
+}
+
+struct MonotonicityInfo {
+  std::optional<ScalarEvolution::MonotonicPredicateType> UnsignedPredicateType;
+  std::optional<ScalarEvolution::MonotonicPredicateType> SignedPredicateType;
+  bool isUnsignedIncreasing() const {
+    return UnsignedPredicateType &&
+           *UnsignedPredicateType == ScalarEvolution::MonotonicallyIncreasing;
+  }
+  bool isUnsignedDecreasing() const {
+    return UnsignedPredicateType &&
+           *UnsignedPredicateType == ScalarEvolution::MonotonicallyDecreasing;
+  }
+  bool isSignedIncreasing() const {
+    return SignedPredicateType &&
+           *SignedPredicateType == ScalarEvolution::MonotonicallyIncreasing;
+  }
+  bool isSignedDecreasing() const {
+    return SignedPredicateType &&
+           *SignedPredicateType == ScalarEvolution::MonotonicallyDecreasing;
+  }
+};
+
+static MonotonicityInfo getMonotonicityInfo(const SCEVAddRecExpr *AR,
+                                            ScalarEvolution &SE) {
+  MonotonicityInfo MI;
+  MI.UnsignedPredicateType =
+      SE.getMonotonicPredicateType(AR, CmpInst::ICMP_UGT);
+  MI.SignedPredicateType = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_SGT);
+  return MI;
+}
+
 // For monotonically decreasing/increasing variables in the loop,
 // this will insert ConditionFact PN >= StartingValue or PN <= StartingValue
 // associated with the loop header, where PN is the corresponding PHi node.
-void State::addConditionFactsIntoLoopHeader(BasicBlock &BB) {
-  auto *L = LI.getLoopFor(&BB);
-  if (!L || L->getHeader() != &BB)
-    return;
+void State::addConditionFactsIntoLoopHeader(Loop &L) {
+  BasicBlock &BB = *L.getHeader();
   DomTreeNode *DTN = DT.getNode(&BB);
-  for (PHINode &PN : L->getHeader()->phis()) {
-    if (PN.getNumIncomingValues() != 2 || PN.getParent() != &BB ||
-        !SE.isSCEVable(PN.getType()))
+  for (PHINode &PN : BB.phis()) {
+    if (PN.getNumIncomingValues() != 2 || !SE.isSCEVable(PN.getType()))
       continue;
     auto *AR = dyn_cast_or_null<SCEVAddRecExpr>(SE.getSCEV(&PN));
-    BasicBlock *LoopPred = L->getLoopPredecessor();
-    if (!AR || AR->getLoop() != L || !LoopPred)
+    BasicBlock *LoopPred = L.getLoopPredecessor();
+    if (!AR || AR->getLoop() != &L || !LoopPred)
       continue;
-    const SCEV *StartSCEV = AR->getStart();
-    Value *StartValue = nullptr;
-    if (auto *C = dyn_cast<SCEVConstant>(StartSCEV)) {
-      StartValue = C->getValue();
-    } else {
-      StartValue = PN.getIncomingValueForBlock(LoopPred);
-      assert(SE.getSCEV(StartValue) == StartSCEV && "inconsistent start value");
-    }
-    auto IncUnsigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_UGT);
-    auto IncSigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_SGT);
-
-    // Monotonically Increasing
-    bool MonotonicallyIncreasingUnsigned =
-        IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyIncreasing;
-    bool MonotonicallyIncreasingSigned =
-        IncSigned && *IncSigned == ScalarEvolution::MonotonicallyIncreasing;
-    if (MonotonicallyIncreasingUnsigned)
+    Value *StartValue = getStartValueFromAddRec(PN, L, SE);
+    auto MI = getMonotonicityInfo(AR, SE);
+
+    if (MI.isUnsignedIncreasing())
       WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_UGE,
                                                        &PN, StartValue));
-    if (MonotonicallyIncreasingSigned)
+    if (MI.isSignedIncreasing())
       WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SGE,
                                                        &PN, StartValue));
-
-    // Monotonically Decreasing
-    bool MonotonicallyDecreasingUnsigned =
-        IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyDecreasing;
-    bool MonotonicallyDecreasingSigned =
-        IncSigned && *IncSigned == ScalarEvolution::MonotonicallyDecreasing;
-    if (MonotonicallyDecreasingUnsigned)
+    if (MI.isUnsignedDecreasing())
       WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_ULE,
                                                        &PN, StartValue));
-    if (MonotonicallyDecreasingSigned)
+    if (MI.isSignedDecreasing())
       WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SLE,
                                                        &PN, StartValue));
   }
 }
 
 void State::addInfoForInductions(BasicBlock &BB) {
-  if (AddInductionInfoIntoHeader)
-    addConditionFactsIntoLoopHeader(BB);
   auto *L = LI.getLoopFor(&BB);
   if (!L || L->getHeader() != &BB)
     return;
+  if (AddInductionInfoIntoHeader)
+    addConditionFactsIntoLoopHeader(*L);
 
   Value *A;
   Value *B;
@@ -999,28 +1022,16 @@ void State::addInfoForInductions(BasicBlock &BB) {
   if (!AR || AR->getLoop() != L || !LoopPred)
     return;
 
-  const SCEV *StartSCEV = AR->getStart();
-  Value *StartValue = nullptr;
-  if (auto *C = dyn_cast<SCEVConstant>(StartSCEV)) {
-    StartValue = C->getValue();
-  } else {
-    StartValue = PN->getIncomingValueForBlock(LoopPred);
-    assert(SE.getSCEV(StartValue) == StartSCEV && "inconsistent start value");
-  }
+  Value *StartValue = getStartValueFromAddRec(*PN, *L, SE);
+  auto MI = getMonotonicityInfo(AR, SE);
 
   DomTreeNode *DTN = DT.getNode(InLoopSucc);
-  auto IncUnsigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_UGT);
-  auto IncSigned = SE.getMonotonicPredicateType(AR, CmpInst::ICMP_SGT);
-  bool MonotonicallyIncreasingUnsigned =
-      IncUnsigned && *IncUnsigned == ScalarEvolution::MonotonicallyIncreasing;
-  bool MonotonicallyIncreasingSigned =
-      IncSigned && *IncSigned == ScalarEvolution::MonotonicallyIncreasing;
   // If SCEV guarantees that AR does not wrap, PN >= StartValue can be added
   // unconditionally.
-  if (MonotonicallyIncreasingUnsigned)
+  if (MI.isUnsignedIncreasing())
     WorkList.push_back(
         FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_UGE, PN, StartValue));
-  if (MonotonicallyIncreasingSigned)
+  if (MI.isSignedIncreasing())
     WorkList.push_back(
         FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SGE, PN, StartValue));
 
@@ -1068,7 +1079,7 @@ void State::addInfoForInductions(BasicBlock &BB) {
 
   if (!StepOffset.isOne()) {
     // Check whether B-Start is known to be a multiple of StepOffset.
-    const SCEV *BMinusStart = SE.getMinusSCEV(SE.getSCEV(B), StartSCEV);
+    const SCEV *BMinusStart = SE.getMinusSCEV(SE.getSCEV(B), AR->getStart());
     if (isa<SCEVCouldNotCompute>(BMinusStart) ||
         !SE.getConstantMultiple(BMinusStart).urem(StepOffset).isZero())
       return;
@@ -1077,11 +1088,11 @@ void State::addInfoForInductions(BasicBlock &BB) {
   // AR may wrap. Add PN >= StartValue conditional on StartValue <= B which
   // guarantees that the loop exits before wrapping in combination with the
   // restrictions on B and the step above.
-  if (!MonotonicallyIncreasingUnsigned)
+  if (!MI.isUnsignedIncreasing())
     WorkList.push_back(FactOrCheck::getConditionFact(
         DTN, CmpInst::ICMP_UGE, PN, StartValue,
         ConditionTy(CmpInst::ICMP_ULE, StartValue, B)));
-  if (!MonotonicallyIncreasingSigned)
+  if (!MI.isSignedIncreasing())
     WorkList.push_back(FactOrCheck::getConditionFact(
         DTN, CmpInst::ICMP_SGE, PN, StartValue,
         ConditionTy(CmpInst::ICMP_SLE, StartValue, B)));



More information about the llvm-commits mailing list