Skip to content

Conversation

@pguyot
Copy link
Collaborator

@pguyot pguyot commented Nov 2, 2025

See #1953

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later

@pguyot pguyot force-pushed the w44/lists-flatten-as-nif branch from 3c3efb6 to 005cf1e Compare November 3, 2025 06:48
Literal pools need to be within 1024 bytes because of limited range of
ldr reg, [pc, #imm] instruction. A pool is emitted when mov_immediate is
called and the pool reference is farther than a given threshold. Emitting
the pool in such a condition requires a branch over the pool, and is
therefore less efficient than the usual pool flush that happens when a
branch is emitted (tail calls).

This threshold was set to 900 but new test module bigint.beam wouldn't
compile. This commit changes the threshold to 512 which works (the test
actually requires 663).

The optimal threshold value depends on the pattern usage of mov_immediate.
If regular code hits the bug, we may need to change the heuristic and emit the
pool based on other conditions.

Signed-off-by: Paul Guyot <[email protected]>
@pguyot pguyot force-pushed the w44/lists-flatten-as-nif branch from 005cf1e to d623db2 Compare November 3, 2025 07:21
?ASSERT_MATCH(?MODULE:id([a, b]), [a, b]),
ok.

test_flatten() ->
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest adding a test for improper lists. Tests like:

  • [7 | {}]
  • [[] | [5 | 5]]
  • [[7 | 4], 2]

if (term_is_nonempty_list(t)) {
term t_head = term_get_list_head(t);
term t_tail = term_get_list_tail(t);
if (term_is_nonempty_list(t_tail)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good, but my guess is that it can be replaced with a slightly optimized alternative implementation that doesn't push all values, but only when there are nested lists.

This should optimize the trivial case (such as [1, 2, 3, 4]), by avoiding copying to the temp stack the entire list.

Basically we should push t_tail to the stack every time t_head is a term_is_nonempty_list.
In that case t_tail is used as a "continuation value" as soon as the current list is finished.

e.g.

flatten([[1, 2], 5, 6, 7]):
iteration 0:
  - t is [[1, 2], 5, 6, 7]
  - t_head is [1, 2]
  - t_tail is [5, 6, 7]
  - t_tail is pushed to the stack
  - t is set to [1, 2]
...
  when t is []:
  - t is popped from the stack
iteration n:
  - t is [5, 6, 7]
  ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants