Conversation
A loop marked .parallel() is expected to be dispatched through the task system even when its extent turns out to be one. Collapsing such a loop into a LetStmt bypasses halide_do_task, which defeats a useful idiom: .parallel(Var::outermost()) to isolate a body into its own function. Don't simplify a parallel For into a serial body even when its bounds prove it runs at most once. Adds a regression test that installs a custom halide_do_task and confirms it fires for a statically-size-one parallel loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RemoveLoopsOverOutermost stripped the always-size-one .__outermost loop unconditionally, so .parallel(Var::outermost()) never reached the task system even after the simplifier stopped collapsing size-one parallel loops. Skip parallel loops there too, and extend the regression test to cover the outermost idiom. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
alexreinking
approved these changes
Sep 17, 2026
alexreinking
left a comment
Member
There was a problem hiding this comment.
If this causes performance regressions anywhere, somehow, I'd say, "if you ask for a parallel loop, don't be surprised when it when it is one."
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9454 +/- ##
==========================================
- Coverage 70.12% 69.98% -0.14%
==========================================
Files 261 261
Lines 79938 79941 +3
Branches 19478 19481 +3
==========================================
- Hits 56053 55944 -109
- Misses 18056 18086 +30
- Partials 5829 5911 +82 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A loop marked
.parallel()is expected to be dispatched through the task system even when its extent turns out to be one. Among other things, this makes.parallel(Var::outermost())a useful idiom for isolating a body into its own task/function without otherwise changing the loop nest.Two passes were collapsing such loops into a serial body:
Forwhose bounds prove it runs at most once into aLetStmt. It now leaves parallel loops alone.RemoveLoopsOverOutermoststripped the always-size-one.__outermostloop unconditionally. It now leaves parallel loops alone too — otherwise the.parallel(Var::outermost())idiom never reaches the task system even after the simplifier change.Test plan
correctness/parallel_size_onetest installs a customhalide_do_taskand asserts it fires both for a statically-size-one parallel loop (f.compute_at(g, x).parallel(x)) and for a parallel outermost loop (f.parallel(Var::outermost())).🤖 Generated with Claude Code