Skip to content

Scalar replacement: unpack records/arrays/updates read only field-wise #240

Description

@Unisay

Problem

A let-bound record, array, constructor, or record update that is only ever read by field, never used as a whole value, still allocates its table. pslua unpacks constructors through a let (propagateKnownCtorThroughLet) and folds an in-place object projection (reduceObjectProp), but has no general rule for records, arrays, or updates. On the Lua target, where a table allocation costs more than in a JS engine with escape analysis, an aggregate that exists only to be projected is pure waste.

The unpacking rewrite explodes such a binding into a per-field let so the aggregate is never built, gated on an exact use equation: total == access + case for a constructor, == access + update for a record, == access for an array. A single whole-value use vetoes the rewrite, preserving sharing and identity.

Approach

Add an unpacking rewrite for let x = <aggregate> in body where <aggregate> is a record literal, array literal, constructor application, or record update and every occurrence of x in body is a field/element projection (or, for a constructor, a case reading its fields). Bind each read field to its own let and drop the aggregate. The exact-use equation is the gate; any use of x as a whole value (returned, passed, compared) turns it off.

Prerequisites / Relations

Blocked by #231 (the Complexity/Capture analysis lattice): "read only field-wise, never as a whole" is the same exact-use accounting the lattice makes precise. The result-side dual is #206 (CPR: return components rather than a product); together they avoid materializing a box on either side of a call. Relates to #208 (SpecConstr), which removes the boxed accumulator this rule would otherwise unpack every iteration.

Verification / Measurement

A let-bound record read at two fields compiles with no table allocation and two direct bindings in golden.lua; a record also used as a whole value keeps its allocation, the soundness guard, tested directly. Allocation-counter drop on a record-heavy benchmark through #172; eval goldens unchanged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    OptimisationA Compiler Optimisationarea: irIR / optimizer / DCE / inlinerenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions