aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src/sys_core_fold.erl
AgeCommit message (Collapse)Author
2015-04-29sys_core_fold: Suppress warnings betterBjörn Gustavsson
86fbd6d76d strengthened type optimization in lets. As a result of the stronger optimizations, special care had to be taken to suppress false warnings. It turns out that false warnings can still slip through. Slapping on a 'compiler_generated' annotation at the top-level of a complex term such as #c_tuple{} may not suppress all warnings. We will need to go deeper into the term to eliminate all warnings.
2015-04-15Raise more descriptive error messages for failed map operationsBjörn Gustavsson
According to EEP-43 for maps, a 'badmap' exception should be generated when an attempt is made to update non-map term such as: <<>>#{a=>42} That was not implemented in the OTP 17. José Valim suggested that we should take the opportunity to improve the errors coming from map operations: http://erlang.org/pipermail/erlang-questions/2015-February/083588.html This commit implement better errors from map operations similar to his suggestion. When a map update operation (Map#{...}) or a BIF that expects a map is given a non-map term, the exception will be: {badmap,Term} This kind of exception is similar to the {badfun,Term} exception from operations that expect a fun. When a map operation requires a key that is not present in a map, the following exception will be raised: {badkey,Key} José Valim suggested that the exception should be {badkey,Key,Map}. We decided not to do that because the map could potentially be huge and cause problems if the error propagated through links to other processes. For BIFs, it could be argued that the exceptions could be simply 'badmap' and 'badkey', because the bad map and bad key can be found in the argument list for the BIF in the stack backtrace. However, for the map update operation (Map#{...}), the bad map or bad key will not be included in the stack backtrace, so that information must be included in the exception reason itself. For consistency, the BIFs should raise the same exceptions as update operation. If more than one key is missing, it is undefined which of keys that will be reported in the {badkey,Key} exception.
2015-03-09sys_core_fold: Generalize case optimizationBjörn Gustavsson
For a long time, there has been an optimization for: {V1,V2,...} = case Expr of Pat -> ... {Val1,Val2,...}; ... end that avoids building the tuples. The construct looks like this in Core Erlang: let <V> = case X of Pattern -> {Y,Z} end in case V of {A,B} -> A+B end The current optimization will try to replace the second 'case' with a 'let': let <A,B> = case X of Pattern -> <Y,Z> end in A+B Simple variations of the construct would prevent the optimizations; for example this one: let <V> = case X of Pattern -> {'ok',Val} end in case V of {ok,Val} -> Val end The problem is that the optimization tries to do too much. By making the optimization do less and have it depend on other optimizations to finish the job, it will become more powerful. Thus we can rewrite the code like this: let <V1,V2> = case X of Pattern -> <'ok',Val> end in let <V> = {V1,V2} in case V of {ok,Val} -> Val end Note that the second case is unchanged. The other optimizations in the sys_core_fold module will optimize the second 'case' and eliminate the building of the tuple.
2015-03-09sys_core_fold: Improve optimization of 'not'Björn Gustavsson
Optimize away 'not' in sys_core_fold instead of in beam_block and beam_dead, as we can do a better job in sys_core_fold. I modified the test suite temporarily to never turn off Core Erlang modifications and looked at the coverage. With the new optimizations active in sys_core_fold, the code in beam_block and beam_dead did not find a single 'not' that it could optimize. That proves that the new optimization is at least as good as the old one. Manually, I could also verify that the new optimization would optimize some variations of 'not' that the old one would not handle.
2015-03-09sys_core_fold: Suppress compiler warnings when evaluating element/2Björn Gustavsson
More aggressive optimizations that we plan to introduce could cause spurious compiler warnings.
2015-03-09Clean up evaluation of setelement/3Björn Gustavsson
The 'try' ... 'catch' is problematic. Firstly, if no optimization is possible, an exception will always be thrown. Secondly, bugs in the code will go unnoticed.
2015-03-09Replace '==' with '=:=' when both operands are integersBjörn Gustavsson
'=:=' is a cheaper operation than '==', so we should always use '=:=' if the result will be the same as if '==' were used.
2015-03-09Update type information based on BIFs that returns integersBjörn Gustavsson
2015-03-09sys_core_fold: Strengthen type optimization in letsBjörn Gustavsson
Make sure that we take extract all possible type information when optimizing a 'let' construct. Since the stronger optimization may generate false warnings, we also need to take special care to suppress false warnings.
2015-03-09v3_core: Add is_map tests before map instructionsBjörn Gustavsson
If we have a sequence of put_map_* instructions operating on the same map, it will be more efficient if we can have one is_map/2 instruction before put_map_* instructions, so that each put_map_* does not need to test whether the argument is a map.
2015-02-20sys_core_fold: Fix non-tail-recursive list comprehensionsBjörn Gustavsson
649d6e73 simplified opt_simple_let_2/6 a little bit too much, so that some list comprehensions in effect context were not properly tail-recursive.
2015-02-12sys_core_fold: Simplify opt_simple_let_2/6Björn Gustavsson
In cd1eaf0116190, opt_simple_let_2/6 was updated to do the same optimizations in 'value' and 'effect' context. Coalesce the clauses for 'value' and 'effect' context to one to make it clear that they do the same thing.
2015-02-12Break out inlining of 'lists' functions to a new moduleBjörn Gustavsson
The code for inlining high-order functions from the lists module is quite annoying when you try to navigate the sys_core_fold module. Break out the code into its own module.
2015-02-12sys_core_fold: Add is_int_type/2 and is_tuple_type/2Björn Gustavsson
Those functions allow us to clean up some more code.
2015-02-12sys_core_fold: Refactor type information accessBjörn Gustavsson
Introduce access functions to hide the low-level details of how type information is implemented.
2015-02-12Eliminate use of core_lib:literal_value/1Björn Gustavsson
Essentially, core_lib:literal_value/1 became useless when literals were introduced in R12. Since we always create #c_literal{} records whenever possible, literal_value/1 would *only* succeed when it was passed a #c_literal{} argument.
2015-02-12Eliminate all uses of core_lib:get_anno/1 and core_lib:set_anno/2Björn Gustavsson
We are about to deprecate core_lib:get_anno/1 and core_lib:set_anno/2, so we should stop using them in the compiler.
2015-02-11sys_core_fold: Rename add_scope/2 to fit in the sub_* familyBjörn Gustavsson
Rename add_scope/2 to sub_add_scope/2 to be similar in naming as the other functions that operates on #sub{} (in particular, sub_subst_scope/1). Also, move the definition to be near to the other sub_* functions.
2015-02-05Merge branch 'bjorn/compiler/dup-bug-fix/OTP-12453'Björn Gustavsson
* bjorn/compiler/dup-bug-fix/OTP-12453: Teach case_opt/3 to avoid unnecessary building sys_core_fold: Optimize let statements more aggressively Suppress warnings for expressions that are assigned to '_' trace_bif_SUITE: Ensure that a call to time/0 is not removed
2015-02-05Merge branch 'maint'Björn Gustavsson
* maint: Update primary bootstrap Correct unsafe optimization of '==' and '/=' Conflicts: bootstrap/lib/compiler/ebin/sys_core_fold.beam
2015-02-04Correct unsafe optimization of '==' and '/='Björn Gustavsson
Since '=:=' is cheaper than '==', the compiler tries to replace '==' with '=:=' if the result of comparison will be the same. As an example: V == {a,b} can be rewritten to: V =:= {a,b} since the literal on the right side contains no numeric values that '==' would compare differently to '=:='. With the introduction of maps, we will need to take them into account. Since the comparison of maps is planned to change in 18.0, we will be very conservative and only do the optimization if both keys and values are non-numeric.
2015-02-03Teach case_opt/3 to avoid unnecessary buildingBjörn Gustavsson
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.
2015-02-03sys_core_fold: Optimize let statements more aggressivelyBjörn Gustavsson
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.
2015-02-03Suppress warnings for expressions that are assigned to '_'Björn Gustavsson
In c34ad2d5, the compiler learned to silence some warnings for expressions that were explicitly assigned to the '_' variable, as in this example: _ = list_to_integer(S), ok That commit intentionally only made it possible to silence warnings for BIFs that could cause an exception. Warnings would still be produced for: _ = date(), ok because date/0 can never fail and thus making the call completely useless. The reasoning was that such warnings can always be eliminated by eliminating the offending code. While that is true, there is the question about rules and their consistency. It is surprising that '_' can be used to silence some warnings, but has no effect on other warnings. Therefore, we will teach the compiler to silence warnings for the following constructs: * Calls to safe BIFs such as date/0 * Expressions that will cause an exception such as 'X/0' * Terms that are built but not used, such as '{x,X}'
2015-02-03Merge branch 'maint'Björn Gustavsson
* maint: Update primary bootstrap Be more careful about map patterns when evalutating element/2 Do not convert map patterns to map expressions Conflicts: bootstrap/lib/compiler/ebin/sys_core_fold.beam lib/compiler/test/match_SUITE.erl
2015-02-03Be more careful about map patterns when evalutating element/2Björn Gustavsson
We must not convert map patterns to map expressions.
2015-02-03Do not convert map patterns to map expressionsBjörn Gustavsson
In code such as: case {a,Map} of {a,#{}}=T -> T end we must NOT rewrite a map pattern to a map expression like this: case Map of #{} -> {a,#{}} end because the pattern '#{}' will match any map, but the expression '#{}' will construct an empty map.
2015-01-29Merge branch 'bjorn/compiler/map-fixes'Björn Gustavsson
* bjorn/compiler/map-fixes: cerl: Remove a clause in fold_map_pairs/3 that will never be reached Move grouping of map constructions from v3_core to v3_kernel core_pp: Correct printing of map literals Strengthen and modernize compile_SUITE core_parse: Always fold literal conses cerl: Make sure that we preserve the invariants for maps cerl_clauses: Fix indentation sys_core_fold: Strengthen optimization of letrecs in effect context Fix handling of binary map keys in comprehensions core_lib: Teach is_var_used/2 to handle keys in map patterns warnings_SUITE: Eliminate compiler warning for a shadowed variable lc_SUITE: Add shadow/1 Modernize lc_SUITE
2015-01-28sys_core_fold: Remove uncovered clauses matching #c_map{}Björn Gustavsson
sys_core_fold:eval_element/3 attempts to evaluate calls to element/2 at compile time or to warn when the call will obviously fail. For example: element(1, [a]) will obviously fail and eval_element/3 will produce a warning. eval_element/3 uses the helper functions is_not_integer/1 and is_not_tuple/1 to test whether the arguments are known to be incorrect. The clauses that attempt to match #c_map{} in those helper function will never be executed, because #c_map{} will never occur directly in an argument for a function call. For example, code such as: element(1, #{a=>Val}) will be translated to: let <NewVar> = #{a=>Val} in element(1, NewVar) since maps are not considered safe (some map operations may cause an exception at run time).
2015-01-27core_parse: Always fold literal consesBjörn Gustavsson
v3_core is careful to always create literals whenever possible. Correct core_parse so it, too, always creates literals out of literal conses. With that correction, we can remove the workaround in sys_core_fold (introduced in 26a5dea3cb5e101) that handles non-literal flags in a binary.
2015-01-26sys_core_fold: Strengthen optimization of letrecs in effect contextBjörn Gustavsson
We used to evaluate the body of a 'letrec' in value context, even if the 'letrec' was being evaluated in effect context. In most cases, the context does not matter because the body is usually just an 'apply' which will never be optimized away. However, in the case of incorrect code described in the previous commit, it does matter. We can find such bad code by evaluating the body in effect context. For example, if we have the following incorrect code: letrec f/1 = fun(A) -> ... <use of Var> ... in let Var = <<2:301>> in apply(Arg) If the letrec is evaluated in effect context, the code will be reduced to: letrec f/1 = fun(A) -> ... <use of Var> ... in seq Var = <<2:301>> do apply(Arg) Now Var will be unbound and a later compiler pass will crash to ensure that the bad Core Erlang code is noticed. Also add a test case to ensure that the compiler crashes if the bug fixed in the previous commit re-surfaces.
2015-01-14sys_core_fold: Correct optimization of 'case'Björn Gustavsson
The optimization of a 'case' statement could lead to incorrect code that would cause an exception at run-time. Here is an example to show how the optimization went wrong. Start with the following code: f({r,#{key:=Val},X}=S) -> case S of {r,_,_} -> setelement(3, Val, S) end. (The record operations have already been translated to the corresponding tuple operations.) The first step in case_opt/3 is to substitute S to obtain: f({r,#{key:=Val},X}=S) -> case {r,#{key:=Val},X} of {r,_,_} -> setelement(3, Val, S) end. After that substitution the 'case' can be simplified to: f({r,#{key:=Val},_}=S) -> case #{key:=Val} of NewVar -> setelement(3, Val, S) end. That is the result from case_opt/3. Now eval_case/2 notices that since there is only one clause left in the 'case', the 'case' can eliminated: f({r,#{key:=Val},_}=S) -> NewVar = #{key:=Val}, setelement(3, Val, S). Since the map construction may have a side effect, it was not eliminated, but assigned to a variable that is never used. The problem is that '#{key:=Val}' is fine as a pattern, but in a construction of a new map, the '=>' operator must be used. So the map construction will fail, generating an exception. As a conservative correction for a maintenance release, we will abort the 'case' optimization if the substitution into the 'case' expression is anything but data items (tuples, conses, or literals) or variables. Reported-by: Dmitry Aleksandrov
2014-09-01sys_core_fold: Eliminate name capture bugBjörn Gustavsson
The scope is supposed to contain all variables that are currently live. We need this information for certain optimizations to avoid capturing a name (a name that is in the scope must be renamed; for an example, see move_let_into_expr/2 or any function that calls sub_subst_scope/1). We also use the scope to optimize sub_del_var/2 and sub_is_val/2. When optimizing case expressions, the scope could be reset to an empty list (because sub_new/0 was called instead of sub_new/1). That could cause name capture if inlining was turned on. As simple way to force this bug is to uncomment the "-define(DEBUG, 1)." near the beginning of the file. Without this correction, most files in the test suite fail to compile.
2014-04-03compiler: Fix compiling map keys in patterns from coreBjörn-Egil Dahlberg
2014-03-25Correctly handle non-matching patterns against literal valuesAnthony Ramine
The pass sys_core_fold did not correctly handle non-matching patterns in code such as: 0 = case <<>> of <<>> -> 0; a -> 1 end. Function case_opt_lit/3 is rewritten in two passes to first remove any non-matching clause and only then potentially remove the related patterns in each clause. Reported-by: Ulf Norell
2014-03-17compiler: Change #c_map{var} to #c_map{arg}Björn-Egil Dahlberg
Not only variables are allowed as arguments, the name should reflect that. Change cerl Map argument interface * cerl:map_arg/1 is more suitable then cerl:map_val/1 in this case.
2014-03-17compiler: Constant fold Maps that are safeBjörn-Egil Dahlberg
For updates of Map literals which may cause an error will be determined in runtime, i.e. instructions are emitted for those updates. The changes in cerl now requires compiler-5.0 to compile because of is_map/1 guard.
2014-03-17compiler: Validate Map srcBjörn-Egil Dahlberg
Reject all expressions that are known to fail. Emit 'badarg' for those expressions. Ex. []#{ a => 1} Is not a valid map update expression.
2014-03-10Properly handle redundant boolean clauses in sys_core_foldAnthony Ramine
Boolean case expressions with redundant clauses could make the compiler crash: case X == 0 of false -> no; false -> no; true -> yes end. Reported-by: Ulf Norell
2014-03-05Merge branch 'nox/compiler/sys_core_fold-erlang-is_function-2'Björn Gustavsson
* nox/compiler/sys_core_fold-erlang-is_function-2: Do not mark all calls to erlang:is_function/2 as safe
2014-03-03Do not mark all calls to erlang:is_function/2 as safeAnthony Ramine
Calls to erlang:is_function/2 where the second is not a literal nonnegative integer can crash at runtime and thus can't be marked as safe.
2014-03-02Do not mark all calls to erlang:is_record/3 as safeAnthony Ramine
Calls to erlang:is_record/3 where the second and third arguments are not respectively a literal atom and a literal integer can't be transformed to guards and thus are not safe. Reported-by: Ulf Norell
2014-02-21Merge branch 'egil/compiler/maps-get_map_elements'Björn-Egil Dahlberg
* egil/compiler/maps-get_map_elements: compiler: Strengthen Maps compile tests compiler: Remove dead warning erts: Fix erts_debug:disassemble/1 compiler: Transform list of Args to exact literal type compiler: Test Maps aliasing compiler: Use aliasing in map pair patterns compiler: Check literal order in beam_validator erts: Introduce new instructions for combined key fetches compiler: Change map instructions for fetching values
2014-02-20compiler: Remove dead warningBjörn-Egil Dahlberg
2014-02-13Merge branch 'nox/compiler/v3_core-case-arg-opt'Björn Gustavsson
* nox/compiler/v3_core-case-arg-opt: Optimise case arguments in sys_core_fold Run sys_core_fold twice if any inliner is used
2014-02-11Teach sys_core_fold:eval_case/2 to cope with handwritten Core ErlangBjörn Gustavsson
Starting in e12b7d5331c58b41db06cadfa4af75b78b62a2b1, sys_core_fold:eval_case/2 will crash on handwritten but legal Core Erlang programs such as: case let <Var> = Arg in {'x',Var} of {x,X} -> X end The problem is that the only clause *is* guaranteed to match, but cerl_clauses:match_list/2 does not understand that; all it can say is that the clause *may* match. In those circumstances, we will need to keep the case. Also make sure that we keep the case if the guard is something else than 'true'. That is not strictly necessary, because in a legal Core Erlang program the guard in the last clause in a case must always evaluate to 'true', so removing the guard test would still leave the program correct. Keeping the guard, however, will make it somewhat easier to debug an incorrect Core Erlang program. (The unsafe_case test case has guard test in the only clause in a case, so we don't need to write a new test case to test that.) Reported-by: Anthony Ramine
2014-02-11sys_core_fold: Remove a redundant word in a commentBjörn Gustavsson
2014-02-11Optimise case arguments in sys_core_foldAnthony Ramine
If the argument of a case expression is a let, a seq or a case with two clauses where the second one is a failing clause; it can be moved outside the case and further optimisations can be performed. module 'foo' ['t'/4] attributes [] 't'/4 = fun (_cor14,Sub0,_cor15,_cor16) -> let Ssa = call 'erlang':'get' ('foo') in case let Ssa = {'ssa',_cor14,Sub0,_cor15,_cor16} in let _rec11 = call 'erlang':'+' (_cor14, 1) in let _cor4 = call 'erlang':'setelement' (2, Ssa, _rec11) in {{'tmp',_cor14},_cor4} of {NewReg,Foo} when 'true' -> {NewReg,Foo,Ssa} _cor20 when 'true' -> primop 'match_failure' ({'case_clause',_cor20}) end end ==> module 'foo' ['t'/4] attributes [] 't'/4 = fun (_cor14,Sub0,_cor15,_cor16) -> let Ssa = call 'erlang':'get' ('foo') in let _fol0 = {'ssa',_cor14,Sub0,_cor15,_cor16} in let _rec11 = call 'erlang':'+' (_cor14, 1) in let _cor4 = call 'erlang':'setelement' (2, _fol0, _rec11) in let NewReg = {'tmp',_cor14} in {NewReg,_cor4,Ssa} end
2014-02-06Merge branch 'bjorn/compiler/optimizations/OTP-11584'Björn Gustavsson
* 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
2014-02-05Merge branch 'bjorn/eep37/OTP-11537'Björn Gustavsson
* bjorn/eep37/OTP-11537: Issue a warning when a named fun is constructed but not used