Skip to content
Permalink
Browse files

Opt nested meta assigns / fix meta assign bugs

Fixes R#1987 #1987
Fixes R#1989 #1989
Fixes #1981 R#1981

For opts: mark applicable METAOP constructs, so that when we
get to optimize nested chains, we can see that these are fine
to optimize further.

For bugs: swap `assign` to `p6store` op in the opt which both
handles arrays/hashes correctly and throws better RO exceptions
  • Loading branch information...
zoffixznet committed Jun 28, 2018
1 parent 23045bc commit b9b0838dd8a7cf24f43c693d0e3e786b40298064
Showing with 15 additions and 5 deletions.
  1. +1 −1 src/Perl6/Actions.nqp
  2. +5 −3 src/Perl6/Optimizer.nqp
  3. +9 −1 t/08-performance/02-qast-rewrites.t
@@ -6750,7 +6750,7 @@ class Perl6::Actions is HLL::Actions does STDActions {
QAST::Var.new( :name($sym), :scope('local') ),
WANTED($/[1].ast, 'EXPR/META')
)
));
)).annotate_self: 'METAOP_opt_result', 1;
}
else {
$past.push(WANTED($/[0].ast, 'EXPR/META'));
@@ -1892,6 +1892,7 @@ class Perl6::Optimizer {
&& (my $is-reverse := 1)) {
if $is-reverse
|| (nqp::istype($op[1], QAST::Var) && (my int $is_var := 1))
|| $op[1].has_ann('METAOP_opt_result') # previously-optimized nested METAOP
# instead of $foo += 1 we may have $foo.bar += 1, which
# we really want to unpack here as well. this second branch
# of the if statement achieves this.
@@ -1923,7 +1924,7 @@ class Perl6::Optimizer {
$assignee := $assignee_var := $op[1];
}
else {
$assignop := "assign";
$assignop := 'p6store';
# We want to be careful to only call $foo.bar once, if that's what
# we have, so we bind to a local var and assign to that. The
# var is also needed when we're unpacking a REVERSE op, since
@@ -1975,6 +1976,7 @@ class Perl6::Optimizer {
$operand;
}

$op.annotate_self: 'METAOP_opt_result', 1;
$op.returns: $assignee.returns
if $assignop ne 'assign'
&& nqp::objprimspec($assignee.returns);
@@ -1993,8 +1995,8 @@ class Perl6::Optimizer {
elsif self.op_eq_core($metaop, '&METAOP_REVERSE') {
return NQPMu unless nqp::istype($metaop[0], QAST::Var)
&& nqp::elems($op) == 3;
return QAST::Op.new: :op<call>, :name($metaop[0].name),
$op[2], $op[1];
return QAST::Op.new(:op<call>, :name($metaop[0].name),
$op[2], $op[1]).annotate_self: 'METAOP_opt_result', 1;
}
NQPMu
}
@@ -1,7 +1,7 @@
use lib <t/packages>;
use Test::Helpers::QAST;
use Test;
plan 5;
plan 6;

subtest 'postfix-inc/dec on natives gets overwritten to prefix' => {
plan 8;
@@ -92,3 +92,11 @@ qast-is 「for ^10 -> $, :$foo {}」, :target<ast>, -> \v {
qast-contains-op v, 'p6forstmt'
and not qast-contains-op v, 'p6for'
}, 'named arg does not accidentally get counted as a positional';

# https://github.com/rakudo/rakudo/issues/1981
subtest 'nested metaops get fully rewritten away from &METAOP sub calls' => {
plan 2;
qast-is 「my $a; ($a //= 0) += 1」, -> \v { not qast-contains-call v, /METAOP/ }, '(//=)+=';
qast-is 「my $a; (((($a //= 0) += 1) //= 0) += 1)」, -> \v { not qast-contains-call v, /METAOP/ },
'((((//=)+=) //=) +=)';
}

1 comment on commit b9b0838

@zoffixznet

This comment has been minimized.

Copy link
Contributor Author

commented on b9b0838 Jun 28, 2018

Forgot to mention the most interesting part: this commit makes nested metaassign ops like ($a //= 42) += 100 3.9x faster

Please sign in to comment.
You can’t perform that action at this time.