From b0da99d35286055d13733e5519c5d8d2ee69f865 Mon Sep 17 00:00:00 2001 From: Grigory Pastukhov Date: Fri, 11 Oct 2024 19:31:04 -0700 Subject: [PATCH 1/7] 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 7c06e0c757e1c..56cc26093cee8 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 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(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(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 Date: Fri, 11 Oct 2024 21:32:54 -0700 Subject: [PATCH 2/7] 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 6bbc73c9c996c..ab1733caf10d1 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 3dbea9496da8d..6510fbb9d260f 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 279238bea1842..b003553ff51b2 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 7b928a030614b..5ff8798730077 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 1842ca2d82545..57191a8ebc087 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 eb252d1a5444e..8863907ecfd50 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 17aa4d54abfba..2a58220b78f00 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 6b128d9e525ca..16c8beff2780c 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 f05f324ef9322..07f10c342ac6f 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 b3432695a96a5..11ab1e2449900 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 efb218ff099fb..645411cc687d1 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 Date: Fri, 11 Oct 2024 22:12:44 -0700 Subject: [PATCH 3/7] 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 0000000000000..9f963b1ff7aaf --- /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 Date: Sat, 12 Oct 2024 22:49:24 -0700 Subject: [PATCH 4/7] 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 56cc26093cee8..e4b93789a67fd 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 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(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 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(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 ReproducerModule( DumpReproducers ? new Module(F.getName(), F.getContext()) : nullptr); From 4bc49ac9397c29e5d2846134d4d9b899a465f499 Mon Sep 17 00:00:00 2001 From: Grigory Pastukhov Date: Fri, 25 Oct 2024 23:24:56 -0700 Subject: [PATCH 5/7] 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 e4b93789a67fd..dadcc793138a6 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(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(StartSCEV)) { diff --git a/llvm/test/Transforms/ConstraintElimination/loop-removal.ll b/llvm/test/Transforms/ConstraintElimination/loop-removal.ll index 9f963b1ff7aaf..752cca10c40dd 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 a4506ba1d64ed..8dbb0593f65d5 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 Date: Sat, 26 Oct 2024 15:19:53 -0700 Subject: [PATCH 6/7] 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 dadcc793138a6..f853bb390e60a 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 C, } #endif +static Value *getStartValueFromAddRec(PHINode &PN, Loop &L, + ScalarEvolution &SE) { + auto *AR = dyn_cast_or_null(SE.getSCEV(&PN)); + const SCEV *StartSCEV = AR->getStart(); + Value *StartValue = nullptr; + BasicBlock *LoopPred = L.getLoopPredecessor(); + if (auto *C = dyn_cast(StartSCEV)) { + StartValue = C->getValue(); + } else { + StartValue = PN.getIncomingValueForBlock(LoopPred); + assert(SE.getSCEV(StartValue) == StartSCEV && "inconsistent start value"); + } + return StartValue; +} + +struct MonotonicityInfo { + std::optional UnsignedPredicateType; + std::optional 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(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(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(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(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))); From bcc8bf4b79be49e65b0dd0872a464be0abc5a7fc Mon Sep 17 00:00:00 2001 From: Grigory Pastukhov Date: Mon, 4 Nov 2024 10:09:13 -0800 Subject: [PATCH 7/7] Removed unnecessary cast --- llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index f853bb390e60a..4298b207f8ced 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -905,10 +905,9 @@ static void dumpConstraint(ArrayRef C, } #endif -static Value *getStartValueFromAddRec(PHINode &PN, Loop &L, - ScalarEvolution &SE) { - auto *AR = dyn_cast_or_null(SE.getSCEV(&PN)); - const SCEV *StartSCEV = AR->getStart(); +static Value *getStartValueFromAddRec(const SCEVAddRecExpr &AR, PHINode &PN, + Loop &L, ScalarEvolution &SE) { + const SCEV *StartSCEV = AR.getStart(); Value *StartValue = nullptr; BasicBlock *LoopPred = L.getLoopPredecessor(); if (auto *C = dyn_cast(StartSCEV)) { @@ -963,7 +962,7 @@ void State::addConditionFactsIntoLoopHeader(Loop &L) { BasicBlock *LoopPred = L.getLoopPredecessor(); if (!AR || AR->getLoop() != &L || !LoopPred) continue; - Value *StartValue = getStartValueFromAddRec(PN, L, SE); + Value *StartValue = getStartValueFromAddRec(*AR, PN, L, SE); auto MI = getMonotonicityInfo(AR, SE); if (MI.isUnsignedIncreasing()) @@ -1022,7 +1021,7 @@ void State::addInfoForInductions(BasicBlock &BB) { if (!AR || AR->getLoop() != L || !LoopPred) return; - Value *StartValue = getStartValueFromAddRec(*PN, *L, SE); + Value *StartValue = getStartValueFromAddRec(*AR, *PN, *L, SE); auto MI = getMonotonicityInfo(AR, SE); DomTreeNode *DTN = DT.getNode(InLoopSucc);