[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