File 1321-Reduce-compilation-times-for-code-with-many-element-.patch of Package erlang
From 437c3957e873685789df3ffdcc2440b74c5195a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Fri, 6 Mar 2026 15:23:20 +0100
Subject: [PATCH] Reduce compilation times for code with many element/2 calls
Improve the compile-time performance of code with many uses of
`element/2`. This reduces the time of the `beam_ssa_opt` pass
to about 6 seconds down from 11 seconds on my computer.
Resolves #10807
---
lib/compiler/src/beam_ssa_alias.erl | 28 +++++++++++-----------------
lib/compiler/src/beam_ssa_type.erl | 23 ++++++++++++-----------
2 files changed, 23 insertions(+), 28 deletions(-)
diff --git a/lib/compiler/src/beam_ssa_alias.erl b/lib/compiler/src/beam_ssa_alias.erl
index 7cbc4843c1..2bf285e660 100644
--- a/lib/compiler/src/beam_ssa_alias.erl
+++ b/lib/compiler/src/beam_ssa_alias.erl
@@ -1653,11 +1653,12 @@ rur_args([], _) ->
%% forcibly alias the variable when it is defined.
%%
forced_aliasing(Linear) ->
- forced_aliasing(Linear, #{0=>#{}}, sets:new()).
+ SeenDb0 = #{0 => #{}, ?EXCEPTION_BLOCK => #{}},
+ forced_aliasing(Linear, SeenDb0, sets:new()).
-forced_aliasing([{Lbl,#b_blk{last=Last,is=Is}}|Rest], SeenDb0, ToExtend0) ->
+forced_aliasing([{Lbl,#b_blk{is=Is}=Block}|Rest], SeenDb0, ToExtend0) ->
#{Lbl:=Seen0} = SeenDb0,
- Successors = fa_successors(Last),
+ Successors = beam_ssa:successors(Block),
{Seen,ToExtend} = forced_aliasing_is(Is, Seen0, ToExtend0),
SeenDb = foldl(fun(Succ, Acc) -> fa_merge(Seen, Succ, Acc) end,
SeenDb0, Successors),
@@ -1710,18 +1711,11 @@ forced_aliasing_extend_to(Dst, Aliases, ToExtend) ->
foldl(fun sets:add_element/2,
sets:add_element(Dst, ToExtend), Aliases).
-fa_successors(#b_ret{}) ->
- [];
-fa_successors(#b_br{succ=S,fail=F}) ->
- [S,F];
-fa_successors(#b_switch{list=Ls,fail=F}) ->
- [F|[L || {_,L} <:- Ls]].
-
-fa_merge(Seen, Succ, SeenDb) ->
+fa_merge(_Seen, ?EXCEPTION_BLOCK, SeenDb) ->
+ SeenDb;
+fa_merge(Seen0, Succ, SeenDb) ->
Other = maps:get(Succ, SeenDb, #{}),
- SeenDb#{Succ=>maps:merge_with(
- fun(_, A, B) ->
- ordsets:union(A, B)
- end,
- Seen, Other)}.
-
+ Seen = maps:merge_with(fun(_, A, A) -> A;
+ (_, A, B) -> ordsets:union(A, B)
+ end, Seen0, Other),
+ SeenDb#{Succ=>Seen}.
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
index 4d40651df8..473bf60965 100644
--- a/lib/compiler/src/beam_ssa_type.erl
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -2961,17 +2961,18 @@ join_types(Ts, Ts) ->
join_types(LHS, RHS) ->
if
map_size(LHS) < map_size(RHS) ->
- join_types_1(maps:keys(LHS), RHS, LHS);
+ join_types_1(maps:next(maps:iterator(LHS)), RHS, LHS);
true ->
- join_types_1(maps:keys(RHS), LHS, RHS)
+ join_types_1(maps:next(maps:iterator(RHS)), LHS, RHS)
end.
%% Joins two type maps, keeping the variables that are common to both maps.
-join_types_1([V | Vs], Bigger, Smaller) ->
- case {Bigger, Smaller} of
- {#{ V := Same }, #{ V := Same }} ->
- join_types_1(Vs, Bigger, Smaller);
- {#{ V := LHS0 }, #{ V := RHS0 }} ->
+join_types_1({V, RHS0, Iter0}, Bigger, Smaller) ->
+ Iter = maps:next(Iter0),
+ case Bigger of
+ #{V := RHS0} ->
+ join_types_1(Iter, Bigger, Smaller);
+ #{V := LHS0} ->
%% Inlined concrete_type/2 for performance.
LHS = case is_function(LHS0) of
true -> LHS0(Bigger);
@@ -2982,11 +2983,11 @@ join_types_1([V | Vs], Bigger, Smaller) ->
false -> RHS0
end,
T = beam_types:join(LHS, RHS),
- join_types_1(Vs, Bigger, Smaller#{ V := T });
- {#{}, #{ V := _ }} ->
- join_types_1(Vs, Bigger, maps:remove(V, Smaller))
+ join_types_1(Iter, Bigger, Smaller#{V := T});
+ #{} ->
+ join_types_1(Iter, Bigger, maps:remove(V, Smaller))
end;
-join_types_1([], _Bigger, Smaller) ->
+join_types_1(none, _Bigger, Smaller) ->
Smaller.
meet_types([{#b_literal{}=Lit, T0} | Vs], Ts) ->
--
2.51.0