Skip to content

Simplify (x*c0 + y)/c1 to x/(c1/c0) when 0 <= y < c0 - #9520

Open
alexreinking wants to merge 4 commits into
alexreinking/struct-let-loadsfrom
alexreinking/simplify-div-bounded-offset
Open

alexreinking wants to merge 4 commits into
alexreinking/struct-let-loadsfrom
alexreinking/simplify-div-bounded-offset

Conversation

@alexreinking

@alexreinking alexreinking commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Adds a Div simplifier rule (and its commuted form):

rewrite((x * c0 + y) / c1, x / fold(c1 / c0), c0 > 0 && c1 % c0 == 0 && in_range(y, 0, c0, this))

An offset y in [0, c0) can't carry into the next multiple of c1. This makes per-block factor indices such as scale((lane*4 + ki) / 32) invariant in ki, so hoist_invariants() can hoist them (#9521).

in_range is a new allocation-free IRMatch predicate, since can_prove is too expensive in rule predicates. It only reads constant bounds of an IntImm, a bare Variable (from bounds_and_alignment_info), or a Broadcast of either, so compound offsets like y % 4 don't fire. It reuses #9400's bound_node/bound_const_int building blocks verbatim; whichever PR lands second gets one trivial conflict (keep #9400's side).

Verified with apps/simplifier_rule_verifier: true and correctly ordered under no-overflow (the rule is in the no_overflow block), false with wraparound.

Tests: positive and negative cases in correctness_simplify.


Authored by GitHub Copilot

@abadams

abadams commented Oct 6, 2026

Copy link
Copy Markdown
Member

We're trying to delete all can_prove usage from the simplifier, as it's very expensive and not guaranteed to terminate.

@abadams

abadams commented Oct 6, 2026

Copy link
Copy Markdown
Member

In general I'd like to be able to retrieve what the computed ConstantInterval was for subexpressions in rewrite rules, as those were already available while mutating the LHS of the division. But currently they've been dropped.

@codecov

codecov Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.30435% with 2 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (alexreinking/struct-let-loads@af07f26). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/Simplify_Exprs.cpp 81.81% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@                       Coverage Diff                        @@
##             alexreinking/struct-let-loads    #9520   +/-   ##
================================================================
  Coverage                                 ?   72.79%           
================================================================
  Files                                    ?      263           
  Lines                                    ?    82133           
  Branches                                 ?    20060           
================================================================
  Hits                                     ?    59786           
  Misses                                   ?    15957           
  Partials                                 ?     6390           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mcourteaux

Copy link
Copy Markdown
Contributor

This is trivially done right once the can-prove-facts branch is in.

@alexreinking

alexreinking commented Oct 7, 2026 •

Copy link
Copy Markdown
Member Author

This is trivially done right once the can-prove-facts branch is in.

How would you do this in terms of #9400's (linear_)?(min|max)_diff?

@alexreinking
alexreinking removed this pull request from stack #9522 October 7, 2026 16:08
@alexreinking
alexreinking added this pull request to stack #9524 October 7, 2026 16:08
@alexreinking
alexreinking removed this pull request from stack #9524 October 7, 2026 19:21
@alexreinking
alexreinking added this pull request to stack #9527 October 7, 2026 19:26
@alexreinking

Copy link
Copy Markdown
Member Author

This PR no longer uses can_prove

@alexreinking
alexreinking marked this pull request as ready for review October 7, 2026 20:35
@alexreinking
alexreinking requested a review from abadams October 7, 2026 20:35
@alexreinking
alexreinking removed this pull request from stack #9527 October 8, 2026 11:09
@alexreinking
alexreinking added this pull request to stack #9529 October 8, 2026 11:10
@alexreinking
alexreinking removed this pull request from stack #9529 October 8, 2026 14:37
@alexreinking
alexreinking added this pull request to stack #9531 October 8, 2026 14:38
@alexreinking
alexreinking removed this pull request from stack #9531 October 8, 2026 16:22
@alexreinking
alexreinking added this pull request to stack #9533 October 8, 2026 16:23
@alexreinking
alexreinking removed this pull request from stack #9533 October 9, 2026 07:11
@alexreinking
alexreinking added this pull request to stack #9540 October 9, 2026 07:12
Comment thread src/Simplify_Div.cpp Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this PR should also drop the last term in this predicate, because the new rules bundle in this transformation but omitting this last term. After discussion we decided the last term was a relic from before when we defined division by zero.

Comment thread src/Simplify_Div.cpp Outdated
// in_range only looks up the bounds already known for y, without
// simplifying anything, so it recognizes y only as a constant or a
// variable with constant bounds (from loops, lets, learned facts,
// or the caller's bounds), or a broadcast of one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please drop comment entirely. The rule is easier to read than the comment.

Comment thread src/Simplify_Div.cpp

@abadams abadams left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved pending two requested changes

@alexreinking
alexreinking force-pushed the alexreinking/simplify-div-bounded-offset branch from 505b388 to f73276e Compare October 16, 2026 19:45
@alexreinking
alexreinking force-pushed the alexreinking/simplify-div-bounded-offset branch from bc38e1e to 29dcc55 Compare October 16, 2026 19:50
@alexreinking
alexreinking added this pull request to stack #9560 October 16, 2026 19:50
@alexreinking
alexreinking force-pushed the alexreinking/simplify-div-bounded-offset branch from 29dcc55 to a5dbfc2 Compare October 16, 2026 20:33
@alexreinking
alexreinking removed this pull request from stack #9560 October 16, 2026 22:00
@alexreinking
alexreinking added this pull request to stack #9561 October 16, 2026 22:00
@alexreinking
alexreinking force-pushed the alexreinking/simplify-div-bounded-offset branch from a5dbfc2 to a471315 Compare October 17, 2026 16:07
@alexreinking
alexreinking force-pushed the alexreinking/simplify-div-bounded-offset branch from a471315 to 36e1bee Compare October 19, 2026 19:49
@alexreinking
alexreinking force-pushed the alexreinking/simplify-div-bounded-offset branch 2 times, most recently from 653a0e2 to f7490c3 Compare October 23, 2026 00:07
@alexreinking
alexreinking removed this pull request from stack #9561 October 23, 2026 00:07
@alexreinking
alexreinking added this pull request to stack #9597 October 23, 2026 00:08
alexreinking and others added 4 commits October 22, 2026 20:19
When c0 > 0 divides the denominator c1, x*c0 % c1 is a multiple of c0 no
greater than |c1| - c0, so an offset y in [0, c0) can never carry into the
next multiple of c1 and doesn't affect the quotient. For example,
(x*4 + y) / 32 == x / 8 for y in [0, 4).

This form arises when a reduction is split twice (e.g. into blocks of 32 and
then lanes of 4) and a per-block factor is indexed by r / 32: after rfactor,
the factor's index is ((lane*4 + rxi) / 32) + u, which this rule reduces to
lane/8 + u so it can be recognized as invariant in the innermost loop.

The bound on y is established with can_prove(y / c0 == 0), which is
equivalent to 0 <= y < c0 for c0 > 0 and mentions y only once, following
the existing ramp rule in Simplify_Mod.cpp. The rule is restricted to
integer types (it is false for floats) and applies lanewise to vectors. It
holds under the no-overflow assumption only, and is placed inside the
existing no_overflow block. To be revisited when #9400 lands, which bounds
can_prove's recursion depth and may offer an allocation-free alternative.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The (x*c0 + y)/c1 -> x/(c1/c0) rule checked 0 <= y < c0 with
can_prove(y / c0 == 0), which builds and simplifies IR every time the
rule's cheaper predicates pass. Replace it with a new IRMatch predicate,
in_range(y, lo, hi, this), which tests y against the half-open range
[lo, hi) without building, simplifying, or reference counting any IR.

in_range requires y to be a wildcard and lo/hi to be WildConsts or
integer literals (enforced by static_assert), and accepts only an
integer constant, a variable whose constant bounds the simplifier
already tracks (from loops, lets, learned facts, or the caller's bounds),
or a broadcast of either. Anything else fails the predicate, so the rule
no longer fires for compound offsets such as y % 4 or clamp(y, 0, 3).

Wild::bound_node, WildConst::bound_const_int, IntLiteral::bound_const_int
and the has_bound_node/has_bound_const_int traits are taken unchanged
from #9400, which needs the same allocation-free access to matched
terms.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the obsolete nonzero quotient predicate and the explanatory comment on bounded-offset division rules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Parse half-open range predicates with an optional matcher context, document their interpretation, and cover boundaries and bounded-offset division rules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@alexreinking
alexreinking removed this pull request from stack #9597 October 23, 2026 00:38
@alexreinking
alexreinking force-pushed the alexreinking/simplify-div-bounded-offset branch from f7490c3 to 6692ec4 Compare October 23, 2026 00:38
@alexreinking
alexreinking added this pull request to stack #9598 October 23, 2026 00:38
@alexreinking
alexreinking removed this pull request from stack #9598 October 23, 2026 05:16
@alexreinking
alexreinking added this pull request to stack #9600 October 23, 2026 05:17
@alexreinking
alexreinking removed this pull request from stack #9600 October 23, 2026 14:43
@alexreinking
alexreinking added this pull request to stack #9605 October 23, 2026 14:43

This branch has not been deployed

No deployments
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.

4 participants