Add eager_inline() directive for schedule-time inlining - #9256
Conversation
c226ea0 to
de722b4
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #9256 +/- ##
==========================================
+ Coverage 69.93% 70.02% +0.08%
==========================================
Files 257 257
Lines 77537 77563 +26
Branches 18884 18889 +5
==========================================
+ Hits 54229 54315 +86
+ Misses 17679 17644 -35
+ Partials 5629 5604 -25 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
I'd like to see an actual example (code or description) of when this is useful. I don't really grasp what it means when you say:
What's now possible that otherwise is impossible? |
That's in #9190 (top of the stack) — the idea is that if you have a function that looks like |
dd530c1 to
2f709b3
Compare
|
Let's discuss in person how this interacts with .in()/.clone_in() and how it would interact with proposed changes to .in()/.clone_in(). I think it's fine but it's worth working through. |
a7a483c to
cbfbb1c
Compare
I followed up on the potential for strange interactions with If someone writes Writing Still, it might be worth warning or erroring if you |
cbfbb1c to
fc9374c
Compare
fc9374c to
f822349
Compare
abadams
left a comment
There was a problem hiding this comment.
Approve pending topological sort
abadams
left a comment
There was a problem hiding this comment.
Approve pending topological sort
Add Func::eager_inline({f1..fN}), which inlines direct calls to each given
Func into this Func's definitions immediately, at schedule time, processed
left to right so that inlining an earlier Func exposes direct calls to a later
one. Unlike compute_inline(), which only marks a Func to be inlined during
lowering, eager_inline() rewrites the caller's definitions in place, surfacing
structure that other schedule-time directives can then act on -- e.g. exposing
an invariant factor buried in a call so hoist_invariants() can hoist it from
h(x) += f(x) * g(x).
Built on Internal::inline_function(Function, Function). Removes the redundant
validate_schedule_inlined_function() call from the Inliner constructor: it is
also (and properly) called at lowering time in ScheduleFunctions with loop
levels locked, and calling it in the constructor inspects unlocked loop
levels, which breaks schedule-time inlining. Adds a Python binding and
correctness/eager_inline.cpp.
This Func predates hoist_invariants() in commit order, so
eager_inline.cpp doesn't yet cover the composed case; a TODO marks it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
eager_inline() previously lived only on Func and inlined into every one of the Func's definitions at once. But the structure it surfaces is stage-scoped -- the schedule-time directives that consume it (e.g. rfactor()) operate on a single Stage -- so inlining into all definitions is both too coarse and conceptually mismatched. Make Stage::eager_inline() the primary API: it rewrites only that stage's definition in place, via a new inline_function(Definition &, Function) overload. Func::eager_inline() is kept as a shorthand targeting the initial (pure) definition, mirroring how Func::vectorize() and friends delegate to the initial Stage; inline into an update with f.update(n).eager_inline(...). Add stage-scoping coverage to correctness/eager_inline (inlining into one stage leaves the others untouched) and an error test for the undefined-Func assert. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f822349 to
07cf296
Compare
Sort the Funcs passed to eager_inline() into dependency order (callers before callees) before inlining, so they are all fully folded regardless of the order they are passed. Reuses build_environment() and topological_order(), reversing the realization order since a call exposed inside an inlined body must be inlined afterward. Passing a Func the stage does not call remains a silent no-op. Update the correctness test to pass Funcs in scrambled order and to cover the unreachable-argument case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This PR adds a scheduling directive,
g.eager_inline({f1, ..., fN})that immediately and destructively inlines the bodies off1, ..., fNintog. This happens in sequence so that direct calls tof_jbyf_i, i < jcan be inlined without needing to issue the directive multiple times.I'm placing this on the bottom of the stack because it is the easiest to review.
Breaking changes
None. This is a new directive.
Checklist
Stack created with GitHub Stacks CLI • Give Feedback 💬