aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/src')
-rw-r--r--lib/compiler/src/beam_bsm.erl1
-rw-r--r--lib/compiler/src/beam_validator.erl1
-rw-r--r--lib/compiler/src/sys_core_fold.erl25
-rw-r--r--lib/compiler/src/v3_core.erl21
-rw-r--r--lib/compiler/src/v3_kernel.erl13
5 files changed, 33 insertions, 28 deletions
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
index fdfcb08125..d54c2a9fde 100644
--- a/lib/compiler/src/beam_bsm.erl
+++ b/lib/compiler/src/beam_bsm.erl
@@ -209,6 +209,7 @@ btb_reaches_match_2([{call,Arity,{f,Lbl}}|Is], Regs, D) ->
btb_reaches_match_2([{apply,Arity}|Is], Regs, D) ->
btb_call(Arity+2, apply, Regs, Is, D);
btb_reaches_match_2([{call_fun,Live}=I|Is], Regs, D) ->
+ btb_ensure_not_used([{x,Live}], I, Regs),
btb_call(Live, I, Regs, Is, D);
btb_reaches_match_2([{make_fun2,_,_,_,Live}|Is], Regs, D) ->
btb_call(Live, make_fun2, Regs, Is, D);
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 97f84da08f..682f7adbc2 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -574,6 +574,7 @@ valfun_4({apply,Live}, Vst) ->
valfun_4({apply_last,Live,_}, Vst) ->
tail_call(apply, Live+2, Vst);
valfun_4({call_fun,Live}, Vst) ->
+ validate_src([{x,Live}], Vst),
call('fun', Live+1, Vst);
valfun_4({call,Live,Func}, Vst) ->
call(Func, Live, Vst);
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 9ce6bb48bf..e302e2324d 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1945,9 +1945,30 @@ eval_case(#c_case{arg=E,clauses=[#c_clause{pats=Ps0,body=B}]}, Sub) ->
true -> cerl:values_es(E);
false -> [E]
end,
- {true,Bs} = cerl_clauses:match_list(Ps0, Es),
+ %% Consider:
+ %%
+ %% case SomeSideEffect() of
+ %% X=Y -> ...
+ %% end
+ %%
+ %% We must not rewrite it to:
+ %%
+ %% let <X,Y> = <SomeSideEffect(),SomeSideEffect()> in ...
+ %%
+ %% because SomeSideEffect() would be called evaluated twice.
+ %%
+ %% Instead we must evaluate the case expression in an outer let
+ %% like this:
+ %%
+ %% let NewVar = SomeSideEffect() in
+ %% let <X,Y> = <NewVar,NewVar> in ...
+ %%
+ Vs = make_vars([], length(Es)),
+ {true,Bs} = cerl_clauses:match_list(Ps0, Vs),
{Ps,As} = unzip(Bs),
- expr(#c_let{vars=Ps,arg=core_lib:make_values(As),body=B}, sub_new(Sub));
+ InnerLet = cerl:c_let(Ps, core_lib:make_values(As), B),
+ Let = cerl:c_let(Vs, E, InnerLet),
+ expr(Let, sub_new(Sub));
eval_case(Case, _) -> Case.
%% case_opt(CaseArg, [Clause]) -> {CaseArg,[Clause]}.
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 59863f52ec..291443f824 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -74,7 +74,7 @@
-export([module/2,format_error/1]).
-import(lists, [reverse/1,reverse/2,map/2,member/2,foldl/3,foldr/3,mapfoldl/3,
- splitwith/2,keyfind/3,sort/1,foreach/2]).
+ splitwith/2,keyfind/3,sort/1,foreach/2,droplast/1,last/1]).
-import(ordsets, [add_element/2,del_element/2,is_element/2,
union/1,union/2,intersection/2,subtract/2]).
-import(cerl, [ann_c_cons/3,ann_c_cons_skel/3,ann_c_tuple/2,c_tuple/1]).
@@ -226,13 +226,13 @@ guard(Gs0, St0) ->
Gt1 = guard_tests(Gt0),
L = element(2, Gt1),
{op,L,'or',Gt1,Rhs}
- end, guard_tests(last(Gs0)), first(Gs0)),
+ end, guard_tests(last(Gs0)), droplast(Gs0)),
{Gs,St} = gexpr_top(Gs1, St0#core{in_guard=true}),
{Gs,St#core{in_guard=false}}.
guard_tests(Gs) ->
L = element(2, hd(Gs)),
- {protect,L,foldr(fun (G, Rhs) -> {op,L,'and',G,Rhs} end, last(Gs), first(Gs))}.
+ {protect,L,foldr(fun (G, Rhs) -> {op,L,'and',G,Rhs} end, last(Gs), droplast(Gs))}.
%% gexpr_top(Expr, State) -> {Cexpr,State}.
%% Generate an internal core expression of a guard test. Explicitly
@@ -513,7 +513,7 @@ expr({bin,L,Es0}, St0) ->
end;
expr({block,_,Es0}, St0) ->
%% Inline the block directly.
- {Es1,St1} = exprs(first(Es0), St0),
+ {Es1,St1} = exprs(droplast(Es0), St0),
{E1,Eps,St2} = expr(last(Es0), St1),
{E1,Es1 ++ Eps,St2};
expr({'if',L,Cs0}, St0) ->
@@ -1588,15 +1588,6 @@ pat_alias_list(_, _) -> throw(nomatch).
pattern_list(Ps, St) -> [pattern(P, St) || P <- Ps].
-%% first([A]) -> [A].
-%% last([A]) -> A.
-
-first([_]) -> [];
-first([H|T]) -> [H|first(T)].
-
-last([L]) -> L;
-last([_|T]) -> last(T).
-
%% make_vars([Name]) -> [{Var,Name}].
make_vars(Vs) -> [ #c_var{name=V} || V <- Vs ].
@@ -1679,13 +1670,13 @@ uclause(#iclause{anno=Anno,pats=Ps0,guard=G0,body=B0}, Pks, Ks0, St0) ->
uguard([], [], _, St) -> {[],St};
uguard(Pg, [], Ks, St) ->
%% No guard, so fold together equality tests.
- uguard(first(Pg), [last(Pg)], Ks, St);
+ uguard(droplast(Pg), [last(Pg)], Ks, St);
uguard(Pg, Gs0, Ks, St0) ->
%% Gs0 must contain at least one element here.
{Gs3,St5} = foldr(fun (T, {Gs1,St1}) ->
{L,St2} = new_var(St1),
{R,St3} = new_var(St2),
- {[#iset{var=L,arg=T}] ++ first(Gs1) ++
+ {[#iset{var=L,arg=T}] ++ droplast(Gs1) ++
[#iset{var=R,arg=last(Gs1)},
#icall{anno=#a{}, %Must have an #a{}
module=#c_literal{val=erlang},
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index 0163b16715..bc5ca0314a 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -81,7 +81,7 @@
-export([module/2,format_error/1]).
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2,
- keymember/3,keyfind/3,partition/2]).
+ keymember/3,keyfind/3,partition/2,droplast/1,last/1]).
-import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]).
-import(cerl, [c_tuple/1]).
@@ -350,7 +350,7 @@ expr(#c_case{arg=Ca,clauses=Ccs}, Sub, St0) ->
{Kvs,Pv,St2} = match_vars(Ka, St1), %Must have variables here!
{Km,St3} = kmatch(Kvs, Ccs, Sub, St2),
Match = flatten_seq(build_match(Kvs, Km)),
- {last(Match),Pa ++ Pv ++ first(Match),St3};
+ {last(Match),Pa ++ Pv ++ droplast(Match),St3};
expr(#c_receive{anno=A,clauses=Ccs0,timeout=Ce,action=Ca}, Sub, St0) ->
{Ke,Pe,St1} = atomic(Ce, Sub, St0), %Force this to be atomic!
{Rvar,St2} = new_var(St1),
@@ -902,15 +902,6 @@ foldr2(Fun, Acc0, [E1|L1], [E2|L2]) ->
foldr2(Fun, Acc1, L1, L2);
foldr2(_, Acc, [], []) -> Acc.
-%% first([A]) -> [A].
-%% last([A]) -> A.
-
-last([L]) -> L;
-last([_|T]) -> last(T).
-
-first([_]) -> [];
-first([H|T]) -> [H|first(T)].
-
%% This code implements the algorithm for an optimizing compiler for
%% pattern matching given "The Implementation of Functional
%% Programming Languages" by Simon Peyton Jones. The code is much