[llvm] [ConstraintElim] Look through post-increment in header EQ/NE compare. (PR #209199)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 13 07:50:16 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Florian Hahn (fhahn)
<details>
<summary>Changes</summary>
Extend the header-controlled induction handling to look through a post-increment `PN + C` (constant C) on the compared value
For now, the new path is limited to deriving unsigned facts.
Alive2 Proof: https://alive2.llvm.org/ce/z/DCNeSr
---
Full diff: https://github.com/llvm/llvm-project/pull/209199.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/ConstraintElimination.cpp (+37-11)
- (modified) llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll (+2-2)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 7f9afe1be6e0e..268e95204f8b8 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -941,12 +941,18 @@ void State::addInfoForInductions(BasicBlock &BB) {
if (!L || L->getHeader() != &BB)
return;
- PHINode *PN;
+ // A is either a phi or a post-increment PN + C with constant step. For the
+ // latter, extract the constant IncStep.
+ Value *A;
Value *B;
+ PHINode *PN = nullptr;
+ const APInt *IncStep = nullptr;
CmpPredicate Pred;
+ auto IndValue =
+ m_Value(A, m_CombineOr(m_Phi(PN), m_c_Add(m_Phi(PN), m_APInt(IncStep))));
if (!match(BB.getTerminator(),
- m_Br(m_c_ICmp(Pred, m_Phi(PN), m_Value(B)), m_Value(), m_Value())))
+ m_Br(m_c_ICmp(Pred, IndValue, m_Value(B)), m_Value(), m_Value())))
return;
if (PN->getParent() != &BB || PN->getNumIncomingValues() != 2 ||
!SE.isSCEVable(PN->getType()))
@@ -1003,6 +1009,11 @@ void State::addInfoForInductions(BasicBlock &BB) {
if (!L->isLoopInvariant(B))
return;
+ // If we looked through `PN + C`, only derive facts when that add is
+ // really the induction's post-increment.
+ if (IncStep && (*IncStep != StepOffset || StepOffset.isNegative()))
+ return;
+
// Handle negative steps.
if (StepOffset.isNegative()) {
// TODO: Extend to allow steps > -1.
@@ -1043,24 +1054,39 @@ void State::addInfoForInductions(BasicBlock &BB) {
return;
}
- // AR may wrap. Add PN >= StartValue conditional on StartValue <= B which
+ Value *LowerBound = StartValue;
+ if (IncStep) {
+ // Adjust lower bound when dealing with a post-increment value.
+ auto *StartC = dyn_cast<ConstantInt>(StartValue);
+ if (!StartC)
+ return;
+ bool Overflow = false;
+ APInt Sum = StartC->getValue().uadd_ov(StepOffset, Overflow);
+ if (Overflow)
+ return;
+ LowerBound = ConstantInt::get(StartValue->getType(), Sum);
+ }
+
+ // AR may wrap. Add PN >= StartValue conditional on LowerBound <= B which
// guarantees that the loop exits before wrapping in combination with the
// restrictions on B and the step above.
if (!MonotonicallyIncreasingUnsigned)
WorkList.push_back(FactOrCheck::getConditionFact(
DTN, CmpInst::ICMP_UGE, PN, StartValue,
- ConditionTy(CmpInst::ICMP_ULE, StartValue, B)));
- if (!MonotonicallyIncreasingSigned)
+ ConditionTy(CmpInst::ICMP_ULE, LowerBound, B)));
+ // Only unsigned facts are derived for the post-increment path.
+ if (!MonotonicallyIncreasingSigned && !IncStep)
WorkList.push_back(FactOrCheck::getConditionFact(
DTN, CmpInst::ICMP_SGE, PN, StartValue,
ConditionTy(CmpInst::ICMP_SLE, StartValue, B)));
WorkList.push_back(FactOrCheck::getConditionFact(
DTN, CmpInst::ICMP_ULT, PN, B,
- ConditionTy(CmpInst::ICMP_ULE, StartValue, B)));
- WorkList.push_back(FactOrCheck::getConditionFact(
- DTN, CmpInst::ICMP_SLT, PN, B,
- ConditionTy(CmpInst::ICMP_SLE, StartValue, B)));
+ ConditionTy(CmpInst::ICMP_ULE, LowerBound, B)));
+ if (!IncStep)
+ WorkList.push_back(FactOrCheck::getConditionFact(
+ DTN, CmpInst::ICMP_SLT, PN, B,
+ ConditionTy(CmpInst::ICMP_SLE, StartValue, B)));
// Try to add condition from header to the dedicated exit blocks. When exiting
// either with EQ or NE in the header, we know that the induction value must
@@ -1068,14 +1094,14 @@ void State::addInfoForInductions(BasicBlock &BB) {
assert(!StepOffset.isNegative() && "induction must be increasing");
assert((Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE) &&
"unsupported predicate");
- ConditionTy Precond = {CmpInst::ICMP_ULE, StartValue, B};
+ ConditionTy Precond = {CmpInst::ICMP_ULE, LowerBound, B};
SmallVector<BasicBlock *> ExitBBs;
L->getExitBlocks(ExitBBs);
for (BasicBlock *EB : ExitBBs) {
// Bail out on non-dedicated exits.
if (DT.dominates(&BB, EB)) {
WorkList.emplace_back(FactOrCheck::getConditionFact(
- DT.getNode(EB), CmpInst::ICMP_ULE, PN, B, Precond));
+ DT.getNode(EB), CmpInst::ICMP_ULE, A, B, Precond));
}
}
}
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 df0cb40965430..66aeb85bf0a93 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
@@ -210,9 +210,9 @@ 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: br i1 [[CMP_IV_END]], label [[TRAP_BB]], label [[LOOP_BODY_1:%.*]]
+; CHECK-NEXT: [[OR_1:%.*]] = or i1 false, [[CMP_IV_END]]
+; CHECK-NEXT: br i1 [[OR_1]], label [[TRAP_BB]], label [[LOOP_BODY_1:%.*]]
; CHECK: loop.body.1:
; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[IV]], 1
; CHECK-NEXT: [[SRC_IV_1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[ADD_1]]
``````````
</details>
https://github.com/llvm/llvm-project/pull/209199
More information about the llvm-commits
mailing list