aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src/sys_core_fold.erl
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2015-01-23 13:12:44 +0100
committerBjörn Gustavsson <[email protected]>2015-02-03 08:40:49 +0100
commitcd1eaf0116190ab72f3a792b74be99eda5dd31eb (patch)
tree0d036a4c6d102d1bd5859c894dd163b6a0a8f0ad /lib/compiler/src/sys_core_fold.erl
parent8c3baeb1275c2e6a316d3b5203e0598906785cdb (diff)
downloadotp-cd1eaf0116190ab72f3a792b74be99eda5dd31eb.tar.gz
otp-cd1eaf0116190ab72f3a792b74be99eda5dd31eb.tar.bz2
otp-cd1eaf0116190ab72f3a792b74be99eda5dd31eb.zip
sys_core_fold: Optimize let statements more aggressively
I originally decided that in 'value' context, rewriting a let statement where the variables were not in the body to a sequence was not worth it, because the variables would be unused in only one let in a thousand lets (roughly). I have reconsidered. The main reason is that if we do the rewrite, core_lib:is_var_used/2 will be used much more frequently, which will help us to find bugs in it sooner. Another reason is that the way letify/2 is currently implemented with its own calls to core_lib:is_var_used/2 is only safe as long as all the bindings are independent of each other. We could make letify/2 smarter, but if we introduce this new optimization there is no need. Measuring compilation speed, I have not seen any significant slowdown. It seems that although core_lib:is_var_used/2 is called much more frequently, most calls will be fast because is_var_used/2 will quickly find a use of the variable. Also add a test case to cover a line opt_guard_try/1 that was no longer covered.
Diffstat (limited to 'lib/compiler/src/sys_core_fold.erl')
-rw-r--r--lib/compiler/src/sys_core_fold.erl27
1 files changed, 14 insertions, 13 deletions
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index eeb3535936..72509947d6 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -2246,18 +2246,11 @@ make_var_name() ->
list_to_atom("fol"++integer_to_list(N)).
letify(Bs, Body) ->
+ Ann = cerl:get_ann(Body),
foldr(fun({V,Val}, B) ->
- letify(V, Val, B)
+ cerl:ann_c_let(Ann, [V], Val, B)
end, Body, Bs).
-letify(#c_var{name=Vname}=Var, Val, Body) ->
- case core_lib:is_var_used(Vname, Body) of
- true ->
- A = element(2, Body),
- #c_let{anno=A,vars=[Var],arg=Val,body=Body};
- false -> Body
- end.
-
%% opt_case_in_let(LetExpr) -> LetExpr'
opt_case_in_let(#c_let{vars=Vs,arg=Arg,body=B}=Let, Sub) ->
@@ -2622,7 +2615,7 @@ opt_simple_let_2(Let0, Vs0, Arg0, Body0, effect, Sub) ->
opt_case_in_let_arg(opt_case_in_let(Let, Sub), effect, Sub)
end
end;
-opt_simple_let_2(Let, Vs0, Arg0, Body, value, Sub) ->
+opt_simple_let_2(Let0, Vs0, Arg0, Body, value, Sub) ->
case {Vs0,Arg0,Body} of
{[#c_var{name=N1}],Arg,#c_var{name=N2}} ->
case N1 =:= N2 of
@@ -2641,9 +2634,17 @@ opt_simple_let_2(Let, Vs0, Arg0, Body, value, Sub) ->
%% can be evaluated in effect context to simplify it.
expr(#c_seq{arg=Arg,body=Body}, value, sub_new_preserve_types(Sub));
{Vs,Arg,Body} ->
- opt_case_in_let_arg(
- opt_case_in_let(Let#c_let{vars=Vs,arg=Arg,body=Body}, Sub),
- value, Sub)
+ %% If none of the variables are used in the body, we can rewrite the
+ %% let to a sequence:
+ %% let <Var> = Arg in BodyWithoutVar ==> seq Arg BodyWithoutVar
+ case is_any_var_used(Vs, Body) of
+ false ->
+ expr(#c_seq{arg=Arg,body=Body}, value,
+ sub_new_preserve_types(Sub));
+ true ->
+ Let = Let0#c_let{vars=Vs,arg=Arg,body=Body},
+ opt_case_in_let_arg(opt_case_in_let(Let, Sub), value, Sub)
+ end
end.
move_case_into_arg(#c_case{arg=#c_let{vars=OuterVars0,arg=OuterArg,