From f19a52e92ae56b8e5248064db56dc38c0d7dff69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 5 Dec 2018 18:00:17 +0100 Subject: 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. --- erts/emulator/utils/beam_makeops | 57 +++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 6 deletions(-) (limited to 'erts/emulator/utils') 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]); } # -- cgit v1.2.3