Age | Commit message (Collapse) | Author |
|
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).
|
|
It was a workaround for a bug that has been fixed.
|
|
* egil/fix-maps-compiler-coverage/OTP-12425:
compiler: Rename util function to adhere to name policy
compiler: Remove get_map_elements label check in blocks
compiler: Remove unnecassary guard for get_map_elements
compiler: Remove dead code in beam_flatten
compiler: Increase Maps code coverage
|
|
* bjorn/compiler/coverage:
map_SUITE: Ensure recompilation when running cover
Add beam_utils_SUITE to cover more lines in beam_utils
beam_utils: Remove unreachable clauses in live_opt/4
receive_SUITE: Cover handling of recv_mark & recv_set in beam_utils
beam_validator_SUITE: Mend the compiler_bug/1 test case
beam_clean: Remove handling of forgotten instructions
compile_SUITE: Test the 'dialyzer' option
|
|
* maint:
Update primary bootstrap
core_lib: Handle patterns in map values
|
|
beam_utils:live_opt() is only invoked on code that has been
blockified by beam_block. Therefore the allocate/3 and
allocate_heap/4 instructions only occur in their transformed
form inside a block.
While we are it, correct a comment. 'asm' has been replaced
by 'from_asm'.
|
|
core_lib:is_var_used/2 would not consider a variable used in the
value of a map pattern such as:
case Map of
#{key := <<42:N>>} -> ok
end
Here the variable 'N' would not be considered used.
It was assumed that there was no need to check map patterns at
all, since maps currently don't support variables in keys.
|
|
* oliv3/math_log2/OTP-12411:
Add math:log2/1
|
|
Commits b44f86b7 and 97953704 introduced translations of instructions
in beam_a and beam_z, but forgot to remove the handling of them in
beam_clean.
|
|
* maint:
Update primary bootstrap
beam_bool: Correct live calculation for GC BIFs
beam_bool: Correct indentation for try...catch
sys_core_fold: Correct optimization of 'case'
Conflicts:
bootstrap/bin/start.boot
bootstrap/bin/start_clean.boot
bootstrap/lib/compiler/ebin/beam_asm.beam
bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
|
|
* bjorn/compiler/map-in-record-bug/OTP-12402:
sys_core_fold: Correct optimization of 'case'
|
|
|
|
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
|
|
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.
|
|
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
|
|
* beam_utils:joineven/1 -> beam_utils:join_even/1
* beam_utils:split_even/1 -> beam_utils:split_even/1
|
|
The get_map_elements instruction has been removed from all blocks by the
mandatory beam_split pass and thus only needs handling by the outer loop.
|
|
|
|
No need to check for fail label zero for get_map_elements in beam_split.
get_map_elements is always used in pattern matching and never in a body.
|
|
The normalization in beam_flatten can never be reached for get_map_elements
since it is always handled in the mandatory beam_split pass.
|
|
|
|
While we are, clean up the comments and rearrange the code for
clarity. Also add a test to cover the last uncovered line in
beam_dead.erl.
|
|
Better optimizations with less code.
|
|
The BEAM compiler translates code such as:
is_hex_digit(D) when $0 =< D, D =< $9 -> true;
is_hex_digit(D) when $a =< D, D =< $z -> true;
is_hex_digit(D) when $A =< D, D =< $Z -> true;
is_hex_digit(_) -> false.
to something like this:
L0: test is_ge L1 {x,0} 48
test is_ge L1 57 {x,0}
move true {x,0}
return.
L1: test is_ge L2 {x,0} 97
test is_ge L2 122 {x,0}
move true {x,0}
return
L2: test is_ge L3 {x,0} 65
test is_ge L3 90 {x,0}
move true {x,0}
return
L3: move false {x,0}
return
We can see that tests will be repeated even if they cannot possibly
succeed. For instance, if we pass in {x,0} equal to 32, the first
test that {x,0} is greater than or equal to 48 at L0 will fail.
The control will transfer to L1, where it will be tested whether
{x,0} is greater than 97. That test will fail and control
will pass to L2, where again the test will fail.
The compiler can do better by short-circuiting repeating tests:
L0: test is_ge L3 {x,0} 48
test is_ge L1 57 {x,0}
move true {x,0}
return.
L1: test is_ge L2 {x,0} 97
test is_ge L3 122 {x,0}
move true {x,0}
return
L2: test is_ge L3 {x,0} 65
test is_ge L3 90 {x,0}
move true {x,0}
return
L3: move false {x,0}
return
|
|
This fixes a regression introduced in commit 805f9c89fc01220bc1bb0f27e1b68fd4eca688ba
The problem occured with map keys compiled with dialyzer option turned on.
In OTP 17, map keys needs to be literals.
|
|
* maint:
Fix miscompilation when module contains multiple named funs
Fix locations of shadowing warnings in ms_transform
|
|
Commit 78ce8917d started to use get_anno/1 to extract the line
annotation from filter qualifiers in comprehensions, but this does not
respect the spec of this function and resuls in a dialyzer warning.
To make the code more type-friendly, introduce a get_qual_anno/1
function.
Kostis Sagonas suggested that the function should be implemented
similar to this to also ensure that the qualifiers are of the
appropriate form:
get_qual_anno({call,Line,_,_}) -> Line;
get_qual_anno({op,Line,_,_,_}) -> Line;
.
.
.
get_qual_anno({var,Line,_}) -> Line.
The problem is that it is difficult to know exacly which forms
that may occur and the function will need to be updated if new
abstract forms are added. Thus this implementation would complicate
maintanance without any real payoff.
Reported-by: Kostis Sagonas
|
|
A module containing two named funs bearing the same name and arity could be
miscompiled.
Reported-by: Sam Chapin
|
|
* egil/map-type-opt/OTP-12253:
compiler: Type is_nonempty_list optimization
compiler: Type map optimization
|
|
* tuncer/compiler/finalize-asm-deprecation/OTP-12100:
compiler: finalize 18.x 'asm' deprecation
|
|
|
|
|
|
* egil/maps/variable-keys/OTP-12218: (22 commits)
compiler: Update test for Maps aliasing
compiler: Properly support Map aliasing
compiler: Refactor Map pairs aliasing
compiler: Fix harmless need_heap error for Maps
stdlib: Update Map tests
stdlib: Use environment bindings for Maps keys in erl_eval matching
debugger: Update Map tests
compiler: Update Map tests
compiler: Fix v3_core Maps pair chains
compiler: Use expressions in core patterns
compiler: Use variables in Map cerl inliner
compiler: Reintroduce binary limit for Map keys
compiler: Shameless v3_core hack for variables
compiler: Use variables in Map beam assmebler
compiler: Use variables in Map kernel pass
compiler: Use variables in Map core pass
compiler: Normalize unary ops on Maps key literals
stdlib: Update Map tests
stdlib: erl_lint Map key variables
compiler: Maps are always patterns never values in matching
...
|
|
Matching of type:
#{K := V1} = #{K := V2} = M,
Will alias (coalesce) to
#{K := V1 = V2} = M.
|
|
|
|
Need heap for maps is zero and fall through is also zero.
|
|
|
|
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.
|
|
Check for literals instead of variables when constructing chains.
|
|
Two patterns, binary_segment size and map_pair key, are expressions
even in matching. If only bound variables are used we are fine but
some expressions which appears as literals needs to be lifted.
Currently only Map key binaries will use this.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Unary ops are normalized before core transformation, i.e. handle
negative integers as map keys.
Strictly speaking, map keys are expressions but by handling them as
patterns we can normalize negative integers.
|
|
'asm' was deprecated in 18315c16, to be removed in 18.x.
|
|
* nox/compiler/improve-core-lint:
Remove obsolete comment in core_lint
Handle return mismatches for calls and primops
Check for more return mismatches
Use +clint0 in compiler's test suites
|
|
|