diff options
author | Björn Gustavsson <[email protected]> | 2018-12-05 18:00:17 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2018-12-06 10:40:48 +0100 |
commit | f19a52e92ae56b8e5248064db56dc38c0d7dff69 (patch) | |
tree | fe74484ec40a398eae8c0a1decc7567320225211 /erts/emulator/utils/beam_makeops | |
parent | c85094dddfa54bb3991d7ba6147ef177c0dd9c42 (diff) | |
download | otp-f19a52e92ae56b8e5248064db56dc38c0d7dff69.tar.gz otp-f19a52e92ae56b8e5248064db56dc38c0d7dff69.tar.bz2 otp-f19a52e92ae56b8e5248064db56dc38c0d7dff69.zip |
beam_makeops: Correct generation of pack instructions
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.
Diffstat (limited to 'erts/emulator/utils/beam_makeops')
-rwxr-xr-x | erts/emulator/utils/beam_makeops | 57 |
1 files changed, 51 insertions, 6 deletions
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops index da994fae3e..f73e2362bf 100755 --- a/erts/emulator/utils/beam_makeops +++ b/erts/emulator/utils/beam_makeops @@ -1840,12 +1840,57 @@ sub do_pack_one { } # - # Return if there is nothing to pack. - # - if ($packable_args == 0) { - return (-1); - } elsif ($packable_args == 1 and $options == 0) { - return (-1); + # Check whether any packing can be done. + # + my $nothing_to_pack = $packable_args == 0 || + $packable_args == 1 && $options == 0; + if ($nothing_to_pack) { + # The packing engine in the loader processes the operands from + # right to left. Rightmost operands that are not packed must + # be stacked and then unstacked. + # + # Because instructions may be broken up into micro + # instructions, we might not see all operands at once. So + # there could be a micro instructions that packs the operands + # to the left of the current micro instruction. If that is the + # case, it is essential that we generate stacking and + # unstacking instructions even when no packing is + # possible. (build_pack_spec() will remove any unecessary + # stacking and unstacking operations.) + # + # Here is an example. Say that we have this instruction: + # + # i_plus x x j d + # + # that comprises two micro instructions: + # + # i_plus.fetch x x + # i_plus.execute j d + # + # This function (do_pack_one()) will be called twice, once to pack + # 'x' and 'x', and once to pack 'j' and 'd'. + # + # On a 32-bit machine, the 'j' and 'd' operands can't be + # packed because 'j' requires a full word. The two 'x' + # operands in the i_plus.fetch micro instruction will be + # packed, though, so we must generate instructions for packing + # and unpacking the 'j' and 'd' operands. + my $down = ''; + my $up = ''; + foreach my $arg (@args) { + my $push = 'g'; + if ($type_bit{$arg} & $type_bit{'q'}) { + # The operand may be a literal. + $push = 'q'; + } elsif ($type_bit{$arg} & $type_bit{'f'}) { + # The operand may be a failure label. + $push = 'f'; + } + $down = "$push${down}"; + $up = "${up}p"; + } + my $pack_spec = "$down:$up"; + return (1, ['',$pack_spec,@args]); } # |