summaryrefslogtreecommitdiff
path: root/lib/compiler/src/v3_kernel.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/src/v3_kernel.erl')
-rw-r--r--lib/compiler/src/v3_kernel.erl86
1 files changed, 70 insertions, 16 deletions
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index febc971427..809924c7f3 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -119,6 +119,7 @@ copy_anno(Kdst, Ksrc) ->
free=#{}, %Free variables
ws=[] :: [warning()], %Warnings.
no_shared_fun_wrappers=false :: boolean(),
+ no_min_max_bifs=false :: boolean(),
labels=sets:new([{version, 2}])
}).
@@ -130,7 +131,9 @@ module(#c_module{anno=A,name=M,exports=Es,attrs=As,defs=Fs}, Options) ->
Kes = map(fun (#c_var{name={_,_}=Fname}) -> Fname end, Es),
NoSharedFunWrappers = proplists:get_bool(no_shared_fun_wrappers,
Options),
- St0 = #kern{no_shared_fun_wrappers=NoSharedFunWrappers},
+ NoMinMaxBifs = proplists:get_bool(no_min_max_bifs, Options),
+ St0 = #kern{no_shared_fun_wrappers=NoSharedFunWrappers,
+ no_min_max_bifs=NoMinMaxBifs},
{Kfs,St} = mapfoldl(fun function/2, St0, Fs),
{ok,#k_mdef{anno=A,name=M#c_literal.val,exports=Kes,attributes=Kas,
body=Kfs ++ St#kern.funs},sort(St#kern.ws)}.
@@ -323,7 +326,7 @@ expr(#c_call{anno=A,module=M0,name=F0,args=Cargs}, Sub, St0) ->
Ar = length(Cargs),
{[M,F|Kargs],Ap,St1} = atomic_list([M0,F0|Cargs], Sub, St0),
Remote = #k_remote{mod=M,name=F,arity=Ar},
- case call_type(M0, F0, Cargs) of
+ case call_type(M0, F0, Cargs, St1) of
bif ->
{#k_bif{anno=A,op=Remote,args=Kargs},Ap,St1};
call ->
@@ -357,7 +360,9 @@ expr(#c_try{anno=A,arg=Ca,vars=Cvs,body=Cb,evars=Evs,handler=Ch}, Sub0, St0) ->
evars=Kevs,handler=pre_seq(Ph, Kh)},[],St5};
expr(#c_catch{anno=A,body=Cb}, Sub, St0) ->
{Kb,Pb,St1} = body(Cb, Sub, St0),
- {#k_catch{anno=A,body=pre_seq(Pb, Kb)},[],St1}.
+ {#k_catch{anno=A,body=pre_seq(Pb, Kb)},[],St1};
+expr(#c_opaque{anno=A,val=V}, _, St) ->
+ {#k_opaque{anno=A,val=V},[],St}.
%% Implement letrec in the traditional way as a local
%% function for each definition in the letrec.
@@ -543,15 +548,24 @@ map_key_clean(#k_literal{val=V}) -> {lit,V}.
%% call_type(Module, Function, Arity) -> call | bif | error.
%% Classify the call.
-call_type(#c_literal{val=M}, #c_literal{val=F}, As) when is_atom(M), is_atom(F) ->
+call_type(#c_literal{val=M}, #c_literal{val=F}, As, St) when is_atom(M), is_atom(F) ->
case is_remote_bif(M, F, As) of
- false -> call;
- true -> bif
+ false ->
+ call;
+ true ->
+ %% The guard BIFs min/2 and max/2 were introduced in
+ %% Erlang/OTP 26. If we are compiling for an earlier
+ %% version, we must translate them as call instructions.
+ case {M,F,St#kern.no_min_max_bifs} of
+ {erlang,min,true} -> call;
+ {erlang,max,true} -> call;
+ {_,_,_} -> bif
+ end
end;
-call_type(#c_var{}, #c_literal{val=A}, _) when is_atom(A) -> call;
-call_type(#c_literal{val=A}, #c_var{}, _) when is_atom(A) -> call;
-call_type(#c_var{}, #c_var{}, _) -> call;
-call_type(_, _, _) -> error.
+call_type(#c_var{}, #c_literal{val=A}, _, _) when is_atom(A) -> call;
+call_type(#c_literal{val=A}, #c_var{}, _, _) when is_atom(A) -> call;
+call_type(#c_var{}, #c_var{}, _, _) -> call;
+call_type(_, _, _, _) -> error.
%% match_vars(Kexpr, State) -> {[Kvar],[PreKexpr],State}.
%% Force return from body into a list of variables.
@@ -1375,8 +1389,9 @@ select_bin_int([#iclause{pats=[#k_bin_seg{anno=A,type=integer,
true -> throw(not_possible);
false -> ok
end,
- Cs = select_bin_int_1(Cs0, Bits, Fl, Val),
- [{k_bin_int,[C#iclause{pats=[P|Ps]}|Cs]}];
+ Cs1 = [C#iclause{pats=[P|Ps]}|select_bin_int_1(Cs0, Bits, Fl, Val)],
+ Cs = reorder_bin_ints(Cs1),
+ [{k_bin_int,Cs}];
select_bin_int(_) -> throw(not_possible).
select_bin_int_1([#iclause{pats=[#k_bin_seg{anno=A,type=integer,
@@ -1419,6 +1434,44 @@ match_fun(Val) ->
{match,Bs}
end.
+reorder_bin_ints([_]=Cs) ->
+ Cs;
+reorder_bin_ints(Cs0) ->
+ %% It is safe to reorder clauses that matches binaries if the
+ %% first segments for all of them match the same number of bits
+ %% and if the patterns that follow are also safe to re-order.
+ try
+ Cs = sort([{reorder_bin_int_sort_key(C),C} || C <- Cs0]),
+ [C || {_,C} <- Cs]
+ catch
+ throw:not_possible ->
+ Cs0
+ end.
+
+reorder_bin_int_sort_key(#iclause{pats=[Pats|More],guard=#c_literal{val=true}}) ->
+ case all(fun(#k_var{}) -> true;
+ (_) -> false
+ end, More) of
+ true ->
+ %% Only variables. Safe to re-order.
+ ok;
+ false ->
+ %% Not safe to re-order. For example:
+ %% f([<<"prefix">>, <<"action">>]) -> ...
+ %% f([<<"prefix">>, Variable]) -> ...
+ throw(not_possible)
+ end,
+ case Pats of
+ #k_bin_int{val=Val,next=#k_bin_end{}} ->
+ %% Sort before clauses with additional segments. This usually results in
+ %% better code.
+ [Val];
+ #k_bin_int{val=Val} ->
+ [Val,more]
+ end;
+reorder_bin_int_sort_key(#iclause{}) ->
+ throw(not_possible).
+
%% match_value([Var], Con, [Clause], Default, State) -> {SelectExpr,State}.
%% At this point all the clauses have the same constructor, we must
%% now separate them according to value.
@@ -1512,9 +1565,7 @@ group_value(_, Us, Cs) ->
Map = group_values(Cs, #{}),
%% We must sort the grouped values to ensure consistent
%% order from compilation to compilation.
- sort(maps:fold(fun (_, Vcs, Css) ->
- [{Us,reverse(Vcs)}|Css]
- end, [], Map)).
+ sort([{Us,reverse(Vcs)} || _ := Vcs <- Map]).
group_values([C|Cs], Acc) ->
Val = clause_val(C),
@@ -2019,6 +2070,8 @@ uexpr(#k_letrec_goto{anno=A,vars=Vs,first=F0,then=T0}=MatchAlt, Br, St0) ->
{T1,Tu,St2} = ubody(T0, Br, St1),
Used = subtract(union(Fu, Tu), Ns),
{MatchAlt#k_letrec_goto{anno=A,first=F1,then=T1,ret=Rs},Used,St2};
+uexpr(#k_opaque{}=O, _, St) ->
+ {O,[],St};
uexpr(Lit, {break,Rs0}, St0) ->
%% Transform literals to puts here.
%%ok = io:fwrite("uexpr ~w:~p~n", [?LINE,Lit]),
@@ -2161,7 +2214,8 @@ lit_vars(#k_bin_seg{size=Size,seg=S,next=N}) ->
union(lit_vars(Size), union(lit_vars(S), lit_vars(N)));
lit_vars(#k_tuple{es=Es}) ->
lit_list_vars(Es);
-lit_vars(#k_literal{}) -> [].
+lit_vars(#k_literal{}) -> [];
+lit_vars(#k_opaque{}) -> [].
lit_list_vars(Ps) ->
foldl(fun (P, Vs) -> union(lit_vars(P), Vs) end, [], Ps).