[llvm] [ConstraintElim] Skip rows implied by a single existing row. (PR #227688)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 1 03:49:53 PDT 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/227688
>From a99d48551a157db45fc18460bd124580ce27970b Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 25 Sep 2026 12:04:49 +0100
Subject: [PATCH 1/2] [ConstraintElim] Skip rows implied by a single existing
row.
There are a number of cases where we add duplicated rows (e.g. from
transferring facts between the signed and unsigned systems, or from
tightening a non-strict bound using !=).
Before adding rows, check if the system already has a row that the same
variable coefficient and a constant that is <= the current constant.
This helps reduce compile-time, as each row adds extra work during
constraint solving:
stage1-O3: -0.02%
stage1-ReleaseThinLTO: -0.05%
stage1-ReleaseLTO-g: -0.02%
stage1-aarch64-O3: -0.00%
stage2-O3: -0.01%
stage2-clang: -0.00%
https://llvm-compile-time-tracker.com/compare.php?from=5da194580292bc90f6577f3959dda3a9bb6d5366&to=67f7d35c131b156663342cfae20d55e7a4187196&stat=instructions:u
The impact depends on the specific module and mostly in cases where the
number of facts is on the larger side. See additional compile-time impact
here https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1527
Fewer rows in the system can improve results in a few cases where we
previously hit the maximum rows cutoff:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1526.
---
llvm/include/llvm/Analysis/ConstraintSystem.h | 3 +++
llvm/lib/Analysis/ConstraintSystem.cpp | 15 ++++++++++++
.../Scalar/ConstraintElimination.cpp | 5 ++++
.../Analysis/ConstraintSystemTest.cpp | 23 +++++++++++++++++++
4 files changed, 46 insertions(+)
diff --git a/llvm/include/llvm/Analysis/ConstraintSystem.h b/llvm/include/llvm/Analysis/ConstraintSystem.h
index 11f40de9968c5..c14e0fbd8b9cf 100644
--- a/llvm/include/llvm/Analysis/ConstraintSystem.h
+++ b/llvm/include/llvm/Analysis/ConstraintSystem.h
@@ -155,6 +155,9 @@ class ConstraintSystem {
LLVM_ABI std::pair<ConstraintSystem, RowTy>
getSubSystem(ArrayRef<Entry> R) const;
+ /// Returns true if a single row of the system implies \p R.
+ LLVM_ABI bool isImpliedBySingleRow(ArrayRef<Entry> R) const;
+
LLVM_ABI bool isConditionImplied(RowTy R) const;
LLVM_ABI bool isConditionImpliedInSubSystem(ArrayRef<Entry> R) const;
diff --git a/llvm/lib/Analysis/ConstraintSystem.cpp b/llvm/lib/Analysis/ConstraintSystem.cpp
index 85ac780b5f720..c659b4de3bb13 100644
--- a/llvm/lib/Analysis/ConstraintSystem.cpp
+++ b/llvm/lib/Analysis/ConstraintSystem.cpp
@@ -279,6 +279,21 @@ ConstraintSystem::getSubSystem(ArrayRef<Entry> R) const {
return {std::move(SubSystem), std::move(NewR)};
}
+bool ConstraintSystem::isImpliedBySingleRow(ArrayRef<Entry> R) const {
+ int64_t C = getConstant(R);
+ if (hasConstantEntry(R))
+ R = R.drop_front();
+ return any_of(Constraints, [&](ArrayRef<Entry> Row) {
+ if (getConstant(Row) > C)
+ return false;
+ if (hasConstantEntry(Row))
+ Row = Row.drop_front();
+ return equal(Row, R, [](const Entry &A, const Entry &B) {
+ return A.Id == B.Id && A.Coefficient == B.Coefficient;
+ });
+ });
+}
+
bool ConstraintSystem::isConditionImplied(RowTy R) const {
// If all variable coefficients are 0, we have 'C >= 0'. If the constant is >=
// 0, R is always true, regardless of the system.
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index ae5f85374ad39..0870db6c004ca 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -2265,6 +2265,11 @@ void ConstraintInfo::addFactImpl(CmpInst::Predicate Pred, Value *A, Value *B,
LLVM_DEBUG(dbgs() << "Adding '"; dumpUnpackedICmp(dbgs(), Pred, A, B);
dbgs() << "'\n");
auto &CSToUse = getCS(R.IsSigned);
+ // A row implied by a single existing row adds no information. Rows in the
+ // system are removed in reverse order, so the existing row outlives R.
+ if (!R.isEq() && NewVariables.empty() &&
+ CSToUse.isImpliedBySingleRow(R.Coefficients))
+ return;
bool Added = CSToUse.addRow(R.Coefficients, R.NumVars);
if (!Added)
return;
diff --git a/llvm/unittests/Analysis/ConstraintSystemTest.cpp b/llvm/unittests/Analysis/ConstraintSystemTest.cpp
index a40131d4d2809..edd7fdd89aac3 100644
--- a/llvm/unittests/Analysis/ConstraintSystemTest.cpp
+++ b/llvm/unittests/Analysis/ConstraintSystemTest.cpp
@@ -169,6 +169,29 @@ TEST(ConstraintSolverTest, IsConditionImplied) {
}
}
+TEST(ConstraintSolverTest, IsImpliedBySingleRow) {
+ ConstraintSystem CS;
+ // x - y <= 0, y <= 5
+ addVariableRow(CS, {0, 1, -1});
+ addVariableRow(CS, {5, 0, 1});
+
+ // The same row, or one with a larger constant.
+ EXPECT_TRUE(CS.isImpliedBySingleRow(toRow({0, 1, -1})));
+ EXPECT_TRUE(CS.isImpliedBySingleRow(toRow({1, 1, -1})));
+ EXPECT_TRUE(CS.isImpliedBySingleRow(toRow({5, 0, 1})));
+ EXPECT_TRUE(CS.isImpliedBySingleRow(toRow({7, 0, 1})));
+ // A smaller constant.
+ EXPECT_FALSE(CS.isImpliedBySingleRow(toRow({-1, 1, -1})));
+ EXPECT_FALSE(CS.isImpliedBySingleRow(toRow({4, 0, 1})));
+ // Different coefficients.
+ EXPECT_FALSE(CS.isImpliedBySingleRow(toRow({0, 2, -2})));
+ EXPECT_FALSE(CS.isImpliedBySingleRow(toRow({0, -1, 1})));
+ EXPECT_FALSE(CS.isImpliedBySingleRow(toRow({5, 1, 1})));
+ // x <= 5 is implied by both rows together, but not by a single one.
+ EXPECT_TRUE(isConditionImplied(CS, {5, 1, 0}));
+ EXPECT_FALSE(CS.isImpliedBySingleRow(toRow({5, 1, 0})));
+}
+
TEST(ConstraintSolverTest, IsConditionImpliedOverflow) {
ConstraintSystem CS;
// Make sure isConditionImplied returns false when there is an overflow.
>From b6880734123dc8d5f7c72a14f7ddc937f8c54771 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 1 Oct 2026 11:44:15 +0100
Subject: [PATCH 2/2] !fixup move before debug output
---
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 0870db6c004ca..5c2ee9005b8dc 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -2262,14 +2262,14 @@ void ConstraintInfo::addFactImpl(CmpInst::Predicate Pred, Value *A, Value *B,
if (R.empty() || R.isNe())
return;
- LLVM_DEBUG(dbgs() << "Adding '"; dumpUnpackedICmp(dbgs(), Pred, A, B);
- dbgs() << "'\n");
auto &CSToUse = getCS(R.IsSigned);
// A row implied by a single existing row adds no information. Rows in the
// system are removed in reverse order, so the existing row outlives R.
if (!R.isEq() && NewVariables.empty() &&
CSToUse.isImpliedBySingleRow(R.Coefficients))
return;
+ LLVM_DEBUG(dbgs() << "Adding '"; dumpUnpackedICmp(dbgs(), Pred, A, B);
+ dbgs() << "'\n");
bool Added = CSToUse.addRow(R.Coefficients, R.NumVars);
if (!Added)
return;
More information about the llvm-commits
mailing list