Repository navigation
hoist_invariants: decide invariance modulo the RVar bounds - #9521
Draft
alexreinking wants to merge 4 commits into
Draft
alexreinking wants to merge 4 commits into
alexreinking wants to merge 4 commits into
Conversation
alexreinking
added this pull request to stack #9522
October 6, 2026 19:34
alexreinking
added a commit
that referenced
this pull request
Oct 6, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 6, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## alexreinking/multiramp-alignment-stacked #9521 +/- ##
===========================================================================
Coverage ? 72.23%
===========================================================================
Files ? 262
Lines ? 81949
Branches ? 20026
===========================================================================
Hits ? 59193
Misses ? 16559
Partials ? 6197 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
alexreinking
force-pushed
the
alexreinking/hoist-invariants-bounds
branch
from
October 7, 2026 06:39
8fb4198 to
a909d91
Compare
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
removed this pull request from stack #9522
October 7, 2026 16:08
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added this pull request to stack #9524
October 7, 2026 16:08
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
removed this pull request from stack #9524
October 7, 2026 19:21
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 7, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added this pull request to stack #9527
October 7, 2026 19:26
alexreinking
removed this pull request from stack #9527
October 8, 2026 11:09
alexreinking
added a commit
that referenced
this pull request
Oct 8, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 8, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added this pull request to stack #9529
October 8, 2026 11:10
alexreinking
added a commit
that referenced
this pull request
Oct 8, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 8, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
removed this pull request from stack #9529
October 8, 2026 14:37
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
removed this pull request from stack #9540
October 16, 2026 19:47
alexreinking
force-pushed
the
alexreinking/hoist-invariants-bounds
branch
from
October 16, 2026 19:47
bec4652 to
2903e64
Compare
alexreinking
added this pull request to stack #9559
October 16, 2026 19:47
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
removed this pull request from stack #9559
October 16, 2026 19:50
alexreinking
force-pushed
the
alexreinking/hoist-invariants-bounds
branch
from
October 16, 2026 19:50
2903e64 to
3ea6ebe
Compare
alexreinking
changed the base branch from
alexreinking/simplify-div-bounded-offset
to
alexreinking/rfactor-tail-allocation
October 16, 2026 19:50
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added this pull request to stack #9560
October 16, 2026 19:50
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
force-pushed
the
alexreinking/hoist-invariants-bounds
branch
from
October 16, 2026 20:33
3ea6ebe to
f60b2a3
Compare
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
force-pushed
the
alexreinking/hoist-invariants-bounds
branch
from
October 16, 2026 21:49
f60b2a3 to
3e42629
Compare
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
removed this pull request from stack #9560
October 16, 2026 22:00
alexreinking
changed the base branch from
alexreinking/rfactor-tail-allocation
to
alexreinking/multiramp-alignment-stacked
October 16, 2026 22:00
alexreinking
force-pushed
the
alexreinking/hoist-invariants-bounds
branch
from
October 16, 2026 22:00
3e42629 to
8157e26
Compare
alexreinking
added this pull request to stack #9561
October 16, 2026 22:00
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
kernels/matmul.cpp: out(n, m) = sum_k W(k, n) * X(k, m) in f32, each operand approximated by its format's scheme and severed at its records. kernels/schedule.h: vec_dot for two block-quantized operands is rfactor -> eager_inline -> hoist_invariants -> change_type(Int(32)) -> lanes, which lowers to GGML's ggml_vec_dot_q4_0_q8_0 Neon loop (sdot, per-lane f32 scale-accumulate, two blocks per iteration); otherwise decode + FMA. Formats gain values per record (schemes.h) and acts (formats.cmake); the kernel ABI is struct-typed records [K / block, N | M] whose types come from the kernel metadata; the vec_dot adapter reuses static buffers. q8_0 vec_dot comes with zero kernel changes. Needs the framework's FR-1 (rank-polymorphic BlockReshape/StructLayout, contextual signature) and hoist_invariants modulo RVar bounds (#9521). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
alexreinking
added a commit
that referenced
this pull request
Oct 16, 2026
hoist_invariants() takes an explicit constant bound on a pure var as its range (#9521); the rfactor'd lane is the in-block vector lane, extent vector size / dot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
hoist_invariants() decided whether a factor was loop-invariant
syntactically. In a blocked reduction with one factor per block, such as
a block-scaled dot product sum_k(scale(k / 32) * data(k)), the natural
schedule splits k by the block size and rfactors the block index:
out.update().split(r, ko, ki, 32);
Func blocks = out.update().rfactor(ko, u);
blocks.update().hoist_invariants();
The intermediate then reads scale((u*32 + ki) / 32), which equals
scale(u) for every ki in [0, 32), but mentions ki, so nothing was hoisted
and hoist_invariants() raised a user error.
Before partitioning the leaves of the inner-op chain, a leaf that is not
syntactically RVar-free now has its float-free RVar-dependent
subexpressions simplified under the RVars' constant bounds. If the
result is RVar-free, it becomes the hoisted factor; otherwise the
original leaf stays in the body unchanged. This is sound for any tail
strategy, since the RDom bounds hold for every iteration the reduction
runs. Floating-point math is never rewritten. The internal promises
rfactor() wraps around a split RVar's index are dropped while
simplifying, but promises on RVar-invariant values and a user's
unsafe_promise_clamped on an RVar-dependent value are kept, so bounds
inference still has them.
Tests cover divisible, symbolic-tail, and constant-tail extents, the
min/+ and ||/&& laws, a promised data-dependent block index, an RDom
starting off a block boundary (block-aligned factor hoisted, misaligned
one kept), and a finer-grained factor that must not be hoisted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split the reduction into blocks of 32 and then lanes of 4, and rfactor both the block and the lane, so each lane keeps its own partial sum. The per-block factor's index then only simplifies to lane/8 + u given the bound on the innermost RVar, which needs the (x*c0 + y)/c1 simplifier rule. Check that the factor is hoisted, with divisible and non-divisible extents. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A blocked reduction whose block is processed as several chunks of lanes,
e.g. split(r, ro, ri, 32).split(ri, rc, rl, 16).split(rl, rv, rw, 4)
followed by rfactor({{rv, v}, {ro, u}}), leaves the per-block factor
reading s((u*32 + rc*16 + v*4 + rw) / 32). That is s(u) only given that
the pure var v (formerly an RVar) is in [0, 4), which nothing recorded,
so hoist_invariants() rejected it.
hoist_invariants() now also uses explicit bound(var, min, extent)
directives with constant min and extent on the Func's pure vars as the
ranges of those vars when simplifying leaves. bound() fixes the region
the Func is computed over, and Halide asserts consumers need no more
than that. bound_extent(), align_bounds() and bound_storage() are not
used.
RVar bounds alone are tried first. A factor that is invariant only given
the pure-var bounds is wrapped in a require() on those vars. The require
simplifies away while the bound stands. If bound() is widened after
hoisting, the require turns that into a runtime error instead of a wrong
result.
Tests cover the two-chunk block with divisible and tail extents, the
error without bound() or with a too-wide bound, and reads outside the
bound both with the bound unchanged and with it widened after hoisting.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
rfactor() now tags the clamped RVar itself, promise_clamped(likely(r), ...). Removing the promise but keeping likely() hid the index from the simplifier, so e.g. (likely(u*32 + ki))/32 no longer simplified to u and the per-block factor was not hoisted (correctness_hoist_invariants, block index cases). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This branch has not been deployed
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.
Stage::hoist_invariants()decided invariance syntactically, so per-block factors in blocked reductions were never hoisted:The intermediate reads
scale(promise_clamped(u*32 + ki, ...) / 32), which isscale(u)for everykiin[0, 32).Now a leaf that mentions RVars has its integer (never float) RVar-dependent subexpressions simplified under the RVars' constant bounds, and is hoisted if the result is RVar-free. rfactor's internal
promise_clampedis dropped for this, along with thelikely()tag on its value; user promises are kept. When the RVar bounds aren't enough (e.g. a lane var that was an RVar before rfactor), constantbound()s on the Func's pure vars are used too, and the factor is wrapped in arequire()so that widening thebound()later fails loudly instead of silently using a wrong factor.Depends on #9520 for the per-lane case,
scale((lane*4 + ki) / 32).Tests: new cases in
correctness_hoist_invariants.Breaking changes
No API changes. Some pipelines that used to error now hoist, and pipelines that already hoisted may hoist more leaves, which can change float rounding (as hoisting already does).
Authored by GitHub Copilot