From cd1eaf0116190ab72f3a792b74be99eda5dd31eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 23 Jan 2015 13:12:44 +0100 Subject: 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. --- lib/compiler/test/core_fold_SUITE.erl | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'lib/compiler/test/core_fold_SUITE.erl') diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index ce1aea5de0..bca8afb1b0 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -242,6 +242,8 @@ do_guard_try_catch(K, V) -> false end. +-record(cover_opt_guard_try, {list=[]}). + coverage(Config) when is_list(Config) -> ?line {'EXIT',{{case_clause,{a,b,c}},_}} = (catch cover_will_match_list_type({a,b,c})), @@ -251,6 +253,9 @@ coverage(Config) when is_list(Config) -> ?line error = cover_will_match_lit_list(), {ok,[a]} = cover_is_safe_bool_expr(a), + ok = cover_opt_guard_try(#cover_opt_guard_try{list=[a]}), + error = cover_opt_guard_try(#cover_opt_guard_try{list=[]}), + %% Make sure that we don't attempt to make literals %% out of pids. (Putting a pid into a #c_literal{} %% would crash later compiler passes.) @@ -304,6 +309,14 @@ cover_is_safe_bool_expr(X) -> false end. +cover_opt_guard_try(Msg) -> + if + length(Msg#cover_opt_guard_try.list) =/= 1 -> + error; + true -> + ok + end. + bsm_an_inlined(<<_:8>>, _) -> ok; bsm_an_inlined(_, _) -> error. -- cgit v1.2.3 From 4babd738633953a09ce3314ed89d0933063b4ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 23 Jan 2015 13:12:09 +0100 Subject: Teach case_opt/3 to avoid unnecessary building Given this code: f(S) -> F0 = F1 = {S,S}, [F0,F1]. case_opt/3 would "optimize" it like this: f(S) -> F1 = {S,S}, F0 = {S,S}, [F0,F1]. Similarly, this code: g({a,_,_}=T) -> {b, [_,_] = [T,none], x}. would be rewritten to: g({a,Tmp1,Tmp2}=T) -> Tmp3 = {a,Tmp1,Tmp2}, {b, [Tmp3,none], x}. where the tuple is rebuilt instead of using the T variable. Rewrite case_opt/3 to be more careful while optimizing. --- lib/compiler/test/core_fold_SUITE.erl | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'lib/compiler/test/core_fold_SUITE.erl') diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index bca8afb1b0..b45874433c 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -23,7 +23,8 @@ t_element/1,setelement/1,t_length/1,append/1,t_apply/1,bifs/1, eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1, unused_multiple_values_error/1,unused_multiple_values/1, - multiple_aliases/1,redundant_boolean_clauses/1,mixed_matching_clauses/1]). + multiple_aliases/1,redundant_boolean_clauses/1, + mixed_matching_clauses/1,unnecessary_building/1]). -export([foo/0,foo/1,foo/2,foo/3]). @@ -40,7 +41,8 @@ groups() -> [t_element,setelement,t_length,append,t_apply,bifs, eq,nested_call_in_case,guard_try_catch,coverage, unused_multiple_values_error,unused_multiple_values, - multiple_aliases,redundant_boolean_clauses,mixed_matching_clauses]}]. + multiple_aliases,redundant_boolean_clauses, + mixed_matching_clauses,unnecessary_building]}]. init_per_suite(Config) -> @@ -403,4 +405,29 @@ mixed_matching_clauses(Config) when is_list(Config) -> end, ok. +unnecessary_building(Config) when is_list(Config) -> + Term1 = do_unnecessary_building_1(test_lib:id(a)), + [{a,a},{a,a}] = Term1, + 7 = erts_debug:size(Term1), + + %% The Input term should not be rebuilt (thus, it should + %% only be counted once in the size of the combined term). + Input = test_lib:id({a,b,c}), + Term2 = test_lib:id(do_unnecessary_building_2(Input)), + {b,[{a,b,c},none],x} = Term2, + 4+4+4+2 = erts_debug:size([Term2|Input]), + + ok. + +do_unnecessary_building_1(S) -> + %% The tuple must only be built once. + F0 = F1 = {S,S}, + [F0,F1]. + +do_unnecessary_building_2({a,_,_}=T) -> + %% The T term should not be rebuilt. + {b, + [_,_] = [T,none], + x}. + id(I) -> I. -- cgit v1.2.3