Skip to content

Commit

Permalink
Implement OP_PADSV_STORE - combined sassign/padsv OP
Browse files Browse the repository at this point in the history
This commit introduces a new OP to replace simple cases
of OP_SASSIGN and OP_PADSV.

For example, 'my $x = 1' is currently implemented as:

1  <;> nextstate(main 1 -e:1) v:{
2  <$> const(IV 1) s
3  <0> padsv[$x:1,2] sRM*/LVINTRO
4  <2> sassign vKS/2

But now will be turned into:

1  <;> nextstate(main 1 -e:1) v:{
2  <$> const(IV 1) s
3  <1> padsv_store[$x:1,2] vKMS/LVINTRO

This intended to be a transparent performance optimization.
It should be applicable for RHS optrees of varying complexity.
  • Loading branch information
richardleach committed Aug 17, 2022
1 parent 434ccf3 commit 9fdd7fc
Show file tree
Hide file tree
Showing 15 changed files with 875 additions and 755 deletions.
2 changes: 1 addition & 1 deletion ext/B/t/b.t
Expand Up @@ -306,7 +306,7 @@ is(B::opnumber("pp_null"), 0, "Testing opnumber with opname (pp_null)");

is(B::class(bless {}, "Wibble::Bibble"), "Bibble", "Testing B::class()");
is(B::cast_I32(3.14), 3, "Testing B::cast_I32()");
is(B::opnumber("chop"), 38, "Testing opnumber with opname (chop)");
is(B::opnumber("chop"), 39, "Testing opnumber with opname (chop)");

{
no warnings 'once';
Expand Down
4 changes: 2 additions & 2 deletions ext/B/t/optree_concise.t
Expand Up @@ -178,13 +178,13 @@ checkOptree ( name => "terse basic",
UNOP (0x82b0918) leavesub [1]
LISTOP (0x82b08d8) lineseq
COP (0x82b0880) nextstate
UNOP (0x82b0860) null [14]
UNOP (0x82b0860) null [15]
PADOP (0x82b0840) gvsv GV (0x82a818c) *a
EOT_EOT
# UNOP (0x8282310) leavesub [1]
# LISTOP (0x82822f0) lineseq
# COP (0x82822b8) nextstate
# UNOP (0x812fc20) null [14]
# UNOP (0x812fc20) null [15]
# SVOP (0x812fc00) gvsv GV (0x814692c) *a
EONT_EONT

Expand Down
132 changes: 65 additions & 67 deletions ext/B/t/optree_samples.t
Expand Up @@ -67,49 +67,49 @@ checkOptree ( name => '-basic (see above, with my $a = shift)',
},
strip_open_hints => 1,
expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
# b <1> leavesub[1 ref] K/REFC,1 ->(end)
# - <@> lineseq KP ->b
# a <1> leavesub[1 ref] K/REFC,1 ->(end)
# - <@> lineseq KP ->a
# 1 <;> nextstate(main 666 optree_samples.t:70) v:>,<,% ->2
# 4 <2> sassign vKS/2 ->5
# 3 <1> padsv_store[$a:666,670] vKS/LVINTRO ->4
# 2 <0> shift s* ->3
# 3 <0> padsv[$a:666,670] sRM*/LVINTRO ->4
# 5 <;> nextstate(main 670 optree_samples.t:71) v:>,<,% ->6
# - <0> ex-padsv sRM*/LVINTRO ->3
# 4 <;> nextstate(main 670 optree_samples.t:71) v:>,<,% ->5
# - <1> null K/1 ->-
# 7 <|> cond_expr(other->8) K/1 ->c
# 6 <0> padsv[$a:666,670] s ->7
# 6 <|> cond_expr(other->7) K/1 ->b
# 5 <0> padsv[$a:666,670] s ->6
# - <@> scope K ->-
# - <;> ex-nextstate(main 1603 optree_samples.t:70) v:>,<,% ->8
# a <@> print sK ->b
# 8 <0> pushmark s ->9
# 9 <$> const[PV "foo"] s ->a
# h <@> leave KP ->b
# c <0> enter ->d
# d <;> nextstate(main 668 optree_samples.t:72) v:>,<,% ->e
# g <@> print sK ->h
# e <0> pushmark s ->f
# f <$> const[PV "bar"] s ->g
# - <;> ex-nextstate(main 1510 optree_samples.t:66) v:>,<,% ->7
# 9 <@> print sK ->a
# 7 <0> pushmark s ->8
# 8 <$> const[PV "foo"] s ->9
# g <@> leave KP ->a
# b <0> enter ->c
# c <;> nextstate(main 1510 optree_samples.t:66) v:>,<,% ->d
# f <@> print sK ->g
# d <0> pushmark s ->e
# e <$> const[PV "bar"] s ->f
EOT_EOT
# b <1> leavesub[1 ref] K/REFC,1 ->(end)
# - <@> lineseq KP ->b
# 1 <;> nextstate(main 666 optree_samples.t:72) v:>,<,% ->2
# 4 <2> sassign vKS/2 ->5
# a <1> leavesub[1 ref] K/REFC,1 ->(end)
# - <@> lineseq KP ->a
# 1 <;> nextstate(main 666 optree_samples.t:70) v:>,<,% ->2
# 3 <1> padsv_store[$a:666,670] vKS/LVINTRO ->4
# 2 <0> shift s* ->3
# 3 <0> padsv[$a:666,670] sRM*/LVINTRO ->4
# 5 <;> nextstate(main 670 optree_samples.t:73) v:>,<,% ->6
# - <0> ex-padsv sRM*/LVINTRO ->3
# 4 <;> nextstate(main 670 optree_samples.t:71) v:>,<,% ->5
# - <1> null K/1 ->-
# 7 <|> cond_expr(other->8) K/1 ->c
# 6 <0> padsv[$a:666,670] s ->7
# 6 <|> cond_expr(other->7) K/1 ->b
# 5 <0> padsv[$a:666,670] s ->6
# - <@> scope K ->-
# - <;> ex-nextstate(main 1603 optree_samples.t:70) v:>,<,% ->8
# a <@> print sK ->b
# 8 <0> pushmark s ->9
# 9 <$> const(PV "foo") s ->a
# h <@> leave KP ->b
# c <0> enter ->d
# d <;> nextstate(main 668 optree_samples.t:74) v:>,<,% ->e
# g <@> print sK ->h
# e <0> pushmark s ->f
# f <$> const(PV "bar") s ->g
# - <;> ex-nextstate(main 1510 optree_samples.t:70) v:>,<,% ->7
# 9 <@> print sK ->a
# 7 <0> pushmark s ->8
# 8 <$> const(PV "foo") s ->9
# g <@> leave KP ->a
# b <0> enter ->c
# c <;> nextstate(main 668 optree_samples.t:72) v:>,<,% ->d
# f <@> print sK ->g
# d <0> pushmark s ->e
# e <$> const(PV "bar") s ->f
EONT_EONT

checkOptree ( name => '-exec sub {if shift print then,else}',
Expand Down Expand Up @@ -160,41 +160,39 @@ checkOptree ( name => '-exec (see above, with my $a = shift)',
expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
# 1 <;> nextstate(main 675 optree_samples.t:165) v:>,<,%
# 2 <0> shift s*
# 3 <0> padsv[$a:675,679] sRM*/LVINTRO
# 4 <2> sassign vKS/2
# 5 <;> nextstate(main 679 optree_samples.t:166) v:>,<,%
# 6 <0> padsv[$a:675,679] s
# 7 <|> cond_expr(other->8) K/1
# 8 <0> pushmark s
# 9 <$> const[PV "foo"] s
# a <@> print sK
# goto b
# c <0> enter
# d <;> nextstate(main 677 optree_samples.t:167) v:>,<,%
# e <0> pushmark s
# f <$> const[PV "bar"] s
# g <@> print sK
# h <@> leave KP
# b <1> leavesub[1 ref] K/REFC,1
# 3 <1> padsv_store[$a:1522,1529] vKS/LVINTRO
# 4 <;> nextstate(main 679 optree_samples.t:166) v:>,<,%
# 5 <0> padsv[$a:675,679] s
# 6 <|> cond_expr(other->7) K/1
# 7 <0> pushmark s
# 8 <$> const[PV "foo"] s
# 9 <@> print sK
# goto a
# b <0> enter
# c <;> nextstate(main 677 optree_samples.t:167) v:>,<,%
# d <0> pushmark s
# e <$> const[PV "bar"] s
# f <@> print sK
# g <@> leave KP
# a <1> leavesub[1 ref] K/REFC,1
EOT_EOT
# 1 <;> nextstate(main 675 optree_samples.t:171) v:>,<,%
# 2 <0> shift s*
# 3 <0> padsv[$a:675,679] sRM*/LVINTRO
# 4 <2> sassign vKS/2
# 5 <;> nextstate(main 679 optree_samples.t:172) v:>,<,%
# 6 <0> padsv[$a:675,679] s
# 7 <|> cond_expr(other->8) K/1
# 8 <0> pushmark s
# 9 <$> const(PV "foo") s
# a <@> print sK
# goto b
# c <0> enter
# d <;> nextstate(main 677 optree_samples.t:173) v:>,<,%
# e <0> pushmark s
# f <$> const(PV "bar") s
# g <@> print sK
# h <@> leave KP
# b <1> leavesub[1 ref] K/REFC,1
# 3 <1> padsv_store[$a:1522,1529] vKS/LVINTRO
# 4 <;> nextstate(main 679 optree_samples.t:172) v:>,<,%
# 5 <0> padsv[$a:675,679] s
# 6 <|> cond_expr(other->7) K/1
# 7 <0> pushmark s
# 8 <$> const(PV "foo") s
# 9 <@> print sK
# goto a
# b <0> enter
# c <;> nextstate(main 677 optree_samples.t:173) v:>,<,%
# d <0> pushmark s
# e <$> const(PV "bar") s
# f <@> print sK
# g <@> leave KP
# a <1> leavesub[1 ref] K/REFC,1
EONT_EONT

checkOptree ( name => '-exec sub { print (shift) ? "foo" : "bar" }',
Expand Down
48 changes: 22 additions & 26 deletions ext/B/t/optree_varinit.t
Expand Up @@ -129,19 +129,19 @@ checkOptree ( name => 'sub {my $a=undef}',
bcopts => '-basic',
strip_open_hints => 1,
expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
5 <1> leavesub[1 ref] K/REFC,1 ->(end)
- <@> lineseq KP ->5
4 <1> leavesub[1 ref] K/REFC,1 ->(end)
- <@> lineseq KP ->4
1 <;> nextstate(main 641 optree_varinit.t:130) v:>,<,% ->2
4 <2> sassign sKS/2 ->5
3 <1> padsv_store[$a:1508,1509] sKS/LVINTRO ->4
2 <0> undef s ->3
3 <0> padsv[$a:641,642] sRM*/LVINTRO ->4
- <0> ex-padsv sRM*/LVINTRO ->3
EOT_EOT
# 5 <1> leavesub[1 ref] K/REFC,1 ->(end)
# - <@> lineseq KP ->5
# 4 <1> leavesub[1 ref] K/REFC,1 ->(end)
# - <@> lineseq KP ->4
# 1 <;> nextstate(main 641 optree_varinit.t:130) v:>,<,% ->2
# 4 <2> sassign sKS/2 ->5
# 3 <1> padsv_store[$a:1508,1509] sKS/LVINTRO ->4
# 2 <0> undef s ->3
# 3 <0> padsv[$a:641,642] sRM*/LVINTRO ->4
# - <0> ex-padsv sRM*/LVINTRO ->3
EONT_EONT

checkOptree ( name => 'sub {our $a=undef}',
Expand Down Expand Up @@ -195,19 +195,19 @@ checkOptree ( name => 'my $a=undef',
bcopts => '-basic',
strip_open_hints => 1,
expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
6 <@> leave[1 ref] vKP/REFC ->(end)
5 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter v ->2
2 <;> nextstate(main 1 -e:1) v:>,<,%,{ ->3
5 <2> sassign vKS/2 ->6
4 <1> padsv_store[$a:1,2] vKS/LVINTRO ->5
3 <0> undef s ->4
4 <0> padsv[$a:1,2] sRM*/LVINTRO ->5
- <0> ex-padsv sRM*/LVINTRO ->4
EOT_EOT
# 6 <@> leave[1 ref] vKP/REFC ->(end)
# 5 <@> leave[1 ref] vKP/REFC ->(end)
# 1 <0> enter v ->2
# 2 <;> nextstate(main 1 -e:1) v:>,<,%,{ ->3
# 5 <2> sassign vKS/2 ->6
# 4 <1> padsv_store[$a:1,2] vKS/LVINTRO ->5
# 3 <0> undef s ->4
# 4 <0> padsv[$a:1,2] sRM*/LVINTRO ->5
# - <0> ex-padsv sRM*/LVINTRO ->4
EONT_EONT

checkOptree ( name => 'our $a=undef',
Expand Down Expand Up @@ -264,15 +264,13 @@ checkOptree ( name => 'sub {my $a=()}',
expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
1 <;> nextstate(main -439 optree.t:105) v:>,<,%
2 <0> stub sP
3 <0> padsv[$a:-439,-438] sRM*/LVINTRO
4 <2> sassign sKS/2
5 <1> leavesub[1 ref] K/REFC,1
3 <1> padsv_store[$a:1516,1517] sKS/LVINTRO
4 <1> leavesub[1 ref] K/REFC,1
EOT_EOT
# 1 <;> nextstate(main 438 optree_varinit.t:247) v:>,<,%
# 2 <0> stub sP
# 3 <0> padsv[$a:438,439] sRM*/LVINTRO
# 4 <2> sassign sKS/2
# 5 <1> leavesub[1 ref] K/REFC,1
# 3 <1> padsv_store[$a:1516,1517] sKS/LVINTRO
# 4 <1> leavesub[1 ref] K/REFC,1
EONT_EONT

checkOptree ( name => 'sub {our $a=()}',
Expand Down Expand Up @@ -321,16 +319,14 @@ checkOptree ( name => 'my $a=()',
1 <0> enter v
2 <;> nextstate(main 1 -e:1) v:>,<,%,{
3 <0> stub sP
4 <0> padsv[$a:1,2] sRM*/LVINTRO
5 <2> sassign vKS/2
6 <@> leave[1 ref] vKP/REFC
4 <1> padsv_store[$a:1516,1517] vKS/LVINTRO
5 <@> leave[1 ref] vKP/REFC
EOT_EOT
# 1 <0> enter v
# 2 <;> nextstate(main 1 -e:1) v:>,<,%,{
# 3 <0> stub sP
# 4 <0> padsv[$a:1,2] sRM*/LVINTRO
# 5 <2> sassign vKS/2
# 6 <@> leave[1 ref] vKP/REFC
# 4 <1> padsv_store[$a:1516,1517] vKS/LVINTRO
# 5 <@> leave[1 ref] vKP/REFC
EONT_EONT

checkOptree ( name => 'our $a=()',
Expand Down
4 changes: 2 additions & 2 deletions ext/Opcode/Opcode.pm
@@ -1,4 +1,4 @@
package Opcode 1.59;
package Opcode 1.60;

use strict;

Expand Down Expand Up @@ -302,7 +302,7 @@ invert_opset function.
null stub scalar pushmark wantarray const defined undef
rv2sv sassign
rv2sv sassign padsv_store
rv2av aassign aelem aelemfast aelemfast_lex aslice kvaslice
av2arylen
Expand Down
14 changes: 13 additions & 1 deletion lib/B/Deparse.pm
Expand Up @@ -7,7 +7,7 @@
# This is based on the module of the same name by Malcolm Beattie,
# but essentially none of his code remains.

package B::Deparse 1.67;
package B::Deparse 1.68;
use strict;
use Carp;
use B qw(class main_root main_start main_cv svref_2object opnumber perlstring
Expand Down Expand Up @@ -3092,6 +3092,18 @@ sub pp_isa { binop(@_, "isa", 15) }
sub pp_sassign { binop(@_, "=", 7, SWAP_CHILDREN) }
sub pp_aassign { binop(@_, "=", 7, SWAP_CHILDREN | LIST_CONTEXT) }

sub pp_padsv_store {
my $self = shift;
my ($op, $cx, $forbid_parens, @args) = @_;
my $targ = $op->targ;
my $var = $self->maybe_my($op, $cx, $self->padname($targ),
$self->padname_sv($targ),
$forbid_parens);

my $val = $self->deparse($op->first, 7);
return $self->maybe_parens("$var = $val", $cx, 7);
}

sub pp_smartmatch {
my ($self, $op, $cx) = @_;
if (($op->flags & OPf_SPECIAL) && $self->{expand} < 2) {
Expand Down
9 changes: 5 additions & 4 deletions lib/B/Op_private.pm

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9fdd7fc

Please sign in to comment.