aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src/beam_bool.erl
AgeCommit message (Collapse)Author
2016-05-23beam_bool: Reject potentially unsafe optimizationBjörn Gustavsson
When calculating the sets of registers that must be killed or unused, registers set in a {protected,_,_,_} block were not considered. That could result in a crash in the assertion in beam_utils:live_opt_block/4.
2016-05-16Eliminate crash in beam_boolBjörn Gustavsson
beam_bool would crash when attempting to optimize BEAM code similar to this code: bif '=:=' Reg1 SomeValue => y(0) bif '=:=' Reg2 {atom,true} => x(2) bif '=:=' Reg3 {atom,true} => x(3) bif 'or' x(2) x(3) => x(2) is_eq_exact Fail x(2) {atom,true} The problem is that the first instruction that assigns a value to a Y register. beam_bool:ssa_assign/2 will not accept a Y register argument. We could change ssa_assign/2 to accept a Y register, but that would only cause the entire optimization to be rejected later because the Y register is alive in the code that follows. Therefore, a better solution is to modify extend_block/3 so that the instruction that assign to Y registers are not added to the block. That is, the optimizer will only operate on the following code: bif '=:=' Reg2 {atom,true} => x(2) bif '=:=' Reg3 {atom,true} => x(3) bif 'or' x(2) x(3) => x(2) is_eq_exact Fail x(2) {atom,true} Usually the optimization will succeed, rewriting the four instructions to a select_val instruction. Assembly code such as the above can be produced by code similar to: Y = Something == SomethingElse, case Y of Condition; OtherCondition -> . . . end, . . ., Y. Reported-by: http://bugs.erlang.org/browse/ERL-143 Reported-by: José Valim
2016-03-15update copyright-yearHenrik Nord
2016-01-08Merge branch 'maint'Björn Gustavsson
* maint: beam_bool: Fix unsafe optimization
2016-01-07beam_bool: Fix unsafe optimizationBjörn Gustavsson
beam_bool would make the following code unsafe (which would be reported by beam_validator): scotland(Echo) -> found(case Echo of Echo when true; Echo, Echo, Echo -> Echo; echo -> [] end, Echo = placed). found(_, _) -> million. Basically, beam_bool would see that the 'case' would always return the value of Echo. Thus: scotland(Echo) -> found(Echo, Echo = placed). The only problem is that beam_bool would also remove a 'move' instruction that would save Echo to the stack. Here is the assembly code for part of the function: {allocate_zero,1,1}. {move,{x,0},{y,0}}. %% Save Echo on stack. {bif,'=:=',{f,7},[{x,0},{atom,true}],{x,1}}. {bif,'=:=',{f,7},[{x,0},{atom,true}],{x,2}}. {bif,'=:=',{f,7},[{x,0},{atom,true}],{x,3}}. {bif,'and',{f,7},[{x,2},{x,3}],{x,2}}. {bif,'and',{f,7},[{x,1},{x,2}],{x,1}}. {jump,{f,8}}. {label,7}. {move,{atom,false},{x,1}}. {label,8}. {bif,'or',{f,6},[{atom,true},{x,1}],{x,1}}. {test,is_eq_exact,{f,6},[{x,1},{atom,true}]}. %% Jump never taken. {jump,{f,5}}. {label,6}. {test,is_eq_exact,{f,9},[{x,0},{atom,echo}]}. {move,nil,{x,0}}. {jump,{f,5}}. {label,9}. {test_heap,3,0}. {put_tuple,2,{x,0}}. {put,{atom,case_clause}}. {put,{y,0}}. {line,[{location,"t.erl",5}]}. {call_ext,1,{extfunc,erlang,error,1}}. {jump,{f,5}}. {label,5}. {test,is_eq_exact,{f,12},[{atom,placed},{y,0}]}. beam_bool would see that the is_eq_exact test at label 8 would always succeed. It could therefore remove most of the code before the jump to label 5. Unfortunately it also removed the essential move of Echo to the stack: {allocate_zero,1,1}. %% Instruction incorrectly removed: {move,{x,0},{y,0}}. {jump,{f,5}}. {label,5}. {test,is_eq_exact,{f,12},[{atom,placed},{y,0}]}. The root cause of the problem is that the 'move' instruction is included in the block of 'bif' instructions before label 8. Normally the 'move' instruction would not have been discarded, but because the left operand to the 'or' BIF is 'true', the entire block with 'bif' instructions are dropped. As far as I can see, there is no gain by including 'move' instructions in the first place. There is no way that better code will be produced. In fact, the entire optimization can be given up if 'move' instructions are found in the block. Thus we can fix this bug by never including any 'move' instructions in the block of 'bif' instructions. We can also remove all the code that deals with 'move' instructions within blocks. Reported-by: Thomas Arts
2015-08-21beam_validator: Don't allow x(1023) to be usedBjörn Gustavsson
In 45f469ca0890, the BEAM loader started to use x(1023) as scratch register for some instructions. Therefore we should not allow x(1023) to be used in code emitted by the compiler.
2015-06-18Change license text to APLv2Bruce Yinhe
2015-03-09beam_bool: Correct initialized_regs/2Björn Gustavsson
initialized_regs/2 did not handle allocating instructions; instead treating them as any other 'set' instruction. The consequences could be one or both of the following: Going past the allocating instruction (looking at more instructions) would mean that initialized_regs/2 could return registers that were not actually initialized. That could mean that MustBeKilled in ensure_opt_safe/6 could contain too few registers, and that the code that followed tried to use an uninitialized register. The beam_validator should have detected that problem. Not taking account the number of live registers in the allocating instruction could mean that some registers were not found to be initialized, which could mean that MustBeKilled would contain too many registers. That would mean a missed optimization.
2015-01-14beam_bool: Correct live calculation for GC BIFsBjörn Gustavsson
When optimizing boolean expressions, it is not always possible to find a number of live registers for a GC BIF that both preserves all source registers that will be tested and at the same time does not include registers that are not initialized. As currently implemented, we have incomplete information about the register calculated from the free variables. Some registers are marked as "reserved". Reserved registers means that we don't know anything about them; they may or may not be initialized. As a conservative correction (suitable for a maintenance release), we will abort the optimization if we find any reserved registers when calculating the number of live registers. We will not attempt to improve the information about the registers in this commit. By examining the coverage when running the existing compiler test suite we find that the optimization is aborted 15 times (before adding any new test cases). To put that in perspective, the optimization is successfully applied 4927 times, and aborted for other reasons 547 times. Reported-by: Ulf Norell Reported-by: Anthony Ramine
2015-01-14beam_bool: Correct indentation for try...catchBjörn Gustavsson
Old versions of the Erlang mode for Emacs used to indent try...catch strangely - the first clause following the 'catch' would be indented with one space less than the following clauses. If we are to use the new Erlang mode when we add more clauses, they would be indented with one space less than the preceding clauses. That would look silly.
2014-03-08Properly detect reused boolean values in beam_boolAnthony Ramine
The following code could crash the compiler: f(X = true) when X or true or X -> ok. Reported-by: Ulf Norell
2014-03-06Merge branch 'nox/compiler/beam_bool-not_boolean_expr'Björn Gustavsson
* nox/compiler/beam_bool-not_boolean_expr: Compile BIF calls and operator expressions to Core the same way Do not try to optimize non-boolean guards
2014-03-05Merge branch 'nox/compiler/beam_bool-bad-protected'Björn Gustavsson
* nox/compiler/beam_bool-bad-protected: Properly detect nonboolean protected expressions in beam_bool
2014-03-05Do not try to optimize non-boolean guardsAnthony Ramine
Expressions such as erlang:'or'(bar, true) can make beam_bool crash if it tries to optimize them, as this code is not quite really written by users, no attempt to rewrite them more efficiently should be done, for simplicity's sake. Reported-by: Ulf Norell
2014-03-04Properly detect nonboolean protected expressions in beam_boolAnthony Ramine
Silly code such as the following could make the compiler crash: f() when erlang:float(self()); true -> ok. Reported-by: Ulf Norell
2014-03-03Properly collect labels in put_map instructions in beam_boolAnthony Ramine
Reported-by: Ulf Norell
2013-08-15Fix compiler crash for 'B and B' guardBjörn Gustavsson
2013-01-25Update copyright yearsBjörn-Egil Dahlberg
2012-10-09beam_bool: Recognize more safe optimizationsBjörn Gustavsson
The optimizer of boolean expressions can often reject optimizations that it does not recognize as safe. For instance, if a boolean expression was preceded by 'move' instructions that saved x registers into y registers, it would almost certainly reject the optimization because it required the y register not be used in the code that follows. Fix this problem by allowing identical 'move' instructions that assing to y registers at the beginning of the old and the optimized code. While at it, correct the spelling of "preceding".
2010-05-21Merge branch 'bg/compiler-cover-and-clean' into devErlang/OTP
* bg/compiler-cover-and-clean: v3_life: Remove clause that cannot match in match_fail/3 v3_life tests: Cover exception handling code in v3_life:function/1 beam_type: Remove redundant clause v3_core tests: Cover make_bool_switch_guard/5 v3_core tests: Cover handling of pattern aliases v3_core: Remove a clause in is_simple/1 that cannot match v3_core: Remove unused support for generating compilation errors Remove stray support for the put_literal/2 instruction Remove stray support for the bs_bits_to_bytes2/2 instruction Remove the bs_bits_to_bytes/3 instruction Cover handling of 'math' BIFs beam_bool: Remove a clause in live_regs/1 that cannot match beam_bool: Cover handling of bs_context_to_binary in initialized_regs/2 beam_bool: Remove a clause in initialized_regs/2 that cannot match beam_block: Remove a clause that will never be executed erts: Stop supporting non-literal empty tuples compile: Remove code that is only executed on Solaris Do not cover-analyze core_scan core_SUITE_data: Don't ignore *.core files in this directory OTP-8636 bg/compiler-cover-and-clean
2010-05-20beam_bool: Remove a clause in live_regs/1 that cannot matchBjörn Gustavsson
live_regs/1 folds over a list of tuples, so a clause matching an element being an empty list can never match. If the list for some unfathomable reason would contain an empty list, there will be an internal compiler error and no *.beam file will be created. Thus this change is safe.
2010-05-20beam_bool: Remove a clause in initialized_regs/2 that cannot matchBjörn Gustavsson
When scanning a reversed instruction sequence for a function, it is impossible to reach the end of the list, because each function must have a fun_info/4 instruction followed by a label/1 instruction at the beginning, and there is a clause that will handle those instructions. If for some unfathomable reason the end of the list would be reached, with this change there will be an internal compiler error and no *.beam file will be created. Thus this change is safe.
2009-12-11beam_bool: Fix generation of code that does not validateBjörn Gustavsson
The following code (by Simon Cornish) bad(XDo1, XDo2, Do3) -> Do1 = (XDo1 =/= []), Do2 = (XDo2 =/= []), CH1 = if Do1 == true; Do1 == false,Do2==false,Do3 == blah -> ch1; true -> no end, CH2 = if Do1 == true; Do1 == false,Do2==false,Do3 == xx -> ch2; true -> no end, {CH1,CH2}. is optimized by beam_bool even though the optimization is not safe. The trouble is that an assignment to {y,0} no longer occurs on all paths leading to its use. The bug is in dst_regs/2 which is supposed to return a set of all registers assigned in a code block, but it ignores registers assigned in 'move' instructions. Fix the bug by taking 'move' instructions into account. This change is safe since it can only cause more registers to be added to the MustBeKilled and MustBeUnused sets in ensure_opt_safe/6, which means that it can only cause the optimization to be turned off for code that used to be optimized.
2009-12-10Fix crash in beam_boolBjörn Gustavsson
The following code crashes beam_bool: bad(XDo1, XDo2, Do3) -> Do1 = (XDo1 =/= []), Do2 = (XDo2 =/= []), if Do1 =:= true; Do1 =:= false, Do2 =:= false, Do3 =:= delete -> no end. (Reported by Simon Cornish; minimized by Kostis Sagonas.) For the moment fix the bug in the simplest and safest way possible (basically, instead of crashing just don't do the optimization). In a future major release (e.g. R14), the following improvements could be considered: * In beam_bool, it should be possible to move the Do1 and Do2 expressions to the pre-block and still optimize the expression in the 'if' statement. * In sys_core_fold, it should be possible to eliminate the try/catch around the guard expression in the 'if', because none of the guard tests can actually fail.
2009-11-20The R13B03 release.OTP_R13B03Erlang/OTP