From 8310ce60596043e3ca50e4c03f779c2834b97fc6 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 6 Jun 2024 13:47:20 +0100 Subject: [PATCH 1/3] [ConstraintElim] Use cond from header as upper bound on IV in exit BB. For loops, we can use the condition in the loop header as upper bound on the compared induction in the unique exit block, if it exists. This can be done even if there are multiple in-loop edges to the unique exit block, as any other exit may only exit earlier. More generally, we could add the OR of all exit conditions to the exit, but that's a possible future extension. Fixes https://github.com/llvm/llvm-project/issues/90417. --- .../Transforms/Scalar/ConstraintElimination.cpp | 17 +++++++++++++++++ .../induction-condition-in-loop-exit.ll | 9 +++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 05012321d7244..976c0a9c2ee14 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1031,6 +1031,23 @@ void State::addInfoForInductions(BasicBlock &BB) { WorkList.push_back(FactOrCheck::getConditionFact( DTN, CmpInst::ICMP_SLT, PN, B, ConditionTy(CmpInst::ICMP_SLE, StartValue, B))); + + assert(!StepOffset.isNegative() && "induction must be increasing"); + // Try to add condition from header to the unique exit block, if there is one. + // When exiting either with EQ or NE, we know that the induction value must be + // u<= B, as a different exit may exit earlier. + if (Pred == CmpInst::ICMP_EQ) { + BasicBlock *EB = cast(BB.getTerminator())->getSuccessor(0); + if (L->getUniqueExitBlock() == EB) + WorkList.emplace_back(FactOrCheck::getConditionFact( + DT.getNode(EB), CmpInst::ICMP_ULE, A, B)); + } + if (Pred == CmpInst::ICMP_NE) { + BasicBlock *EB = cast(BB.getTerminator())->getSuccessor(1); + if (L->getUniqueExitBlock() == EB) + WorkList.emplace_back(FactOrCheck::getConditionFact( + DT.getNode(EB), CmpInst::ICMP_ULE, A, B)); + } } void State::addInfoFor(BasicBlock &BB) { diff --git a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll index 05c7c9e5b90d8..80a34d15c69c8 100644 --- a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll +++ b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll @@ -19,8 +19,7 @@ define i1 @multi_exiting_loop_eq_same_unique_exit_const_compare_known(ptr %s) { ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: br i1 [[LATCH_C]], label %[[LOOP_HEADER]], label %[[EXIT]] ; CHECK: [[EXIT]]: -; CHECK-NEXT: [[T:%.*]] = icmp ult i32 [[IV]], 1235 -; CHECK-NEXT: ret i1 [[T]] +; CHECK-NEXT: ret i1 true ; entry: br label %loop.header @@ -341,8 +340,7 @@ define i1 @multi_exiting_loop_eq_same_unique_exit_var_compare_known(ptr %s, i32 ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: br i1 [[LATCH_C]], label %[[LOOP_HEADER]], label %[[EXIT]] ; CHECK: [[EXIT]]: -; CHECK-NEXT: [[T:%.*]] = icmp ule i32 [[IV]], [[N]] -; CHECK-NEXT: ret i1 [[T]] +; CHECK-NEXT: ret i1 true ; entry: br label %loop.header @@ -419,8 +417,7 @@ define i1 @multi_exiting_loop_ne_same_unique_exit_const_compare_known(ptr %s) { ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: br i1 [[LATCH_C]], label %[[LOOP_HEADER]], label %[[EXIT]] ; CHECK: [[EXIT]]: -; CHECK-NEXT: [[T:%.*]] = icmp ult i32 [[IV]], 1235 -; CHECK-NEXT: ret i1 [[T]] +; CHECK-NEXT: ret i1 true ; entry: br label %loop.header From 474acb53f2d9a6ffd501ee4855ca2709a0b7ab45 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 6 Jun 2024 15:37:40 +0100 Subject: [PATCH 2/3] !fixup properly handle non-monotonically increasing case. --- llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 10 +++++++--- .../induction-condition-in-loop-exit.ll | 3 +-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 976c0a9c2ee14..99a7e6d6c4dc1 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1036,17 +1036,21 @@ void State::addInfoForInductions(BasicBlock &BB) { // Try to add condition from header to the unique exit block, if there is one. // When exiting either with EQ or NE, we know that the induction value must be // u<= B, as a different exit may exit earlier. + ConditionTy Precond; + if (!MonotonicallyIncreasingUnsigned) + Precond = {CmpInst::ICMP_ULE, StartValue, B}; if (Pred == CmpInst::ICMP_EQ) { BasicBlock *EB = cast(BB.getTerminator())->getSuccessor(0); - if (L->getUniqueExitBlock() == EB) + if (L->getUniqueExitBlock() == EB) { WorkList.emplace_back(FactOrCheck::getConditionFact( - DT.getNode(EB), CmpInst::ICMP_ULE, A, B)); + DT.getNode(EB), CmpInst::ICMP_ULE, A, B, Precond)); + } } if (Pred == CmpInst::ICMP_NE) { BasicBlock *EB = cast(BB.getTerminator())->getSuccessor(1); if (L->getUniqueExitBlock() == EB) WorkList.emplace_back(FactOrCheck::getConditionFact( - DT.getNode(EB), CmpInst::ICMP_ULE, A, B)); + DT.getNode(EB), CmpInst::ICMP_ULE, A, B, Precond)); } } diff --git a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll index 80a34d15c69c8..7996041605681 100644 --- a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll +++ b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll @@ -98,8 +98,7 @@ define i1 @multi_exiting_loop_eq_same_unique_exit_const_compare_known_due_to_pre ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 ; CHECK-NEXT: br i1 [[LATCH_C]], label %[[LOOP_HEADER]], label %[[EXIT]] ; CHECK: [[EXIT]]: -; CHECK-NEXT: [[T:%.*]] = icmp ult i32 [[IV]], 1235 -; CHECK-NEXT: ret i1 [[T]] +; CHECK-NEXT: ret i1 true ; entry: %pre.c = icmp ule i32 %start, 1234 From d51a03644e5c789eed7b5ebadeac62aee4800712 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 28 Jun 2024 15:36:28 +0100 Subject: [PATCH 3/3] !fixup always emit precondition, don't check unique predecessor --- .../Scalar/ConstraintElimination.cpp | 29 +++++++------------ .../induction-condition-in-loop-exit.ll | 3 +- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 99a7e6d6c4dc1..e1535a5cc01a1 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1032,25 +1032,18 @@ void State::addInfoForInductions(BasicBlock &BB) { DTN, CmpInst::ICMP_SLT, PN, B, ConditionTy(CmpInst::ICMP_SLE, StartValue, B))); + // Try to add condition from header to the exit blocks. When exiting either + // with EQ or NE in the header, we know that the induction value must be u<= + // B, as other exits may only exit earlier. assert(!StepOffset.isNegative() && "induction must be increasing"); - // Try to add condition from header to the unique exit block, if there is one. - // When exiting either with EQ or NE, we know that the induction value must be - // u<= B, as a different exit may exit earlier. - ConditionTy Precond; - if (!MonotonicallyIncreasingUnsigned) - Precond = {CmpInst::ICMP_ULE, StartValue, B}; - if (Pred == CmpInst::ICMP_EQ) { - BasicBlock *EB = cast(BB.getTerminator())->getSuccessor(0); - if (L->getUniqueExitBlock() == EB) { - WorkList.emplace_back(FactOrCheck::getConditionFact( - DT.getNode(EB), CmpInst::ICMP_ULE, A, B, Precond)); - } - } - if (Pred == CmpInst::ICMP_NE) { - BasicBlock *EB = cast(BB.getTerminator())->getSuccessor(1); - if (L->getUniqueExitBlock() == EB) - WorkList.emplace_back(FactOrCheck::getConditionFact( - DT.getNode(EB), CmpInst::ICMP_ULE, A, B, Precond)); + assert((Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE) && + "unsupported predicate"); + ConditionTy Precond = {CmpInst::ICMP_ULE, StartValue, B}; + SmallVector ExitBBs; + L->getExitBlocks(ExitBBs); + for (BasicBlock *EB : ExitBBs) { + WorkList.emplace_back(FactOrCheck::getConditionFact( + DT.getNode(EB), CmpInst::ICMP_ULE, A, B, Precond)); } } diff --git a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll index 7996041605681..15e1d84372627 100644 --- a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll +++ b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit.ll @@ -541,8 +541,7 @@ define i1 @multi_exiting_loop_eq_different_exits_2_const_compare_known(ptr %s, i ; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: br i1 [[LATCH_C]], label %[[LOOP_HEADER]], label %[[EXIT_2]] ; CHECK: [[EXIT_1]]: -; CHECK-NEXT: [[T_1:%.*]] = icmp ult i32 [[IV]], 1235 -; CHECK-NEXT: ret i1 [[T_1]] +; CHECK-NEXT: ret i1 true ; CHECK: [[EXIT_2]]: ; CHECK-NEXT: ret i1 true ;