aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/utils/beam_makeops
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2016-04-05 12:56:57 +0200
committerBjörn Gustavsson <[email protected]>2016-04-07 15:28:29 +0200
commit937f527054f13dd524588c064cd5d76e3cfd23eb (patch)
tree8fe284d496399fb4b0a3e07286b101517dbf4f6a /erts/emulator/utils/beam_makeops
parente93a66110aa27a5b8228fb46a3459a6de0e626d0 (diff)
downloadotp-937f527054f13dd524588c064cd5d76e3cfd23eb.tar.gz
otp-937f527054f13dd524588c064cd5d76e3cfd23eb.tar.bz2
otp-937f527054f13dd524588c064cd5d76e3cfd23eb.zip
Avoid rebuilding unchanged instructions
In transformations such as: move S X0=x==0 | line Loc | call_ext Ar Func => \ line Loc | move S X0 | call_ext Ar Func we can avoid rebuilding the last instruction in the sequence by introducing a 'keep' instruction. Currently, there are only 13 transformations that are hit by this optimization, but most of them are frequently used.
Diffstat (limited to 'erts/emulator/utils/beam_makeops')
-rwxr-xr-xerts/emulator/utils/beam_makeops41
1 files changed, 41 insertions, 0 deletions
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index 3d4213d55d..66ffd83ee9 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -1718,6 +1718,7 @@ sub tr_gen_to {
push(@code, make_op('', 'end'))
unless is_instr($code[$#code], 'call_end');
+ tr_maybe_keep(\@code);
tr_maybe_rename(\@code);
#
@@ -1745,6 +1746,46 @@ sub tr_gen_to {
push(@{$gen_transform{$key}}, @code),
}
+sub tr_maybe_keep {
+ my($ref) = @_;
+ my @last_instr;
+ my $pos;
+ my $reused_instr;
+
+ for (my $i = 0; $i < @$ref; $i++) {
+ my $instr = $$ref[$i];
+ my($size, $instr_ref, $comment) = @$instr;
+ my($op, @args) = @$instr_ref;
+ if ($op eq 'next_instr') {
+ @last_instr = ($args[0]);
+ } elsif ($op eq 'set_var_next_arg') {
+ push @last_instr, $args[0];
+ } elsif ($op eq 'next_arg') {
+ push @last_instr, 'ignored';
+ } elsif ($op eq 'new_instr') {
+ unless (defined $pos) {
+ # 'new_instr' immediately after 'commit'.
+ $reused_instr = $args[0];
+ return unless shift(@last_instr) == $reused_instr;
+ $pos = $i - 1;
+ } else {
+ # Second 'new_instr' after 'commit'. The instructions
+ # from $pos up to and including $i - 1 rebuilds the
+ # existing instruction exactly.
+ my $name = $gen_opname[$reused_instr];
+ my $arity = $gen_arity[$reused_instr];
+ my $reuse = make_op("$name/$arity", 'keep');
+ splice @$ref, $pos, $i-$pos, ($reuse);
+ return;
+ }
+ } elsif ($op eq 'store_var_next_arg') {
+ return unless shift(@last_instr) eq $args[0];
+ } elsif (defined $pos) {
+ return;
+ }
+ }
+}
+
sub tr_maybe_rename {
my($ref) = @_;
my $s = 'left';