Skip to content

Ptr<Shape>: a scalar-replaced object is still counted as a promotion, and emits nothing #7115

Description

@proggeramlug

Follow-up to #7106. Sibling of #7109 / #7110 / #7111 / #7112.

A Ptr<Shape> promotion can be selected, counted by --opt-report as a win,
and produce literally nothing — three ways. Two are known:

  1. the module-init / program-entry context gate (repsel: module-init / program-entry bodies are excluded from canonical i32+Str selection, so a top-level hot loop promotes nothing #7109), and
  2. the receiver-fact context gate — repsel_context_allows_canonical_i32: false makes FnCtx::ptr_shape_receiver_fact return None for the whole
    body, so every access site falls through to the guarded diamond.

This issue is the third, which was undocumented.

Mechanism

collectors/escape_news.rs scalar-replaces the object: its fields become
per-field allocas and the allocation is deleted outright
(stmt/let_stmt.rs, the ctx.non_escaping_news arm). No property access ever
reaches a representation-selection lowering, because there is no property
access left — and no object left to have a representation.

The Ptr<Shape> collector runs anyway and proves the local, so the report
records selected: 1.

Why it matters, given that scalar replacement is the BETTER outcome

It is. Deleting the allocation beats promoting it, and the two passes are
complementary rather than competing: adding one in-loop field store flips a
workload from scalar-replaced to Ptr<Shape>-consumed. Nothing here asks for
that to change.

The defect is that "scalar-replaced" and "promoted but wasted" are
indistinguishable in the report, and they mean opposite things.
One says the
compiler did something better than you asked for. The other says the compiler
proved something and threw it away. Both render as selected: 1.

Evidence

benchmarks/suite/07_object_create.ts and benchmarks/suite/12_binary_trees.ts
each report exactly one Ptr<Shape> promotion. For both, compiling with
PERRY_PTR_SHAPE_LOCALS=0 and with the default produces a byte-identical
object file
:

WORKLOAD                       VERDICT      note
suite_07_object_create         IDENTICAL    analysis changed NOTHING
suite_12_binary_trees          IDENTICAL    analysis changed NOTHING

(23-workload A/B over the census corpus, perry compile --no-link --no-cache,
sha256 of the emitted objects.)

Those two workloads were, together with 09_method_calls, proposed as the
"cleanest available experiment" for measuring what a promotion is worth. All
three would have measured 0.00%, and the report would have said the promotion
was there.

Ask

Record the drop where it happens, naming the mechanism — as the sibling issues
do for the context gates — so selected stops being readable as "this promotion
is in the binary". Concretely: at the Stmt::Let site that commits to scalar
replacement, if the local is also shape-proven, record an unconsumed entry
with rule scalar_replaced.

Status

Implemented as part of the consumed-vs-selected census work. This issue exists
because the mechanism was undocumented and had no tracking issue of its own,
and because the remaining question is a real one: should Ptr<Shape> even
run its proof for a local that escape analysis has already deleted?
Today it
does, and pays for the proof. Skipping it would be a small compile-time win and
would make the census number self-evidently honest, but it needs care — the two
passes' eligibility sets are not identical and the ordering is not currently a
dependency.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions