Age | Commit message (Collapse) | Author |
|
beam_utils:bif_to_test/3 is supposed to never put a literal
operand as the first operand in is_eq_exact or is_ne_exact,
but 'nil' was not recognized as a literal.
|
|
If a try/catch is used to ignore the potential exception caused by some
expression with a side effect such as:
try
side_effect()
catch _Class:_Reason ->
ok
end,
.
.
.
the generated code will be wasteful:
try YReg TryLabel
%% call side_effect() here
try_end Yreg
jump GoodLabel
TryLabel:
try_case YReg
%% try_case has set up registers as follows:
%% x(0) -> error | exit | throw
%% x(1) -> reason
%% x(2) -> raw stack trace data
GoodLabel:
%% This code does not use any x registers.
There will be two code paths that both end up at GoodLabel, and
the try_case instruction will set up registers that are never used.
We can do better by replacing try_case with try_end to obtain this
code:
try YReg TryLabel
%% call side_effect() here
try_end Yreg
jump GoodLabel
TryLabel:
try_end YReg
GoodLabel:
The jump optimizer (beam_jump) can further optimize this code
like this:
try YReg TryLabel
%% call side_effect() here
TryLabel:
try_end YReg
|
|
* In both loader and compiler, make sure constants are always the second
operand - many passes of the compiler assume that's always the case.
* In loader rewrite is_eq_exact with same arguments to skip the instruction
and with different constants move one to an x register to maintain
the properly outlined above.
* The same (but in reverse) is done with the is_ne_exact, where we rewrite
to an unconditional jump or add a move to an x register.
* All of the above allow to replace is_eq_exact_fss with is_eq_exact_fyy and
is_ne_exact_fss with is_ne_exact_fSS as those are the only possibilities left.
|
|
|
|
'john/compiler/fail-labels-in-blocks-otp-18/ERIERL-48/OTP-14522' into maint
* john/compiler/fail-labels-in-blocks-otp-18/ERIERL-48/OTP-14522:
compiler: Fix live regs update on allocate in validator
Take fail labels into account when determining liveness in block ops
Conflicts:
lib/compiler/src/beam_utils.erl
|
|
|
|
|
|
|
|
The beam_type may pass move and recalculates test_heap instructions.
The number of live registers are not always the lowest. Minimize the
number of registers by running beam_utils:live_opt/1 one more time.
|
|
The guard optimizations in v3_kernel has removed the need for
beam_bool.
|
|
* maint:
Update primary bootstrap
beam_block: Avoid unsafe inclusion of get_map_elements in blocks
|
|
c2035ebb8b restricted the get_map_elements instruction so that it
could only occur at the beginning of a block. It turns out that
including it anywhere in a block is unsafe.
Therefore, never put get_map_elements instruction in blocks.
(Also remove the beam_utils:join_even/2 function since it is no
longer used.)
ERL-266
|
|
When beam_utils was first written, it did not have the functions
for testing whether a register was not used. Those were added
later, in sort of a hacky way.
Also, is_killed*() and is_not_used*() for Y registers would
return the same answer. Fix that to make the API more consistent
(an Y register can only be killed by a deallocate/1 instruction).
We will need to change beam_trim to call beam_utils:is_not_used/3
instead of beam_utils:is_killed/3.
|
|
The 'is_bitstr' and 'is_function2' tests are pure. The corresponding BIFs
have different names; thus the default call to erl_internal:new_type_test/2
is not sufficient.
|
|
Y registers are killed by the deallocate/1 instruction, so there is no
need to handle Y register in the return/1 instruction in
check_liveness/3.
There is also no need to keep check_liveness_live_ret/3 since it
is only used in one place.
|
|
Exported functions in this file should appear at the top of the file.
Also add missing spaces after commas.
|
|
I can't remember that clause ever trigger during development.
Remove it to eliminated an uncovered line.
|
|
check_liveness/3 returns {unknown,State} if an instruction is
not handled. All callers will handle 'unknown' the same way as
'used'. Therefore, we can simplify the code and improve the
coverage if we return {used,State} instead of {unknown,State}.
|
|
|
|
All callers only calls code_at/2 for existing labels and they don't
handle the return value 'none'.
|
|
30cc5c902d moved try/3 instruction inside blocks, so the clause for
handling try/3 in live_opt/4 is never executed.
|
|
Two lines were never covered, because '[]' was used instead of 'nil'.
|
|
* bjorn/compiler/misc-opt:
v3_kernel: Construct literal lists properly
Use the register map in %live in beam_utils:is_killed_block/2
Teach beam_utils to check liveness for put_map instructions
beam_peep: Help out beam_jump
|
|
In 1f0ae04d374, a complete register map was introduced in the %live
instructions thar are added by beam_utils:live_opt/1.
Use the register map to improve beam_utils:is_killed_block/2.
|
|
|
|
|
|
When matching tuples, the pattern matching compiler would generate
code that would fetch all elements of the tuple that will ultimately
be used, *before* testing that (for example) the first element is the
correct record tag. For example:
is_tuple Fail {x,0}
test_arity Fail {x,0} 3
get_tuple_element {x,0} 0 {x,1}
get_tuple_element {x,0} 1 {x,2}
get_tuple_element {x,0} 2 {x,3}
is_eq_exact Fail {x,1} some_tag
If {x,2} and {x,3} are not used at label Fail, we can re-arrange the
code like this:
is_tuple Fail {x,0}
test_arity Fail {x,0} 3
get_tuple_element {x,0} 0 {x,1}
is_eq_exact Fail {x,1} some_tag
get_tuple_element {x,0} 1 {x,2}
get_tuple_element {x,0} 2 {x,3}
Doing that may be beneficial in two ways.
If the branch is taken, we have eliminated the execution of two
unnecessary instructions.
Even if the branch is never or rarely taken, there is the possibility
for more optimizations following the is_eq_exact instructions.
For example, imagine that the code looks like this:
get_tuple_element {x,0} 1 {x,2}
get_tuple_element {x,0} 2 {x,3}
move {x,2} {y,0}
move {x,3} {y,1}
Assuming that {x,2} and {x,3} have no further uses in the code
that follows, that can be rewritten to:
get_tuple_element {x,0} 1 {y,0}
get_tuple_element {x,0} 2 {y,1}
When should we perform this optimization?
At the very latest, it must be done before opt_blocks/1 in
beam_block which does the elimination of unnecessary moves.
Actually, we want do the optimization before the blocks have
been established, since moving instructions out of one block
into another is cumbersome.
Therefore, we will do the optimization in a new pass that is
run before beam_block. A new pass will make debugging easier,
and beam_block already has a fair number of sub passes.
|
|
|
|
In 8470558, the drop_labels/1 function was added to beam_utils
as a minor optimization. Since the function is already available,
we might as well use it in index_label/3 too.
|
|
Understanding get_map_elements improves the stack trimming done
by beam_trim.
|
|
beam_utils used to be overly conservative about liveness for
exit instructions such as:
call_ext erlang:exit/1
beam_utils would consider all y registers to be used, to avoid
overwriting a catch or try tag. That does not seem to be a real
risk.
However, we miss opportunities for stack trimming if we consider
y registers used by an exit instruction.
|
|
The execution time for beam_utils:index_labels_1/2 is among
the longest in the beam_bool, beam_bsm, beam_receive, and
beam_trim compiler passes. Therefore it is worthwhile to do
the minor optimization of replacing a call to lists:dropwhile/2
with a special-purpose drop_labels function.
|
|
As a preparation for fixing a bug, introduce a complete register
map in the '%live' annotations.
|
|
The has_map_fields test was not recognized in is_pure_test/1,
because beam_a has rewritten the {list,_} part of instruction.
|
|
* 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
|
|
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'.
|
|
* beam_utils:joineven/1 -> beam_utils:join_even/1
* beam_utils:split_even/1 -> beam_utils:split_even/1
|
|
|
|
Reported-by: Ulf Norell
|
|
* Combine multiple get values with one instruction
* Combine multiple check keys with one instruction
|
|
To add a type-testing guard BIF, the following steps are needed:
* The BIF itself is added to bif.tab (note that it should be declared
using "ubif", not "bif"), and its implementation to erl_bif_op.c.
* erl_internal must be modified in 3 places: The type test must be
recognized as guard BIF, as a type test, and it must be auto-imported.
* There must be an instruction that implements the same type test as
the BIF (it will be used in guards). beam_utils:bif_to_test/3 must
be updated to recognize the new guard BIF.
|
|
|
|
|
|
The live optimization in beam_utils:live_opt/4 did not take into
account that the wait/1 instruction *never* falls through to
the next instruction (it has the same effect on the control flow
as the jump/1 instruction).
|
|
beam_utils:is_not_used_at/3 could be very slow for complex guards,
because the cached result for previously encountered labels were
neither used nor updated within blocks.
Reported-by: Magnus Müller
|
|
|
|
Somewhat reduce the code bloat by eliminating special cases.
|
|
Somewhat reduce code bloat.
|
|
Eliminate some code bloat.
|
|
Rewrite the five binary creation instructions to a bs_init
instruction, in order to somewhat reduce code bloat.
|