From b24f3fd8c0fcbd87bbeeafefedee1ebd8f4d159b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 16 Jul 2026 10:05:57 -0700 Subject: [PATCH 1/2] fast --- src/ir/constraint.cpp | 36 +++++++++++++++++++------------ src/ir/constraint.h | 4 ++-- src/passes/ConstraintAnalysis.cpp | 4 +--- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/ir/constraint.cpp b/src/ir/constraint.cpp index 9e384a6c40f..03190b44ea2 100644 --- a/src/ir/constraint.cpp +++ b/src/ir/constraint.cpp @@ -159,25 +159,25 @@ void AndedConstraintSet::approximateAnd(const Constraint& c) { // useful to implement that). } -void AndedConstraintSet::approximateOr(const AndedConstraintSet& other) { +bool AndedConstraintSet::approximateOr(const AndedConstraintSet& other) { // If one proves everything, the only thing that matters is the other. + if (other.provesEverything()) { + return false; + } if (provesEverything()) { *this = other; - return; - } - if (other.provesEverything()) { - return; + return true; } // If this is already implied by current constraints, then it is redundant. // E.g. if we are { x = 10 } and other is { x >= 0 } then all we need is // { x >= 0 } as the result of the OR. + if (other.proves(*this) == True) { + return false; + } if (proves(other) == True) { *this = other; - return; - } - if (other.proves(*this) == True) { - return; + return true; } // TODO smarts: handle <= > and so forth @@ -185,6 +185,7 @@ void AndedConstraintSet::approximateOr(const AndedConstraintSet& other) { // Otherwise, we don't know how to nicely OR these things, and expand to the // trivial set of no constraints. clear(); + return true; } std::optional LocalConstraint::parse(Expression* curr) { @@ -303,21 +304,22 @@ void BasicBlockConstraintMap::setProvesNothing(Index index) { map.erase(index); } -void BasicBlockConstraintMap::approximateOr( +bool BasicBlockConstraintMap::approximateOr( const BasicBlockConstraintMap& other) { // If one is unreachable, it adds nothing to the other. if (other.unreachable) { - return; + return false; } if (unreachable) { *this = other; - return; + return true; } // We only need to loop on our locals, as any local that is missing in us is // one that would end up proving nothing (and get removed). + bool changed = false; for (auto& [local, constraints] : map) { - constraints.approximateOr(other.get(local)); + changed |= constraints.approximateOr(other.get(local)); } // Anything that became trivial after the OR must be removed. @@ -325,8 +327,14 @@ void BasicBlockConstraintMap::approximateOr( const auto& [local, constraints] = item; // We do not store contradictions. assert(!constraints.provesEverything()); - return constraints.provesNothing(); + if (constraints.provesNothing()) { + changed = true; + return true; + } + return false; }); + + return changed; } void BasicBlockConstraintMap::approximateAndInternal(Index index, diff --git a/src/ir/constraint.h b/src/ir/constraint.h index e3be8305268..038d115deee 100644 --- a/src/ir/constraint.h +++ b/src/ir/constraint.h @@ -177,7 +177,7 @@ struct AndedConstraintSet : inplace_vector { // { x >= 0 } // // If we become too imprecise, we lose the ability to imply anything useful. - void approximateOr(const AndedConstraintSet& other); + bool approximateOr(const AndedConstraintSet& other); // Set a constraint, replacing all previous state. void set(const Constraint& c) { @@ -266,7 +266,7 @@ struct BasicBlockConstraintMap { // Perform an OR as above. When a local only appears in one map, we treat it // as if it contains a contradiction there, that is, as if the code is // unreachable. - void approximateOr(const BasicBlockConstraintMap& other); + bool approximateOr(const BasicBlockConstraintMap& other); // Perform an AND as above, on a particular index. void approximateAnd(Index index, const Constraint& c) { diff --git a/src/passes/ConstraintAnalysis.cpp b/src/passes/ConstraintAnalysis.cpp index 356e6e035b1..d16a326dc29 100644 --- a/src/passes/ConstraintAnalysis.cpp +++ b/src/passes/ConstraintAnalysis.cpp @@ -171,9 +171,7 @@ struct ConstraintAnalysis } // If anything changed at the start of the target block, flow onwards. - auto old = outStartConstraints; - outStartConstraints.approximateOr(sentConstraints); - if (outStartConstraints != old) { + if (outStartConstraints.approximateOr(sentConstraints)) { work.push(out); } } From 976dbf82cee4bd341210afeb731d9028373c302d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 16 Jul 2026 10:06:56 -0700 Subject: [PATCH 2/2] fast --- src/ir/constraint.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ir/constraint.h b/src/ir/constraint.h index 038d115deee..4412c53a21b 100644 --- a/src/ir/constraint.h +++ b/src/ir/constraint.h @@ -177,6 +177,8 @@ struct AndedConstraintSet : inplace_vector { // { x >= 0 } // // If we become too imprecise, we lose the ability to imply anything useful. + // + // Returns whether we changed anything. bool approximateOr(const AndedConstraintSet& other); // Set a constraint, replacing all previous state. @@ -266,6 +268,8 @@ struct BasicBlockConstraintMap { // Perform an OR as above. When a local only appears in one map, we treat it // as if it contains a contradiction there, that is, as if the code is // unreachable. + // + // Returns whether we changed anything. bool approximateOr(const BasicBlockConstraintMap& other); // Perform an AND as above, on a particular index.