Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog.d/9033-push-typed-inversion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Changed

- `a.push(i)` where `a` has a static numeric-layout proof (e.g. a `number[]` local or parameter) and `i` is an integer-provenance local now takes the full inline append tier instead of the three-call guarded-numeric tier. The typed receiver was slower than an untyped one for the most common append shape; it is now ~25× faster and ahead of node on the isolated operation.
19 changes: 19 additions & 0 deletions crates/perry-codegen/src/type_analysis/numeric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,25 @@ pub(crate) fn is_numeric_expr(ctx: &FnCtx<'_>, e: &Expr) -> bool {
pub(crate) fn expr_produces_canonical_raw_f64(ctx: &FnCtx<'_>, e: &Expr) -> bool {
match e {
Expr::Integer(_) | Expr::Number(_) => true,
// An integer-provenance local holds an integer-valued double by
// dataflow: it can never be NaN, so its bits can never fall inside the
// NaN-box tag window — which is the entire hazard this predicate
// guards (a raw-f64 store whose bits alias a tag). This is the
// `a.push(i)` loop-counter shape: without the arm, a statically
// numeric receiver routed every such push through the three-call
// guarded-numeric tier, slower than the untyped receiver's inline
// store — the push-side twin of the read inversion #6904 retired.
// The storage conditions mirror
// `local_get_produces_non_pointer_bits_by_dataflow`: plain slot, not
// boxed, captured, or a module global (those can be rebound by code
// the dataflow walk cannot see).
Expr::LocalGet(id) => {
(ctx.i32_counter_slots.contains_key(id) || ctx.integer_locals.contains(id))
&& (ctx.locals.contains_key(id) || ctx.local_slot_reps.contains_key(id))
&& !ctx.boxed_vars.contains(id)
&& !ctx.closure_captures.contains_key(id)
&& !ctx.module_globals.contains_key(id)
}
Expr::IndexGet { .. }
if crate::stmt::stable_packed_loop::has_numeric_index_fact(ctx, e) =>
{
Expand Down
Loading