Age | Commit message (Collapse) | Author |
|
|
|
|
|
On a 32-bit machine, `beam_makeops` would generate incorrect
pack instructions for instructions such as:
i_plus x x j? d
See the added comment block for a detailed description of the
problem and its fix.
|
|
Don't allow defining an specific operation more than once with
the exact same operands. Don't allow a specific operation to be
defined with different arities.
|
|
It can easily be implemented as $OPERAND_POSITION($Operand) == 0.
|
|
It is easy to to forget to use $REFRESH_GEN_DEST() in an instruction
that has a general destionation ('d'). Add a heuristic that should
catch most if not all such problems.
|
|
Add an $IF() macro to conditionally expand macros. Use it like
this:
$IF(Expression, IfTrue, IfFalse)
Expression is a Perl expression that can be evaulated at macro
expansion time. If the expression evaluates to 0, the result will be
IfFalse, otherwise IfTrue.
|
|
Although the terminology "arguments" is used in the comments
for beam_makeops, the documentation in beam_makeops.md consistenly
use the term "operand". Since the name of the macro is user-facing,
it should be consistent with the documentation.
|
|
Make it easier to define new macros.
|
|
Any type that is a lower-case letter is allowed in a transformation,
even though some of them don't make sense, could cause compilation
errors when building the emulator, or crash at runtime. For example,
the type 'z' is emitted by the compiler, but eaten by the loader
before the transform engine can see it. Another example is the 'q'
type, which would crash the emulator if it was used on the right
side of a transformation rule.
In beam_makeops, define explicitly which types that are allowed in
patterns (on the left side) and in construction (on the right side).
Using that information, check the transformation rules thoroughly and
reject operands that don't make sense.
While we are it, also correct some misleading comments.
|
|
The operands for the first part of a combined instruction (the entry
point following the OpCase() label) can safely be packed into the
instruction word.
This commit will make each of the following instructions one word
shorter:
bs_context_to_binary_x
i_band_xcjtd
i_bs_get_binary_all_reuse_xft
i_bs_get_integer_imm_xWtftx
i_bs_get_integer_small_imm_xWftx
i_bs_init_bits_fail_xjtx
i_bs_init_bits_fail_yjtx
i_bs_init_bits_fail_heap_sIjtx
i_bs_init_bits_heap_WItx
i_bs_init_fail_xjtx
i_bs_init_fail_yjtx
i_bs_init_fail_heap_sIjtx
i_bs_init_heap_WItx
i_bs_start_match2_xfttx
i_bs_start_match2_yfttx
i_element_xjsd
i_element_yjsd
i_fast_element_xjId
i_fast_element_yjId
i_increment_xWtd
i_increment_yWtd
i_jump_on_val_xfIW
i_jump_on_val_yfIW
i_jump_on_val_zero_xfI
i_jump_on_val_zero_yfI
i_minus_xxjtd
i_plus_xxjtd
i_plus_xyjtd
i_put_tuple_xI
i_put_tuple_yI
i_rem_xxjtd
i_select_tuple_arity_xfI
i_select_tuple_arity_yfI
i_select_tuple_arity2_xfAA
i_select_tuple_arity2_yfAA
i_select_val2_xfcc
i_select_val2_yfcc
i_select_val_bins_xfI
i_select_val_bins_yfI
i_select_val_lins_xfI
i_select_val_lins_yfI
|
|
The number of arguments has become unwieldy.
|
|
Operands that are marked with a "?" are not always used when
an instruction is executed. Enhance the packing algorithm to
place optional use operands into the instruction word even they
are not the first operand (as long as the total instruction
size stays the same).
Here are the instructions that will be packed differently
because of this change:
allocate_heap t I t?
allocate_heap_zero t I t?
test_heap I t?
i_bs_get_integer_8 x f? x
i_bs_get_integer_16 x f? x
i_bs_get_integer_32 x f? x
|
|
Having the instruction name available in the functions
that implement packing also simplifies debugging.
|
|
Introduce a syntax to mark an operand that is not always used when
an instrution is executed. Example of such operands are the fail
label for is_nil or the number of live registers for an
allocate instruction.
Use a question mark to annotate optional use:
is_nil f? xy
allocate t t?
|
|
|
|
|
|
On 64-bit machines where the C code is always at address below 4Gb,
pack one or more operands into the instruction word.
|
|
* bjorn/erts/improve-beam-ops:
Move out variables from the head of combined instructions
Change operand from 'P' to 'Q' for i_apply_last and i_apply_fun_last
Add CHECK_ALIGNED() for testing storage destinations
instrs.tab: Add missing -no_next directives
beam_load.c: Generalize the 'P' operator in the packing engine
Break out most of the initialization from process_main()
Eliminate the OpCode() macro
Eliminate unnecessary and inconsistent casts
Refactor macros for accessing Beam instructions
beam_emu: Make order of macros consistent
beam_SUITE: Strengthen test of packed registers
|
|
Consider the types in the code below:
BeamInstr* I;
.
.
.
BeamInstr* next;
next = (BeamInstr *) *I;
Goto(next);
This is illogical. If 'I' points to a BeamInstr, then 'next' should
be a BeamInstr, not a pointer to a BeamInstr. The Goto() macros does
not require a pointer, because it will cast its argument to a void*
anyway.
Therefore, this code example can be simplified to:
BeamInstr* I;
.
.
.
BeamInstr next;
next = *I;
Goto(next);
Similarly, we can remove the casts in the macros when NO_JUMP_TABLE
is defined.
|
|
Sometimes the line number in a stack trace could be wrong,
for example for this code:
t() ->
Res = id(x), %<== Wrong line number.
Res + 1.
id(I) -> I.
The line number pointed out in the stack trace would be the
line before the line where the exception occurred.
The reason is the way the increment instruction instruction
is implemented:
OpCase(i_increment_rWtd):
{
increment_reg_val = r(0);
}
I -= 1;
goto increment__execute;
OpCase(i_increment_xWtd):
{
increment_reg_val = xb(I[1]);
}
goto increment__execute;
increment__execute:
/* Common code for increment */
.
.
.
(The implementation in OTP 20 is similar, but hand-coded directly
in beam_emu.c instead of generated.)
The instruction i_increment_rWtd decrements the instruction pointer (I)
before jumping to the common code. That means that I points *before*
the 'increment' instruction. If there is a 'line' instruction directly
before the 'increment' instruction (as there is in this example), the
instruction pointer will point before that line. Thus the previous line
will be picked up instead.
To eliminate this bug, we must never decrement the instruction pointer.
Instead, we can increment the other (longer) instructions in the
same group of combined instructions:
OpCase(i_increment_rWtd):
{
increment_reg_val = r(0);
}
goto increment__execute;
OpCase(i_increment_xWtd):
{
increment_reg_val = xb(I[1]);
}
I += 1;
goto increment__execute;
increment__execute:
/* Common code for increment */
.
.
.
Also fix a bug that was only a potential bug when ddaed7774eb0a
introduced relative jumps, but is now a real bug. See the added
comment for SET_I_REL() in macros.tab.
|
|
|
|
The refactoring will simplify packing of combined instructions.
|
|
* bjorn/erts/relative-jumps:
Pack failure labels in i_select_val2 and i_select_tuple_arity2
Optimize i_select_tuple_arity2 and is_select_lins
Rewrite select_val_bins so that its labels can be packed
Pack sequences of trailing 'f' operands
Implement packing of 'f' and 'j'
Make sure that mask literals are 64 bits
Use relative failure labels
Add information about offset to common group start position
Remove JUMP_OFFSET
Refactor instructions to support relative jumps
Introduce a new trace_jump/1 instruction for tracing
Avoid using $Src more than once
|
|
|
|
Use the "ull" suffix for the mask literals instead of "ul"
to ensure that the literals are 64 bits also on Windows.
|
|
|
|
|
|
The right side of a transformation must be either a single call
to a transformation function OR a list of instructions. Mixing
them like this is not supported:
some_instruction A B C => gen_something(A) | other B C
Unfortunately, beam_makeops would silenty ignore anything after the
function call, basically handling it in the same way as:
some_instruction A B C => gen_something(A)
Add a sanity check to reject such mixed right-hand sides.
|
|
Make the generated code easier to read.
|
|
The bit syntax instructions are mixed among other instructions
in beam_hot.h and beam_cold.h.
Introduce a new hotness level called '%warm' with is associated
file beam_warm.h. Mark all bit syntax instructions as '%warm'.
|
|
Generated code uses 'I' explicitly in other places, so it
can as well use 'I' when accessing the operands for instructions.
|
|
The beam_instrs.h file serves no useful purpose. Put the
instructions in beam_hot.h instead.
|
|
The type 'd' could be used both for destination registers and
source register.
Restrict the 'd' type to only be used for destinations, and
introduce the new 'S' type to be used when a source must be
a register.
|
|
Cold instructions used to be cooler (less frequently executed),
so it did not seem worthwhile to pack their operands. Now bit
syntax instructions are included among the cold instructions,
and they are frequently used.
|
|
Update the pack engine to safely push literal operands to the pack
stack and to safely pop them back to another code address. That
will allow packing of more instructions.
|
|
The packer had several bugs and limitations. For instance, on
a 32-bit Erlang virtual machine it would gladly pack three
't' values into one word even though it would be not safe.
The rewritten version will be more careful how much it packs
into each word. It will also be able to do packing for more
instructions.
|
|
As a preparation for potentially improving packing in the future,
we will need to make sure that packable types have a defined maximum
size.
The packer algorithm assumes that two 'I' operands can be packed
into one 64-bit word, but there are instructions that use an 'I'
operand to store a pointer. It only works because those instructions
are not packed for other reasons.
Introduce the 'W' type and use it for operands that don't fit in
32 bits.
|
|
I don't remember what they were used for, but they are certainly
no longer used.
|
|
If a type has a size in %arg_size, it should also have
a defined pattern in %bit_type.
|
|
BEAM_WIDE_MASK covered the 16 right-most bits, instead of the 32
right-most bits. This bug will bite us when we'll do more packing in
the future.
This bug has been harmless in the past. It has been used in
test_heap and allocate instructions for the number of heap words
needed. It would be theoretically possible to construct a program
that would need 65536 or more heap words, but it is hard to imagine
a practical use for such a program. (The program would have to build
a tuple or list with at least one variable and the rest of the elements
being literals.)
|
|
|
|
|
|
|
|
beam_makeops will place all micro instructions in a block and generate
goto instructions from one micro instruction to the next. It will also
add adjustments of 'I' if necessary (if the micro instructions have
different length).
|
|
Eliminate the need to write pre-processor macros for each instruction.
Instead allow the implementation of instruction to be written in
C directly in the .tab files. Rewrite all existing macros in this
way and remove the %macro directive.
|
|
|
|
Inroduce syntactic sugar so that we can write:
get_list xy xy xy
instead of:
get_list x x x
get_list x x y
get_list x y x
get_list x y y
get_list y x x
get_list y x y
get_list y y x
get_list y y y
|
|
In Perl 5, '&' on direct subroutine calls are optional.
|
|
Instructions that take a 'd' argument needs a -gen_dest flag in their
macros. For example:
%macro:put_list PutList -pack -gen_dest
put_list s s d
-gen_dest was needed when x(0) was stored in a register, since it is
not possible to take the address of a register. Now that x(0) is stored
in memory and we can take the address, we can eliminate gen_dest.
|