Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Make Junction optimization less costly.
This refactor splits analysis and transform, decreasing the cost of
the common case when we just analyze and realise we're not looking
at a Junction.
  • Loading branch information
jnthn committed Aug 1, 2014
1 parent 89c8e4a commit 3618990
Showing 1 changed file with 56 additions and 52 deletions.
108 changes: 56 additions & 52 deletions src/Perl6/Optimizer.nqp
Expand Up @@ -741,65 +741,69 @@ my class JunctionOptimizer {
$proceed := $exp-side == 0;
}
if $proceed {
# TODO chain_handles_Any may get more cleverness to check only the parameters that actually have
# a junction passed to them, so that in some cases the unfolding may still happen.
my str $juncop := $op[0][$exp-side].name eq '&infix:<&>' ?? 'if' !! 'unless';
my str $juncname := %foldable_junction{$op[0][$exp-side].name};
my str $chainop := $op[0].op;
my str $chainname := $op[0].name;
my $values := $op[0][$exp-side];
my $ovalue := $op[0][1 - $exp-side];

# the first time $valop is refered to, create a bind op for a
# local var, next time create a reference var op.
my %reference;
sub refer_to($valop) {
my $id := nqp::where($valop);
if nqp::existskey(%reference, $id) {
QAST::Var.new(:name(%reference{$id}), :scope<local>);
} else {
%reference{$id} := $op.unique('junction_unfold');
QAST::Op.new(:op<bind>,
QAST::Var.new(:name(%reference{$id}),
:scope<local>,
:decl<var>),
$valop);
}
}
return self.apply_transform($op, $exp-side);
}
}
return NQPMu;
}

# create a comparison operation for the inner comparisons
sub chain($value) {
if $exp-side == 0 {
QAST::Op.new(:op($chainop), :name($chainname),
$value,
refer_to($ovalue));
} else {
QAST::Op.new(:op($chainop), :name($chainname),
refer_to($ovalue),
$value);
}
}
method apply_transform($op, $exp-side) {
# TODO chain_handles_Any may get more cleverness to check only the parameters that actually have
# a junction passed to them, so that in some cases the unfolding may still happen.
my str $juncop := $op[0][$exp-side].name eq '&infix:<&>' ?? 'if' !! 'unless';
my str $juncname := %foldable_junction{$op[0][$exp-side].name};
my str $chainop := $op[0].op;
my str $chainname := $op[0].name;
my $values := $op[0][$exp-side];
my $ovalue := $op[0][1 - $exp-side];

# the first time $valop is refered to, create a bind op for a
# local var, next time create a reference var op.
my %reference;
sub refer_to($valop) {
my $id := nqp::where($valop);
if nqp::existskey(%reference, $id) {
QAST::Var.new(:name(%reference{$id}), :scope<local>);
} else {
%reference{$id} := $op.unique('junction_unfold');
QAST::Op.new(:op<bind>,
QAST::Var.new(:name(%reference{$id}),
:scope<local>,
:decl<var>),
$valop);
}
}

# create a chain of outer logical junction operators with inner comparisons
sub create_junc() {
my $junc := QAST::Op.new(:name($juncname), :op($juncop));
# create a comparison operation for the inner comparisons
sub chain($value) {
if $exp-side == 0 {
QAST::Op.new(:op($chainop), :name($chainname),
$value,
refer_to($ovalue));
} else {
QAST::Op.new(:op($chainop), :name($chainname),
refer_to($ovalue),
$value);
}
}

$junc.push(chain($values.shift()));
# create a chain of outer logical junction operators with inner comparisons
sub create_junc() {
my $junc := QAST::Op.new(:name($juncname), :op($juncop));

if +$values.list > 1 {
$junc.push(create_junc());
} else {
$junc.push(chain($values.shift()));
}
return $junc;
}
$junc.push(chain($values.shift()));

$op.shift;
$op.unshift(create_junc());
return $!optimizer.visit_op($op);
if +$values.list > 1 {
$junc.push(create_junc());
} else {
$junc.push(chain($values.shift()));
}
return $junc;
}
return NQPMu;

$op.shift;
$op.unshift(create_junc());
return $!optimizer.visit_op($op);
}
}

Expand Down

0 comments on commit 3618990

Please sign in to comment.