Skip to content

Move LC ++ Tail fusion from v3_core to sys_core_fold#10912

Open
michalmuskala wants to merge 1 commit intoerlang:masterfrom
michalmuskala:opt-letrec
Open

Move LC ++ Tail fusion from v3_core to sys_core_fold#10912
michalmuskala wants to merge 1 commit intoerlang:masterfrom
michalmuskala:opt-letrec

Conversation

@michalmuskala
Copy link
Copy Markdown
Contributor

When [E || Qs] ++ Tail is written, the compiler fuses the ++ into the list comprehension's base case, replacing [] with Tail to avoid an O(n) append traversal. Previously this optimization lived in v3_core and only worked when the LC and ++ appeared in the same expression. It failed when an intermediate variable separated them:

Expanded = [Exp || Exp <- Exps],
Expanded ++ Tail

Move the optimization to sys_core_fold where it can handle both cases. After v3_core's force_safe binds the letrec to a variable, both the inline and variable forms produce the same Core Erlang pattern:

let V = letrec lc/1 = ... in apply lc/1(List)
in call erlang:'++'(V, Tail)

The new opt_lc_append in opt_let_2 detects this pattern and rewrites the LC function to accept an extra tail parameter, replacing the [] base case with the tail argument and eliminating the ++ call entirely.

When `[E || Qs] ++ Tail` is written, the compiler fuses the `++` into
the list comprehension's base case, replacing `[]` with `Tail` to
avoid an O(n) append traversal. Previously this optimization lived in
v3_core and only worked when the LC and `++` appeared in the same
expression. It failed when an intermediate variable separated them:

    Expanded = [Exp || Exp <- Exps],
    Expanded ++ Tail

Move the optimization to sys_core_fold where it can handle both cases.
After v3_core's `force_safe` binds the letrec to a variable, both the
inline and variable forms produce the same Core Erlang pattern:

    let V = letrec lc/1 = ... in apply lc/1(List)
    in call erlang:'++'(V, Tail)

The new `opt_lc_append` in `opt_let_2` detects this pattern and
rewrites the LC function to accept an extra tail parameter, replacing
the `[]` base case with the tail argument and eliminating the `++`
call entirely.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 24, 2026

CT Test Results

    2 files    335 suites   9m 19s ⏱️
  872 tests   866 ✅ 6 💤 0 ❌
5 729 runs  5 723 ✅ 6 💤 0 ❌

Results for commit 742ca64.

♻️ This comment has been updated with latest results.

To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass.

See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally.

Artifacts

// Erlang/OTP Github Action Bot

@TD5
Copy link
Copy Markdown
Contributor

TD5 commented Mar 24, 2026

Thanks @michalmuskala - I've hit this before and had to make the frustrating trade-off of code-style vs. performance.

@bjorng bjorng added the team:VM Assigned to OTP team VM label Mar 25, 2026
@bjorng bjorng self-assigned this Mar 25, 2026
@bjorng
Copy link
Copy Markdown
Contributor

bjorng commented Mar 25, 2026

Thanks for your pull request. We'll include it in OTP 30.

@bjorng bjorng added the stalled waiting for input by the Erlang/OTP team label Mar 25, 2026
@bjorng bjorng added this to the 30.0 milestone Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stalled waiting for input by the Erlang/OTP team team:VM Assigned to OTP team VM

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants