aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2014-02-06 10:08:01 +0100
committerBjörn Gustavsson <[email protected]>2014-02-06 10:08:01 +0100
commit3efa33db1e59b400babf672b07763c4a2467798a (patch)
tree6206771cfb14ab3a1072b3a802e464129ff9fa5d /lib/compiler/src
parentdc85bc5a8ea9e3c6409e960aabb41ebb6fa47c1b (diff)
parent5d1471fae699fed9318ea6cad939156c2775d8be (diff)
downloadotp-3efa33db1e59b400babf672b07763c4a2467798a.tar.gz
otp-3efa33db1e59b400babf672b07763c4a2467798a.tar.bz2
otp-3efa33db1e59b400babf672b07763c4a2467798a.zip
Merge branch 'bjorn/compiler/optimizations/OTP-11584'
* bjorn/compiler/optimizations/OTP-11584: sys_core_fold: Prevent case expressions from being evaluated twice sys_core_fold_SUITE: For cleanliness, move id/1 to the end
Diffstat (limited to 'lib/compiler/src')
-rw-r--r--lib/compiler/src/sys_core_fold.erl25
1 files changed, 23 insertions, 2 deletions
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]}.