[llvm] [ConstraintElim] Skip rows implied by a single existing row. (PR #227688)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 05:49:59 PDT 2026


https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/227688

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.

>From 3ca709bcf57882805c2503b4597e1e30bea402ad 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] [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 11f40de9968c56..c14e0fbd8b9cfb 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 85ac780b5f7200..c659b4de3bb13d 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 ae5f85374ad39f..0870db6c004ca9 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 a40131d4d28093..edd7fdd89aac33 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.



More information about the llvm-commits mailing list