Skip to content

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

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

Move LC ++ Tail fusion from v3_core to sys_core_fold#10912
michalmuskala wants to merge 1 commit into
erlang: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

github-actions Bot commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

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

TD5 commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

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

bjorng commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

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
@bjorng bjorng added testing currently being tested, tag is used by OTP internal CI and removed stalled waiting for input by the Erlang/OTP team labels May 25, 2026
@bjorng

bjorng commented May 27, 2026

Copy link
Copy Markdown
Contributor

The following code is no longer optimized (slightly simplified from asn1ct_imm.erl):

per_dec_named_integer(NamedList0, Int) ->
    NamedList = [{K,V} || {V,K} <- NamedList0] ++ [integer_default],
    {map,Int,NamedList}.

Hint: I ran scripts/diffable to find this. If you run ``scripts/diffable` without any arguments, it will print text explaining how to use it.

@bjorng bjorng added waiting waiting for changes/input from author and removed testing currently being tested, tag is used by OTP internal CI labels May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

team:VM Assigned to OTP team VM waiting waiting for changes/input from author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants