Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
0ec1112
work
kripken Jul 29, 2026
279c29f
work
kripken Jul 29, 2026
f9ec4e9
work
kripken Jul 29, 2026
978217b
work
kripken Jul 29, 2026
3e6cc0e
work
kripken Jul 29, 2026
aa3788d
work
kripken Jul 29, 2026
66799fb
work
kripken Jul 29, 2026
9d7c472
work
kripken Jul 29, 2026
9c707af
work
kripken Jul 29, 2026
83976d4
work
kripken Jul 29, 2026
35b44de
work
kripken Jul 29, 2026
e166af5
work
kripken Jul 29, 2026
db350c7
work
kripken Jul 29, 2026
4918d32
work
kripken Jul 29, 2026
7458b6a
work
kripken Jul 29, 2026
5695b31
work
kripken Jul 29, 2026
d5deb26
work
kripken Jul 29, 2026
07e8fa5
work
kripken Jul 29, 2026
95430f4
work
kripken Jul 29, 2026
019faf5
work
kripken Jul 29, 2026
147e989
work
kripken Jul 29, 2026
4aecba5
work
kripken Jul 29, 2026
c1342f9
work
kripken Jul 29, 2026
3bb360b
work
kripken Jul 29, 2026
5343be1
work
kripken Jul 29, 2026
13a9ded
work
kripken Jul 29, 2026
eb4d187
work
kripken Jul 29, 2026
3aa5e8f
work
kripken Jul 30, 2026
15c0431
work
kripken Jul 30, 2026
b7a49e7
work
kripken Jul 30, 2026
9a40700
work
kripken Jul 30, 2026
5e3db80
work
kripken Jul 30, 2026
0b04e23
work
kripken Jul 30, 2026
cfd704f
work
kripken Jul 30, 2026
d5e54e9
work
kripken Jul 30, 2026
71daf85
work
kripken Jul 30, 2026
8f07a3f
work
kripken Jul 30, 2026
dd1d128
work
kripken Jul 30, 2026
c32a870
ConstraintAnalysis: Add more simple inequalities
kripken Jul 30, 2026
3118ba0
fix
kripken Jul 30, 2026
5fe2c9e
fix
kripken Jul 30, 2026
aaa7a48
Merge remote-tracking branch 'origin/main' into loops
kripken Jul 30, 2026
d61d1d4
fix warning
kripken Jul 30, 2026
4835487
handle overflow
kripken Jul 31, 2026
aab5dc5
work
kripken Jul 31, 2026
65e884b
Merge remote-tracking branch 'origin/main' into loops
kripken Jul 31, 2026
871d132
work
kripken Jul 31, 2026
2f28f67
work
kripken Jul 31, 2026
fac861b
work
kripken Jul 31, 2026
b55fa2a
work
kripken Jul 31, 2026
03a82c5
work
kripken Jul 31, 2026
71a24e8
work
kripken Jul 31, 2026
1fba050
work
kripken Jul 31, 2026
480e5c6
work
kripken Jul 31, 2026
c3d65f3
work
kripken Jul 31, 2026
dd6730c
work
kripken Jul 31, 2026
634b0d3
work
kripken Jul 31, 2026
b60cf18
work
kripken Jul 31, 2026
45484f1
work
kripken Jul 31, 2026
ac6653e
work
kripken Jul 31, 2026
0c0f908
work
kripken Jul 31, 2026
3e9c83e
work
kripken Jul 31, 2026
5a261aa
work
kripken Jul 31, 2026
762c612
work
kripken Jul 31, 2026
cd6f9f1
work
kripken Jul 31, 2026
8fadc2b
work
kripken Jul 31, 2026
4c27988
work
kripken Jul 31, 2026
778a64a
work
kripken Jul 31, 2026
741ee9a
more
kripken Jul 31, 2026
74f0bed
Merge branch 'moar2' into loops
kripken Jul 31, 2026
fd1fcb4
work
kripken Jul 31, 2026
1916871
work
kripken Jul 31, 2026
b1e2934
work
kripken Jul 31, 2026
6502d51
work
kripken Aug 3, 2026
75f4064
Merge remote-tracking branch 'origin/main' into loops
kripken Aug 3, 2026
1444406
work
kripken Aug 3, 2026
ae5d9ee
work
kripken Aug 3, 2026
24ae210
work
kripken Aug 3, 2026
d3c997b
work
kripken Aug 4, 2026
15af30f
work
kripken Aug 4, 2026
d76f898
work
kripken Aug 4, 2026
8cd6b92
work
kripken Aug 4, 2026
183a594
work
kripken Aug 4, 2026
c0f966a
work
kripken Aug 4, 2026
b19bb0b
work
kripken Aug 4, 2026
62f0ae9
work
kripken Aug 4, 2026
37d5efd
work
kripken Aug 4, 2026
2ea981d
work
kripken Aug 4, 2026
c6b1904
work
kripken Aug 4, 2026
75d76fc
work
kripken Aug 4, 2026
42681fe
work
kripken Aug 4, 2026
bb0b742
work
kripken Aug 4, 2026
418ee18
work
kripken Aug 4, 2026
19157ee
work
kripken Aug 4, 2026
e02ab01
clean
kripken Aug 4, 2026
dc39877
work
kripken Aug 4, 2026
67e7be9
work
kripken Aug 4, 2026
4c48d1a
work
kripken Aug 4, 2026
cc480f7
work
kripken Aug 4, 2026
4ff74fa
go
kripken Aug 4, 2026
9b38ac6
simpl
kripken Aug 4, 2026
a319bc1
simpl
kripken Aug 4, 2026
9cd4af1
FIX
kripken Aug 4, 2026
fa4dbca
FIX
kripken Aug 4, 2026
a9a9405
FIX2
kripken Aug 4, 2026
9d8fe3a
FIX
kripken Aug 4, 2026
1d17f83
FIX2
kripken Aug 4, 2026
eb4fc78
FIX
kripken Aug 4, 2026
3e88a20
FIX
kripken Aug 4, 2026
b368c1c
SIMPL
kripken Aug 4, 2026
461c972
SIMPL
kripken Aug 4, 2026
fa9468f
Merge remote-tracking branch 'origin/main' into constraint.add
kripken Aug 5, 2026
9a2459f
Merge remote-tracking branch 'myself/constraint.add' into loops
kripken Aug 5, 2026
4ff9da5
Merge remote-tracking branch 'origin/main' into constraint.add
kripken Aug 6, 2026
c79ac07
simpler
kripken Aug 6, 2026
cc37875
Merge remote-tracking branch 'myself/constraint.add' into loops
kripken Aug 6, 2026
bb8f742
work
kripken Aug 6, 2026
7516199
simpler
kripken Aug 6, 2026
b93608e
Merge remote-tracking branch 'myself/constraint.add' into loops
kripken Aug 6, 2026
231835c
work
kripken Aug 6, 2026
d1b8260
share code in ::set()
kripken Aug 7, 2026
5b10745
Merge remote-tracking branch 'myself/constraint.add' into loops
kripken Aug 7, 2026
ddf9d40
simpl
kripken Aug 7, 2026
08e7dcb
short
kripken Aug 7, 2026
a32d606
fix
kripken Aug 7, 2026
ae76769
fix
kripken Aug 7, 2026
7a19e4c
merg
kripken Aug 7, 2026
048ca7f
merg
kripken Aug 7, 2026
9fe2a92
merg
kripken Aug 7, 2026
2041356
merg
kripken Aug 7, 2026
9ca789d
merg
kripken Aug 7, 2026
5717dd6
update test outputs
kripken Aug 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 96 additions & 1 deletion src/passes/ConstraintAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,50 @@
// assert(x != 0); // redundant and can be removed.
// }
//
// For loops, we must avoid the following problem:
//
// x = 0
// do {
// print(x >= 0 & x < 100)
// x++
// } while (x < 100)
//
// Say that we flow information around precisely. Then initially x is 0 at the
// top of the loop, and x++ turns it into 1. 1 < 100 so we return to the top of
// the loop, and now x can be 0 or 1. We will then interpret this loop for 100
// iterations at compile time, going from [0] to [0, 1] to [0, 2] and so forth,
// which is obviously not a good idea.
//
// Instead, we do something similar to "widening" in abstract interpretation
// (which at a loop header, where a merge occurs, widens the range of values
// based on the bounds check that it sees elsewhere). We do something even
// simpler here, which can be accomplished in an eager way as follows:
//
// * x++ turns x from 0 to 1 in the example above, in the first iteration of
// the loop.
// * When we then see x == 1 that branches with x < 100, we turn that into
// x >= 1 && x < 100. This is "imprecise", because perhaps the local will
// not actually get incremented all the way to 100, but it is an upper
// bound that ends up getting us to the result we want in common loop
// shapes. (And it is safe to do because we allow more values for x, meaning
// we can prove fewer things, so we won't prove anything false.)
// * After doing that, we return to the top of the loop, where now we can see
// x >= 0 && x < 100. After running that through the loop a second time, no
// more happen: we successfully "jumped ahead" to the end state of the
// loop variable.
//
// Doing this eagerly when we see a branch, rather than identifying specific
// loop headers and analyzing their bounds more precisely, is good enough for
// us: the only imprecision we add is "x == C, branch with x < D => x >= C &&
// x < D". While imprecise, if we see "x == C, branch with x < D", then this is
// a situation inside a loop: if it were not, then x would get constant-
// propagatated to the branch anyhow by other passes. And, if this is in a loop,
// then this widening is exactly what we want. This eager approach avoids us
// needing to analyze loops shapes specifically and/or to consider branch
// conditions "from afar" (seeing a branch on "x < D", but *not* applying it
// eagerly, and instead using it later at the loop header or in some whole-
// function analysis).
//

#include "cfg/cfg-traversal.h"
#include "ir/constraint.h"
Expand Down Expand Up @@ -286,7 +330,7 @@ struct ConstraintAnalysis
if (auto branch = getBranchConstraints(block, out);
branch && checkRelevancy(*branch)) {
auto sentConstraints = constraints;
sentConstraints.approximateAnd(branch->local, branch->constraint);
applyBranchConstraints(*branch, sentConstraints);
#if CONSTRAINT_DEBUG
std::cout << block << " sending branch to " << out
<< " with sent constraints: " << sentConstraints << '\n';
Expand Down Expand Up @@ -521,6 +565,57 @@ struct ConstraintAnalysis
}
return true;
}

// Apply branch constraints to the current set of constraints.
void applyBranchConstraints(const LocalConstraint& branch,
BasicBlockConstraintMap& constraints) {
// Extend the range of values in the "jump ahead" manner described in the
// top-level comment.
if (applyBranchRangeExtensionToConstraints(branch, constraints)) {
return;
}

// Otherwise, apply the constraint normally.
constraints.approximateAnd(branch.local, branch.constraint);
}

bool
applyBranchRangeExtensionToConstraints(const LocalConstraint& branch,
BasicBlockConstraintMap& constraints) {
using namespace Abstract;

// "Jump ahead" and extend ranges. If the branch is x < M, and we were
// x == N where N < M, then extend to x >= N && x < M (see top-level
// comment).
if (auto* M = std::get_if<Literal>(&branch.constraint.term)) {
auto localConstraints = constraints.get(branch.local);
if (localConstraints.size() == 1 &&
localConstraints[0].op == Abstract::Eq) {
if (auto* N = std::get_if<Literal>(&localConstraints[0].term)) {
// We can handle both x < M as the branch, as described above, or
// x <= M (if N <= M).
if ((branch.constraint.op == Abstract::LtS &&
N->ltS(*M).getUnsigned()) ||
(branch.constraint.op == Abstract::LeS &&
N->leS(*M).getUnsigned())) {
constraints.set(branch.local, branch.constraint);
constraints.approximateAnd(branch.local, {GeS, {*N}});
return true;
}
if ((branch.constraint.op == Abstract::LtU &&
N->ltU(*M).getUnsigned()) ||
(branch.constraint.op == Abstract::LeU &&
N->leU(*M).getUnsigned())) {
constraints.set(branch.local, branch.constraint);
constraints.approximateAnd(branch.local, {GeU, {*N}});
return true;
}
}
}
}

return false;
}
};

} // anonymous namespace
Expand Down
Loading
Loading