File 0107-beam_makeops-Correct-generation-of-pack-instructions.patch of Package erlang
From f19a52e92ae56b8e5248064db56dc38c0d7dff69 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Wed, 5 Dec 2018 18:00:17 +0100
Subject: [PATCH 1/2] 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(-)
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]);
}
#
--
2.16.4