Skip to content

betaReduce substitutes a non-trivial argument into every occurrence of the parameter, multiplying work #167

Description

@Unisay

Problem

betaReduce (lib/Language/PureScript/Backend/IR/Optimizer.hs) rewrites App (Abs (ParamNamed param) body) r by substituting r for every occurrence of param, with no look at either the shape of r or the number of occurrences. In a strict language that duplicates evaluation: (\x -> ... x ... x ...) (g y) becomes ... (g y) ... (g y) ..., and the work of g y now runs once per occurrence instead of once.

The path is live. Redexes with non-trivial arguments show up whenever the inliner puts a lambda into call-head position, which it does for used-once bindings and for @inline always annotations; the more the inliner improves, the more such redexes this rule sees.

This is a performance defect, not a correctness one. Effect and ST computations are nullary thunks in the IR, so evaluating a duplicated argument builds the thunk twice but runs the effect exactly as many times as the body calls it. The remaining evaluation-order edge — an Exception inside the duplicated or dropped argument — follows the policy the pipeline already declares for let-bound values (see the FloatIn module note: discardable and reorderable once nothing observes them).

Approach

Apply GHC's rule: substitute only when the argument is trivial (a Ref or a literal) or the parameter occurs at most once; otherwise rewrite the redex to Let param = r in body and leave the decision to inlineLocalBindings, which already counts occurrences.

Prerequisites / Relations

Optimizer correctness/efficiency bug, independent. Related to #142 and #143: once their occurrence-annotation rework lands, the occurrence check here becomes a field read instead of a traversal.

Verification / Measurement

A redex (\x -> ... x ... x ...) (g y) with a non-trivial argument no longer duplicates g y into every occurrence of the parameter; instead it is let-bound and the argument's work is evaluated once. Trivial arguments (a Ref or literal) and single-occurrence parameters still substitute directly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: irIR / optimizer / DCE / inlinerbugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions