Skip to content

Eagerly constant fold all arithmetic - #771

Open
dsharlet wants to merge 9 commits into
mainfrom
ds/eager-constant-fold
Open

Eagerly constant fold all arithmetic#771
dsharlet wants to merge 9 commits into
mainfrom
ds/eager-constant-fold

Conversation

@dsharlet

@dsharlet dsharlet commented Feb 9, 2026

Copy link
Copy Markdown
Owner

This changes the construction of expressions to eagerly constant fold arithmetic as we encounter it.

When client code is constructing expressions, they might check if an expression is a constant, but that expression might be constant arithmetic that produces that constant instead. This is an annoying thing to deal with and leads to bugs.

The main downside of this change is that it doesn't maintain expressions as the user expected. This is both surprising in a different way, and this also did affect our tests a lot.

I had hoped this would make the simplifier faster, but it's actually slower. I guess this makes sense, the constant folding logic in the simplifier was cheap, but now we do that logic when constructing all expressions.

The change also uncovered quite a few bugs:

  • We learned incorrectly from min(a, b) < c and similar cases.
  • We learned non-boolean facts incorrectly
  • The constant bounds analysis of !x was wrong
  • We had a few incorrect rules

Some of these bugs are pretty surprising, they are not subtle edge cases.


SLINKY_NO_INLINE void test_expr(expr pattern, expr replacement, const std::string& rule_str) {
SLINKY_NO_INLINE void test_expr(expr pattern, expr replacement, const std::string& rule_str, bool& applied) {
expr simplified = simplify(pattern);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should be applied = false; in the beginning, so it doesn't have to rely on what was passed (and I think it's incorrect to keep it unchanged).

ASSERT_THAT(constant_upper_bound(min(x, 4)), matches(4));
ASSERT_THAT(constant_upper_bound(max(x, 4)), matches(max(x, 4)));
ASSERT_THAT(constant_upper_bound(!min(x, 0)), matches(1));
ASSERT_THAT(constant_upper_bound(!min(x, -1)), matches(1)); // TODO: We might be able to prove this is 0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re TODO: Shouldn't this always be 1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants